diff --git a/src/platform/DARWIN/AFSPreference/AFSCommanderPref.m b/src/platform/DARWIN/AFSPreference/AFSCommanderPref.m index d0d621a727..15dd12b101 100644 --- a/src/platform/DARWIN/AFSPreference/AFSCommanderPref.m +++ b/src/platform/DARWIN/AFSPreference/AFSCommanderPref.m @@ -750,14 +750,13 @@ // afsStartupSwitchEvent: // ------------------------------------------------------------------------------- - (IBAction) afsStartupSwitchEvent:(id) sender { - NSString *rootHelperApp = [[self bundle] pathForResource:@"afshlp" ofType:@""]; //get the new state startAFSAtLogin = [checkButtonAfsAtBootTime state]; - [PListManager launchctlStringCommandAuth:startAFSAtLogin?@"load":@"unload" - option:[NSArray arrayWithObjects:@"-w", nil] - plistName:@AFS_DAEMON_PATH - helper:rootHelperApp - withAuthRef:[[authView authorization] authorizationRef]]; + if (startAFSAtLogin) { + [TaskUtil executePrivTask:"startup_enable"]; + } else { + [TaskUtil executePrivTask:"startup_disable"]; + } } @@ -878,16 +877,13 @@ { BOOL afsIsUp = [afsProperty checkAfsStatus]; BOOL afsEnabledAtStartup = NO; - NSString *rootHelperApp = [[self bundle] pathForResource:@"afshlp" ofType:@""]; if ([self isUnlocked]) { - afsEnabledAtStartup = ( - [TaskUtil executeTaskWithAuth:@"/bin/launchctl" - arguments:[NSArray arrayWithObjects:@"list", - @"org.openafs.filesystems.afs", nil] - helper:rootHelperApp - withAuthRef:[[authView authorization] authorizationRef] - ] == noErr)?YES:NO; + if ([TaskUtil executePrivTask:"startup_check"] == 0) { + afsEnabledAtStartup = YES; + } else { + afsEnabledAtStartup = NO; + } [checkButtonAfsAtBootTime setState:afsEnabledAtStartup]; } diff --git a/src/platform/DARWIN/AFSPreference/PListManager.h b/src/platform/DARWIN/AFSPreference/PListManager.h index 44f90bffba..1284ffab14 100644 --- a/src/platform/DARWIN/AFSPreference/PListManager.h +++ b/src/platform/DARWIN/AFSPreference/PListManager.h @@ -75,12 +75,6 @@ @discussion <#(comprehensive description)#> */ +(void) launchctlCommand:(BOOL)enable userDomain:(BOOL)userDomain option:(NSArray*)option plistName:(NSString*)plistName; -/*! - @method launchctlCommand - @abstract exec the launchctl command on a particular plist job - @discussion <#(comprehensive description)#> - */ -+(void) launchctlStringCommandAuth:(NSString*)operation option:(NSArray*)option plistName:(NSString*)plistName helper:(NSString *)helper withAuthRef:(AuthorizationRef)authRef; /*! @method launchdJobState @abstract check is a job has been submitted to launchd diff --git a/src/platform/DARWIN/AFSPreference/PListManager.m b/src/platform/DARWIN/AFSPreference/PListManager.m index 977f96236a..e049b2912f 100644 --- a/src/platform/DARWIN/AFSPreference/PListManager.m +++ b/src/platform/DARWIN/AFSPreference/PListManager.m @@ -314,31 +314,6 @@ arguments:argument]; } -// ------------------------------------------------------------------------------- -// launchctlCommand: -// ------------------------------------------------------------------------------- -+(void) launchctlStringCommandAuth:(NSString *)operation - option:(NSArray *)option - plistName:(NSString *)plistName - helper:(NSString *)helper - withAuthRef:(AuthorizationRef)authRef -{ - NSMutableArray *argument = [NSMutableArray array]; - - //set the load unload - [argument addObject:operation]; - - //if there are load the user custom option - if(option) [argument addObjectsFromArray:option]; - - //construct the path - [argument addObject: plistName]; - - //exec the command - [TaskUtil executeTaskWithAuth:@"/bin/launchctl" - arguments:argument helper:helper withAuthRef:authRef]; -} - // ------------------------------------------------------------------------------- // launchdJobState: // ------------------------------------------------------------------------------- diff --git a/src/platform/DARWIN/AFSPreference/TaskUtil.h b/src/platform/DARWIN/AFSPreference/TaskUtil.h index 9e2fa64e23..cd8c53f1a5 100644 --- a/src/platform/DARWIN/AFSPreference/TaskUtil.h +++ b/src/platform/DARWIN/AFSPreference/TaskUtil.h @@ -17,7 +17,5 @@ +(NSString*) searchExecutablePath:(NSString*)unixCommand; +(NSString*) executeTaskSearchingPath:(NSString*)unixCommand args:(NSArray*)args; +(NSString*) executeTask:(NSString*) taskName arguments:(NSArray *)args; -+(int) executeTaskWithAuth:(NSString*) taskName arguments:(NSArray *)args authExtForm:(NSData*)auth; -+(int) executeTaskWithAuth:(NSString*) taskName arguments:(NSArray *)args helper:(NSString *)helper withAuthRef:(AuthorizationRef)authRef; +(int) executePrivTask:(const char *)task; @end diff --git a/src/platform/DARWIN/AFSPreference/TaskUtil.m b/src/platform/DARWIN/AFSPreference/TaskUtil.m index 1e395b4b1d..23d12c3e47 100644 --- a/src/platform/DARWIN/AFSPreference/TaskUtil.m +++ b/src/platform/DARWIN/AFSPreference/TaskUtil.m @@ -75,81 +75,6 @@ return [result autorelease]; } - -// ------------------------------------------------------------------------------- -// executeTask: -// ------------------------------------------------------------------------------- -+(int) executeTaskWithAuth:(NSString*) taskName arguments:(NSArray *)args helper:(NSString *)helper withAuthRef:(AuthorizationRef)authRef { - const char *rootHelperApp = [helper fileSystemRepresentation]; - OSStatus status; - AuthorizationFlags flags = kAuthorizationFlagDefaults; - int count = [args count]; - char **myArguments = calloc(count + 2, sizeof(char *)); - int i=0; - - myArguments[0] = strdup([taskName UTF8String]); - for(i=0;i < count;i++) { - const char *string = [[args objectAtIndex:i] UTF8String]; - if(!string) - break; - myArguments[1+i] = strdup(string); - } - myArguments[1+i] = NULL; - - // should use SMJobBless but we need to sign things... - status = AuthorizationExecuteWithPrivileges(authRef, rootHelperApp, flags, myArguments, NULL); - - i = 0; - while (myArguments[i] != NULL) { - free(myArguments[i]); - i++; - } - - free(myArguments); - return status; -} - -+(int) executeTaskWithAuth:(NSString*) taskName arguments:(NSArray *)args authExtForm:(NSData*)auth { - NSString *result = nil; - int status = 0; - NSFileHandle *file = nil; - NSDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys: @"$PATH:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin",@"PATH",nil]; - - NSPipe *pipe = [NSPipe pipe]; - NSPipe *pipeIn = [NSPipe pipe]; - NSTask *taskToRun = [[NSTask alloc] init]; - - [taskToRun setLaunchPath: taskName]; - [taskToRun setArguments: args]; - [taskToRun setEnvironment:environment]; - [taskToRun setStandardOutput: pipe]; - [taskToRun setStandardInput: pipeIn]; - file = [pipe fileHandleForReading]; - //Write to standard in - [taskToRun launch]; - - NSFileHandle* taskInput = [[ taskToRun standardInput ] fileHandleForWriting ]; - [taskInput writeData:auth]; - [taskToRun waitUntilExit]; - status = [taskToRun terminationStatus]; - if (status == 0){ - NSData *data = [file readDataToEndOfFile]; - // remove the \n character from unix command - if([data length] > 0){ - NSData *realData = [NSData dataWithBytes:[data bytes] - length:[data length]-1]; - - [taskToRun release]; - result = [[NSString alloc] initWithData: realData - encoding: NSUTF8StringEncoding]; - [result release]; - } - } else { - } - - return status; -} - /** * Perform a task that requires root access via privhelper. * diff --git a/src/platform/DARWIN/PrivilegedHelper/privhelper.c b/src/platform/DARWIN/PrivilegedHelper/privhelper.c index 955c75ca2e..0114279aaf 100644 --- a/src/platform/DARWIN/PrivilegedHelper/privhelper.c +++ b/src/platform/DARWIN/PrivilegedHelper/privhelper.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include #include @@ -39,7 +42,11 @@ #include +#define LAUNCHCTL "/bin/launchctl" + #define PRIVHELPER_ID "org.openafs.privhelper" +#define AFS_ID "org.openafs.filesystems.afs" +#define AFS_PLIST "/Library/LaunchDaemons/org.openafs.filesystems.afs.plist" /* * This is the code signing requirement imposed on anyone that connects to our @@ -157,10 +164,81 @@ SecCodeCreateWithXPCMessage(xpc_object_t event, SecCSFlags secflags, SecCodeRef } #endif /* !HAVE_SECCODECREATEWITHXPCMESSAGE */ +static int +RunCommand(int log_failure, const char *arg1, const char *arg2, + const char *arg3, const char *arg4) +{ + extern char **environ; + pid_t pid; + int code; + int status; + const char *argv[] = { + arg1, arg2, arg3, arg4, NULL + }; + + code = posix_spawn(&pid, argv[0], NULL, NULL, argv, environ); + if (code != 0) { + syslog(LOG_ERR, "%s: Failed to execute %s, error %d", PRIVHELPER_ID, + argv[0], code); + return -1; + } + + code = waitpid(pid, &status, 0); + if (code <= 0) { + syslog(LOG_ERR, "%s: waitpid for %s failed, error %d/%d", + PRIVHELPER_ID, argv[0], code, errno); + return -1; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + /* Command exited successfully. */ + return 0; + } + + if (log_failure) { + syslog(LOG_WARNING, "%s: Command %s failed, status %d", + PRIVHELPER_ID, argv[0], status); + } + + return status; +} + +/** + * Run the requested privileged task. + * + * We implement the following tasks: + * + * - startup_enable: Run "launchctl load" to configure the OpenAFS client to + * run at startup. + * + * - startup_disable: Run "launchctl unload" to configure the OpenAFS client to + * not run at startup. + * + * - startup_check: Run "launchctl list" to check whether OpenAFS is configured + * to run at startup. If it is, return 0; otherwise, return nonzero. + * + * @param[in] task The name of the requested task. + * @param[in] event The XPC dictionary containing other task-specific + * arguments. + * + * @returns Return status of the task + * @retval 0 success + * @retval -1 internal error + * @retval nonzero The return value of system() of a failed command for the + * task. + */ static int ProcessRequest(const char *task, xpc_object_t event) { - /* Tasks we understand will be added here as they are implemented. */ + if (strcmp(task, "startup_enable") == 0) { + return RunCommand(1, LAUNCHCTL, "load", "-w", AFS_PLIST); + + } else if (strcmp(task, "startup_disable") == 0) { + return RunCommand(1, LAUNCHCTL, "unload", "-w", AFS_PLIST); + + } else if (strcmp(task, "startup_check") == 0) { + return RunCommand(0, LAUNCHCTL, "list", AFS_ID, NULL); + } syslog(LOG_WARNING, "%s: Received unknown task '%s'", PRIVHELPER_ID, task);