Description:
I am attempting to use the OpenDirectory API ODRecord.changePassword to change a user's password without needing the old password, given that I have the appropriate permissions. The goal is to ensure that the password change operation bypasses third-party tools such as EDR or eBPF apps that might otherwise intercept commands, as the operation occurs directly via the API.
Problem:
When invoking the OpenDirectory API from a launch daemon with root privileges, I receive the following error message:
Error Domain=com.apple.OpenDirectory Code=4001 "Operation was denied because the current credentials do not have the appropriate privileges."
UserInfo={NSUnderlyingError=0x135907570 {Error Domain=com.apple.OpenDirectory Code=4001 "Credential cannot update user's SecureToken" UserInfo={NSDescription=Credential cannot update user's SecureToken}},
NSLocalizedDescription=Operation was denied because the current credentials do not have the appropriate privileges.,
NSLocalizedFailureReason=Operation was denied because the current credentials do not have the appropriate privileges.}
It seems the error is related to SecureToken, and the underlying issue is that the current credentials (even though they are root-level) do not have the necessary privileges to update the SecureToken status for the user.
Steps I’ve Taken:
- Tested the API via a launch daemon running with root privileges.
- Ensured that Full Disk Access was granted to the daemon, but this did not resolve the issue.
Request:
-
Has anyone encountered this specific issue where root privileges are insufficient to update the user password via the OpenDirectory API ?
-
What additional steps or permissions are required for a user password change?
-
Is there a specific API or method to elevate the privileges for modifying SecureToken, or a workaround to overcome this limitation?
Any insights or guidance on this issue would be greatly appreciated!
Thank you in advance for your help!
OK. Then the keychain password behaviour you’re seeing has a ready explanation. Your login keychain is effectively encrypted with your login password. So, to set a new password you have to have the old password. That’s what -newPassword
does. When you use -resetPasswordFor
there’s nowhere to supply the old password and thus you lose the login keychain contents.
You see this exact same phenomenon in System Settings. If an admin sets a new password for some other user, the resulting UI explains that it doesn’t reset that user’s keychain password.
The issue here for you is that -newPassword
is expecting to be run in the user’s context, not from your daemon. Indeed, it doesn’t even take a user name argument.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"