started on install/uninstall logic (as root, etc)
TODOs/code cleanup
This commit is contained in:
parent
5173869913
commit
d14d33fbd1
|
@ -54,6 +54,7 @@
|
|||
7D17C5031D658DEC0066232A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Installer/Base.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; };
|
||||
7D24C8651D2CDEA7009932EE /* Installer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Installer.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7D6245821D87C3D700870565 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Images/Images.xcassets; sourceTree = "<group>"; };
|
||||
7D9A7DE91D8A8BDA0091C1AF /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = main.h; path = Installer/main.h; sourceTree = SOURCE_ROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -117,6 +118,7 @@
|
|||
children = (
|
||||
7D17C5021D658DEC0066232A /* MainMenu.xib */,
|
||||
7D17C4EC1D658DB90066232A /* Configure.m */,
|
||||
7D17C4F61D658DB90066232A /* AppDelegate.h */,
|
||||
7D17C4ED1D658DB90066232A /* AppDelegate.m */,
|
||||
7D17C4EE1D658DB90066232A /* ConfigureWindowController.m */,
|
||||
7D17C4EF1D658DB90066232A /* ConfigureWindowController.xib */,
|
||||
|
@ -124,7 +126,6 @@
|
|||
7D17C4F11D658DB90066232A /* ConfigureWindowController.h */,
|
||||
7D17C4F21D658DB90066232A /* ErrorWindowController.h */,
|
||||
7D17C4F31D658DB90066232A /* ErrorWindowController.m */,
|
||||
7D17C4F61D658DB90066232A /* AppDelegate.h */,
|
||||
7D17C4F81D658DB90066232A /* ErrorWindowController.xib */,
|
||||
7D24C86B1D2CDEA7009932EE /* Supporting Files */,
|
||||
);
|
||||
|
@ -137,6 +138,7 @@
|
|||
children = (
|
||||
7D17C4F51D658DB90066232A /* Info.plist */,
|
||||
7D17C4F41D658DB90066232A /* main.m */,
|
||||
7D9A7DE91D8A8BDA0091C1AF /* main.h */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
|
|
|
@ -87,14 +87,13 @@ bail:
|
|||
-(BOOL)isInstalled
|
||||
{
|
||||
//check if extension exists
|
||||
return [[NSFileManager defaultManager] fileExistsAtPath:[[EXTENSION_FOLDER stringByExpandingTildeInPath] stringByAppendingPathComponent:EXTENSION_NAME]];
|
||||
return [[NSFileManager defaultManager] fileExistsAtPath:[APPS_FOLDER stringByAppendingPathComponent:APP_NAME]];
|
||||
}
|
||||
|
||||
|
||||
//install
|
||||
// a) create and copy extension to ~/Library/WhatsYourSign
|
||||
// b) add extension: 'pluginkit -a /path/2/WhatsYourSign.appex'
|
||||
// c) enable extension: 'pluginkit -e use -i com.objective-see.WhatsYourSignExt.FinderSync'
|
||||
// a) copy to /Applications
|
||||
// b) chown/chmod XPC component
|
||||
-(BOOL)install
|
||||
{
|
||||
//return/status var
|
||||
|
@ -103,75 +102,34 @@ bail:
|
|||
//error
|
||||
NSError* error = nil;
|
||||
|
||||
//path to finder sync (src)
|
||||
NSString* extensionPathSrc = nil;
|
||||
//path to app (src)
|
||||
NSString* appPathSrc = nil;
|
||||
|
||||
//path to finder sync (dest)
|
||||
NSString* extensionPathDest = nil;
|
||||
|
||||
//results from 'pluginkit' cmd
|
||||
NSData* results = nil;
|
||||
//path to app (dest)
|
||||
NSString* appPathDest = nil;
|
||||
|
||||
//set src path
|
||||
// ->orginally stored in installer app's /Resource bundle
|
||||
extensionPathSrc = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:EXTENSION_NAME];
|
||||
appPathSrc = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:APP_NAME];
|
||||
|
||||
//set dest path
|
||||
extensionPathDest = [[EXTENSION_FOLDER stringByExpandingTildeInPath] stringByAppendingPathComponent:EXTENSION_NAME];
|
||||
appPathDest = [APPS_FOLDER stringByAppendingPathComponent:APP_NAME];
|
||||
|
||||
//check if extension folder needs to be created
|
||||
if(YES != [[NSFileManager defaultManager] fileExistsAtPath:[EXTENSION_FOLDER stringByExpandingTildeInPath]])
|
||||
{
|
||||
//create it
|
||||
if(YES != [[NSFileManager defaultManager] createDirectoryAtPath:[EXTENSION_FOLDER stringByExpandingTildeInPath] withIntermediateDirectories:YES attributes:nil error:&error])
|
||||
//move app into /Applications
|
||||
if(YES != [[NSFileManager defaultManager] copyItemAtPath:appPathSrc toPath:appPathDest error:&error])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to create extension's directory %@ (%@)", EXTENSION_FOLDER, error]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
//move extension into persistent location
|
||||
// ->'/Library/WhatsYourSign/' + extension name
|
||||
if(YES != [[NSFileManager defaultManager] copyItemAtPath:extensionPathSrc toPath:extensionPathDest error:&error])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to copy %@ -> %@ (%@)", extensionPathSrc, extensionPathDest, error]);
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to copy %@ -> %@ (%@)", appPathSrc, appPathDest, error]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"copied %@ -> %@", extensionPathSrc, extensionPathDest]);
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"copied %@ -> %@", appPathSrc, appPathDest]);
|
||||
|
||||
//install extension via 'pluginkit -a <path 2 ext>
|
||||
results = execTask(PLUGIN_KIT, @[@"-a", extensionPathDest]);
|
||||
if(0 != results.length)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"pluginkit failed to install extension (%@)", [[NSString alloc] initWithData:results encoding:NSUTF8StringEncoding]]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//nap
|
||||
// ->VM sometimes didn't enable
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
//enable extension via 'pluginkit -e use -i <ext bundle id>
|
||||
results = execTask(PLUGIN_KIT, @[@"-e", @"use", @"-i", EXTENSION_BUNDLE_ID]);
|
||||
if(0 != results.length)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"pluginkit failed to enable extension (%@)", [[NSString alloc] initWithData:results encoding:NSUTF8StringEncoding]]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
//always set group/owner to root/wheel
|
||||
setFileOwner(appPathDest, @0, @0, YES);
|
||||
|
||||
//no error
|
||||
wasInstalled = YES;
|
||||
|
@ -195,23 +153,19 @@ bail:
|
|||
BOOL bAnyErrors = NO;
|
||||
|
||||
//path to finder sync
|
||||
NSString* extensionPath = nil;
|
||||
NSString* appPath = nil;
|
||||
|
||||
//error
|
||||
NSError* error = nil;
|
||||
|
||||
//init path
|
||||
extensionPath = [[EXTENSION_FOLDER stringByExpandingTildeInPath] stringByAppendingPathComponent:EXTENSION_NAME];
|
||||
|
||||
//this always seem to 'fail' with 'remove: no plugin at <path/2/FinderSync.appex>'
|
||||
// ->but yet works, so just ignore any return from this invocation of execTask()
|
||||
execTask(PLUGIN_KIT, @[@"-r", extensionPath]);
|
||||
appPath = [APPS_FOLDER stringByAppendingPathComponent:APP_NAME];
|
||||
|
||||
//delete folder
|
||||
if(YES != [[NSFileManager defaultManager] removeItemAtPath:[EXTENSION_FOLDER stringByExpandingTildeInPath] error:&error])
|
||||
if(YES != [[NSFileManager defaultManager] removeItemAtPath:appPath error:&error])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to delete extension directory %@ (%@)", EXTENSION_FOLDER, error]);
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to delete app %@ (%@)", appPath, error]);
|
||||
|
||||
//set flag
|
||||
bAnyErrors = YES;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// main.h
|
||||
// Installer
|
||||
//
|
||||
// Created by Patrick Wardle on 9/14/16.
|
||||
// Copyright © 2016 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef main_h
|
||||
#define main_h
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Configure.h"
|
||||
|
||||
#import <syslog.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* FUNCTION DECLARATIONS */
|
||||
|
||||
//spawn self as root
|
||||
BOOL spawnAsRoot(const char* path2Self);
|
||||
|
||||
#endif /* main_h */
|
112
Installer/main.m
112
Installer/main.m
|
@ -6,8 +6,116 @@
|
|||
// Copyright (c) 2016 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "main.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
return NSApplicationMain(argc, argv);
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
//return var
|
||||
int retVar = -1;
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
|
||||
//check for r00t
|
||||
// ->then spawn self via auth exec
|
||||
if(0 != geteuid())
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"non-root installer instance");
|
||||
|
||||
//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
|
||||
logMsg(LOG_DEBUG, @"root installer instance");
|
||||
|
||||
//app away
|
||||
retVar = NSApplicationMain(argc, (const char **)argv);
|
||||
}
|
||||
|
||||
}//pool
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return retVar;
|
||||
}
|
||||
|
||||
//spawn self as root
|
||||
BOOL spawnAsRoot(const char* path2Self)
|
||||
{
|
||||
//return/status var
|
||||
BOOL bRet = NO;
|
||||
|
||||
//authorization ref
|
||||
AuthorizationRef authorizatioRef = {0};
|
||||
|
||||
//args
|
||||
char *args[] = {NULL};
|
||||
|
||||
//flag creation of ref
|
||||
BOOL authRefCreated = NO;
|
||||
|
||||
//status code
|
||||
OSStatus osStatus = -1;
|
||||
|
||||
//create authorization ref
|
||||
// ->and check
|
||||
osStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizatioRef);
|
||||
if(errAuthorizationSuccess != osStatus)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"AuthorizationCreate() failed with %d", osStatus]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set flag indicating auth ref was created
|
||||
authRefCreated = YES;
|
||||
|
||||
//spawn self as r00t w/ install flag (will ask user for password)
|
||||
// ->and check
|
||||
osStatus = AuthorizationExecuteWithPrivileges(authorizatioRef, path2Self, 0, args, NULL);
|
||||
|
||||
//check
|
||||
if(errAuthorizationSuccess != osStatus)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"AuthorizationExecuteWithPrivileges() failed with %d", osStatus]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//no errors
|
||||
bRet = YES;
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
//free auth ref
|
||||
if(YES == authRefCreated)
|
||||
{
|
||||
//free
|
||||
AuthorizationFree(authorizatioRef, kAuthorizationFlagDefaults);
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
// Copyright (c) 2015 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
//TODO: NSLOg -> logmSg
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Utilities.h"
|
||||
|
|
|
@ -39,20 +39,17 @@
|
|||
|
||||
//check for updates
|
||||
// ->but only when user has not disabled that feature
|
||||
// TODO: change to YES
|
||||
if(NO == [[NSUserDefaults standardUserDefaults] boolForKey:CHECK_4_UPDATES])
|
||||
if(YES == [[NSUserDefaults standardUserDefaults] boolForKey:CHECK_4_UPDATES])
|
||||
{
|
||||
//TODO: make a min!
|
||||
//after a minute
|
||||
//->check for updates in background
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"checking for update");
|
||||
|
||||
//check
|
||||
[self isThereAndUpdate];
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -262,9 +262,6 @@ bail:
|
|||
//TODO: ignore self!!
|
||||
//Sample analysis of process 18340 written to file /tmp/OverSight_Helper_2016-09-12_211234_StAd.sample.txt
|
||||
|
||||
//save to baseline
|
||||
// TODO: test that this works, esp if cnt goes down!! (facetime battery mode)
|
||||
//[self.machSenders addEntriesFromDictionary:currentSenders];
|
||||
//update
|
||||
self.machSenders = currentSenders;
|
||||
|
||||
|
|
|
@ -9,16 +9,10 @@
|
|||
#import "Logging.h"
|
||||
#import "Enumerator.h"
|
||||
#import "OverSightXPC.h"
|
||||
|
||||
|
||||
#import "../Shared/Utilities.h"
|
||||
|
||||
|
||||
|
||||
@implementation OverSightXPC
|
||||
|
||||
//TODO: method to set flag, that's sync'd~!?
|
||||
|
||||
@synthesize machSenders;
|
||||
@synthesize videoActive;
|
||||
|
||||
|
|
|
@ -12,12 +12,18 @@
|
|||
//success
|
||||
#define STATUS_SUCCESS 0
|
||||
|
||||
//apps folder
|
||||
#define APPS_FOLDER @"/Applications"
|
||||
|
||||
//app name
|
||||
#define APP_NAME @"OverSight.app"
|
||||
|
||||
//product url
|
||||
#define PRODUCT_URL @"https://objective-see.com/products/oversight.html"
|
||||
|
||||
//product version url
|
||||
//TODO: change back!
|
||||
#define PRODUCT_VERSION_URL @"https://objective-see.com/products/versions/ransomwhere.json"
|
||||
//TODO: test final/with page
|
||||
#define PRODUCT_VERSION_URL @"https://objective-see.com/products/versions/oversight.json"
|
||||
|
||||
//frame shift
|
||||
// ->for status msg to avoid activity indicator
|
||||
|
|
|
@ -20,6 +20,12 @@
|
|||
// ->extracted from Info.plist
|
||||
NSString* getAppVersion();
|
||||
|
||||
//set dir's|file's group/owner
|
||||
BOOL setFileOwner(NSString* path, NSNumber* groupID, NSNumber* ownerID, BOOL recursive);
|
||||
|
||||
//set permissions for file
|
||||
void setFilePermissions(NSString* file, int permissions);
|
||||
|
||||
//exec a process and grab it's output
|
||||
NSData* execTask(NSString* binaryPath, NSArray* arguments);
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
//
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
#import <signal.h>
|
||||
#import <unistd.h>
|
||||
#import <libproc.h>
|
||||
#import <sys/stat.h>
|
||||
#import <sys/sysctl.h>
|
||||
#import <Security/Security.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
@ -71,6 +73,116 @@ NSBundle* findAppBundle(NSString* binaryPath)
|
|||
return appBundle;
|
||||
}
|
||||
|
||||
//set dir's|file's group/owner
|
||||
BOOL setFileOwner(NSString* path, NSNumber* groupID, NSNumber* ownerID, BOOL recursive)
|
||||
{
|
||||
//ret var
|
||||
BOOL bRet = NO;
|
||||
|
||||
//owner dictionary
|
||||
NSDictionary* fileOwner = nil;
|
||||
|
||||
//sub paths
|
||||
NSArray *subPaths = nil;
|
||||
|
||||
//full path
|
||||
// ->for recursive
|
||||
NSString* fullPath = nil;
|
||||
|
||||
//init permissions dictionary
|
||||
fileOwner = @{NSFileGroupOwnerAccountID:groupID, NSFileOwnerAccountID:ownerID};
|
||||
|
||||
//set group/owner
|
||||
if(YES != [[NSFileManager defaultManager] setAttributes:fileOwner ofItemAtPath:path error:NULL])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to set ownership for %@ (%@)", path, fileOwner]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"set ownership for %@ (%@)", path, fileOwner]);
|
||||
|
||||
//do it recursively
|
||||
if(YES == recursive)
|
||||
{
|
||||
//sanity check
|
||||
// ->make sure root starts with '/'
|
||||
if(YES != [path hasSuffix:@"/"])
|
||||
{
|
||||
//add '/'
|
||||
path = [NSString stringWithFormat:@"%@/", path];
|
||||
}
|
||||
|
||||
//get all subpaths
|
||||
subPaths = [[NSFileManager defaultManager] subpathsAtPath:path];
|
||||
for(NSString *subPath in subPaths)
|
||||
{
|
||||
//init full path
|
||||
fullPath = [path stringByAppendingString:subPath];
|
||||
|
||||
//set group/owner
|
||||
if(YES != [[NSFileManager defaultManager] setAttributes:fileOwner ofItemAtPath:fullPath error:NULL])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to set ownership for %@ (%@)", fullPath, fileOwner]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//no errors
|
||||
bRet = YES;
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
//set permissions for file
|
||||
void setFilePermissions(NSString* file, int permissions)
|
||||
{
|
||||
//file permissions
|
||||
NSDictionary* filePermissions = nil;
|
||||
|
||||
//new permissions
|
||||
//newPermissions =
|
||||
|
||||
//get current file attributes
|
||||
filePermissions = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:NULL];
|
||||
|
||||
//int currentPermissions = [[filePermissions objectForKey:@"NSFilePosixPermissions"] intValue];
|
||||
//permissions |= (S_IRSUR | S_IRGRP | S_IROTH);
|
||||
// NSDictionary *newattribs = [NSDict dictionaryWithObject:[NSNumber numberWithInt:permissions]
|
||||
// forKey:NSFilePosixPermissions];
|
||||
//[fm setAttributes:dict ofItemAtPath:[file path] error:&error];
|
||||
|
||||
|
||||
|
||||
//init dictionary
|
||||
filePermissions = @{NSFilePosixPermissions: [NSNumber numberWithInt:permissions]};
|
||||
|
||||
//set permissions
|
||||
if(YES != [[NSFileManager defaultManager] setAttributes:filePermissions ofItemAtPath:file error:NULL])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to set permissions for %@ (%@)", file, filePermissions]);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"set permissions for %@ (%@)", file, filePermissions]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//exec a process and grab it's output
|
||||
NSData* execTask(NSString* binaryPath, NSArray* arguments)
|
||||
{
|
||||
|
@ -385,3 +497,5 @@ void makeModal(NSWindowController* windowController)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue