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