Hello,
I am working on updating an app to see if we can remove deprecated API usage, and am running into an issue after migrating from SMJobBless to SMAppService. If there is no current solution, I know that SMJobBless still works, but I wish to move to non-deprecated APIs whenever possible.
The app is a text editor that installs a privileged helper for when users need to edit text files with root privileges. The example I'll use here is /etc/ssh/sshd_config. When using SMJobBless, the privileged helper was able to write to this location. When using SMAppService.daemon, the daemon is not able to write to this location.
Neither the app nor the daemon are sandboxed. Both use the hardened runtime, and the daemon does not have any hardened runtime exceptions.
I'm not sure how to attach a debugger to the daemon, but I was able to add logging to the daemon to confirm that getuid() and geteuid() are both 0, so the daemon appears to be running as root.
However, the daemon is returning permission errors when attempting to replace the file.
{Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}
I've tried both atomic saving and writing directly to the file. When this code is run by the privileged helper installed with SMJobBless, it works without permissions problems.
Here is some simplified code I tried for atomic saving.
do {
let fileManager = FileManager.default
try? fileManager.createDirectory(at: originalItemURL.deletingLastPathComponent(), withIntermediateDirectories: true)
_ = try fileManager.replaceItemAt(originalItemURL, withItemAt: newItemURL, options: options)
completionHandler(nil)
}
catch {
completionHandler(error)
}
And the code for writing directly to the file
do {
try data.write(to: url)
completionHandler(nil)
}
catch {
completionHandler(error)
}
One thing I should note is that the privileged helper tool had a launchd plist embedded in the binary. When moving to SMAppService, I removed it from the build settings and added BundleProgram to it. It gets placed in my app bundle in Contents/Library/LaunchDaemons, while the daemon itself gets put in Contents/MacOS. The plist only contains the following keys: BundleProgram, Label, MachServices, and AssociatedBundleIdentifiers.
is there anything additional I can do to give my daemon permission to edit these files, or do I need to stick with SMJobBless for the time being?