]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2011-2013 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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> | |
d8f41ccd | 28 | #include <security_utilities/cfmunge.h> |
b1ab9ed8 A |
29 | |
30 | ||
31 | namespace Security { | |
32 | namespace CodeSigning { | |
d8f41ccd A |
33 | |
34 | ||
35 | static void doProgress(xpc_object_t msg); | |
36 | ||
b1ab9ed8 A |
37 | |
38 | static const char serviceName[] = "com.apple.security.syspolicy"; | |
39 | ||
40 | ||
41 | static dispatch_once_t dispatchInit; // one-time init marker | |
42 | static xpc_connection_t service; // connection to spd | |
43 | static dispatch_queue_t queue; // dispatch queue for service | |
44 | ||
45 | static void init() | |
46 | { | |
47 | dispatch_once(&dispatchInit, ^void(void) { | |
48 | const char *name = serviceName; | |
49 | if (const char *env = getenv("SYSPOLICYNAME")) | |
50 | name = env; | |
51 | queue = dispatch_queue_create("spd-client", 0); | |
52 | service = xpc_connection_create_mach_service(name, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); | |
d8f41ccd A |
53 | xpc_connection_set_event_handler(service, ^(xpc_object_t msg) { |
54 | if (xpc_get_type(msg) == XPC_TYPE_DICTIONARY) { | |
55 | const char *function = xpc_dictionary_get_string(msg, "function"); | |
56 | if (!strcmp(function, "progress")) { | |
57 | doProgress(msg); | |
58 | } | |
59 | } | |
b1ab9ed8 A |
60 | }); |
61 | xpc_connection_resume(service); | |
62 | }); | |
63 | } | |
64 | ||
65 | ||
66 | // | |
67 | // Your standard XPC client-side machinery | |
68 | // | |
69 | class Message { | |
70 | public: | |
71 | xpc_object_t obj; | |
72 | ||
73 | Message(const char *function) | |
74 | { | |
75 | init(); | |
76 | obj = xpc_dictionary_create(NULL, NULL, 0); | |
77 | xpc_dictionary_set_string(obj, "function", function); | |
78 | } | |
79 | ~Message() | |
80 | { | |
81 | if (obj) | |
82 | xpc_release(obj); | |
83 | } | |
84 | operator xpc_object_t () { return obj; } | |
85 | ||
86 | void send() | |
87 | { | |
88 | xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, obj); | |
89 | xpc_release(obj); | |
90 | obj = NULL; | |
91 | xpc_type_t type = xpc_get_type(reply); | |
92 | if (type == XPC_TYPE_DICTIONARY) { | |
93 | obj = reply; | |
94 | if (int64_t error = xpc_dictionary_get_int64(obj, "error")) | |
427c49bc | 95 | MacOSError::throwMe((int)error); |
b1ab9ed8 A |
96 | } else if (type == XPC_TYPE_ERROR) { |
97 | const char *s = xpc_copy_description(reply); | |
98 | printf("Error returned: %s\n", s); | |
99 | free((char*)s); | |
100 | MacOSError::throwMe(errSecCSInternalError); | |
101 | } else { | |
102 | const char *s = xpc_copy_description(reply); | |
103 | printf("Unexpected type of return object: %s\n", s); | |
104 | free((char*)s); | |
105 | } | |
106 | } | |
107 | }; | |
108 | ||
109 | ||
110 | ||
111 | static void copyCFDictionary(const void *key, const void *value, void *ctx) | |
112 | { | |
113 | CFMutableDictionaryRef target = CFMutableDictionaryRef(ctx); | |
b1ab9ed8 A |
114 | if (CFGetTypeID(value) == CFURLGetTypeID()) { |
115 | CFRef<CFStringRef> path = CFURLCopyFileSystemPath(CFURLRef(value), kCFURLPOSIXPathStyle); | |
116 | CFDictionaryAddValue(target, key, path); | |
d8f41ccd A |
117 | } else if (CFEqual(key, kSecAssessmentContextKeyFeedback)) { |
118 | CFDictionaryAddValue(target, key, CFTempNumber(uint64_t(value))); | |
b1ab9ed8 A |
119 | } else { |
120 | CFDictionaryAddValue(target, key, value); | |
121 | } | |
122 | } | |
123 | ||
427c49bc | 124 | void xpcEngineAssess(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result) |
b1ab9ed8 A |
125 | { |
126 | Message msg("assess"); | |
127 | xpc_dictionary_set_string(msg, "path", cfString(path).c_str()); | |
128 | xpc_dictionary_set_int64(msg, "flags", flags); | |
129 | CFRef<CFMutableDictionaryRef> ctx = makeCFMutableDictionary(); | |
130 | if (context) | |
131 | CFDictionaryApplyFunction(context, copyCFDictionary, ctx); | |
132 | CFRef<CFDataRef> contextData = makeCFData(CFDictionaryRef(ctx)); | |
133 | xpc_dictionary_set_data(msg, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData)); | |
134 | ||
135 | msg.send(); | |
136 | ||
137 | if (int64_t error = xpc_dictionary_get_int64(msg, "error")) | |
427c49bc | 138 | MacOSError::throwMe((int)error); |
b1ab9ed8 A |
139 | |
140 | size_t resultLength; | |
141 | const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength); | |
142 | CFRef<CFDictionaryRef> resultDict = makeCFDictionaryFrom(resultData, resultLength); | |
143 | CFDictionaryApplyFunction(resultDict, copyCFDictionary, result); | |
144 | CFDictionaryAddValue(result, CFSTR("assessment:remote"), kCFBooleanTrue); | |
145 | } | |
d8f41ccd A |
146 | |
147 | static void doProgress(xpc_object_t msg) | |
148 | { | |
149 | uint64_t current = xpc_dictionary_get_uint64(msg, "current"); | |
150 | uint64_t total = xpc_dictionary_get_uint64(msg, "total"); | |
151 | uint64_t ref = xpc_dictionary_get_uint64(msg, "ref"); | |
152 | const char *token = xpc_dictionary_get_string(msg, "token"); | |
153 | SecAssessmentFeedback feedback = SecAssessmentFeedback(ref); | |
154 | CFTemp<CFDictionaryRef> info("{current=%d,total=%d}", current, total); | |
155 | Boolean proceed = feedback(kSecAssessmentFeedbackProgress, info); | |
156 | if (!proceed) { | |
157 | xpc_connection_t connection = xpc_dictionary_get_remote_connection(msg); | |
158 | xpc_object_t cancelRequest = xpc_dictionary_create(NULL, NULL, 0); | |
159 | xpc_dictionary_set_string(cancelRequest, "function", "cancel"); | |
160 | xpc_dictionary_set_string(cancelRequest, "token", token); | |
161 | xpc_connection_send_message(connection, cancelRequest); | |
162 | xpc_release(cancelRequest); | |
163 | } | |
164 | } | |
b1ab9ed8 A |
165 | |
166 | ||
427c49bc | 167 | CFDictionaryRef xpcEngineUpdate(CFTypeRef target, SecAssessmentFlags flags, CFDictionaryRef context) |
b1ab9ed8 A |
168 | { |
169 | Message msg("update"); | |
170 | // target can be NULL, a CFURLRef, a SecRequirementRef, or a CFNumberRef | |
171 | if (target) { | |
172 | if (CFGetTypeID(target) == CFNumberGetTypeID()) | |
173 | xpc_dictionary_set_uint64(msg, "rule", cfNumber<int64_t>(CFNumberRef(target))); | |
174 | else if (CFGetTypeID(target) == CFURLGetTypeID()) | |
175 | xpc_dictionary_set_string(msg, "url", cfString(CFURLRef(target)).c_str()); | |
176 | else if (CFGetTypeID(target) == SecRequirementGetTypeID()) { | |
177 | CFRef<CFDataRef> data; | |
178 | MacOSError::check(SecRequirementCopyData(SecRequirementRef(target), kSecCSDefaultFlags, &data.aref())); | |
179 | xpc_dictionary_set_data(msg, "requirement", CFDataGetBytePtr(data), CFDataGetLength(data)); | |
180 | } else | |
181 | MacOSError::throwMe(errSecCSInvalidObjectRef); | |
182 | } | |
183 | xpc_dictionary_set_int64(msg, "flags", flags); | |
184 | CFRef<CFMutableDictionaryRef> ctx = makeCFMutableDictionary(); | |
185 | if (context) | |
186 | CFDictionaryApplyFunction(context, copyCFDictionary, ctx); | |
187 | AuthorizationRef localAuthorization = NULL; | |
188 | if (CFDictionaryGetValue(ctx, kSecAssessmentUpdateKeyAuthorization) == NULL) { // no caller-provided authorization | |
189 | MacOSError::check(AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &localAuthorization)); | |
190 | AuthorizationExternalForm extForm; | |
191 | MacOSError::check(AuthorizationMakeExternalForm(localAuthorization, &extForm)); | |
192 | CFDictionaryAddValue(ctx, kSecAssessmentUpdateKeyAuthorization, CFTempData(&extForm, sizeof(extForm))); | |
193 | } | |
194 | CFRef<CFDataRef> contextData = makeCFData(CFDictionaryRef(ctx)); | |
195 | xpc_dictionary_set_data(msg, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData)); | |
196 | ||
197 | msg.send(); | |
198 | ||
199 | if (localAuthorization) | |
200 | AuthorizationFree(localAuthorization, kAuthorizationFlagDefaults); | |
201 | ||
202 | if (int64_t error = xpc_dictionary_get_int64(msg, "error")) | |
427c49bc | 203 | MacOSError::throwMe((int)error); |
b1ab9ed8 A |
204 | |
205 | size_t resultLength; | |
206 | const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength); | |
207 | return makeCFDictionaryFrom(resultData, resultLength); | |
208 | } | |
209 | ||
210 | ||
211 | bool xpcEngineControl(const char *control) | |
212 | { | |
213 | Message msg("control"); | |
214 | xpc_dictionary_set_string(msg, "control", control); | |
215 | msg.send(); | |
216 | return true; | |
217 | } | |
218 | ||
219 | ||
427c49bc A |
220 | void xpcEngineRecord(CFDictionaryRef info) |
221 | { | |
222 | Message msg("record"); | |
223 | CFRef<CFDataRef> infoData = makeCFData(CFDictionaryRef(info)); | |
224 | xpc_dictionary_set_data(msg, "info", CFDataGetBytePtr(infoData), CFDataGetLength(infoData)); | |
225 | ||
226 | msg.send(); | |
227 | } | |
228 | ||
229 | ||
b1ab9ed8 A |
230 | } // end namespace CodeSigning |
231 | } // end namespace Security |