How to add Root privileges to my OSX application? - objective-c

I made an application as root user, it worked perfectly(in root user). When I try same application with a standard user it didn't work out. Then I get to know that I need root privileges to run the application. I Google for few day but didn't get it. I have read some questions and apple doc. which are-
https://developer.apple.com/library/mac/documentation/Security/Conceptual/authorization_concepts/01introduction/introduction.html
How to set my application to always run as root OSX
How to programmatically gain root privileges?
How to running application under root privilege?
but still I didn't get anything.
One more thing I get to know is I need to make a new project to get the root privileges, Am I right? Anything that you can tell me that will help me please do it. Every suggestion is most welcome.
for now I am trying this-
- (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;
}
}
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
{
[objDisk setFileDescriptor:open(cDriveMountedPath, O_RDONLY)];
//[objDisk setDiskPath:cDriveMountedPath];
}
Thanks a lot in advance.

I use this code to get the root privilege for my application. I made a new project to use this code.
// Create authorization reference
OSStatus status;
AuthorizationRef authorizationRef;
// AuthorizationCreate and pass NULL as the initial
// AuthorizationRights set so that the AuthorizationRef gets created
// successfully, and then later call AuthorizationCopyRights to
// determine or extend the allowable rights.
// http://developer.apple.com/qa/qa2001/qa1172.html
status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults, &authorizationRef);
if (status != errAuthorizationSuccess)
NSLog(#"Error Creating Initial Authorization: %d", status);
// kAuthorizationRightExecute == "system.privilege.admin"
AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights rights = {1, &right};
AuthorizationFlags flags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
// Call AuthorizationCopyRights to determine or extend the allowable rights.
status = AuthorizationCopyRights(authorizationRef, &rights, NULL, flags, NULL);
if (status != errAuthorizationSuccess)
NSLog(#"Copy Rights Unsuccessful: %d", status);
NSLog(#"\n\n** %# **\n\n", #"This command should work.");
char *tool = "/sbin/dmesg";
char *args[] = {NULL};
FILE *pipe = NULL;
status = AuthorizationExecuteWithPrivileges(authorizationRef, tool,
flags, args, &pipe);
if (status != errAuthorizationSuccess)
NSLog(#"Error: %d", status);
// The only way to guarantee that a credential acquired when you
// request a right is not shared with other authorization instances is
// to destroy the credential. To do so, call the AuthorizationFree
// function with the flag kAuthorizationFlagDestroyRights.
// http://developer.apple.com/documentation/Security/Conceptual/authorization_concepts/02authconcepts/chapter_2_section_7.html
status = AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);

Related

objective c gets EXC_BAD_ACCESS error on completionhandler

i'm new to objective-c, please bear with me if i ask stupid questions :)
The following is part of code i have to start vpn tunnel, but keeps getting EXC_BAD_ACCESS error
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL * error))completionHandler {
vpnAdapter = [[OpenAdapter alloc] init];
vpnAdapter.delegate = self;
// get config
config = [[NSDictionary alloc] init];
NETunnelProviderProtocol *protocol = (NETunnelProviderProtocol *)self.protocolConfiguration;
config = protocol.providerConfiguration;
host = config[#"server"];
// Load config data
username = config[#"username"];
password = config[#"password"];
if(option != nil){
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
// return success;
completionHandler(&success); // Thread 2: EXC_BAD_ACCESS (code=1, address=0xbcc68f020)
}];
}else{
[vpnAdapter connect:host user:username pass:password add:NO completionHandler:^(BOOL success){
completionHandler(&success);
}];
}
}
here is connect method
- (void)connect: (NSString *) host user:(NSString *)username pass:(NSString *) password add:(Boolean) isAdd completionHandler:(void (^)(BOOL success)) completionHandler{
dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.open-adapter.connection", attributes);
dispatch_async(connectQueue, ^{
// Call connect
//int ret=1;
NSArray* options = [NSArray arrayWithObjects:
#"--user", username,
host,
nil];
if(isAdd){
options = [NSArray arrayWithObjects:
#"--user", username,
#"--protocol", #"ad",
host,
nil];
}
//NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
//NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:1+[options count]];
[arguments addObject:#"connect"];
[arguments addObjectsFromArray:options];
int argc = [arguments count];
char **argv = (char **)malloc(sizeof(char*) * (argc + 1));
[arguments enumerateObjectsUsingBlock:^(NSString *option, NSUInteger i, BOOL *stop) {
const char * c_string = [option UTF8String];
int length = (int)strlen(c_string);
char *c_string_copy = (char *) malloc(sizeof(char) * (length + 1));
strcpy(c_string_copy, c_string);
argv[i] = c_string_copy;
}];
argv[argc] = NULL;
const char *cfPass=[password UTF8String];
int ret = self.vpnClient->start2connect(argc, argv, cfPass);
BOOL result;
if (ret!=0){
result=false;
}
else {result = true;}
completionHandler(result);
});
}
all of these are from networkextension and while debugging, i found int ret = self.vpnClient->start2connect(argc, argv, cfPass);
seems not returning any value.
however, i confirmed that the start2connect method does return int value
so for now, anyone can help explain what's wrong?
thanks
The BOOL * is a pointer to a BOOL. We don’t use that pattern very often. We use it where the block needs to update a BOOL property somewhere, e.g. in enumerateMatchesinString, where you can update the boolean that stop points to in order to stop the enumeration.
But this is a completion handler, so there’s no point in passing a pointer to the boolean (one that presumably was on the stack, inviting problems). Just pass the boolean itself, not a pointer to it.
I would suggest that instead of:
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL * error))completionHandler {
...
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
completionHandler(&success);
}];
...
}
That you want:
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL success))completionHandler {
...
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
completionHandler(success);
}];
...
}
Note the block parameter isn’t BOOL * error but rather BOOL success and when it calls the completionHandler, there’s not & before success.
If there’s some reason you needed to update the BOOL, then that’s a different matter, but it doesn’t make sense in the context of a completion handler.

Is there anyway to access system keychain in OS X from objective C

I am trying to save Password in system keychain but it gives a "write permission error", is there any way to access it as root and save password using AuthorizationRef or anything?
+ (int) createItem:(NSString*)label withService:(NSString*)service account:(NSString*)account description:(NSString*)description andPassword:(NSString*)password {
// This variable will hold all sorts of operation status responses
OSStatus status;
// Converting the NSStrings to char* variables which we will need later
const char *labelUTF8 = [label UTF8String];
const char *serviceUTF8 = [service UTF8String];
const char *accountUTF8 = [account UTF8String];
const char *descriptionUTF8 = [description UTF8String];
const char *passwordUTF8 = [password UTF8String];
// This variable is soon to hold the System Keychain
SecKeychainRef keychain = NULL;
status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &keychain);
if (status == errSecSuccess) {
NSLog(#"Succeeded opening System Keychain");
} else {
NSLog(#"Could not obtain System Keychain: %#", SecCopyErrorMessageString(status, NULL));
return 60;
}
NSLog(#"Unlocking System Keychain");
status = SecKeychainUnlock(keychain, 0, NULL, FALSE);
if (status == errSecSuccess) {
NSLog(#"Succeeded unlocking System Keychain");
} else {
NSLog(#"Could not unlock System Keychain: %#", SecCopyErrorMessageString(status, NULL));
return 61;
}
// This variable is going to hold our new Keychain Item
SecKeychainItemRef item = nil;
SecAccessRef access = nil;
status = SecAccessCreate(CFSTR("Some VPN Test"), (__bridge CFArrayRef)(self.trustedApps), &access);
if(status == noErr) {
NSLog(#"Created empty Keychain access object");
} else {
NSLog(#"Could not unlock System Keychain: %#", SecCopyErrorMessageString(status, NULL));
return 62;
}
// Putting together the configuration options
SecKeychainAttribute attrs[] = {
{kSecLabelItemAttr, (int)strlen(labelUTF8), (char *)labelUTF8},
{kSecAccountItemAttr, (int)strlen(accountUTF8), (char *)accountUTF8},
{kSecServiceItemAttr, (int)strlen(serviceUTF8), (char *)serviceUTF8},
{kSecDescriptionItemAttr, (int)strlen(descriptionUTF8), (char *)descriptionUTF8},
};
SecKeychainAttributeList attributes = {sizeof(attrs) / sizeof(attrs[0]), attrs};
status = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, (int)strlen(passwordUTF8), passwordUTF8, keychain, access, &item);
NSLog(#"item %#", item);
if(status == noErr) {
NSLog(#"Successfully created Keychain Item");
} else {
NSLog(#"Creating Keychain item failed: %#", SecCopyErrorMessageString(status, NULL));
return 63;
}
return 0;
}
I have also tried to do it with shell script when I give commands to NSTask and launches it, it results in same output. Does anyone have idea about how should it can be done?
Try this:
//first check if item already exists, if it is - it might cause an error while trying to save data
if([self tryToFetchForService:service account:account])
[self deleteItemForService:service account:account];
NSDictionary *query=#{(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:service,
(__bridge id)kSecAttrAccount:account,
(__bridge id)kSecValueData:password,
(__bridge id)kSecAttrLabel:description};
status=SecItemAdd((__bridge CFDictionaryRef)query,NULL);
if(status!=errSecSuccess && error!=NULL)
*error=...; // error initialize
You need to include Security-framework.
If you need to delete object from the keychain look below
NSDictionary *query=#{(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService:service,
(__bridge id)kSecAttrAccount:account,
(__bridge id)kSecReturnRef:#YES};
CFTypeRef result=NULL;
status=SecItemCopyMatching((__bridge CFDictionaryRef)query,&result);
if(status==errSecSuccess)
{
status=SecKeychainItemDelete((SecKeychainItemRef)result);
CFRelease(result); // release core foundation class instance
}
if(status!=errSecSuccess && error!=NULL)
*error=...; // failed operation
Only an Administrator account can write to the System keychain.
Factor out the code, which accesses the keychain, to an XPC Helper application using XPC Helper Services, so that the helper can run with root privileges.

ios7 - cannot store credentials after authentication using AFOAuthCredential

I am authenticating against my mobile server using AFNetworking 2.0 + GROAuth2SessionManager ( which includes AFOAuthCredential) ( security framework is included ... )
on authentication success , the tokens are stored into the credentials :
- (void)authorizeUser:(NSString *)login password:(NSString *)password onSuccess:(void (^)())success onFailure:(void (^)(NSString *))failure {
NSURL *url = self.base_url;
GROAuth2SessionManager *sessionManager = [GROAuth2SessionManager managerWithBaseURL:url clientID:self.client_key secret:self.client_secret];
sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
[sessionManager authenticateUsingOAuthWithPath:self.token_path
login:login
password:password
scope:nil
success:^(AFOAuthCredential *credential) {
[AFOAuthCredential storeCredential:credential
withIdentifier:[url host]];
self.creds = credential;
success();
}
failure:^(NSError *error) {
NSLog(#"OAuth client authorization error: %#", error);
NSDictionary *uinfo = [error userInfo];
NSHTTPURLResponse *response = [uinfo valueForKey:AFNetworkingOperationFailingURLResponseErrorKey];
NSInteger status = response.statusCode;
if (400 <= status && status < 500) {
[self resignAuthorization];
}
failure([uinfo valueForKey:NSLocalizedRecoverySuggestionErrorKey]);
}];
}
but I get an error in the console :
Unable to fetch credential with identifier "localhost" (Error -25300)
I look into the AFOAuthCredential, and I can see some blocks regarding security ..
Did I miss anything in my app setup to cope with it ? ...
#ifdef _SECURITY_SECITEM_H_
NSString * const kAFOAuth2CredentialServiceName = #"AFOAuthCredentialService";
static NSMutableDictionary * AFKeychainQueryDictionaryWithIdentifier(NSString *identifier) {
NSMutableDictionary *queryDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)kSecClassGenericPassword, kSecClass, kAFOAuth2CredentialServiceName, kSecAttrService, nil];
[queryDictionary setValue:identifier forKey:(__bridge id)kSecAttrAccount];
return queryDictionary;
}
#endif
...
#pragma mark Keychain
#ifdef _SECURITY_SECITEM_H_
+ (BOOL)storeCredential:(AFOAuthCredential *)credential withIdentifier:(NSString *)identifier {
return [self storeCredential:credential withIdentifier:identifier useICloud:NO];
}
+ (BOOL)storeCredential:(AFOAuthCredential *)credential withIdentifier:(NSString *)identifier useICloud:(BOOL)shouldUseICloud {
id securityAccessibility;
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 43000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
securityAccessibility = (__bridge id)kSecAttrAccessibleWhenUnlocked;
#endif
return [self storeCredential:credential withIdentifier:identifier withAccessibility:securityAccessibility useICloud:shouldUseICloud];
}
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier withAccessibility:(id)securityAccessibility useICloud:(BOOL)shouldUseICloud {
NSMutableDictionary *queryDictionary = AFKeychainQueryDictionaryWithIdentifier(identifier);
if (!credential) {
return [self deleteCredentialWithIdentifier:identifier useICloud:shouldUseICloud];
}
NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:credential];
[updateDictionary setObject:data forKey:(__bridge id)kSecValueData];
if (securityAccessibility) {
[updateDictionary setObject:securityAccessibility forKey:(__bridge id)kSecAttrAccessible];
}
if (shouldUseICloud && &kSecAttrSynchronizable != NULL) {
[queryDictionary setObject:#YES forKey:(__bridge id)kSecAttrSynchronizable];
[updateDictionary setObject:#YES forKey:(__bridge id)kSecAttrSynchronizable];
}
OSStatus status;
BOOL exists = ([self retrieveCredentialWithIdentifier:identifier] != nil);
if (exists) {
status = SecItemUpdate((__bridge CFDictionaryRef)queryDictionary, (__bridge CFDictionaryRef)updateDictionary);
} else {
[queryDictionary addEntriesFromDictionary:updateDictionary];
status = SecItemAdd((__bridge CFDictionaryRef)queryDictionary, NULL);
}
if (status != errSecSuccess) {
NSLog(#"Unable to %# credential with identifier \"%#\" (Error %li)", exists ? #"update" : #"add", identifier, (long int)status);
}
return (status == errSecSuccess);
}
Sorry , after running the test once more time, I realise that it's running fine .... the first fetch doesn't hit the identifier ... then credentials are stored , and subsequent fetches hit the stored identifier .... my fault running on the simulator and reseting the content ....

(Objective-c/Mac OSX) How to distinguish managed AD users (AD user create mobile card) from local users on Mac OSX

<\RESOLVED>, Please see the first reply
My mac(10.9) has joined into a AD domain. In my program, I tried to recognize whether the current login user is local account or AD user. I can successfully distinguish them by using the following code.
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
NSDictionary *nodeInfo = [searchNode nodeDetailsForKeys:nil error:error];
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
While when the AD user create a mobile card, it is viewed as a managed user(from the System preference -> Users & Groups). The code also recognize this kind of AD user as local. How to deal with this kind of situation?
Do you guys have any idea of this problem?
I have solved this problem by myself. Hope the following code helps:
#import "DasUser.h"
#import <OpenDirectory/OpenDirectory.h>
#import <Collaboration/Collaboration.h>
#implementation DasUser
+ (bool)isLocalUser:(NSString*)user
{
NSError *dirSearchError = nil;
ODRecord *foundUser = findUser(user, &dirSearchError);
if(foundUser !=nil)
{
return YES;
}else
{
return NO;
}
}
ODRecord *findUser(NSString *user, NSError **error)
{
NSLog(#"[MacLogonUI] findUser");
CSIdentityAuthorityRef defaultAuthority = CSGetManagedIdentityAuthority();
CSIdentityClass identityClass = kCSIdentityClassUser;
CSIdentityQueryRef query = CSIdentityQueryCreate(NULL, identityClass, defaultAuthority);
CFErrorRef err = NULL;
CSIdentityQueryExecute(query, 0, &err);
CFArrayRef results = CSIdentityQueryCopyResults(query);
int numResults = CFArrayGetCount(results);
NSMutableArray * managedUsers = [NSMutableArray array];
for (int i = 0; i < numResults; ++i) {
CSIdentityRef identity = (CSIdentityRef)CFArrayGetValueAtIndex(results, i);
CBIdentity * identityObject = [CBIdentity identityWithCSIdentity:identity];
NSString* posixName = [identityObject posixName];
[managedUsers addObject:posixName];
}
CFRelease(results);
CFRelease(query);
ODNode *searchNode = [ODNode nodeWithSession: [ODSession defaultSession]
type: kODNodeTypeLocalNodes
error: error];
if (searchNode == nil) {
return nil;
}
/* query this node for the user record we're interested in.
* We only need one result, which is why maximumResults is set to 1.
*/
ODQuery *userSearch = [ODQuery queryWithNode: searchNode
forRecordTypes: kODRecordTypeUsers
attribute: kODAttributeTypeRecordName
matchType: kODMatchEqualTo
queryValues: user
returnAttributes: kODAttributeTypeStandardOnly
maximumResults: 1
error: error];
if (userSearch == nil) {
return nil;
}
/* For this example we'll use a synchronous search. This could take a while
* so asynchronous searching is preferable.
*/
NSArray *foundRecords = [userSearch resultsAllowingPartial: NO error: error];
if([foundRecords count]>0)
{
NSString *nameStr = [foundRecords[0] recordName];
NSLog(#"[MacLogonUI] findUser nameStr %#", nameStr);
int j;
for( j = 0; j<[managedUsers count]; j++)
{
if([nameStr isEqualToString:managedUsers[j]])
{
break;
}
}
if(j<[managedUsers count])
{
foundRecords = nil;
}
}
if (foundRecords == nil || [foundRecords count] == 0) {
return nil;
}
ODRecord *userRecord = [foundRecords objectAtIndex: 0];
return [[userRecord retain] autorelease];
}
#end
While when network of the mac is disconnected. The managed user can not be listed. Is there anybody has any idea of this?

sudo auth session while executing command using NSTask in cocoa application

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