]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecKeychain.cpp
Security-57740.51.3.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 secnotice("KCLogin", "SecKeychainLogin failed: %d, password was%s supplied", (int)e.osStatus(), password?"":" not");
896 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
897 {
898 return errSecAuthFailed;
899 }
900 else
901 {
902 return e.osStatus();
903 }
904 }
905
906 catch (...) {
907 __secapiresult=errSecInternalComponent;
908 }
909 secnotice("KCLogin", "SecKeychainLogin result: %d, password was%s supplied", (int)__secapiresult, password?"":" not");
910
911 END_SECAPI
912 }
913
914 OSStatus SecKeychainStash()
915 {
916 BEGIN_SECAPI
917
918 try
919 {
920 globals().storageManager.stashKeychain();
921 }
922 catch (CommonError &e)
923 {
924 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
925 {
926 return errSecAuthFailed;
927 }
928 else
929 {
930 return e.osStatus();
931 }
932 }
933
934 END_SECAPI
935 }
936
937 OSStatus
938 SecKeychainLogout()
939 {
940 BEGIN_SECAPI
941
942 globals().storageManager.logout();
943
944 END_SECAPI
945 }
946
947 /* (non-exported C utility routine) 'Makes' a keychain based on a full path
948 */
949 static Keychain make(const char *name)
950 {
951 return globals().storageManager.make(name);
952 }
953
954 /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs.
955 Note this version doesn't take an accessRef or password.
956 The "KC" create API takes a keychainRef...
957 */
958 OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef)
959 {
960 BEGIN_SECAPI
961 RequiredParam(fullPathName);
962 RequiredParam(keychainRef)=make(fullPathName)->handle();
963 END_SECAPI
964 }
965
966
967 /* Determines if the keychainRef is a valid keychain.
968 */
969 OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
970 {
971 BEGIN_SECAPI
972 *isValid = false;
973 if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL)
974 *isValid = true;
975 END_SECAPI
976 }
977
978 /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs.
979 */
980 OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
981 {
982 BEGIN_SECAPI
983 StorageManager::KeychainList singleton;
984 singleton.push_back(KeychainImpl::required(keychainRef));
985 globals().storageManager.remove(singleton);
986 END_SECAPI
987 }
988
989 /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs.
990 */
991 OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
992 {
993 BEGIN_SECAPI
994 RequiredParam(inPassword);
995 KeychainImpl::required(keychainRef)->create(passwordLength, inPassword);
996 END_SECAPI
997 }
998
999 /* Modify a keychain so that it can be synchronized.
1000 */
1001 OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
1002 {
1003 BEGIN_SECAPI
1004
1005 // do error checking for required parameters
1006 RequiredParam(dbBlobArray);
1007 RequiredParam(extraData);
1008
1009 const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)),
1010 CFDataGetLength(extraData));
1011
1012 CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray);
1013 size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle));
1014 void *dataPtr = (void*)malloc(space);
1015 if ( !dataPtr )
1016 return errSecAllocate;
1017 //
1018 // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with.
1019 //
1020 uint8* sizePtr = (uint8*)dataPtr;
1021 *sizePtr = dbBlobArrayCount;
1022 SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1023 CFIndex index;
1024 SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
1025 for (index=0; index < dbBlobArrayCount; index++)
1026 {
1027 CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index);
1028 const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData));
1029 //
1030 // Since it's to a DbHandle that's not on our disk (it came from user's iDisk),
1031 // it's OK to use the mIdentifier and access credentials of the keychain we're recoding.
1032 //
1033 Keychain kc = KeychainImpl::required(keychainRef);
1034 *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */
1035
1036 currDbHandle++;
1037 }
1038 // do the work
1039 Keychain keychain = Keychain::optional(keychainRef);
1040 const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space);
1041 Boolean recodeFailed = false;
1042
1043 int errCode=errSecSuccess;
1044
1045 try
1046 {
1047 keychain->recode(data, extraCssmData);
1048 }
1049 catch (MacOSError e)
1050 {
1051 errCode = e.osStatus();
1052 recodeFailed = true;
1053 }
1054 catch (UnixError ue)
1055 {
1056 errCode = ue.unixError();
1057 }
1058
1059 currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1060 for (index=0; index < dbBlobArrayCount; index++)
1061 {
1062 ss.releaseDb(*currDbHandle);
1063 currDbHandle++;
1064 }
1065 if ( dataPtr )
1066 free(dataPtr);
1067
1068 if ( recodeFailed )
1069 {
1070 return errCode;
1071 }
1072
1073 END_SECAPI
1074 }
1075
1076 OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature)
1077 {
1078 BEGIN_SECAPI
1079
1080 // do error checking for required parameters
1081 RequiredParam(keychainSignature);
1082
1083 // make a keychain object "wrapper" for this keychain ref
1084 Keychain keychain = Keychain::optional(keychainRef);
1085 CssmAutoData data(keychain->database()->allocator());
1086 keychain->copyBlob(data.get());
1087
1088 // get the cssmDBBlob
1089 const SecurityServer::DbBlob *cssmDBBlob =
1090 data.get().interpretedAs<const SecurityServer::DbBlob>();
1091
1092 // convert from CDSA standards to CF standards
1093 *keychainSignature = CFDataCreate(kCFAllocatorDefault,
1094 cssmDBBlob->randomSignature.bytes,
1095 sizeof(SecurityServer::DbBlob::Signature));
1096
1097 END_SECAPI
1098 }
1099
1100 OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
1101 {
1102 BEGIN_SECAPI
1103
1104 // do error checking for required parameters
1105 RequiredParam(dbBlob);
1106
1107 // make a keychain object "wrapper" for this keychain ref
1108 Keychain keychain = Keychain::optional(keychainRef);
1109 CssmAutoData data(keychain->database()->allocator());
1110 keychain->copyBlob(data.get());
1111
1112 // convert from CDSA standards to CF standards
1113 *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length());
1114
1115 END_SECAPI
1116 }
1117
1118 // make a new keychain with pre-existing secrets
1119 OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
1120 {
1121 BEGIN_SECAPI
1122
1123 KCThrowParamErrIf_(!fullPathName);
1124 KCThrowParamErrIf_(!dbBlob);
1125
1126 Keychain keychain = globals().storageManager.make(fullPathName);
1127
1128 CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob));
1129
1130 // @@@ the call to StorageManager::make above leaves keychain the the cache.
1131 // If the create below fails we should probably remove it.
1132 keychain->createWithBlob(blob);
1133
1134 RequiredParam(kcRef)=keychain->handle();
1135
1136 //
1137
1138 END_SECAPI
1139 }
1140
1141 // add a non-file based DB to the keychain list
1142 OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName,
1143 const CSSM_GUID *guid, uint32 subServiceType)
1144 {
1145 BEGIN_SECAPI
1146
1147 RequiredParam(dbName);
1148 StorageManager &smr = globals().storageManager;
1149 smr.addToDomainList(domain, dbName, *guid, subServiceType);
1150
1151 END_SECAPI
1152 }
1153
1154 // determine if a non-file based DB is in the keychain list
1155 OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName,
1156 const CSSM_GUID *guid, uint32 subServiceType)
1157 {
1158 BEGIN_SECAPI
1159 RequiredParam(dbName);
1160 StorageManager &smr = globals().storageManager;
1161 smr.isInDomainList(domain, dbName, *guid, subServiceType);
1162 END_SECAPI
1163 }
1164
1165 // remove a non-file based DB from the keychain list
1166 OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName,
1167 const CSSM_GUID *guid, uint32 subServiceType)
1168 {
1169 BEGIN_SECAPI
1170 RequiredParam(dbName);
1171 StorageManager &smr = globals().storageManager;
1172 smr.removeFromDomainList(domain, dbName, *guid, subServiceType);
1173 END_SECAPI
1174 }
1175
1176
1177 // set server mode -- must be called before any other Sec* etc. call
1178 void SecKeychainSetServerMode()
1179 {
1180 gServerMode = true;
1181 }
1182
1183
1184
1185 OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
1186 {
1187 BEGIN_SECAPI
1188 RequiredParam(kcRef);
1189 Keychain keychain = Keychain::optional(kcRef);
1190 keychain->setBatchMode(mode, rollback);
1191 END_SECAPI
1192 }
1193
1194
1195
1196 OSStatus SecKeychainCleanupHandles()
1197 {
1198 BEGIN_SECAPI
1199 END_SECAPI // which causes the handle cache cleanup routine to run
1200 }
1201
1202 OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
1203 {
1204 BEGIN_SECAPI
1205 SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
1206 END_SECAPI
1207 }
1208
1209 OSStatus SecKeychainChangeKeyStorePassphrase()
1210 {
1211 BEGIN_SECAPI
1212 SecurityServer::ClientSession().changeKeyStorePassphrase();
1213 END_SECAPI
1214 }
1215
1216 static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
1217 {
1218 BEGIN_SECAPI
1219
1220 // make a keychain object "wrapper" for this keychain ref
1221 Keychain keychain = Keychain::optional(userKeychainRef);
1222
1223 CssmClient::Db db = keychain->database();
1224
1225 // create the keychain, using appropriate credentials
1226 Allocator &alloc = db->allocator();
1227 AutoCredentials cred(alloc); // will leak, but we're quitting soon :-)
1228
1229 char passphrase[1024];
1230 CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8);
1231
1232 // use this passphrase
1233 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
1234 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
1235 new(alloc) ListElement(StringData(passphrase)));
1236 db->authenticate(CSSM_DB_ACCESS_READ, &cred);
1237
1238 CSSM_DL_DB_HANDLE dlDb = db->handle();
1239 CssmData dlDbData = CssmData::wrap(dlDb);
1240 CssmKey refKey;
1241 KeySpec spec(CSSM_KEYUSE_ANY,
1242 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
1243
1244 DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64);
1245 derive(&dlDbData, spec, refKey);
1246
1247 // now extract the raw keybits
1248 CssmKey rawKey;
1249 WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE);
1250 wrap(refKey, rawKey);
1251
1252 *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length());
1253
1254 END_SECAPI
1255 }
1256
1257 static const char *kAutologinPWFilePath = "/etc/kcpassword";
1258 static const uint32_t kObfuscatedPasswordSizeMultiple = 12;
1259 static const uint32_t buffer_size = 512;
1260 static const uint8_t kObfuscationKey[] = {0x7d, 0x89, 0x52, 0x23, 0xd2, 0xbc, 0xdd, 0xea, 0xa3, 0xb9, 0x1f};
1261
1262 static void obfuscate(void *buffer, size_t bufferLength)
1263 {
1264 uint8_t *pBuf = (uint8_t *) buffer;
1265 const uint8_t *pKey = kObfuscationKey, *eKey = pKey + sizeof( kObfuscationKey );
1266
1267 while (bufferLength--) {
1268 *pBuf = *pBuf ^ *pKey;
1269 ++pKey;
1270 ++pBuf;
1271 if (pKey == eKey)
1272 pKey = kObfuscationKey;
1273 }
1274 }
1275
1276 static bool _SASetAutologinPW(CFStringRef inAutologinPW)
1277 {
1278 bool result = false;
1279 struct stat sb;
1280
1281 // Delete the kcpassword file if it exists already
1282 if (stat(kAutologinPWFilePath, &sb) == 0)
1283 unlink( kAutologinPWFilePath );
1284
1285 // NIL incoming password ==> clear auto login password (above) without setting a new one. In other words: turn auto login off.
1286 if (inAutologinPW != NULL) {
1287 char buffer[buffer_size];
1288 const char *pwAsUTF8String = CFStringGetCStringPtr(inAutologinPW, kCFStringEncodingUTF8);
1289 if (pwAsUTF8String == NULL) {
1290 if (CFStringGetCString(inAutologinPW, buffer, buffer_size, kCFStringEncodingUTF8)) pwAsUTF8String = buffer;
1291 }
1292
1293 if (pwAsUTF8String != NULL) {
1294 size_t pwLength = strlen(pwAsUTF8String) + 1;
1295 size_t obfuscatedPWLength;
1296 char *obfuscatedPWBuffer;
1297
1298 // The size of the obfuscated password should be the smallest multiple of
1299 // kObfuscatedPasswordSizeMultiple greater than or equal to pwLength.
1300 obfuscatedPWLength = (((pwLength - 1) / kObfuscatedPasswordSizeMultiple) + 1) * kObfuscatedPasswordSizeMultiple;
1301 obfuscatedPWBuffer = (char *) malloc(obfuscatedPWLength);
1302
1303 // Copy the password (including null terminator) to beginning of obfuscatedPWBuffer
1304 bcopy(pwAsUTF8String, obfuscatedPWBuffer, pwLength);
1305
1306 // Pad remainder of obfuscatedPWBuffer with random bytes
1307 {
1308 char *p;
1309 char *endOfBuffer = obfuscatedPWBuffer + obfuscatedPWLength;
1310
1311 for (p = obfuscatedPWBuffer + pwLength; p < endOfBuffer; ++p)
1312 *p = random() & 0x000000FF;
1313 }
1314
1315 obfuscate(obfuscatedPWBuffer, obfuscatedPWLength);
1316
1317 int pwFile = open(kAutologinPWFilePath, O_CREAT | O_WRONLY | O_NOFOLLOW, S_IRUSR | S_IWUSR);
1318 if (pwFile >= 0) {
1319 size_t wrote = write(pwFile, obfuscatedPWBuffer, obfuscatedPWLength);
1320 if (wrote == obfuscatedPWLength)
1321 result = true;
1322 close(pwFile);
1323 }
1324
1325 chmod(kAutologinPWFilePath, S_IRUSR | S_IWUSR);
1326 free(obfuscatedPWBuffer);
1327 }
1328 }
1329
1330 return result;
1331 }
1332
1333 OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
1334 SecTrustedApplicationRef itemPath;
1335 SecAccessRef ourAccessRef = NULL;
1336
1337 OSStatus result = errSecParam;
1338
1339 if (userKeychainRef == NULL) {
1340 // We don't have a specific user keychain, fall back
1341 if (_SASetAutologinPW(password))
1342 result = errSecSuccess;
1343
1344 return result;
1345 }
1346
1347 CFDataRef masterKey = NULL;
1348 result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password);
1349 if (errSecSuccess != result) {
1350 return result;
1351 }
1352
1353 result = SecKeychainStash();
1354 if (errSecSuccess != result) {
1355 if (masterKey != NULL) CFRelease(masterKey);
1356 return result;
1357 }
1358
1359 CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1360 if (noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath)
1361 CFArrayAppendValue(trustedApplications, itemPath);
1362
1363 if (trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
1364 if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) {
1365 SecKeychainRef internalSystemKeychainRef = NULL;
1366 if (NULL == systemKeychainRef) {
1367 SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &internalSystemKeychainRef);
1368 } else {
1369 internalSystemKeychainRef = systemKeychainRef;
1370 }
1371
1372 const void *queryKeys[] = { kSecClass,
1373 kSecAttrService,
1374 kSecAttrAccount,
1375 kSecUseKeychain,
1376 };
1377 const void *queryValues[] = { kSecClassGenericPassword,
1378 CFSTR("com.apple.loginwindow.auto-login"),
1379 username,
1380 internalSystemKeychainRef,
1381 };
1382
1383 const void *updateKeys[] = { kSecAttrAccess,
1384 kSecValueData,
1385 };
1386 const void *updateValues[] = { ourAccessRef,
1387 masterKey,
1388 };
1389
1390 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1391 CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1392
1393 result = SecItemUpdate(query, update);
1394
1395 if (errSecSuccess != result) {
1396 const void *addKeys[] = { kSecClass,
1397 kSecAttrService,
1398 kSecAttrAccount,
1399 kSecUseKeychain,
1400 kSecAttrAccess,
1401 kSecValueData,
1402 };
1403 const void *addValues[] = { kSecClassGenericPassword,
1404 CFSTR("com.apple.loginwindow.auto-login"),
1405 username,
1406 internalSystemKeychainRef,
1407 ourAccessRef,
1408 masterKey,
1409 };
1410
1411 CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1412 result = SecItemAdd(add, NULL);
1413 if (NULL != add) CFRelease(add);
1414 }
1415
1416 if (NULL != query) CFRelease(query);
1417 if (NULL != update) CFRelease(update);
1418
1419 // If the caller wanted us to locate the system keychain reference, it's okay to go ahead and free our magically created one
1420 if (systemKeychainRef == NULL) CFRelease(internalSystemKeychainRef);
1421 }
1422 }
1423
1424 if (NULL != masterKey) CFRelease(masterKey);
1425 if (NULL != trustedApplications) CFRelease(trustedApplications);
1426 if (NULL != ourAccessRef) CFRelease(ourAccessRef);
1427
1428 return result;
1429 }
1430
1431 OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
1432 {
1433 BEGIN_SECAPI
1434
1435 if(attempts) {
1436 SecurityServer::ClientSession().getUserPromptAttempts(*attempts);
1437 }
1438
1439 END_SECAPI
1440 }
1441
1442 OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash,
1443 SecKeychainRef userKeychain, CFStringRef password)
1444 {
1445 CFRef<CFStringRef> pwd;
1446 OSStatus result;
1447
1448 if (password == NULL || CFStringGetLength(password) == 0) {
1449 AuthorizationRef authorizationRef;
1450 result = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &authorizationRef);
1451 if (result != errAuthorizationSuccess) {
1452 secnotice("SecKeychain", "failed to create authorization");
1453 return result;
1454 }
1455
1456 AuthorizationItem myItems = {"com.apple.ctk.pair", 0, NULL, 0};
1457 AuthorizationRights myRights = {1, &myItems};
1458 AuthorizationRights *authorizedRights = NULL;
1459
1460 char pathName[PATH_MAX];
1461 UInt32 pathLength = PATH_MAX;
1462 result = SecKeychainGetPath(userKeychain, &pathLength, pathName);
1463 if (result != errSecSuccess) {
1464 secnotice("SecKeychain", "failed to create authorization");
1465 return result;
1466 }
1467
1468 Boolean checkPwd = TRUE;
1469 Boolean ignoreSession = TRUE;
1470 AuthorizationItem envItems[] = {
1471 {AGENT_HINT_KEYCHAIN_PATH, pathLength, pathName, 0},
1472 {AGENT_HINT_KEYCHAIN_CHECK, sizeof(checkPwd), &checkPwd},
1473 {AGENT_HINT_IGNORE_SESSION, sizeof(ignoreSession), &ignoreSession}
1474 };
1475
1476 AuthorizationEnvironment environment = {3, envItems};
1477 AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
1478 result = AuthorizationCopyRights(authorizationRef, &myRights, &environment, flags, &authorizedRights);
1479 if (authorizedRights)
1480 AuthorizationFreeItemSet(authorizedRights);
1481
1482 if (result == errAuthorizationSuccess) {
1483 AuthorizationItemSet *items;
1484 result = AuthorizationCopyInfo(authorizationRef, kAuthorizationEnvironmentPassword, &items);
1485 if (result == errAuthorizationSuccess) {
1486 if (items->count > 0) {
1487 pwd = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)items->items[0].value, kCFStringEncodingUTF8);
1488 }
1489 AuthorizationFreeItemSet(items);
1490 }
1491 }
1492 AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
1493 if (result != errAuthorizationSuccess) {
1494 secnotice("SecKeychain", "did not get authorization to pair the card");
1495 return result;
1496 }
1497 } else {
1498 pwd.take(password);
1499 }
1500
1501 if (!pwd) {
1502 secnotice("SecKeychain", "did not get kcpass");
1503 return errSecInternalComponent;
1504 }
1505
1506 CFRef<CFDataRef> masterKey;
1507 result = SecKeychainGetMasterKey(userKeychain, masterKey.take(), pwd);
1508 if (result != errSecSuccess) {
1509 secnotice("SecKeychain", "Failed to get master key: %d", (int) result);
1510 return result;
1511 }
1512
1513 CFRef<CFDataRef> scBlob;
1514 result = TokenLoginGetScBlob(wrapPubKeyHash, tokenID, pwd, scBlob.take());
1515 if (result != errSecSuccess) {
1516 secnotice("SecKeychain", "Failed to get stash: %d", (int) result);
1517 return result;
1518 }
1519
1520 result = TokenLoginCreateLoginData(tokenID, pubKeyHash, wrapPubKeyHash, masterKey, scBlob);
1521 if (result != errSecSuccess) {
1522 secnotice("SecKeychain", "Failed to create login data: %d", (int) result);
1523 return result;
1524 }
1525
1526 secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result);
1527 return result;
1528 }
1529
1530 OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash)
1531 {
1532 OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash);
1533 if (result != errSecSuccess) {
1534 secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result);
1535 }
1536 return result;
1537 }
1538