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 CFDataRef entitlementData
= NULL
;
174 SecCodeRef target
= NULL
;
175 CFErrorRef cfErr
= NULL
;
176 OSStatus ret
= noErr
;
178 /* XXX: Check for NULL == task->token? */
180 audit_token_to_au32 (task
->token
,
191 * Ref: /usr/include/sys/_types.h
192 * typedef __int32_t __darwin_pid_t;
195 targetPID
= CFNumberCreate (kCFAllocatorDefault
, kCFNumberSInt32Type
, &pid
);
196 if (NULL
== targetPID
) {
197 ret
= kPOSIXErrorENOMEM
;
201 guestAttributes
= CFDictionaryCreate (kCFAllocatorDefault
,
202 (const void **)&kSecGuestAttributePid
,
203 (const void **)&targetPID
,
207 if (NULL
== guestAttributes
) goto err
;
209 ret
= SecCodeCopyGuestWithAttributes (NULL
,
213 if (noErr
!= ret
) goto err
;
215 ret
= SecCodeCopySigningInformation (target
,
216 kSecCSRequirementInformation
,
218 if (noErr
!= ret
|| NULL
== targetInfo
) goto err
;
220 bool gotKey
= CFDictionaryGetValueIfPresent (targetInfo
,
221 (const void *)kSecCodeInfoEntitlements
,
222 (const void **)&entitlementData
);
223 if (false == gotKey
|| NULL
== entitlementData
) {
224 ret
= kIOReturnInvalid
;
228 task
->entitlements
= parseEntitlementsFromData (entitlementData
);
229 if (NULL
== task
->entitlements
) goto err
;
231 /* secdebug("entitlements", "entitlements %@", task->entitlements); */
233 task
->entitlementsLoaded
= true;
235 if (noErr
!= ret
&& NULL
!= error
) {
239 *error
= CFErrorCreate(CFGetAllocator(task
), kCFErrorDomainMach
, ret
, NULL
);
243 /* Free up any allocated things now! */
244 if (NULL
!= targetPID
) CFRelease (targetPID
);
246 if (NULL
!= guestAttributes
) CFRelease (guestAttributes
);
248 if (NULL
!= target
) CFRelease (target
);
250 if (NULL
!= targetInfo
) CFRelease (targetInfo
);
253 CFTypeRef
SecTaskCopyValueForEntitlement(SecTaskRef task
, CFStringRef entitlement
, CFErrorRef
*error
)
255 /* Load entitlements if necessary */
256 if (task
->entitlementsLoaded
== false) {
257 SecTaskLoadEntitlements(task
, error
);
260 CFTypeRef value
= NULL
;
261 if (task
->entitlements
!= NULL
) {
262 value
= CFDictionaryGetValue(task
->entitlements
, entitlement
);
264 /* Return something the caller must release */
273 CFDictionaryRef
SecTaskCopyValuesForEntitlements(SecTaskRef task
, CFArrayRef entitlements
, CFErrorRef
*error
)
275 /* Load entitlements if necessary */
276 if (task
->entitlementsLoaded
== false) {
277 SecTaskLoadEntitlements(task
, error
);
280 /* Iterate over the passed in entitlements, populating the dictionary
281 * If entitlements were loaded but none were present, return an empty
283 CFMutableDictionaryRef values
= NULL
;
284 if (task
->entitlementsLoaded
== true) {
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
);
293 CFDictionarySetValue(values
, entitlement
, value
);