2 * Copyright (c) 2011-2013 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
);
124 void xpcEngineAssess(CFURLRef path
, SecAssessmentFlags flags
, CFDictionaryRef context
, CFMutableDictionaryRef result
)
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();
131 CFDictionaryApplyFunction(context
, copyCFDictionary
, ctx
);
132 CFRef
<CFDataRef
> contextData
= makeCFData(CFDictionaryRef(ctx
));
133 xpc_dictionary_set_data(msg
, "context", CFDataGetBytePtr(contextData
), CFDataGetLength(contextData
));
137 if (int64_t error
= xpc_dictionary_get_int64(msg
, "error"))
138 MacOSError::throwMe((int)error
);
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
);
147 static void doProgress(xpc_object_t msg
)
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
);
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
);
167 CFDictionaryRef
xpcEngineUpdate(CFTypeRef target
, SecAssessmentFlags flags
, CFDictionaryRef context
)
169 Message
msg("update");
170 // target can be NULL, a CFURLRef, a SecRequirementRef, or a CFNumberRef
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
));
181 MacOSError::throwMe(errSecCSInvalidObjectRef
);
183 xpc_dictionary_set_int64(msg
, "flags", flags
);
184 CFRef
<CFMutableDictionaryRef
> ctx
= makeCFMutableDictionary();
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
)));
194 CFRef
<CFDataRef
> contextData
= makeCFData(CFDictionaryRef(ctx
));
195 xpc_dictionary_set_data(msg
, "context", CFDataGetBytePtr(contextData
), CFDataGetLength(contextData
));
199 if (localAuthorization
)
200 AuthorizationFree(localAuthorization
, kAuthorizationFlagDefaults
);
202 if (int64_t error
= xpc_dictionary_get_int64(msg
, "error"))
203 MacOSError::throwMe((int)error
);
206 const void *resultData
= xpc_dictionary_get_data(msg
, "result", &resultLength
);
207 return makeCFDictionaryFrom(resultData
, resultLength
);
211 bool xpcEngineControl(const char *control
)
213 Message
msg("control");
214 xpc_dictionary_set_string(msg
, "control", control
);
220 void xpcEngineRecord(CFDictionaryRef info
)
222 Message
msg("record");
223 CFRef
<CFDataRef
> infoData
= makeCFData(CFDictionaryRef(info
));
224 xpc_dictionary_set_data(msg
, "info", CFDataGetBytePtr(infoData
), CFDataGetLength(infoData
));
230 } // end namespace CodeSigning
231 } // end namespace Security