AuthorizationExecuteWithPrivileges is deprecated

2019-01-02 15:54发布

问题:

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?

回答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.



回答2:

In fact, AuthorizationExecuteWithPrivileges() has been deprecated for a very long time, it's only recently that the header file has caught up with this fact.

You can create a privileged helper tool as part of your application. You can use ServiceManagement.framework's SMJobBless() function to have the helper deployed into the system launchd context: then when you need to perform privileged tasks, you just message the privileged helper to do that work.

There's a little bit of hidden complexity, in that the app and the helper must each declare the signing identity of the other before SMJobBless() believes they're supposed to be used together, and you need to get the linker to write the helper tool's Info.plist file into the binary. That's all covered by Apple's Documentation and Apple have provided a sample project, too.

I wrote an example application that uses SMJobBless() to deploy its privileged helper.



回答3:

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.



回答4:

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



标签: