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