2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // dlclient - client interface to CSSM DLs and their operations
22 #include <security_cdsa_client/dlclient.h>
23 #include <security_cdsa_client/aclclient.h>
24 #include <Security/cssmapple.h>
25 #include <Security/cssmapplePriv.h>
27 using namespace CssmClient
;
30 // blob type for blobs created by these classes -- done so that we can change the formats later
31 const uint32 kBlobType
= 0x1;
40 DbCursorMaker::~DbCursorMaker()
43 DbUniqueRecordMaker::~DbUniqueRecordMaker()
48 // Manage DL attachments
50 DLImpl::DLImpl(const Guid
&guid
) : AttachmentImpl(guid
, CSSM_SERVICE_DL
)
54 DLImpl::DLImpl(const Module
&module) : AttachmentImpl(module, CSSM_SERVICE_DL
)
63 DLImpl::getDbNames(char **)
65 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED
);
69 DLImpl::freeNameList(char **)
71 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED
);
75 DLImpl::newDb(const char *inDbName
, const CSSM_NET_ADDRESS
*inDbLocation
)
77 return new DbImpl(DL(this), inDbName
, inDbLocation
);
84 DbImpl::DbImpl(const DL
&dl
, const char *inDbName
, const CSSM_NET_ADDRESS
*inDbLocation
)
85 : ObjectImpl(dl
), mDbName(inDbName
, inDbLocation
),
86 mUseNameFromHandle(!inDbName
), mNameFromHandle(NULL
),
87 mAccessRequest(CSSM_DB_ACCESS_READ
), mAccessCredentials(NULL
),
88 mDefaultCredentials(NULL
), mOpenParameters(NULL
), mDbInfo(NULL
),
89 mResourceControlContext(NULL
)
98 allocator().free(mNameFromHandle
);
109 assert(mDbInfo
== nil
);
110 mHandle
.DLHandle
= dl()->handle();
111 check(CSSM_DL_DbOpen(mHandle
.DLHandle
, mDbName
.canonicalName(), dbLocation(),
112 mAccessRequest
, mAccessCredentials
,
113 mOpenParameters
, &mHandle
.DBHandle
));
115 StLock
<Mutex
> _(mActivateMutex
);
118 if (!mAccessCredentials
&& mDefaultCredentials
)
119 if (const AccessCredentials
*creds
= mDefaultCredentials
->makeCredentials())
120 CSSM_DL_Authenticate(handle(), mAccessRequest
, creds
); // ignore error
125 DbImpl::createWithBlob(CssmData
&blob
)
128 CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS
);
130 if (mDbInfo
== nil
) {
131 // handle a missing (null) mDbInfo as an all-zero one
132 static const CSSM_DBINFO nullDbInfo
= { };
133 mDbInfo
= &nullDbInfo
;
136 mHandle
.DLHandle
= dl()->handle();
138 // create a parameter block for our call to the passthrough
139 CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS params
;
141 params
.dbName
= mDbName
.canonicalName ();
142 params
.dbLocation
= dbLocation ();
143 params
.dbInfo
= mDbInfo
;
144 params
.accessRequest
= mAccessRequest
;
145 params
.credAndAclEntry
= NULL
;
146 params
.openParameters
= mOpenParameters
;
149 check(CSSM_DL_PassThrough (mHandle
, CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB
, ¶ms
, (void**) &mHandle
.DBHandle
));
155 StLock
<Mutex
> _(mActivateMutex
);
157 CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS
);
159 if (mDbInfo
== nil
) {
160 // handle a missing (null) mDbInfo as an all-zero one
161 static const CSSM_DBINFO nullDbInfo
= { };
162 mDbInfo
= &nullDbInfo
;
164 mHandle
.DLHandle
= dl()->handle();
166 if (!mResourceControlContext
&& mAccessCredentials
) {
167 AclFactory::AnyResourceContext
ctx(mAccessCredentials
);
168 check(CSSM_DL_DbCreate(mHandle
.DLHandle
, mDbName
.canonicalName(), dbLocation(),
169 mDbInfo
, mAccessRequest
, &ctx
,
170 mOpenParameters
, &mHandle
.DBHandle
));
172 check(CSSM_DL_DbCreate(mHandle
.DLHandle
, mDbName
.canonicalName(), dbLocation(),
173 mDbInfo
, mAccessRequest
, mResourceControlContext
,
174 mOpenParameters
, &mHandle
.DBHandle
));
182 StLock
<Mutex
> _(mActivateMutex
);
185 check(CSSM_DL_DbClose (mHandle
));
193 StLock
<Mutex
> _(mActivateMutex
);
206 StLock
<Mutex
> _(mActivateMutex
);
217 // Deactivate so the db gets closed if it was open.
219 // This call does not require the receiver to be active.
220 check(CSSM_DL_DbDelete(dl()->handle(), mDbName
.canonicalName(), dbLocation(),
221 mAccessCredentials
));
225 DbImpl::rename(const char *newName
)
227 // Deactivate so the db gets closed if it was open.
229 if (::rename(mDbName
.canonicalName(), newName
))
230 UnixError::throwMe(errno
);
232 // Change our DbName to reflect this rename.
233 mDbName
= DbName(newName
, dbLocation());
237 DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest
,
238 const CSSM_ACCESS_CREDENTIALS
*inAccessCredentials
)
242 // XXX Could do the same for create but this would require sticking
243 // inAccessCredentials into mResourceControlContext.
246 // We were not yet active. Just do an open.
247 accessRequest(inAccessRequest
);
248 accessCredentials(inAccessCredentials
);
254 check(CSSM_DL_Authenticate(handle(), inAccessRequest
, inAccessCredentials
));
258 DbImpl::name(char *&outDbName
)
260 check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName
));
266 if (mUseNameFromHandle
)
269 || !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle
))
271 return mNameFromHandle
;
274 // We failed to get the name from the handle so use the passed
276 mUseNameFromHandle
= false;
279 return mDbName
.canonicalName();
283 DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID
,
284 const char *inRelationName
,
285 uint32 inNumberOfAttributes
,
286 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*pAttributeInfo
,
287 uint32 inNumberOfIndexes
,
288 const CSSM_DB_SCHEMA_INDEX_INFO
*pIndexInfo
)
290 check(CSSM_DL_CreateRelation(handle(), inRelationID
, inRelationName
,
291 inNumberOfAttributes
, pAttributeInfo
,
292 inNumberOfIndexes
, pIndexInfo
));
296 DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID
)
298 check(CSSM_DL_DestroyRelation(handle(), inRelationID
));
302 DbImpl::insert(CSSM_DB_RECORDTYPE recordType
, const CSSM_DB_RECORD_ATTRIBUTE_DATA
*attributes
,
303 const CSSM_DATA
*data
)
305 DbUniqueRecord
uniqueId(Db(this));
306 check(CSSM_DL_DataInsert(handle(), recordType
,
309 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
310 uniqueId
->activate();
316 DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType
, const CSSM_DB_RECORD_ATTRIBUTE_DATA
*attributes
,
319 DbUniqueRecord
uniqueId(Db(this));
321 // fill out the parameters
322 CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params
;
323 params
.recordType
= recordType
;
324 params
.attributes
= const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA
*>(attributes
);
327 // for clarity, call the overloaded operator to produce a unique record pointer
328 CSSM_DB_UNIQUE_RECORD_PTR
*uniquePtr
= uniqueId
;
331 passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION
, ¶ms
, (void**) uniquePtr
);
333 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
334 uniqueId
->activate();
340 // Generic Passthrough interface
342 void DbImpl::passThrough(uint32 passThroughId
, const void *in
, void **out
)
344 check(CSSM_DL_PassThrough(handle(), passThroughId
, in
, out
));
349 // Passthrough functions (only implemented by AppleCSPDL).
354 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK
, NULL
, NULL
));
360 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK
, NULL
, NULL
));
364 DbImpl::unlock(const CSSM_DATA
&password
)
366 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK
, &password
, NULL
));
370 DbImpl::getSettings(uint32
&outIdleTimeout
, bool &outLockOnSleep
)
372 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings
;
373 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS
,
374 NULL
, reinterpret_cast<void **>(&settings
)));
375 outIdleTimeout
= settings
->idleTimeout
;
376 outLockOnSleep
= settings
->lockOnSleep
;
377 allocator().free(settings
);
381 DbImpl::setSettings(uint32 inIdleTimeout
, bool inLockOnSleep
)
383 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings
;
384 settings
.idleTimeout
= inIdleTimeout
;
385 settings
.lockOnSleep
= inLockOnSleep
;
386 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS
, &settings
, NULL
));
392 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params
;
393 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED
,
394 NULL
, reinterpret_cast<void **>(¶ms
)));
395 bool isLocked
= params
->isLocked
;
396 allocator().free(params
);
401 DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS
*cred
)
403 CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params
;
404 params
.accessCredentials
= const_cast<CSSM_ACCESS_CREDENTIALS
*>(cred
);
405 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD
, ¶ms
, NULL
));
408 void DbImpl::recode(const CSSM_DATA
&data
, const CSSM_DATA
&extraData
)
410 // setup parameters for the recode call
411 CSSM_APPLECSPDL_RECODE_PARAMETERS params
;
412 params
.dbBlob
= data
;
413 params
.extraData
= extraData
;
416 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE
, ¶ms
, NULL
));
419 void DbImpl::copyBlob (CssmData
&data
)
422 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB
, NULL
, (void**) (CSSM_DATA
*) &data
));
425 void DbImpl::setBatchMode(Boolean mode
, Boolean rollback
)
428 // We need the DL_DB_Handle of the underyling DL in order to use CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
431 CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL
;
432 result
= CSSM_DL_PassThrough(handle(),
433 CSSM_APPLECSPDL_DB_GET_HANDLE
,
435 (void **)&dldbHandleOfUnderlyingDL
);
437 // Now, toggle the autocommit...
439 if ( result
== noErr
)
441 CSSM_BOOL modeToUse
= !mode
;
444 result
= (OSStatus
)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL
,
445 CSSM_APPLEFILEDL_ROLLBACK
, NULL
, NULL
);
448 result
= CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL
,
449 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
452 if (!rollback
&& modeToUse
)
453 result
= CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL
,
454 CSSM_APPLEFILEDL_COMMIT
,
464 DbImpl::newDbCursor(const CSSM_QUERY
&query
, Allocator
&allocator
)
466 return new DbDbCursorImpl(Db(this), query
, allocator
);
470 DbImpl::newDbCursor(uint32 capacity
, Allocator
&allocator
)
472 return new DbDbCursorImpl(Db(this), capacity
, allocator
);
477 // Db adapters for AclBearer
479 void DbImpl::getAcl(AutoAclEntryInfoList
&aclInfos
, const char *selectionTag
) const
481 aclInfos
.allocator(allocator());
482 check(CSSM_DL_GetDbAcl(const_cast<DbImpl
*>(this)->handle(),
483 reinterpret_cast<const CSSM_STRING
*>(selectionTag
), aclInfos
, aclInfos
));
486 void DbImpl::changeAcl(const CSSM_ACL_EDIT
&aclEdit
,
487 const CSSM_ACCESS_CREDENTIALS
*accessCred
)
489 check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred
), &aclEdit
));
492 void DbImpl::getOwner(AutoAclOwnerPrototype
&owner
) const
494 owner
.allocator(allocator());
495 check(CSSM_DL_GetDbOwner(const_cast<DbImpl
*>(this)->handle(), owner
));
498 void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE
&newOwner
,
499 const CSSM_ACCESS_CREDENTIALS
*accessCred
)
501 check(CSSM_DL_ChangeDbOwner(handle(),
502 AccessCredentials::needed(accessCred
), &newOwner
));
505 void DbImpl::defaultCredentials(DefaultCredentialsMaker
*maker
)
507 mDefaultCredentials
= maker
;
512 // Abstract DefaultCredentialsMakers
514 DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
519 // Db adapters for DLAccess
521 CSSM_HANDLE
Db::dlGetFirst(const CSSM_QUERY
&query
, CSSM_DB_RECORD_ATTRIBUTE_DATA
&attributes
,
522 CSSM_DATA
*data
, CSSM_DB_UNIQUE_RECORD
*&id
)
525 switch (CSSM_RETURN rc
= CSSM_DL_DataGetFirst(handle(), &query
, &result
, &attributes
, data
, &id
)) {
528 case CSSMERR_DL_ENDOFDATA
:
529 return CSSM_INVALID_HANDLE
;
531 CssmError::throwMe(rc
);
532 return CSSM_INVALID_HANDLE
; // placebo
536 bool Db::dlGetNext(CSSM_HANDLE query
, CSSM_DB_RECORD_ATTRIBUTE_DATA
&attributes
,
537 CSSM_DATA
*data
, CSSM_DB_UNIQUE_RECORD
*&id
)
539 CSSM_RETURN rc
= CSSM_DL_DataGetNext(handle(), query
, &attributes
, data
, &id
);
543 case CSSMERR_DL_ENDOFDATA
:
546 CssmError::throwMe(rc
);
547 return false; // placebo
551 void Db::dlAbortQuery(CSSM_HANDLE query
)
553 CssmError::check(CSSM_DL_DataAbortQuery(handle(), query
));
556 void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD
*id
)
558 CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id
));
561 void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD
*id
)
563 CssmError::check(CSSM_DL_DataDelete(handle(), id
));
566 Allocator
&Db::allocator()
568 return Object::allocator();
573 // DbUniqueRecordMaker
576 DbImpl::newDbUniqueRecord()
578 return new DbUniqueRecordImpl(Db(this));
586 DbImpl::dlDbIdentifier()
588 // Always use the same dbName and dbLocation that were passed in during
590 return DLDbIdentifier(dl()->subserviceUid(), mDbName
.canonicalName(), dbLocation());
597 DbDbCursorImpl::DbDbCursorImpl(const Db
&db
, const CSSM_QUERY
&query
, Allocator
&allocator
)
598 : DbCursorImpl(db
, query
, allocator
), mResultsHandle(CSSM_INVALID_HANDLE
)
602 DbDbCursorImpl::DbDbCursorImpl(const Db
&db
, uint32 capacity
, Allocator
&allocator
)
603 : DbCursorImpl(db
, capacity
, allocator
), mResultsHandle(CSSM_INVALID_HANDLE
)
607 DbDbCursorImpl::~DbDbCursorImpl()
617 DbDbCursorImpl::next(DbAttributes
*attributes
, ::CssmDataContainer
*data
, DbUniqueRecord
&uniqueId
)
620 attributes
->deleteValues();
627 DbUniqueRecord
unique(db
);
630 // ask the CSP/DL if the requested record type exists
631 CSSM_BOOL boolResult
;
632 CSSM_DL_PassThrough(db
->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS
, &RecordType
, (void**) &boolResult
);
643 result
= CSSM_DL_DataGetFirst(db
->handle(),
650 StLock
<Mutex
> _(mActivateMutex
);
651 if (result
== CSSM_OK
)
653 else if (data
!= NULL
)
658 result
= CSSM_DL_DataGetNext(db
->handle(),
664 if (result
!= CSSM_OK
&& data
!= NULL
)
670 if (result
!= CSSM_OK
&& attributes
!= NULL
)
672 attributes
->invalidate();
675 if (result
== CSSMERR_DL_ENDOFDATA
)
677 StLock
<Mutex
> _(mActivateMutex
);
684 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
691 DbDbCursorImpl::activate()
696 DbDbCursorImpl::deactivate()
698 StLock
<Mutex
> _(mActivateMutex
);
702 check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle
));
710 DbCursorImpl::DbCursorImpl(const Object
&parent
, const CSSM_QUERY
&query
, Allocator
&allocator
) :
711 ObjectImpl(parent
), CssmAutoQuery(query
, allocator
)
715 DbCursorImpl::DbCursorImpl(const Object
&parent
, uint32 capacity
, Allocator
&allocator
) :
716 ObjectImpl(parent
), CssmAutoQuery(capacity
, allocator
)
721 DbCursorImpl::allocator() const
723 return ObjectImpl::allocator();
727 DbCursorImpl::allocator(Allocator
&alloc
)
729 ObjectImpl::allocator(alloc
);
736 DbUniqueRecordImpl::DbUniqueRecordImpl(const Db
&db
) : ObjectImpl(db
), mDestroyID (false)
740 DbUniqueRecordImpl::~DbUniqueRecordImpl()
746 allocator ().free (mUniqueId
);
755 DbUniqueRecordImpl::deleteRecord()
757 check(CSSM_DL_DataDelete(database()->handle(), mUniqueId
));
761 DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType
,
762 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*attributes
,
763 const CSSM_DATA
*data
,
764 CSSM_DB_MODIFY_MODE modifyMode
)
766 check(CSSM_DL_DataModify(database()->handle(), recordType
, mUniqueId
,
772 DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType
,
773 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*attributes
,
774 const CSSM_DATA
*data
,
775 CSSM_DB_MODIFY_MODE modifyMode
)
777 // fill out the parameters
778 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params
;
779 params
.recordType
= recordType
;
780 params
.uniqueID
= mUniqueId
;
781 params
.attributes
= const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA
*>(attributes
);
782 params
.data
= (CSSM_DATA
*) data
;
783 params
.modifyMode
= modifyMode
;
786 check(CSSM_DL_PassThrough(database()->handle(),
787 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION
,
793 DbUniqueRecordImpl::get(DbAttributes
*attributes
,
794 ::CssmDataContainer
*data
)
797 attributes
->deleteValues();
802 // @@@ Fix the allocators for attributes and data.
804 result
= CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId
,
808 if (result
!= CSSM_OK
)
811 attributes
->invalidate();
812 if (data
!= NULL
) // the data returned is no longer valid
822 DbUniqueRecordImpl::getWithoutEncryption(DbAttributes
*attributes
,
823 ::CssmDataContainer
*data
)
826 attributes
->deleteValues();
831 // @@@ Fix the allocators for attributes and data.
834 // make the parameter block
835 CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params
;
836 params
.uniqueID
= mUniqueId
;
837 params
.attributes
= attributes
;
840 ::CssmDataContainer recordData
;
841 result
= CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION
, ¶ms
,
847 DbUniqueRecordImpl::activate()
849 StLock
<Mutex
> _(mActivateMutex
);
854 DbUniqueRecordImpl::deactivate()
856 StLock
<Mutex
> _(mActivateMutex
);
860 check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId
));
865 DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA
&data
)
867 check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER
,
868 mUniqueId
, (void**) &data
));
871 void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr
)
874 mUniqueId
= (CSSM_DB_UNIQUE_RECORD_PTR
) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD
));
875 *mUniqueId
= *uniquePtr
;
882 DbAttributes::DbAttributes()
883 : CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
887 DbAttributes::DbAttributes(const Db
&db
, uint32 capacity
, Allocator
&allocator
)
888 : CssmAutoDbRecordAttributeData(capacity
, db
->allocator(), allocator
)