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// dlclient - client interface to CSSM DLs and their operations
21//
22#include <security_cdsa_client/dlclient.h>
23#include <security_cdsa_client/aclclient.h>
24#include <Security/cssmapple.h>
25#include <Security/cssmapplePriv.h>
26#include <Security/SecBase.h>
27
28using namespace CssmClient;
29
30#pragma clang diagnostic push
31#pragma clang diagnostic ignored "-Wunused-const-variable"
32// blob type for blobs created by these classes -- done so that we can change the formats later
33const uint32 kBlobType = 0x1;
34#pragma clang diagnostic pop
35
36//
37// Abstract classes
38//
39DbMaker::~DbMaker()
40{ /* virtual */ }
41
42DbCursorMaker::~DbCursorMaker()
43{ /* virtual */ }
44
45DbUniqueRecordMaker::~DbUniqueRecordMaker()
46{ /* virtual */ }
47
48
49//
50// Manage DL attachments
51//
52DLImpl::DLImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_DL)
53{
54}
55
56DLImpl::DLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_DL)
57{
58}
59
60DLImpl::~DLImpl()
61{
62}
63
64void
65DLImpl::getDbNames(char **)
66{
67	CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
68}
69
70void
71DLImpl::freeNameList(char **)
72{
73	CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
74}
75
76DbImpl *
77DLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
78{
79	return new DbImpl(DL(this), inDbName, inDbLocation);
80}
81
82
83//
84// Db (database)
85//
86DbImpl::DbImpl(const DL &dl, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
87	: ObjectImpl(dl), mDbName(inDbName, inDbLocation),
88	mUseNameFromHandle(!inDbName), mNameFromHandle(NULL),
89	mAccessRequest(CSSM_DB_ACCESS_READ), mAccessCredentials(NULL),
90	mDefaultCredentials(NULL), mOpenParameters(NULL), mDbInfo(NULL),
91	mResourceControlContext(NULL)
92{
93}
94
95DbImpl::~DbImpl()
96{
97	try
98	{
99		if (mNameFromHandle)
100			allocator().free(mNameFromHandle);
101		deactivate();
102	}
103	catch(...) {}
104}
105
106void
107DbImpl::open()
108{
109    {
110        StLock<Mutex> _(mActivateMutex);
111        if (!mActive)
112        {
113            assert(mDbInfo == nil);
114            mHandle.DLHandle = dl()->handle();
115            check(CSSM_DL_DbOpen(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
116                                    mAccessRequest, mAccessCredentials,
117                                    mOpenParameters, &mHandle.DBHandle));
118
119            mActive = true;
120        }
121	}
122
123    if (!mAccessCredentials && mDefaultCredentials)
124        if (const AccessCredentials *creds = mDefaultCredentials->makeCredentials())
125            CSSM_DL_Authenticate(handle(), mAccessRequest, creds);	// ignore error
126}
127
128void
129DbImpl::createWithBlob(CssmData &blob)
130{
131	if (mActive)
132		CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
133
134	if (mDbInfo == nil) {
135		// handle a missing (null) mDbInfo as an all-zero one
136		static const CSSM_DBINFO nullDbInfo = { };
137		mDbInfo = &nullDbInfo;
138	}
139
140	mHandle.DLHandle = dl()->handle();
141
142	// create a parameter block for our call to the passthrough
143	CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS params;
144
145	params.dbName = mDbName.canonicalName ();
146	params.dbLocation = dbLocation ();
147	params.dbInfo = mDbInfo;
148	params.accessRequest = mAccessRequest;
149	params.credAndAclEntry = NULL;
150	params.openParameters = mOpenParameters;
151	params.blob = &blob;
152
153	check(CSSM_DL_PassThrough (mHandle, CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB, &params, (void**) &mHandle.DBHandle));
154}
155
156void
157DbImpl::create()
158{
159    StLock<Mutex> _(mActivateMutex);
160	if (mActive)
161		CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
162
163	if (mDbInfo == nil) {
164		// handle a missing (null) mDbInfo as an all-zero one
165		static const CSSM_DBINFO nullDbInfo = { };
166		mDbInfo = &nullDbInfo;
167	}
168	mHandle.DLHandle = dl()->handle();
169
170	if (!mResourceControlContext && mAccessCredentials) {
171		AclFactory::AnyResourceContext ctx(mAccessCredentials);
172		check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
173							mDbInfo, mAccessRequest, &ctx,
174							mOpenParameters, &mHandle.DBHandle));
175	} else {
176		check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
177							mDbInfo, mAccessRequest, mResourceControlContext,
178							mOpenParameters, &mHandle.DBHandle));
179	}
180	mActive = true;
181}
182
183void
184DbImpl::close()
185{
186    StLock<Mutex> _(mActivateMutex);
187	if (mActive)
188	{
189		check(CSSM_DL_DbClose (mHandle));
190		mActive = false;
191	}
192}
193
194void
195DbImpl::activate()
196{
197	if (!mActive)
198	{
199		if (mDbInfo)
200			create();
201		else
202			open();
203	}
204}
205
206void
207DbImpl::deactivate()
208{
209    StLock<Mutex> _(mActivateMutex);
210	if (mActive)
211	{
212		mActive = false;
213		close();
214	}
215}
216
217void
218DbImpl::deleteDb()
219{
220	// Deactivate so the db gets closed if it was open.
221	deactivate();
222	// This call does not require the receiver to be active.
223	check(CSSM_DL_DbDelete(dl()->handle(), mDbName.canonicalName(), dbLocation(),
224						   mAccessCredentials));
225}
226
227void
228DbImpl::rename(const char *newName)
229{
230	// Deactivate so the db gets closed if it was open.
231	deactivate();
232    if (::rename(mDbName.canonicalName(), newName))
233		UnixError::throwMe(errno);
234
235	// Change our DbName to reflect this rename.
236	mDbName = DbName(newName, dbLocation());
237}
238
239void
240DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
241					 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
242{
243	if (!mActive)
244	{
245		// XXX Could do the same for create but this would require sticking
246		// inAccessCredentials into mResourceControlContext.
247		if (!mDbInfo)
248		{
249			// We were not yet active.  Just do an open.
250			accessRequest(inAccessRequest);
251			accessCredentials(inAccessCredentials);
252			activate();
253			return;
254		}
255	}
256
257	check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
258}
259
260void
261DbImpl::name(char *&outDbName)
262{
263	check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
264}
265
266const char *
267DbImpl::name()
268{
269	if (mUseNameFromHandle)
270	{
271		if (mNameFromHandle
272		    || !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle))
273		{
274			return mNameFromHandle;
275		}
276
277		// We failed to get the name from the handle so use the passed
278		// in name instead
279		mUseNameFromHandle = false;
280	}
281
282	return mDbName.canonicalName();
283}
284
285void
286DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
287							 const char *inRelationName,
288							 uint32 inNumberOfAttributes,
289							 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
290							 uint32 inNumberOfIndexes,
291							 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
292{
293	check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
294								 inNumberOfAttributes, pAttributeInfo,
295								 inNumberOfIndexes, pIndexInfo));
296}
297
298void
299DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
300{
301	check(CSSM_DL_DestroyRelation(handle(), inRelationID));
302}
303
304DbUniqueRecord
305DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
306				 const CSSM_DATA *data)
307{
308	DbUniqueRecord uniqueId(Db(this));
309	check(CSSM_DL_DataInsert(handle(), recordType,
310							 attributes,
311							 data, uniqueId));
312	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
313	uniqueId->activate();
314	return uniqueId;
315}
316
317
318DbUniqueRecord
319DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
320								CSSM_DATA *data)
321{
322	DbUniqueRecord uniqueId(Db(this));
323
324	// fill out the parameters
325	CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params;
326	params.recordType = recordType;
327	params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
328	params.data = *data;
329
330	// for clarity, call the overloaded operator to produce a unique record pointer
331	CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = uniqueId;
332
333	// make the call
334	passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION, &params, (void**) uniquePtr);
335
336	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
337	uniqueId->activate();
338	return uniqueId;
339}
340
341
342//
343// Generic Passthrough interface
344//
345void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
346{
347	check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
348}
349
350
351//
352// Passthrough functions (only implemented by AppleCSPDL).
353//
354void
355DbImpl::lock()
356{
357	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
358}
359
360void
361DbImpl::unlock()
362{
363	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
364}
365
366void
367DbImpl::unlock(const CSSM_DATA &password)
368{
369	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
370}
371
372void
373DbImpl::stash()
374{
375    check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH, NULL, NULL));
376}
377
378void
379DbImpl::stashCheck()
380{
381    check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH_CHECK, NULL, NULL));
382}
383
384void
385DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
386{
387	CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
388	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
389							  NULL, reinterpret_cast<void **>(&settings)));
390	outIdleTimeout = settings->idleTimeout;
391	outLockOnSleep = settings->lockOnSleep;
392	allocator().free(settings);
393}
394
395void
396DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
397{
398	CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
399	settings.idleTimeout = inIdleTimeout;
400	settings.lockOnSleep = inLockOnSleep;
401	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
402}
403
404bool
405DbImpl::isLocked()
406{
407	CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
408	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
409							  NULL, reinterpret_cast<void **>(&params)));
410	bool isLocked = params->isLocked;
411	allocator().free(params);
412	return isLocked;
413}
414
415void
416DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
417{
418	CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
419	params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
420	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, &params, NULL));
421}
422
423void DbImpl::recode(const CSSM_DATA &data, const CSSM_DATA &extraData)
424{
425	// setup parameters for the recode call
426	CSSM_APPLECSPDL_RECODE_PARAMETERS params;
427	params.dbBlob = data;
428	params.extraData = extraData;
429
430	// do the call
431	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE, &params, NULL));
432}
433
434void DbImpl::copyBlob (CssmData &data)
435{
436	// do the call
437	check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB, NULL, (void**) (CSSM_DATA*) &data));
438}
439
440void DbImpl::setBatchMode(Boolean mode, Boolean rollback)
441{
442	//
443	// We need the DL_DB_Handle of the underyling DL in order to use CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
444	//
445	CSSM_RETURN result;
446	CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL;
447	result = CSSM_DL_PassThrough(handle(),
448								 CSSM_APPLECSPDL_DB_GET_HANDLE,
449								 NULL,
450								 (void **)&dldbHandleOfUnderlyingDL);
451	//
452	// Now, toggle the autocommit...
453	//
454	if ( result == errSecSuccess )
455	{
456		CSSM_BOOL modeToUse = !mode;
457		if (rollback)
458		{
459			result = (OSStatus)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
460										CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
461		}
462
463		result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
464									 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
465									 (void *)((size_t) modeToUse),
466									 NULL);
467		if (!rollback && modeToUse)
468			result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
469									 CSSM_APPLEFILEDL_COMMIT,
470									 NULL,
471									 NULL);
472	}
473}
474
475//
476// DbCursorMaker
477//
478DbCursorImpl *
479DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
480{
481	return new DbDbCursorImpl(Db(this), query, allocator);
482}
483
484DbCursorImpl *
485DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
486{
487	return new DbDbCursorImpl(Db(this), capacity, allocator);
488}
489
490
491//
492// Db adapters for AclBearer
493//
494void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
495{
496	aclInfos.allocator(allocator());
497	check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
498		reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
499}
500
501void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
502	const CSSM_ACCESS_CREDENTIALS *accessCred)
503{
504	check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
505}
506
507void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
508{
509	owner.allocator(allocator());
510	check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
511}
512
513void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
514	const CSSM_ACCESS_CREDENTIALS *accessCred)
515{
516	check(CSSM_DL_ChangeDbOwner(handle(),
517		AccessCredentials::needed(accessCred), &newOwner));
518}
519
520void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
521{
522	mDefaultCredentials = maker;
523}
524
525
526//
527// Abstract DefaultCredentialsMakers
528//
529DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
530{ /* virtual */ }
531
532
533//
534// Db adapters for DLAccess
535//
536CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query,	CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
537	CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
538{
539	CSSM_HANDLE result;
540	switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
541	case CSSM_OK:
542		return result;
543	case CSSMERR_DL_ENDOFDATA:
544		return CSSM_INVALID_HANDLE;
545	default:
546		CssmError::throwMe(rc);
547		return CSSM_INVALID_HANDLE; // placebo
548	}
549}
550
551bool Db::dlGetNext(CSSM_HANDLE query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
552	CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
553{
554	CSSM_RETURN rc = CSSM_DL_DataGetNext(handle(), query, &attributes, data, &id);
555	switch (rc) {
556	case CSSM_OK:
557		return true;
558	case CSSMERR_DL_ENDOFDATA:
559		return false;
560	default:
561		CssmError::throwMe(rc);
562		return false;   // placebo
563	}
564}
565
566void Db::dlAbortQuery(CSSM_HANDLE query)
567{
568	CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
569}
570
571void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
572{
573	CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
574}
575
576void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
577{
578	CssmError::check(CSSM_DL_DataDelete(handle(), id));
579}
580
581Allocator &Db::allocator()
582{
583	return Object::allocator();
584}
585
586
587//
588// DbUniqueRecordMaker
589//
590DbUniqueRecordImpl *
591DbImpl::newDbUniqueRecord()
592{
593	return new DbUniqueRecordImpl(Db(this));
594}
595
596
597//
598// Utility methods
599//
600DLDbIdentifier
601DbImpl::dlDbIdentifier()
602{
603	// Always use the same dbName and dbLocation that were passed in during
604	// construction
605	return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
606}
607
608
609//
610// DbDbCursorImpl
611//
612DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
613: DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
614{
615}
616
617DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
618: DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
619{
620}
621
622DbDbCursorImpl::~DbDbCursorImpl()
623{
624	try
625	{
626		deactivate();
627	}
628	catch(...) {}
629}
630
631bool
632DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
633{
634	if (attributes)
635		attributes->deleteValues();
636
637	if (data)
638		data->clear();
639
640	CSSM_RETURN result;
641	Db db(database());
642	DbUniqueRecord unique(db);
643	if (!mActive)
644	{
645		// ask the CSP/DL if the requested  record type exists
646		CSSM_BOOL boolResult;
647		CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
648		if (!boolResult)
649		{
650			if (data != NULL)
651			{
652				data->invalidate();
653			}
654
655			return false;
656		}
657
658		result = CSSM_DL_DataGetFirst(db->handle(),
659									  this,
660									  &mResultsHandle,
661									  attributes,
662									  data,
663									  unique);
664
665        StLock<Mutex> _(mActivateMutex);
666		if (result == CSSM_OK)
667			mActive = true;
668		else if (data != NULL)
669			data->invalidate ();
670	}
671	else
672	{
673		result = CSSM_DL_DataGetNext(db->handle(),
674									 mResultsHandle,
675									 attributes,
676									 data,
677									 unique);
678
679		if (result != CSSM_OK && data != NULL)
680		{
681			data->invalidate ();
682		}
683	}
684
685	if (result != CSSM_OK && attributes != NULL)
686	{
687		attributes->invalidate();
688	}
689
690	if (result == CSSMERR_DL_ENDOFDATA)
691	{
692        StLock<Mutex> _(mActivateMutex);
693		mActive = false;
694		return false;
695	}
696
697	check(result);
698
699	// Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
700	unique->activate();
701	uniqueId = unique;
702	return true;
703}
704
705void
706DbDbCursorImpl::activate()
707{
708}
709
710void
711DbDbCursorImpl::deactivate()
712{
713    StLock<Mutex> _(mActivateMutex);
714	if (mActive)
715	{
716		mActive = false;
717		check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
718	}
719}
720
721
722//
723// DbCursorImpl
724//
725DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
726ObjectImpl(parent), CssmAutoQuery(query, allocator)
727{
728}
729
730DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
731ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
732{
733}
734
735Allocator &
736DbCursorImpl::allocator() const
737{
738	return ObjectImpl::allocator();
739}
740
741void
742DbCursorImpl::allocator(Allocator &alloc)
743{
744	ObjectImpl::allocator(alloc);
745}
746
747
748//
749// DbUniqueRecord
750//
751DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
752{
753}
754
755DbUniqueRecordImpl::~DbUniqueRecordImpl()
756{
757	try
758	{
759		if (mDestroyID)
760		{
761			allocator ().free (mUniqueId);
762		}
763
764		deactivate();
765	}
766	catch(...) {}
767}
768
769void
770DbUniqueRecordImpl::deleteRecord()
771{
772	check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
773}
774
775void
776DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
777						   const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
778						   const CSSM_DATA *data,
779						   CSSM_DB_MODIFY_MODE modifyMode)
780{
781	check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
782							 attributes,
783							 data, modifyMode));
784}
785
786void
787DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
788											const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
789											const CSSM_DATA *data,
790											CSSM_DB_MODIFY_MODE modifyMode)
791{
792	// fill out the parameters
793	CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
794	params.recordType = recordType;
795	params.uniqueID = mUniqueId;
796	params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
797	params.data = (CSSM_DATA*) data;
798	params.modifyMode = modifyMode;
799
800	// modify the data
801	check(CSSM_DL_PassThrough(database()->handle(),
802		  CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
803		  &params,
804		  NULL));
805}
806
807void
808DbUniqueRecordImpl::get(DbAttributes *attributes,
809						::CssmDataContainer *data)
810{
811	if (attributes)
812		attributes->deleteValues();
813
814	if (data)
815		data->clear();
816
817	// @@@ Fix the allocators for attributes and data.
818	CSSM_RETURN result;
819	result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
820											attributes,
821											data);
822
823	if (result != CSSM_OK)
824	{
825        if (attributes)
826            attributes->invalidate();
827		if (data != NULL) // the data returned is no longer valid
828		{
829			data->invalidate ();
830		}
831	}
832
833	check(result);
834}
835
836void
837DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
838										 ::CssmDataContainer *data)
839{
840	if (attributes)
841		attributes->deleteValues();
842
843	if (data)
844		data->clear();
845
846	// @@@ Fix the allocators for attributes and data.
847	CSSM_RETURN result;
848
849	// make the parameter block
850	CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
851	params.uniqueID = mUniqueId;
852	params.attributes = attributes;
853
854	// get the data
855	::CssmDataContainer recordData;
856	result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, &params,
857								 (void**) data);
858	check (result);
859}
860
861void
862DbUniqueRecordImpl::activate()
863{
864    StLock<Mutex> _(mActivateMutex);
865	mActive = true;
866}
867
868void
869DbUniqueRecordImpl::deactivate()
870{
871    StLock<Mutex> _(mActivateMutex);
872	if (mActive)
873	{
874		mActive = false;
875		check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
876	}
877}
878
879void
880DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
881{
882	check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
883		  mUniqueId, (void**) &data));
884}
885
886void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
887{
888	// clone the record
889	mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
890	*mUniqueId = *uniquePtr;
891	mDestroyID = true;
892}
893
894//
895// DbAttributes
896//
897DbAttributes::DbAttributes()
898:  CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
899{
900}
901
902DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
903:  CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
904{
905}
906