]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/SecTask.c
a1d62aa58f53a6098400de44faf94bb8b30ad17f
[apple/libsecurity_codesigning.git] / lib / SecTask.c
1 /*
2 * Copyright (c) 2009 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
24 #include <CoreFoundation/CFRuntime.h>
25 #include <Carbon/Carbon.h> /* Yuck! For MacErrors.h */
26
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/IOCFUnserialize.h>
29
30 #include <pthread.h>
31
32 #include <bsm/libbsm.h>
33
34 /* XXX: convert <Security/xyz.h> -> "xyz.h" for these when in project */
35 #include "SecCode.h"
36 #include "SecRequirement.h"
37
38 /* #include <debugging.h> */
39
40 #include "SecTask.h"
41
42 struct __SecTask {
43 CFRuntimeBase base;
44
45 audit_token_t token;
46
47 /* Track whether we've loaded entitlements independently since after the
48 * load, entitlements may legitimately be NULL */
49 Boolean entitlementsLoaded;
50 CFDictionaryRef entitlements;
51 };
52
53 enum {
54 kSecCodeMagicEntitlement = 0xfade7171, /* entitlement blob */
55 };
56
57
58 CFTypeID _kSecTaskTypeID = _kCFRuntimeNotATypeID;
59
60 static void SecTaskFinalize(CFTypeRef cfTask)
61 {
62 SecTaskRef task = (SecTaskRef) cfTask;
63
64 if (task->entitlements != NULL) {
65 CFRelease(task->entitlements);
66 task->entitlements = NULL;
67 }
68 }
69
70 static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask)
71 {
72 SecTaskRef task = (SecTaskRef) cfTask;
73
74 return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("<SecTask %p>"), task);
75 }
76
77 static void SecTaskRegisterClass(void)
78 {
79 static const CFRuntimeClass SecTaskClass = {
80 .version = 0,
81 .className = "SecTask",
82 .init = NULL,
83 .copy = NULL,
84 .finalize = SecTaskFinalize,
85 .equal = NULL,
86 .hash = NULL,
87 .copyFormattingDesc = NULL,
88 .copyDebugDesc = SecTaskCopyDebugDescription,
89 };
90
91 _kSecTaskTypeID = _CFRuntimeRegisterClass(&SecTaskClass);
92 }
93
94 CFTypeID SecTaskGetTypeID(void)
95 {
96 static pthread_once_t secTaskRegisterClassOnce = PTHREAD_ONCE_INIT;
97
98 /* Register the class with the CF runtime the first time through */
99 pthread_once(&secTaskRegisterClassOnce, SecTaskRegisterClass);
100
101 return _kSecTaskTypeID;
102 }
103
104 SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t token)
105 {
106 CFIndex extra = sizeof(struct __SecTask) - sizeof(CFRuntimeBase);
107 SecTaskRef task = (SecTaskRef) _CFRuntimeCreateInstance(allocator, SecTaskGetTypeID(), extra, NULL);
108 if (task != NULL) {
109
110 memcpy(&task->token, &token, sizeof(token));
111 task->entitlementsLoaded = false;
112 task->entitlements = NULL;
113 }
114
115 return task;
116 }
117
118
119 static CFDictionaryRef parseEntitlementsFromData(CFDataRef blobData)
120 {
121 const struct theBlob {
122 uint32_t magic; /* kSecCodeMagicEntitlement */
123 uint32_t length;
124 const uint8_t data[];
125 } *blob = NULL;
126
127 CFDictionaryRef entitlements = NULL;
128
129 size_t blobDataLen = CFDataGetLength (blobData);
130
131 /* Make sure we're at least the size of a blob */
132 if (blobDataLen <= sizeof(struct theBlob)) goto fin;
133
134 blob = (const struct theBlob *) CFDataGetBytePtr (blobData);
135
136 /* Check the magic */
137 if (kSecCodeMagicEntitlement != ntohl(blob->magic)) goto fin;
138
139 /* Make sure we have as much data as the blob says we should */
140 if (blobDataLen != ntohl(blob->length)) goto fin;
141
142 /* Convert the blobs payload to a dictionary */
143 CFDataRef entitlementData = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault,
144 blob->data,
145 blobDataLen - sizeof(struct theBlob),
146 kCFAllocatorNull);
147
148 if (NULL == entitlementData) goto fin;
149
150 entitlements = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
151 entitlementData,
152 kCFPropertyListImmutable,
153 NULL);
154 if (NULL == entitlements) goto fin;
155
156 if (CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) {
157 CFRelease (entitlements);
158 entitlements = NULL;
159 }
160 fin:
161 if (NULL != entitlementData) { CFRelease (entitlementData); }
162
163 return entitlements;
164 }
165
166
167 static void SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error)
168 {
169 pid_t pid;
170 CFNumberRef targetPID = NULL;
171 CFDictionaryRef guestAttributes = NULL;
172 CFDictionaryRef targetInfo = NULL;
173 CFDictionaryRef entitlements = NULL;
174 CFDataRef entitlementData = NULL;
175 SecCodeRef target = NULL;
176 CFErrorRef cfErr = NULL;
177 OSStatus ret = noErr;
178
179 /* XXX: Check for NULL == task->token? */
180
181 audit_token_to_au32 (task->token,
182 /* auidp */ NULL,
183 /* euidp */ NULL,
184 /* egidp */ NULL,
185 /* ruidp */ NULL,
186 /* rgidp */ NULL,
187 /* pidp */ &pid,
188 /* asidp */ NULL,
189 /* tidp */ NULL);
190
191 /*
192 * Ref: /usr/include/sys/_types.h
193 * typedef __int32_t __darwin_pid_t;
194 */
195
196 targetPID = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
197 if (NULL == targetPID) {
198 ret = kPOSIXErrorENOMEM;
199 goto err;
200 }
201
202 guestAttributes = CFDictionaryCreate (kCFAllocatorDefault,
203 (const void **)&kSecGuestAttributePid,
204 (const void **)&targetPID,
205 1,
206 NULL,
207 NULL);
208 if (NULL == guestAttributes) goto err;
209
210 ret = SecCodeCopyGuestWithAttributes (NULL,
211 guestAttributes,
212 kSecCSDefaultFlags,
213 &target);
214 if (noErr != ret) goto err;
215
216 ret = SecCodeCopySigningInformation (target,
217 kSecCSRequirementInformation,
218 &targetInfo);
219 if (noErr != ret || NULL == targetInfo) goto err;
220
221 bool gotKey = CFDictionaryGetValueIfPresent (targetInfo,
222 (const void *)kSecCodeInfoEntitlements,
223 (const void **)&entitlementData);
224 if (false == gotKey || NULL == entitlementData) {
225 ret = kIOReturnInvalid;
226 goto err;
227 }
228
229 task->entitlements = parseEntitlementsFromData (entitlementData);
230 if (NULL == task->entitlements) goto err;
231
232 /* secdebug("entitlements", "entitlements %@", task->entitlements); */
233
234 task->entitlementsLoaded = true;
235 err:
236 if (noErr != ret && NULL != error) {
237 if (NULL != cfErr) {
238 *error = cfErr;
239 } else {
240 *error = CFErrorCreate(CFGetAllocator(task), kCFErrorDomainMach, ret, NULL);
241 }
242 }
243
244 /* Free up any allocated things now! */
245 if (NULL != targetPID) CFRelease (targetPID);
246
247 if (NULL != guestAttributes) CFRelease (guestAttributes);
248
249 if (NULL != target) CFRelease (target);
250
251 if (NULL != targetInfo) CFRelease (targetInfo);
252 }
253
254 CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error)
255 {
256 /* Load entitlements if necessary */
257 if (task->entitlementsLoaded == false) {
258 SecTaskLoadEntitlements(task, error);
259 }
260
261 CFTypeRef value = NULL;
262 if (task->entitlements != NULL) {
263 value = CFDictionaryGetValue(task->entitlements, entitlement);
264
265 /* Return something the caller must release */
266 if (value != NULL) {
267 CFRetain(value);
268 }
269 }
270
271 return value;
272 }
273
274 CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error)
275 {
276 /* Load entitlements if necessary */
277 if (task->entitlementsLoaded == false) {
278 SecTaskLoadEntitlements(task, error);
279 }
280
281 /* Iterate over the passed in entitlements, populating the dictionary
282 * If entitlements were loaded but none were present, return an empty
283 * dictionary */
284 CFMutableDictionaryRef values = NULL;
285 if (task->entitlementsLoaded == true) {
286
287 CFIndex i, count = CFArrayGetCount(entitlements);
288 values = CFDictionaryCreateMutable(CFGetAllocator(task), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
289 if (task->entitlements != NULL) {
290 for (i = 0; i < count; i++) {
291 CFStringRef entitlement = CFArrayGetValueAtIndex(entitlements, i);
292 CFTypeRef value = CFDictionaryGetValue(task->entitlements, entitlement);
293 if (value != NULL) {
294 CFDictionarySetValue(values, entitlement, value);
295 }
296 }
297 }
298 }
299
300 return values;
301 }