]>
Commit | Line | Data |
---|---|---|
866f8763 A |
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 | #import <Foundation/Foundation.h> | |
25 | #import <Foundation/NSXPCConnection.h> | |
26 | #import <Foundation/NSXPCConnection_Private.h> | |
27 | #include <xpc/private.h> | |
28 | #include <xpc/xpc.h> | |
29 | ||
30 | #include <ipc/securityd_client.h> | |
31 | #include <ipc/server_security_helpers.h> | |
32 | #include <ipc/server_entitlement_helpers.h> | |
33 | #include <ipc/server_endpoint.h> | |
34 | ||
35 | #include <securityd/SecItemServer.h> | |
36 | #include <Security/SecEntitlements.h> | |
37 | ||
38 | #pragma mark - Securityd Server | |
39 | ||
40 | @implementation SecuritydXPCServer | |
41 | @synthesize connection = _connection; | |
42 | ||
43 | - (instancetype)initWithConnection:(NSXPCConnection *)connection | |
44 | { | |
45 | if ((self = [super init])) { | |
46 | _connection = connection; | |
47 | ||
48 | fill_security_client(&self->_client, connection.effectiveUserIdentifier, connection.auditToken); | |
49 | } | |
50 | return self; | |
51 | } | |
52 | ||
53 | - (instancetype)initWithSecurityClient:(SecurityClient*) existingClient | |
54 | { | |
55 | if(!existingClient) { | |
56 | return nil; | |
57 | } | |
58 | if((self = [super init])) { | |
59 | _connection = nil; | |
60 | ||
61 | self->_client.task = CFRetainSafe(existingClient->task); | |
62 | self->_client.accessGroups = CFRetainSafe(existingClient->accessGroups); | |
63 | self->_client.allowSystemKeychain = existingClient->allowSystemKeychain; | |
64 | self->_client.allowSyncBubbleKeychain = existingClient->allowSyncBubbleKeychain; | |
65 | self->_client.isNetworkExtension = existingClient->isNetworkExtension; | |
66 | self->_client.canAccessNetworkExtensionAccessGroups = existingClient->canAccessNetworkExtensionAccessGroups; | |
67 | self->_client.uid = existingClient->uid; | |
68 | self->_client.musr = CFRetainSafe(existingClient->musr); | |
69 | #if TARGET_OS_EMBEDDED && TARGET_HAS_KEYSTORE | |
70 | self->_client.keybag = existingClient->keybag; | |
71 | #endif | |
72 | #if TARGET_OS_IPHONE | |
73 | self->_client.inMultiUser = existingClient->inMultiUser; | |
74 | self->_client.activeUser = existingClient->activeUser; | |
75 | #endif | |
76 | } | |
77 | return self; | |
78 | } | |
79 | ||
80 | ||
81 | - (bool)clientHasBooleanEntitlement: (NSString*) entitlement { | |
82 | return SecTaskGetBooleanValueForEntitlement(self->_client.task, (__bridge CFStringRef) entitlement); | |
83 | } | |
84 | ||
85 | -(void)dealloc { | |
86 | CFReleaseNull(self->_client.task); | |
87 | CFReleaseNull(self->_client.accessGroups); | |
88 | CFReleaseNull(self->_client.musr); | |
89 | } | |
90 | @end | |
91 | ||
92 | ||
93 | // Class to use for local dispatching of securityd xpcs. Adds capability of fake entitlements, because you don't have a real task on the other end. | |
94 | @interface LocalSecuritydXPCServer : SecuritydXPCServer | |
95 | @property NSMutableDictionary<NSString*, id>* fakeEntitlements; | |
96 | - (instancetype)initWithSecurityClient:(SecurityClient*) existingClient fakeEntitlements:(NSDictionary<NSString*, id>*)fakeEntitlements; | |
97 | @end | |
98 | ||
99 | @implementation LocalSecuritydXPCServer | |
100 | - (instancetype)initWithSecurityClient:(SecurityClient*) existingClient fakeEntitlements:(NSDictionary<NSString*, id>*)fakeEntitlements { | |
101 | if((self = [super initWithSecurityClient: existingClient])) { | |
102 | _fakeEntitlements = [fakeEntitlements mutableCopy]; | |
103 | } | |
104 | return self; | |
105 | } | |
106 | ||
107 | - (bool)clientHasBooleanEntitlement: (NSString*) entitlement { | |
108 | if(self.fakeEntitlements) { | |
109 | return [self.fakeEntitlements[entitlement] isEqual: @YES]; | |
110 | } else { | |
111 | return false; | |
112 | } | |
113 | } | |
114 | @end | |
115 | ||
116 | ||
117 | #pragma mark - SecuritydXPCServerListener | |
118 | ||
119 | // Responsible for bringing up new SecuritydXPCServer objects, and configuring them with their remote connection | |
120 | @interface SecuritydXPCServerListener : NSObject <NSXPCListenerDelegate> | |
121 | @property (retain,nonnull) NSXPCListener *listener; | |
866f8763 A |
122 | @end |
123 | ||
124 | @implementation SecuritydXPCServerListener | |
125 | -(instancetype)init | |
126 | { | |
127 | if((self = [super init])){ | |
ecaf5866 | 128 | self.listener = [[NSXPCListener alloc] initWithMachServiceName:@(kSecuritydGeneralServiceName)]; |
866f8763 A |
129 | self.listener.delegate = self; |
130 | [self.listener resume]; | |
131 | } | |
132 | return self; | |
133 | } | |
134 | ||
866f8763 A |
135 | - (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection |
136 | { | |
137 | // Anyone is allowed to get a connection to securityd, except if you have kSecEntitlementKeychainDeny entitlement | |
138 | // The SecuritydClient class _must_ check for required entitlements in each XPC handler. | |
139 | ||
140 | if([newConnection valueForEntitlement: (__bridge NSString*) kSecEntitlementKeychainDeny]) { | |
141 | return NO; | |
142 | } | |
143 | ||
144 | newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)]; | |
145 | // Configure the interface on the server side, too | |
146 | [SecuritydXPCClient configureSecuritydXPCProtocol: newConnection.exportedInterface]; | |
147 | ||
148 | newConnection.exportedObject = [[SecuritydXPCServer alloc] initWithConnection:newConnection]; | |
149 | [newConnection resume]; | |
150 | ||
151 | return YES; | |
152 | } | |
153 | @end | |
154 | ||
ecaf5866 A |
155 | void |
156 | SecCreateSecuritydXPCServer(void) | |
866f8763 A |
157 | { |
158 | static SecuritydXPCServerListener* listener = NULL; | |
159 | static dispatch_once_t onceToken; | |
160 | dispatch_once(&onceToken, ^{ | |
ecaf5866 A |
161 | @autoreleasepool { |
162 | listener = [[SecuritydXPCServerListener alloc] init]; | |
163 | } | |
866f8763 | 164 | }); |
866f8763 A |
165 | } |
166 | ||
167 | id<SecuritydXPCProtocol> SecCreateLocalSecuritydXPCServer(void) { | |
168 | // Create a fake securitydxpcserver using the access groups of securityd and some number of fake entitlements | |
169 | SecurityClient* client = SecSecurityClientGet(); | |
170 | ||
171 | // We know that SecuritydXPCServerListener will comply with SecuritydXPCProtocol via category, so help the compiler out | |
172 | return (id<SecuritydXPCProtocol>) [[LocalSecuritydXPCServer alloc] initWithSecurityClient: client fakeEntitlements: @{}]; | |
173 | } | |
174 | ||
175 | CFTypeRef SecCreateLocalCFSecuritydXPCServer(void) { | |
176 | return (CFTypeRef) CFBridgingRetain(SecCreateLocalSecuritydXPCServer()); | |
177 | } | |
178 | ||
179 | void SecResetLocalSecuritydXPCFakeEntitlements(void) { | |
180 | if([(__bridge id) gSecurityd->secd_xpc_server isKindOfClass: [LocalSecuritydXPCServer class]]) { | |
181 | LocalSecuritydXPCServer* server = (__bridge LocalSecuritydXPCServer*)gSecurityd->secd_xpc_server; | |
182 | server.fakeEntitlements = [[NSMutableDictionary alloc] init]; | |
183 | } | |
184 | } | |
185 | ||
186 | void SecAddLocalSecuritydXPCFakeEntitlement(CFStringRef entitlement, CFTypeRef value) { | |
187 | if([(__bridge id) gSecurityd->secd_xpc_server isKindOfClass: [LocalSecuritydXPCServer class]]) { | |
188 | LocalSecuritydXPCServer* server = (__bridge LocalSecuritydXPCServer*)gSecurityd->secd_xpc_server; | |
189 | server.fakeEntitlements[(__bridge NSString*)entitlement] = (__bridge id)value; | |
190 | } | |
191 | } |