2 * Copyright (c) 2017 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 <pthread/pthread.h>
26 #include "server_security_helpers.h"
27 #include "server_entitlement_helpers.h"
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"
42 #if __has_include(<MobileKeyBag/MobileKeyBag.h>) && TARGET_HAS_KEYSTORE
43 #include <MobileKeyBag/MobileKeyBag.h>
44 #define HAVE_MOBILE_KEYBAG_SUPPORT 1
47 #if __has_include(<UserManagement/UserManagement.h>)
48 #include <UserManagement/UserManagement.h>
51 #if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
53 device_is_multiuser(void)
55 static dispatch_once_t once;
58 dispatch_once(&once, ^{
59 CFDictionaryRef deviceMode = MKBUserTypeDeviceMode(NULL, NULL);
60 CFTypeRef value = NULL;
62 if (deviceMode && CFDictionaryGetValueIfPresent(deviceMode, kMKBDeviceModeKey, &value) && CFEqual(value, kMKBDeviceModeMultiUser)) {
65 CFReleaseNull(deviceMode);
70 #endif /* HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS */
72 static bool sanityCheckClientAccessGroups(SecurityClient* client) {
73 if (!client->accessGroups) {
77 CFRange range = { 0, CFArrayGetCount(client->accessGroups) };
78 if (!CFArrayContainsValue(client->accessGroups, range, CFSTR("*"))) {
82 CFMutableArrayRef allowedIdentifiers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
84 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.keychainaccess"));
85 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.KeychainMigrator"));
87 if (SecIsInternalRelease()) {
89 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security2"));
91 CFArrayAppendValue(allowedIdentifiers, CFSTR("com.apple.security"));
95 bool answer = SecTaskIsEligiblePlatformBinary(client->task, allowedIdentifiers);
96 CFReleaseNull(allowedIdentifiers);
102 fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t auditToken) {
112 #if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
113 if (device_is_multiuser()) {
114 CFErrorRef error = NULL;
116 client->inMultiUser = true;
117 client->activeUser = MKBForegroundUserSessionID(&error);
118 if (client->activeUser == -1 || client->activeUser == 0) {
120 client->activeUser = 0;
124 * If we are a edu mode user, and its not the active user,
125 * then the request is coming from inside the syncbubble.
127 * otherwise we are going to execute the request as the
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;
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;
142 #endif /* TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT */
143 #if TARGET_OS_IOS || TARGET_OS_TV
145 * iOS supports Enterprise Data Separation.
146 * tvOS supports guest users.
147 * Use the appropriate musr values for either.
150 UMUserPersona * persona = [[UMUserManager sharedManager] currentPersona];
153 persona.userPersonaType == UMUserPersonaTypeEnterprise
155 persona.userPersonaType == UMUserPersonaTypeGuest
158 secinfo("serverxpc", "securityd client: persona user %@", persona.userPersonaNickName);
161 if (uuid_parse([persona.userPersonaUniqueString UTF8String], uuid) != 0) {
164 client->musr = CFDataCreate(NULL, uuid, sizeof(uuid_t));
167 #endif /* TARGET_OS_IOS || TARGET_OS_TV */
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)");
178 client->allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateSystemKeychain);
179 client->isNetworkExtension = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateNetworkExtension);
180 client->canAccessNetworkExtensionAccessGroups = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementNetworkExtensionAccessGroups);
182 #if HAVE_MOBILE_KEYBAG_SUPPORT && TARGET_OS_IOS
183 if (client->inMultiUser) {
184 client->allowSyncBubbleKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateKeychainSyncBubble);
187 if (!sanityCheckClientAccessGroups(client)) {
188 CFReleaseNull(client->task);
189 CFReleaseNull(client->accessGroups);
190 CFReleaseNull(client->musr);
191 CFReleaseNull(client->applicationIdentifier);
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");
206 secerror("serverxpc: Client task is null, cannot verify platformness");
210 uint32_t flags = SecTaskGetCodeSignStatus(task);
211 /* check if valid and platform binary, but not platform path */
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);
220 secerror("serverxpc: client is not a platform binary: 0x%08x", flags);
225 CFStringRef signingIdentifier = SecTaskCopySigningIdentifier(task, NULL);
227 if (signingIdentifier == NULL) {
228 secerror("serverxpc: client has no codesign identifier");
232 __block bool result = false;
233 CFArrayForEach(identifiers, ^(const void *value) {
234 if (CFEqual(value, signingIdentifier)) {
239 if (result == true) {
240 secinfo("serverxpc", "client %@ is eligible platform binary", signingIdentifier);
242 secerror("serverxpc: client %@ is not eligible", signingIdentifier);
245 CFReleaseNull(signingIdentifier);
249 secinfo("serverxpc", "Client %@ is valid platform binary", signingIdentifier);
250 CFReleaseNull(signingIdentifier);