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