2 * Copyright (c) 2011-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 #include "xpcengine.h"
24 #include <xpc/connection.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <security_utilities/cfutilities.h>
28 #include <security_utilities/cfmunge.h>
32 namespace CodeSigning
{
35 static void doProgress(xpc_object_t msg
);
38 static const char serviceName
[] = "com.apple.security.syspolicy";
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
47 dispatch_once(&dispatchInit
, ^void(void) {
48 const char *name
= serviceName
;
49 if (const char *env
= getenv("SYSPOLICYNAME"))
51 queue
= dispatch_queue_create("spd-client", 0);
52 service
= xpc_connection_create_mach_service(name
, queue
, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
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")) {
61 xpc_connection_resume(service
);
67 // Your standard XPC client-side machinery
73 Message(const char *function
)
76 obj
= xpc_dictionary_create(NULL
, NULL
, 0);
77 xpc_dictionary_set_string(obj
, "function", function
);
84 operator xpc_object_t () { return obj
; }
88 xpc_object_t reply
= xpc_connection_send_message_with_reply_sync(service
, obj
);
91 xpc_type_t type
= xpc_get_type(reply
);
92 if (type
== XPC_TYPE_DICTIONARY
) {
94 if (int64_t error
= xpc_dictionary_get_int64(obj
, "error"))
95 MacOSError::throwMe((int)error
);
96 } else if (type
== XPC_TYPE_ERROR
) {
97 const char *s
= xpc_copy_description(reply
);
98 printf("Error returned: %s\n", s
);
100 MacOSError::throwMe(errSecCSInternalError
);
102 const char *s
= xpc_copy_description(reply
);
103 printf("Unexpected type of return object: %s\n", s
);
111 static void copyCFDictionary(const void *key
, const void *value
, void *ctx
)
113 CFMutableDictionaryRef target
= CFMutableDictionaryRef(ctx
);
114 if (CFGetTypeID(value
) == CFURLGetTypeID()) {
115 CFRef
<CFStringRef
> path
= CFURLCopyFileSystemPath(CFURLRef(value
), kCFURLPOSIXPathStyle
);
116 CFDictionaryAddValue(target
, key
, path
);
117 } else if (CFEqual(key
, kSecAssessmentContextKeyFeedback
)) {
118 CFDictionaryAddValue(target
, key
, CFTempNumber(uint64_t(value
)));
120 CFDictionaryAddValue(target
, key
, value
);
125 static void precheckAccess(CFURLRef path
, CFDictionaryRef context
)
127 CFTypeRef type
= CFDictionaryGetValue(context
, kSecAssessmentContextKeyOperation
);
128 if (type
== NULL
|| CFEqual(type
, kSecAssessmentOperationTypeExecute
)) {
129 CFRef
<SecStaticCodeRef
> code
;
130 MacOSError::check(SecStaticCodeCreateWithPath(path
, kSecCSDefaultFlags
, &code
.aref()));
131 CFRef
<CFURLRef
> exec
;
132 MacOSError::check(SecCodeCopyPath(code
, kSecCSDefaultFlags
, &exec
.aref()));
133 UnixError::check(::access(cfString(exec
).c_str(), R_OK
));
135 UnixError::check(access(cfString(path
).c_str(), R_OK
));
140 void xpcEngineAssess(CFURLRef path
, SecAssessmentFlags flags
, CFDictionaryRef context
, CFMutableDictionaryRef result
)
142 precheckAccess(path
, context
);
143 Message
msg("assess");
144 xpc_dictionary_set_string(msg
, "path", cfString(path
).c_str());
145 xpc_dictionary_set_int64(msg
, "flags", flags
);
146 CFRef
<CFMutableDictionaryRef
> ctx
= makeCFMutableDictionary();
148 CFDictionaryApplyFunction(context
, copyCFDictionary
, ctx
);
149 CFRef
<CFDataRef
> contextData
= makeCFData(CFDictionaryRef(ctx
));
150 xpc_dictionary_set_data(msg
, "context", CFDataGetBytePtr(contextData
), CFDataGetLength(contextData
));
154 if (int64_t error
= xpc_dictionary_get_int64(msg
, "error"))
155 MacOSError::throwMe((int)error
);
158 const void *resultData
= xpc_dictionary_get_data(msg
, "result", &resultLength
);
159 CFRef
<CFDictionaryRef
> resultDict
= makeCFDictionaryFrom(resultData
, resultLength
);
160 CFDictionaryApplyFunction(resultDict
, copyCFDictionary
, result
);
161 CFDictionaryAddValue(result
, CFSTR("assessment:remote"), kCFBooleanTrue
);
164 static void doProgress(xpc_object_t msg
)
166 uint64_t current
= xpc_dictionary_get_uint64(msg
, "current");
167 uint64_t total
= xpc_dictionary_get_uint64(msg
, "total");
168 uint64_t ref
= xpc_dictionary_get_uint64(msg
, "ref");
169 const char *token
= xpc_dictionary_get_string(msg
, "token");
170 SecAssessmentFeedback feedback
= SecAssessmentFeedback(ref
);
171 CFTemp
<CFDictionaryRef
> info("{current=%d,total=%d}", current
, total
);
172 Boolean proceed
= feedback(kSecAssessmentFeedbackProgress
, info
);
174 xpc_connection_t connection
= xpc_dictionary_get_remote_connection(msg
);
175 xpc_object_t cancelRequest
= xpc_dictionary_create(NULL
, NULL
, 0);
176 xpc_dictionary_set_string(cancelRequest
, "function", "cancel");
177 xpc_dictionary_set_string(cancelRequest
, "token", token
);
178 xpc_connection_send_message(connection
, cancelRequest
);
179 xpc_release(cancelRequest
);
184 CFDictionaryRef
xpcEngineUpdate(CFTypeRef target
, SecAssessmentFlags flags
, CFDictionaryRef context
)
186 Message
msg("update");
187 // target can be NULL, a CFURLRef, a SecRequirementRef, or a CFNumberRef
189 if (CFGetTypeID(target
) == CFNumberGetTypeID())
190 xpc_dictionary_set_uint64(msg
, "rule", cfNumber
<int64_t>(CFNumberRef(target
)));
191 else if (CFGetTypeID(target
) == CFURLGetTypeID()) {
192 precheckAccess(CFURLRef(target
), context
);
193 xpc_dictionary_set_string(msg
, "url", cfString(CFURLRef(target
)).c_str());
194 } else if (CFGetTypeID(target
) == SecRequirementGetTypeID()) {
195 CFRef
<CFDataRef
> data
;
196 MacOSError::check(SecRequirementCopyData(SecRequirementRef(target
), kSecCSDefaultFlags
, &data
.aref()));
197 xpc_dictionary_set_data(msg
, "requirement", CFDataGetBytePtr(data
), CFDataGetLength(data
));
199 MacOSError::throwMe(errSecCSInvalidObjectRef
);
201 xpc_dictionary_set_int64(msg
, "flags", flags
);
202 CFRef
<CFMutableDictionaryRef
> ctx
= makeCFMutableDictionary();
204 CFDictionaryApplyFunction(context
, copyCFDictionary
, ctx
);
205 AuthorizationRef localAuthorization
= NULL
;
206 if (CFDictionaryGetValue(ctx
, kSecAssessmentUpdateKeyAuthorization
) == NULL
) { // no caller-provided authorization
207 MacOSError::check(AuthorizationCreate(NULL
, NULL
, kAuthorizationFlagDefaults
, &localAuthorization
));
208 AuthorizationExternalForm extForm
;
209 MacOSError::check(AuthorizationMakeExternalForm(localAuthorization
, &extForm
));
210 CFDictionaryAddValue(ctx
, kSecAssessmentUpdateKeyAuthorization
, CFTempData(&extForm
, sizeof(extForm
)));
212 CFRef
<CFDataRef
> contextData
= makeCFData(CFDictionaryRef(ctx
));
213 xpc_dictionary_set_data(msg
, "context", CFDataGetBytePtr(contextData
), CFDataGetLength(contextData
));
217 if (localAuthorization
)
218 AuthorizationFree(localAuthorization
, kAuthorizationFlagDefaults
);
220 if (int64_t error
= xpc_dictionary_get_int64(msg
, "error"))
221 MacOSError::throwMe((int)error
);
224 const void *resultData
= xpc_dictionary_get_data(msg
, "result", &resultLength
);
225 return makeCFDictionaryFrom(resultData
, resultLength
);
229 bool xpcEngineControl(const char *control
)
231 Message
msg("control");
232 xpc_dictionary_set_string(msg
, "control", control
);
238 void xpcEngineRecord(CFDictionaryRef info
)
240 Message
msg("record");
241 CFRef
<CFDataRef
> infoData
= makeCFData(CFDictionaryRef(info
));
242 xpc_dictionary_set_data(msg
, "info", CFDataGetBytePtr(infoData
), CFDataGetLength(infoData
));
248 } // end namespace CodeSigning
249 } // end namespace Security