2 * Copyright (c) 2009 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@
24 #include <CoreFoundation/CFRuntime.h>
25 #include <Carbon/Carbon.h> /* Yuck! For MacErrors.h */
27 #include <IOKit/IOKitLib.h>
28 #include <IOKit/IOCFUnserialize.h>
32 #include <bsm/libbsm.h>
34 /* XXX: convert <Security/xyz.h> -> "xyz.h" for these when in project */
36 #include "SecRequirement.h"
38 /* #include <debugging.h> */
47 /* Track whether we've loaded entitlements independently since after the
48 * load, entitlements may legitimately be NULL */
49 Boolean entitlementsLoaded
;
50 CFDictionaryRef entitlements
;
54 kSecCodeMagicEntitlement
= 0xfade7171, /* entitlement blob */
58 CFTypeID _kSecTaskTypeID
= _kCFRuntimeNotATypeID
;
60 static void SecTaskFinalize(CFTypeRef cfTask
)
62 SecTaskRef task
= (SecTaskRef
) cfTask
;
64 if (task
->entitlements
!= NULL
) {
65 CFRelease(task
->entitlements
);
66 task
->entitlements
= NULL
;
70 static CFStringRef
SecTaskCopyDebugDescription(CFTypeRef cfTask
)
72 SecTaskRef task
= (SecTaskRef
) cfTask
;
74 return CFStringCreateWithFormat(CFGetAllocator(task
), NULL
, CFSTR("<SecTask %p>"), task
);
77 static void SecTaskRegisterClass(void)
79 static const CFRuntimeClass SecTaskClass
= {
81 .className
= "SecTask",
84 .finalize
= SecTaskFinalize
,
87 .copyFormattingDesc
= NULL
,
88 .copyDebugDesc
= SecTaskCopyDebugDescription
,
91 _kSecTaskTypeID
= _CFRuntimeRegisterClass(&SecTaskClass
);
94 CFTypeID
SecTaskGetTypeID(void)
96 static pthread_once_t secTaskRegisterClassOnce
= PTHREAD_ONCE_INIT
;
98 /* Register the class with the CF runtime the first time through */
99 pthread_once(&secTaskRegisterClassOnce
, SecTaskRegisterClass
);
101 return _kSecTaskTypeID
;
104 SecTaskRef
SecTaskCreateWithAuditToken(CFAllocatorRef allocator
, audit_token_t token
)
106 CFIndex extra
= sizeof(struct __SecTask
) - sizeof(CFRuntimeBase
);
107 SecTaskRef task
= (SecTaskRef
) _CFRuntimeCreateInstance(allocator
, SecTaskGetTypeID(), extra
, NULL
);
110 memcpy(&task
->token
, &token
, sizeof(token
));
111 task
->entitlementsLoaded
= false;
112 task
->entitlements
= NULL
;
119 static CFDictionaryRef
parseEntitlementsFromData(CFDataRef blobData
)
121 const struct theBlob
{
122 uint32_t magic
; /* kSecCodeMagicEntitlement */
124 const uint8_t data
[];
127 CFDictionaryRef entitlements
= NULL
;
129 size_t blobDataLen
= CFDataGetLength (blobData
);
131 /* Make sure we're at least the size of a blob */
132 if (blobDataLen
<= sizeof(struct theBlob
)) goto fin
;
134 blob
= (const struct theBlob
*) CFDataGetBytePtr (blobData
);
136 /* Check the magic */
137 if (kSecCodeMagicEntitlement
!= ntohl(blob
->magic
)) goto fin
;
139 /* Make sure we have as much data as the blob says we should */
140 if (blobDataLen
!= ntohl(blob
->length
)) goto fin
;
142 /* Convert the blobs payload to a dictionary */
143 CFDataRef entitlementData
= CFDataCreateWithBytesNoCopy (kCFAllocatorDefault
,
145 blobDataLen
- sizeof(struct theBlob
),
148 if (NULL
== entitlementData
) goto fin
;
150 entitlements
= CFPropertyListCreateFromXMLData (kCFAllocatorDefault
,
152 kCFPropertyListImmutable
,
154 if (NULL
== entitlements
) goto fin
;
156 if (CFGetTypeID(entitlements
) != CFDictionaryGetTypeID()) {
157 CFRelease (entitlements
);
161 if (NULL
!= entitlementData
) { CFRelease (entitlementData
); }
167 static void SecTaskLoadEntitlements(SecTaskRef task
, CFErrorRef
*error
)
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
;
179 /* XXX: Check for NULL == task->token? */
181 audit_token_to_au32 (task
->token
,
192 * Ref: /usr/include/sys/_types.h
193 * typedef __int32_t __darwin_pid_t;
196 targetPID
= CFNumberCreate (kCFAllocatorDefault
, kCFNumberSInt32Type
, &pid
);
197 if (NULL
== targetPID
) {
198 ret
= kPOSIXErrorENOMEM
;
202 guestAttributes
= CFDictionaryCreate (kCFAllocatorDefault
,
203 (const void **)&kSecGuestAttributePid
,
204 (const void **)&targetPID
,
208 if (NULL
== guestAttributes
) goto err
;
210 ret
= SecCodeCopyGuestWithAttributes (NULL
,
214 if (noErr
!= ret
) goto err
;
216 ret
= SecCodeCopySigningInformation (target
,
217 kSecCSRequirementInformation
,
219 if (noErr
!= ret
|| NULL
== targetInfo
) goto err
;
221 bool gotKey
= CFDictionaryGetValueIfPresent (targetInfo
,
222 (const void *)kSecCodeInfoEntitlements
,
223 (const void **)&entitlementData
);
224 if (false == gotKey
|| NULL
== entitlementData
) {
225 ret
= kIOReturnInvalid
;
229 task
->entitlements
= parseEntitlementsFromData (entitlementData
);
230 if (NULL
== task
->entitlements
) goto err
;
232 /* secdebug("entitlements", "entitlements %@", task->entitlements); */
234 task
->entitlementsLoaded
= true;
236 if (noErr
!= ret
&& NULL
!= error
) {
240 *error
= CFErrorCreate(CFGetAllocator(task
), kCFErrorDomainMach
, ret
, NULL
);
244 /* Free up any allocated things now! */
245 if (NULL
!= targetPID
) CFRelease (targetPID
);
247 if (NULL
!= guestAttributes
) CFRelease (guestAttributes
);
249 if (NULL
!= target
) CFRelease (target
);
251 if (NULL
!= targetInfo
) CFRelease (targetInfo
);
254 CFTypeRef
SecTaskCopyValueForEntitlement(SecTaskRef task
, CFStringRef entitlement
, CFErrorRef
*error
)
256 /* Load entitlements if necessary */
257 if (task
->entitlementsLoaded
== false) {
258 SecTaskLoadEntitlements(task
, error
);
261 CFTypeRef value
= NULL
;
262 if (task
->entitlements
!= NULL
) {
263 value
= CFDictionaryGetValue(task
->entitlements
, entitlement
);
265 /* Return something the caller must release */
274 CFDictionaryRef
SecTaskCopyValuesForEntitlements(SecTaskRef task
, CFArrayRef entitlements
, CFErrorRef
*error
)
276 /* Load entitlements if necessary */
277 if (task
->entitlementsLoaded
== false) {
278 SecTaskLoadEntitlements(task
, error
);
281 /* Iterate over the passed in entitlements, populating the dictionary
282 * If entitlements were loaded but none were present, return an empty
284 CFMutableDictionaryRef values
= NULL
;
285 if (task
->entitlementsLoaded
== true) {
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
);
294 CFDictionarySetValue(values
, entitlement
, value
);