]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 <Security/SecKeychain.h> | |
25 | #include <Security/SecKeychainPriv.h> | |
26 | #include <security_keychain/KCCursor.h> | |
27 | #include <security_cdsa_utilities/cssmdata.h> | |
d8f41ccd | 28 | #include <security_cdsa_client/wrapkey.h> |
b1ab9ed8 A |
29 | #include <security_keychain/KCExceptions.h> |
30 | #include <securityd_client/ssblob.h> | |
d8f41ccd A |
31 | #include <Security/SecAccess.h> |
32 | #include <Security/SecTrustedApplicationPriv.h> | |
b1ab9ed8 A |
33 | #include "SecBridge.h" |
34 | #include "CCallbackMgr.h" | |
35 | #include <security_cdsa_utilities/Schema.h> | |
d8f41ccd | 36 | #include <security_cdsa_client/mdsclient.h> |
b1ab9ed8 | 37 | #include <pwd.h> |
866f8763 | 38 | #include <os/activity.h> |
fa7225c8 A |
39 | #include <Security/AuthorizationTagsPriv.h> |
40 | #include <Security/Authorization.h> | |
41 | #include "TokenLogin.h" | |
b1ab9ed8 | 42 | |
d8f41ccd A |
43 | OSStatus |
44 | SecKeychainMDSInstall() | |
45 | { | |
866f8763 A |
46 | BEGIN_SECAPI |
47 | os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); | |
48 | os_activity_scope(activity); | |
49 | os_release(activity); | |
d8f41ccd A |
50 | |
51 | Security::MDSClient::Directory d; | |
52 | d.install(); | |
53 | ||
54 | END_SECAPI | |
55 | } | |
56 | ||
b1ab9ed8 A |
57 | CFTypeID |
58 | SecKeychainGetTypeID(void) | |
59 | { | |
60 | BEGIN_SECAPI | |
61 | ||
62 | return gTypes().KeychainImpl.typeID; | |
63 | ||
64 | END_SECAPI1(_kCFRuntimeNotATypeID) | |
65 | } | |
66 | ||
67 | ||
68 | OSStatus | |
69 | SecKeychainGetVersion(UInt32 *returnVers) | |
70 | { | |
71 | if (!returnVers) | |
427c49bc | 72 | return errSecSuccess; |
b1ab9ed8 A |
73 | |
74 | *returnVers = 0x02028000; | |
427c49bc | 75 | return errSecSuccess; |
b1ab9ed8 A |
76 | } |
77 | ||
78 | ||
79 | OSStatus | |
80 | SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef) | |
81 | { | |
82 | BEGIN_SECAPI | |
866f8763 A |
83 | os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
84 | os_activity_scope(activity); | |
85 | os_release(activity); | |
b1ab9ed8 A |
86 | |
87 | RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle(); | |
88 | ||
89 | END_SECAPI | |
90 | } | |
91 | ||
92 | ||
93 | OSStatus | |
94 | SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName, | |
95 | const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain) | |
96 | { | |
97 | BEGIN_SECAPI | |
866f8763 A |
98 | os_activity_t activity = os_activity_create("SecKeychainOpenWithGuid", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
99 | os_activity_scope(activity); | |
100 | os_release(activity); | |
b1ab9ed8 A |
101 | |
102 | // range check parameters | |
103 | RequiredParam (guid); | |
104 | RequiredParam (dbName); | |
105 | ||
106 | // create a DLDbIdentifier that describes what should be opened | |
107 | const CSSM_VERSION *version = NULL; | |
108 | const CssmSubserviceUid ssuid(*guid, version, subserviceId, subserviceType); | |
109 | DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation); | |
110 | ||
111 | // make a keychain from the supplied info | |
fa7225c8 | 112 | RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false, false)->handle (); |
b1ab9ed8 A |
113 | |
114 | END_SECAPI | |
115 | } | |
116 | ||
117 | ||
118 | OSStatus | |
119 | SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password, | |
120 | Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef) | |
121 | { | |
122 | BEGIN_SECAPI | |
866f8763 A |
123 | os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
124 | os_activity_scope(activity); | |
125 | os_release(activity); | |
427c49bc A |
126 | |
127 | KCThrowParamErrIf_(!pathName); | |
fa7225c8 | 128 | Keychain keychain = globals().storageManager.make(pathName, true, true); |
b1ab9ed8 A |
129 | |
130 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
131 | // If the create below fails we should probably remove it. | |
132 | if(promptUser) | |
133 | keychain->create(); | |
134 | else | |
135 | { | |
136 | KCThrowParamErrIf_(!password); | |
137 | keychain->create(passwordLength, password); | |
138 | } | |
139 | ||
140 | RequiredParam(keychainRef)=keychain->handle(); | |
141 | ||
142 | END_SECAPI | |
143 | } | |
144 | ||
145 | ||
146 | OSStatus | |
147 | SecKeychainDelete(SecKeychainRef keychainOrArray) | |
148 | { | |
149 | BEGIN_SECAPI | |
866f8763 A |
150 | os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
151 | os_activity_scope(activity); | |
152 | os_release(activity); | |
b1ab9ed8 A |
153 | |
154 | KCThrowIf_(!keychainOrArray, errSecInvalidKeychain); | |
155 | StorageManager::KeychainList keychains; | |
156 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
157 | ||
158 | globals().storageManager.remove(keychains, true); | |
159 | ||
160 | END_SECAPI | |
161 | } | |
162 | ||
163 | ||
164 | OSStatus | |
165 | SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings) | |
166 | { | |
167 | BEGIN_SECAPI | |
866f8763 A |
168 | os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
169 | os_activity_scope(activity); | |
170 | os_release(activity); | |
b1ab9ed8 A |
171 | |
172 | Keychain keychain = Keychain::optional(keychainRef); | |
173 | if (newSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
174 | { | |
175 | UInt32 lockInterval=newSettings->lockInterval; | |
176 | bool lockOnSleep=newSettings->lockOnSleep; | |
177 | keychain->setSettings(lockInterval, lockOnSleep); | |
178 | } | |
179 | ||
180 | END_SECAPI | |
181 | } | |
182 | ||
183 | ||
184 | OSStatus | |
185 | SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings) | |
186 | { | |
187 | BEGIN_SECAPI | |
866f8763 A |
188 | os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
189 | os_activity_scope(activity); | |
190 | os_release(activity); | |
b1ab9ed8 A |
191 | |
192 | Keychain keychain = Keychain::optional(keychainRef); | |
193 | if (outSettings->version==SEC_KEYCHAIN_SETTINGS_VERS1) | |
194 | { | |
195 | uint32 lockInterval; | |
196 | bool lockOnSleep; | |
197 | ||
198 | keychain->getSettings(lockInterval, lockOnSleep); | |
199 | outSettings->lockInterval=lockInterval; | |
200 | outSettings->lockOnSleep=lockOnSleep; | |
201 | } | |
202 | ||
203 | END_SECAPI | |
204 | } | |
205 | ||
206 | ||
207 | OSStatus | |
208 | SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword) | |
209 | { | |
210 | BEGIN_SECAPI | |
866f8763 A |
211 | os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
212 | os_activity_scope(activity); | |
213 | os_release(activity); | |
b1ab9ed8 A |
214 | |
215 | Keychain keychain = Keychain::optional(keychainRef); | |
216 | ||
217 | if (usePassword) | |
218 | keychain->unlock(CssmData(const_cast<void *>(password), passwordLength)); | |
219 | else | |
220 | keychain->unlock(); | |
221 | ||
222 | END_SECAPI | |
223 | } | |
224 | ||
225 | ||
226 | OSStatus | |
227 | SecKeychainLock(SecKeychainRef keychainRef) | |
228 | { | |
229 | BEGIN_SECAPI | |
866f8763 A |
230 | os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
231 | os_activity_scope(activity); | |
232 | os_release(activity); | |
b1ab9ed8 A |
233 | |
234 | Keychain keychain = Keychain::optional(keychainRef); | |
235 | keychain->lock(); | |
236 | ||
237 | END_SECAPI | |
238 | } | |
239 | ||
240 | ||
241 | OSStatus | |
242 | SecKeychainLockAll(void) | |
243 | { | |
244 | BEGIN_SECAPI | |
866f8763 A |
245 | os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
246 | os_activity_scope(activity); | |
247 | os_release(activity); | |
b1ab9ed8 A |
248 | |
249 | globals().storageManager.lockAll(); | |
250 | ||
251 | END_SECAPI | |
252 | } | |
253 | ||
254 | ||
255 | OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList) | |
256 | { | |
257 | BEGIN_SECAPI | |
866f8763 A |
258 | os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
259 | os_activity_scope(activity); | |
260 | os_release(activity); | |
b1ab9ed8 A |
261 | // |
262 | // Get the current user (using fallback method if necessary) | |
263 | // | |
264 | char* uName = getenv("USER"); | |
265 | string userName = uName ? uName : ""; | |
266 | if ( userName.length() == 0 ) | |
267 | { | |
268 | uid_t uid = geteuid(); | |
269 | if (!uid) uid = getuid(); | |
270 | struct passwd *pw = getpwuid(uid); // fallback case... | |
271 | if (pw) | |
272 | userName = pw->pw_name; | |
273 | endpwent(); | |
274 | } | |
275 | if ( userName.length() == 0 ) // did we ultimately get one? | |
ecaf5866 | 276 | { |
b1ab9ed8 | 277 | MacOSError::throwMe(errAuthorizationInternal); |
ecaf5866 | 278 | } |
822b670c A |
279 | |
280 | SecurityServer::ClientSession().resetKeyStorePassphrase(password ? CssmData(const_cast<void *>(password), passwordLength) : CssmData()); | |
ecaf5866 | 281 | secwarning("SecKeychainResetLogin: reset AKS passphrase"); |
b1ab9ed8 A |
282 | if (password) |
283 | { | |
284 | // Clear the plist and move aside (rename) the existing login.keychain | |
285 | globals().storageManager.resetKeychain(resetSearchList); | |
286 | ||
287 | // Create the login keychain without UI | |
fa7225c8 | 288 | globals().storageManager.login((UInt32)userName.length(), userName.c_str(), passwordLength, password, true); |
b1ab9ed8 A |
289 | |
290 | // Set it as the default | |
291 | Keychain keychain = globals().storageManager.loginKeychain(); | |
292 | globals().storageManager.defaultKeychain(keychain); | |
293 | } | |
294 | else | |
295 | { | |
296 | // Create the login keychain, prompting for password | |
297 | // (implicitly calls resetKeychain, login, and defaultKeychain) | |
fa7225c8 | 298 | globals().storageManager.makeLoginAuthUI(NULL, true); |
b1ab9ed8 | 299 | } |
ecaf5866 | 300 | secwarning("SecKeychainResetLogin: reset osx keychain"); |
b1ab9ed8 A |
301 | |
302 | // Post a "list changed" event after a reset, so apps can refresh their list. | |
303 | // Make sure we are not holding mLock when we post this event. | |
304 | KCEventNotifier::PostKeychainEvent(kSecKeychainListChangedEvent); | |
305 | ||
ecaf5866 | 306 | |
b1ab9ed8 A |
307 | END_SECAPI |
308 | } | |
309 | ||
310 | OSStatus | |
311 | SecKeychainCopyDefault(SecKeychainRef *keychainRef) | |
312 | { | |
313 | BEGIN_SECAPI | |
314 | ||
315 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain()->handle(); | |
316 | ||
317 | END_SECAPI | |
318 | } | |
319 | ||
320 | ||
321 | OSStatus | |
322 | SecKeychainSetDefault(SecKeychainRef keychainRef) | |
323 | { | |
324 | BEGIN_SECAPI | |
866f8763 A |
325 | os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
326 | os_activity_scope(activity); | |
327 | os_release(activity); | |
b1ab9ed8 A |
328 | |
329 | globals().storageManager.defaultKeychain(Keychain::optional(keychainRef)); | |
330 | ||
331 | END_SECAPI | |
332 | } | |
333 | ||
334 | OSStatus SecKeychainCopySearchList(CFArrayRef *searchList) | |
335 | { | |
336 | BEGIN_SECAPI | |
866f8763 A |
337 | os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
338 | os_activity_scope(activity); | |
339 | os_release(activity); | |
b1ab9ed8 A |
340 | |
341 | RequiredParam(searchList); | |
342 | StorageManager &smr = globals().storageManager; | |
343 | StorageManager::KeychainList keychainList; | |
344 | smr.getSearchList(keychainList); | |
345 | *searchList = smr.convertFromKeychainList(keychainList); | |
346 | ||
347 | END_SECAPI | |
348 | } | |
349 | ||
350 | OSStatus SecKeychainSetSearchList(CFArrayRef searchList) | |
351 | { | |
352 | BEGIN_SECAPI | |
866f8763 A |
353 | os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
354 | os_activity_scope(activity); | |
355 | os_release(activity); | |
b1ab9ed8 A |
356 | |
357 | RequiredParam(searchList); | |
358 | StorageManager &smr = globals().storageManager; | |
359 | StorageManager::KeychainList keychainList; | |
360 | smr.convertToKeychainList(searchList, keychainList); | |
361 | smr.setSearchList(keychainList); | |
362 | ||
363 | END_SECAPI | |
364 | } | |
365 | ||
366 | OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef) | |
367 | { | |
368 | BEGIN_SECAPI | |
866f8763 A |
369 | os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
370 | os_activity_scope(activity); | |
371 | os_release(activity); | |
b1ab9ed8 A |
372 | |
373 | RequiredParam(keychainRef)=globals().storageManager.defaultKeychain(domain)->handle(); | |
374 | ||
375 | END_SECAPI | |
376 | } | |
377 | ||
378 | OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef) | |
379 | { | |
380 | BEGIN_SECAPI | |
866f8763 A |
381 | os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
382 | os_activity_scope(activity); | |
383 | os_release(activity); | |
b1ab9ed8 A |
384 | |
385 | globals().storageManager.defaultKeychain(domain, Keychain::optional(keychainRef)); | |
386 | ||
387 | END_SECAPI | |
388 | } | |
389 | ||
390 | OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef *searchList) | |
391 | { | |
392 | BEGIN_SECAPI | |
393 | ||
394 | RequiredParam(searchList); | |
395 | StorageManager &smr = globals().storageManager; | |
396 | StorageManager::KeychainList keychainList; | |
397 | smr.getSearchList(domain, keychainList); | |
398 | *searchList = smr.convertFromKeychainList(keychainList); | |
399 | ||
400 | END_SECAPI | |
401 | } | |
402 | ||
403 | OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList) | |
404 | { | |
405 | BEGIN_SECAPI | |
866f8763 A |
406 | os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
407 | os_activity_scope(activity); | |
408 | os_release(activity); | |
b1ab9ed8 A |
409 | |
410 | RequiredParam(searchList); | |
411 | StorageManager &smr = globals().storageManager; | |
412 | StorageManager::KeychainList keychainList; | |
413 | smr.convertToKeychainList(searchList, keychainList); | |
414 | smr.setSearchList(domain, keychainList); | |
415 | ||
416 | END_SECAPI | |
417 | } | |
418 | ||
419 | OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain) | |
420 | { | |
421 | BEGIN_SECAPI | |
866f8763 A |
422 | os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
423 | os_activity_scope(activity); | |
424 | os_release(activity); | |
b1ab9ed8 A |
425 | |
426 | globals().storageManager.domain(domain); | |
427 | ||
428 | END_SECAPI | |
429 | } | |
430 | ||
431 | OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain) | |
432 | { | |
433 | BEGIN_SECAPI | |
866f8763 A |
434 | os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
435 | os_activity_scope(activity); | |
436 | os_release(activity); | |
b1ab9ed8 A |
437 | |
438 | *domain = globals().storageManager.domain(); | |
439 | ||
440 | END_SECAPI | |
441 | } | |
442 | ||
443 | ||
444 | OSStatus | |
445 | SecKeychainGetStatus(SecKeychainRef keychainRef, SecKeychainStatus *keychainStatus) | |
446 | { | |
447 | BEGIN_SECAPI | |
448 | ||
449 | RequiredParam(keychainStatus) = (SecKeychainStatus)Keychain::optional(keychainRef)->status(); | |
450 | ||
451 | END_SECAPI | |
452 | } | |
453 | ||
454 | ||
455 | OSStatus | |
456 | SecKeychainGetPath(SecKeychainRef keychainRef, UInt32 *ioPathLength, char *pathName) | |
457 | { | |
458 | BEGIN_SECAPI | |
459 | ||
460 | RequiredParam(pathName); | |
461 | RequiredParam(ioPathLength); | |
462 | ||
463 | const char *name = Keychain::optional(keychainRef)->name(); | |
427c49bc | 464 | UInt32 nameLen = (UInt32)strlen(name); |
b1ab9ed8 A |
465 | UInt32 callersLen = *ioPathLength; |
466 | *ioPathLength = nameLen; | |
467 | if (nameLen+1 > callersLen) // if the client's buffer is too small (including null-termination), throw | |
468 | return errSecBufferTooSmall; | |
469 | strncpy(pathName, name, nameLen); | |
470 | pathName[nameLen] = 0; | |
471 | *ioPathLength = nameLen; // set the length. | |
472 | ||
473 | END_SECAPI | |
474 | } | |
475 | ||
e3d460c9 A |
476 | OSStatus |
477 | SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version) | |
478 | { | |
479 | BEGIN_SECAPI | |
480 | ||
481 | RequiredParam(version); | |
482 | ||
483 | *version = Keychain::optional(keychainRef)->database()->dbBlobVersion(); | |
484 | ||
485 | END_SECAPI | |
486 | } | |
487 | ||
fa7225c8 A |
488 | OSStatus |
489 | SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename) | |
490 | { | |
491 | BEGIN_SECAPI | |
866f8763 A |
492 | os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
493 | os_activity_scope(activity); | |
494 | os_release(activity); | |
fa7225c8 A |
495 | |
496 | RequiredParam(masterKeyFilename); | |
497 | Keychain kc = Keychain::optional(keychain); | |
498 | ||
499 | SecurityServer::SystemKeychainKey keychainKey(masterKeyFilename); | |
500 | if(keychainKey.valid()) { | |
501 | // We've managed to read the key; now, create credentials using it | |
502 | string path = kc->name(); | |
503 | ||
504 | CssmClient::Key keychainMasterKey(kc->csp(), keychainKey.key(), true); | |
505 | CssmClient::AclFactory::MasterKeyUnlockCredentials creds(keychainMasterKey, Allocator::standard(Allocator::sensitive)); | |
506 | ||
507 | // Attempt the migrate, using our master key as the ACL override | |
508 | bool result = kc->keychainMigration(path, kc->database()->dbBlobVersion(), path, version, creds.getAccessCredentials()); | |
509 | if(!result) { | |
510 | return errSecBadReq; | |
511 | } | |
512 | return (kc->database()->dbBlobVersion() == version ? errSecSuccess : errSecBadReq); | |
513 | } else { | |
514 | return errSecBadReq; | |
515 | } | |
516 | ||
517 | END_SECAPI | |
518 | } | |
519 | ||
b1ab9ed8 A |
520 | |
521 | // @@@ Deprecated | |
522 | UInt16 | |
523 | SecKeychainListGetCount(void) | |
524 | { | |
525 | BEGIN_SECAPI | |
526 | ||
527 | return globals().storageManager.size(); | |
528 | ||
529 | END_SECAPI1(0) | |
530 | } | |
531 | ||
532 | ||
533 | // @@@ Deprecated | |
534 | OSStatus | |
535 | SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef) | |
536 | { | |
537 | BEGIN_SECAPI | |
538 | ||
539 | KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager; | |
540 | RequiredParam(keychainRef)=smgr[index]->handle(); | |
541 | ||
542 | END_SECAPI | |
543 | } | |
544 | ||
545 | ||
546 | // @@@ Deprecated | |
547 | OSStatus | |
548 | SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef) | |
549 | { | |
550 | BEGIN_SECAPI | |
551 | ||
552 | Required(keychainRef); | |
553 | Keychain keychain = Keychain::optional(*keychainRef); | |
554 | StorageManager::KeychainList keychainList; | |
555 | keychainList.push_back(keychain); | |
556 | globals().storageManager.remove(keychainList); | |
557 | *keychainRef = NULL; | |
558 | ||
559 | END_SECAPI | |
560 | } | |
561 | ||
562 | ||
563 | OSStatus | |
564 | SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info) | |
565 | { | |
566 | BEGIN_SECAPI | |
567 | ||
568 | Keychain keychain = Keychain::optional(keychainRef); | |
569 | keychain->getAttributeInfoForItemID(itemID, info); | |
570 | ||
571 | END_SECAPI | |
572 | } | |
573 | ||
574 | ||
575 | OSStatus | |
576 | SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) | |
577 | { | |
578 | BEGIN_SECAPI | |
579 | ||
580 | KeychainImpl::freeAttributeInfo(info); | |
581 | ||
582 | END_SECAPI | |
583 | } | |
584 | ||
585 | ||
586 | pascal OSStatus | |
587 | SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext) | |
588 | { | |
589 | BEGIN_SECAPI | |
866f8763 A |
590 | os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
591 | os_activity_scope(activity); | |
592 | os_release(activity); | |
b1ab9ed8 A |
593 | |
594 | RequiredParam(callbackFunction); | |
595 | CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext); | |
596 | ||
597 | END_SECAPI | |
598 | } | |
599 | ||
600 | ||
601 | OSStatus | |
602 | SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) | |
603 | { | |
604 | BEGIN_SECAPI | |
866f8763 A |
605 | os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
606 | os_activity_scope(activity); | |
607 | os_release(activity); | |
b1ab9ed8 A |
608 | |
609 | RequiredParam(callbackFunction); | |
610 | CCallbackMgr::RemoveCallback(callbackFunction); | |
611 | ||
612 | END_SECAPI | |
613 | } | |
614 | ||
615 | OSStatus | |
616 | SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) | |
617 | { | |
618 | BEGIN_SECAPI | |
866f8763 A |
619 | os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
620 | os_activity_scope(activity); | |
621 | os_release(activity); | |
b1ab9ed8 A |
622 | |
623 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
624 | // @@@ Get real itemClass | |
625 | Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
626 | ||
627 | if (serverName && serverNameLength) | |
628 | { | |
629 | CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength); | |
630 | item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server); | |
631 | // use server name as default label | |
632 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server); | |
633 | } | |
634 | ||
635 | if (accountName && accountNameLength) | |
636 | { | |
637 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
638 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
639 | } | |
640 | ||
641 | if (securityDomain && securityDomainLength) | |
642 | item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
643 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength)); | |
644 | ||
645 | item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port)); | |
646 | item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol); | |
647 | item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType); | |
648 | ||
649 | if (path && pathLength) | |
650 | item->setAttribute(Schema::attributeInfo(kSecPathItemAttr), | |
651 | CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength)); | |
652 | ||
653 | Keychain keychain = nil; | |
654 | try | |
655 | { | |
656 | keychain = Keychain::optional(keychainRef); | |
657 | if ( !keychain->exists() ) | |
658 | { | |
659 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
660 | } | |
661 | } | |
662 | catch(...) | |
663 | { | |
664 | keychain = globals().storageManager.defaultKeychainUI(item); | |
665 | } | |
666 | ||
667 | keychain->add(item); | |
668 | ||
669 | if (itemRef) | |
670 | *itemRef = item->handle(); | |
671 | ||
672 | END_SECAPI | |
673 | } | |
674 | ||
675 | ||
676 | OSStatus | |
677 | SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) | |
678 | ||
679 | { | |
680 | BEGIN_SECAPI | |
866f8763 A |
681 | os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
682 | os_activity_scope(activity); | |
683 | os_release(activity); | |
b1ab9ed8 A |
684 | |
685 | StorageManager::KeychainList keychains; | |
686 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
687 | KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL); | |
688 | ||
689 | if (serverName && serverNameLength) | |
690 | { | |
691 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr), | |
692 | CssmData(const_cast<char *>(serverName), serverNameLength)); | |
693 | } | |
694 | ||
695 | if (securityDomain && securityDomainLength) | |
696 | { | |
697 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr), | |
698 | CssmData (const_cast<char*>(securityDomain), securityDomainLength)); | |
699 | } | |
700 | ||
701 | if (accountName && accountNameLength) | |
702 | { | |
703 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
704 | CssmData (const_cast<char*>(accountName), accountNameLength)); | |
705 | } | |
706 | ||
707 | if (port) | |
708 | { | |
709 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr), | |
710 | UInt32(port)); | |
711 | } | |
712 | ||
713 | if (protocol) | |
714 | { | |
715 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr), | |
716 | protocol); | |
717 | } | |
718 | ||
719 | if (authenticationType) | |
720 | { | |
721 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr), | |
722 | authenticationType); | |
723 | } | |
724 | ||
725 | if (path && pathLength) | |
726 | { | |
727 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path); | |
728 | } | |
729 | ||
730 | Item item; | |
731 | if (!cursor->next(item)) | |
732 | return errSecItemNotFound; | |
733 | ||
734 | // Get its data (only if necessary) | |
735 | if (passwordData || passwordLength) | |
736 | { | |
737 | CssmDataContainer outData; | |
738 | item->getData(outData); | |
fa7225c8 A |
739 | if (passwordLength) { |
740 | *passwordLength=(UInt32)outData.length(); | |
741 | } | |
b1ab9ed8 | 742 | outData.Length=0; |
fa7225c8 A |
743 | if (passwordData) { |
744 | *passwordData=outData.data(); | |
745 | } | |
b1ab9ed8 A |
746 | outData.Data=NULL; |
747 | } | |
748 | ||
749 | if (itemRef) | |
750 | *itemRef=item->handle(); | |
751 | ||
752 | END_SECAPI | |
753 | } | |
754 | ||
755 | ||
756 | OSStatus | |
757 | SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) | |
758 | { | |
759 | BEGIN_SECAPI | |
866f8763 A |
760 | os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
761 | os_activity_scope(activity); | |
762 | os_release(activity); | |
b1ab9ed8 A |
763 | |
764 | KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL); | |
765 | // @@@ Get real itemClass | |
766 | ||
767 | Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false); | |
768 | ||
769 | if (serviceName && serviceNameLength) | |
770 | { | |
771 | CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength); | |
772 | item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); | |
866f8763 | 773 | item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); |
b1ab9ed8 A |
774 | } |
775 | ||
776 | if (accountName && accountNameLength) | |
777 | { | |
778 | CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength); | |
779 | item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); | |
780 | } | |
781 | ||
782 | Keychain keychain = nil; | |
783 | try | |
784 | { | |
785 | keychain = Keychain::optional(keychainRef); | |
786 | if ( !keychain->exists() ) | |
787 | { | |
788 | MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. | |
789 | } | |
790 | } | |
791 | catch(...) | |
792 | { | |
793 | keychain = globals().storageManager.defaultKeychainUI(item); | |
794 | } | |
795 | ||
796 | keychain->add(item); | |
797 | if (itemRef) | |
798 | *itemRef = item->handle(); | |
799 | ||
800 | END_SECAPI | |
801 | } | |
802 | ||
803 | ||
804 | OSStatus | |
805 | SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef) | |
806 | ||
807 | { | |
808 | BEGIN_SECAPI | |
866f8763 A |
809 | os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
810 | os_activity_scope(activity); | |
811 | os_release(activity); | |
b1ab9ed8 A |
812 | |
813 | StorageManager::KeychainList keychains; | |
814 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); | |
815 | KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); | |
816 | ||
817 | if (serviceName && serviceNameLength) | |
818 | { | |
819 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), | |
820 | CssmData(const_cast<char *>(serviceName), serviceNameLength)); | |
821 | } | |
822 | ||
823 | if (accountName && accountNameLength) | |
824 | { | |
825 | cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr), | |
826 | CssmData(const_cast<char *>(accountName), accountNameLength)); | |
827 | } | |
828 | ||
829 | Item item; | |
830 | if (!cursor->next(item)) | |
831 | return errSecItemNotFound; | |
832 | ||
833 | // Get its data (only if necessary) | |
834 | if (passwordData || passwordLength) | |
835 | { | |
836 | CssmDataContainer outData; | |
837 | item->getData(outData); | |
fa7225c8 A |
838 | if (passwordLength) { |
839 | *passwordLength=(UInt32)outData.length(); | |
840 | } | |
b1ab9ed8 | 841 | outData.Length=0; |
fa7225c8 A |
842 | if (passwordData) { |
843 | *passwordData=outData.data(); | |
844 | } | |
b1ab9ed8 A |
845 | outData.Data=NULL; |
846 | } | |
847 | ||
848 | if (itemRef) | |
849 | *itemRef=item->handle(); | |
850 | ||
851 | END_SECAPI | |
852 | } | |
853 | ||
854 | ||
855 | OSStatus | |
856 | SecKeychainSetUserInteractionAllowed(Boolean state) | |
857 | { | |
858 | BEGIN_SECAPI | |
859 | ||
860 | globals().setUserInteractionAllowed(state); | |
861 | ||
862 | END_SECAPI | |
863 | } | |
864 | ||
865 | ||
866 | OSStatus | |
867 | SecKeychainGetUserInteractionAllowed(Boolean *state) | |
868 | { | |
869 | BEGIN_SECAPI | |
870 | ||
871 | Required(state)=globals().getUserInteractionAllowed(); | |
872 | ||
873 | END_SECAPI | |
874 | } | |
875 | ||
876 | ||
877 | OSStatus | |
878 | SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle) | |
879 | { | |
880 | BEGIN_SECAPI | |
866f8763 A |
881 | os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
882 | os_activity_scope(activity); | |
883 | os_release(activity); | |
b1ab9ed8 A |
884 | |
885 | RequiredParam(dldbHandle); | |
886 | ||
887 | Keychain keychain = Keychain::optional(keychainRef); | |
888 | *dldbHandle = keychain->database()->handle(); | |
889 | ||
890 | END_SECAPI | |
891 | } | |
892 | ||
866f8763 A |
893 | static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex; |
894 | static std::set<CssmClient::CSP> gSecReturnedKeychainCSPs; | |
b1ab9ed8 A |
895 | |
896 | OSStatus | |
897 | SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle) | |
898 | { | |
899 | BEGIN_SECAPI | |
900 | ||
901 | RequiredParam(cspHandle); | |
902 | ||
903 | Keychain keychain = Keychain::optional(keychainRef); | |
866f8763 A |
904 | |
905 | // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). | |
906 | // Keep a global pointer to it to force the CSP to stay live forever. | |
907 | CssmClient::CSP returnedKeychainCSP = keychain->csp(); | |
908 | { | |
909 | StLock<Mutex> _(gSecReturnedKeyCSPsMutex()); | |
910 | gSecReturnedKeychainCSPs.insert(returnedKeychainCSP); | |
911 | } | |
912 | *cspHandle = returnedKeychainCSP->handle(); | |
b1ab9ed8 A |
913 | |
914 | END_SECAPI | |
915 | } | |
916 | ||
917 | ||
918 | OSStatus | |
919 | SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef) | |
920 | { | |
921 | BEGIN_SECAPI | |
922 | ||
427c49bc | 923 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
924 | |
925 | END_SECAPI | |
926 | } | |
927 | ||
928 | ||
929 | OSStatus | |
930 | SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef) | |
931 | { | |
932 | BEGIN_SECAPI | |
933 | ||
427c49bc | 934 | MacOSError::throwMe(errSecUnimplemented);//%%%for now |
b1ab9ed8 A |
935 | |
936 | END_SECAPI | |
937 | } | |
938 | ||
939 | ||
940 | #pragma mark ---- Private API ---- | |
941 | ||
942 | ||
943 | OSStatus | |
944 | SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword) | |
945 | { | |
946 | BEGIN_SECAPI | |
866f8763 A |
947 | os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
948 | os_activity_scope(activity); | |
949 | os_release(activity); | |
b1ab9ed8 A |
950 | |
951 | Keychain keychain = Keychain::optional(keychainRef); | |
952 | keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword); | |
953 | ||
954 | END_SECAPI | |
955 | } | |
956 | ||
957 | ||
958 | OSStatus | |
959 | SecKeychainCopyLogin(SecKeychainRef *keychainRef) | |
960 | { | |
961 | BEGIN_SECAPI | |
866f8763 A |
962 | os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
963 | os_activity_scope(activity); | |
964 | os_release(activity); | |
b1ab9ed8 A |
965 | |
966 | RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle(); | |
967 | ||
968 | END_SECAPI | |
969 | } | |
970 | ||
971 | ||
972 | OSStatus | |
973 | SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password) | |
974 | { | |
975 | BEGIN_SECAPI | |
866f8763 A |
976 | os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
977 | os_activity_scope(activity); | |
978 | os_release(activity); | |
b1ab9ed8 A |
979 | |
980 | try | |
981 | { | |
427c49bc | 982 | if (password) { |
fa7225c8 | 983 | globals().storageManager.login(nameLength, name, passwordLength, password, false); |
427c49bc A |
984 | } else { |
985 | globals().storageManager.stashLogin(); | |
986 | } | |
b1ab9ed8 A |
987 | } |
988 | catch (CommonError &e) | |
989 | { | |
b04fe171 | 990 | secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not"); |
b1ab9ed8 A |
991 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) |
992 | { | |
993 | return errSecAuthFailed; | |
994 | } | |
995 | else | |
996 | { | |
997 | return e.osStatus(); | |
998 | } | |
999 | } | |
b04fe171 A |
1000 | |
1001 | catch (...) { | |
1002 | __secapiresult=errSecInternalComponent; | |
1003 | } | |
1004 | secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not"); | |
1005 | ||
b1ab9ed8 A |
1006 | END_SECAPI |
1007 | } | |
1008 | ||
427c49bc A |
1009 | OSStatus SecKeychainStash() |
1010 | { | |
1011 | BEGIN_SECAPI | |
866f8763 A |
1012 | os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1013 | os_activity_scope(activity); | |
1014 | os_release(activity); | |
427c49bc A |
1015 | |
1016 | try | |
1017 | { | |
1018 | globals().storageManager.stashKeychain(); | |
1019 | } | |
1020 | catch (CommonError &e) | |
1021 | { | |
1022 | if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED) | |
1023 | { | |
1024 | return errSecAuthFailed; | |
1025 | } | |
1026 | else | |
1027 | { | |
1028 | return e.osStatus(); | |
1029 | } | |
1030 | } | |
1031 | ||
1032 | END_SECAPI | |
1033 | } | |
b1ab9ed8 A |
1034 | |
1035 | OSStatus | |
1036 | SecKeychainLogout() | |
1037 | { | |
1038 | BEGIN_SECAPI | |
866f8763 A |
1039 | os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1040 | os_activity_scope(activity); | |
1041 | os_release(activity); | |
b1ab9ed8 A |
1042 | |
1043 | globals().storageManager.logout(); | |
1044 | ||
1045 | END_SECAPI | |
1046 | } | |
1047 | ||
1048 | /* (non-exported C utility routine) 'Makes' a keychain based on a full path | |
1049 | */ | |
1050 | static Keychain make(const char *name) | |
1051 | { | |
1052 | return globals().storageManager.make(name); | |
1053 | } | |
1054 | ||
1055 | /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs. | |
1056 | Note this version doesn't take an accessRef or password. | |
1057 | The "KC" create API takes a keychainRef... | |
1058 | */ | |
1059 | OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef) | |
1060 | { | |
1061 | BEGIN_SECAPI | |
1062 | RequiredParam(fullPathName); | |
1063 | RequiredParam(keychainRef)=make(fullPathName)->handle(); | |
1064 | END_SECAPI | |
1065 | } | |
1066 | ||
1067 | ||
1068 | /* Determines if the keychainRef is a valid keychain. | |
1069 | */ | |
1070 | OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid) | |
1071 | { | |
1072 | BEGIN_SECAPI | |
1073 | *isValid = false; | |
1074 | if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL) | |
1075 | *isValid = true; | |
1076 | END_SECAPI | |
1077 | } | |
1078 | ||
1079 | /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs. | |
1080 | */ | |
1081 | OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef) | |
1082 | { | |
1083 | BEGIN_SECAPI | |
866f8763 A |
1084 | os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1085 | os_activity_scope(activity); | |
1086 | os_release(activity); | |
b1ab9ed8 A |
1087 | StorageManager::KeychainList singleton; |
1088 | singleton.push_back(KeychainImpl::required(keychainRef)); | |
1089 | globals().storageManager.remove(singleton); | |
1090 | END_SECAPI | |
1091 | } | |
1092 | ||
1093 | /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs. | |
1094 | */ | |
1095 | OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword) | |
1096 | { | |
1097 | BEGIN_SECAPI | |
866f8763 A |
1098 | os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1099 | os_activity_scope(activity); | |
1100 | os_release(activity); | |
b1ab9ed8 A |
1101 | RequiredParam(inPassword); |
1102 | KeychainImpl::required(keychainRef)->create(passwordLength, inPassword); | |
1103 | END_SECAPI | |
1104 | } | |
1105 | ||
1106 | /* Modify a keychain so that it can be synchronized. | |
1107 | */ | |
1108 | OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData) | |
1109 | { | |
1110 | BEGIN_SECAPI | |
866f8763 A |
1111 | os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1112 | os_activity_scope(activity); | |
1113 | os_release(activity); | |
b1ab9ed8 A |
1114 | |
1115 | // do error checking for required parameters | |
1116 | RequiredParam(dbBlobArray); | |
1117 | RequiredParam(extraData); | |
1118 | ||
1119 | const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)), | |
1120 | CFDataGetLength(extraData)); | |
1121 | ||
1122 | CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray); | |
1123 | size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle)); | |
1124 | void *dataPtr = (void*)malloc(space); | |
1125 | if ( !dataPtr ) | |
427c49bc | 1126 | return errSecAllocate; |
b1ab9ed8 A |
1127 | // |
1128 | // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with. | |
1129 | // | |
1130 | uint8* sizePtr = (uint8*)dataPtr; | |
1131 | *sizePtr = dbBlobArrayCount; | |
1132 | SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
1133 | CFIndex index; | |
1134 | SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard()); | |
1135 | for (index=0; index < dbBlobArrayCount; index++) | |
1136 | { | |
1137 | CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index); | |
1138 | const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData)); | |
1139 | // | |
1140 | // Since it's to a DbHandle that's not on our disk (it came from user's iDisk), | |
1141 | // it's OK to use the mIdentifier and access credentials of the keychain we're recoding. | |
1142 | // | |
1143 | Keychain kc = KeychainImpl::required(keychainRef); | |
1144 | *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */ | |
1145 | ||
1146 | currDbHandle++; | |
1147 | } | |
1148 | // do the work | |
1149 | Keychain keychain = Keychain::optional(keychainRef); | |
1150 | const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space); | |
1151 | Boolean recodeFailed = false; | |
1152 | ||
427c49bc | 1153 | int errCode=errSecSuccess; |
b1ab9ed8 A |
1154 | |
1155 | try | |
1156 | { | |
1157 | keychain->recode(data, extraCssmData); | |
1158 | } | |
1159 | catch (MacOSError e) | |
1160 | { | |
1161 | errCode = e.osStatus(); | |
1162 | recodeFailed = true; | |
1163 | } | |
1164 | catch (UnixError ue) | |
1165 | { | |
1166 | errCode = ue.unixError(); | |
1167 | } | |
1168 | ||
1169 | currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1); | |
1170 | for (index=0; index < dbBlobArrayCount; index++) | |
1171 | { | |
1172 | ss.releaseDb(*currDbHandle); | |
1173 | currDbHandle++; | |
1174 | } | |
1175 | if ( dataPtr ) | |
1176 | free(dataPtr); | |
1177 | ||
1178 | if ( recodeFailed ) | |
1179 | { | |
1180 | return errCode; | |
1181 | } | |
1182 | ||
1183 | END_SECAPI | |
1184 | } | |
1185 | ||
1186 | OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) | |
1187 | { | |
1188 | BEGIN_SECAPI | |
866f8763 A |
1189 | os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1190 | os_activity_scope(activity); | |
1191 | os_release(activity); | |
b1ab9ed8 A |
1192 | |
1193 | // do error checking for required parameters | |
1194 | RequiredParam(keychainSignature); | |
1195 | ||
1196 | // make a keychain object "wrapper" for this keychain ref | |
1197 | Keychain keychain = Keychain::optional(keychainRef); | |
1198 | CssmAutoData data(keychain->database()->allocator()); | |
1199 | keychain->copyBlob(data.get()); | |
1200 | ||
1201 | // get the cssmDBBlob | |
1202 | const SecurityServer::DbBlob *cssmDBBlob = | |
1203 | data.get().interpretedAs<const SecurityServer::DbBlob>(); | |
1204 | ||
1205 | // convert from CDSA standards to CF standards | |
1206 | *keychainSignature = CFDataCreate(kCFAllocatorDefault, | |
1207 | cssmDBBlob->randomSignature.bytes, | |
1208 | sizeof(SecurityServer::DbBlob::Signature)); | |
1209 | ||
1210 | END_SECAPI | |
1211 | } | |
1212 | ||
1213 | OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob) | |
1214 | { | |
1215 | BEGIN_SECAPI | |
866f8763 A |
1216 | os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1217 | os_activity_scope(activity); | |
1218 | os_release(activity); | |
b1ab9ed8 A |
1219 | |
1220 | // do error checking for required parameters | |
1221 | RequiredParam(dbBlob); | |
1222 | ||
1223 | // make a keychain object "wrapper" for this keychain ref | |
1224 | Keychain keychain = Keychain::optional(keychainRef); | |
1225 | CssmAutoData data(keychain->database()->allocator()); | |
1226 | keychain->copyBlob(data.get()); | |
1227 | ||
1228 | // convert from CDSA standards to CF standards | |
1229 | *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length()); | |
1230 | ||
1231 | END_SECAPI | |
1232 | } | |
1233 | ||
1234 | // make a new keychain with pre-existing secrets | |
1235 | OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef) | |
1236 | { | |
1237 | BEGIN_SECAPI | |
866f8763 A |
1238 | os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1239 | os_activity_scope(activity); | |
1240 | os_release(activity); | |
b1ab9ed8 A |
1241 | |
1242 | KCThrowParamErrIf_(!fullPathName); | |
1243 | KCThrowParamErrIf_(!dbBlob); | |
1244 | ||
1245 | Keychain keychain = globals().storageManager.make(fullPathName); | |
1246 | ||
1247 | CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob)); | |
1248 | ||
1249 | // @@@ the call to StorageManager::make above leaves keychain the the cache. | |
1250 | // If the create below fails we should probably remove it. | |
1251 | keychain->createWithBlob(blob); | |
1252 | ||
1253 | RequiredParam(kcRef)=keychain->handle(); | |
1254 | ||
1255 | // | |
1256 | ||
1257 | END_SECAPI | |
1258 | } | |
1259 | ||
1260 | // add a non-file based DB to the keychain list | |
1261 | OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1262 | const CSSM_GUID *guid, uint32 subServiceType) | |
1263 | { | |
1264 | BEGIN_SECAPI | |
866f8763 A |
1265 | os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1266 | os_activity_scope(activity); | |
1267 | os_release(activity); | |
b1ab9ed8 A |
1268 | |
1269 | RequiredParam(dbName); | |
1270 | StorageManager &smr = globals().storageManager; | |
1271 | smr.addToDomainList(domain, dbName, *guid, subServiceType); | |
1272 | ||
1273 | END_SECAPI | |
1274 | } | |
1275 | ||
1276 | // determine if a non-file based DB is in the keychain list | |
1277 | OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1278 | const CSSM_GUID *guid, uint32 subServiceType) | |
1279 | { | |
1280 | BEGIN_SECAPI | |
1281 | RequiredParam(dbName); | |
1282 | StorageManager &smr = globals().storageManager; | |
1283 | smr.isInDomainList(domain, dbName, *guid, subServiceType); | |
1284 | END_SECAPI | |
1285 | } | |
1286 | ||
1287 | // remove a non-file based DB from the keychain list | |
1288 | OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName, | |
1289 | const CSSM_GUID *guid, uint32 subServiceType) | |
1290 | { | |
1291 | BEGIN_SECAPI | |
866f8763 A |
1292 | os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1293 | os_activity_scope(activity); | |
1294 | os_release(activity); | |
b1ab9ed8 A |
1295 | RequiredParam(dbName); |
1296 | StorageManager &smr = globals().storageManager; | |
1297 | smr.removeFromDomainList(domain, dbName, *guid, subServiceType); | |
1298 | END_SECAPI | |
1299 | } | |
1300 | ||
1301 | ||
1302 | // set server mode -- must be called before any other Sec* etc. call | |
1303 | void SecKeychainSetServerMode() | |
1304 | { | |
1305 | gServerMode = true; | |
1306 | } | |
1307 | ||
1308 | ||
1309 | ||
1310 | OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback) | |
1311 | { | |
1312 | BEGIN_SECAPI | |
866f8763 A |
1313 | os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1314 | os_activity_scope(activity); | |
1315 | os_release(activity); | |
b1ab9ed8 A |
1316 | RequiredParam(kcRef); |
1317 | Keychain keychain = Keychain::optional(kcRef); | |
1318 | keychain->setBatchMode(mode, rollback); | |
1319 | END_SECAPI | |
1320 | } | |
1321 | ||
1322 | ||
1323 | ||
1324 | OSStatus SecKeychainCleanupHandles() | |
1325 | { | |
1326 | BEGIN_SECAPI | |
1327 | END_SECAPI // which causes the handle cache cleanup routine to run | |
1328 | } | |
1329 | ||
427c49bc A |
1330 | OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries) |
1331 | { | |
1332 | BEGIN_SECAPI | |
866f8763 A |
1333 | os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1334 | os_activity_scope(activity); | |
1335 | os_release(activity); | |
427c49bc A |
1336 | SecurityServer::ClientSession().verifyKeyStorePassphrase(retries); |
1337 | END_SECAPI | |
1338 | } | |
1339 | ||
1340 | OSStatus SecKeychainChangeKeyStorePassphrase() | |
1341 | { | |
1342 | BEGIN_SECAPI | |
866f8763 A |
1343 | os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1344 | os_activity_scope(activity); | |
1345 | os_release(activity); | |
427c49bc A |
1346 | SecurityServer::ClientSession().changeKeyStorePassphrase(); |
1347 | END_SECAPI | |
d8f41ccd A |
1348 | } |
1349 | ||
1350 | static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password) | |
1351 | { | |
1352 | BEGIN_SECAPI | |
866f8763 A |
1353 | os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1354 | os_activity_scope(activity); | |
1355 | os_release(activity); | |
d8f41ccd A |
1356 | |
1357 | // make a keychain object "wrapper" for this keychain ref | |
1358 | Keychain keychain = Keychain::optional(userKeychainRef); | |
1359 | ||
1360 | CssmClient::Db db = keychain->database(); | |
1361 | ||
1362 | // create the keychain, using appropriate credentials | |
1363 | Allocator &alloc = db->allocator(); | |
1364 | AutoCredentials cred(alloc); // will leak, but we're quitting soon :-) | |
1365 | ||
1366 | char passphrase[1024]; | |
1367 | CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8); | |
1368 | ||
1369 | // use this passphrase | |
1370 | cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, | |
1371 | new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD), | |
1372 | new(alloc) ListElement(StringData(passphrase))); | |
fa7225c8 A |
1373 | db->authenticate(CSSM_DB_ACCESS_READ, &cred); |
1374 | ||
1375 | CSSM_DL_DB_HANDLE dlDb = db->handle(); | |
d8f41ccd A |
1376 | CssmData dlDbData = CssmData::wrap(dlDb); |
1377 | CssmKey refKey; | |
1378 | KeySpec spec(CSSM_KEYUSE_ANY, | |
1379 | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE); | |
1380 | ||
1381 | DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64); | |
1382 | derive(&dlDbData, spec, refKey); | |
1383 | ||
1384 | // now extract the raw keybits | |
1385 | CssmKey rawKey; | |
1386 | WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE); | |
1387 | wrap(refKey, rawKey); | |
1388 | ||
1389 | *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length()); | |
1390 | ||
1391 | END_SECAPI | |
1392 | } | |
1393 | ||
fa7225c8 A |
1394 | static const char *kAutologinPWFilePath = "/etc/kcpassword"; |
1395 | static const uint32_t kObfuscatedPasswordSizeMultiple = 12; | |
1396 | static const uint32_t buffer_size = 512; | |
1397 | static const uint8_t kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f}; | |
1398 | ||
1399 | static void obfuscate(void *buffer, size_t bufferLength) | |
1400 | { | |
1401 | uint8_t *pBuf = (uint8_t *) buffer; | |
1402 | const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey ); | |
1403 | ||
1404 | while (bufferLength--) { | |
1405 | *pBuf = *pBuf ^ *pKey; | |
1406 | ++pKey; | |
1407 | ++pBuf; | |
1408 | if (pKey == eKey) | |
1409 | pKey = kObfuscationKey; | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | static bool _SASetAutologinPW(CFStringRef inAutologinPW) | |
1414 | { | |
1415 | bool result = false; | |
1416 | struct stat sb; | |
1417 | ||
1418 | // Delete the kcpassword file if it exists already | |
1419 | if (stat(kAutologinPWFilePath, &sb) == 0) | |
1420 | unlink( kAutologinPWFilePath ); | |
1421 | ||
1422 | // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off. | |
1423 | if (inAutologinPW != NULL) { | |
1424 | char buffer[buffer_size]; | |
1425 | const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8); | |
1426 | if (pwAsUTF8String == NULL) { | |
1427 | if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer; | |
1428 | } | |
1429 | ||
1430 | if (pwAsUTF8String != NULL) { | |
1431 | size_t pwLength = strlen(pwAsUTF8String) + 1; | |
1432 | size_t obfuscatedPWLength; | |
1433 | char *obfuscatedPWBuffer; | |
1434 | ||
1435 | // The size of the obfuscated password should be the smallest multiple of | |
1436 | // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength. | |
1437 | obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple; | |
1438 | obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength); | |
1439 | ||
1440 | // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer | |
1441 | bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength); | |
1442 | ||
1443 | // Pad remainder of obfuscatedPWBuffer with random bytes | |
1444 | { | |
1445 | char *p; | |
1446 | char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength; | |
1447 | ||
1448 | for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p) | |
1449 | *p = random() & 0x000000FF; | |
1450 | } | |
1451 | ||
1452 | obfuscate(obfuscatedPWBuffer, obfuscatedPWLength); | |
1453 | ||
1454 | int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR); | |
1455 | if (pwFile >= 0) { | |
1456 | size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength); | |
1457 | if (wrote == obfuscatedPWLength) | |
1458 | result = true; | |
1459 | close(pwFile); | |
1460 | } | |
1461 | ||
1462 | chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR); | |
1463 | free(obfuscatedPWBuffer); | |
1464 | } | |
1465 | } | |
1466 | ||
1467 | return result; | |
1468 | } | |
d8f41ccd A |
1469 | |
1470 | OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) { | |
1471 | SecTrustedApplicationRef itemPath; | |
1472 | SecAccessRef ourAccessRef = NULL; | |
1473 | ||
1474 | OSStatus result = errSecParam; | |
1475 | ||
fa7225c8 A |
1476 | if (userKeychainRef == NULL) { |
1477 | // We don't have a specific user keychain, fall back | |
1478 | if (_SASetAutologinPW(password)) | |
1479 | result = errSecSuccess; | |
1480 | ||
1481 | return result; | |
1482 | } | |
1483 | ||
d8f41ccd A |
1484 | CFDataRef masterKey = NULL; |
1485 | result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password); | |
1486 | if (errSecSuccess != result) { | |
1487 | return result; | |
1488 | } | |
1489 | ||
1490 | result = SecKeychainStash(); | |
1491 | if (errSecSuccess != result) { | |
fa7225c8 | 1492 | if (masterKey != NULL) CFRelease(masterKey); |
d8f41ccd A |
1493 | return result; |
1494 | } | |
1495 | ||
1496 | CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
fa7225c8 | 1497 | if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath) |
d8f41ccd A |
1498 | CFArrayAppendValue(trustedApplications, itemPath); |
1499 | ||
fa7225c8 | 1500 | if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) { |
d8f41ccd | 1501 | if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) { |
fa7225c8 | 1502 | SecKeychainRef internalSystemKeychainRef = NULL; |
d8f41ccd | 1503 | if (NULL == systemKeychainRef) { |
fa7225c8 A |
1504 | SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef); |
1505 | } else { | |
1506 | internalSystemKeychainRef = systemKeychainRef; | |
d8f41ccd A |
1507 | } |
1508 | ||
1509 | const void *queryKeys[] = { kSecClass, | |
1510 | kSecAttrService, | |
1511 | kSecAttrAccount, | |
1512 | kSecUseKeychain, | |
1513 | }; | |
1514 | const void *queryValues[] = { kSecClassGenericPassword, | |
1515 | CFSTR("com.apple.loginwindow.auto-login"), | |
1516 | username, | |
fa7225c8 | 1517 | internalSystemKeychainRef, |
d8f41ccd A |
1518 | }; |
1519 | ||
1520 | const void *updateKeys[] = { kSecAttrAccess, | |
1521 | kSecValueData, | |
1522 | }; | |
1523 | const void *updateValues[] = { ourAccessRef, | |
1524 | masterKey, | |
1525 | }; | |
1526 | ||
1527 | CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1528 | CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1529 | ||
1530 | result = SecItemUpdate(query, update); | |
1531 | ||
1532 | if (errSecSuccess != result) { | |
1533 | const void *addKeys[] = { kSecClass, | |
1534 | kSecAttrService, | |
1535 | kSecAttrAccount, | |
1536 | kSecUseKeychain, | |
1537 | kSecAttrAccess, | |
1538 | kSecValueData, | |
1539 | }; | |
1540 | const void *addValues[] = { kSecClassGenericPassword, | |
1541 | CFSTR("com.apple.loginwindow.auto-login"), | |
1542 | username, | |
fa7225c8 | 1543 | internalSystemKeychainRef, |
d8f41ccd A |
1544 | ourAccessRef, |
1545 | masterKey, | |
1546 | }; | |
1547 | ||
1548 | CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
1549 | result = SecItemAdd(add, NULL); | |
1550 | if (NULL != add) CFRelease(add); | |
1551 | } | |
1552 | ||
1553 | if (NULL != query) CFRelease(query); | |
1554 | if (NULL != update) CFRelease(update); | |
fa7225c8 A |
1555 | |
1556 | // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one | |
1557 | if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef); | |
d8f41ccd A |
1558 | } |
1559 | } | |
1560 | ||
1561 | if (NULL != masterKey) CFRelease(masterKey); | |
1562 | if (NULL != trustedApplications) CFRelease(trustedApplications); | |
1563 | if (NULL != ourAccessRef) CFRelease(ourAccessRef); | |
d8f41ccd A |
1564 | |
1565 | return result; | |
1566 | } | |
fa7225c8 A |
1567 | |
1568 | OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts) | |
1569 | { | |
1570 | BEGIN_SECAPI | |
866f8763 A |
1571 | os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT); |
1572 | os_activity_scope(activity); | |
1573 | os_release(activity); | |
fa7225c8 A |
1574 | |
1575 | if(attempts) { | |
1576 | SecurityServer::ClientSession().getUserPromptAttempts(*attempts); | |
1577 | } | |
1578 | ||
1579 | END_SECAPI | |
1580 | } | |
1581 | ||
1582 | OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash, | |
1583 | SecKeychainRef userKeychain, CFStringRef password) | |
1584 | { | |
1585 | CFRef<CFStringRef> pwd; | |
1586 | OSStatus result; | |
1587 | ||
1588 | if (password == NULL || CFStringGetLength(password) == 0) { | |
1589 | AuthorizationRef authorizationRef; | |
1590 | result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef); | |
1591 | if (result != errAuthorizationSuccess) { | |
b04fe171 | 1592 | secnotice("SecKeychain", "failed to create authorization"); |
fa7225c8 A |
1593 | return result; |
1594 | } | |
1595 | ||
1596 | AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0}; | |
1597 | AuthorizationRights myRights = {1, &myItems}; | |
1598 | AuthorizationRights *authorizedRights = NULL; | |
1599 | ||
1600 | char pathName[PATH_MAX]; | |
1601 | UInt32 pathLength = PATH_MAX; | |
1602 | result = SecKeychainGetPath(userKeychain, &pathLength, pathName); | |
1603 | if (result != errSecSuccess) { | |
b04fe171 | 1604 | secnotice("SecKeychain", "failed to create authorization"); |
fa7225c8 A |
1605 | return result; |
1606 | } | |
1607 | ||
1608 | Boolean checkPwd = TRUE; | |
b04fe171 | 1609 | Boolean ignoreSession = TRUE; |
fa7225c8 A |
1610 | AuthorizationItem envItems[] = { |
1611 | {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0}, | |
b04fe171 A |
1612 | {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd}, |
1613 | {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession} | |
fa7225c8 A |
1614 | }; |
1615 | ||
b04fe171 | 1616 | AuthorizationEnvironment environment = {3, envItems}; |
fa7225c8 A |
1617 | AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights; |
1618 | result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, &authorizedRights); | |
1619 | if (authorizedRights) | |
1620 | AuthorizationFreeItemSet(authorizedRights); | |
1621 | ||
1622 | if (result == errAuthorizationSuccess) { | |
1623 | AuthorizationItemSet *items; | |
1624 | result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items); | |
1625 | if (result == errAuthorizationSuccess) { | |
1626 | if (items->count > 0) { | |
1627 | pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8); | |
1628 | } | |
1629 | AuthorizationFreeItemSet(items); | |
1630 | } | |
1631 | } | |
1632 | AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults); | |
1633 | if (result != errAuthorizationSuccess) { | |
b04fe171 | 1634 | secnotice("SecKeychain", "did not get authorization to pair the card"); |
fa7225c8 A |
1635 | return result; |
1636 | } | |
1637 | } else { | |
1638 | pwd.take(password); | |
1639 | } | |
1640 | ||
1641 | if (!pwd) { | |
b04fe171 | 1642 | secnotice("SecKeychain", "did not get kcpass"); |
fa7225c8 A |
1643 | return errSecInternalComponent; |
1644 | } | |
1645 | ||
1646 | CFRef<CFDataRef> masterKey; | |
1647 | result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd); | |
1648 | if (result != errSecSuccess) { | |
1649 | secnotice("SecKeychain", "Failed to get master key: %d", (int) result); | |
1650 | return result; | |
1651 | } | |
1652 | ||
1653 | CFRef<CFDataRef> scBlob; | |
1654 | result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take()); | |
1655 | if (result != errSecSuccess) { | |
1656 | secnotice("SecKeychain", "Failed to get stash: %d", (int) result); | |
1657 | return result; | |
1658 | } | |
1659 | ||
1660 | result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob); | |
1661 | if (result != errSecSuccess) { | |
1662 | secnotice("SecKeychain", "Failed to create login data: %d", (int) result); | |
1663 | return result; | |
1664 | } | |
1665 | ||
1666 | secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result); | |
1667 | return result; | |
1668 | } | |
1669 | ||
1670 | OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash) | |
1671 | { | |
1672 | OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash); | |
1673 | if (result != errSecSuccess) { | |
1674 | secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result); | |
1675 | } | |
1676 | return result; | |
1677 | } | |
1678 |