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