/* * Copyright (c) 2004-2011 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * trustSettings.cpp - routines called by MIG for Trust Settings r/w * * Created 9 May 2006 by dmitch */ #include /* created by MIG */ #include #include #include #include #include #include #include #include /* for audit_token_to_au32() */ #include #include #include #include #include #include "ocspdServer.h" #include /* for mbr_uid_to_uuid() */ /* One lock for all accesses to TrustSettings files */ static ModuleNexus gTrustSettingsLock; /* * The auth rights we use. * This probably will get tweaked: what I'd like to have, I think, for * the admin settings is "OK if root, else authenticate as admin". For * now just require root. */ #define TRUST_SETTINGS_RIGHT_USER "com.apple.trust-settings.user" #define TRUST_SETTINGS_RIGHT_ADMIN "com.apple.trust-settings.admin" #define TRUST_SETTINGS_RULE_USER CFSTR("authenticate-session-owner"); #define TRUST_SETTINGS_RULE_ADMIN CFSTR("is-root"); /* * Everyone can look in the settings directory, and hence stat the admin * file (as a quick optimization to avoid an RPC to us if it's not there), * but the individual files are readable only by root. */ #define TRUST_SETTINGS_PATH_MODE 0755 #define TRUST_SETTINGS_FILES_MODE 0600 /* * Create a stringified UUID. Caller allocs result, length UUID_STR_LEN + 1. * String has two characters for each UUID byte, plus 4 '-' chars, plus NULL. */ #define UUID_STR_LEN ((2 * sizeof(uuid_t)) + 5) static void uuidString( uuid_t uuid, char *cp) { unsigned dex; unsigned char *uuidCp = (unsigned char *)uuid; for(dex=0; dex _(gTrustSettingsLock()); char path[MAXPATHLEN + 1]; trustSettingsPath(auditToken, domain, path); unsigned char *fileData = NULL; unsigned fileDataLen; if(readFile(path, &fileData, &fileDataLen)) { ocspdTrustDebug("trustSettingsRead: no file at %s", path); *rcode = errSecNoTrustSettings; *trustSettings = NULL; *trustSettingsCnt = 0; return 0; } /* realloc using our server's allocator for later free */ CSSM_DATA cdata; Allocator &alloc = OcspdServer::active().alloc(); cdata.Data = (uint8 *)alloc.malloc(fileDataLen); cdata.Length = fileDataLen; memmove(cdata.Data, fileData, fileDataLen); free(fileData); passDataToCaller(cdata, trustSettings, trustSettingsCnt); ocspdTrustDebug("trustSettingsRead: read %lu bytes from %s", (unsigned long)cdata.Length, path); *rcode = noErr; return 0; } kern_return_t ocsp_server_trustSettingsWrite( mach_port_t serverport, audit_token_t auditToken, mach_port_t clientport, uint32_t domain, Data authBlob, mach_msg_type_number_t authBlobCnt, Data trustSettings, mach_msg_type_number_t trustSettingsCnt, OSStatus *rcode) { ocspdDebug("Processing trustSettingsWrite request"); ServerActivity(); const char *authRight = NULL; CFStringRef authRule = NULL; switch(domain) { case kSecTrustSettingsDomainUser: authRight = TRUST_SETTINGS_RIGHT_USER; authRule = TRUST_SETTINGS_RULE_USER; break; case kSecTrustSettingsDomainAdmin: authRight = TRUST_SETTINGS_RIGHT_ADMIN; authRule = TRUST_SETTINGS_RULE_ADMIN; break; case kSecTrustSettingsDomainSystem: /* this TrustSetting is immutable */ *rcode = errSecDataNotModifiable; return 0; default: *rcode = errSecInvalidPrefsDomain; return 0; } AuthorizationExternalForm extForm; if(authBlobCnt > sizeof(extForm)) { /* not sure how this could legitimately happen.... */ ocspdErrorLog("trustSettingsWrite: authBlob too big\n"); *rcode = paramErr; return 0; } /* * Lazily create auth rights we (and we alone) use */ AuthorizationRef authRef; OSStatus ortn; /* * WARNING: Authorization APIs may cause ocspd to be re-entered! */ if(AuthorizationRightGet(authRight, NULL)) { ortn = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 0, &authRef); if(ortn) { /* should never happen */ ocspdErrorLog("trustSettingsWrite: AuthorizationCreate failure\n"); *rcode = internalComponentErr; return 0; } ortn = AuthorizationRightSet(authRef, authRight, authRule, NULL, NULL, NULL); if(ortn) { ocspdErrorLog("trustSettingsWrite: AuthorizationRightSet failure\n"); *rcode = internalComponentErr; return 0; } AuthorizationFree(authRef, 0); } /* * Cook up an auth object from the client's blob */ memmove(&extForm, authBlob, authBlobCnt); ortn = AuthorizationCreateFromExternalForm(&extForm, &authRef); if(ortn) { ocspdErrorLog("trustSettingsWrite: AuthorizationCreateFromExternalForm failure\n"); *rcode = paramErr; return 0; } /* now, see if we're authorized to do this thing */ AuthorizationItem authItem = {authRight, 0, NULL, 0}; AuthorizationRights authRights = { 1, &authItem }; AuthorizationFlags authFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; /* save and restore context around call which can put up UI */ switchToContext(clientport, auditToken); ortn = AuthorizationCopyRights(authRef, &authRights, NULL, authFlags, NULL); restoreContext(); if(ortn) { ocspdErrorLog("trustSettingsWrite: AuthorizationCopyRights failure\n"); } /* fixme - destroy rights? Really? */ AuthorizationFree(authRef, kAuthorizationFlagDestroyRights); if(ortn) { *rcode = ortn; return 0; } /* * Take the trust settings lock only after we've confirmed our authorization */ StLock _(gTrustSettingsLock()); char path[MAXPATHLEN + 1]; trustSettingsPath(auditToken, domain, path); /* * Looks like we're good to go. * First, handle easy case of deleting a Trust Settings file (indicated * by an empty trustSettings). */ if(trustSettingsCnt == 0) { ocspdTrustDebug("trustSettingsWrite: DELETING %s", path); if(unlink(path)) { /* FIXME maybe we should log this to the console */ *rcode = errno; ocspdErrorLog("trustSettingsWrite: unlink error %d\n", errno); } else { *rcode = noErr; } return 0; } /* * Create TRUST_SETTINGS_PATH if necessary. */ struct stat sb; if(stat(TRUST_SETTINGS_PATH, &sb)) { ocspdTrustDebug("trustSettingsWrite: creating %s", TRUST_SETTINGS_PATH); int errcode = mkpath_np(TRUST_SETTINGS_PATH, TRUST_SETTINGS_PATH_MODE); if(errcode) { ocspdErrorLog("trustSettingsWrite: mkpath_np() returned %d\n", errcode); *rcode = internalComponentErr; return 0; } /* override the probable umask that made this directory unreadable by others */ chmod(TRUST_SETTINGS_PATH, TRUST_SETTINGS_PATH_MODE); } /* And, finally.... */ if(writeFile(path, (const unsigned char *)trustSettings, trustSettingsCnt)) { ocspdErrorLog("trustSettingsWrite: writeFile() error\n"); *rcode = internalComponentErr; } else { ocspdTrustDebug("trustSettingsWrite: wrote %lu bytes to %s", (unsigned long)trustSettingsCnt, path); chmod(path, TRUST_SETTINGS_FILES_MODE); *rcode = noErr; } return 0; }