3

I have an application that requires executing a command with sudo. How can I ask for a password and if successful, then run the sudo command using NSTask.

ed1t
  • 8,719
  • 17
  • 67
  • 110
  • possible duplicate of [How to give permission using NSTask - objective-c](http://stackoverflow.com/questions/3541654/how-to-give-permission-using-nstask-objective-c) –  Jul 09 '11 at 02:27
  • This is not a duplicate of that question. This question is about *actually using sudo* (though I agree that the correct answer is “use Authorization Services instead”). – Peter Hosey Jul 09 '11 at 13:09

2 Answers2

3

If you're looking for a more lightweight solution, there is another way. I wrote this generic implementation which should achieve what you want:

- (BOOL) runProcessAsAdministrator:(NSString*)scriptPath
                     withArguments:(NSArray *)arguments
                            output:(NSString **)output
                  errorDescription:(NSString **)errorDescription {

    NSString * allArgs = [arguments componentsJoinedByString:@" "];
    NSString * fullScript = [NSString stringWithFormat:@"%@ %@", scriptPath, allArgs];

    NSDictionary *errorInfo = [NSDictionary new];
    NSString *script =  [NSString stringWithFormat:@"do shell script \"%@\" with administrator privileges", fullScript];

    NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
    NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];

    // Check errorInfo
    if (! eventResult)
    {
        // Describe common errors
        *errorDescription = nil;
        if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
        {
            NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
            if ([errorNumber intValue] == -128)
                *errorDescription = @"The administrator password is required to do this.";
        }

        // Set error message from provided message
        if (*errorDescription == nil)
        {
            if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
                *errorDescription =  (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
        }

        return NO;
    }
    else
    {
        // Set output to the AppleScript's output
        *output = [eventResult stringValue];

        return YES;
    }
}

Usage example:

    NSString * output = nil;
    NSString * processErrorDescription = nil;
    BOOL success = [self runProcessAsAdministrator:@"/usr/bin/id"
                    withArguments:[NSArray arrayWithObjects:@"-un", nil]
                           output:&output
                            errorDescription:&processErrorDescription
                  asAdministrator:YES];


    if (!success) // Process failed to run
    {
         // ...look at errorDescription 
    }
    else
    {
         // ...process output
    }

Hat tip to user950473.

Community
  • 1
  • 1
Carlos P
  • 3,928
  • 2
  • 34
  • 50
1

Use the Authorization Services, Luke. (If you've ever seen the "Application XYZ needs an admin password to continue", this is how it's implemented. It does not use sudo under the sheets.)

http://developer.apple.com/library/mac/#documentation/Security/Conceptual/authorization_concepts/01introduction/introduction.html