]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/SecTask.c
libsecurity_codesigning-55037.15.tar.gz
[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 CFDataRef entitlementData = NULL;
174 SecCodeRef target = NULL;
175 CFErrorRef cfErr = NULL;
176 OSStatus ret = noErr;
177
178 /* XXX: Check for NULL == task->token? */
179
180 audit_token_to_au32 (task->token,
181 /* auidp */ NULL,
182 /* euidp */ NULL,
183 /* egidp */ NULL,
184 /* ruidp */ NULL,
185 /* rgidp */ NULL,
186 /* pidp */ &pid,
187 /* asidp */ NULL,
188 /* tidp */ NULL);
189
190 /*
191 * Ref: /usr/include/sys/_types.h
192 * typedef __int32_t __darwin_pid_t;
193 */
194
195 targetPID = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
196 if (NULL == targetPID) {
197 ret = kPOSIXErrorENOMEM;
198 goto err;
199 }
200
201 guestAttributes = CFDictionaryCreate (kCFAllocatorDefault,
202 (const void **)&kSecGuestAttributePid,
203 (const void **)&targetPID,
204 1,
205 NULL,
206 NULL);
207 if (NULL == guestAttributes) goto err;
208
209 ret = SecCodeCopyGuestWithAttributes (NULL,
210 guestAttributes,
211 kSecCSDefaultFlags,
212 &target);
213 if (noErr != ret) goto err;
214
215 ret = SecCodeCopySigningInformation (target,
216 kSecCSRequirementInformation,
217 &targetInfo);
218 if (noErr != ret || NULL == targetInfo) goto err;
219
220 bool gotKey = CFDictionaryGetValueIfPresent (targetInfo,
221 (const void *)kSecCodeInfoEntitlements,
222 (const void **)&entitlementData);
223 if (false == gotKey || NULL == entitlementData) {
224 ret = kIOReturnInvalid;
225 goto err;
226 }
227
228 task->entitlements = parseEntitlementsFromData (entitlementData);
229 if (NULL == task->entitlements) goto err;
230
231 /* secdebug("entitlements", "entitlements %@", task->entitlements); */
232
233 task->entitlementsLoaded = true;
234 err:
235 if (noErr != ret && NULL != error) {
236 if (NULL != cfErr) {
237 *error = cfErr;
238 } else {
239 *error = CFErrorCreate(CFGetAllocator(task), kCFErrorDomainMach, ret, NULL);
240 }
241 }
242
243 /* Free up any allocated things now! */
244 if (NULL != targetPID) CFRelease (targetPID);
245
246 if (NULL != guestAttributes) CFRelease (guestAttributes);
247
248 if (NULL != target) CFRelease (target);
249
250 if (NULL != targetInfo) CFRelease (targetInfo);
251 }
252
253 CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error)
254 {
255 /* Load entitlements if necessary */
256 if (task->entitlementsLoaded == false) {
257 SecTaskLoadEntitlements(task, error);
258 }
259
260 CFTypeRef value = NULL;
261 if (task->entitlements != NULL) {
262 value = CFDictionaryGetValue(task->entitlements, entitlement);
263
264 /* Return something the caller must release */
265 if (value != NULL) {
266 CFRetain(value);
267 }
268 }
269
270 return value;
271 }
272
273 CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error)
274 {
275 /* Load entitlements if necessary */
276 if (task->entitlementsLoaded == false) {
277 SecTaskLoadEntitlements(task, error);
278 }
279
280 /* Iterate over the passed in entitlements, populating the dictionary
281 * If entitlements were loaded but none were present, return an empty
282 * dictionary */
283 CFMutableDictionaryRef values = NULL;
284 if (task->entitlementsLoaded == true) {
285
286 CFIndex i, count = CFArrayGetCount(entitlements);
287 values = CFDictionaryCreateMutable(CFGetAllocator(task), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
288 if (task->entitlements != NULL) {
289 for (i = 0; i < count; i++) {
290 CFStringRef entitlement = CFArrayGetValueAtIndex(entitlements, i);
291 CFTypeRef value = CFDictionaryGetValue(task->entitlements, entitlement);
292 if (value != NULL) {
293 CFDictionarySetValue(values, entitlement, value);
294 }
295 }
296 }
297 }
298
299 return values;
300 }