1/*
2 * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19//
20// SSDLSession.h - DL session for security server CSP/DL.
21//
22#include "SSDLSession.h"
23
24#include "CSPDLPlugin.h"
25#include "SSKey.h"
26#include <security_cdsa_utilities/cssmbridge.h>
27#include <Security/cssmapplePriv.h>
28
29using namespace CssmClient;
30using namespace SecurityServer;
31using namespace std;
32
33//
34// SSDLSession -- Security Server DL session
35//
36SSDLSession::SSDLSession(CSSM_MODULE_HANDLE handle,
37						 CSPDLPlugin &plug,
38						 const CSSM_VERSION &version,
39						 uint32 subserviceId,
40						 CSSM_SERVICE_TYPE subserviceType,
41						 CSSM_ATTACH_FLAGS attachFlags,
42						 const CSSM_UPCALLS &upcalls,
43						 DatabaseManager &databaseManager,
44						 SSCSPDLSession &ssCSPDLSession)
45: DLPluginSession(handle, plug, version, subserviceId, subserviceType,
46				  attachFlags, upcalls, databaseManager),
47  mSSCSPDLSession(ssCSPDLSession),
48  mDL(Module(gGuidAppleFileDL, Cssm::standard())),
49  mClientSession(Allocator::standard(), static_cast<PluginSession &>(*this))
50{
51	mClientSession.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback, &mSSCSPDLSession);
52	// @@@ mDL.allocator(*static_cast<DatabaseSession *>(this));
53	mDL->allocator(allocator());
54	mDL->version(version);
55	mDL->subserviceId(subserviceId);
56	mDL->flags(attachFlags);
57	// fprintf(stderr, "%p: Created %p\n", pthread_self(), this);
58}
59
60SSDLSession::~SSDLSession()
61try
62{
63	StLock<Mutex> _1(mSSUniqueRecordLock);
64	mSSUniqueRecordMap.clear();
65
66	StLock<Mutex> _2(mDbHandleLock);
67	DbHandleMap::iterator end = mDbHandleMap.end();
68	for (DbHandleMap::iterator it = mDbHandleMap.begin(); it != end; ++it)
69		it->second->close();
70
71	mDbHandleMap.clear();
72	mDL->detach();
73}
74catch (...)
75{
76}
77
78// Utility functions
79void
80SSDLSession::GetDbNames(CSSM_NAME_LIST_PTR &outNameList)
81{
82	// @@@ Fix client lib
83	CSSM_DL_GetDbNames(mDL->handle(), &outNameList);
84}
85
86
87void
88SSDLSession::FreeNameList(CSSM_NAME_LIST &inNameList)
89{
90	// @@@ Fix client lib
91	CSSM_DL_FreeNameList(mDL->handle(), &inNameList);
92}
93
94
95void
96SSDLSession::DbDelete(const char *inDbName,
97					  const CSSM_NET_ADDRESS *inDbLocation,
98					  const AccessCredentials *inAccessCred)
99{
100	SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
101	db->accessCredentials(inAccessCred);
102	db->deleteDb();
103}
104
105// DbContext creation and destruction.
106void
107SSDLSession::DbCreate(const char *inDbName,
108					  const CSSM_NET_ADDRESS *inDbLocation,
109					  const CSSM_DBINFO &inDBInfo,
110					  CSSM_DB_ACCESS_TYPE inAccessRequest,
111					  const CSSM_RESOURCE_CONTROL_CONTEXT *inCredAndAclEntry,
112					  const void *inOpenParameters,
113					  CSSM_DB_HANDLE &outDbHandle)
114{
115	SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
116	db->dbInfo(&inDBInfo);
117	db->accessRequest(inAccessRequest);
118	db->resourceControlContext(inCredAndAclEntry);
119	db->openParameters(inOpenParameters);
120	db->create(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
121												CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
122							  inDbName, inDbLocation));
123	db->dbInfo(NULL);
124	outDbHandle = makeDbHandle(db);
125	// fprintf(stderr, "%p %p was created for %s in session %p\n", pthread_self(), (void*) outDbHandle, inDbName, this);
126}
127
128void
129SSDLSession::CreateWithBlob(const char *DbName,
130							const CSSM_NET_ADDRESS *DbLocation,
131							const CSSM_DBINFO &DBInfo,
132							CSSM_DB_ACCESS_TYPE AccessRequest,
133							const void *OpenParameters,
134							const CSSM_DATA &blob,
135							CSSM_DB_HANDLE &DbHandle)
136{
137	SSDatabase db(mClientSession, mDL, DbName, DbLocation);
138	db->dbInfo(&DBInfo);
139	db->accessRequest(AccessRequest);
140	db->resourceControlContext(NULL);
141	db->openParameters(OpenParameters);
142	db->createWithBlob(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
143									  CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
144									  DbName, DbLocation),
145					   blob);
146	db->dbInfo(NULL);
147	DbHandle = makeDbHandle(db);
148	// fprintf(stderr, "%p %p was created with a blob in session %p\n", pthread_self(), (void*) DbHandle, this);
149}
150
151void
152SSDLSession::DbOpen(const char *inDbName,
153					const CSSM_NET_ADDRESS *inDbLocation,
154					CSSM_DB_ACCESS_TYPE inAccessRequest,
155					const AccessCredentials *inAccessCred,
156					const void *inOpenParameters,
157					CSSM_DB_HANDLE &outDbHandle)
158{
159	SSDatabase db(mClientSession, mDL, inDbName, inDbLocation);
160	db->accessRequest(inAccessRequest);
161	db->accessCredentials(inAccessCred);
162	db->openParameters(inOpenParameters);
163	db->open(DLDbIdentifier(CssmSubserviceUid(plugin.myGuid(), &version(), subserviceId(),
164											  CSSM_SERVICE_DL | CSSM_SERVICE_CSP),
165							inDbName, inDbLocation));
166	outDbHandle = makeDbHandle(db);
167	// fprintf(stderr, "%p %p was opened for %s in session %p\n", pthread_self(), (void*) outDbHandle, inDbName, this);
168}
169
170// Operations using DbContext instances.
171void
172SSDLSession::DbClose(CSSM_DB_HANDLE inDbHandle)
173{
174	killDbHandle(inDbHandle)->close();
175}
176
177void
178SSDLSession::CreateRelation(CSSM_DB_HANDLE inDbHandle,
179							CSSM_DB_RECORDTYPE inRelationID,
180							const char *inRelationName,
181							uint32 inNumberOfAttributes,
182							const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
183							uint32 inNumberOfIndexes,
184							const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo)
185{
186	SSDatabase db = findDbHandle(inDbHandle);
187	// @@@ Fix inAttributeInfo and inIndexInfo arguments (might be NULL if NumberOf = 0)
188	db->createRelation(inRelationID, inRelationName,
189					  inNumberOfAttributes, inAttributeInfo,
190					  inNumberOfIndexes, &inIndexInfo);
191}
192
193void
194SSDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle,
195							 CSSM_DB_RECORDTYPE inRelationID)
196{
197	// @@@ Check credentials.
198	SSDatabase db = findDbHandle(inDbHandle);
199	db->destroyRelation(inRelationID);
200}
201
202void
203SSDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle,
204						  CSSM_DB_ACCESS_TYPE inAccessRequest,
205						  const AccessCredentials &inAccessCred)
206{
207	SSDatabase db = findDbHandle(inDbHandle);
208	db->authenticate(inAccessRequest, &inAccessCred);
209}
210
211
212void
213SSDLSession::GetDbAcl(CSSM_DB_HANDLE inDbHandle,
214					  const CSSM_STRING *inSelectionTag,
215					  uint32 &outNumberOfAclInfos,
216					  CSSM_ACL_ENTRY_INFO_PTR &outAclInfos)
217{
218	SSDatabase db = findDbHandle(inDbHandle);
219	mClientSession.getDbAcl(db->dbHandle(),
220		inSelectionTag ? *inSelectionTag : NULL,
221		outNumberOfAclInfos, AclEntryInfo::overlayVar(outAclInfos), allocator());
222}
223
224void
225SSDLSession::ChangeDbAcl(CSSM_DB_HANDLE inDbHandle,
226						 const AccessCredentials &inAccessCred,
227						 const CSSM_ACL_EDIT &inAclEdit)
228{
229	SSDatabase db = findDbHandle(inDbHandle);
230	mClientSession.changeDbAcl(db->dbHandle(), inAccessCred, AclEdit::overlay(inAclEdit));
231}
232
233void
234SSDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle,
235						CSSM_ACL_OWNER_PROTOTYPE &outOwner)
236{
237	SSDatabase db = findDbHandle(inDbHandle);
238	mClientSession.getDbOwner(db->dbHandle(),
239		AclOwnerPrototype::overlay(outOwner), allocator());
240}
241
242void
243SSDLSession::ChangeDbOwner(CSSM_DB_HANDLE inDbHandle,
244						   const AccessCredentials &inAccessCred,
245						   const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner)
246{
247	SSDatabase db = findDbHandle(inDbHandle);
248	mClientSession.changeDbOwner(db->dbHandle(), inAccessCred,
249		AclOwnerPrototype::overlay(inNewOwner));
250}
251
252void
253SSDLSession::GetDbNameFromHandle(CSSM_DB_HANDLE inDbHandle,
254                                 char **outDbName)
255{
256	SSDatabase db = findDbHandle(inDbHandle);
257	// @@@ Fix this functions signature.
258	db->name(*outDbName);
259}
260
261void
262SSDLSession::DataInsert(CSSM_DB_HANDLE inDbHandle,
263						CSSM_DB_RECORDTYPE inRecordType,
264						const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
265						const CssmData *inData,
266						CSSM_DB_UNIQUE_RECORD_PTR &outUniqueId)
267{
268	SSDatabase db = findDbHandle(inDbHandle);
269	// @@@ Fix client lib.
270    SSUniqueRecord uniqueId = db->insert(inRecordType, inAttributes, inData, true); // @@@ Fix me
271	outUniqueId = makeSSUniqueRecord(uniqueId);
272	// @@@ If this is a key do the right thing.
273}
274
275void
276SSDLSession::DataDelete(CSSM_DB_HANDLE inDbHandle,
277						const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
278{
279	SSDatabase db = findDbHandle(inDbHandle);
280	SSUniqueRecord uniqueId = findSSUniqueRecord(inUniqueRecordIdentifier);
281	uniqueId->deleteRecord();
282	// @@@ If this is a key do the right thing.
283}
284
285
286void
287SSDLSession::DataModify(CSSM_DB_HANDLE inDbHandle,
288						CSSM_DB_RECORDTYPE inRecordType,
289						CSSM_DB_UNIQUE_RECORD &inoutUniqueRecordIdentifier,
290						const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
291						const CssmData *inDataToBeModified,
292						CSSM_DB_MODIFY_MODE inModifyMode)
293{
294	SSDatabase db = findDbHandle(inDbHandle);
295	SSUniqueRecord uniqueId = findSSUniqueRecord(inoutUniqueRecordIdentifier);
296	uniqueId->modify(inRecordType, inAttributesToBeModified, inDataToBeModified, inModifyMode);
297	// @@@ If this is a key do the right thing.
298}
299
300CSSM_HANDLE
301SSDLSession::DataGetFirst(CSSM_DB_HANDLE inDbHandle,
302						  const CssmQuery *inQuery,
303						  CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
304						  CssmData *inoutData,
305						  CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
306{
307	SSDatabase db = findDbHandle(inDbHandle);
308	CSSM_HANDLE resultsHandle = CSSM_INVALID_HANDLE;
309    SSUniqueRecord uniqueId(db);
310
311	// Setup so we always retrive the attributes even if the client
312	// doesn't want them so we can figure out if we just retrived a key.
313	CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
314	CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
315	if (inoutAttributes)
316		pAttributes = inoutAttributes;
317	else
318	{
319		pAttributes = &attributes;
320		memset(pAttributes, 0, sizeof(attributes));
321	}
322
323	// Retrive the record.
324	CSSM_RETURN result = CSSM_DL_DataGetFirst(db->handle(), inQuery, &resultsHandle,
325											  pAttributes, inoutData, uniqueId);
326	if (result)
327	{
328		if (result == CSSMERR_DL_ENDOFDATA)
329			return CSSM_INVALID_HANDLE;
330
331		CssmError::throwMe(result);
332	}
333
334	uniqueId->activate();
335
336	// If we the client didn't ask for data then it doesn't matter
337	// if this record is a key or not, just return it.
338	if (inoutData)
339	{
340		if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
341			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
342			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
343		{
344			// This record is a key, do the right thing (tm).
345			// Allocate storage for the key.
346            CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
347			new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
348
349			// Free the data we retrived (keyblob)
350			allocator().free(inoutData->Data);
351
352			// Set the length and data on the data we return to the client
353			inoutData->Length = sizeof(*outKey);
354			inoutData->Data = reinterpret_cast<uint8 *>(outKey);
355		}
356	}
357
358	outUniqueRecord = makeSSUniqueRecord(uniqueId);
359	return resultsHandle;
360}
361
362bool
363SSDLSession::DataGetNext(CSSM_DB_HANDLE inDbHandle,
364						 CSSM_HANDLE inResultsHandle,
365						 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
366						 CssmData *inoutData,
367						 CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
368{
369	// @@@ If this is a key do the right thing.
370	SSDatabase db = findDbHandle(inDbHandle);
371    SSUniqueRecord uniqueId(db);
372
373	// Setup so we always retrive the attributes even if the client
374	// doesn't want them so we can figure out if we just retrived a key.
375	CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
376	CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
377	if (inoutAttributes)
378		pAttributes = inoutAttributes;
379	else
380	{
381		pAttributes = &attributes;
382		memset(pAttributes, 0, sizeof(attributes));
383	}
384
385	CSSM_RETURN result = CSSM_DL_DataGetNext(db->handle(), inResultsHandle,
386											 inoutAttributes, inoutData, uniqueId);
387	if (result)
388	{
389		if (result == CSSMERR_DL_ENDOFDATA)
390			return false;
391
392		CssmError::throwMe(result);
393	}
394
395	uniqueId->activate();
396
397	// If we the client didn't ask for data then it doesn't matter
398	// if this record is a key or not, just return it.
399	if (inoutData)
400	{
401		if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
402			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
403			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
404		{
405			// This record is a key, do the right thing (tm).
406			// Allocate storage for the key.
407			CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
408			new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
409
410			// Free the data we retrived (keyblob)
411			allocator().free(inoutData->Data);
412
413			// Set the length and data on the data we return to the client
414			inoutData->Length = sizeof(*outKey);
415			inoutData->Data = reinterpret_cast<uint8 *>(outKey);
416		}
417	}
418
419	outUniqueRecord = makeSSUniqueRecord(uniqueId);
420
421	return true;
422}
423
424void
425SSDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle,
426							CSSM_HANDLE inResultsHandle)
427{
428	// @@@ If this is a key do the right thing.
429	SSDatabase db = findDbHandle(inDbHandle);
430	CSSM_RETURN result = CSSM_DL_DataAbortQuery(db->handle(), inResultsHandle);
431	if (result)
432		CssmError::throwMe(result);
433}
434
435void
436SSDLSession::DataGetFromUniqueRecordId(CSSM_DB_HANDLE inDbHandle,
437									   const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
438									   CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
439									   CssmData *inoutData)
440{
441	SSDatabase db = findDbHandle(inDbHandle);
442	const SSUniqueRecord uniqueId = findSSUniqueRecord(inUniqueRecord);
443
444	// Setup so we always retrive the attributes even if the client
445	// doesn't want them so we can figure out if we just retrived a key.
446	CSSM_DB_RECORD_ATTRIBUTE_DATA attributes;
447	CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes;
448	if (inoutAttributes)
449		pAttributes = inoutAttributes;
450	else
451	{
452		pAttributes = &attributes;
453		memset(pAttributes, 0, sizeof(attributes));
454	}
455
456	CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(),
457		uniqueId, pAttributes, inoutData);
458	if (result)
459		CssmError::throwMe(result);
460
461	if (inoutData)
462	{
463		if (pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PUBLIC_KEY
464			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_PRIVATE_KEY
465			|| pAttributes->DataRecordType == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
466		{
467			// This record is a key, do the right thing (tm).
468			// Allocate storage for the key.
469			CssmKey *outKey = DatabaseSession::alloc<CssmKey>();
470			new SSKey(*this, *outKey, db, uniqueId, pAttributes->DataRecordType, *inoutData);
471
472			// Free the data we retrived (keyblob)
473			allocator().free(inoutData->Data);
474
475			// Set the length and data on the data we return to the client
476			inoutData->Length = sizeof(*outKey);
477			inoutData->Data = reinterpret_cast<uint8 *>(outKey);
478		}
479	}
480}
481
482void
483SSDLSession::FreeUniqueRecord(CSSM_DB_HANDLE inDbHandle,
484							  CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
485{
486	killSSUniqueRecord(inUniqueRecordIdentifier);
487}
488
489#pragma clang diagnostic push
490#pragma clang diagnostic ignored "-Wunused-const-variable"
491
492static const uint32 kGenericAttributeNames[] =
493{
494	'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'svce',
495	'gena'
496};
497
498const uint32 kNumGenericAttributes = sizeof (kGenericAttributeNames) / sizeof (uint32);
499
500static const uint32 kApplesharePasswordNames[] =
501{
502	'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'vlme',
503	'srvr', 'ptcl', 'addr', 'ssig'
504};
505
506const uint32 kNumApplesharePasswordAttributes = sizeof (kApplesharePasswordNames) / sizeof (uint32);
507
508static const uint32 kInternetPasswordNames[] =
509{
510	'cdat', 'mdat', 'desc', 'icmt', 'crtr', 'type', 'scrp', 7, 8, 'invi', 'nega', 'cusi', 'prot', 'acct', 'sdmn',
511	'srvr', 'ptcl', 'atyp', 'port', 'path'
512};
513
514const uint32 kNumInternetPasswordAttributes = sizeof (kInternetPasswordNames) / sizeof (uint32);
515
516const uint32 kKeyAttributeNames[] =
517{
518	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
519};
520
521const uint32 kNumKeyAttributes = sizeof (kKeyAttributeNames) / sizeof (uint32);
522
523const uint32 kCertificateAttributeNames[] =
524{
525	'ctyp', 'cenc', 'labl', 'alis', 'subj', 'issu', 'snbr', 'skid', 'hpky'
526};
527
528const uint32 kNumCertificateAttributes = sizeof (kCertificateAttributeNames) / sizeof (uint32);
529
530const unsigned kSymmetricKeyLabel = 6; // record id for the symmetric key
531const unsigned kLabelSize = 20;
532const unsigned kNumSymmetricAttributes = 27; // number of attributes to request
533
534#pragma clang diagnostic pop
535
536static void appendUInt32ToData (const uint32 value, CssmDataContainer &data)
537{
538	data.append (CssmPolyData (uint32 (htonl (value))));
539}
540
541static inline uint32 GetUInt32AtFinger (uint8 *&finger)
542{
543	uint32 a = ((finger[0] << 24) | (finger[1] << 16) | (finger[2] << 8) | finger[3]);
544	finger += sizeof (uint32);
545	return a;
546}
547
548void
549SSDLSession::unwrapAttributesAndData (uint32 &numAttributes,
550									  CSSM_DB_ATTRIBUTE_DATA_PTR &attributes,
551									  CSSM_DATA &data,
552									  CSSM_DATA &input)
553{
554	// get the number of attributes
555	uint8* finger = input.Data;
556	numAttributes = GetUInt32AtFinger (finger);
557
558	// compute the end of the data for sanity checking later
559	uint8* maximum = input.Data + input.Length;
560
561	// make the attribute array
562	attributes = (CSSM_DB_ATTRIBUTE_DATA*) allocator ().malloc (numAttributes * sizeof (CSSM_DB_ATTRIBUTE_DATA));
563
564	// for each attribute, retrieve the name format, name, type, and number of values
565	unsigned i;
566	for (i = 0; i < numAttributes; ++i)
567	{
568		attributes[i].Info.AttributeNameFormat = GetUInt32AtFinger (finger);
569		attributes[i].Info.Label.AttributeID = GetUInt32AtFinger (finger);
570		attributes[i].Info.AttributeFormat = GetUInt32AtFinger (finger);
571		attributes[i].NumberOfValues = GetUInt32AtFinger (finger);
572
573		// for each value, get the length and data
574		attributes[i].Value = (CSSM_DATA*) allocator ().malloc (sizeof (CSSM_DATA) * attributes[i].NumberOfValues);
575		unsigned j;
576		for (j = 0; j < attributes[i].NumberOfValues; ++j)
577		{
578			attributes[i].Value[j].Length = GetUInt32AtFinger (finger);
579			if (attributes[i].Value[j].Length != 0)
580			{
581				// sanity check what we are about to do
582				if (finger > maximum || finger + attributes[i].Value[j].Length > maximum)
583				{
584					CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
585				}
586
587				attributes[i].Value[j].Data = (uint8*) allocator ().malloc (attributes[i].Value[j].Length);
588
589				switch (attributes[i].Info.AttributeFormat)
590				{
591					default:
592					{
593						memmove (attributes[i].Value[j].Data, finger, attributes[i].Value[j].Length);
594						finger += attributes[i].Value[j].Length;
595						break;
596					}
597
598					case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
599					case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
600					{
601						*(uint32*) attributes[i].Value[j].Data = GetUInt32AtFinger (finger);
602						break;
603					}
604
605					case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
606					{
607						uint32* d = (uint32*) attributes[i].Value[j].Data;
608						unsigned long numValues = attributes[i].Value[j].Length / sizeof (UInt32);
609						while (numValues--)
610						{
611							*d++ = GetUInt32AtFinger (finger);
612						}
613						break;
614					}
615				}
616			}
617			else
618			{
619				attributes[i].Value[j].Data = NULL;
620			}
621		}
622	}
623
624	// get the data
625	data.Length = GetUInt32AtFinger (finger);
626	if (data.Length != 0)
627	{
628		// sanity check the pointer
629		if (finger + data.Length > maximum)
630		{
631			CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
632		}
633
634		data.Data = (uint8*) allocator ().malloc (data.Length);
635		memmove (data.Data, finger, data.Length);
636		finger += data.Length;
637	}
638	else
639	{
640		data.Data = NULL;
641	}
642}
643
644void
645SSDLSession::getWrappedAttributesAndData (SSDatabase &db,
646										  CSSM_DB_RECORDTYPE recordType,
647										  CSSM_DB_UNIQUE_RECORD_PTR recordPtr,
648										  CssmDataContainer &output,
649										  CSSM_DATA *dataBlob)
650{
651	// figure out which attributes to use
652	const uint32* attributeNameArray;
653	uint32 numAttributeNames;
654
655	switch (recordType)
656	{
657		case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
658		{
659			attributeNameArray = kGenericAttributeNames;
660			numAttributeNames = kNumGenericAttributes;
661			break;
662		}
663
664		case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
665		{
666			attributeNameArray = kInternetPasswordNames;
667			numAttributeNames = kNumInternetPasswordAttributes;
668			break;
669		}
670
671		case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
672		{
673			attributeNameArray = kApplesharePasswordNames;
674			numAttributeNames = kNumApplesharePasswordAttributes;
675			break;
676		}
677
678		case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
679		{
680			attributeNameArray = kCertificateAttributeNames;
681			numAttributeNames = kNumCertificateAttributes;
682			break;
683		}
684
685		case CSSM_DL_DB_RECORD_PUBLIC_KEY:
686		case CSSM_DL_DB_RECORD_PRIVATE_KEY:
687		case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
688		{
689			attributeNameArray = kKeyAttributeNames;
690			numAttributeNames = kNumKeyAttributes;
691			break;
692		}
693
694		default:
695		{
696			CssmError::throwMe (CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
697		}
698	}
699
700	// make the attribute array
701	size_t arraySize = numAttributeNames * sizeof (CSSM_DB_ATTRIBUTE_DATA);
702
703	CSSM_DB_ATTRIBUTE_DATA_PTR attributes =
704		(CSSM_DB_ATTRIBUTE_DATA_PTR) allocator ().malloc (arraySize);
705
706	// initialize the array
707	memset (attributes, 0, arraySize);
708	unsigned i;
709	for (i = 0; i < numAttributeNames; ++i)
710	{
711		attributes[i].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
712		attributes[i].Info.Label.AttributeID = attributeNameArray[i];
713	}
714
715	// make the attribute record
716	CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
717	attrData.DataRecordType = recordType;
718	attrData.SemanticInformation = 0;
719	attrData.NumberOfAttributes = numAttributeNames;
720	attrData.AttributeData = attributes;
721
722	// get the data
723	CssmDataContainer data;
724	CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId (db->handle (),
725															recordPtr,
726															&attrData,
727															&data);
728	if (result != 0)
729	{
730		CssmError::throwMe (result);
731	}
732
733	// wrap the data -- write the number of attributes
734	appendUInt32ToData (numAttributeNames, output);
735
736	// for each attribute, write the type and number of values
737	for (i = 0; i < numAttributeNames; ++i)
738	{
739		appendUInt32ToData (attributes[i].Info.AttributeNameFormat, output);
740		appendUInt32ToData (attributes[i].Info.Label.AttributeID, output);
741		appendUInt32ToData (attributes[i].Info.AttributeFormat, output);
742		appendUInt32ToData (attributes[i].NumberOfValues, output);
743
744		// for each value, write the name format, name, length and the data
745		unsigned j;
746		for (j = 0; j < attributes[i].NumberOfValues; ++j)
747		{
748			appendUInt32ToData ((uint32)attributes[i].Value[j].Length, output);
749			if (attributes[i].Value[j].Length != 0)
750			{
751				switch (attributes[i].Info.AttributeFormat)
752				{
753					default:
754					{
755						output.append (CssmPolyData (attributes[i].Value[j]));
756						break;
757					}
758
759					case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
760					case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
761					{
762						uint32 n = htonl (*(uint32*) attributes[i].Value[j].Data);
763						CSSM_DATA d;
764						d.Length = sizeof (uint32);
765						d.Data = (uint8*) &n;
766						output.append (CssmPolyData (d));
767						break;
768					}
769				}
770			}
771		}
772	}
773
774	// write the length of the data
775	appendUInt32ToData ((uint32)data.Length, output);
776
777	// write the data itself
778	if (data.Length != 0)
779	{
780		output.append (CssmPolyData (data));
781	}
782
783	// clean up
784	for (i = 0; i < numAttributeNames; ++i)
785	{
786		unsigned j;
787		for (j = 0; j < attributes[i].NumberOfValues; ++j)
788		{
789			allocator ().free (attributes[i].Value[j].Data);
790		}
791
792		allocator ().free (attributes[i].Value);
793	}
794
795	allocator ().free (attributes);
796
797	// copy out the data if the caller needs it
798	if (dataBlob)
799	{
800		dataBlob->Data = data.Data;
801		dataBlob->Length = data.Length;
802		data.Data = NULL;
803		data.Length = 0;
804	}
805}
806
807void
808SSDLSession::getUniqueIdForSymmetricKey (SSDatabase &db, CSSM_DATA &label,
809										 CSSM_DB_UNIQUE_RECORD_PTR &uniqueRecord)
810{
811	// set up a query to get the key
812	CSSM_SELECTION_PREDICATE predicate;
813	predicate.DbOperator = CSSM_DB_EQUAL;
814	predicate.Attribute.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
815	predicate.Attribute.Info.Label.AttributeID = kSymmetricKeyLabel;
816	predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
817	predicate.Attribute.NumberOfValues = 1;
818	// the label of the corresponding key is the first 20 bytes of the blob we returned
819	predicate.Attribute.Value = &label;
820
821	CSSM_QUERY query;
822	query.RecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
823	query.Conjunctive = CSSM_DB_NONE;
824	query.NumSelectionPredicates = 1;
825	query.SelectionPredicate = &predicate;
826
827	// fill out the record data
828	CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttributeData;
829	recordAttributeData.DataRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
830	recordAttributeData.SemanticInformation = 0;
831	recordAttributeData.NumberOfAttributes = 0;
832	recordAttributeData.AttributeData = NULL;
833
834	// get the data
835	CSSM_HANDLE handle;
836	CSSM_RETURN result = CSSM_DL_DataGetFirst (db->handle (), &query, &handle, &recordAttributeData, NULL,
837											   &uniqueRecord);
838	if (result)
839	{
840		CssmError::throwMe (result);
841	}
842
843	// clean up
844	CSSM_DL_DataAbortQuery (db->handle (), handle);
845}
846
847void
848SSDLSession::getCorrespondingSymmetricKey (SSDatabase &db, CSSM_DATA &labelData, CssmDataContainer &data)
849{
850	// get the unique ID
851	CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord;
852	getUniqueIdForSymmetricKey (db, labelData, uniqueRecord);
853
854	// from this. get the wrapped attributes and data
855	getWrappedAttributesAndData (db, CSSM_DL_DB_RECORD_SYMMETRIC_KEY, uniqueRecord, data, NULL);
856
857	// clean up after the query
858	CSSM_DL_FreeUniqueRecord (db->handle (), uniqueRecord);
859}
860
861void SSDLSession::doGetWithoutEncryption (SSDatabase &db, const void *inInputParams, void **outOutputParams)
862{
863	CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS* params =
864		(CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
865
866	SSUniqueRecord uniqueID = findSSUniqueRecord(*(params->uniqueID));
867
868	CSSM_DATA *outputData = (CSSM_DATA*) outOutputParams;
869	CssmDataContainer output;
870
871	// get the record type and requested attributes from the DL
872	CssmDataContainer data;
873	CSSM_RETURN result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(),
874														   uniqueID,
875														   params->attributes,
876														   NULL);
877
878	if (result)
879	{
880		CssmError::throwMe(result);
881	}
882
883	// get the real data and all of the attributes from the DL
884	CssmDataContainer blobData;
885	getWrappedAttributesAndData (db, params->attributes->DataRecordType, uniqueID, data, &blobData);
886
887	// write out the data blob
888	appendUInt32ToData ((uint32)data.Length, output);
889	output.append (CssmPolyData (data));
890
891	// figure out what we need to do with the key blob
892	CssmDataContainer key;
893	switch (params->attributes->DataRecordType)
894	{
895		case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
896		case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
897		case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
898		{
899			// the label is the first kLabelSize bytes of the resultant data blob
900			CSSM_DATA label = {kLabelSize, blobData.Data};
901
902			// get the key
903			getCorrespondingSymmetricKey (db, label, key);
904		}
905		break;
906
907		default:
908		{
909			break;
910		}
911	}
912
913
914	// write out the length of the key blob
915	appendUInt32ToData ((uint32)key.Length, output);
916
917	if (key.Length != 0)
918	{
919		// write the key
920		output.append (CssmPolyData (key));
921	}
922
923	// copy out the results
924	outputData->Data = output.Data;
925	output.Data = NULL;
926	outputData->Length = output.Length;
927	output.Length = 0;
928}
929
930void
931SSDLSession::cleanupAttributes (uint32 numAttributes, CSSM_DB_ATTRIBUTE_DATA_PTR attributes)
932{
933	unsigned i;
934	for (i = 0; i < numAttributes; ++i)
935	{
936		unsigned j;
937		for (j = 0; j < attributes[i].NumberOfValues; ++j)
938		{
939			free (attributes[i].Value[j].Data);
940		}
941
942		free (attributes[i].Value);
943	}
944
945	free (attributes);
946}
947
948void
949SSDLSession::doModifyWithoutEncryption (SSDatabase &db, const void* inInputParams, void** outOutputParams)
950{
951	CSSM_RETURN result;
952	CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS* params =
953		(CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
954
955	// extract the data for this modify.
956	uint8* finger = params->data->Data;
957	CSSM_DATA data;
958	data.Length = GetUInt32AtFinger (finger);
959	data.Data = finger;
960	if (data.Length + sizeof (UInt32) > params->data->Length)
961	{
962		CssmError::throwMe (CSSM_ERRCODE_INVALID_POINTER);
963	}
964
965	// point to the key
966	finger += data.Length;
967
968	// reconstruct the attributes and data
969	uint32 numAttributes;
970	CSSM_DB_ATTRIBUTE_DATA_PTR attributes;
971	CssmDataContainer dataBlob;
972
973	unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
974
975	CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
976	attrData.DataRecordType = params->attributes->DataRecordType;
977	attrData.SemanticInformation = 0;
978	attrData.NumberOfAttributes = numAttributes;
979	attrData.AttributeData = attributes;
980
981	// get the unique ID for this record (from the db's perspective)
982	SSUniqueRecord uniqueID = findSSUniqueRecord(*(params->uniqueID));
983	CSSM_DB_UNIQUE_RECORD *uniqueIDPtr = uniqueID; // for readability.  There's cast overloading
984												   // going on here.
985
986	switch (attrData.DataRecordType)
987	{
988		case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
989		case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
990		case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
991		{
992			// read off the data so that we can update the key
993			CssmDataContainer oldData;
994			result = CSSM_DL_DataGetFromUniqueRecordId (db->handle(),
995														uniqueIDPtr,
996														NULL,
997														&oldData);
998			if (result)
999			{
1000				CssmError::throwMe (result);
1001			}
1002
1003			CSSM_DB_MODIFY_MODE modifyMode = params->modifyMode;
1004
1005			// parse the key data blob
1006			CssmDataContainer keyBlob;
1007			data.Length = GetUInt32AtFinger (finger);
1008			data.Data = finger;
1009
1010			CSSM_DB_RECORD_ATTRIBUTE_DATA* attrDataPtr = NULL;
1011			CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
1012
1013			CSSM_DATA labelData = {kLabelSize, oldData.Data};
1014			CSSM_DB_UNIQUE_RECORD_PTR recordID;
1015			getUniqueIdForSymmetricKey (db, labelData, recordID);
1016
1017			CSSM_DB_ATTRIBUTE_DATA_PTR keyAttributes;
1018			uint32 numKeyAttributes;
1019			unwrapAttributesAndData (numKeyAttributes, keyAttributes, keyBlob, data);
1020
1021			// make the attribute data
1022			attrData.DataRecordType = params->recordType;
1023			attrData.SemanticInformation = 0;
1024			attrData.NumberOfAttributes = numKeyAttributes;
1025			attrData.AttributeData = keyAttributes;
1026
1027			attrDataPtr = &attrData;
1028
1029			result = CSSM_DL_DataModify (db->handle(),
1030							 CSSM_DL_DB_RECORD_SYMMETRIC_KEY,
1031							 recordID,
1032							 attrDataPtr,
1033							 &keyBlob,
1034							 modifyMode);
1035
1036			// clean up
1037			CSSM_DL_FreeUniqueRecord (db->handle (), recordID);
1038
1039			cleanupAttributes (numKeyAttributes, keyAttributes);
1040			break;
1041		}
1042
1043		default:
1044		{
1045			break;
1046		}
1047	}
1048
1049	// save off the new data
1050	result = CSSM_DL_DataModify(db->handle(),
1051								params->recordType,
1052								uniqueIDPtr,
1053								&attrData,
1054								&dataBlob,
1055								params->modifyMode);
1056
1057	// clean up
1058	cleanupAttributes (numAttributes, attributes);
1059
1060	if (result)
1061	{
1062		CssmError::throwMe(result);
1063	}
1064
1065}
1066
1067void
1068SSDLSession::doInsertWithoutEncryption (SSDatabase &db, const void* inInputParams, void** outOutputParams)
1069{
1070	CSSM_RETURN result;
1071
1072	CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS* params =
1073		(CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS*) inInputParams;
1074
1075	// extract the data for this insert.
1076	uint8* finger = params->data.Data;
1077	CSSM_DATA data;
1078	data.Length = GetUInt32AtFinger (finger);
1079	data.Data = finger;
1080	finger += data.Length;
1081
1082	// reconstruct the attributes and data
1083	uint32 numAttributes;
1084	CSSM_DB_ATTRIBUTE_DATA_PTR attributes;
1085	CSSM_DATA dataBlob;
1086
1087	unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
1088
1089	// make the attribute data
1090	CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
1091	attrData.DataRecordType = params->recordType;
1092	attrData.SemanticInformation = 0;
1093	attrData.NumberOfAttributes = numAttributes;
1094	attrData.AttributeData = attributes;
1095
1096	// insert into the database
1097	SSUniqueRecord uniqueID (db);
1098	result = CSSM_DL_DataInsert (db->handle(), params->recordType,
1099								 &attrData,
1100								 &dataBlob,
1101								 uniqueID);
1102
1103	// cleanup
1104	allocator ().free (dataBlob.Data);
1105	cleanupAttributes (numAttributes, attributes);
1106
1107	// attach into the CSP/DL mechanism
1108	CSSM_DB_UNIQUE_RECORD_PTR newRecord = makeSSUniqueRecord(uniqueID);
1109	*(CSSM_DB_UNIQUE_RECORD_PTR*) outOutputParams = newRecord;
1110
1111	if (result)
1112	{
1113		CssmError::throwMe(result);
1114	}
1115
1116	// Get the key data for this insert
1117	data.Length = GetUInt32AtFinger (finger);
1118	if (data.Length != 0)
1119	{
1120		data.Data = finger;
1121
1122		// parse the key data blob
1123		unwrapAttributesAndData (numAttributes, attributes, dataBlob, data);
1124
1125		// make the attribute data
1126		CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
1127		attrData.DataRecordType = params->recordType;
1128		attrData.SemanticInformation = 0;
1129		attrData.NumberOfAttributes = numAttributes;
1130		attrData.AttributeData = attributes;
1131
1132		// insert the key data into the symmetric key table
1133		CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord;
1134		result = CSSM_DL_DataInsert (db->handle(), CSSM_DL_DB_RECORD_SYMMETRIC_KEY, &attrData, &dataBlob,
1135									 &uniqueRecord);
1136		if (result)
1137		{
1138			CssmError::throwMe (result);
1139		}
1140
1141		// clean up after inserting the key
1142		CSSM_DL_FreeUniqueRecord (db->handle (), uniqueRecord);
1143		allocator ().free (dataBlob.Data);
1144		cleanupAttributes (numAttributes, attributes);
1145	}
1146}
1147
1148void
1149SSDLSession::doConvertRecordIdentifier (SSDatabase &db, const void *inInputParams, void **outOutputParams)
1150{
1151	SSUniqueRecord uniqueId (db);
1152
1153	// clone the unique record
1154	CSSM_DB_UNIQUE_RECORD_PTR clone = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
1155	*clone = *(CSSM_DB_UNIQUE_RECORD_PTR) inInputParams;
1156
1157	// set the value of the unique record
1158	uniqueId->setUniqueRecordPtr (clone);
1159
1160	// byte swap the retrieved record pointer to host order
1161	uint32* idArray = (uint32*) clone->RecordIdentifier.Data;
1162	idArray[0] = ntohl (idArray[0]);
1163	idArray[1] = ntohl (idArray[1]);
1164	idArray[2] = ntohl (idArray[2]);
1165
1166	CSSM_DB_UNIQUE_RECORD_PTR newRecord = makeSSUniqueRecord(uniqueId);
1167	*(CSSM_DB_UNIQUE_RECORD_PTR*) outOutputParams = newRecord;
1168}
1169
1170void
1171SSDLSession::PassThrough(CSSM_DB_HANDLE inDbHandle,
1172						 uint32 inPassThroughId,
1173						 const void *inInputParams,
1174						 void **outOutputParams)
1175{
1176	if (inPassThroughId == CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB)
1177	{
1178		CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS* params = (CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS*) inInputParams;
1179		CreateWithBlob(params->dbName, params->dbLocation, *params->dbInfo, params->accessRequest, params->openParameters, *params->blob,
1180					   * (CSSM_DB_HANDLE*) outOutputParams);
1181		return;
1182	}
1183
1184	SSDatabase db = findDbHandle(inDbHandle);
1185	switch (inPassThroughId)
1186	{
1187		case CSSM_APPLECSPDL_DB_LOCK:
1188			db->lock();
1189			break;
1190		case CSSM_APPLECSPDL_DB_UNLOCK:
1191			if (inInputParams)
1192				db->unlock(*reinterpret_cast<const CSSM_DATA *>(inInputParams));
1193			else
1194				db->unlock();
1195			break;
1196		case CSSM_APPLECSPDL_DB_STASH:
1197            db->stash();
1198            break;
1199        case CSSM_APPLECSPDL_DB_STASH_CHECK:
1200            db->stashCheck();
1201            break;
1202        case CSSM_APPLECSPDL_DB_GET_SETTINGS:
1203		{
1204			if (!outOutputParams)
1205				CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
1206
1207			CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR params =
1208            DatabaseSession::alloc<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS>();
1209			try
1210			{
1211				uint32 idleTimeout;
1212				bool lockOnSleep;
1213				db->getSettings(idleTimeout, lockOnSleep);
1214				params->idleTimeout = idleTimeout;
1215				params->lockOnSleep = lockOnSleep;
1216			}
1217			catch(...)
1218			{
1219				allocator().free(params);
1220				throw;
1221			}
1222			*reinterpret_cast<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR *>(outOutputParams) = params;
1223			break;
1224		}
1225		case CSSM_APPLECSPDL_DB_SET_SETTINGS:
1226		{
1227			if (!inInputParams)
1228				CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
1229
1230			const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS *params =
1231				reinterpret_cast<const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS *>(inInputParams);
1232			db->setSettings(params->idleTimeout, params->lockOnSleep);
1233			break;
1234		}
1235		case CSSM_APPLECSPDL_DB_IS_LOCKED:
1236		{
1237			if (!outOutputParams)
1238				CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
1239
1240			CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params =
1241            DatabaseSession::alloc<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS>();
1242			try
1243			{
1244				params->isLocked = db->isLocked();
1245			}
1246			catch(...)
1247			{
1248				allocator().free(params);
1249				throw;
1250			}
1251			*reinterpret_cast<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR *>(outOutputParams) = params;
1252			break;
1253		}
1254		case CSSM_APPLECSPDL_DB_CHANGE_PASSWORD:
1255		{
1256			if (!inInputParams)
1257				CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
1258
1259			const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *params =
1260				reinterpret_cast<const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *>(inInputParams);
1261			db->changePassphrase(params->accessCredentials);
1262			break;
1263		}
1264		case CSSM_APPLECSPDL_DB_GET_HANDLE:
1265		{
1266			using SecurityServer::DbHandle;
1267			Required(outOutputParams, CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
1268			*reinterpret_cast<CSSM_DL_DB_HANDLE *>(outOutputParams) = db->handle();
1269			break;
1270		}
1271		case CSSM_APPLECSPDL_CSP_RECODE:
1272		{
1273			if (!inInputParams)
1274				CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
1275
1276			const CSSM_APPLECSPDL_RECODE_PARAMETERS *params =
1277				reinterpret_cast<const CSSM_APPLECSPDL_RECODE_PARAMETERS *>(inInputParams);
1278
1279			db->recode(CssmData::overlay(params->dbBlob),
1280				CssmData::overlay(params->extraData));
1281			break;
1282		}
1283		case CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER:
1284		{
1285			SSUniqueRecord uniqueID = findSSUniqueRecord(*(CSSM_DB_UNIQUE_RECORD_PTR) inInputParams);
1286			db->getRecordIdentifier(uniqueID, *reinterpret_cast<CSSM_DATA *>(outOutputParams));
1287			break;
1288		}
1289		case CSSM_APPLECSPDL_DB_COPY_BLOB:
1290		{
1291			// make the output parameters
1292			db->copyBlob(*reinterpret_cast<CSSM_DATA *>(outOutputParams));
1293			break;
1294		}
1295		case CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION:
1296		{
1297			doInsertWithoutEncryption (db, inInputParams, outOutputParams);
1298			break;
1299		}
1300		case CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION:
1301		{
1302			doModifyWithoutEncryption (db, inInputParams, outOutputParams);
1303			break;
1304		}
1305		case CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION:
1306		{
1307			doGetWithoutEncryption (db, inInputParams, outOutputParams);
1308			break;
1309		}
1310		case CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER:
1311		{
1312			doConvertRecordIdentifier (db, inInputParams, outOutputParams);
1313			break;
1314		}
1315		default:
1316		{
1317			CSSM_RETURN result = CSSM_DL_PassThrough(db->handle(), inPassThroughId, inInputParams, outOutputParams);
1318			if (result)
1319				CssmError::throwMe(result);
1320			break;
1321		}
1322	}
1323}
1324
1325CSSM_DB_HANDLE
1326SSDLSession::makeDbHandle(SSDatabase &inDb)
1327{
1328	StLock<Mutex> _(mDbHandleLock);
1329	CSSM_DB_HANDLE aDbHandle = inDb->handle().DBHandle;
1330	bool inserted;
1331    inserted = mDbHandleMap.insert(DbHandleMap::value_type(aDbHandle, inDb)).second;
1332	assert(inserted);
1333	// fprintf(stderr, "%p Added %p to %p\n", pthread_self(), (void*) aDbHandle, (void*) this);
1334	return aDbHandle;
1335}
1336
1337SSDatabase
1338SSDLSession::killDbHandle(CSSM_DB_HANDLE inDbHandle)
1339{
1340	StLock<Mutex> _(mDbHandleLock);
1341	DbHandleMap::iterator it = mDbHandleMap.find(inDbHandle);
1342	if (it == mDbHandleMap.end())
1343	{
1344		// fprintf(stderr, "Can't find %p in %p\n", (void*) inDbHandle, this);
1345		CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
1346	}
1347
1348	SSDatabase db = it->second;
1349	// fprintf(stderr, "%p Removed %p from %p\n", pthread_self(), (void*) it->first, (void*) this);
1350	mDbHandleMap.erase(it);
1351	return db;
1352}
1353
1354SSDatabase
1355SSDLSession::findDbHandle(CSSM_DB_HANDLE inDbHandle)
1356{
1357	StLock<Mutex> _(mDbHandleLock);
1358	// fprintf(stderr, "%p Looking for %p in %p\n", pthread_self(), (void*) inDbHandle, (void*) this);
1359	DbHandleMap::iterator it = mDbHandleMap.find(inDbHandle);
1360	if (it == mDbHandleMap.end())
1361	{
1362		// fprintf(stderr, "%p Can't find %p in %p\n", pthread_self(), (void*) inDbHandle, this);
1363		DbHandleMap::iterator it = mDbHandleMap.begin();
1364		while (it != mDbHandleMap.end())
1365		{
1366			// fprintf(stderr, "\t%p\n", (void*) it->first);
1367			it++;
1368		}
1369
1370		CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
1371	}
1372
1373	return it->second;
1374}
1375
1376CSSM_DB_UNIQUE_RECORD_PTR
1377SSDLSession::makeSSUniqueRecord(SSUniqueRecord &uniqueId)
1378{
1379	StLock<Mutex> _(mSSUniqueRecordLock);
1380	CSSM_HANDLE ref = CSSM_HANDLE(static_cast<CSSM_DB_UNIQUE_RECORD *>(uniqueId));
1381	bool inserted;
1382    inserted = mSSUniqueRecordMap.insert(SSUniqueRecordMap::value_type(ref, uniqueId)).second;
1383	assert(inserted);
1384	return createUniqueRecord(ref);
1385}
1386
1387SSUniqueRecord
1388SSDLSession::killSSUniqueRecord(CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
1389{
1390	CSSM_HANDLE ref = parseUniqueRecord(inUniqueRecord);
1391	StLock<Mutex> _(mSSUniqueRecordLock);
1392	SSUniqueRecordMap::iterator it = mSSUniqueRecordMap.find(ref);
1393	if (it == mSSUniqueRecordMap.end())
1394		CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
1395
1396	SSUniqueRecord uniqueRecord = it->second;
1397	mSSUniqueRecordMap.erase(it);
1398	freeUniqueRecord(inUniqueRecord);
1399	return uniqueRecord;
1400}
1401
1402SSUniqueRecord
1403SSDLSession::findSSUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
1404{
1405	CSSM_HANDLE ref = parseUniqueRecord(inUniqueRecord);
1406	StLock<Mutex> _(mSSUniqueRecordLock);
1407	SSUniqueRecordMap::iterator it = mSSUniqueRecordMap.find(ref);
1408	if (it == mSSUniqueRecordMap.end())
1409		CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
1410
1411	return it->second;
1412}
1413
1414CSSM_DB_UNIQUE_RECORD_PTR
1415SSDLSession::createUniqueRecord(CSSM_HANDLE ref)
1416{
1417	CSSM_DB_UNIQUE_RECORD *aUniqueRecord = DatabaseSession::alloc<CSSM_DB_UNIQUE_RECORD>();
1418	memset(aUniqueRecord, 0, sizeof(CSSM_DB_UNIQUE_RECORD));
1419	aUniqueRecord->RecordIdentifier.Length = sizeof(CSSM_HANDLE);
1420	try
1421	{
1422		aUniqueRecord->RecordIdentifier.Data = DatabaseSession::alloc<uint8>(sizeof(CSSM_HANDLE));
1423		*reinterpret_cast<CSSM_HANDLE *>(aUniqueRecord->RecordIdentifier.Data) = ref;
1424	}
1425	catch(...)
1426	{
1427		free(aUniqueRecord);
1428		throw;
1429	}
1430
1431	return aUniqueRecord;
1432}
1433
1434CSSM_HANDLE
1435SSDLSession::parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
1436{
1437	if (inUniqueRecord.RecordIdentifier.Length != sizeof(CSSM_HANDLE))
1438		CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
1439
1440	return *reinterpret_cast<CSSM_HANDLE *>(inUniqueRecord.RecordIdentifier.Data);
1441}
1442
1443void
1444SSDLSession::freeUniqueRecord(CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
1445{
1446	if (inUniqueRecord.RecordIdentifier.Length != 0
1447		&& inUniqueRecord.RecordIdentifier.Data != NULL)
1448	{
1449		inUniqueRecord.RecordIdentifier.Length = 0;
1450		allocator().free(inUniqueRecord.RecordIdentifier.Data);
1451	}
1452	allocator().free(&inUniqueRecord);
1453}
1454