+++ /dev/null
-/* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
-
-#include "process.h"
-#include "server.h"
-#include "session.h"
-#include "debugging.h"
-#include "authd_private.h"
-#include "authtoken.h"
-#include "authutilities.h"
-#include "ccaudit.h"
-
-#include <Security/SecCode.h>
-#include <Security/SecRequirement.h>
-
-struct _process_s {
- __AUTH_BASE_STRUCT_HEADER__;
-
- audit_info_s auditInfo;
-
- session_t session;
-
- CFMutableBagRef authTokens;
- dispatch_queue_t dispatch_queue;
-
- CFMutableSetRef connections;
-
- SecCodeRef codeRef;
- char code_url[PATH_MAX+1];
- char * code_identifier;
- CFDataRef code_requirement_data;
- SecRequirementRef code_requirement;
- CFDictionaryRef code_entitlements;
-
- mach_port_t bootstrap;
-
- bool appleSigned;
-};
-
-static void
-_unregister_auth_tokens(const void *value, void *context)
-{
- auth_token_t auth = (auth_token_t)value;
- process_t proc = (process_t)context;
-
- CFIndex count = auth_token_remove_process(auth, proc);
- if ((count == 0) && auth_token_check_state(auth, auth_token_state_registered)) {
- server_unregister_auth_token(auth);
- }
-}
-
-static void
-_destroy_zombie_tokens(process_t proc)
-{
- LOGD("process[%i] destroy zombies, %ld auth tokens", process_get_pid(proc), CFBagGetCount(proc->authTokens));
- _cf_bag_iterate(proc->authTokens, ^bool(CFTypeRef value) {
- auth_token_t auth = (auth_token_t)value;
- LOGD("process[%i] %p, creator=%i, zombie=%i, process_cout=%ld", process_get_pid(proc), auth, auth_token_is_creator(auth, proc), auth_token_check_state(auth, auth_token_state_zombie), auth_token_get_process_count(auth));
- if (auth_token_is_creator(auth, proc) && auth_token_check_state(auth, auth_token_state_zombie) && (auth_token_get_process_count(auth) == 1)) {
- CFBagRemoveValue(proc->authTokens, auth);
- }
- return true;
- });
-}
-
-static void
-_process_finalize(CFTypeRef value)
-{
- process_t proc = (process_t)value;
-
- LOGV("process[%i]: deallocated %p", proc->auditInfo.pid, proc);
-
- dispatch_barrier_sync(proc->dispatch_queue, ^{
- CFBagApplyFunction(proc->authTokens, _unregister_auth_tokens, proc);
- });
-
- session_remove_process(proc->session, proc);
-
- dispatch_release(proc->dispatch_queue);
- CFReleaseSafe(proc->authTokens);
- CFReleaseSafe(proc->connections);
- CFReleaseSafe(proc->session);
- CFReleaseSafe(proc->codeRef);
- CFReleaseSafe(proc->code_requirement);
- CFReleaseSafe(proc->code_requirement_data);
- CFReleaseSafe(proc->code_entitlements);
- free_safe(proc->code_identifier);
- if (proc->bootstrap != MACH_PORT_NULL) {
- mach_port_deallocate(mach_task_self(), proc->bootstrap);
- }
-}
-
-AUTH_TYPE_INSTANCE(process,
- .init = NULL,
- .copy = NULL,
- .finalize = _process_finalize,
- .equal = NULL,
- .hash = NULL,
- .copyFormattingDesc = NULL,
- .copyDebugDesc = NULL
- );
-
-static CFTypeID process_get_type_id() {
- static CFTypeID type_id = _kCFRuntimeNotATypeID;
- static dispatch_once_t onceToken;
-
- dispatch_once(&onceToken, ^{
- type_id = _CFRuntimeRegisterClass(&_auth_type_process);
- });
-
- return type_id;
-}
-
-process_t
-process_create(const audit_info_s * auditInfo, session_t session)
-{
- OSStatus status = errSecSuccess;
- process_t proc = NULL;
- CFDictionaryRef code_info = NULL;
- CFURLRef code_url = NULL;
-
- require(session != NULL, done);
- require(auditInfo != NULL, done);
-
- proc = (process_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, process_get_type_id(), AUTH_CLASS_SIZE(process), NULL);
- require(proc != NULL, done);
-
- proc->auditInfo = *auditInfo;
-
- proc->session = (session_t)CFRetain(session);
-
- proc->connections = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL);
-
- proc->authTokens = CFBagCreateMutable(kCFAllocatorDefault, 0, &kCFTypeBagCallBacks);
- check(proc->authTokens != NULL);
-
- proc->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
- check(proc->dispatch_queue != NULL);
-
- CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFNumberRef codePid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &proc->auditInfo.pid);
- CFDictionarySetValue(codeDict, kSecGuestAttributePid, codePid);
- status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &proc->codeRef);
- CFReleaseSafe(codeDict);
- CFReleaseSafe(codePid);
-
- if (status) {
- LOGE("process[%i]: failed to create code ref %i", proc->auditInfo.pid, status);
- CFReleaseNull(proc);
- goto done;
- }
-
- status = SecCodeCopySigningInformation(proc->codeRef, kSecCSRequirementInformation, &code_info);
- require_noerr_action(status, done, LOGV("process[%i]: SecCodeCopySigningInformation failed with %i", proc->auditInfo.pid, status));
-
- CFTypeRef value = NULL;
- if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoDesignatedRequirement, (const void**)&value)) {
- if (CFGetTypeID(value) == SecRequirementGetTypeID()) {
- SecRequirementCopyData((SecRequirementRef)value, kSecCSDefaultFlags, &proc->code_requirement_data);
- if (proc->code_requirement_data) {
- SecRequirementCreateWithData(proc->code_requirement_data, kSecCSDefaultFlags, &proc->code_requirement);
- }
- }
- value = NULL;
- }
-
- if (SecCodeCopyPath(proc->codeRef, kSecCSDefaultFlags, &code_url) == errSecSuccess) {
- CFURLGetFileSystemRepresentation(code_url, true, (UInt8*)proc->code_url, sizeof(proc->code_url));
- }
-
- if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoIdentifier, &value)) {
- if (CFGetTypeID(value) == CFStringGetTypeID()) {
- proc->code_identifier = _copy_cf_string(value, NULL);
- }
- value = NULL;
- }
-
- if (CFDictionaryGetValueIfPresent(code_info, kSecCodeInfoEntitlementsDict, &value)) {
- if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {
- proc->code_entitlements = CFDictionaryCreateCopy(kCFAllocatorDefault, value);
- }
- value = NULL;
- }
-
- // This is the clownfish supported way to check for a Mac App Store or B&I signed build
- CFStringRef requirementString = CFSTR("(anchor apple) or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9])");
- SecRequirementRef secRequirementRef = NULL;
- status = SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &secRequirementRef);
- if (status == errSecSuccess) {
- proc->appleSigned = process_verify_requirment(proc, secRequirementRef);
- }
- CFReleaseSafe(secRequirementRef);
-
- LOGV("process[%i]: created (sid=%i) %s %p", proc->auditInfo.pid, proc->auditInfo.asid, proc->code_url, proc);
-
-done:
- CFReleaseSafe(code_info);
- CFReleaseSafe(code_url);
- return proc;
-}
-
-const void *
-process_get_key(process_t proc)
-{
- return &proc->auditInfo;
-}
-
-uid_t
-process_get_uid(process_t proc)
-{
- return proc ? proc->auditInfo.euid : (uid_t)-2;
-}
-
-pid_t
-process_get_pid(process_t proc)
-{
- return proc ? proc->auditInfo.pid : -1;
-}
-
-int32_t process_get_generation(process_t proc)
-{
- return proc->auditInfo.tid;
-}
-
-session_id_t
-process_get_session_id(process_t proc)
-{
- return proc ? proc->auditInfo.asid : -1;
-}
-
-session_t
-process_get_session(process_t proc)
-{
- return proc->session;
-}
-
-const audit_info_s *
-process_get_audit_info(process_t proc)
-{
- return &proc->auditInfo;
-}
-
-SecCodeRef
-process_get_code(process_t proc)
-{
- return proc->codeRef;
-}
-
-const char *
-process_get_code_url(process_t proc)
-{
- return proc->code_url;
-}
-
-void
-process_add_auth_token(process_t proc, auth_token_t auth)
-{
- dispatch_sync(proc->dispatch_queue, ^{
- CFBagAddValue(proc->authTokens, auth);
- if (CFBagGetCountOfValue(proc->authTokens, auth) == 1) {
- auth_token_add_process(auth, proc);
- }
- });
-}
-
-void
-process_remove_auth_token(process_t proc, auth_token_t auth, AuthorizationFlags flags)
-{
- dispatch_sync(proc->dispatch_queue, ^{
- bool destroy = false;
- bool creator = auth_token_is_creator(auth, proc);
- CFIndex count = auth_token_get_process_count(auth);
-
- // if we are the last ones associated with this auth token or the caller passed in the kAuthorizationFlagDestroyRights
- // then we break the link between the process and auth token. If another process holds a reference
- // then kAuthorizationFlagDestroyRights will only break the link and not destroy the auth token
- // <rdar://problem/14553640>
- if ((count == 1) ||
- (flags & kAuthorizationFlagDestroyRights))
- {
- destroy = true;
- goto done;
- }
-
- // If we created this token and someone else is holding a reference to it
- // don't destroy the link until they have freed the authorization ref
- // instead set the zombie state on the auth_token
- if (creator) {
- if (CFBagGetCountOfValue(proc->authTokens, auth) == 1) {
- auth_token_set_state(auth, auth_token_state_zombie);
- } else {
- destroy = true;
- }
- } else {
- destroy = true;
- }
-
- done:
- if (destroy) {
- CFBagRemoveValue(proc->authTokens, auth);
- if (!CFBagContainsValue(proc->authTokens, auth)) {
- auth_token_remove_process(auth, proc);
-
- if ((count == 1) && auth_token_check_state(auth, auth_token_state_registered)) {
- server_unregister_auth_token(auth);
- }
- }
- }
-
- // destroy all eligible zombies
- _destroy_zombie_tokens(proc);
- });
-}
-
-auth_token_t
-process_find_copy_auth_token(process_t proc, const AuthorizationBlob * blob)
-{
- __block CFTypeRef auth = NULL;
- dispatch_sync(proc->dispatch_queue, ^{
- _cf_bag_iterate(proc->authTokens, ^bool(CFTypeRef value) {
- auth_token_t iter = (auth_token_t)value;
- if (memcmp(blob, auth_token_get_blob(iter), sizeof(AuthorizationBlob)) == 0) {
- auth = iter;
- CFRetain(auth);
- return false;
- }
- return true;
- });
- });
- return (auth_token_t)auth;
-}
-
-CFIndex
-process_get_auth_token_count(process_t proc)
-{
- __block CFIndex count = 0;
- dispatch_sync(proc->dispatch_queue, ^{
- count = CFBagGetCount(proc->authTokens);
- });
- return count;
-}
-
-CFIndex
-process_add_connection(process_t proc, connection_t conn)
-{
- __block CFIndex count = 0;
- dispatch_sync(proc->dispatch_queue, ^{
- CFSetAddValue(proc->connections, conn);
- count = CFSetGetCount(proc->connections);
- });
- return count;
-}
-
-CFIndex
-process_remove_connection(process_t proc, connection_t conn)
-{
- __block CFIndex count = 0;
- dispatch_sync(proc->dispatch_queue, ^{
- CFSetRemoveValue(proc->connections, conn);
- count = CFSetGetCount(proc->connections);
- });
- return count;
-}
-
-CFIndex
-process_get_connection_count(process_t proc)
-{
- __block CFIndex count = 0;
- dispatch_sync(proc->dispatch_queue, ^{
- count = CFSetGetCount(proc->connections);
- });
- return count;
-}
-
-CFTypeRef
-process_copy_entitlement_value(process_t proc, const char * entitlement)
-{
- CFTypeRef value = NULL;
- require(entitlement != NULL, done);
-
- CFStringRef key = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, entitlement, kCFStringEncodingUTF8, kCFAllocatorNull);
- if (proc->code_entitlements && key && (CFDictionaryGetValueIfPresent(proc->code_entitlements, key, &value))) {
- CFRetainSafe(value);
- }
- CFReleaseSafe(key);
-
-done:
- return value;
-}
-
-bool
-process_has_entitlement(process_t proc, const char * entitlement)
-{
- bool entitled = false;
- require(entitlement != NULL, done);
-
- CFStringRef key = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, entitlement, kCFStringEncodingUTF8, kCFAllocatorNull);
- CFTypeRef value = NULL;
- if (proc->code_entitlements && key && (CFDictionaryGetValueIfPresent(proc->code_entitlements, key, &value))) {
- if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
- entitled = CFBooleanGetValue(value);
- }
- }
- CFReleaseSafe(key);
-
-done:
- return entitled;
-}
-
-bool
-process_has_entitlement_for_right(process_t proc, const char * right)
-{
- bool entitled = false;
- require(right != NULL, done);
-
- CFTypeRef rights = NULL;
- if (proc->code_entitlements && CFDictionaryGetValueIfPresent(proc->code_entitlements, CFSTR("com.apple.private.AuthorizationServices"), &rights)) {
- if (CFGetTypeID(rights) == CFArrayGetTypeID()) {
- CFStringRef key = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, right, kCFStringEncodingUTF8, kCFAllocatorNull);
- require(key != NULL, done);
-
- CFIndex count = CFArrayGetCount(rights);
- for (CFIndex i = 0; i < count; i++) {
- if (CFEqual(CFArrayGetValueAtIndex(rights, i), key)) {
- entitled = true;
- break;
- }
- }
- CFReleaseSafe(key);
- }
- }
-
-done:
- return entitled;
-}
-
-const char *
-process_get_identifier(process_t proc)
-{
- return proc->code_identifier;
-}
-
-CFDataRef
-process_get_requirement_data(process_t proc)
-{
- return proc->code_requirement_data;
-}
-
-SecRequirementRef
-process_get_requirement(process_t proc)
-{
- return proc->code_requirement;
-}
-
-bool process_verify_requirment(process_t proc, SecRequirementRef requirment)
-{
- OSStatus status = SecCodeCheckValidity(proc->codeRef, kSecCSDefaultFlags, requirment);
- if (status != errSecSuccess) {
- LOGV("process[%i]: code requirement check failed (%d)", proc->auditInfo.pid, status);
- }
- return (status == errSecSuccess);
-}
-
-// Returns true if the process was signed by B&I or the Mac App Store
-bool process_apple_signed(process_t proc) {
- return proc->appleSigned;
-}
-
-mach_port_t process_get_bootstrap(process_t proc)
-{
- return proc->bootstrap;
-}
-
-bool process_set_bootstrap(process_t proc, mach_port_t bootstrap)
-{
- if (bootstrap != MACH_PORT_NULL) {
- if (proc->bootstrap != MACH_PORT_NULL) {
- mach_port_deallocate(mach_task_self(), proc->bootstrap);
- }
- proc->bootstrap = bootstrap;
- return true;
- }
- return false;
-}
-