v 1.2.0
high sierra compatibility improved nstask execution alleviated need for 'sudo' refactored code to find camera/mic process pushed various XPC intensive stuff into background
This commit is contained in:
parent
027d0840ed
commit
d7b4648a90
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
BOOL spawnAsRoot(const char* path2Self);
|
||||
|
||||
//install
|
||||
BOOL cmdlineInstall();
|
||||
BOOL cmdlineInstall(void);
|
||||
|
||||
//uninstall
|
||||
BOOL cmdlineUninstall();
|
||||
BOOL cmdlineUninstall(void);
|
||||
|
||||
#endif /* main_h */
|
||||
|
|
153
Installer/main.m
153
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
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
//version label/string
|
||||
@property (weak) IBOutlet NSTextField *windowText;
|
||||
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//save stuff into iVars
|
||||
|
|
|
@ -137,9 +137,6 @@
|
|||
//close connection
|
||||
[xpcConnection invalidate];
|
||||
|
||||
//nil out
|
||||
xpcConnection = nil;
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}];
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>LSUIElement</key>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="611" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/>
|
||||
<value key="minSize" type="size" width="500" height="100"/>
|
||||
<value key="maxSize" type="size" width="1500" height="500"/>
|
||||
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.2.0</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2017 Objective-See. All rights reserved.</string>
|
||||
<key>XPCService</key>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,4 @@ OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement)
|
|||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* main_h */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16E195" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES" unifiedTitleAndToolbar="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="486" height="301"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1058"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="486" height="301"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
@ -98,7 +98,7 @@
|
|||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OSm-xS-Dmd">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OSm-xS-Dmd">
|
||||
<rect key="frame" x="158" y="220" width="182" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Version:" id="bBK-v0-ypq">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#import <signal.h>
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
patrick wardle
|
Loading…
Reference in New Issue