Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OSX launchctl programmatically as root

I'm trying to start samba service using launchctl from OSX app as root, but I get error status -60031. I can run without problems the command in Terminal:

sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.smbd.plist

In the objective-c code, I'm using (I know it's deprecated, but that really shouldn't be the issue here) AuthorizationExecuteWithPrivileges method.

Here's the code:

    NSString *command = @"launchctl";

    // Conversion of NSArray args to char** args here (not relevant part of the code)

    OSStatus authStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &_authRef);
    if (authStatus != errAuthorizationSuccess) {
        NSLog(@"Failed to create application authorization: %d", (int)authStatus);
        return;
    }

    FILE* pipe = NULL;
    AuthorizationFlags flags = kAuthorizationFlagDefaults;
    AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
    AuthorizationRights rights = {1, &right};

    // Call AuthorizationCopyRights to determine or extend the allowable rights.
    OSStatus stat = AuthorizationCopyRights(_authRef, &rights, NULL, flags, NULL);
    if (stat != errAuthorizationSuccess) {
        NSLog(@"Copy Rights Unsuccessful: %d", (int)stat);
        return;
    }

    OSStatus status = AuthorizationExecuteWithPrivileges(_authRef,
                                                         command.UTF8String,
                                                         flags,
                                                         args,
                                                         &pipe);
    if (status != errAuthorizationSuccess) {
        NSLog(@"Error executing command %@ with status %d", command, status);
    } else {
        // some other stuff
    }

I have also tried using different flags then kAuthorizationFlagDefaults, but that led to either the same problem or error code -60011 -> invalid flags.

What am I doing wrong here, please?

like image 985
Lukas1 Avatar asked Aug 19 '14 09:08

Lukas1


1 Answers

I would suggest to use STPrivilegedTask - https://github.com/sveinbjornt/STPrivilegedTask

I had similar issue and I found above nicely written wrapper. It is straight forward and very simple. You can modify it to your needs if you have to, otherwise use it as it!!!

It worked for me, I hope it will help you as well.

Thanks.

Updated (Aug 28, 2014): There is a difference between execute command with root privileges and execute command as root!

In your particular case you are trying to load/unload daemon (which must belong to root). In that case you MUST execute command as root. If you try to load/unload only with root privileges then you will run daemon under your user! - not good!

Now, your code example and my reference to STPrivilegedTask, both use the same code and allow user to execute a task with root privileges but NOT as root! In order to execute as root you have several choices. First you might wanna check out Apple Docs for a recommended way. In my case I couldn't go with recommended way because my application is not signed and will not be signed + it needs to work on a old OSX.

So my solution is simple. Make a command utility helper tool, let it assume root and execute anything you pass into it via arguments. Now please take a note (it is NOT very secure way of doing things). Also note that you will make a call to helper tool with root privilege and it will assume a root identity.

Code:

 int main(int argc, const char * argv[])
 {

@autoreleasepool {

    if (argc >= 2)
    {
        setuid(0);  // Here is a key - set user id to 0 - meaning become a root and everything below executes as root.

        NSMutableArray *arguments = [[NSMutableArray alloc] init];
        NSString *command = [[NSString alloc] initWithFormat:@"%s", argv[1]];

        for (int idx = 2; idx < argc; idx++) {
            NSString *tmp = [[NSString alloc] initWithFormat:@"%s", argv[idx]];
            [arguments addObject:tmp];
        }

        NSTask *task = [[NSTask alloc] init];
        [task setLaunchPath:command];
        [task setArguments:arguments];

        NSPipe * out = [NSPipe pipe];
        [task setStandardOutput:out];
        [task launch];

        [task waitUntilExit];

        NSFileHandle * read = [out fileHandleForReading];
        NSData * dataRead = [read readDataToEndOfFile];
        NSString * stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];

        printf("%s", [stringRead UTF8String]);

        }
     return 0;
     }
 }
like image 56
MeIr Avatar answered Nov 03 '22 08:11

MeIr