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