6

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?

Lukas1
  • 582
  • 1
  • 5
  • 28

2 Answers2

4

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;
     }
 }
MeIr
  • 7,236
  • 6
  • 47
  • 80
  • Thanks! I'm adding a thumbs up, although I haven't tried it. I ended up using this: http://stackoverflow.com/questions/6841937/authorizationexecutewithprivileges-is-deprecated I'd still like to try solution provided by arri, if it's possible to avoid hacking it with apple script (which produces it's own prompt for password and that's not desirable) – Lukas1 Aug 26 '14 at 07:32
  • Thank you, I am working on similar problem and what I found out is that you can NOT load/unload daemon via above example or using STPriviliegedTask. If you want solution let me know. – MeIr Aug 26 '14 at 20:46
  • what do you mean 'via above example' -> the one that I posted as a question, or the Apple Script that I posted to this comment? Because for me, the Apple Script works, but it produces a duplicate prompt for password, which is not totally desirable; – Lukas1 Aug 27 '14 at 07:43
  • "Above example" - mean one in the question. I have a solution without AppleScript. Let me know if you want to see it. – MeIr Aug 27 '14 at 16:35
  • Yes, I'd like to see it, please – Lukas1 Aug 28 '14 at 08:40
  • I posted update to my answer. Use above code to create command utility and run it via your code or STPrivilegedTask and you will load/unload daemons. – MeIr Aug 28 '14 at 17:14
  • Hi, thanks for the update. The code runs and no error is generated from NSTask(which is kind of weird, I'd expect something), but it doesn't start the samba daemon. I don't understand why. I suppose it would work for launching other daemons, but not the Samba... It seems sticking to the apple script solution (which works for me) is my only option – Lukas1 Sep 03 '14 at 07:55
  • btw setuid(0); doesn't seem to do anything at all – Lukas1 Sep 03 '14 at 07:56
  • It might not seem like it but check which user is running it and you will see one setuid runs, you will see root running. – MeIr Sep 13 '14 at 03:22
  • by that I means it doesn't fix my issue ;o) I just used the Apple script approach, which works. – Lukas1 Oct 10 '14 at 07:46
  • for me, setuid(0) doesn't seem to have any effect. I don't try to run an NSTask, but rather to simply copy a launchd daemon definition .plist into place "/Library/LaunchDaemons/" -- to no avail. As the methods I'm using don't return an NSError - only a boolean, I don't even know what's wrong. Only when I'm copying within my users's home directory and sub-directories - it works fine. – Motti Shneor Nov 30 '20 at 16:06
0

Looking at the documentation, it seems that your code is missing the kAuthorizationFlagExtendRightsflag, which is required when the Security Server is to grant requested rights. The relevant excerpt;

... ThekAuthorizationFlagDefaultsconstant zeros the bit mask. The kAuthorizationFlagExtendRightsconstant instructs the Security Server to grant the rights. Without this flag, theAuthorizationCopyRights andAuthorizationCreatefunctions would return the appropriate error code, but no rights would be extended to the user ...

From the documentation forkAuthorizationFlagExtendRights:

kAuthorizationFlagExtendRights

If the bit specified by this mask is set, the Security Server attempts to grant the rights requested ...

Try adding this flag to yourflagsbefore callingAuthorizationCopyRights(), and perhaps also include kAuthorizationFlagPartialRights to limit granted permissions a bit more.

arri
  • 371
  • 4
  • 7
  • however, as I mentioned, writing this: `flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;` produces error code -60011 (invalid flags). I don't understand why it would do that. Perhaps there's a problem in my AuthorizationCreate call? Would you know the answer for that please? – Lukas1 Aug 26 '14 at 07:28
  • ahh, I didn't see `kAuthorizationFlagExtendRights` mentioned anywhere, so thought that might be what you were overlooking. – arri Aug 27 '14 at 11:56
  • but it's completely possible, that I'm missing those rights, but I don't understand why I get that invalid flags error code... the code comes from the apple documentation, so I'd expect it to work ;o) – Lukas1 Aug 27 '14 at 12:15