diff --git a/Installer.xcodeproj/project.pbxproj b/Installer.xcodeproj/project.pbxproj
index 3ee8cd2..a7934df 100644
--- a/Installer.xcodeproj/project.pbxproj
+++ b/Installer.xcodeproj/project.pbxproj
@@ -172,7 +172,7 @@
7D24C85D1D2CDEA7009932EE /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0800;
+ LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Objective-See";
TargetAttributes = {
7D24C8641D2CDEA7009932EE = {
@@ -229,7 +229,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "#for normal builds\n# ->just copy in app\n#cp -R -f $BUILT_PRODUCTS_DIR/OverSight.app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/\n\n#for achieving\n# ->first build OverSight in release mode (don't archive it)\n# then archive (this) installer app\ncp -R -f ~/objective-see/OverSight/DerivedData/OverSight/Build/Products/Release/OverSight.app ~/objective-see/OverSight/DerivedData/OverSight/Build/Intermediates/ArchiveIntermediates/Installer/BuildProductsPath/Release/OverSight_Installer.app/Contents/Resources/\n";
+ shellScript = "#for normal builds\n# ->just copy in app\n#cp -R -f $BUILT_PRODUCTS_DIR/OverSight.app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Resources/\n\n#for achieving\n# ->first build OverSight in release mode (don't archive it)\n# then archive (this) installer app\n#cp -R -f ~/objective-see/OverSight/DerivedData/OverSight/Build/Products/Release/OverSight.app ~/objective-see/OverSight/DerivedData/OverSight/Build/Intermediates/ArchiveIntermediates/Installer/BuildProductsPath/Release/OverSight_Installer.app/Contents/Resources/\n";
};
/* End PBXShellScriptBuildPhase section */
@@ -273,14 +273,20 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -319,14 +325,20 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
diff --git a/Installer/AppDelegate.m b/Installer/AppDelegate.m
index 33c6a3c..5f2951f 100644
--- a/Installer/AppDelegate.m
+++ b/Installer/AppDelegate.m
@@ -72,6 +72,9 @@ bail:
//alloc/init
configureWindowController = [[ConfigureWindowController alloc] initWithWindowNibName:@"ConfigureWindowController"];
+ //indicated title bar is tranparent (too)
+ self.configureWindowController.window.titlebarAppearsTransparent = YES;
+
//display it
// ->call this first to so that outlets are connected
[self.configureWindowController display];
diff --git a/Installer/Configure.m b/Installer/Configure.m
index c4840b5..fd58996 100644
--- a/Installer/Configure.m
+++ b/Installer/Configure.m
@@ -117,7 +117,6 @@
//no errors
wasConfigured = YES;
-//bail
bail:
return wasConfigured;
@@ -154,8 +153,8 @@ bail:
//path to login item
NSString* loginItem = nil;
- //logged in user
- NSString* user = nil;
+ //logged in user info
+ NSMutableDictionary* userInfo = nil;
//white list
NSString* whiteList = nil;
@@ -184,7 +183,7 @@ bail:
//remove xattrs
// ->otherwise app translocation causes issues
- execTask(XATTR, @[@"-cr", appPathDest], YES);
+ execTask(XATTR, @[@"-cr", appPathDest], NO);
//dbg msg
#ifdef DEBUG
@@ -194,9 +193,9 @@ bail:
//init path to login item
loginItem = [appPathDest stringByAppendingPathComponent:@"Contents/Library/LoginItems/OverSight Helper.app/Contents/MacOS/OverSight Helper"];
- //get user
- user = loggedinUser();
- if(nil == user)
+ //get user info
+ userInfo = loggedinUser();
+ if(nil == userInfo[@"user"])
{
//err msg
logMsg(LOG_ERR, @"failed to determine logged-in user");
@@ -206,7 +205,7 @@ bail:
}
//create app support directory
- if(YES != [self createAppSupport:user])
+ if(YES != [self createAppSupport:userInfo[@"user"]])
{
//err msg
logMsg(LOG_ERR, @"failed to create app support directory for current user");
@@ -221,7 +220,7 @@ bail:
#endif
//init path to whitelist
- whiteList = [[NSString pathWithComponents:@[@"/Users/", user, APP_SUPPORT_DIRECTORY]] stringByAppendingPathComponent:FILE_WHITELIST];
+ whiteList = [[NSString pathWithComponents:@[@"/Users/", userInfo[@"user"], APP_SUPPORT_DIRECTORY]] stringByAppendingPathComponent:FILE_WHITELIST];
//if whitelist exists
// ->make sure it's owned by root
@@ -232,8 +231,7 @@ bail:
}
//call into login item to install itself
- // ->runs as logged in user, so can access user's login items, etc
- execTask(SUDO, @[@"-u", user, loginItem, [NSString stringWithUTF8String:CMD_INSTALL]], YES);
+ execTask(loginItem, @[[NSString stringWithUTF8String:CMD_INSTALL]], NO);
//dbg msg
#ifdef DEBUG
@@ -266,7 +264,6 @@ bail:
//no error
wasInstalled = YES;
-//bail
bail:
return wasInstalled;
@@ -278,35 +275,20 @@ bail:
{
//flag
BOOL bStarted = NO;
-
- //logged in user
- NSString* user = nil;
-
+
//path to login item
NSString* loginItem = nil;
- //get user
- user = loggedinUser();
- if(nil == user)
- {
- //err msg
- logMsg(LOG_ERR, @"failed to determine logged-in user");
-
- //bail
- goto bail;
- }
-
//init path
loginItem = [[APPS_FOLDER stringByAppendingPathComponent:APP_NAME] stringByAppendingPathComponent:@"Contents/Library/LoginItems/OverSight Helper.app/Contents/MacOS/OverSight Helper"];
//start it!
// ->don't wait, as it won't exit
- execTask(SUDO, @[@"-u", user, loginItem], NO);
+ execTask(loginItem, nil, NO);
//happy
bStarted = YES;
-//bail
bail:
return bStarted;
@@ -350,8 +332,8 @@ bail:
//error
NSError* error = nil;
- //logged in user
- NSString* user = nil;
+ //logged in user info
+ NSMutableDictionary* userInfo = nil;
//uninstall command
// ->changed between v1.0 and 1.1+
@@ -385,8 +367,8 @@ bail:
#endif
//get user
- user = loggedinUser();
- if(nil == user)
+ userInfo = loggedinUser();
+ if(nil == userInfo[@"user"])
{
//err msg
logMsg(LOG_ERR, @"failed to determine logged-in user");
@@ -401,8 +383,7 @@ bail:
#endif
//call into login item to uninstall itself
- // ->runs as logged in user, so can access user's login items, etc
- execTask(SUDO, @[@"-u", user, loginItem, uninstallCmd], YES);
+ execTask(loginItem, @[uninstallCmd], YES);
//dbg msg
#ifdef DEBUG
@@ -436,13 +417,13 @@ bail:
#endif
//delete app's app support folder
- if(YES == [[NSFileManager defaultManager] fileExistsAtPath:[self appSupportPath:user]])
+ if(YES == [[NSFileManager defaultManager] fileExistsAtPath:[self appSupportPath:userInfo[@"user"]]])
{
//delete
- if(YES != [self removeAppSupport:user])
+ if(YES != [self removeAppSupport:userInfo[@"user"]])
{
//err msg
- logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to delete app support directory %@", [self appSupportPath:user]]);
+ logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to delete app support directory %@", [self appSupportPath:userInfo[@"user"]]]);
//set flag
bAnyErrors = YES;
@@ -455,7 +436,7 @@ bail:
else
{
//dbg msg
- logMsg(LOG_DEBUG, [NSString stringWithFormat:@"removed app support directory %@", [self appSupportPath:user]]);
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"removed app support directory %@", [self appSupportPath:userInfo[@"user"]]]);
}
#endif
@@ -469,7 +450,6 @@ bail:
wasUninstalled = YES;
}
-//bail
bail:
return wasUninstalled;
@@ -531,7 +511,6 @@ bail:
//happy
createdDirectory = YES;
-//bail
bail:
return createdDirectory;
@@ -580,12 +559,9 @@ bail:
//happy
removedDirectory = YES;
-//bail
bail:
return removedDirectory;
}
-
@end
-
diff --git a/Installer/ConfigureWindowController.m b/Installer/ConfigureWindowController.m
index 09bd031..875d943 100644
--- a/Installer/ConfigureWindowController.m
+++ b/Installer/ConfigureWindowController.m
@@ -81,6 +81,9 @@
// ->center, make front, set bg to white, etc
-(void)display
{
+ //indicated title bar is tranparent (too)
+ self.window.titlebarAppearsTransparent = YES;
+
//center window
[[self window] center];
diff --git a/Installer/Info.plist b/Installer/Info.plist
index a9b7be4..d30ce7b 100644
--- a/Installer/Info.plist
+++ b/Installer/Info.plist
@@ -17,11 +17,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.1.2
+ 1.2.0
CFBundleSignature
????
CFBundleVersion
- 1.1.2
+ 1.2.0
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
NSHumanReadableCopyright
diff --git a/Installer/main.h b/Installer/main.h
index 8aa5717..644a098 100644
--- a/Installer/main.h
+++ b/Installer/main.h
@@ -21,9 +21,9 @@
BOOL spawnAsRoot(const char* path2Self);
//install
-BOOL cmdlineInstall();
+BOOL cmdlineInstall(void);
//uninstall
-BOOL cmdlineUninstall();
+BOOL cmdlineUninstall(void);
#endif /* main_h */
diff --git a/Installer/main.m b/Installer/main.m
index 676e46f..b78f825 100644
--- a/Installer/main.m
+++ b/Installer/main.m
@@ -17,100 +17,101 @@ int main(int argc, const char * argv[])
//return var
int retVar = -1;
- @autoreleasepool
+ //pool
+ @autoreleasepool {
+
+ //handle '-install' / '-uninstall'
+ // ->this performs non-UI logic for easier automated deployment
+ if( (argc >= 2) &&
+ ( (0 == strcmp(argv[1], CMD_INSTALL)) || (0 == strcmp(argv[1], CMD_UNINSTALL)) ) )
{
- //handle '-install' / '-uninstall'
- // ->this performs non-UI logic for easier automated deployment
- if( (argc >= 2) &&
- ( (0 == strcmp(argv[1], CMD_INSTALL)) || (0 == strcmp(argv[1], CMD_UNINSTALL)) ) )
- {
- //first check rooot
- if(0 != geteuid())
- {
- //err msg
- printf("\nERROR: '%s' option, requires root\n\n", argv[1]);
-
- //bail
- goto bail;
- }
-
- //handle install
- if(0 == strcmp(argv[1], CMD_INSTALL))
- {
- //install
- if(YES != cmdlineInstall())
- {
- //err msg
- printf("\nERROR: install failed\n\n");
-
- //bail
- goto bail;
- }
-
- //dbg msg
- printf("OVERSIGHT: install ok!\n");
-
- //happy
- retVar = 0;
- }
-
- //handle uninstall
- else if(0 == strcmp(argv[1], CMD_UNINSTALL))
- {
- //uninstall
- if(YES != cmdlineUninstall())
- {
- //err msg
- printf("\nERROR: install failed\n\n");
- }
-
- //dbg msg
- printf("OVERSIGHT: uninstall ok!\n");
-
- //happy
- retVar = 0;
- }
-
- //bail
- goto bail;
-
- }//args
-
- //check for r00t
- // ->then spawn self via auth exec
+ //first check rooot
if(0 != geteuid())
{
- //dbg msg
- #ifdef DEBUG
- logMsg(LOG_DEBUG, @"non-root installer instance");
- #endif
+ //err msg
+ printf("\nERROR: '%s' option, requires root\n\n", argv[1]);
- //spawn as root
- if(YES != spawnAsRoot(argv[0]))
+ //bail
+ goto bail;
+ }
+
+ //handle install
+ if(0 == strcmp(argv[1], CMD_INSTALL))
+ {
+ //install
+ if(YES != cmdlineInstall())
{
//err msg
- logMsg(LOG_ERR, @"failed to spawn self as r00t");
+ printf("\nERROR: install failed\n\n");
//bail
goto bail;
}
+ //dbg msg
+ printf("OVERSIGHT: install ok!\n");
+
//happy
retVar = 0;
}
- //otherwise
- // ->just kick off app, as we're root now
- else
+ //handle uninstall
+ else if(0 == strcmp(argv[1], CMD_UNINSTALL))
{
- //dbg msg
- #ifdef DEBUG
- logMsg(LOG_DEBUG, @"root installer instance");
- #endif
+ //uninstall
+ if(YES != cmdlineUninstall())
+ {
+ //err msg
+ printf("\nERROR: install failed\n\n");
+ }
- //app away
- retVar = NSApplicationMain(argc, (const char **)argv);
+ //dbg msg
+ printf("OVERSIGHT: uninstall ok!\n");
+
+ //happy
+ retVar = 0;
}
+
+ //bail
+ goto bail;
+
+ }//args
+
+ //check for r00t
+ // ->then spawn self via auth exec
+ if(0 != geteuid())
+ {
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, @"non-root installer instance");
+ #endif
+
+ //spawn as root
+ if(YES != spawnAsRoot(argv[0]))
+ {
+ //err msg
+ logMsg(LOG_ERR, @"failed to spawn self as r00t");
+
+ //bail
+ goto bail;
+ }
+
+ //happy
+ retVar = 0;
+ }
+
+ //otherwise
+ // ->just kick off app, as we're root now
+ else
+ {
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, @"root installer instance");
+ #endif
+
+ //app away
+ retVar = NSApplicationMain(argc, (const char **)argv);
+ }
}//pool
diff --git a/LoginItem/AVMonitor.m b/LoginItem/AVMonitor.m
index 8d8b3e6..ec7b131 100644
--- a/LoginItem/AVMonitor.m
+++ b/LoginItem/AVMonitor.m
@@ -239,7 +239,7 @@ bail:
{
//signal sema
dispatch_semaphore_signal(waitSema);
-
+
}];
//wait until XPC is done
@@ -414,9 +414,7 @@ bail:
{
//close connection
[xpcConnection invalidate];
-
- //nil out
- xpcConnection = nil;
+
}
return bRet;
@@ -474,7 +472,7 @@ bail:
}
//helper function
-// ->determines if video went active/inactive then invokes notification generator method
+// determines if video went active/inactive then invokes notification generator method
-(void)handleVideoNotification:(CMIOObjectID)deviceID addresses:(const CMIOObjectPropertyAddress[]) addresses
{
//event dictionary
@@ -517,9 +515,14 @@ bail:
[devices addObject:@{EVENT_DEVICE:self.mic, EVENT_DEVICE_STATUS:@(self.audioActive)}];
}
- //send msg to status menu
- // ->update menu to show (all) devices & their status
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:devices];
+ //update status menu
+ // run on main thread, since its a UI update
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //update status menu
+ [((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:devices];
+
+ });
//add timestamp
event[EVENT_TIMESTAMP] = [NSDate date];
@@ -579,9 +582,6 @@ bail:
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
-
//dbg msg
#ifdef DEBUG
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"video procs from XPC: %@", videoProcesses]);
@@ -594,7 +594,14 @@ bail:
event[EVENT_PROCESS_ID] = processID;
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
+
}
//if no consumer process was found
@@ -605,7 +612,13 @@ bail:
event[EVENT_PROCESS_ID] = @0;
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
}
//signal sema
@@ -625,11 +638,15 @@ bail:
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
-
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
+
}
//poll for new video procs
@@ -694,8 +711,27 @@ bail:
// ->invoked when video changes & just calls helper function
CMIOObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const CMIOObjectPropertyAddress addresses[])
{
- //invoke helper function
- [self handleVideoNotification:deviceID addresses:addresses];
+ //on main thread?
+ // handle on background thread
+ if(YES == [NSThread isMainThread])
+ {
+ //invoke in background
+ // XPC stuff might be slow!
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+ ^{
+
+ //handle notification
+ [self handleVideoNotification:deviceID addresses:addresses];
+
+ });
+ }
+ //on background thread
+ // just can invoke as it
+ else
+ {
+ //handle notification
+ [self handleVideoNotification:deviceID addresses:addresses];
+ }
};
//register (add) property block listener
@@ -764,6 +800,9 @@ bail:
//event dictionary
NSMutableDictionary* event = nil;
+ //devices
+ NSMutableArray* devices = nil;
+
//xpc connection
__block NSXPCConnection* xpcConnection = nil;
@@ -772,6 +811,9 @@ bail:
//init dictionary
event = [NSMutableDictionary dictionary];
+
+ //init array for devices
+ devices = [NSMutableArray array];
//sync
@synchronized (self)
@@ -781,10 +823,29 @@ bail:
// ->updates 'audioActive' iVar
[self setAudioDevStatus:deviceID];
- //send msg to status menu
- // ->update menu to show (all) devices & their status
- [((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:@[@{EVENT_DEVICE:self.mic, EVENT_DEVICE_STATUS:@(self.audioActive)},@{EVENT_DEVICE:self.camera, EVENT_DEVICE_STATUS:@(self.videoActive)}]];
-
+ //add camera
+ if(nil != self.camera)
+ {
+ //add
+ [devices addObject:@{EVENT_DEVICE:self.camera, EVENT_DEVICE_STATUS:@(self.videoActive)}];
+ }
+
+ //add mic
+ if(nil != self.mic)
+ {
+ //add
+ [devices addObject:@{EVENT_DEVICE:self.mic, EVENT_DEVICE_STATUS:@(self.audioActive)}];
+ }
+
+ //update status menu
+ // run on main thread, since its a UI update
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //update status menu
+ [((AppDelegate*)[[NSApplication sharedApplication] delegate]).statusBarMenuController updateStatusItemMenu:devices];
+
+ });
+
//add timestamp
event[EVENT_TIMESTAMP] = [NSDate date];
@@ -804,28 +865,28 @@ bail:
//set remote object interface
xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
-
+
//resume
[xpcConnection resume];
-
+
//init wait semaphore
waitSema = dispatch_semaphore_create(0);
//tell XPC about audio status
// ->for example, when audio is active, will stop baselining
[[xpcConnection remoteObjectProxy] updateAudioStatus:self.audioActive reply:^{
-
+
//signal sema
dispatch_semaphore_signal(waitSema);
}];
-
+
//wait until XPC is done
// ->XPC reply block will signal semaphore
dispatch_semaphore_wait(waitSema, DISPATCH_TIME_FOREVER);
-
- //if video just started
- // ->ask for video procs from XPC
+
+ //if audio just started
+ // ->ask for audio procs from XPC
if(YES == self.audioActive)
{
//dbg msg
@@ -843,9 +904,6 @@ bail:
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
-
//dbg msg
#ifdef DEBUG
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"audio procs from XPC: %@", audioProcesses]);
@@ -858,7 +916,13 @@ bail:
event[EVENT_PROCESS_ID] = processID;
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
}
//if no consumer process was found
@@ -869,7 +933,13 @@ bail:
event[EVENT_PROCESS_ID] = @0;
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
}
//signal sema
@@ -889,11 +959,14 @@ bail:
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
-
//generate notification
- [self generateNotification:event];
+ // do on main thread since its a UI event
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ //generate notification
+ [self generateNotification:event];
+
+ });
}
}//sync
@@ -930,7 +1003,27 @@ bail:
// ->invoked when audio changes & just calls helper function
AudioObjectPropertyListenerBlock listenerBlock = ^(UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses)
{
- [self handleAudioNotification:deviceID];
+ //on main thread?
+ // handle on background thread
+ if(YES == [NSThread isMainThread])
+ {
+ //invoke in background
+ // XPC stuff might be slow!
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+ ^{
+
+ //handle notification
+ [self handleAudioNotification:deviceID];
+
+ });
+ }
+ //on background thread
+ // just can invoke as it
+ else
+ {
+ //handle notification
+ [self handleAudioNotification:deviceID];
+ }
};
//add property listener for audio changes
@@ -957,6 +1050,9 @@ bail:
// ->handles extra logic like ignore whitelisted apps, disable alerts (if user has turned that off), etc
-(void)generateNotification:(NSMutableDictionary*)event
{
+ //pool
+ @autoreleasepool {
+
//notification
NSUserNotification* notification = nil;
@@ -1291,6 +1387,8 @@ bail:
}
}
+ }//pool
+
//bail
bail:
@@ -1307,6 +1405,9 @@ bail:
// ->handle rule creation, blocking/killing proc, etc
-(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
+ //pool
+ @autoreleasepool {
+
//xpc connection
__block NSXPCConnection* xpcConnection = nil;
@@ -1524,11 +1625,11 @@ bail:
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
}];
}//user clicked 'block'
+
+ }//pool
//bail
bail:
@@ -1607,9 +1708,13 @@ bail:
}
//monitor for new procs (video only at the moment)
-// ->runs until video is no longer in use (set elsewhere)
+// runs until video is no longer in use (set elsewhere)
-(void)monitor4Procs
{
+
+ //pool
+ @autoreleasepool {
+
//xpc connection
NSXPCConnection* xpcConnection = nil;
@@ -1621,22 +1726,12 @@ bail:
logMsg(LOG_DEBUG, @"[MONITOR THREAD] video is active, so polling for new procs");
#endif
- //alloc XPC connection
- xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.OverSightXPC"];
-
- //set remote object interface
- xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
-
- //set classes
- // ->arrays/numbers ok to vend
- [xpcConnection.remoteObjectInterface setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSNumber class], nil]
- forSelector: @selector(getVideoProcs:reply:) argumentIndex: 0 ofReply: YES];
- //resume
- [xpcConnection resume];
-
//poll while video is active
while(YES == self.videoActive)
{
+ //pool
+ @autoreleasepool {
+
//init wait semaphore
waitSema = dispatch_semaphore_create(0);
@@ -1644,6 +1739,20 @@ bail:
#ifdef DEBUG
logMsg(LOG_DEBUG, @"[MONITOR THREAD] (re)Asking XPC for (new) video procs");
#endif
+
+ //alloc XPC connection
+ xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.OverSightXPC"];
+
+ //set remote object interface
+ xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
+
+ //set classes
+ // ->arrays/numbers ok to vend
+ [xpcConnection.remoteObjectInterface setClasses: [NSSet setWithObjects: [NSMutableArray class], [NSNumber class], nil]
+ forSelector: @selector(getVideoProcs:reply:) argumentIndex: 0 ofReply: YES];
+ //resume
+ [xpcConnection resume];
+
//invoke XPC service to get (new) video procs
// ->will generate user notifications for any new processes
@@ -1652,7 +1761,7 @@ bail:
//dbg msg
#ifdef DEBUG
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"[MONITOR THREAD] found %lu new video procs: %@", (unsigned long)videoProcesses.count, videoProcesses]);
- #endif
+ #endif
//generate a notification for each process
// ->double check video is still active though...
@@ -1672,26 +1781,27 @@ bail:
//signal sema
dispatch_semaphore_signal(waitSema);
+ //invalidate
+ [xpcConnection invalidate];
+
}];
//wait until XPC is done
// ->XPC reply block will signal semaphore
dispatch_semaphore_wait(waitSema, DISPATCH_TIME_FOREVER);
+
+ }//pool
//nap
[NSThread sleepForTimeInterval:5.0f];
}//run until video (camera) is off
-//bail
+ //pool
+ }
+
bail:
- //close connection
- [xpcConnection invalidate];
-
- //nil out
- xpcConnection = nil;
-
//dbg msg
#ifdef DEBUG
logMsg(LOG_DEBUG, @"[MONITOR THREAD] exiting polling/monitor thread since camera is off");
diff --git a/LoginItem/AppDelegate.m b/LoginItem/AppDelegate.m
index 0657f47..0399523 100644
--- a/LoginItem/AppDelegate.m
+++ b/LoginItem/AppDelegate.m
@@ -10,6 +10,7 @@
#import "Logging.h"
#import "Utilities.h"
#import "AppDelegate.h"
+#import "XPCProtocol.h"
@interface AppDelegate ()
@@ -29,16 +30,30 @@
//preferences
NSDictionary* preferences = nil;
+ //logged in user info
+ NSMutableDictionary* userInfo = nil;
+
//dbg msg
#ifdef DEBUG
logMsg(LOG_DEBUG, @"starting login item app logic");
#endif
+ //get user
+ userInfo = loggedinUser();
+ if(nil == userInfo[@"user"])
+ {
+ //err msg
+ logMsg(LOG_ERR, @"failed to determine logged-in user");
+
+ //bail
+ goto bail;
+ }
+
//drop group privs
- setgid(getgid());
+ setgid([userInfo[@"gid"] intValue]);
//drop user privs
- setuid(getuid());
+ setuid([userInfo[@"uid"] intValue]);
//load preferences
preferences = [NSDictionary dictionaryWithContentsOfFile:[APP_PREFERENCES stringByExpandingTildeInPath]];
@@ -99,10 +114,12 @@
//dbg msg
// ->and to file
- logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging intialized");
-
+ logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging intialized (login item)");
}
-
+
+ //spawn 'heartbeat' thread to XPC to keep it open
+ [NSThread detachNewThreadSelector:@selector(heartBeat) toTarget:self withObject:nil];
+
//create/init av event monitor
avMonitor = [[AVMonitor alloc] init];
@@ -194,6 +211,60 @@ bail:
return;
}
+//ping XPC service to keep it alive
+-(void)heartBeat
+{
+ //pool
+ @autoreleasepool {
+
+ //xpc connection
+ __block NSXPCConnection* xpcConnection = nil;
+
+ //wait semaphore
+ dispatch_semaphore_t waitSema = nil;
+
+ //alloc XPC connection
+ xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.objective-see.OverSightXPC"];
+
+ //set remote object interface
+ xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCProtocol)];
+
+ //resume
+ [xpcConnection resume];
+
+ //forever
+ while(YES)
+ {
+ //init wait semaphore
+ waitSema = dispatch_semaphore_create(0);
+
+ #ifdef DEBUG
+ //dbg msg
+ logMsg(LOG_DEBUG, @"sending XPC heart beat request");
+ #endif
+
+ //XPC service to begin baselining mach messages
+ // ->wait, since want this to compelete before doing other things!
+ [[xpcConnection remoteObjectProxy] heartBeat:^(BOOL reply)
+ {
+ //signal sema
+ dispatch_semaphore_signal(waitSema);
+
+ }];
+
+ //wait until XPC is done
+ // ->XPC reply block will signal semaphore
+ dispatch_semaphore_wait(waitSema, DISPATCH_TIME_FOREVER);
+
+ //nap
+ [NSThread sleepForTimeInterval:3.0f];
+ }
+
+ }//pool
+
+ return;
+}
+
//going bye-bye
// ->close logging
-(void)applicationWillTerminate:(NSNotification *)notification
@@ -202,7 +273,7 @@ bail:
logMsg(LOG_DEBUG|LOG_TO_FILE, @"OverSight ending");
//log msg
- logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging deinitialized");
+ logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging deinitialized (login item)");
//stop logz
deinitLogging();
diff --git a/LoginItem/Info.plist b/LoginItem/Info.plist
index a11238c..06aa6dc 100644
--- a/LoginItem/Info.plist
+++ b/LoginItem/Info.plist
@@ -17,11 +17,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.1.2
+ 1.2.0
CFBundleSignature
????
CFBundleVersion
- 1.1.2
+ 1.2.0
LSUIElement
LSMinimumSystemVersion
diff --git a/LoginItem/RemeberWindowController.h b/LoginItem/RemeberWindowController.h
index caf1f51..64b16bb 100644
--- a/LoginItem/RemeberWindowController.h
+++ b/LoginItem/RemeberWindowController.h
@@ -31,7 +31,6 @@
//version label/string
@property (weak) IBOutlet NSTextField *windowText;
-
/* METHODS */
//save stuff into iVars
diff --git a/LoginItem/RemeberWindowController.m b/LoginItem/RemeberWindowController.m
index b854cad..10c1f02 100644
--- a/LoginItem/RemeberWindowController.m
+++ b/LoginItem/RemeberWindowController.m
@@ -137,9 +137,6 @@
//close connection
[xpcConnection invalidate];
- //nil out
- xpcConnection = nil;
-
}];
}
diff --git a/LoginItem/StatusBarMenu.m b/LoginItem/StatusBarMenu.m
index 7c38979..6fae470 100644
--- a/LoginItem/StatusBarMenu.m
+++ b/LoginItem/StatusBarMenu.m
@@ -66,6 +66,10 @@
//create/update status item menu
-(void)updateStatusItemMenu:(NSArray*)devices
{
+ //pool
+ @autoreleasepool
+ {
+
//menu
NSMenu* menu = nil;
@@ -194,6 +198,8 @@
//tie menu to status item
self.statusItem.menu = menu;
+ }//pool
+
return;
}
diff --git a/LoginItem/main.m b/LoginItem/main.m
index f96ab6c..e3f1c55 100644
--- a/LoginItem/main.m
+++ b/LoginItem/main.m
@@ -18,14 +18,44 @@ int main(int argc, const char * argv[])
//return var
int iReturn = 0;
+ //logged in user info
+ NSMutableDictionary* userInfo = nil;
+
+ //pool
+ @autoreleasepool
+ {
+
//dbg msg
#ifdef DEBUG
- logMsg(LOG_DEBUG, [NSString stringWithFormat:@"starting login item (args: %@/user: %@)", [[NSProcessInfo processInfo] arguments], NSUserName()]);
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"starting login item (args: %@/user: %@/%@)", [[NSProcessInfo processInfo] arguments], NSUserName(), loggedinUser()]);
#endif
//check for uninstall/install flags, and process to remove from whitelist
if(2 == argc)
{
+ //drops privs when installing/uninstalling
+ // do here, only for these as they then bail
+ if( (0 == strcmp(argv[1], CMD_INSTALL)) ||
+ (0 == strcmp(argv[1], CMD_UNINSTALL)) )
+ {
+ //get user
+ userInfo = loggedinUser();
+ if(nil == userInfo[@"user"])
+ {
+ //err msg
+ logMsg(LOG_ERR, @"failed to determine logged-in user");
+
+ //bail
+ goto bail;
+ }
+
+ //drop group privs
+ setgid([userInfo[@"gid"] intValue]);
+
+ //drop user privs
+ setuid([userInfo[@"uid"] intValue]);
+ }
+
//install
if(0 == strcmp(argv[1], CMD_INSTALL))
{
@@ -34,9 +64,6 @@ int main(int argc, const char * argv[])
logMsg(LOG_DEBUG, @"running install logic");
#endif
- //drop user privs
- setuid(getuid());
-
//install
if(YES != toggleLoginItem([NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]], ACTION_INSTALL_FLAG))
{
@@ -74,9 +101,6 @@ int main(int argc, const char * argv[])
logMsg(LOG_DEBUG, @"running uninstall logic");
#endif
- //drop user privs
- setuid(getuid());
-
//uninstall
if(YES != toggleLoginItem([NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]], ACTION_UNINSTALL_FLAG))
{
@@ -130,7 +154,8 @@ int main(int argc, const char * argv[])
//launch app normally
iReturn = NSApplicationMain(argc, argv);
-//bail
+ }//pool
+
bail:
return iReturn;
@@ -173,9 +198,6 @@ void unWhiteList(NSString* process, NSNumber* device)
//close connection
[xpcConnection invalidate];
-
- //nil out
- xpcConnection = nil;
}];
diff --git a/MainApp/AppDelegate.m b/MainApp/AppDelegate.m
index 0bc5190..ee18f55 100644
--- a/MainApp/AppDelegate.m
+++ b/MainApp/AppDelegate.m
@@ -244,7 +244,7 @@ bail:
else
{
//log msg
- logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging initialized");
+ logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging initialized (main app)");
}
}
//when logging is disabled
@@ -252,7 +252,7 @@ bail:
else
{
//log msg
- logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging deinitialized");
+ logMsg(LOG_DEBUG|LOG_TO_FILE, @"logging deinitialized (main app)");
//close
deinitLogging();
@@ -539,7 +539,6 @@ bail:
goto bail;
}
-
//bail
bail:
diff --git a/MainApp/Info.plist b/MainApp/Info.plist
index 26919b0..48b469c 100644
--- a/MainApp/Info.plist
+++ b/MainApp/Info.plist
@@ -15,11 +15,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.1.2
+ 1.2.0
CFBundleSignature
????
CFBundleVersion
- 1.1.2
+ 1.2.0
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
LSUIElement
diff --git a/MainApp/Rules.xib b/MainApp/Rules.xib
index c5204fc..03e7488 100644
--- a/MainApp/Rules.xib
+++ b/MainApp/Rules.xib
@@ -21,7 +21,7 @@
-
+
diff --git a/OverSight.xcodeproj/project.pbxproj b/OverSight.xcodeproj/project.pbxproj
index 16f08ba..af90098 100644
--- a/OverSight.xcodeproj/project.pbxproj
+++ b/OverSight.xcodeproj/project.pbxproj
@@ -413,7 +413,7 @@
8B57559319DA3E9500799E6B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0820;
+ LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Cory Bohon";
TargetAttributes = {
7DC9C8111D641A350017D143 = {
@@ -620,14 +620,20 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -667,14 +673,20 @@
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
diff --git a/OverSightXPC/Enumerator.h b/OverSightXPC/Enumerator.h
index 88df0f1..b255d59 100644
--- a/OverSightXPC/Enumerator.h
+++ b/OverSightXPC/Enumerator.h
@@ -33,6 +33,12 @@
/* PROPERTIES */
+//camera assistant pid
+@property pid_t cameraAssistantProcess;
+
+//core audio pid
+@property pid_t coreAudioProcess;
+
//flag indicating video is active
@property BOOL videoActive;
@@ -49,8 +55,6 @@
// ->IOService:/AppleACPIPlatformExpert/IOPMrootDomain/RootDomainUserClient
@property(nonatomic, retain)NSMutableDictionary* userClients;
-
-
/* METHODS */
//singleton interface
diff --git a/OverSightXPC/Enumerator.m b/OverSightXPC/Enumerator.m
index 36087ee..185e81b 100644
--- a/OverSightXPC/Enumerator.m
+++ b/OverSightXPC/Enumerator.m
@@ -23,8 +23,11 @@ static NSArray* ignoredProcs = nil;
@synthesize audioActive;
@synthesize userClients;
@synthesize videoActive;
+@synthesize coreAudioProcess;
@synthesize machSendersAudio;
@synthesize machSendersVideo;
+@synthesize cameraAssistantProcess;
+
//init
-(instancetype)init
@@ -78,13 +81,28 @@ static NSArray* ignoredProcs = nil;
// ->logic only exec'd while camera/mic is not in use, so these are all just baselined procs
-(void)start
{
- //camera assistant
- pid_t cameraAssistant = 0;
+ //flag
+ BOOL nap = NO;
//baseline forever
// ->though logic will skip if video or mic is active (respectively)
while(YES)
{
+ //le sleep?
+ if(nap == YES)
+ {
+ //nap
+ [NSThread sleepForTimeInterval:30];
+ }
+
+ //set flag
+ // from now on, want to wait a bit
+ nap = YES;
+
+ //pool
+ @autoreleasepool
+ {
+
//sync baselining
@synchronized(self)
{
@@ -97,31 +115,36 @@ static NSArray* ignoredProcs = nil;
#endif
//find camera assistant
- // ->first look for 'VDCAssistant'
- cameraAssistant = findProcess(VDC_ASSISTANT);
- if(0 == cameraAssistant)
+ // only do this once, or again, if it died
+ if( (0 == self.cameraAssistantProcess) ||
+ (YES != isProcessAlive(self.cameraAssistantProcess)) )
{
- //look for 'AppleCameraAssistant'
- cameraAssistant = findProcess(APPLE_CAMERA_ASSISTANT);
+ //find camera assistant
+ // ->first look for 'VDCAssistant'
+ self.cameraAssistantProcess = findProcess(VDC_ASSISTANT);
+ if(0 == self.cameraAssistantProcess)
+ {
+ //look for 'AppleCameraAssistant'
+ self.cameraAssistantProcess = findProcess(APPLE_CAMERA_ASSISTANT);
+ }
}
- //sanity check
- if(0 == cameraAssistant)
+ //baseline
+ if(0 != self.cameraAssistantProcess)
{
- //nap for a minute
- [NSThread sleepForTimeInterval:60];
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"camera assistent process: %d", self.coreAudioProcess]);
+ #endif
- //next
- continue;
+ //enumerate procs that have send mach messages
+ self.machSendersVideo = [self enumMachSenders:self.cameraAssistantProcess];
+
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined mach senders: %@", (unsigned long)self.machSendersVideo.count, self.machSendersVideo]);
+ #endif
}
-
- //enumerate procs that have send mach messages
- self.machSendersVideo = [self enumMachSenders:cameraAssistant];
-
- //dbg msg
- #ifdef DEBUG
- logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined mach senders: %@", (unsigned long)self.machSendersVideo.count, self.machSendersVideo]);
- #endif
}
//only baseline if audio isn't active
@@ -132,29 +155,47 @@ static NSArray* ignoredProcs = nil;
logMsg(LOG_DEBUG, @"baselining mach senders for audio...");
#endif
- //enumerate procs that have send mach messages
- self.machSendersAudio = [self enumMachSenders:findProcess(CORE_AUDIO)];
+ //find core audio
+ // only do this once, or again, if it died
+ if( (0 == self.coreAudioProcess) ||
+ (YES != isProcessAlive(self.coreAudioProcess)) )
+ {
+ //find core audio
+ self.coreAudioProcess = findProcess(CORE_AUDIO);
+ }
- //dbg msg
- #ifdef DEBUG
- logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined mach senders: %@", (unsigned long)self.machSendersAudio.count, self.machSendersVideo]);
-
- //dbg msg
- logMsg(LOG_DEBUG, @"baselining i/o registry entries for audio...");
- #endif
-
- //enumerate procs that have i/o registry entries
- self.userClients = [self enumDomainUserClients];
-
- //dbg msg
- #ifdef DEBUG
- logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined i/or registry senders: %@", (unsigned long)self.userClients.count, self.userClients]);
- #endif
+ //baseline
+ if(0 != self.coreAudioProcess)
+ {
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"camera core audio process: %d", self.coreAudioProcess]);
+ #endif
+
+ //enumerate procs that have send mach messages
+ self.machSendersAudio = [self enumMachSenders:self.coreAudioProcess];
+
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined mach senders: %@", (unsigned long)self.machSendersAudio.count, self.machSendersVideo]);
+
+ //dbg msg
+ logMsg(LOG_DEBUG, @"baselining i/o registry entries for audio...");
+ #endif
+
+ //enumerate procs that have i/o registry entries
+ self.userClients = [self enumDomainUserClients];
+
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found %lu baselined i/or registry senders: %@", (unsigned long)self.userClients.count, self.userClients]);
+ #endif
+ }
}
- }
+
+ }//sync
- //nap for a minute
- [NSThread sleepForTimeInterval:60];
+ }//pool
}
return;
@@ -166,18 +207,19 @@ static NSArray* ignoredProcs = nil;
//current procs
NSMutableArray* videoProcs = nil;
+ //pool
+ @autoreleasepool
+ {
+
//mach senders
NSMutableDictionary* currentSenders = nil;
//candidate video procs
// ->those that have new mach message
NSMutableArray* candidateVideoProcs = nil;
-
- //pid of camera assistant process
- pid_t cameraAssistant = 0;
-
- //'frontmost' application
- pid_t activeApp = -1;
+
+ //foreground app
+ pid_t activeApp = 0;
//alloc
candidateVideoProcs = [NSMutableArray array];
@@ -186,17 +228,24 @@ static NSArray* ignoredProcs = nil;
// ->prevent baselining thread from doing anything
@synchronized(self)
{
-
- //first look for 'VDCAssistant'
- cameraAssistant = findProcess(VDC_ASSISTANT);
- if(0 == cameraAssistant)
+
+ //find camera assistant
+ // only do this once, or again, if it died
+ if( (0 == self.cameraAssistantProcess) ||
+ (YES != isProcessAlive(self.cameraAssistantProcess)) )
{
- //look for 'AppleCameraAssistant'
- cameraAssistant = findProcess(APPLE_CAMERA_ASSISTANT);
+ //find camera assistant
+ // ->first look for 'VDCAssistant'
+ self.cameraAssistantProcess = findProcess(VDC_ASSISTANT);
+ if(0 == self.cameraAssistantProcess)
+ {
+ //look for 'AppleCameraAssistant'
+ self.cameraAssistantProcess = findProcess(APPLE_CAMERA_ASSISTANT);
+ }
}
//sanity check
- if(0 == cameraAssistant)
+ if(0 == self.cameraAssistantProcess)
{
//err msg
logMsg(LOG_ERR, @"failed to find VDCAssistant/AppleCameraAssistant process");
@@ -207,7 +256,7 @@ static NSArray* ignoredProcs = nil;
//get procs that currrently have sent Mach msg to *Assistant
// ->returns dictionary of process id, and number of mach messages
- currentSenders = [self enumMachSenders:cameraAssistant];
+ currentSenders = [self enumMachSenders:self.cameraAssistantProcess];
//dbg msg
#ifdef DEBUG
@@ -219,7 +268,7 @@ static NSArray* ignoredProcs = nil;
{
//add any candidate procs
// ->those that have new mach message
- if( [currentSenders[processID] intValue] > [self.machSendersVideo[processID] intValue])
+ if([currentSenders[processID] intValue] > [self.machSendersVideo[processID] intValue])
{
//ignore client/requestor
if(clientPID == processID.intValue)
@@ -270,8 +319,9 @@ static NSArray* ignoredProcs = nil;
videoProcs = [self sampleCandidates:candidateVideoProcs];
}//sync
+
+ }//pool
-//bail
bail:
return videoProcs;
@@ -283,6 +333,10 @@ bail:
//current procs
NSMutableArray* audioProcs = nil;
+ //pool
+ @autoreleasepool
+ {
+
//current mach senders
NSMutableDictionary* currentSenders = nil;
@@ -302,9 +356,6 @@ bail:
//itersection set
NSMutableSet* intersection = nil;
- //pid of coreaudio process
- pid_t coreAudio = 0;
-
//'frontmost' application
pid_t activeApp = -1;
@@ -314,16 +365,22 @@ bail:
//alloc array
newUserClients = [NSMutableArray array];
- //alloc array
- candidateAudioProcs = [NSMutableArray array];
-
//sync this logic
// ->prevent baselining thread from doing anything
@synchronized(self)
{
//find coreaudio
- coreAudio = findProcess(CORE_AUDIO);
- if(0 == coreAudio)
+ //find core audio
+ // only do this once, or again, if it died
+ if( (0 == self.coreAudioProcess) ||
+ (YES != isProcessAlive(self.coreAudioProcess)) )
+ {
+ //find core audio
+ self.coreAudioProcess = findProcess(CORE_AUDIO);
+ }
+
+ //sanity check
+ if(0 == self.coreAudioProcess)
{
//err msg
logMsg(LOG_ERR, @"failed to find coreaudio process");
@@ -334,7 +391,7 @@ bail:
//get procs that currrently have sent Mach msg to core audio
// ->returns dictionary of process id, and number of mach messages
- currentSenders = [self enumMachSenders:coreAudio];
+ currentSenders = [self enumMachSenders:self.coreAudioProcess];
//dbg msg
#ifdef DEBUG
@@ -509,8 +566,9 @@ bail:
audioProcs = [self sampleCandidates:candidateAudioProcs];
}//sync
+
+ }//pool
-//bail
bail:
return audioProcs;
@@ -523,6 +581,10 @@ bail:
//senders
NSMutableDictionary* senders = nil;
+ //pool
+ @autoreleasepool
+ {
+
//results from 'lsmp' cmd
NSString* results = nil;
@@ -610,8 +672,9 @@ bail:
//add/inc to dictionary
senders[processID] = @([senders[processID] unsignedIntegerValue] + 1);
}
+
+ }//pool
-//bail
bail:
return senders;
@@ -621,6 +684,13 @@ bail:
// ->returns dictionary of process id, and number of user client entries
-(NSMutableDictionary*)enumDomainUserClients
{
+ //array of RootDomainUserClients
+ NSMutableDictionary* clients = nil;
+
+ //pool
+ @autoreleasepool
+ {
+
//matching service
io_service_t matchingService = 0;
@@ -630,9 +700,6 @@ bail:
//kids
io_registry_entry_t child = 0;
- //array of RootDomainUserClients
- NSMutableDictionary* clients = nil;
-
//client creator
CFTypeRef creator = 0;
@@ -670,6 +737,9 @@ bail:
//always release child
IOObjectRelease(child);
+ //unset
+ child = 0;
+
//if couldn't get a creator
// ->might just not be of RootDomainUserClient, so skip
if(0 == creator)
@@ -696,9 +766,11 @@ bail:
//release
CFRelease(creator);
+
+ //unset
+ creator = 0;
}
-//bail
bail:
//release iterator
@@ -706,6 +778,9 @@ bail:
{
//release
IOObjectRelease(iterator);
+
+ //unset
+ iterator = 0;
}
//release obj
@@ -713,10 +788,14 @@ bail:
{
//release
IOObjectRelease(matchingService);
+
+ //unset
+ matchingService = 0;
}
+
+ }//pool
return clients;
-
}
//invoke 'sample' to confirm candidates are using CMIO/video/av inputs
@@ -726,6 +805,10 @@ bail:
//av procs
NSMutableArray* avProcs = nil;
+ //pool
+ @autoreleasepool
+ {
+
//results from 'sample' cmd
NSString* results = nil;
@@ -807,6 +890,8 @@ bail:
[avProcs addObject:processID];
}
+ }//pool
+
return avProcs;
}
@@ -814,6 +899,10 @@ bail:
// ->this looks for that file and deletes it
-(void)deleteSampleFile:(NSString*)processPath
{
+ //pool
+ @autoreleasepool
+ {
+
//error
NSError* error = nil;
@@ -864,6 +953,8 @@ bail:
}
}//all files
+
+ }//pool
//bail
bail:
@@ -876,9 +967,10 @@ bail:
// ->extra logic is executed to 'refresh' iVars when video is disabled
-(void)updateVideoStatus:(BOOL)isEnabled
{
- //camera assistant
- pid_t cameraAssistant = 0;
-
+ //pool
+ @autoreleasepool
+ {
+
//sync
@synchronized(self)
{
@@ -889,16 +981,23 @@ bail:
// ->re-enumerate mach senders
if(YES != isEnabled)
{
- //first, look for 'VDCAssistant'
- cameraAssistant = findProcess(VDC_ASSISTANT);
- if(0 == cameraAssistant)
+ //find camera assistant
+ // only do this once, or again, if it died
+ if( (0 == self.cameraAssistantProcess) ||
+ (YES != isProcessAlive(self.cameraAssistantProcess)) )
{
- //look for 'AppleCameraAssistant'
- cameraAssistant = findProcess(APPLE_CAMERA_ASSISTANT);
+ //find camera assistant
+ // ->first look for 'VDCAssistant'
+ self.cameraAssistantProcess = findProcess(VDC_ASSISTANT);
+ if(0 == self.cameraAssistantProcess)
+ {
+ //look for 'AppleCameraAssistant'
+ self.cameraAssistantProcess = findProcess(APPLE_CAMERA_ASSISTANT);
+ }
}
//sanity check
- if(0 == cameraAssistant)
+ if(0 == self.cameraAssistantProcess)
{
//err msg
logMsg(LOG_ERR, @"failed to find VDCAssistant/AppleCameraAssistant process");
@@ -908,11 +1007,13 @@ bail:
}
//enumerate mach senders
- self.machSendersVideo = [self enumMachSenders:cameraAssistant];
+ self.machSendersVideo = [self enumMachSenders:self.cameraAssistantProcess];
}
}//sync
+ }//pool
+
//bail
bail:
@@ -923,6 +1024,10 @@ bail:
// ->extra logic is executed to 'refresh' iVars when audio is disabled
-(void)updateAudioStatus:(BOOL)isEnabled
{
+ //pool
+ @autoreleasepool
+ {
+
//sync
@synchronized(self)
{
@@ -933,14 +1038,30 @@ bail:
// ->re-enumerate mach senders & i/o registry user clients
if(YES != isEnabled)
{
- //enumerate mach senders
- self.machSendersAudio = [self enumMachSenders:findProcess(CORE_AUDIO)];
+ //find coreaudio
+ //find core audio
+ // only do this once, or again, if it died
+ if( (0 == self.coreAudioProcess) ||
+ (YES != isProcessAlive(self.coreAudioProcess)) )
+ {
+ //find core audio
+ self.coreAudioProcess = findProcess(CORE_AUDIO);
+ }
- //enumerate i/o registry user clients
- self.userClients = [self enumDomainUserClients];
+ //enumerate
+ if(0 != self.coreAudioProcess)
+ {
+ //enumerate mach senders
+ self.machSendersAudio = [self enumMachSenders:self.coreAudioProcess];
+
+ //enumerate i/o registry user clients
+ self.userClients = [self enumDomainUserClients];
+ }
}
}
-
+
+ }//pool
+
return;
}
diff --git a/OverSightXPC/Info.plist b/OverSightXPC/Info.plist
index ba51a3b..2330d25 100644
--- a/OverSightXPC/Info.plist
+++ b/OverSightXPC/Info.plist
@@ -17,11 +17,11 @@
CFBundlePackageType
XPC!
CFBundleShortVersionString
- 1.1.2
+ 1.2.0
CFBundleSignature
????
CFBundleVersion
- 1.1.2
+ 1.2.0
NSHumanReadableCopyright
Copyright (c) 2017 Objective-See. All rights reserved.
XPCService
diff --git a/OverSightXPC/OverSightXPC.m b/OverSightXPC/OverSightXPC.m
index 4da7fa8..0724746 100644
--- a/OverSightXPC/OverSightXPC.m
+++ b/OverSightXPC/OverSightXPC.m
@@ -12,7 +12,6 @@
#import "Enumerator.h"
#import "OverSightXPC.h"
-
@implementation OverSightXPC
@synthesize machSenders;
@@ -23,7 +22,7 @@
-(void)initialize:(void (^)(void))reply
{
//start enumerating
- // ->will forever baseline current mach msg procs
+ // will forever baseline current mach msg procs
[NSThread detachNewThreadSelector:@selector(start) toTarget:[Enumerator sharedManager] withObject:nil];
//reply
@@ -32,6 +31,23 @@
return;
}
+//heartbeat
+// need as otherwise kernel might kill XPC
+-(void)heartBeat:(void (^)(BOOL))reply
+{
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, @"heartbeat request");
+ #endif
+
+ //nap
+ [NSThread sleepForTimeInterval:3.0f];
+
+ reply(YES);
+
+ return;
+}
+
//call into emumerate to get (new) video proc
-(void)getVideoProcs:(BOOL)polling reply:(void (^)(NSMutableArray *))reply
{
@@ -69,7 +85,7 @@
{
//set status
[[Enumerator sharedManager] updateAudioStatus:status];
-
+
//reply
reply();
@@ -118,7 +134,6 @@
//happy
wasAdded = YES;
-//bail
bail:
//reply
@@ -192,7 +207,6 @@ bail:
}
}
-//bail
bail:
//reply
@@ -220,7 +234,6 @@ bail:
//happy
wasKilled = YES;
-//bail
bail:
//reply
@@ -236,7 +249,4 @@ bail:
exit(0);
}
-
@end
-
-
diff --git a/OverSightXPC/main.h b/OverSightXPC/main.h
index 7a43b43..513fba0 100644
--- a/OverSightXPC/main.h
+++ b/OverSightXPC/main.h
@@ -51,6 +51,4 @@ OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
@end
-
-
#endif /* main_h */
diff --git a/OverSightXPC/main.m b/OverSightXPC/main.m
index fc22736..485c5a0 100644
--- a/OverSightXPC/main.m
+++ b/OverSightXPC/main.m
@@ -7,7 +7,7 @@
//
#import "main.h"
-
+#import "Logging.h"
/* GLOBALS */
@@ -26,8 +26,8 @@ pid_t clientPID = 0;
@implementation ServiceDelegate
//automatically invoked
-//->allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
-// note: we only allow binaries signed by Objective-See to talk to this!
+// allows NSXPCListener to configure/accept/resume a new incoming NSXPCConnection
+// note: we only allow binaries signed by Objective-See to connect & talk to this!
-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
//flag
@@ -39,6 +39,11 @@ pid_t clientPID = 0;
//signing req string
NSString *requirementString = nil;
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, @"new client connection");
+ #endif
+
//init signing req string
requirementString = [NSString stringWithFormat:@"anchor trusted and certificate leaf [subject.CN] = \"%@\"", SIGNING_AUTH];
@@ -68,11 +73,16 @@ pid_t clientPID = 0;
//resume
[newConnection resume];
+ //grab client/requestor's pid
+ clientPID = audit_token_to_pid(((ExtendedNSXPCConnection*)newConnection).auditToken);
+
//happy
shouldAccept = YES;
- //grab client/requestor's pid
- clientPID = audit_token_to_pid(((ExtendedNSXPCConnection*)newConnection).auditToken);
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"accepted new client connection (pid: %d)", clientPID]);
+ #endif
//bail
bail:
@@ -110,7 +120,7 @@ int main(int argc, const char *argv[])
installExceptionHandlers();
//create the delegate for the service.
- delegate = [ServiceDelegate new];
+ delegate = [[ServiceDelegate alloc] init];
//set up the one NSXPCListener for this service
// ->handles incoming connections
@@ -126,7 +136,6 @@ int main(int argc, const char *argv[])
//happy
status = 0;
-//bail
bail:
return status;
diff --git a/Shared/AboutWindow.xib b/Shared/AboutWindow.xib
index f5d585f..110bc05 100644
--- a/Shared/AboutWindow.xib
+++ b/Shared/AboutWindow.xib
@@ -1,7 +1,7 @@
-
+
-
+
@@ -17,7 +17,7 @@
-
+
@@ -98,7 +98,7 @@
-
+
diff --git a/Shared/Consts.h b/Shared/Consts.h
index 32185b7..7ff2be7 100644
--- a/Shared/Consts.h
+++ b/Shared/Consts.h
@@ -28,7 +28,7 @@
#define PRODUCT_URL @"https://objective-see.com/products/oversight.html"
//product version url
-#define PRODUCT_VERSION_URL @"https://objective-see.com/products.json"
+#define PRODUCT_VERSIONS_URL @"https://objective-see.com/products.json"
//patreon url
#define PATREON_URL @"https://www.patreon.com/objective_see"
@@ -129,9 +129,6 @@
//path to xattr
#define XATTR @"/usr/bin/xattr"
-//path to sudo
-#define SUDO @"/usr/bin/sudo"
-
//path to facetime
#define FACE_TIME @"/Applications/FaceTime.app/Contents/MacOS/FaceTime"
@@ -187,5 +184,4 @@
//log to file flag
#define LOG_TO_FILE 0x10
-
#endif
diff --git a/Shared/Exception.h b/Shared/Exception.h
index 1f45004..53969b6 100755
--- a/Shared/Exception.h
+++ b/Shared/Exception.h
@@ -9,7 +9,7 @@
#import
//install exception/signal handlers
-void installExceptionHandlers();
+void installExceptionHandlers(void);
//exception handler for Obj-C exceptions
void exceptionHandler(NSException *exception);
@@ -19,6 +19,3 @@ void signalHandler(int signal, siginfo_t *info, void *context);
//display error window
void displayErrorWindow(NSDictionary* errorInfo);
-
-
-
diff --git a/Shared/Logging.h b/Shared/Logging.h
index c1eb394..e6f2dc9 100644
--- a/Shared/Logging.h
+++ b/Shared/Logging.h
@@ -13,15 +13,13 @@
void logMsg(int level, NSString* msg);
//prep/open log file
-BOOL initLogging();
+BOOL initLogging(void);
//get path to log file
-NSString* logFilePath();
+NSString* logFilePath(void);
//de-init logging
-void deinitLogging();
+void deinitLogging(void);
//log to file
void log2File(NSString* msg);
-
-
diff --git a/Shared/Logging.m b/Shared/Logging.m
index 568973d..bfa3d97 100644
--- a/Shared/Logging.m
+++ b/Shared/Logging.m
@@ -31,7 +31,7 @@ void logMsg(int level, NSString* msg)
level &= ~LOG_TO_FILE;
//alloc/init
- // ->always start w/ 'OVERSIGHT' + pid
+ // ->always start w/ 'LULU' + pid
logPrefix = [NSMutableString stringWithFormat:@"OVERSIGHT(%d)", getpid()];
//if its error, add error to prefix
@@ -44,8 +44,8 @@ void logMsg(int level, NSString* msg)
//debug mode logic
#ifdef DEBUG
- //in debug mode. promote debug msgs to LOG_NOTICE
- // ->OS X/macOS only shows LOG_NOTICE and above in the system log
+ //in debug mode promote debug msgs to LOG_NOTICE
+ // OSX/macOS only shows LOG_NOTICE and above
if(LOG_DEBUG == level)
{
//promote
@@ -54,29 +54,23 @@ void logMsg(int level, NSString* msg)
#endif
- //log to syslog
- syslog(level, "%s: %s", [logPrefix UTF8String], [msg UTF8String]);
+ //log to syslog if a level was specified
+ // as code doesn't use LOG_EMERG (0), this check is ok
+ if(0 != level)
+ {
+ //log to syslog
+ syslog(level, "%s: %s", [logPrefix UTF8String], [msg UTF8String]);
+ }
//when a message is to be logged to file
- // ->log it to file and syslog, when logging is enabled
+ // ->log it, when logging is enabled
if(YES == shouldLog)
{
- //but only when logging is enabled
+ //but only when logging is enable
if(nil != logFileHandle)
{
//log
log2File(msg);
-
- //promote to notice for syslog
- if(LOG_DEBUG == level)
- {
- //promote
- level = LOG_NOTICE;
- }
-
- //also syslog
- // ->should result in 1 log msg, (in release), as all LOG_TO_FILE are at LOG_DEBUG level
- syslog(level, "%s: %s", [logPrefix UTF8String], [msg UTF8String]);
}
}
diff --git a/Shared/Utilities.h b/Shared/Utilities.h
index 5a1f60b..290c81e 100644
--- a/Shared/Utilities.h
+++ b/Shared/Utilities.h
@@ -15,11 +15,11 @@
/* FUNCTIONS */
//get OS version
-NSDictionary* getOSVersion();
+NSDictionary* getOSVersion(void);
//get app's version
// ->extracted from Info.plist
-NSString* getAppVersion();
+NSString* getAppVersion(void);
//set dir's|file's group/owner
BOOL setFileOwner(NSString* path, NSNumber* groupID, NSNumber* ownerID, BOOL recursive);
@@ -39,10 +39,10 @@ NSBundle* findAppBundle(NSString* binaryPath);
//get app's version
// ->extracted from Info.plist
-NSString* getAppVersion();
+NSString* getAppVersion(void);
//query interwebz to get latest version
-NSString* getLatestVersion();
+NSString* getLatestVersion(void);
//determine if there is a new version
// -1, YES or NO
@@ -72,7 +72,8 @@ void makeModal(NSWindowController* windowController);
BOOL toggleLoginItem(NSURL* loginItem, int toggleFlag);
//get logged in user
-NSString* loggedinUser();
+// name, uid, and gid
+NSMutableDictionary* loggedinUser(void);
//find a process by name
pid_t findProcess(NSString* processName);
@@ -81,6 +82,9 @@ pid_t findProcess(NSString* processName);
void makeTextViewHyperlink(NSTextField* textField, NSURL* url);
//get active application
-pid_t frontmostApplication();
+pid_t frontmostApplication(void);
+
+//check if process is alive
+BOOL isProcessAlive(pid_t processID);
#endif
diff --git a/Shared/Utilities.m b/Shared/Utilities.m
index 02f32ff..22e0ec1 100644
--- a/Shared/Utilities.m
+++ b/Shared/Utilities.m
@@ -274,17 +274,27 @@ NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait)
//output
NSData *output = nil;
+ //dispatch group
+ dispatch_group_t dispatchGroup = 0;
+
//init task
- task = [NSTask new];
+ task = [[NSTask alloc] init];
//init pipe
outPipe = [NSPipe pipe];
+ //create dispatch group
+ dispatchGroup = dispatch_group_create();
+
//set task's path
task.launchPath = binaryPath;
//set task's args
- task.arguments = arguments;
+ if(nil != arguments)
+ {
+ //add
+ task.arguments = arguments;
+ }
//set task's output to pipe
// ->but only if we're waiting for exit
@@ -299,6 +309,16 @@ NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait)
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"@exec'ing %@ (args: %@)", binaryPath, arguments]);
#endif
+ //enter dispatch
+ dispatch_group_enter(dispatchGroup);
+
+ //set task's termination to leave dispatch group
+ task.terminationHandler = ^(NSTask *task){
+
+ //leave
+ dispatch_group_leave(dispatchGroup);
+ };
+
//wrap task launch
@try
{
@@ -333,7 +353,7 @@ NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait)
#endif
//wait till exit
- [task waitUntilExit];
+ dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER);
//dbg msg
#ifdef DEBUG
@@ -345,6 +365,7 @@ NSData* execTask(NSString* binaryPath, NSArray* arguments, BOOL shouldWait)
//bail
bail:
+
return output;
}
@@ -756,59 +777,54 @@ bail:
//query interwebz to get latest version
NSString* getLatestVersion()
{
- //version data
- __block NSData* versionData = nil;
+ //product version(s) data
+ NSData* productsVersionData = nil;
//version dictionary
- NSDictionary* versionDictionary = nil;
+ NSDictionary* productsVersionDictionary = nil;
//latest version
NSString* latestVersion = nil;
- //run in background if main thread
- if(YES == [NSThread isMainThread])
- {
- //run in background
- dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
- ^{
- //get version data
- versionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSION_URL]];
- });
- }
- //no need to background
- else
- {
- //get version from remote URL
- versionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSION_URL]];
- }
-
- //sanity check
- if(nil == versionData)
+ //get version from remote URL
+ productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]];
+ if(nil == productsVersionData)
{
//bail
goto bail;
}
//convert JSON to dictionary
- versionDictionary = [NSJSONSerialization JSONObjectWithData:versionData options:0 error:nil];
-
- //sanity check
- if(nil == versionDictionary)
+ // ->wrap as may throw exception
+ @try
+ {
+ //convert
+ productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil];
+ if(nil == productsVersionDictionary)
+ {
+ //bail
+ goto bail;
+ }
+ }
+ @catch(NSException* exception)
{
//bail
goto bail;
}
//extract latest version
- latestVersion = versionDictionary[@"latestVersion"];
+ latestVersion = [[productsVersionDictionary objectForKey:@"OverSight"] objectForKey:@"version"];
+
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"latest version: %@", latestVersion]);
+ #endif
-//bail
bail:
return latestVersion;
}
-
//wait until a window is non nil
// ->then make it modal
void makeModal(NSWindowController* windowController)
@@ -981,14 +997,27 @@ bail:
}
//get logged in user
-NSString* loggedinUser()
+// name, uid, and gid
+NSMutableDictionary* loggedinUser()
{
+ //user info
+ NSMutableDictionary* userInfo = nil;
+
//store
SCDynamicStoreRef store = nil;
//user
NSString* user = nil;
+ //uid
+ uid_t uid = 0;
+
+ //gid
+ gid_t gid = 0;
+
+ //allco dictionary
+ userInfo = [NSMutableDictionary dictionary];
+
//create store
store = SCDynamicStoreCreate(NULL, CFSTR("GetConsoleUser"), NULL, NULL);
if(NULL == store)
@@ -997,8 +1026,17 @@ NSString* loggedinUser()
goto bail;
}
- //get user
- user = CFBridgingRelease(SCDynamicStoreCopyConsoleUser(store, NULL, NULL));
+ //get user and uid/gid
+ user = CFBridgingRelease(SCDynamicStoreCopyConsoleUser(store, &uid, &gid));
+
+ //add user
+ userInfo[@"user"] = user;
+
+ //add uid
+ userInfo[@"uid"] = [NSNumber numberWithUnsignedInt:uid];
+
+ //add uid
+ userInfo[@"gid"] = [NSNumber numberWithUnsignedInt:gid];
//bail
bail:
@@ -1010,7 +1048,7 @@ bail:
CFRelease(store);
}
- return user;
+ return userInfo;
}
//find a process by name
@@ -1059,7 +1097,7 @@ pid_t findProcess(NSString* processName)
//get name
processPath = getProcessPath(pids[i]);
if( (nil == processPath) ||
- (0 == processPath.length) )
+ (0 == processPath.length) )
{
//skip
continue;
@@ -1134,3 +1172,31 @@ pid_t frontmostApplication()
return NSWorkspace.sharedWorkspace.frontmostApplication.processIdentifier;
}
+//check if process is alive
+BOOL isProcessAlive(pid_t processID)
+{
+ //ret var
+ BOOL bIsAlive = NO;
+
+ //signal status
+ int signalStatus = -1;
+
+ //send kill with 0 to determine if alive
+ // -> see: http://stackoverflow.com/questions/9152979/check-if-process-exists-given-its-pid
+ signalStatus = kill(processID, 0);
+
+ //is alive?
+ if( (0 == signalStatus) ||
+ ( (0 != signalStatus) && (errno != ESRCH) ) )
+ {
+ //dbg msg
+ #ifdef DEBUG
+ logMsg(LOG_DEBUG, [NSString stringWithFormat:@"agent (%d) is ALIVE", processID]);
+ #endif
+
+ //alive!
+ bIsAlive = YES;
+ }
+
+ return bIsAlive;
+}
diff --git a/Shared/XPCProtocol.h b/Shared/XPCProtocol.h
index 5f37554..701df1d 100644
--- a/Shared/XPCProtocol.h
+++ b/Shared/XPCProtocol.h
@@ -14,6 +14,10 @@
//start enumerator
-(void)initialize:(void (^)(void))reply;
+//heartbeat
+// need as otherwise kernel might kill XPC
+-(void)heartBeat:(void (^)(BOOL))reply;
+
//get (new) audio procs
-(void)getAudioProcs:(void (^)(NSMutableArray *))reply;
diff --git a/contributors.txt b/contributors.txt
new file mode 100644
index 0000000..a8f8973
--- /dev/null
+++ b/contributors.txt
@@ -0,0 +1 @@
+patrick wardle