Handle GateKeeper and write permissions in the auto updater

This commit is contained in:
Lior Halphon 2022-07-03 22:23:35 +03:00
parent 3c4bfd2a1b
commit 004c20d8e2
2 changed files with 55 additions and 2 deletions

View File

@ -5,6 +5,7 @@
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#import <JoyKit/JoyKit.h> #import <JoyKit/JoyKit.h>
#import <WebKit/WebKit.h> #import <WebKit/WebKit.h>
#import <mach-o/dyld.h>
#define UPDATE_SERVER "https://sameboy.github.io" #define UPDATE_SERVER "https://sameboy.github.io"
@ -31,6 +32,7 @@ static uint32_t color_to_int(NSColor *color)
UPDATE_FAILED, UPDATE_FAILED,
} _updateState; } _updateState;
NSString *_downloadDirectory; NSString *_downloadDirectory;
AuthorizationRef _auth;
} }
- (void) applicationDidFinishLaunching:(NSNotification *)notification - (void) applicationDidFinishLaunching:(NSNotification *)notification
@ -366,8 +368,55 @@ static uint32_t color_to_int(NSColor *color)
[self.updateWindow performClose:sender]; [self.updateWindow performClose:sender];
} }
- (bool)executePath:(NSString *)path withArguments:(NSArray <NSString *> *)arguments
{
if (!_auth) {
NSTask *task = [[NSTask alloc] init];
task.launchPath = path;
task.arguments = arguments;
[task launch];
[task waitUntilExit];
return task.terminationStatus == 0 && task.terminationReason == NSTaskTerminationReasonExit;
}
char *argv[arguments.count + 1];
argv[arguments.count] = NULL;
for (unsigned i = 0; i < arguments.count; i++) {
argv[i] = (char *)arguments[i].UTF8String;
}
return AuthorizationExecuteWithPrivileges(_auth, path.UTF8String, kAuthorizationFlagDefaults, argv, NULL) == errAuthorizationSuccess;
}
- (void)deauthorize
{
if (_auth) {
AuthorizationFree(_auth, kAuthorizationFlagDefaults);
_auth = nil;
}
}
- (IBAction)installUpdate:(id)sender - (IBAction)installUpdate:(id)sender
{ {
bool needsAuthorization = false;
if ([self executePath:@"/usr/sbin/spctl" withArguments:@[@"--status"]]) { // Succeeds when GateKeeper is on
// GateKeeper is on, we need to --add ourselves as root, else we might get a GateKeeper crash
needsAuthorization = true;
}
else if (access(_dyld_get_image_name(0), W_OK)) {
// We don't have write access, so we need authorization to update as root
needsAuthorization = true;
}
if (needsAuthorization && !_auth) {
AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagPreAuthorize | kAuthorizationFlagInteractionAllowed, &_auth);
// Make sure we can modify the bundle
if (![self executePath:@"/usr/sbin/chown" withArguments:@[@"-R", [NSString stringWithFormat:@"%d:%d", getuid(), getgid()], [NSBundle mainBundle].bundlePath]]) {
[self deauthorize];
return;
}
}
[self.updateProgressSpinner startAnimation:nil]; [self.updateProgressSpinner startAnimation:nil];
self.updateProgressButton.title = @"Cancel"; self.updateProgressButton.title = @"Cancel";
self.updateProgressButton.enabled = true; self.updateProgressButton.enabled = true;
@ -386,8 +435,8 @@ static uint32_t color_to_int(NSColor *color)
appropriateForURL:[[NSBundle mainBundle] bundleURL] appropriateForURL:[[NSBundle mainBundle] bundleURL]
create:true create:true
error:nil] path]; error:nil] path];
NSTask *unzipTask;
if (!_downloadDirectory) { if (!_downloadDirectory) {
[self deauthorize];
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
self.updateProgressButton.enabled = false; self.updateProgressButton.enabled = false;
self.updateProgressLabel.stringValue = @"Failed to extract update."; self.updateProgressLabel.stringValue = @"Failed to extract update.";
@ -399,12 +448,14 @@ static uint32_t color_to_int(NSColor *color)
return; return;
} }
NSTask *unzipTask;
unzipTask = [[NSTask alloc] init]; unzipTask = [[NSTask alloc] init];
unzipTask.launchPath = @"/usr/bin/unzip"; unzipTask.launchPath = @"/usr/bin/unzip";
unzipTask.arguments = @[location.path, @"-d", _downloadDirectory]; unzipTask.arguments = @[location.path, @"-d", _downloadDirectory];
[unzipTask launch]; [unzipTask launch];
[unzipTask waitUntilExit]; [unzipTask waitUntilExit];
if (unzipTask.terminationStatus != 0 || unzipTask.terminationReason != NSTaskTerminationReasonExit) { if (unzipTask.terminationStatus != 0 || unzipTask.terminationReason != NSTaskTerminationReasonExit) {
[self deauthorize];
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil]; [[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
self.updateProgressButton.enabled = false; self.updateProgressButton.enabled = false;
@ -449,6 +500,7 @@ static uint32_t color_to_int(NSColor *color)
NSError *error = nil; NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:contentsPath toPath:contentsTempPath error:&error]; [[NSFileManager defaultManager] moveItemAtPath:contentsPath toPath:contentsTempPath error:&error];
if (error) { if (error) {
[self deauthorize];
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil]; [[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
_downloadDirectory = nil; _downloadDirectory = nil;
dispatch_sync(dispatch_get_main_queue(), ^{ dispatch_sync(dispatch_get_main_queue(), ^{
@ -463,6 +515,7 @@ static uint32_t color_to_int(NSColor *color)
} }
[[NSFileManager defaultManager] moveItemAtPath:updateContentsPath toPath:contentsPath error:&error]; [[NSFileManager defaultManager] moveItemAtPath:updateContentsPath toPath:contentsPath error:&error];
if (error) { if (error) {
[self deauthorize];
[[NSFileManager defaultManager] moveItemAtPath:contentsTempPath toPath:contentsPath error:nil]; [[NSFileManager defaultManager] moveItemAtPath:contentsTempPath toPath:contentsPath error:nil];
[[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil]; [[NSFileManager defaultManager] removeItemAtPath:_downloadDirectory error:nil];
_downloadDirectory = nil; _downloadDirectory = nil;

View File

@ -163,7 +163,7 @@ endif
CFLAGS += -F/Library/Frameworks -mmacosx-version-min=10.9 -isysroot $(SYSROOT) CFLAGS += -F/Library/Frameworks -mmacosx-version-min=10.9 -isysroot $(SYSROOT)
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT) OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT)
LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore -weak_framework Metal -weak_framework MetalKit -mmacosx-version-min=10.9 -isysroot $(SYSROOT) LDFLAGS += -framework AppKit -framework PreferencePanes -framework Carbon -framework QuartzCore -framework Security -weak_framework Metal -weak_framework MetalKit -mmacosx-version-min=10.9 -isysroot $(SYSROOT)
GL_LDFLAGS := -framework OpenGL GL_LDFLAGS := -framework OpenGL
endif endif
CFLAGS += -Wno-deprecated-declarations CFLAGS += -Wno-deprecated-declarations