AuthorizationExecuteWithPrivileges is deprecated
Asked Answered
A

4

38

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?

Alembic answered 27/7, 2011 at 9:11 Comment(0)
W
37

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.

Weihs answered 27/7, 2011 at 9:31 Comment(8)
Hi, thanks for the reply. If AuthorizationExecuteWithPrivileges() has been deprecated for a long time, should it still continue to work? Basically, this stopped working in my application since the Lion update, and I assumed it was because it is now being marked as deprecated... Should it infact still work, and my problem lies elsewhere? Many thanksAlembic
You shouldn't be relying on AuthorizationExecuteWithPrivileges(), it's a horrendous security hole. The way to do what you want to do is with SMJobBless().Weihs
@GrahamLee And what about using AuthorizationExecuteWithPrivileges for the installer? Reference says that "You should use this function only to allow installers to run as root and to allow a setuid tool to repair its setuid bit if lost" and Authorization Services Programming Guide suggests to use this function to launch installers (although it somewhat outdated). Is there any alternative to launch installer in simple application like command line tool?Murrelet
That's out of date, too. If you're using System Management you can deploy the privileged components without an installer.Weihs
@GrahamLee. Well ok, and what if I have a pkg file and I want to launch installer utility on it? How can I do that without using deprecated functionality. Can I use system utilities as helper tool? I understand that I can launch installer with NSWorkspace class. But I don't need a GUI installer app, I want to do it quietly and I need an install process exit code, so I need to wait for it. What can you suggest in such case?Murrelet
@Murrelet hopefully you've found a solution in the past six years, but for the record—I was able to run installer as root from a privileged helper tool using posix_spawnEdmead
Would this work on BigSur (macOS 11.6)? Otherwise how to get admin permission? I'm trying to write an app Uninstaller which uses NSFileManager to delete /Applications/MyApplication.app folder and some app data in ~/Library/Application Support/my.app/Sun
@Weihs what's insecure about AuthorizationExecuteWithPrivileges()? And the reference docs for SMJobBless() say that it's deprecated now, too :( What's the replacement in 2022? developer.apple.com/documentation/servicemanagement/…Reinke
O
37

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.

Odlo answered 14/1, 2012 at 20:53 Comment(8)
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.Barium
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?Boeotia
FYI: As documented in Technical Note TN2065: do shell script in AppleScript (developer.apple.com/library/mac/#technotes/tn2065/_index.html): Use the administrator privileges, user name and password parameters like this: do shell script "command" user name "me" password "mypassword" with administrator privilegesStempien
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.Murrelet
I am getting DYLD_ environment variables being ignored because main executable (/usr/libexec/security_authtrampoline) is setuid or setgid on 10.8Immingle
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...Nebuchadnezzar
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.Minos
The AppleScript approach no longer seems to work on macOS 12. For example: % osascript -e 'do shell script "/bin/sh ./hello.sh" with administrator privileges' errors with the following message: 0:82: execution error: /bin/sh: ./hello.sh: Operation not permitted (126). However the same command runs successfully if the with administrator privileges portion is omitted from AppleScript. (P.S. The script hello.sh has required r/w/x permissions, etc.)Clougher
G
18

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.

Gies answered 6/3, 2013 at 13:27 Comment(3)
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.Rotter
Hi, is there a way to add the app icon in the password prompt in place of the blank file with your solution?Hurtle
@Hurtle I don't believe so, as the prompt is delivered by Applescript itselfGies
P
7

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

Premonish answered 24/3, 2013 at 13:38 Comment(2)
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.Premonish
Have you run a project successfully yet? It was asking for code signing of the app with an OSX developer account.Legislatorial

© 2022 - 2024 — McMap. All rights reserved.