]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecKeychain.cpp
Security-57337.40.85.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
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 OSStatus
412 SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version)
413 {
414 BEGIN_SECAPI
415
416 RequiredParam(version);
417
418 *version = Keychain::optional(keychainRef)->database()->dbBlobVersion();
419
420 END_SECAPI
421 }
422
423
424 // @@@ Deprecated
425 UInt16
426 SecKeychainListGetCount(void)
427 {
428 BEGIN_SECAPI
429
430 return globals().storageManager.size();
431
432 END_SECAPI1(0)
433 }
434
435
436 // @@@ Deprecated
437 OSStatus
438 SecKeychainListCopyKeychainAtIndex(UInt16 index, SecKeychainRef *keychainRef)
439 {
440 BEGIN_SECAPI
441
442 KeychainCore::StorageManager &smgr=KeychainCore::globals().storageManager;
443 RequiredParam(keychainRef)=smgr[index]->handle();
444
445 END_SECAPI
446 }
447
448
449 // @@@ Deprecated
450 OSStatus
451 SecKeychainListRemoveKeychain(SecKeychainRef *keychainRef)
452 {
453 BEGIN_SECAPI
454
455 Required(keychainRef);
456 Keychain keychain = Keychain::optional(*keychainRef);
457 StorageManager::KeychainList keychainList;
458 keychainList.push_back(keychain);
459 globals().storageManager.remove(keychainList);
460 *keychainRef = NULL;
461
462 END_SECAPI
463 }
464
465
466 OSStatus
467 SecKeychainAttributeInfoForItemID(SecKeychainRef keychainRef, UInt32 itemID, SecKeychainAttributeInfo **info)
468 {
469 BEGIN_SECAPI
470
471 Keychain keychain = Keychain::optional(keychainRef);
472 keychain->getAttributeInfoForItemID(itemID, info);
473
474 END_SECAPI
475 }
476
477
478 OSStatus
479 SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info)
480 {
481 BEGIN_SECAPI
482
483 KeychainImpl::freeAttributeInfo(info);
484
485 END_SECAPI
486 }
487
488
489 pascal OSStatus
490 SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext)
491 {
492 BEGIN_SECAPI
493
494 RequiredParam(callbackFunction);
495 CCallbackMgr::AddCallback(callbackFunction,eventMask,userContext);
496
497 END_SECAPI
498 }
499
500
501 OSStatus
502 SecKeychainRemoveCallback(SecKeychainCallback callbackFunction)
503 {
504 BEGIN_SECAPI
505
506 RequiredParam(callbackFunction);
507 CCallbackMgr::RemoveCallback(callbackFunction);
508
509 END_SECAPI
510 }
511
512 OSStatus
513 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)
514 {
515 BEGIN_SECAPI
516
517 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
518 // @@@ Get real itemClass
519 Item item(kSecInternetPasswordItemClass, 'aapl', passwordLength, passwordData, false);
520
521 if (serverName && serverNameLength)
522 {
523 CssmData server(const_cast<void *>(reinterpret_cast<const void *>(serverName)), serverNameLength);
524 item->setAttribute(Schema::attributeInfo(kSecServerItemAttr), server);
525 // use server name as default label
526 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), server);
527 }
528
529 if (accountName && accountNameLength)
530 {
531 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
532 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
533 }
534
535 if (securityDomain && securityDomainLength)
536 item->setAttribute(Schema::attributeInfo(kSecSecurityDomainItemAttr),
537 CssmData(const_cast<void *>(reinterpret_cast<const void *>(securityDomain)), securityDomainLength));
538
539 item->setAttribute(Schema::attributeInfo(kSecPortItemAttr), UInt32(port));
540 item->setAttribute(Schema::attributeInfo(kSecProtocolItemAttr), protocol);
541 item->setAttribute(Schema::attributeInfo(kSecAuthenticationTypeItemAttr), authenticationType);
542
543 if (path && pathLength)
544 item->setAttribute(Schema::attributeInfo(kSecPathItemAttr),
545 CssmData(const_cast<void *>(reinterpret_cast<const void *>(path)), pathLength));
546
547 Keychain keychain = nil;
548 try
549 {
550 keychain = Keychain::optional(keychainRef);
551 if ( !keychain->exists() )
552 {
553 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
554 }
555 }
556 catch(...)
557 {
558 keychain = globals().storageManager.defaultKeychainUI(item);
559 }
560
561 keychain->add(item);
562
563 if (itemRef)
564 *itemRef = item->handle();
565
566 END_SECAPI
567 }
568
569
570 OSStatus
571 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)
572
573 {
574 BEGIN_SECAPI
575
576 StorageManager::KeychainList keychains;
577 globals().storageManager.optionalSearchList(keychainOrArray, keychains);
578 KCCursor cursor(keychains, kSecInternetPasswordItemClass, NULL);
579
580 if (serverName && serverNameLength)
581 {
582 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServerItemAttr),
583 CssmData(const_cast<char *>(serverName), serverNameLength));
584 }
585
586 if (securityDomain && securityDomainLength)
587 {
588 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecSecurityDomainItemAttr),
589 CssmData (const_cast<char*>(securityDomain), securityDomainLength));
590 }
591
592 if (accountName && accountNameLength)
593 {
594 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
595 CssmData (const_cast<char*>(accountName), accountNameLength));
596 }
597
598 if (port)
599 {
600 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPortItemAttr),
601 UInt32(port));
602 }
603
604 if (protocol)
605 {
606 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecProtocolItemAttr),
607 protocol);
608 }
609
610 if (authenticationType)
611 {
612 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAuthenticationTypeItemAttr),
613 authenticationType);
614 }
615
616 if (path && pathLength)
617 {
618 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecPathItemAttr), path);
619 }
620
621 Item item;
622 if (!cursor->next(item))
623 return errSecItemNotFound;
624
625 // Get its data (only if necessary)
626 if (passwordData || passwordLength)
627 {
628 CssmDataContainer outData;
629 item->getData(outData);
630 *passwordLength=(UInt32)outData.length();
631 outData.Length=0;
632 *passwordData=outData.data();
633 outData.Data=NULL;
634 }
635
636 if (itemRef)
637 *itemRef=item->handle();
638
639 END_SECAPI
640 }
641
642
643 OSStatus
644 SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
645 {
646 BEGIN_SECAPI
647
648 KCThrowParamErrIf_(passwordLength!=0 && passwordData==NULL);
649 // @@@ Get real itemClass
650
651 Item item(kSecGenericPasswordItemClass, 'aapl', passwordLength, passwordData, false);
652
653 if (serviceName && serviceNameLength)
654 {
655 CssmData service(const_cast<void *>(reinterpret_cast<const void *>(serviceName)), serviceNameLength);
656 item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
657 // use service name as default label (UNLESS the service is iTools and we have an account name [3787371])
658 const char *iTools = "iTools";
659 if (accountNameLength && serviceNameLength==strlen(iTools) && !memcmp(serviceName, iTools, serviceNameLength))
660 {
661 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
662 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), account);
663 }
664 else
665 {
666 item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
667 }
668 }
669
670 if (accountName && accountNameLength)
671 {
672 CssmData account(const_cast<void *>(reinterpret_cast<const void *>(accountName)), accountNameLength);
673 item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
674 }
675
676 Keychain keychain = nil;
677 try
678 {
679 keychain = Keychain::optional(keychainRef);
680 if ( !keychain->exists() )
681 {
682 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
683 }
684 }
685 catch(...)
686 {
687 keychain = globals().storageManager.defaultKeychainUI(item);
688 }
689
690 keychain->add(item);
691 if (itemRef)
692 *itemRef = item->handle();
693
694 END_SECAPI
695 }
696
697
698 OSStatus
699 SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 *passwordLength, void **passwordData, SecKeychainItemRef *itemRef)
700
701 {
702 BEGIN_SECAPI
703
704 StorageManager::KeychainList keychains;
705 globals().storageManager.optionalSearchList(keychainOrArray, keychains);
706 KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
707
708 if (serviceName && serviceNameLength)
709 {
710 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr),
711 CssmData(const_cast<char *>(serviceName), serviceNameLength));
712 }
713
714 if (accountName && accountNameLength)
715 {
716 cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecAccountItemAttr),
717 CssmData(const_cast<char *>(accountName), accountNameLength));
718 }
719
720 Item item;
721 if (!cursor->next(item))
722 return errSecItemNotFound;
723
724 // Get its data (only if necessary)
725 if (passwordData || passwordLength)
726 {
727 CssmDataContainer outData;
728 item->getData(outData);
729 *passwordLength=(UInt32)outData.length();
730 outData.Length=0;
731 *passwordData=outData.data();
732 outData.Data=NULL;
733 }
734
735 if (itemRef)
736 *itemRef=item->handle();
737
738 END_SECAPI
739 }
740
741
742 OSStatus
743 SecKeychainSetUserInteractionAllowed(Boolean state)
744 {
745 BEGIN_SECAPI
746
747 globals().setUserInteractionAllowed(state);
748
749 END_SECAPI
750 }
751
752
753 OSStatus
754 SecKeychainGetUserInteractionAllowed(Boolean *state)
755 {
756 BEGIN_SECAPI
757
758 Required(state)=globals().getUserInteractionAllowed();
759
760 END_SECAPI
761 }
762
763
764 OSStatus
765 SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle)
766 {
767 BEGIN_SECAPI
768
769 RequiredParam(dldbHandle);
770
771 Keychain keychain = Keychain::optional(keychainRef);
772 *dldbHandle = keychain->database()->handle();
773
774 END_SECAPI
775 }
776
777
778 OSStatus
779 SecKeychainGetCSPHandle(SecKeychainRef keychainRef, CSSM_CSP_HANDLE *cspHandle)
780 {
781 BEGIN_SECAPI
782
783 RequiredParam(cspHandle);
784
785 Keychain keychain = Keychain::optional(keychainRef);
786 *cspHandle = keychain->csp()->handle();
787
788 END_SECAPI
789 }
790
791
792 OSStatus
793 SecKeychainCopyAccess(SecKeychainRef keychainRef, SecAccessRef *accessRef)
794 {
795 BEGIN_SECAPI
796
797 MacOSError::throwMe(errSecUnimplemented);//%%%for now
798
799 END_SECAPI
800 }
801
802
803 OSStatus
804 SecKeychainSetAccess(SecKeychainRef keychainRef, SecAccessRef accessRef)
805 {
806 BEGIN_SECAPI
807
808 MacOSError::throwMe(errSecUnimplemented);//%%%for now
809
810 END_SECAPI
811 }
812
813
814 #pragma mark ---- Private API ----
815
816
817 OSStatus
818 SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword, UInt32 newPasswordLength, const void *newPassword)
819 {
820 BEGIN_SECAPI
821
822 Keychain keychain = Keychain::optional(keychainRef);
823 keychain->changePassphrase (oldPasswordLength, oldPassword, newPasswordLength, newPassword);
824
825 END_SECAPI
826 }
827
828
829 OSStatus
830 SecKeychainCopyLogin(SecKeychainRef *keychainRef)
831 {
832 BEGIN_SECAPI
833
834 RequiredParam(keychainRef)=globals().storageManager.loginKeychain()->handle();
835
836 END_SECAPI
837 }
838
839
840 OSStatus
841 SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password)
842 {
843 BEGIN_SECAPI
844
845 try
846 {
847 if (password) {
848 globals().storageManager.login(nameLength, name, passwordLength, password);
849 } else {
850 globals().storageManager.stashLogin();
851 }
852 }
853 catch (CommonError &e)
854 {
855 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
856 {
857 return errSecAuthFailed;
858 }
859 else
860 {
861 return e.osStatus();
862 }
863 }
864
865 END_SECAPI
866 }
867
868 OSStatus SecKeychainStash()
869 {
870 BEGIN_SECAPI
871
872 try
873 {
874 globals().storageManager.stashKeychain();
875 }
876 catch (CommonError &e)
877 {
878 if (e.osStatus() == CSSMERR_DL_OPERATION_AUTH_DENIED)
879 {
880 return errSecAuthFailed;
881 }
882 else
883 {
884 return e.osStatus();
885 }
886 }
887
888 END_SECAPI
889 }
890
891 OSStatus
892 SecKeychainLogout()
893 {
894 BEGIN_SECAPI
895
896 globals().storageManager.logout();
897
898 END_SECAPI
899 }
900
901 /* (non-exported C utility routine) 'Makes' a keychain based on a full path
902 */
903 static Keychain make(const char *name)
904 {
905 return globals().storageManager.make(name);
906 }
907
908 /* 'Makes' a keychain based on a full path for legacy "KC" CoreServices APIs.
909 Note this version doesn't take an accessRef or password.
910 The "KC" create API takes a keychainRef...
911 */
912 OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef)
913 {
914 BEGIN_SECAPI
915 RequiredParam(fullPathName);
916 RequiredParam(keychainRef)=make(fullPathName)->handle();
917 END_SECAPI
918 }
919
920
921 /* Determines if the keychainRef is a valid keychain.
922 */
923 OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
924 {
925 BEGIN_SECAPI
926 *isValid = false;
927 if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL)
928 *isValid = true;
929 END_SECAPI
930 }
931
932 /* Removes a keychain from the keychain search list for legacy "KC" CoreServices APIs.
933 */
934 OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
935 {
936 BEGIN_SECAPI
937 StorageManager::KeychainList singleton;
938 singleton.push_back(KeychainImpl::required(keychainRef));
939 globals().storageManager.remove(singleton);
940 END_SECAPI
941 }
942
943 /* Create a keychain based on a keychain Ref for legacy "KC" CoreServices APIs.
944 */
945 OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
946 {
947 BEGIN_SECAPI
948 RequiredParam(inPassword);
949 KeychainImpl::required(keychainRef)->create(passwordLength, inPassword);
950 END_SECAPI
951 }
952
953 /* Modify a keychain so that it can be synchronized.
954 */
955 OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
956 {
957 BEGIN_SECAPI
958
959 // do error checking for required parameters
960 RequiredParam(dbBlobArray);
961 RequiredParam(extraData);
962
963 const CssmData extraCssmData(const_cast<UInt8 *>(CFDataGetBytePtr(extraData)),
964 CFDataGetLength(extraData));
965
966 CFIndex dbBlobArrayCount = CFArrayGetCount(dbBlobArray);
967 size_t space = sizeof(uint8) + (dbBlobArrayCount * sizeof(SecurityServer::DbHandle));
968 void *dataPtr = (void*)malloc(space);
969 if ( !dataPtr )
970 return errSecAllocate;
971 //
972 // Get a DbHandle(IPCDbHandle) from securityd for each blob in the array that we'll authenticate with.
973 //
974 uint8* sizePtr = (uint8*)dataPtr;
975 *sizePtr = dbBlobArrayCount;
976 SecurityServer::DbHandle *currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
977 CFIndex index;
978 SecurityServer::ClientSession ss(Allocator::standard(), Allocator::standard());
979 for (index=0; index < dbBlobArrayCount; index++)
980 {
981 CFDataRef cfBlobData = (CFDataRef)CFArrayGetValueAtIndex(dbBlobArray, index);
982 const CssmData thisKCData(const_cast<UInt8 *>(CFDataGetBytePtr(cfBlobData)), CFDataGetLength(cfBlobData));
983 //
984 // Since it's to a DbHandle that's not on our disk (it came from user's iDisk),
985 // it's OK to use the mIdentifier and access credentials of the keychain we're recoding.
986 //
987 Keychain kc = KeychainImpl::required(keychainRef);
988 *currDbHandle = ss.decodeDb(kc->dlDbIdentifier(), kc->defaultCredentials(), thisKCData); /* returns a DbHandle (IPCDbHandle) */
989
990 currDbHandle++;
991 }
992 // do the work
993 Keychain keychain = Keychain::optional(keychainRef);
994 const CssmData data(const_cast<UInt8 *>((uint8*)dataPtr), space);
995 Boolean recodeFailed = false;
996
997 int errCode=errSecSuccess;
998
999 try
1000 {
1001 keychain->recode(data, extraCssmData);
1002 }
1003 catch (MacOSError e)
1004 {
1005 errCode = e.osStatus();
1006 recodeFailed = true;
1007 }
1008 catch (UnixError ue)
1009 {
1010 errCode = ue.unixError();
1011 }
1012
1013 currDbHandle = (SecurityServer::DbHandle *)(sizePtr+1);
1014 for (index=0; index < dbBlobArrayCount; index++)
1015 {
1016 ss.releaseDb(*currDbHandle);
1017 currDbHandle++;
1018 }
1019 if ( dataPtr )
1020 free(dataPtr);
1021
1022 if ( recodeFailed )
1023 {
1024 return errCode;
1025 }
1026
1027 END_SECAPI
1028 }
1029
1030 OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature)
1031 {
1032 BEGIN_SECAPI
1033
1034 // do error checking for required parameters
1035 RequiredParam(keychainSignature);
1036
1037 // make a keychain object "wrapper" for this keychain ref
1038 Keychain keychain = Keychain::optional(keychainRef);
1039 CssmAutoData data(keychain->database()->allocator());
1040 keychain->copyBlob(data.get());
1041
1042 // get the cssmDBBlob
1043 const SecurityServer::DbBlob *cssmDBBlob =
1044 data.get().interpretedAs<const SecurityServer::DbBlob>();
1045
1046 // convert from CDSA standards to CF standards
1047 *keychainSignature = CFDataCreate(kCFAllocatorDefault,
1048 cssmDBBlob->randomSignature.bytes,
1049 sizeof(SecurityServer::DbBlob::Signature));
1050
1051 END_SECAPI
1052 }
1053
1054 OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
1055 {
1056 BEGIN_SECAPI
1057
1058 // do error checking for required parameters
1059 RequiredParam(dbBlob);
1060
1061 // make a keychain object "wrapper" for this keychain ref
1062 Keychain keychain = Keychain::optional(keychainRef);
1063 CssmAutoData data(keychain->database()->allocator());
1064 keychain->copyBlob(data.get());
1065
1066 // convert from CDSA standards to CF standards
1067 *dbBlob = CFDataCreate(kCFAllocatorDefault, data, data.length());
1068
1069 END_SECAPI
1070 }
1071
1072 // make a new keychain with pre-existing secrets
1073 OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
1074 {
1075 BEGIN_SECAPI
1076
1077 KCThrowParamErrIf_(!fullPathName);
1078 KCThrowParamErrIf_(!dbBlob);
1079
1080 Keychain keychain = globals().storageManager.make(fullPathName);
1081
1082 CssmData blob(const_cast<unsigned char *>(CFDataGetBytePtr(dbBlob)), CFDataGetLength(dbBlob));
1083
1084 // @@@ the call to StorageManager::make above leaves keychain the the cache.
1085 // If the create below fails we should probably remove it.
1086 keychain->createWithBlob(blob);
1087
1088 RequiredParam(kcRef)=keychain->handle();
1089
1090 //
1091
1092 END_SECAPI
1093 }
1094
1095 // add a non-file based DB to the keychain list
1096 OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName,
1097 const CSSM_GUID *guid, uint32 subServiceType)
1098 {
1099 BEGIN_SECAPI
1100
1101 RequiredParam(dbName);
1102 StorageManager &smr = globals().storageManager;
1103 smr.addToDomainList(domain, dbName, *guid, subServiceType);
1104
1105 END_SECAPI
1106 }
1107
1108 // determine if a non-file based DB is in the keychain list
1109 OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName,
1110 const CSSM_GUID *guid, uint32 subServiceType)
1111 {
1112 BEGIN_SECAPI
1113 RequiredParam(dbName);
1114 StorageManager &smr = globals().storageManager;
1115 smr.isInDomainList(domain, dbName, *guid, subServiceType);
1116 END_SECAPI
1117 }
1118
1119 // remove a non-file based DB from the keychain list
1120 OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName,
1121 const CSSM_GUID *guid, uint32 subServiceType)
1122 {
1123 BEGIN_SECAPI
1124 RequiredParam(dbName);
1125 StorageManager &smr = globals().storageManager;
1126 smr.removeFromDomainList(domain, dbName, *guid, subServiceType);
1127 END_SECAPI
1128 }
1129
1130
1131 // set server mode -- must be called before any other Sec* etc. call
1132 void SecKeychainSetServerMode()
1133 {
1134 gServerMode = true;
1135 }
1136
1137
1138
1139 OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
1140 {
1141 BEGIN_SECAPI
1142 RequiredParam(kcRef);
1143 Keychain keychain = Keychain::optional(kcRef);
1144 keychain->setBatchMode(mode, rollback);
1145 END_SECAPI
1146 }
1147
1148
1149
1150 OSStatus SecKeychainCleanupHandles()
1151 {
1152 BEGIN_SECAPI
1153 END_SECAPI // which causes the handle cache cleanup routine to run
1154 }
1155
1156 OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
1157 {
1158 BEGIN_SECAPI
1159 SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
1160 END_SECAPI
1161 }
1162
1163 OSStatus SecKeychainChangeKeyStorePassphrase()
1164 {
1165 BEGIN_SECAPI
1166 SecurityServer::ClientSession().changeKeyStorePassphrase();
1167 END_SECAPI
1168 }
1169
1170 static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
1171 {
1172 BEGIN_SECAPI
1173
1174 // make a keychain object "wrapper" for this keychain ref
1175 Keychain keychain = Keychain::optional(userKeychainRef);
1176
1177 CssmClient::Db db = keychain->database();
1178
1179 // create the keychain, using appropriate credentials
1180 Allocator &alloc = db->allocator();
1181 AutoCredentials cred(alloc); // will leak, but we're quitting soon :-)
1182
1183 char passphrase[1024];
1184 CFStringGetCString(password, passphrase, sizeof(passphrase), kCFStringEncodingUTF8);
1185
1186 // use this passphrase
1187 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
1188 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
1189 new(alloc) ListElement(StringData(passphrase)));
1190 db->accessCredentials(&cred);
1191
1192 CSSM_DL_DB_HANDLE dlDb = db->handle();
1193 CssmData dlDbData = CssmData::wrap(dlDb);
1194 CssmKey refKey;
1195 KeySpec spec(CSSM_KEYUSE_ANY,
1196 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE);
1197
1198 DeriveKey derive(keychain->csp(), CSSM_ALGID_KEYCHAIN_KEY, CSSM_ALGID_3DES_3KEY, 3 * 64);
1199 derive(&dlDbData, spec, refKey);
1200
1201 // now extract the raw keybits
1202 CssmKey rawKey;
1203 WrapKey wrap(keychain->csp(), CSSM_ALGID_NONE);
1204 wrap(refKey, rawKey);
1205
1206 *masterKey = CFDataCreate(kCFAllocatorDefault, rawKey.keyData(), rawKey.length());
1207
1208 END_SECAPI
1209 }
1210
1211
1212 OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
1213 SecTrustedApplicationRef itemPath;
1214 SecAccessRef ourAccessRef = NULL;
1215
1216 OSStatus result = errSecParam;
1217
1218 CFDataRef masterKey = NULL;
1219 result = SecKeychainGetMasterKey(userKeychainRef, &masterKey, password);
1220 if (errSecSuccess != result) {
1221 return result;
1222 }
1223
1224 result = SecKeychainStash();
1225 if (errSecSuccess != result) {
1226 if (NULL != masterKey) CFRelease(masterKey);
1227 return result;
1228 }
1229
1230 CFMutableArrayRef trustedApplications = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1231 if ( noErr == SecTrustedApplicationCreateApplicationGroup("com.apple.security.auto-login", NULL, &itemPath) && itemPath )
1232 CFArrayAppendValue(trustedApplications, itemPath);
1233
1234 if ( trustedApplications && (CFArrayGetCount(trustedApplications) > 0)) {
1235 if (errSecSuccess == (result = SecAccessCreate(CFSTR("Auto-Login applications"), trustedApplications, &ourAccessRef))) {
1236 if (NULL == systemKeychainRef) {
1237 SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem, &systemKeychainRef);
1238 }
1239
1240 const void *queryKeys[] = { kSecClass,
1241 kSecAttrService,
1242 kSecAttrAccount,
1243 kSecUseKeychain,
1244 };
1245 const void *queryValues[] = { kSecClassGenericPassword,
1246 CFSTR("com.apple.loginwindow.auto-login"),
1247 username,
1248 systemKeychainRef,
1249 };
1250
1251 const void *updateKeys[] = { kSecAttrAccess,
1252 kSecValueData,
1253 };
1254 const void *updateValues[] = { ourAccessRef,
1255 masterKey,
1256 };
1257
1258 CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, queryKeys, queryValues, sizeof(queryValues)/sizeof(*queryValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1259 CFDictionaryRef update = CFDictionaryCreate(kCFAllocatorDefault, updateKeys, updateValues, sizeof(updateValues)/sizeof(*updateValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1260
1261 result = SecItemUpdate(query, update);
1262
1263 if (errSecSuccess != result) {
1264 const void *addKeys[] = { kSecClass,
1265 kSecAttrService,
1266 kSecAttrAccount,
1267 kSecUseKeychain,
1268 kSecAttrAccess,
1269 kSecValueData,
1270 };
1271 const void *addValues[] = { kSecClassGenericPassword,
1272 CFSTR("com.apple.loginwindow.auto-login"),
1273 username,
1274 systemKeychainRef,
1275 ourAccessRef,
1276 masterKey,
1277 };
1278
1279 CFDictionaryRef add = CFDictionaryCreate(kCFAllocatorDefault, addKeys, addValues, sizeof(addValues)/sizeof(*addValues), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1280 result = SecItemAdd(add, NULL);
1281 if (NULL != add) CFRelease(add);
1282 }
1283
1284 if (NULL != query) CFRelease(query);
1285 if (NULL != update) CFRelease(update);
1286 }
1287 }
1288
1289 if (NULL != masterKey) CFRelease(masterKey);
1290 if (NULL != trustedApplications) CFRelease(trustedApplications);
1291 if (NULL != ourAccessRef) CFRelease(ourAccessRef);
1292 if (NULL != systemKeychainRef) CFRelease(systemKeychainRef);
1293
1294 return result;
1295 }