How can I execute a sudo command in a macOS app and persist root user privileges?

43 views Asked by At

I need to implement the following behavior in my app: When the app is run for the first time, prompt the user to authenticate by entering their administrative password. Upon successful authentication, securely store the administrative password using macOS Keychain Access. For subsequent executions of the same command, retrieve the stored password from the Keychain and use it to execute the privileged command without requiring the user to enter the administrative password again. By implementing this approach, users will only need to authenticate once, and subsequent executions of the privileged command will be seamless without further authentication prompts. (I need to programmatically execute a set of sudo in my app.)

Could you please confirm if any specific entitlement is required in macOS app development for this purpose? Additionally, is there a specific service available in macOS to facilitate this type of implementation? Thank you!

1

There are 1 answers

0
Tritonal On

You need to request access using either AuthorizationServices or SecurityFoundation APIs. Here's a bare-bones example for authorizing as admin using SFAuthorization:

import SecurityFoundation

func authorize() -> Bool {
    guard let auth = SFAuthorization.authorization() as? SFAuthorization,
          let admin = NSString(string: kAuthorizationRuleAuthenticateAsAdmin).utf8String
    else {
        // Authorization failed
        return false
    }
    
    do {
        try auth.obtain(withRight: admin, flags: [.interactionAllowed, .extendRights])
        return true
    } catch {
        // Authorization failed
        return false
    }
}

// Usage
let admin = authorize()
print("Authorized:", admin)

Note that this won't work if your app is sandboxed.

There's a lot of discussion and examples for using authorization APIs in Swift in this thread on Apple forums:
https://forums.developer.apple.com/forums/thread/675712

SFAuthorization (used above) is a higher-level API, but based on that trhead, it seems to have its caveats. The key in that example (kAuthorizationRuleAuthenticateAsAdmin) is not a right name, but a rule name, which means it will fail in some authorization methods.

AuthorizationServices on the other hand requires you to use non-ARC references, which is a bit daunting in Swift and you need some knowledge of C and memory management. The thread linked above also has an example from Quinn for wrapping the authorization APIs in Swift.

An example app using SFAuthorization in pre-ARC Objective C:
https://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html