AuthorizationExecuteWithPrivileges is deprecated

22,549

Solution 1

I know it sounds crazy, but this actually works:

NSDictionary *error = [NSDictionary new]; 
NSString *script =  @"do shell script \"whoami > /tmp/me\" with administrator privileges";  
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:script]; 
if ([appleScript executeAndReturnError:&error]) {
  NSLog(@"success!"); 
} else {
  NSLog(@"failure!"); 
}

I'm executing an Applescript from Objective C. The only disadvantage is that you cannot gain permanent root privileges with this. It will ask for the password each time you run this.

Solution 2

Based on a great find by user950473 I've implemented his/her discovery as a method; thought I'd share the code in case it's helpful.

- (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];


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

It's very slightly hacky, but IMHO is a satisfactory solution.

Solution 3

AuthorizationExecuteWithPrivileges is indeed deprecated.
But fortunately, there is a new recommended way to proceed.

As of 10.6 there is the new API and it is recommended to install a helper tool that will perform the privileged operation. Apple provide a code sample that clearly demonstrate how to manage it.

Make sure you check out their readme.txt since contrarily to other code sample there is more to do than just downloading the project and running it.

From The SMJobBless example introduction

SMJobBless demonstrates how to securely install a helper tool that performs a privileged operation and how to associate the tool with an application that invokes it.

As of Snow Leopard, this is the preferred method of managing privilege escalation on Mac OS X and should be used instead of earlier approaches such as BetterAuthorizationSample or directly calling AuthorizationExecuteWithPrivileges.

SMJobBless uses ServiceManagement.framework that was introduced in Mac OS X v10.6 Snow Leopard.

Source: Apple SMJobBless code sample

Share:
22,549
Admin
Author by

Admin

Updated on October 03, 2020

Comments

  • Admin
    Admin over 3 years

    Since updating to OSX 10.7 Lion, Xcode tells me that AuthorizationExecuteWithPrivileges is deprecated.

    Can anyone suggest a way my application can write to a directory it doesn't have permission for?

  • Alex Gray
    Alex Gray about 12 years
    Would ya look at that. so YOU'RE root?! Oh wait, I am. No, wait.. AppleScript is? Jesus. That is certainly crazy. The only thing that would be crazier is if it didn't ask for your password, lol.
  • ArtOfWarfare
    ArtOfWarfare almost 12 years
    I attempted to use this but it didn't ask me for my password ever. Instead it just skipped to printing "failure!" When I printed the description of error, I got this: "NSAppleScriptErrorMessage = "The administrator user name or password was incorrect.";" This is in an app with the sandbox enabled... does anyone have suggestions that work with a sandbox enabled app?
  • geowar
    geowar over 11 years
    FYI: As documented in Technical Note TN2065: do shell script in AppleScript (developer.apple.com/library/mac/#technotes/tn2065/_index.ht‌​ml): Use the administrator privileges, user name and password parameters like this: do shell script "command" user name "me" password "mypassword" with administrator privileges
  • Jim
    Jim almost 11 years
    This method fails if there is a space in the path of the script, which is likely if you want to run a script included in your application bundle. To fix this, just change the format when setting fullScript to @"'%@' %@" so the process path name is quoted.
  • cody
    cody almost 11 years
    Note, that Threading Programming Guide says that NSAppleScript class must be used only from the main thread of an application. Although I myself using it not only in the main thread and have no problems.
  • Parag Bafna
    Parag Bafna over 10 years
    I am getting DYLD_ environment variables being ignored because main executable (/usr/libexec/security_authtrampoline) is setuid or setgid on 10.8
  • Jean
    Jean over 10 years
    Why would you say that? I was able to download the sample code today, using the link I provided and a non-paid developer account.
  • Fast Engy
    Fast Engy over 10 years
    Have you run a project successfully yet? It was asking for code signing of the app with an OSX developer account.
  • kainjow
    kainjow about 10 years
    You can gain permanent root privileges if you a) create a separate binary that will do what you want as root, b) copy that binary to a safe writable location (e.g. /Library/Application Support/xxx), c) set the setuid bit on that binary, d) chown the binary as root, and e) chmod the binary appropriately. Maybe I'll create an example project on Github one day...
  • Yann86
    Yann86 almost 10 years
    Hi, is there a way to add the app icon in the password prompt in place of the blank file with your solution?
  • Carlos P
    Carlos P almost 10 years
    @Yann86 I don't believe so, as the prompt is delivered by Applescript itself
  • Motti Shneor
    Motti Shneor over 3 years
    I don't know why you and others are surprised. AppleScript is designed to be standalone, and maintain complex flows and scenarios. So it makes things easy (and NOT less secure). It does NOT run as root, and you don't need "root" for copying files to anywhere - you just need the "Full Disk Access" capability. Plus - administrator privileges are NOT root. Macs can run root-less and still copy files anywhere. It's probably the easiest thing to do programmatically, but not a fast or preferable solution.