added 'start' button and logic to preferences so Login Item can be restarted if necessary

change launching of login item (at install time) to NSTask, so focus would stay with installer app
fixed issue where activity indicator would overlap with install/uninstall message on macOS Sierra
'Inactive' video and audio notifications are now automatically closed after two seconds
updated code for macOS Sierra (e.g. FaceTime does call CMIO:doWork)
added check to ensure we can get a process's path (which fixed a NULL pointer de-ref)
added 'avconferenced' as a white-listed apple daemon for macOS Sierra
added getOSVersion() function to facilitate macOS Sierra specific logic
added getProcessID() function to get a process name from it's pid
code cleanup/extra debug statements
This commit is contained in:
Patrick Wardle 2016-09-24 17:08:38 -10:00
parent d9ae15b3bc
commit 2eddae193d
16 changed files with 381 additions and 81 deletions

View File

@ -135,4 +135,6 @@ bail:
return; return;
} }
- (IBAction)startLoginItem:(id)sender {
}
@end @end

View File

@ -63,7 +63,7 @@
//dbg msg //dbg msg
logMsg(LOG_DEBUG, @"installed, now will start"); logMsg(LOG_DEBUG, @"installed, now will start");
//start login item //start login item
if(YES != [self start]) if(YES != [self start])
{ {
@ -198,19 +198,30 @@ bail:
//path to login item //path to login item
NSString* loginItem = nil; NSString* loginItem = nil;
//task
NSTask* task = nil;
//init path //init path
loginItem = [[APPS_FOLDER stringByAppendingPathComponent:APP_NAME] stringByAppendingPathComponent:@"Contents/Library/LoginItems/OverSight Helper.app"]; loginItem = [[APPS_FOLDER stringByAppendingPathComponent:APP_NAME] stringByAppendingPathComponent:@"Contents/Library/LoginItems/OverSight Helper.app/Contents/MacOS/OverSight Helper"];
//launch it! //alloc task
if(YES != [[NSWorkspace sharedWorkspace] launchApplication:loginItem]) task = [[NSTask alloc] init];
//set path
[task setLaunchPath:loginItem];
//wrap task launch
@try
{
//launch
[task launch];
}
@catch(NSException* exception)
{ {
//err msg
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to start login item, %@", loginItem]);
//bail //bail
goto bail; goto bail;
} }
//happy //happy
bStarted = YES; bStarted = YES;

View File

@ -230,19 +230,6 @@ bail:
// ->basically just update UI // ->basically just update UI
-(void)beginEvent:(NSUInteger)event -(void)beginEvent:(NSUInteger)event
{ {
//status msg frame
CGRect statusMsgFrame = {0};
//grab exiting frame
statusMsgFrame = self.statusMsg.frame;
//avoid activity indicator
// ->shift frame shift delta
statusMsgFrame.origin.x += FRAME_SHIFT;
//update frame to align
self.statusMsg.frame = statusMsgFrame;
//align text left //align text left
[self.statusMsg setAlignment:NSLeftTextAlignment]; [self.statusMsg setAlignment:NSLeftTextAlignment];
@ -250,13 +237,15 @@ bail:
if(ACTION_INSTALL_FLAG == event) if(ACTION_INSTALL_FLAG == event)
{ {
//update status msg //update status msg
[self.statusMsg setStringValue:@"Installing..."]; // ->with space to avoid spinner
[self.statusMsg setStringValue:@"\t Installing..."];
} }
//uninstall msg //uninstall msg
else else
{ {
//update status msg //update status msg
[self.statusMsg setStringValue:@"Uninstalling..."]; // ->with space to avoid spinner
[self.statusMsg setStringValue:@"\t Uninstalling..."];
} }
//disable action button //disable action button
@ -278,9 +267,6 @@ bail:
// ->update UI after background event has finished // ->update UI after background event has finished
-(void)completeEvent:(BOOL)success event:(NSUInteger)event -(void)completeEvent:(BOOL)success event:(NSUInteger)event
{ {
//status msg frame
CGRect statusMsgFrame = {0};
//action //action
NSString* action = nil; NSString* action = nil;
@ -341,15 +327,6 @@ bail:
//hide spinner //hide spinner
[self.activityIndicator setHidden:YES]; [self.activityIndicator setHidden:YES];
//grab exiting frame
statusMsgFrame = self.statusMsg.frame;
//shift back since activity indicator is gone
statusMsgFrame.origin.x -= FRAME_SHIFT;
//update frame to align
self.statusMsg.frame = statusMsgFrame;
//set font to bold //set font to bold
[self.statusMsg setFont:[NSFont fontWithName:@"Menlo-Bold" size:13]]; [self.statusMsg setFont:[NSFont fontWithName:@"Menlo-Bold" size:13]];

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A323" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies> </dependencies>
@ -20,7 +20,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES" unifiedTitleAndToolbar="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES" unifiedTitleAndToolbar="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="460" height="176"/> <rect key="contentRect" x="196" y="240" width="460" height="176"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/> <rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" id="se5-gp-TjO"> <view key="contentView" id="se5-gp-TjO">
<rect key="frame" x="0.0" y="0.0" width="460" height="176"/> <rect key="frame" x="0.0" y="0.0" width="460" height="176"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@ -43,7 +43,7 @@
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon" id="bCU-0f-ff8"/> <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="icon" id="bCU-0f-ff8"/>
</imageView> </imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="293" translatesAutoresizingMaskIntoConstraints="NO" id="SpB-Xc-WlB"> <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="293" translatesAutoresizingMaskIntoConstraints="NO" id="SpB-Xc-WlB">
<rect key="frame" x="142" y="10" width="297" height="47"/> <rect key="frame" x="144" y="11" width="293" height="47"/>
<textFieldCell key="cell" truncatesLastVisibleLine="YES" enabled="NO" sendsActionOnEndEditing="YES" alignment="center" id="Rib-WU-Syl"> <textFieldCell key="cell" truncatesLastVisibleLine="YES" enabled="NO" sendsActionOnEndEditing="YES" alignment="center" id="Rib-WU-Syl">
<font key="font" size="13" name="Menlo-Regular"/> <font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>

View File

@ -209,6 +209,9 @@
// ->start monitoring thread // ->start monitoring thread
if(YES == self.videoActive) if(YES == self.videoActive)
{ {
//dbg msg
logMsg(LOG_DEBUG, @"video already active, so will start polling for new video procs");
//tell XPC video is active //tell XPC video is active
[[xpcConnection remoteObjectProxy] updateVideoStatus:self.videoActive reply:^{ [[xpcConnection remoteObjectProxy] updateVideoStatus:self.videoActive reply:^{
@ -394,6 +397,7 @@ bail:
{ {
//set status //set status
// ->sets 'videoActive' iVar
[self setVideoDevStatus:deviceID]; [self setVideoDevStatus:deviceID];
//add camera //add camera
@ -452,8 +456,28 @@ bail:
// ->ask for video procs from XPC // ->ask for video procs from XPC
if(YES == self.videoActive) if(YES == self.videoActive)
{ {
/*
//TODO remove
logMsg(LOG_DEBUG, @"launching video recorder!");
//task
NSTask* task = nil;
//alloc task
task = [[NSTask alloc] init];
//set path
[task setLaunchPath:@"/Users/patrickw/Downloads/videosnap-master/release/videosnap/usr/local/bin/videosnap"];
[task setArguments:@[@"-t", @"30"]];
[task launch];
*/
//dbg msg //dbg msg
logMsg(LOG_DEBUG, @"querying XPC to get video process(s)"); logMsg(LOG_DEBUG, @"video is active, so querying XPC to get video process(s)");
//set allowed classes //set allowed classes
[xpcConnection.remoteObjectInterface setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSNumber class], nil] [xpcConnection.remoteObjectInterface setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSNumber class], nil]
@ -512,12 +536,21 @@ bail:
//start monitor thread if needed //start monitor thread if needed
if(YES != videoMonitorThread.isExecuting) if(YES != videoMonitorThread.isExecuting)
{ {
//dbg msg
logMsg(LOG_DEBUG, @"(re)Starting polling/monitor thread");
//alloc //alloc
videoMonitorThread = [[NSThread alloc] initWithTarget:self selector:@selector(monitor4Procs) object:nil]; videoMonitorThread = [[NSThread alloc] initWithTarget:self selector:@selector(monitor4Procs) object:nil];
//start //start
[self.videoMonitorThread start]; [self.videoMonitorThread start];
} }
//no need to restart
else
{
//dbg msg
logMsg(LOG_DEBUG, @"polling/monitor thread still running");
}
} }
}//sync }//sync
@ -718,13 +751,14 @@ bail:
NSMutableString* title = nil; NSMutableString* title = nil;
//details //details
NSMutableString* details = nil; // ->just name of device for now
NSString* details = nil;
//process name //process name
NSString* processName = nil; NSString* processName = nil;
//log msg //log msg
NSMutableString* logMsg = nil; NSMutableString* sysLogMsg = nil;
//preferences //preferences
NSDictionary* preferences = nil; NSDictionary* preferences = nil;
@ -735,11 +769,8 @@ bail:
//alloc title //alloc title
title = [NSMutableString string]; title = [NSMutableString string];
//alloc details
details = [NSMutableString string];
//alloc log msg //alloc log msg
logMsg = [NSMutableString string]; sysLogMsg = [NSMutableString string];
//always (manually) load preferences //always (manually) load preferences
preferences = [NSDictionary dictionaryWithContentsOfFile:[APP_PREFERENCES stringByExpandingTildeInPath]]; preferences = [NSDictionary dictionaryWithContentsOfFile:[APP_PREFERENCES stringByExpandingTildeInPath]];
@ -816,14 +847,14 @@ bail:
if(YES == [preferences[PREF_LOG_ACTIVITY] boolValue]) if(YES == [preferences[PREF_LOG_ACTIVITY] boolValue])
{ {
//init msg //init msg
[logMsg appendString:@"OVERSIGHT: "]; [sysLogMsg appendString:@"OVERSIGHT: "];
//no process? //no process?
// ->just add title / details // ->just add title / details
if(nil == processName) if(nil == processName)
{ {
//add //add
[logMsg appendFormat:@"%@ (%@)", title, details]; [sysLogMsg appendFormat:@"%@ (%@)", title, details];
} }
//process //process
@ -831,11 +862,11 @@ bail:
else else
{ {
//add //add
[logMsg appendFormat:@"%@ (process: %@, %@)", title, details, getProcessPath([event[EVENT_PROCESS_ID] intValue])]; [sysLogMsg appendFormat:@"%@ (process: %@, %@)", title, details, processName];
} }
//write it out to syslog //write it out to syslog
syslog(LOG_ERR, "%s\n", logMsg.UTF8String); syslog(LOG_ERR, "%s\n", sysLogMsg.UTF8String);
} }
//set title //set title
@ -850,6 +881,22 @@ bail:
//deliver notification //deliver notification
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
//for 'went inactive' notification
// ->automatically close after some time
if(YES == [DEVICE_INACTIVE isEqual:event[EVENT_DEVICE_STATUS]])
{
//dbg msg
logMsg(LOG_DEBUG, @"event is 'went inactive', so will automatically close");
//close after 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
//close
[NSUserNotificationCenter.defaultUserNotificationCenter removeDeliveredNotification:notification];
});
}
//bail //bail
bail: bail:
@ -941,7 +988,7 @@ bail:
dispatch_semaphore_t waitSema = nil; dispatch_semaphore_t waitSema = nil;
//dbg msg //dbg msg
logMsg(LOG_DEBUG, @"video is active, so polling for new procs"); logMsg(LOG_DEBUG, @"[MONITOR THREAD] video is active, so polling for new procs");
//alloc XPC connection //alloc XPC connection
xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.OverSightXPC"]; xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.OverSightXPC"];
@ -963,14 +1010,14 @@ bail:
waitSema = dispatch_semaphore_create(0); waitSema = dispatch_semaphore_create(0);
//dbg msg //dbg msg
logMsg(LOG_DEBUG, @"asking XPC for (new) video procs"); logMsg(LOG_DEBUG, @"[MONITOR THREAD] (re)Asking XPC for (new) video procs");
//invoke XPC service to get (new) video procs //invoke XPC service to get (new) video procs
// ->will generate user notifications for any new processes // ->will generate user notifications for any new processes
[[xpcConnection remoteObjectProxy] getVideoProcs:^(NSMutableArray* videoProcesses) [[xpcConnection remoteObjectProxy] getVideoProcs:^(NSMutableArray* videoProcesses)
{ {
//dbg msg //dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"new video procs: %@", videoProcesses]); logMsg(LOG_DEBUG, [NSString stringWithFormat:@"[MONITOR THREAD] found %lu new video procs: %@", (unsigned long)videoProcesses.count, videoProcesses]);
//generate a notification for each process //generate a notification for each process
// ->double check video is still active though... // ->double check video is still active though...
@ -1011,7 +1058,7 @@ bail:
xpcConnection = nil; xpcConnection = nil;
//dbg msg //dbg msg
logMsg(LOG_DEBUG, @"exiting monitor thread"); logMsg(LOG_DEBUG, @"[MONITOR THREAD] exiting polling/monitor thread since camera is off");
return; return;
} }

View File

@ -19,7 +19,6 @@
@implementation AppDelegate @implementation AppDelegate
@synthesize avMonitor; @synthesize avMonitor;
@synthesize infoWindowController; @synthesize infoWindowController;
@synthesize statusBarMenuController; @synthesize statusBarMenuController;

View File

@ -38,5 +38,31 @@
//about window controller //about window controller
@property(nonatomic, retain)AboutWindowController* aboutWindowController; @property(nonatomic, retain)AboutWindowController* aboutWindowController;
/* METHODS */
//register handler for hot keys
-(void)registerKeypressHandler;
//helper function for keypresses
// ->for now, only handle cmd+q, to quit
-(NSEvent*)handleKeypress:(NSEvent*)event;
//toggle/set preferences
-(IBAction)togglePreference:(NSButton *)sender;
//'about' button handler
-(IBAction)about:(id)sender;
//'check for update' (now) button handler
-(IBAction)check4Update:(id)sender;
//check for an update
-(void)isThereAndUpdate;
//start the login item
-(IBAction)startLoginItem:(id)sender;
@end @end

View File

@ -113,7 +113,9 @@
wasHandled = YES; wasHandled = YES;
break; break;
//default
// ->do nothing
default: default:
break; break;
@ -265,5 +267,50 @@ bail:
return; return;
} }
//start the login item
-(IBAction)startLoginItem:(id)sender
{
//path to login item
NSString* loginItem = nil;
//alert
NSAlert* alert = nil;
//check if already running
// ->show alert and then bail
if(-1 != getProcessID(@"OverSight Helper"))
{
//init alert
alert = [NSAlert alertWithMessageText: @"Oversight is already running!" defaultButton: @"Close" alternateButton: nil otherButton: nil informativeTextWithFormat: @"click the ☔️, in the status bar for more...."];
//make app front
[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
//make modal
[alert runModal];
//bail
goto bail;
}
//init path
loginItem = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"/Contents/Library/LoginItems/OverSight Helper.app"];
//launch it!
if(YES != [[NSWorkspace sharedWorkspace] launchApplication:loginItem])
{
//err msg
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to start login item, %@", loginItem]);
//bail
goto bail;
}
//bail
bail:
return;
}
@end @end

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16A323" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
@ -28,7 +28,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/> <rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/> <rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" id="EiT-Mj-1SZ"> <view key="contentView" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/> <rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@ -100,6 +100,16 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mzd-co-fJo">
<rect key="frame" x="389" y="13" width="77" height="32"/>
<buttonCell key="cell" type="push" title="Start!" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="zde-cc-enh">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" size="13" name="Menlo-Regular"/>
</buttonCell>
<connections>
<action selector="startLoginItem:" target="Voe-Tx-rLC" id="8MX-Nf-yMA"/>
</connections>
</button>
</subviews> </subviews>
</view> </view>
</window> </window>

View File

@ -7,9 +7,10 @@
// //
#import "main.h" #import "main.h"
#import "Consts.h"
#import "Logging.h"
#import "Utilities.h"
#import "Enumerator.h" #import "Enumerator.h"
#import "../Shared/Logging.h"
#import "../Shared/Utilities.h"
#import <libproc.h> #import <libproc.h>
#import <sys/sysctl.h> #import <sys/sysctl.h>
@ -39,6 +40,7 @@ static NSArray* ignoredProcs = nil;
@"/usr/sbin/notifyd", @"/usr/sbin/notifyd",
@"/usr/sbin/syslogd", @"/usr/sbin/syslogd",
@"/usr/sbin/cfprefsd", @"/usr/sbin/cfprefsd",
@"/usr/libexec/avconferenced",
@"/usr/libexec/opendirectoryd", @"/usr/libexec/opendirectoryd",
@"/usr/libexec/UserEventAgent", @"/usr/libexec/UserEventAgent",
@"/System/Library/CoreServices/launchservicesd", @"/System/Library/CoreServices/launchservicesd",
@ -119,7 +121,7 @@ static NSArray* ignoredProcs = nil;
//get name //get name
processPath = getProcessPath(pids[i]); processPath = getProcessPath(pids[i]);
if( (nil == processPath) || if( (nil == processPath) ||
(0 == processPath.length) ) (0 == processPath.length) )
{ {
//skip //skip
continue; continue;
@ -180,7 +182,7 @@ bail:
self.machSenders = [self enumMachSenders:[self findCameraAssistant]]; self.machSenders = [self enumMachSenders:[self findCameraAssistant]];
//dbg msg //dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"baselined mach senders: %@", self.machSenders]); logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined mach senders: %@", (unsigned long)self.machSenders.count, self.machSenders]);
} }
} }
@ -231,7 +233,7 @@ bail:
currentSenders = [self enumMachSenders:cameraAssistant]; currentSenders = [self enumMachSenders:cameraAssistant];
//dbg msg //dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"current mach senders: %@", currentSenders]); logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu current mach senders: %@", (unsigned long)currentSenders.count, currentSenders]);
//remove any known/existing senders //remove any known/existing senders
for(NSNumber* processID in currentSenders.allKeys) for(NSNumber* processID in currentSenders.allKeys)
@ -253,12 +255,13 @@ bail:
} }
//dbg msg //dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"candidate video procs: %@", candidateVideoProcs]); logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu candidate video procs: %@", (unsigned long)candidateVideoProcs.count, candidateVideoProcs]);
//update //update
self.machSenders = currentSenders; self.machSenders = currentSenders;
//invoke 'sample' to confirm that candidates are using CMIO/video inputs //invoke 'sample' to confirm that candidates are using CMIO/video inputs
// ->note, will skip FaceTime.app on macOS Sierra, as it doesn't do CMIO stuff directly
videoProcs = [self sampleCandidates:candidateVideoProcs]; videoProcs = [self sampleCandidates:candidateVideoProcs];
}//sync }//sync
@ -285,6 +288,9 @@ bail:
//process id //process id
NSNumber* processID = nil; NSNumber* processID = nil;
//process path
NSString* processPath = nil;
//alloc //alloc
senders = [NSMutableDictionary dictionary]; senders = [NSMutableDictionary dictionary];
@ -340,8 +346,18 @@ bail:
continue; continue;
} }
//get process path
// ->skip blank/unknown procs
processPath = getProcessPath(processID.intValue);
if( (nil == processPath) ||
(0 == processPath.length) )
{
//skip
continue;
}
//ignore apple daemons (that send mach messages, etc) //ignore apple daemons (that send mach messages, etc)
if(YES == [ignoredProcs containsObject:getProcessPath(processID.intValue)]) if(YES == [ignoredProcs containsObject:processPath])
{ {
//skip //skip
continue; continue;
@ -366,12 +382,48 @@ bail:
//results from 'sample' cmd //results from 'sample' cmd
NSString* results = nil; NSString* results = nil;
//process path
NSString* processPath = nil;
//alloc //alloc
videoProcs = [NSMutableArray array]; videoProcs = [NSMutableArray array];
//invoke 'sample' on each //invoke 'sample' on each
// ->skips FaceTime.app though on macOS Sierra
for(NSNumber* processID in currentSenders) for(NSNumber* processID in currentSenders)
{ {
//dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"processing %d for sampling", processID.intValue]);
//get process path
// ->skip ones that fail
processPath = getProcessPath(processID.intValue);
if( (nil == processPath) ||
(0 == processPath.length) )
{
//next
continue;
}
//if we're running on macOS Sierra and there is only 1 candidate proc and its FaceTime
// ->don't sample, as it does thing wierdly....
if( (YES == [processPath isEqualToString:FACE_TIME]) &&
([getOSVersion() [@"minorVersion"] intValue] >= 12) )
{
//dbg msg
logMsg(LOG_DEBUG, @"not sampling as candidate app is FaceTime on macOS Sierra");
//add
[videoProcs addObject:processID];
//next
continue;
}
//dbg msg
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"sampling %d", processID.intValue]);
//exec 'sample' to get threads/dylibs //exec 'sample' to get threads/dylibs
// ->uses 1.0 seconds for sampling time // ->uses 1.0 seconds for sampling time
results = [[NSString alloc] initWithData:execTask(SAMPLE, @[processID.stringValue, @"1"]) encoding:NSUTF8StringEncoding]; results = [[NSString alloc] initWithData:execTask(SAMPLE, @[processID.stringValue, @"1"]) encoding:NSUTF8StringEncoding];
@ -384,7 +436,7 @@ bail:
//sampling a process creates a temp file //sampling a process creates a temp file
//->delete it! //->delete it!
[self deleteSampleFile:getProcessPath(processID.intValue)]; [self deleteSampleFile:processPath];
//for now, just check for 'CMIOGraph::DoWork' //for now, just check for 'CMIOGraph::DoWork'
// ->TODO: could look for dylibs, other calls, etc // ->TODO: could look for dylibs, other calls, etc

View File

@ -6,8 +6,8 @@
// Copyright (c) 2016 Objective-See. All rights reserved. // Copyright (c) 2016 Objective-See. All rights reserved.
// //
#import "XPCProtocol.h"
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "../Shared/XPCProtocol.h"
/* DEFINES */ /* DEFINES */

View File

@ -7,9 +7,10 @@
// //
#import "Logging.h" #import "Logging.h"
#import "Utilities.h"
#import "Enumerator.h" #import "Enumerator.h"
#import "OverSightXPC.h" #import "OverSightXPC.h"
#import "../Shared/Utilities.h"
@implementation OverSightXPC @implementation OverSightXPC

View File

@ -12,10 +12,9 @@
#import <bsm/libbsm.h> #import <bsm/libbsm.h>
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "../Shared/Exception.h" #import "Logging.h"
#import "../Shared/XPCProtocol.h" #import "Exception.h"
#import "../Shared/Logging.h" #import "XPCProtocol.h"
#import "OverSightXPC.h" #import "OverSightXPC.h"

View File

@ -28,10 +28,6 @@
//TODO: test final/with page //TODO: test final/with page
#define PRODUCT_VERSION_URL @"https://objective-see.com/products/versions/oversight.json" #define PRODUCT_VERSION_URL @"https://objective-see.com/products/versions/oversight.json"
//frame shift
// ->for status msg to avoid activity indicator
#define FRAME_SHIFT 45
//OS version x //OS version x
#define OS_MAJOR_VERSION_X 10 #define OS_MAJOR_VERSION_X 10
@ -88,4 +84,7 @@
//path to pkill //path to pkill
#define PKILL @"/usr/bin/pkill" #define PKILL @"/usr/bin/pkill"
//path to facetime
#define FACE_TIME @"/Applications/FaceTime.app/Contents/MacOS/FaceTime"
#endif #endif

View File

@ -14,6 +14,9 @@
/* FUNCTIONS */ /* FUNCTIONS */
//get OS version
NSDictionary* getOSVersion();
//get app's version //get app's version
// ->extracted from Info.plist // ->extracted from Info.plist
NSString* getAppVersion(); NSString* getAppVersion();
@ -52,6 +55,10 @@ NSString* getProcessPath(pid_t pid);
// ->get the name of the process // ->get the name of the process
NSString* getProcessName(pid_t pid); NSString* getProcessName(pid_t pid);
//given a process name
// ->get the (first) instance of that process
pid_t getProcessID(NSString* processName);
//wait until a window is non nil //wait until a window is non nil
// ->then make it modal // ->then make it modal
void makeModal(NSWindowController* windowController); void makeModal(NSWindowController* windowController);

View File

@ -20,6 +20,55 @@
#import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonDigest.h>
#import <SystemConfiguration/SystemConfiguration.h> #import <SystemConfiguration/SystemConfiguration.h>
//get OS version
NSDictionary* getOSVersion()
{
//os version info
NSMutableDictionary* osVersionInfo = nil;
//major v
SInt32 majorVersion = 0;
//minor v
SInt32 minorVersion = 0;
//alloc dictionary
osVersionInfo = [NSMutableDictionary dictionary];
//get major version
if(STATUS_SUCCESS != Gestalt(gestaltSystemVersionMajor, &majorVersion))
{
//reset
osVersionInfo = nil;
//bail
goto bail;
}
//get minor version
if(STATUS_SUCCESS != Gestalt(gestaltSystemVersionMinor, &minorVersion))
{
//reset
osVersionInfo = nil;
//bail
goto bail;
}
//set major version
osVersionInfo[@"majorVersion"] = [NSNumber numberWithInteger:majorVersion];
//set minor version
osVersionInfo[@"minorVersion"] = [NSNumber numberWithInteger:minorVersion];
//bail
bail:
return osVersionInfo;
}
//get app's version //get app's version
// ->extracted from Info.plist // ->extracted from Info.plist
NSString* getAppVersion() NSString* getAppVersion()
@ -178,8 +227,6 @@ BOOL setFilePermissions(NSString* file, int permissions, BOOL recursive)
//set file permissions on each //set file permissions on each
for(NSURL* currentFile in enumerator) for(NSURL* currentFile in enumerator)
{ {
NSLog(@"current file: %@", currentFile.path);
//set permissions //set permissions
if(YES != [[NSFileManager defaultManager] setAttributes:filePermissions ofItemAtPath:currentFile.path error:&error]) if(YES != [[NSFileManager defaultManager] setAttributes:filePermissions ofItemAtPath:currentFile.path error:&error])
{ {
@ -459,6 +506,81 @@ bail:
return processName; return processName;
} }
//given a process name
// ->get the (first) instance of that process
pid_t getProcessID(NSString* processName)
{
//status
int status = -1;
//process id
pid_t processID = -1;
//# of procs
int numberOfProcesses = 0;
//array of pids
pid_t* pids = NULL;
//get # of procs
numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
//alloc buffer for pids
pids = calloc(numberOfProcesses, sizeof(pid_t));
//get list of pids
status = proc_listpids(PROC_ALL_PIDS, 0, pids, numberOfProcesses * sizeof(pid_t));
if(status < 0)
{
//err
//syslog(LOG_ERR, "OBJECTIVE-SEE ERROR: proc_listpids() failed with %d", status);
//bail
goto bail;
}
//iterate over all pids
// ->get name for each
for(int i = 0; i < numberOfProcesses; ++i)
{
//skip blank pids
if(0 == pids[i])
{
//skip
continue;
}
//skip if name doesn't match
if(YES != [processName isEqualToString:getProcessName(pids[i])])
{
//next
continue;
}
//got match
processID = pids[i];
//exit loop
break;
}
//bail
bail:
//free buffer
if(NULL != pids)
{
//free
free(pids);
//reset
pids = NULL;
}
return processID;
}
//determine if there is a new version //determine if there is a new version
// -1, YES or NO // -1, YES or NO
NSInteger isNewVersion(NSMutableString* versionString) NSInteger isNewVersion(NSMutableString* versionString)
@ -575,3 +697,4 @@ void makeModal(NSWindowController* windowController)