]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecSharedCredential.c
Security-57740.20.22.tar.gz
[apple/security.git] / OSX / sec / Security / SecSharedCredential.c
1 /*
2 * Copyright (c) 2014-2016 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 * SecSharedCredential.c - CoreFoundation-based functions to store and retrieve shared credentials.
24 *
25 */
26
27
28 #include <Security/SecSharedCredential.h>
29 #include <Security/SecBasePriv.h>
30 #include <utilities/SecCFError.h>
31 #include <utilities/SecCFWrappers.h>
32 #include "SecItemInternal.h"
33 #include <ipc/securityd_client.h>
34 #include "SecPasswordGenerate.h"
35
36 /* forward declarations */
37 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFStringRef password, CFErrorRef *error);
38 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
39
40
41 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
42 CFStringRef account,
43 CFStringRef password,
44 CFErrorRef *error)
45 {
46 OSStatus status;
47 __block CFErrorRef* outError = error;
48 __block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
49 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
50 if (fqdn) {
51 CFDictionaryAddValue(args, kSecAttrServer, fqdn);
52 }
53 if (account) {
54 CFDictionaryAddValue(args, kSecAttrAccount, account);
55 }
56 if (password) {
57 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_WATCH && !TARGET_OS_TV
58 CFDictionaryAddValue(args, kSecSharedPassword, password);
59 #else
60 CFDictionaryAddValue(args, CFSTR("spwd"), password);
61 #endif
62 }
63 status = SecOSStatusWith(^bool (CFErrorRef *error) {
64 CFTypeRef raw_result = NULL;
65 bool xpc_result;
66 bool internal_spi = false; // TODO: support this for SecurityDevTests
67 if(internal_spi && gSecurityd && gSecurityd->sec_add_shared_web_credential) {
68 xpc_result = gSecurityd->sec_add_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
69 } else {
70 xpc_result = cftype_client_to_bool_cftype_error_request(sec_add_shared_web_credential_id, args, SecSecurityClientGet(), &raw_result, error);
71 }
72 CFReleaseSafe(args);
73 if (!xpc_result) {
74 if (NULL == *error) {
75 SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
76 }
77 }
78 if (outError) {
79 *outError = (error) ? *error : NULL;
80 CFRetainSafe(*outError);
81 } else {
82 CFReleaseNull(*error);
83 }
84 CFReleaseNull(raw_result);
85 return xpc_result;
86 });
87
88 return status;
89 }
90
91 void SecAddSharedWebCredential(CFStringRef fqdn,
92 CFStringRef account,
93 CFStringRef password,
94 void (^completionHandler)(CFErrorRef error))
95 {
96 __block CFErrorRef error = NULL;
97 __block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
98 dispatch_retain(dst_queue);
99
100 /* sanity check input arguments */
101 CFStringRef errStr = NULL;
102 if (!fqdn || CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn) ||
103 !account || CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account) ) {
104 errStr = CFSTR("fqdn or account was not of type CFString, or not provided");
105 }
106 else if (password && CFGetTypeID(password) != CFStringGetTypeID()) {
107 errStr = CFSTR("non-nil password was not of type CFString");
108 }
109 if (errStr) {
110 SecError(errSecParam, &error, errStr);
111 dispatch_async(dst_queue, ^{
112 if (completionHandler) {
113 completionHandler(error);
114 }
115 CFReleaseSafe(error);
116 dispatch_release(dst_queue);
117 });
118 return;
119 }
120
121 __block CFStringRef serverStr = CFRetainSafe(fqdn);
122 __block CFStringRef accountStr = CFRetainSafe(account);
123 __block CFStringRef passwordStr = CFRetainSafe(password);
124
125 dispatch_async(dst_queue, ^{
126 OSStatus status = SecAddSharedWebCredentialSync(serverStr, accountStr, passwordStr, &error);
127 CFReleaseSafe(serverStr);
128 CFReleaseSafe(accountStr);
129 CFReleaseSafe(passwordStr);
130
131 if (status && !error) {
132 SecError(status, &error, CFSTR("Error adding shared password"));
133 }
134 dispatch_async(dst_queue, ^{
135 if (completionHandler) {
136 completionHandler(error);
137 }
138 CFReleaseSafe(error);
139 dispatch_release(dst_queue);
140 });
141 });
142
143 }
144
145 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
146 CFStringRef account,
147 CFArrayRef *credentials,
148 CFErrorRef *error)
149 {
150 OSStatus status;
151 __block CFErrorRef* outError = error;
152 __block CFMutableDictionaryRef args = CFDictionaryCreateMutable(kCFAllocatorDefault,
153 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
154 if (fqdn) {
155 CFDictionaryAddValue(args, kSecAttrServer, fqdn);
156 }
157 if (account) {
158 CFDictionaryAddValue(args, kSecAttrAccount, account);
159 }
160 status = SecOSStatusWith(^bool (CFErrorRef *error) {
161 CFTypeRef raw_result = NULL;
162 bool xpc_result;
163 bool internal_spi = false; // TODO: support this for SecurityDevTests
164 if(internal_spi && gSecurityd && gSecurityd->sec_copy_shared_web_credential) {
165 xpc_result = gSecurityd->sec_copy_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
166 } else {
167 xpc_result = cftype_client_to_bool_cftype_error_request(sec_copy_shared_web_credential_id, args, SecSecurityClientGet(), &raw_result, error);
168 }
169 CFReleaseSafe(args);
170 if (!xpc_result) {
171 if (NULL == *error) {
172 SecError(errSecInternal, error, CFSTR("Internal error (XPC failure)"));
173 }
174 }
175 if (outError) {
176 *outError = (error) ? *error : NULL;
177 CFRetainSafe(*outError);
178 } else {
179 CFReleaseNull(*error);
180 }
181 if (!raw_result) {
182 raw_result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
183 }
184 *credentials = raw_result;
185 return xpc_result;
186 });
187
188 return status;
189
190 }
191
192 void SecRequestSharedWebCredential(CFStringRef fqdn,
193 CFStringRef account,
194 void (^completionHandler)(CFArrayRef credentials, CFErrorRef error))
195 {
196 __block CFArrayRef result = NULL;
197 __block CFErrorRef error = NULL;
198 __block dispatch_queue_t dst_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
199 dispatch_retain(dst_queue);
200
201 /* sanity check input arguments, if provided */
202 CFStringRef errStr = NULL;
203 if (fqdn && (CFGetTypeID(fqdn) != CFStringGetTypeID() || !CFStringGetLength(fqdn))) {
204 errStr = CFSTR("fqdn was empty or not a CFString");
205 }
206 else if (account && (CFGetTypeID(account) != CFStringGetTypeID() || !CFStringGetLength(account))) {
207 errStr = CFSTR("account was empty or not a CFString");
208 }
209 if (errStr) {
210 SecError(errSecParam, &error, errStr);
211 dispatch_async(dst_queue, ^{
212 if (completionHandler) {
213 completionHandler(result, error);
214 }
215 CFReleaseSafe(error);
216 CFReleaseSafe(result);
217 dispatch_release(dst_queue);
218 });
219 return;
220 }
221
222 __block CFStringRef serverStr = CFRetainSafe(fqdn);
223 __block CFStringRef accountStr = CFRetainSafe(account);
224
225 dispatch_async(dst_queue, ^{
226 OSStatus status = SecCopySharedWebCredentialSync(serverStr, accountStr, &result, &error);
227 CFReleaseSafe(serverStr);
228 CFReleaseSafe(accountStr);
229
230 if (status && !error) {
231 SecError(status, &error, CFSTR("Error copying shared password"));
232 }
233 dispatch_async(dst_queue, ^{
234 if (completionHandler) {
235 completionHandler(result, error);
236 }
237 CFReleaseSafe(error);
238 CFReleaseSafe(result);
239 dispatch_release(dst_queue);
240 });
241 });
242
243 }
244
245 CFStringRef SecCreateSharedWebCredentialPassword(void)
246 {
247
248 CFStringRef password = NULL;
249 CFErrorRef error = NULL;
250 CFMutableDictionaryRef passwordRequirements = NULL;
251
252 CFStringRef allowedCharacters = CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
253 CFCharacterSetRef requiredCharactersLower = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("abcdefghkmnopqrstuvwxyz"));
254 CFCharacterSetRef requiredCharactersUppder = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
255 CFCharacterSetRef requiredCharactersNumbers = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR("3456789"));
256
257 int groupSize = 3;
258 int groupCount = 4;
259 int totalLength = (groupSize * groupCount);
260 CFNumberRef groupSizeRef = CFNumberCreate(NULL, kCFNumberIntType, &groupSize);
261 CFNumberRef groupCountRef = CFNumberCreate(NULL, kCFNumberIntType, &groupCount);
262 CFNumberRef totalLengthRef = CFNumberCreate(NULL, kCFNumberIntType, &totalLength);
263 CFStringRef separator = CFSTR("-");
264
265 CFMutableArrayRef requiredCharacterSets = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
266 CFArrayAppendValue(requiredCharacterSets, requiredCharactersLower);
267 CFArrayAppendValue(requiredCharacterSets, requiredCharactersUppder);
268 CFArrayAppendValue(requiredCharacterSets, requiredCharactersNumbers);
269
270 passwordRequirements = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
271 CFDictionaryAddValue(passwordRequirements, kSecPasswordAllowedCharactersKey, allowedCharacters);
272 CFDictionaryAddValue(passwordRequirements, kSecPasswordRequiredCharactersKey, requiredCharacterSets);
273 CFDictionaryAddValue(passwordRequirements, kSecPasswordGroupSize, groupSizeRef );
274 CFDictionaryAddValue(passwordRequirements, kSecPasswordNumberOfGroups, groupCountRef);
275 CFDictionaryAddValue(passwordRequirements, kSecPasswordSeparator, separator);
276 CFDictionaryAddValue(passwordRequirements, kSecPasswordMaxLengthKey, totalLengthRef);
277 CFDictionaryAddValue(passwordRequirements, kSecPasswordMinLengthKey, totalLengthRef);
278 CFDictionaryAddValue(passwordRequirements, kSecPasswordDefaultForType, CFSTR("false"));
279 CFRelease(requiredCharactersLower);
280 CFRelease(requiredCharactersUppder);
281 CFRelease(requiredCharactersNumbers);
282 CFRelease(groupSizeRef);
283 CFRelease(groupCountRef);
284 CFRelease(totalLengthRef);
285
286 password = SecPasswordGenerate(kSecPasswordTypeSafari, &error, passwordRequirements);
287
288 CFRelease(requiredCharacterSets);
289 CFRelease(passwordRequirements);
290 if ((error && error != errSecSuccess) || !password)
291 {
292 if (password) CFRelease(password);
293 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");
294 return NULL;
295 } else {
296 return password;
297 }
298
299 }
300