I have a problem with a helper implemented with SMAppService daemonServiceWithPlistName. The helper run a command line program that executes system(dscl . delete /Users/name_of_user)
Previously, this was implemented using AuthorizationExecuteWithPrivileges and it worked, from macOS Ventura start to show a dialog window "App would like to administer your computer. Administration can include modifying passwords, networking and system setting".
But with SMAppService there is no such dialog window and helper app just stuck.
I would like to know if this is a bug or correct behavior for a helper through SMAppService.
Thanks for the answer.
SMAppService daemon helper
On recent system we’ve placed the ability to delete accounts behind a TCC check. When dscl trips that check, TCC needs to be able to map back from that process to the responsible code so that it can present a meaningful alert. Something about running dscl from your daemon is breaking that chain of responsibility.
So, taking a step back, why are you doing this using dscl? You can delete records using the Open Directory framework and that avoids the whole privilege escalation malarkey [1].
If you search DevForums for user:eskimo odsession you’ll find a number of OD code snippets to get you started.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] Well, you still have to provide an admin password to authenticate with the OD node but that’s not the same as running code as root.
@eskimo as you said, I rewrote the deletion of users on the Open Directory. It requires administrator rights, I tried to do it with ODNodeSetCredentialsExtended and kODAuthenticationTypeWithAuthorizationRef. I didn't find any usage examples and there isn't much information in the documentation, only "Authentication array has following items in order: externalized AuthorizationRef". The code I wrote returns the error kODErrorRecordParameterError 4100. Could you please point out what I'm doing wrong. Thanks for the answer.
ODSession * session;
ODNode * node;
ODQuery * query;
session = [ODSession sessionWithOptions:nil error:NULL];
node = [ODNode nodeWithSession:session type:kODNodeTypeAuthentication error:NULL];
query = [ODQuery queryWithNode:node
forRecordTypes:kODRecordTypeUsers
attribute:nil
matchType:kODMatchAny
queryValues:nil
returnAttributes:nil
maximumResults:0
error:NULL
];
AuthorizationExternalForm extForm;
AuthorizationMakeExternalForm(myAuthorizationRef, &extForm);
CFErrorRef error = nullptr;
CFMutableArrayRef cfArrayBuf = nullptr;
cfArrayBuf = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFStringRef extBytes = CFStringCreateWithBytes(nullptr, (const UInt8 *)extForm.bytes, kAuthorizationExternalFormLength, kCFStringEncodingUnicode, true);
CFArrayAppendValue(cfArrayBuf, extBytes);
ODNodeSetCredentialsExtended((__bridge ODNodeRef)node, NULL, kODAuthenticationTypeWithAuthorizationRef, cfArrayBuf, nullptr, nullptr, &error);
for (ODRecord * record in [query resultsAllowingPartial:NO error:NULL]) {
if ([record.recordName rangeOfString:@"name"].location != NSNotFound) {
ODRecordDelete((__bridge ODRecordRef)record, &error);
}
}
Ooo, you’re mixing the Objective-C and the C APIs. I’ve honestly no idea how that’ll pan out. I recommend that you pick one, and specifically the Objective-C one, and run with it.
As to how you authenticate with a node from Objective-C, the simplest option is the -setCredentialsWithRecordType:recordName:password:error: method.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Hello, @eskimo I would also like to ask about what AuthorizationRights I should give for AuthorizationRef in order to be able to delete users using Open Directory. I am using [node setCredentialsWithRecordType:kODRecordTypeUsers authenticationType:kODAuthenticationTypeWithAuthorizationRef authenticationItems:arrayBuf continueItems:nullptr context:nullptr error:&error] At attempt to delete the user writes an error kODErrorRecordPermissionError. Thanks for the answer.
kODAuthenticationTypeWithAuthorizationRef expects a serialisation authorisation ref. So, something like this:
let rec: ODRecord = …
let authRef: AuthorizationRef = …
var ext = AuthorizationExternalForm()
let err = AuthorizationMakeExternalForm(authRef, &ext)
guard err == errSecSuccess else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(err))
}
let extData = NSData(bytes: &ext, length: MemoryLayout.size(ofValue: ext))
try rec.setNodeCredentialsWithRecordType(kODRecordTypeUsers,
authenticationType: kODAuthenticationTypeWithAuthorizationRef,
authenticationItems: [extData],
continueItems: nil,
context: nil
)
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"