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