]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/server_security_helpers.m
Security-59306.120.7.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 <utilities/SecInternalReleasePriv.h>
34 #include <sys/codesign.h>
35 #include <Security/SecItem.h>
36 #include "utilities/SecCFRelease.h"
37 #include "utilities/SecCFWrappers.h"
38 #include "utilities/debugging.h"
39 #include "keychain/securityd/SecDbQuery.h"
40
41 #if __has_include(<MobileKeyBag/MobileKeyBag.h>) && TARGET_HAS_KEYSTORE
42 #include <MobileKeyBag/MobileKeyBag.h>
43 #define HAVE_MOBILE_KEYBAG_SUPPORT 1
44 #endif
45
46 #if __has_include(<UserManagement/UserManagement.h>)
47 #include <UserManagement/UserManagement.h>
48 #endif
49
50 #if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
51 static bool
52 device_is_multiuser(void)
53 {
54 static dispatch_once_t once;
55 static bool result;
56
57 dispatch_once(&once, ^{
58 CFDictionaryRef deviceMode = MKBUserTypeDeviceMode(NULL, NULL);
59 CFTypeRef value = NULL;
60
61 if (deviceMode && CFDictionaryGetValueIfPresent(deviceMode, kMKBDeviceModeKey, &value) && CFEqual(value, kMKBDeviceModeMultiUser)) {
62 result = true;
63 }
64 CFReleaseNull(deviceMode);
65 });
66
67 return result;
68 }
69 #endif /* HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS */
70
71 static bool sanityCheckClientAccessGroups(SecurityClient* client) {
72 if (!client->accessGroups) {
73 return true;
74 }
75
76 CFRange range = { 0, CFArrayGetCount(client->accessGroups) };
77 if (!CFArrayContainsValue(client->accessGroups, range, CFSTR("*"))) {
78 return true;
79 }
80
81 CFMutableArrayRef allowedIdentifiers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
82 #if TARGET_OS_OSX
83 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.keychainaccess"));
84 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.KeychainMigrator"));
85 #endif
86 if (SecIsInternalRelease()) {
87 #if TARGET_OS_OSX
88 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security2"));
89 #else
90 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security"));
91 #endif
92 }
93
94 bool answer = SecTaskIsEligiblePlatformBinary(client->task, allowedIdentifiers);
95 CFReleaseNull(allowedIdentifiers);
96
97 return answer;
98 }
99
100 bool
101 fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken) {
102 if(!client) {
103 return false;
104 }
105
106 @autoreleasepool {
107
108 client->uid = uid;
109 client->musr = NULL;
110
111 #if TARGET_OS_IOS
112 #if 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
143 /*
144 * If the client application is a enterprise app according to usermanager, switch
145 * to the per enterprise slice of keychain.
146 */
147 {
148 UMUserPersona * persona = [[UMUserManager sharedManager] currentPersona];
149 if (persona && persona.userPersonaType == UMUserPersonaTypeEnterprise) {
150 secinfo("serverxpc", "securityd client: enterprise user");
151 uuid_t uuid;
152
153 if (uuid_parse([persona.userPersonaUniqueString UTF8String], uuid) != 0) {
154 return false;
155 }
156 client->musr = CFDataCreate(NULL, uuid, sizeof(uuid_t));
157 }
158 }
159 #endif /* TARGET_OS_IOS */
160
161 client->task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
162
163 client->accessGroups = SecTaskCopyAccessGroups(client->task);
164
165 #if TARGET_OS_IPHONE
166 client->allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateSystemKeychain);
167 client->isNetworkExtension = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateNetworkExtension);
168 client->canAccessNetworkExtensionAccessGroups = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementNetworkExtensionAccessGroups);
169 #endif
170 #if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS
171 if (client->inMultiUser) {
172 client->allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateKeychainSyncBubble);
173 }
174 #endif
175 if (!sanityCheckClientAccessGroups(client)) {
176 return false;
177 }
178 }
179 return true;
180 }
181
182 // Stolen and adapted from securityd_service
183 bool SecTaskIsEligiblePlatformBinary(SecTaskRef task, CFArrayRef identifiers) {
184 #if (DEBUG || RC_BUILDIT_YES)
185 secnotice("serverxpc", "Accepting client because debug");
186 return true;
187 #else
188
189 if (task == NULL) {
190 secerror("serverxpc: Client task is null, cannot verify platformness");
191 return false;
192 }
193
194 uint32_t flags = SecTaskGetCodeSignStatus(task);
195 /* check if valid and platform binary, but not platform path */
196
197 if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
198 if (SecIsInternalRelease()) {
199 if ((flags & (CS_DEBUGGED | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_DEBUGGED | CS_PLATFORM_BINARY)) {
200 secerror("serverxpc: client is not a platform binary: 0x%08x", flags);
201 return false;
202 }
203 } else {
204 secerror("serverxpc: client is not a platform binary: 0x%08x", flags);
205 return false;
206 }
207 }
208
209 CFStringRef signingIdentifier = SecTaskCopySigningIdentifier(task, NULL);
210 if (identifiers) {
211 if (signingIdentifier == NULL) {
212 secerror("serverxpc: client has no codesign identifier");
213 return false;
214 }
215
216 __block bool result = false;
217 CFArrayForEach(identifiers, ^(const void *value) {
218 if (CFEqual(value, signingIdentifier)) {
219 result = true;
220 }
221 });
222
223 if (result == true) {
224 secinfo("serverxpc", "client %@ is eligible platform binary", signingIdentifier);
225 } else {
226 secerror("serverxpc: client %@ is not eligible", signingIdentifier);
227 }
228
229 CFReleaseNull(signingIdentifier);
230 return result;
231 }
232
233 secinfo("serverxpc", "Client %@ is valid platform binary", signingIdentifier);
234 CFReleaseNull(signingIdentifier);
235 return true;
236
237 #endif
238 }