]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/server_security_helpers.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / ipc / server_security_helpers.m
1 /*
2 * Copyright (c) 2017 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 <pthread/pthread.h>
25
26 #include "server_security_helpers.h"
27 #include "server_entitlement_helpers.h"
28
29 #include <Security/SecTask.h>
30 #include <Security/SecTaskPriv.h>
31 #include "ipc/securityd_client.h"
32 #include <Security/SecEntitlements.h>
33 #include "sectask/SystemEntitlements.h"
34 #include <utilities/SecInternalReleasePriv.h>
35 #include <sys/codesign.h>
36 #include <Security/SecItem.h>
37 #include "utilities/SecCFRelease.h"
38 #include "utilities/SecCFWrappers.h"
39 #include "utilities/debugging.h"
40 #include "keychain/securityd/SecDbQuery.h"
41
42 #if __has_include(<MobileKeyBag/MobileKeyBag.h>) && TARGET_HAS_KEYSTORE
43 #include <MobileKeyBag/MobileKeyBag.h>
44 #define HAVE_MOBILE_KEYBAG_SUPPORT 1
45 #endif
46
47 #if __has_include(<UserManagement/UserManagement.h>)
48 #include <UserManagement/UserManagement.h>
49 #endif
50
51 #if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
52 static bool
53 device_is_multiuser(void)
54 {
55 static dispatch_once_t once;
56 static bool result;
57
58 dispatch_once(&once, ^{
59 CFDictionaryRef deviceMode = MKBUserTypeDeviceMode(NULL, NULL);
60 CFTypeRef value = NULL;
61
62 if (deviceMode && CFDictionaryGetValueIfPresent(deviceMode, kMKBDeviceModeKey, &value) && CFEqual(value, kMKBDeviceModeMultiUser)) {
63 result = true;
64 }
65 CFReleaseNull(deviceMode);
66 });
67
68 return result;
69 }
70 #endif /* HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS */
71
72 static bool sanityCheckClientAccessGroups(SecurityClient* client) {
73 if (!client->accessGroups) {
74 return true;
75 }
76
77 CFRange range = { 0, CFArrayGetCount(client->accessGroups) };
78 if (!CFArrayContainsValue(client->accessGroups, range, CFSTR("*"))) {
79 return true;
80 }
81
82 CFMutableArrayRef allowedIdentifiers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
83 #if TARGET_OS_OSX
84 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.keychainaccess"));
85 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.KeychainMigrator"));
86 #endif
87 if (SecIsInternalRelease()) {
88 #if TARGET_OS_OSX
89 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security2"));
90 #else
91 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security"));
92 #endif
93 }
94
95 bool answer = SecTaskIsEligiblePlatformBinary(client->task, allowedIdentifiers);
96 CFReleaseNull(allowedIdentifiers);
97
98 return answer;
99 }
100
101 bool
102 fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken) {
103 if(!client) {
104 return false;
105 }
106
107 @autoreleasepool {
108
109 client->uid = uid;
110 client->musr = NULL;
111
112 #if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
113 if (device_is_multiuser()) {
114 CFErrorRef error = NULL;
115
116 client->inMultiUser = true;
117 client->activeUser = MKBForegroundUserSessionID(&error);
118 if (client->activeUser == -1 || client->activeUser == 0) {
119 assert(0);
120 client->activeUser = 0;
121 }
122
123 /*
124 * If we are a edu mode user, and its not the active user,
125 * then the request is coming from inside the syncbubble.
126 *
127 * otherwise we are going to execute the request as the
128 * active user.
129 */
130
131 if (client->uid > 501 && (uid_t)client->activeUser != client->uid) {
132 secinfo("serverxpc", "securityd client: sync bubble user");
133 client->musr = SecMUSRCreateSyncBubbleUserUUID(client->uid);
134 client->keybag = KEYBAG_DEVICE;
135 } else {
136 secinfo("serverxpc", "securityd client: active user");
137 client->musr = SecMUSRCreateActiveUserUUID(client->activeUser);
138 client->uid = (uid_t)client->activeUser;
139 client->keybag = KEYBAG_DEVICE;
140 }
141 } else
142 #endif /* TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT */
143 #if TARGET_OS_IOS || TARGET_OS_TV
144 /*
145 * iOS supports Enterprise Data Separation.
146 * tvOS supports guest users.
147 * Use the appropriate musr values for either.
148 */
149 {
150 UMUserPersona * persona = [[UMUserManager sharedManager] currentPersona];
151 if (persona &&
152 #if TARGET_OS_IOS
153 persona.userPersonaType == UMUserPersonaTypeEnterprise
154 #elif TARGET_OS_TV
155 persona.userPersonaType == UMUserPersonaTypeGuest
156 #endif
157 ) {
158 secinfo("serverxpc", "securityd client: persona user %@", persona.userPersonaNickName);
159 uuid_t uuid;
160
161 if (uuid_parse([persona.userPersonaUniqueString UTF8String], uuid) != 0) {
162 return false;
163 }
164 client->musr = CFDataCreate(NULL, uuid, sizeof(uuid_t));
165 }
166 }
167 #endif /* TARGET_OS_IOS || TARGET_OS_TV */
168
169 client->task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
170 client->accessGroups = SecTaskCopyAccessGroups(client->task);
171 client->applicationIdentifier = SecTaskCopyApplicationIdentifier(client->task);
172 client->isAppClip = SecTaskGetBooleanValueForEntitlement(client->task, kSystemEntitlementOnDemandInstallCapable);
173 if (client->isAppClip) {
174 secinfo("serverxpc", "securityd client: app clip (API restricted)");
175 }
176
177 #if TARGET_OS_IPHONE
178 client->allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateSystemKeychain);
179 client->isNetworkExtension = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateNetworkExtension);
180 client->canAccessNetworkExtensionAccessGroups = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementNetworkExtensionAccessGroups);
181 #endif
182 #if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS
183 if (client->inMultiUser) {
184 client->allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateKeychainSyncBubble);
185 }
186 #endif
187 if (!sanityCheckClientAccessGroups(client)) {
188 CFReleaseNull(client->task);
189 CFReleaseNull(client->accessGroups);
190 CFReleaseNull(client->musr);
191 CFReleaseNull(client->applicationIdentifier);
192 return false;
193 }
194 }
195 return true;
196 }
197
198 // Stolen and adapted from securityd_service
199 bool SecTaskIsEligiblePlatformBinary(SecTaskRef task, CFArrayRef identifiers) {
200 #if (DEBUG || RC_BUILDIT_YES)
201 secnotice("serverxpc", "Accepting client because debug");
202 return true;
203 #else
204
205 if (task == NULL) {
206 secerror("serverxpc: Client task is null, cannot verify platformness");
207 return false;
208 }
209
210 uint32_t flags = SecTaskGetCodeSignStatus(task);
211 /* check if valid and platform binary, but not platform path */
212
213 if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
214 if (SecIsInternalRelease()) {
215 if ((flags & (CS_DEBUGGED | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_DEBUGGED | CS_PLATFORM_BINARY)) {
216 secerror("serverxpc: client is not a platform binary: 0x%08x", flags);
217 return false;
218 }
219 } else {
220 secerror("serverxpc: client is not a platform binary: 0x%08x", flags);
221 return false;
222 }
223 }
224
225 CFStringRef signingIdentifier = SecTaskCopySigningIdentifier(task, NULL);
226 if (identifiers) {
227 if (signingIdentifier == NULL) {
228 secerror("serverxpc: client has no codesign identifier");
229 return false;
230 }
231
232 __block bool result = false;
233 CFArrayForEach(identifiers, ^(const void *value) {
234 if (CFEqual(value, signingIdentifier)) {
235 result = true;
236 }
237 });
238
239 if (result == true) {
240 secinfo("serverxpc", "client %@ is eligible platform binary", signingIdentifier);
241 } else {
242 secerror("serverxpc: client %@ is not eligible", signingIdentifier);
243 }
244
245 CFReleaseNull(signingIdentifier);
246 return result;
247 }
248
249 secinfo("serverxpc", "Client %@ is valid platform binary", signingIdentifier);
250 CFReleaseNull(signingIdentifier);
251 return true;
252
253 #endif
254 }