]> git.saurik.com Git - apple/security.git/blob - libsecurity_codesigning/lib/SecTask.c
Security-55179.11.tar.gz
[apple/security.git] / libsecurity_codesigning / 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/CoreFoundation.h>
25 #include <CoreFoundation/CFRuntime.h>
26 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
27
28 #include <IOKit/IOKitLib.h>
29 #include <IOKit/IOCFUnserialize.h>
30
31 #include <System/sys/codesign.h>
32
33 #include <pthread.h>
34
35 #include <bsm/libbsm.h>
36
37 #include "SecTask.h"
38
39 struct __SecTask {
40 CFRuntimeBase base;
41
42 pid_t pid;
43
44 /* Track whether we've loaded entitlements independently since after the
45 * load, entitlements may legitimately be NULL */
46 Boolean entitlementsLoaded;
47 CFDictionaryRef entitlements;
48 };
49
50 enum {
51 kSecCodeMagicEntitlement = 0xfade7171, /* entitlement blob */
52 };
53
54
55 CFTypeID _kSecTaskTypeID = _kCFRuntimeNotATypeID;
56
57 static void SecTaskFinalize(CFTypeRef cfTask)
58 {
59 SecTaskRef task = (SecTaskRef) cfTask;
60
61 if (task->entitlements != NULL) {
62 CFRelease(task->entitlements);
63 task->entitlements = NULL;
64 }
65 }
66
67 static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask)
68 {
69 SecTaskRef task = (SecTaskRef) cfTask;
70
71 return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("<SecTask %p>"), task);
72 }
73
74 static void SecTaskRegisterClass(void)
75 {
76 static const CFRuntimeClass SecTaskClass = {
77 .version = 0,
78 .className = "SecTask",
79 .init = NULL,
80 .copy = NULL,
81 .finalize = SecTaskFinalize,
82 .equal = NULL,
83 .hash = NULL,
84 .copyFormattingDesc = NULL,
85 .copyDebugDesc = SecTaskCopyDebugDescription,
86 };
87
88 _kSecTaskTypeID = _CFRuntimeRegisterClass(&SecTaskClass);
89 }
90
91 CFTypeID SecTaskGetTypeID(void)
92 {
93 static pthread_once_t secTaskRegisterClassOnce = PTHREAD_ONCE_INIT;
94
95 /* Register the class with the CF runtime the first time through */
96 pthread_once(&secTaskRegisterClassOnce, SecTaskRegisterClass);
97
98 return _kSecTaskTypeID;
99 }
100
101 static SecTaskRef SecTaskCreateWithPID(CFAllocatorRef allocator, pid_t pid)
102 {
103 CFIndex extra = sizeof(struct __SecTask) - sizeof(CFRuntimeBase);
104 SecTaskRef task = (SecTaskRef) _CFRuntimeCreateInstance(allocator, SecTaskGetTypeID(), extra, NULL);
105 if (task != NULL) {
106 task->pid = pid;
107 task->entitlementsLoaded = false;
108 task->entitlements = NULL;
109 }
110
111 return task;
112
113 }
114
115 SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t token)
116 {
117 pid_t pid;
118
119 audit_token_to_au32(token,
120 /* auidp */ NULL,
121 /* euidp */ NULL,
122 /* egidp */ NULL,
123 /* ruidp */ NULL,
124 /* rgidp */ NULL,
125 /* pidp */ &pid,
126 /* asidp */ NULL,
127 /* tidp */ NULL);
128 return SecTaskCreateWithPID(allocator, pid);
129 }
130
131 SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator)
132 {
133 return SecTaskCreateWithPID(allocator, getpid());
134 }
135
136 static CFRange myMakeRange(CFIndex loc, CFIndex len) {
137 CFRange r = {.location = loc, .length = len };
138 return r;
139 }
140 struct csheader {
141 uint32_t magic;
142 uint32_t length;
143 };
144
145 static int SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error)
146 {
147 CFMutableDataRef data = NULL;
148 struct csheader header;
149 uint32_t bufferlen;
150 int ret;
151
152 ret = csops(task->pid, CS_OPS_ENTITLEMENTS_BLOB, &header, sizeof(header));
153 if (ret != -1 || errno != ERANGE) {
154 /* no entitlements */
155 task->entitlementsLoaded = true;
156 return 0;
157 }
158
159 bufferlen = ntohl(header.length);
160 /* check for insane values */
161 if (bufferlen > 1024 * 1024 || bufferlen < 8) {
162 ret = EINVAL;
163 goto out;
164 }
165 data = CFDataCreateMutable(NULL, bufferlen);
166 if (data == NULL) {
167 ret = ENOMEM;
168 goto out;
169 }
170 CFDataSetLength(data, bufferlen);
171 ret = csops(task->pid, CS_OPS_ENTITLEMENTS_BLOB, CFDataGetMutableBytePtr(data), bufferlen);
172 if (ret) {
173 ret = errno;
174 goto out;
175 }
176 CFDataDeleteBytes(data, myMakeRange(0, 8));
177 task->entitlements = CFPropertyListCreateWithData(NULL, data, 0, NULL, error);
178 task->entitlementsLoaded = true;
179 out:
180 if (data)
181 CFRelease(data);
182 if (ret && error)
183 *error = CFErrorCreate(NULL, kCFErrorDomainMach, ret, NULL);
184
185 return ret;
186 }
187
188 CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error)
189 {
190 /* Load entitlements if necessary */
191 if (task->entitlementsLoaded == false) {
192 SecTaskLoadEntitlements(task, error);
193 }
194
195 CFTypeRef value = NULL;
196 if (task->entitlements != NULL) {
197 value = CFDictionaryGetValue(task->entitlements, entitlement);
198
199 /* Return something the caller must release */
200 if (value != NULL) {
201 CFRetain(value);
202 }
203 }
204
205 return value;
206 }
207
208 CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error)
209 {
210 /* Load entitlements if necessary */
211 if (task->entitlementsLoaded == false) {
212 SecTaskLoadEntitlements(task, error);
213 }
214
215 /* Iterate over the passed in entitlements, populating the dictionary
216 * If entitlements were loaded but none were present, return an empty
217 * dictionary */
218 CFMutableDictionaryRef values = NULL;
219 if (task->entitlementsLoaded == true) {
220
221 CFIndex i, count = CFArrayGetCount(entitlements);
222 values = CFDictionaryCreateMutable(CFGetAllocator(task), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
223 if (task->entitlements != NULL) {
224 for (i = 0; i < count; i++) {
225 CFStringRef entitlement = CFArrayGetValueAtIndex(entitlements, i);
226 CFTypeRef value = CFDictionaryGetValue(task->entitlements, entitlement);
227 if (value != NULL) {
228 CFDictionarySetValue(values, entitlement, value);
229 }
230 }
231 }
232 }
233
234 return values;
235 }