OSX launchctl programmatically as root

I am trying to start the samba service using launchctl from an OSX application with root privileges, but I am getting error status -60031 . I can run the command in the terminal without any problems:

 sudo launchctl load -F /System/Library/LaunchDaemons/com.apple.smbd.plist 

In objective-c code, I use (I know that it is deprecated, but that really should not be a problem here) AuthorizationExecuteWithPrivileges .

Here is the code:

  NSString *command = @"launchctl"; // Conversion of NSArray args to char** args here (not relevant part of the code) OSStatus authStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &_authRef); if (authStatus != errAuthorizationSuccess) { NSLog(@"Failed to create application authorization: %d", (int)authStatus); return; } FILE* pipe = NULL; AuthorizationFlags flags = kAuthorizationFlagDefaults; AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0}; AuthorizationRights rights = {1, &right}; // Call AuthorizationCopyRights to determine or extend the allowable rights. OSStatus stat = AuthorizationCopyRights(_authRef, &rights, NULL, flags, NULL); if (stat != errAuthorizationSuccess) { NSLog(@"Copy Rights Unsuccessful: %d", (int)stat); return; } OSStatus status = AuthorizationExecuteWithPrivileges(_authRef, command.UTF8String, flags, args, &pipe); if (status != errAuthorizationSuccess) { NSLog(@"Error executing command %@ with status %d", command, status); } else { // some other stuff } 

I also tried using different flags and then kAuthorizationFlagDefaults, but this led to the same problem or error code -60011 invalid flags.

What am I doing wrong here, please?

+6
source share
2 answers

I would suggest using STPrivilegedTask - https://github.com/sveinbjornt/STPrivilegedTask

I had a similar problem and found the beautifully written wrapper above. It is straightforward and very simple. You can change it to your needs if you need, otherwise use it like this.

It worked for me, I hope it helps you too.

Thanks.

Updated (August 28, 2014): There is a difference between the execute command as root and executing the command as root!

In your particular case, you are trying to load / unload a daemon (which must be owned by root). In this case, you MUST run the command as root. If you try to load / unload only with root privileges, then you will run the daemon as your user! - not good!

Now, an example of your code and my link to STPrivilegedTask, both use the same code and allow the user to perform the task with root privileges, but NOT as root! To perform the root role, you have several options. First you can check out Apple Docs for the recommended method . In my case, I could not go with the recommended method, because my application is not signed and will not be signed + it needs to work on the old OSX.

So my solution is simple. Create a helper utility for the command line utility, let it take root and do whatever you pass to it through the arguments. Now, please pay attention (this is not a very safe way to do things). Also note that you will make a call to the helper tool with root privileges, and it will accept the root identifier.

Code:

  int main(int argc, const char * argv[]) { @autoreleasepool { if (argc >= 2) { setuid(0); // Here is a key - set user id to 0 - meaning become a root and everything below executes as root. NSMutableArray *arguments = [[NSMutableArray alloc] init]; NSString *command = [[NSString alloc] initWithFormat:@"%s", argv[1]]; for (int idx = 2; idx < argc; idx++) { NSString *tmp = [[NSString alloc] initWithFormat:@"%s", argv[idx]]; [arguments addObject:tmp]; } NSTask *task = [[NSTask alloc] init]; [task setLaunchPath:command]; [task setArguments:arguments]; NSPipe * out = [NSPipe pipe]; [task setStandardOutput:out]; [task launch]; [task waitUntilExit]; NSFileHandle * read = [out fileHandleForReading]; NSData * dataRead = [read readDataToEndOfFile]; NSString * stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding]; printf("%s", [stringRead UTF8String]); } return 0; } } 
+4
source

After looking at the documentation , it seems that your code kAuthorizationFlagExtendRights not have the kAuthorizationFlagExtendRights flag, which is required when the Security Server must grant the requested rights. Relevant passage;

... The constant kAuthorizationFlagDefaults returns a null mask. kAuthorizationFlagExtendRights constant tells the security server to grant permissions. Without this flag, AuthorizationCopyRights and AuthorizationCreate will return the corresponding code error, but no rights will be extended to the user ...

From the documentation for kAuthorizationFlagExtendRights :

kAuthorizationFlagExtendRights

If the bit specified by this mask is set, the security server attempts to grant the requested rights ...

Try adding this flag to flags before calling AuthorizationCopyRights() and perhaps also include kAuthorizationFlagPartialRights to limit the permissions granted a bit more.

0
source

Source: https://habr.com/ru/post/974017/


All Articles