/* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static Boolean hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype) { Boolean hasEntitlement = FALSE; SecTaskRef task; /* Create the security task from the audit token. */ task = SecTaskCreateWithAuditToken(NULL, audit_token); if (task != NULL) { CFErrorRef error = NULL; CFTypeRef value; /* Get the value for the entitlement. */ value = SecTaskCopyValueForEntitlement(task, entitlement, &error); if (value != NULL) { if (isA_CFBoolean(value)) { if (CFBooleanGetValue(value)) { /* if client DOES have entitlement */ hasEntitlement = TRUE; } } else if (isA_CFArray(value)){ if (vpntype == NULL){ /* we don't care about subtype */ hasEntitlement = TRUE; }else { if (CFArrayContainsValue(value, CFRangeMake(0, CFArrayGetCount(value)), vpntype)) { // if client DOES have entitlement hasEntitlement = TRUE; } } } else { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: entitlement not valid: %@"), entitlement); } CFRelease(value); } else if (error != NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: SecTaskCopyValueForEntitlement() failed, error=%@: %@"), error, entitlement); CFRelease(error); } CFRelease(task); } else { SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: SecTaskCreateWithAuditToken() failed: %@"), entitlement); } return hasEntitlement; }
int sectask_11_sectask_audittoken(int argc, char *const *argv) { SecTaskRef task=NULL; CFStringRef appId=NULL; CFStringRef signingIdentifier=NULL; plan_tests(6); init_self_audittoken(); ok(task=SecTaskCreateWithAuditToken(kCFAllocatorDefault, g_self_audittoken), "SecTaskCreateFromAuditToken"); require(task, out); /* TODO: remove the todo once xcode signs simulator binaries */ SKIP: { #if TARGET_IPHONE_SIMULATOR todo("no entitlements in the simulator binaries yet, until <rdar://problem/12194625>"); #endif ok(appId=SecTaskCopyValueForEntitlement(task, kSecEntitlementApplicationIdentifier, NULL), "SecTaskCopyValueForEntitlement"); skip("appId is NULL", 1, appId); ok(CFEqual(appId, CFSTR("com.apple.security.regressions")), "Application Identifier match"); ok(signingIdentifier=SecTaskCopySigningIdentifier(task, NULL), "SecTaskCopySigningIdentifier"); ok(CFEqual(signingIdentifier, CFBundleGetIdentifier(CFBundleGetMainBundle())), "CodeSigning Identifier match"); } pid_t pid = getpid(); CFStringRef name = copyProcName(pid); CFStringRef pidstr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("[%d]"), pid); CFStringRef desc = CFCopyDescription(task); ok(CFStringFind(desc, name, 0).location != kCFNotFound, "didn't find name: %@ vs %@", desc, name); ok(CFStringFind(desc, pidstr, 0).location != kCFNotFound, "didn't find pidstr: %@ vs %@", desc, pidstr); CFReleaseSafe(name); CFReleaseSafe(desc); CFReleaseSafe(pidstr); out: CFReleaseSafe(task); CFReleaseSafe(appId); CFReleaseSafe(signingIdentifier); return 0; }
/* AUDIT[securityd](done): receiver (unused) is a mach_port owned by this process. reply (checked by mig) is a caller provided mach_port. auditToken (ok) is a kernel provided audit token. request_id (checked by mig) is caller provided value, that matches the mig entry for this function. msg_id (ok) is caller provided value. msg_data (ok) is a caller provided data of length: msg_length (ok). */ kern_return_t securityd_server_request(mach_port_t receiver, mach_port_t reply, audit_token_t auditToken, uint32_t request_id, uint32_t msg_id, uint8_t *msg_data, mach_msg_type_number_t msg_length) { CFTypeRef args_in = NULL; CFTypeRef args_out = NULL; bool sendResponse = true; const char *op_name; request_begin(); if (msg_length) { CFDataRef data_in = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, msg_data, msg_length, kCFAllocatorNull); if (data_in) { args_in = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data_in, kCFPropertyListImmutable, NULL); CFRelease(data_in); } } #if 0 static int crash_counter = 0; if (crash_counter++) { secdebug("server", "crash test"); exit(1); } #endif SecTaskRef clientTask = #if CHECK_ENTITLEMENTS SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken); #else NULL; #endif CFArrayRef groups = SecTaskCopyAccessGroups(clientTask); SecAccessGroupsSetCurrent(groups); OSStatus status = errSecParam; switch(msg_id) { case sec_item_add_id: op_name = "SecItemAdd"; if (isDictionary(args_in)) status = _SecItemAdd(args_in, &args_out, groups); break; case sec_item_copy_matching_id: op_name = "SecItemCopyMatching"; if (isDictionary(args_in)) status = _SecItemCopyMatching(args_in, &args_out, groups); break; case sec_item_delete_id: op_name = "SecItemDelete"; if (isDictionary(args_in)) status = _SecItemDelete(args_in, groups); break; case sec_item_update_id: op_name = "SecItemUpdate"; if (isArrayOfLength(args_in, 2)) { CFDictionaryRef in0 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 0), in1 = (CFDictionaryRef)CFArrayGetValueAtIndex(args_in, 1); if (isDictionary(in0) && isDictionary(in1)) status = _SecItemUpdate(in0, in1, groups); } break; case sec_trust_store_contains_id: { op_name = "SecTrustStoreContains"; if (!isArray(args_in)) break; CFIndex argc_in = CFArrayGetCount(args_in); if (argc_in != 2) break; CFStringRef domainName = CFArrayGetValueAtIndex(args_in, 0); CFDataRef digest = CFArrayGetValueAtIndex(args_in, 1); if (!isString(domainName) || !isData(digest)) break; SecTrustStoreRef ts = SecTrustStoreForDomainName(domainName); status = !SecTrustStoreContainsCertificateWithDigest(ts, digest); break; } case sec_trust_store_set_trust_settings_id: { op_name = "SecTrustStoreSetTrustSettings"; /* Open the trust store unconditially so we can abuse this method even in clients that just want to read from the truststore, and this call will force it to be created. */ SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser); if (!isArray(args_in)) break; CFIndex argc_in = CFArrayGetCount(args_in); if (argc_in != 1 && argc_in != 2) break; if (!SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementModifyAnchorCertificates)) { status = errSecMissingEntitlement; break; } CFDataRef certificateData = (CFDataRef)CFArrayGetValueAtIndex(args_in, 0); if (!isData(certificateData)) break; SecCertificateRef certificate = SecCertificateCreateWithData(NULL, certificateData); if (certificate) { CFTypeRef trustSettingsDictOrArray; if (argc_in < 2) { trustSettingsDictOrArray = NULL; } else { trustSettingsDictOrArray = CFArrayGetValueAtIndex(args_in, 1); if (trustSettingsDictOrArray) { CFTypeID tst = CFGetTypeID(trustSettingsDictOrArray); if (tst != CFArrayGetTypeID() && tst != CFDictionaryGetTypeID()) { CFRelease(certificate); break; } } } status = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray); CFRelease(certificate); } break; } case sec_trust_store_remove_certificate_id: op_name = "SecTrustStoreRemoveCertificate"; if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementModifyAnchorCertificates)) { SecTrustStoreRef ts = SecTrustStoreForDomain(kSecTrustStoreDomainUser); if (isData(args_in)) { status = SecTrustStoreRemoveCertificateWithDigest(ts, args_in); } } else { status = errSecMissingEntitlement; } break; case sec_delete_all_id: op_name = "SecDeleteAll"; if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementWipeDevice)) { status = SecItemDeleteAll(); } else { status = errSecMissingEntitlement; } break; case sec_trust_evaluate_id: op_name = "SecTrustEvaluate"; if (isDictionary(args_in)) { struct securityd_server_trust_evaluation_context *tec = malloc(sizeof(*tec)); tec->reply = reply; tec->request_id = request_id; status = SecTrustServerEvaluateAsync(args_in, securityd_server_trust_evaluate_done, tec); if (status == noErr || status == errSecWaitForCallback) { sendResponse = false; } else { free(tec); } } break; case sec_restore_keychain_id: op_name = "SecRestoreKeychain"; if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementRestoreKeychain)) { status = _SecServerRestoreKeychain(); } else { status = errSecMissingEntitlement; } break; case sec_migrate_keychain_id: op_name = "SecMigrateKeychain"; if (isArray(args_in)) { if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementMigrateKeychain)) { status = _SecServerMigrateKeychain(args_in, &args_out); } else { status = errSecMissingEntitlement; } } break; case sec_keychain_backup_id: op_name = "SecKeychainBackup"; if (!args_in || isArray(args_in)) { if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementRestoreKeychain)) { status = _SecServerKeychainBackup(args_in, &args_out); } else { status = errSecMissingEntitlement; } } break; case sec_keychain_restore_id: op_name = "SecKeychainRestore"; if (isArray(args_in)) { if (SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementRestoreKeychain)) { status = _SecServerKeychainRestore(args_in, &args_out); } else { status = errSecMissingEntitlement; } } break; default: op_name = "invalid_operation"; status = errSecParam; break; } const char *proc_name; #ifdef NDEBUG if (status == errSecMissingEntitlement) { #endif pid_t pid; audit_token_to_au32(auditToken, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; struct kinfo_proc kp; size_t len = sizeof(kp); if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1 || len == 0) proc_name = strerror(errno); else proc_name = kp.kp_proc.p_comm; #ifndef NDEBUG if (status == errSecMissingEntitlement) { #endif asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s[%u] %s: missing entitlement", proc_name, pid, op_name); /* Remap errSecMissingEntitlement -> errSecInteractionNotAllowed. */ status = errSecInteractionNotAllowed; } secdebug("ipc", "%s[%u] %s: returning: %d", proc_name, pid, op_name, status); CFReleaseSafe(groups); CFReleaseSafe(clientTask); SecAccessGroupsSetCurrent(NULL); kern_return_t err = 0; if (sendResponse) err = securityd_server_send_reply(reply, request_id, status, args_out); CFReleaseSafe(args_in); return err; } extern boolean_t securityd_request_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); union max_msg_size_union { union __RequestUnion__securityd_client_securityd_reply_subsystem reply; }; static uint8_t reply_buffer[sizeof(union max_msg_size_union) + MAX_TRAILER_SIZE]; static void *handle_message(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { mach_msg_header_t *message = (mach_msg_header_t *)msg; mach_msg_header_t *reply = (mach_msg_header_t *)reply_buffer; securityd_request_server(message, reply); return NULL; }