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