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?
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?
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.
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.
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.
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