1/* 2 * Copyright (c) 2011 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include "xpcengine.h" 24#include <xpc/connection.h> 25#include <syslog.h> 26#include <CoreFoundation/CoreFoundation.h> 27#include <security_utilities/cfutilities.h> 28 29 30namespace Security { 31namespace CodeSigning { 32 33static const char serviceName[] = "com.apple.security.syspolicy"; 34 35 36static dispatch_once_t dispatchInit; // one-time init marker 37static xpc_connection_t service; // connection to spd 38static dispatch_queue_t queue; // dispatch queue for service 39 40static void init() 41{ 42 dispatch_once(&dispatchInit, ^void(void) { 43 const char *name = serviceName; 44 if (const char *env = getenv("SYSPOLICYNAME")) 45 name = env; 46 queue = dispatch_queue_create("spd-client", 0); 47 service = xpc_connection_create_mach_service(name, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); 48 xpc_connection_set_event_handler(service, ^(xpc_object_t ev) { 49 }); 50 xpc_connection_resume(service); 51 }); 52} 53 54 55// 56// Your standard XPC client-side machinery 57// 58class Message { 59public: 60 xpc_object_t obj; 61 62 Message(const char *function) 63 { 64 init(); 65 obj = xpc_dictionary_create(NULL, NULL, 0); 66 xpc_dictionary_set_string(obj, "function", function); 67 } 68 ~Message() 69 { 70 if (obj) 71 xpc_release(obj); 72 } 73 operator xpc_object_t () { return obj; } 74 75 void send() 76 { 77 xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, obj); 78 xpc_release(obj); 79 obj = NULL; 80 xpc_type_t type = xpc_get_type(reply); 81 if (type == XPC_TYPE_DICTIONARY) { 82 obj = reply; 83 if (int64_t error = xpc_dictionary_get_int64(obj, "error")) 84 MacOSError::throwMe((int)error); 85 } else if (type == XPC_TYPE_ERROR) { 86 const char *s = xpc_copy_description(reply); 87 printf("Error returned: %s\n", s); 88 free((char*)s); 89 MacOSError::throwMe(errSecCSInternalError); 90 } else { 91 const char *s = xpc_copy_description(reply); 92 printf("Unexpected type of return object: %s\n", s); 93 free((char*)s); 94 } 95 } 96}; 97 98 99 100static void copyCFDictionary(const void *key, const void *value, void *ctx) 101{ 102 CFMutableDictionaryRef target = CFMutableDictionaryRef(ctx); 103 if (CFGetTypeID(value) == CFURLGetTypeID()) { 104 CFRef<CFStringRef> path = CFURLCopyFileSystemPath(CFURLRef(value), kCFURLPOSIXPathStyle); 105 CFDictionaryAddValue(target, key, path); 106 } else { 107 CFDictionaryAddValue(target, key, value); 108 } 109} 110 111void xpcEngineAssess(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result) 112{ 113 Message msg("assess"); 114 xpc_dictionary_set_string(msg, "path", cfString(path).c_str()); 115 xpc_dictionary_set_int64(msg, "flags", flags); 116 CFRef<CFMutableDictionaryRef> ctx = makeCFMutableDictionary(); 117 if (context) 118 CFDictionaryApplyFunction(context, copyCFDictionary, ctx); 119 CFRef<CFDataRef> contextData = makeCFData(CFDictionaryRef(ctx)); 120 xpc_dictionary_set_data(msg, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData)); 121 122 msg.send(); 123 124 if (int64_t error = xpc_dictionary_get_int64(msg, "error")) 125 MacOSError::throwMe((int)error); 126 127 size_t resultLength; 128 const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength); 129 CFRef<CFDictionaryRef> resultDict = makeCFDictionaryFrom(resultData, resultLength); 130 CFDictionaryApplyFunction(resultDict, copyCFDictionary, result); 131 CFDictionaryAddValue(result, CFSTR("assessment:remote"), kCFBooleanTrue); 132} 133 134 135CFDictionaryRef xpcEngineUpdate(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context) 136{ 137 Message msg("update"); 138 // target can be NULL, a CFURLRef, a SecRequirementRef, or a CFNumberRef 139 if (target) { 140 if (CFGetTypeID(target) == CFNumberGetTypeID()) 141 xpc_dictionary_set_uint64(msg, "rule", cfNumber<int64_t>(CFNumberRef(target))); 142 else if (CFGetTypeID(target) == CFURLGetTypeID()) 143 xpc_dictionary_set_string(msg, "url", cfString(CFURLRef(target)).c_str()); 144 else if (CFGetTypeID(target) == SecRequirementGetTypeID()) { 145 CFRef<CFDataRef> data; 146 MacOSError::check(SecRequirementCopyData(SecRequirementRef(target), kSecCSDefaultFlags, &data.aref())); 147 xpc_dictionary_set_data(msg, "requirement", CFDataGetBytePtr(data), CFDataGetLength(data)); 148 } else 149 MacOSError::throwMe(errSecCSInvalidObjectRef); 150 } 151 xpc_dictionary_set_int64(msg, "flags", flags); 152 CFRef<CFMutableDictionaryRef> ctx = makeCFMutableDictionary(); 153 if (context) 154 CFDictionaryApplyFunction(context, copyCFDictionary, ctx); 155 AuthorizationRef localAuthorization = NULL; 156 if (CFDictionaryGetValue(ctx, kSecAssessmentUpdateKeyAuthorization) == NULL) { // no caller-provided authorization 157 MacOSError::check(AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &localAuthorization)); 158 AuthorizationExternalForm extForm; 159 MacOSError::check(AuthorizationMakeExternalForm(localAuthorization, &extForm)); 160 CFDictionaryAddValue(ctx, kSecAssessmentUpdateKeyAuthorization, CFTempData(&extForm, sizeof(extForm))); 161 } 162 CFRef<CFDataRef> contextData = makeCFData(CFDictionaryRef(ctx)); 163 xpc_dictionary_set_data(msg, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData)); 164 165 msg.send(); 166 167 if (localAuthorization) 168 AuthorizationFree(localAuthorization, kAuthorizationFlagDefaults); 169 170 if (int64_t error = xpc_dictionary_get_int64(msg, "error")) 171 MacOSError::throwMe((int)error); 172 173 size_t resultLength; 174 const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength); 175 return makeCFDictionaryFrom(resultData, resultLength); 176} 177 178 179bool xpcEngineControl(const char *control) 180{ 181 Message msg("control"); 182 xpc_dictionary_set_string(msg, "control", control); 183 msg.send(); 184 return true; 185} 186 187 188void xpcEngineRecord(CFDictionaryRef info) 189{ 190 Message msg("record"); 191 CFRef<CFDataRef> infoData = makeCFData(CFDictionaryRef(info)); 192 xpc_dictionary_set_data(msg, "info", CFDataGetBytePtr(infoData), CFDataGetLength(infoData)); 193 194 msg.send(); 195} 196 197 198} // end namespace CodeSigning 199} // end namespace Security 200