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