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/CoreFoundation.h>
25 #include <CoreFoundation/CFRuntime.h>
26 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
28 #include <IOKit/IOKitLib.h>
29 #include <IOKit/IOCFUnserialize.h>
31 #include <System/sys/codesign.h>
35 #include <bsm/libbsm.h>
44 /* Track whether we've loaded entitlements independently since after the
45 * load, entitlements may legitimately be NULL */
46 Boolean entitlementsLoaded
;
47 CFDictionaryRef entitlements
;
51 kSecCodeMagicEntitlement
= 0xfade7171, /* entitlement blob */
55 CFTypeID _kSecTaskTypeID
= _kCFRuntimeNotATypeID
;
57 static void SecTaskFinalize(CFTypeRef cfTask
)
59 SecTaskRef task
= (SecTaskRef
) cfTask
;
61 if (task
->entitlements
!= NULL
) {
62 CFRelease(task
->entitlements
);
63 task
->entitlements
= NULL
;
67 static CFStringRef
SecTaskCopyDebugDescription(CFTypeRef cfTask
)
69 SecTaskRef task
= (SecTaskRef
) cfTask
;
71 return CFStringCreateWithFormat(CFGetAllocator(task
), NULL
, CFSTR("<SecTask %p>"), task
);
74 static void SecTaskRegisterClass(void)
76 static const CFRuntimeClass SecTaskClass
= {
78 .className
= "SecTask",
81 .finalize
= SecTaskFinalize
,
84 .copyFormattingDesc
= NULL
,
85 .copyDebugDesc
= SecTaskCopyDebugDescription
,
88 _kSecTaskTypeID
= _CFRuntimeRegisterClass(&SecTaskClass
);
91 CFTypeID
SecTaskGetTypeID(void)
93 static pthread_once_t secTaskRegisterClassOnce
= PTHREAD_ONCE_INIT
;
95 /* Register the class with the CF runtime the first time through */
96 pthread_once(&secTaskRegisterClassOnce
, SecTaskRegisterClass
);
98 return _kSecTaskTypeID
;
101 static SecTaskRef
SecTaskCreateWithPID(CFAllocatorRef allocator
, pid_t pid
)
103 CFIndex extra
= sizeof(struct __SecTask
) - sizeof(CFRuntimeBase
);
104 SecTaskRef task
= (SecTaskRef
) _CFRuntimeCreateInstance(allocator
, SecTaskGetTypeID(), extra
, NULL
);
107 task
->entitlementsLoaded
= false;
108 task
->entitlements
= NULL
;
115 SecTaskRef
SecTaskCreateWithAuditToken(CFAllocatorRef allocator
, audit_token_t token
)
119 audit_token_to_au32(token
,
128 return SecTaskCreateWithPID(allocator
, pid
);
131 SecTaskRef
SecTaskCreateFromSelf(CFAllocatorRef allocator
)
133 return SecTaskCreateWithPID(allocator
, getpid());
136 static CFRange
myMakeRange(CFIndex loc
, CFIndex len
) {
137 CFRange r
= {.location
= loc
, .length
= len
};
145 static int SecTaskLoadEntitlements(SecTaskRef task
, CFErrorRef
*error
)
147 CFMutableDataRef data
= NULL
;
148 struct csheader header
;
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;
159 bufferlen
= ntohl(header
.length
);
160 /* check for insane values */
161 if (bufferlen
> 1024 * 1024 || bufferlen
< 8) {
165 data
= CFDataCreateMutable(NULL
, bufferlen
);
170 CFDataSetLength(data
, bufferlen
);
171 ret
= csops(task
->pid
, CS_OPS_ENTITLEMENTS_BLOB
, CFDataGetMutableBytePtr(data
), bufferlen
);
176 CFDataDeleteBytes(data
, myMakeRange(0, 8));
177 task
->entitlements
= CFPropertyListCreateWithData(NULL
, data
, 0, NULL
, error
);
178 task
->entitlementsLoaded
= true;
183 *error
= CFErrorCreate(NULL
, kCFErrorDomainMach
, ret
, NULL
);
188 CFTypeRef
SecTaskCopyValueForEntitlement(SecTaskRef task
, CFStringRef entitlement
, CFErrorRef
*error
)
190 /* Load entitlements if necessary */
191 if (task
->entitlementsLoaded
== false) {
192 SecTaskLoadEntitlements(task
, error
);
195 CFTypeRef value
= NULL
;
196 if (task
->entitlements
!= NULL
) {
197 value
= CFDictionaryGetValue(task
->entitlements
, entitlement
);
199 /* Return something the caller must release */
208 CFDictionaryRef
SecTaskCopyValuesForEntitlements(SecTaskRef task
, CFArrayRef entitlements
, CFErrorRef
*error
)
210 /* Load entitlements if necessary */
211 if (task
->entitlementsLoaded
== false) {
212 SecTaskLoadEntitlements(task
, error
);
215 /* Iterate over the passed in entitlements, populating the dictionary
216 * If entitlements were loaded but none were present, return an empty
218 CFMutableDictionaryRef values
= NULL
;
219 if (task
->entitlementsLoaded
== true) {
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
);
228 CFDictionarySetValue(values
, entitlement
, value
);