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