DARWIN: Convert prefpane startup ops to privhelper

Convert the logic for the "start at login" option in the prefpane to use
privhelper, so it can work with macOS 10.8+.

Specifically, define these new privhelper tasks:

- startup_enable
- startup_disable
- startup_check

And convert our startup-related logic in the prefpane to use them.

Get rid of our now-unused method executeTaskWithAuth() and related
methods.

Change-Id: I2cb4c31f964529ab1af43ab7828c14eba7354af0
Reviewed-on: https://gerrit.openafs.org/15957
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Reviewed-by: Mark Vitale <mvitale@sinenomine.net>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
This commit is contained in:
Marcio Barbosa 2024-11-23 03:31:54 -08:00 committed by Andrew Deason
parent 120871f03f
commit 89eafda960
6 changed files with 89 additions and 123 deletions

View File

@ -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];
}

View File

@ -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

View File

@ -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:
// -------------------------------------------------------------------------------

View File

@ -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

View File

@ -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.
*

View File

@ -29,6 +29,9 @@
#include <syslog.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <spawn.h>
#include <xpc/xpc.h>
#include <Security/Security.h>
@ -39,7 +42,11 @@
#include <xpc/xpc.h>
#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);