Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XPC service for Lion Sandboxing #165

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions Configurations/ConfigService.xcconfig
@@ -0,0 +1,5 @@
// Sandbox Service only

PRODUCT_NAME = com.andymatuschak.Sparkle.SandboxService
WRAPPER_EXTENSION = xpc
MACH_O_TYPE = mh_execute
5 changes: 5 additions & 0 deletions Configurations/ConfigServiceDebug.xcconfig
@@ -0,0 +1,5 @@
#include "ConfigCommon.xcconfig"
#include "ConfigCommonDebug.xcconfig"
#include "ConfigService.xcconfig"

OTHER_CFLAGS = -fsingle-precision-constant -DDEBUG
3 changes: 3 additions & 0 deletions Configurations/ConfigServiceRelease.xcconfig
@@ -0,0 +1,3 @@
#include "ConfigCommon.xcconfig"
#include "ConfigCommonRelease.xcconfig"
#include "ConfigService.xcconfig"
18 changes: 16 additions & 2 deletions SUBasicUpdateDriver.m
Expand Up @@ -19,6 +19,7 @@
#import "SUPlainInstallerInternals.h"
#import "SUBinaryDeltaCommon.h"
#import "SUUpdater_Private.h"
#import "SUXPC.h"

@interface SUBasicUpdateDriver () <NSURLDownloadDelegate>; @end

Expand Down Expand Up @@ -272,6 +273,10 @@ - (void)installWithToolAndRelaunch:(BOOL)relaunch
[self abortUpdate];
return;
}

BOOL running10_7 = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6;
BOOL useXPC = running10_7 && [[NSFileManager defaultManager] fileExistsAtPath:
[[host bundlePath] stringByAppendingPathComponent:@"Contents/XPCServices/com.andymatuschak.Sparkle.SandboxService.xpc"]];

// Give the host app an opportunity to postpone the install and relaunch.
static BOOL postponedOnce = NO;
Expand Down Expand Up @@ -302,7 +307,12 @@ - (void)installWithToolAndRelaunch:(BOOL)relaunch
#endif

// Only the paranoid survive: if there's already a stray copy of relaunch there, we would have problems.
if( [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error] )
BOOL copiedRelaunchTool = FALSE;
if( useXPC )
copiedRelaunchTool = [SUXPC copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error];
else
copiedRelaunchTool = [SUPlainInstaller copyPathWithAuthentication: relaunchPathToCopy overPath: targetPath temporaryName: nil error: &error];
if( copiedRelaunchTool )
relaunchPath = [targetPath retain];
else
[self abortUpdateWithError:[NSError errorWithDomain:SUSparkleErrorDomain code:SURelaunchError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:SULocalizedString(@"An error occurred while extracting the archive. Please try again later.", nil), NSLocalizedDescriptionKey, [NSString stringWithFormat:@"Couldn't copy relauncher (%@) to temporary path (%@)! %@", relaunchPathToCopy, targetPath, (error ? [error localizedDescription] : @"")], NSLocalizedFailureReasonErrorKey, nil]]];
Expand All @@ -323,7 +333,11 @@ - (void)installWithToolAndRelaunch:(BOOL)relaunch
if ([[updater delegate] respondsToSelector:@selector(pathToRelaunchForUpdater:)])
pathToRelaunch = [[updater delegate] pathToRelaunchForUpdater:updater];
NSString *relaunchToolPath = [relaunchPath stringByAppendingPathComponent: @"/Contents/MacOS/finish_installation"];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:[host bundlePath], pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil]];
NSArray *arguments = [NSArray arrayWithObjects:[host bundlePath], pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil];
if( useXPC )
[SUXPC launchTaskWithLaunchPath: relaunchToolPath arguments:arguments];
else
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:arguments];

[NSApp terminate:self];
}
Expand Down
5 changes: 4 additions & 1 deletion SUPlainInstallerInternals.m
Expand Up @@ -524,7 +524,10 @@ + (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temp
// new home in case it's moved across filesystems: if that
// happens, the move is actually a copy, and it may result
// in the application being quarantined.
[self performSelectorOnMainThread:@selector(releaseFromQuarantine:) withObject:dst waitUntilDone:YES];
if ([NSThread isMultiThreaded])
[self performSelectorOnMainThread:@selector(releaseFromQuarantine:) withObject:dst waitUntilDone:YES];
else
[self releaseFromQuarantine:dst];

return YES;
}
Expand Down
16 changes: 16 additions & 0 deletions SUXPC.h
@@ -0,0 +1,16 @@
//
// SUXPC.h
// Sparkle
//
// Created by Whitney Young on 3/19/12.
// Copyright (c) 2012 FadingRed. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface SUXPC : NSObject

+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error;
+ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;

@end
72 changes: 72 additions & 0 deletions SUXPC.m
@@ -0,0 +1,72 @@
//
// SUXPC.m
// Sparkle
//
// Created by Whitney Young on 3/19/12.
// Copyright (c) 2012 FadingRed. All rights reserved.
//

#import <xpc/xpc.h>
#import "SUXPC.h"


@implementation SUXPC

+ (BOOL)copyPathWithAuthentication:(NSString *)src overPath:(NSString *)dst temporaryName:(NSString *)tmp error:(NSError **)error {
xpc_connection_t connection = xpc_connection_create("com.andymatuschak.Sparkle.SandboxService", NULL);
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
xpc_dictionary_apply(event, ^bool(const char *key, xpc_object_t value) {
NSLog(@"XPC %s: %s", key, xpc_string_get_string_ptr(value));
return true;
});
});
xpc_connection_resume(connection);

xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "id", "copy_path");

if( src )
xpc_dictionary_set_string(message, "source", [src fileSystemRepresentation]);
if( dst )
xpc_dictionary_set_string(message, "destination", [dst fileSystemRepresentation]);
if( tmp )
xpc_dictionary_set_string(message, "tmp", [tmp UTF8String]);

xpc_object_t response = xpc_connection_send_message_with_reply_sync(connection, message);
xpc_type_t type = xpc_get_type(response);
return type == XPC_TYPE_DICTIONARY;
}

+ (void)launchTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments {
xpc_connection_t connection = xpc_connection_create("com.andymatuschak.Sparkle.SandboxService", NULL);
xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
xpc_dictionary_apply(event, ^bool(const char *key, xpc_object_t value) {
NSLog(@"XPC %s: %s", key, xpc_string_get_string_ptr(value));
return true;
});
});
xpc_connection_resume(connection);

xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "id", "launch_task");

if( path )
xpc_dictionary_set_string(message, "path", [path fileSystemRepresentation]);

xpc_object_t array = xpc_array_create(NULL, 0);
for (id argument in arguments) {
xpc_array_append_value(array, xpc_string_create([argument UTF8String]));
}

xpc_dictionary_set_value(message, "arguments", array);

xpc_object_t response = xpc_connection_send_message_with_reply_sync(connection, message);
xpc_type_t type = xpc_get_type(response);
BOOL success = (type == XPC_TYPE_DICTIONARY);

if (!success) {
NSLog(@"XPC launch error");
}
}

@end
29 changes: 29 additions & 0 deletions SandboxService.plist
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>XPCService</key>
<dict>
<key>ServiceType</key>
<string>Application</string>
</dict>
</dict>
</plist>