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 // SSDLSession.h - DL session for security server CSP/DL.
22 #include "SSDLSession.h"
24 #include "CSPDLPlugin.h"
27 using namespace CssmClient
;
28 using namespace SecurityServer
;
32 // SSDLSession -- Security Server DL session
34 SSDLSession::SSDLSession(CSSM_MODULE_HANDLE handle
,
36 const CSSM_VERSION
&version
,
38 CSSM_SERVICE_TYPE subserviceType
,
39 CSSM_ATTACH_FLAGS attachFlags
,
40 const CSSM_UPCALLS
&upcalls
,
41 DatabaseManager
&databaseManager
,
42 SSCSPDLSession
&ssCSPDLSession
)
43 : DLPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
,
44 attachFlags
, upcalls
, databaseManager
),
45 mSSCSPDLSession(ssCSPDLSession
),
46 mDL(Module(gGuidAppleFileDL
, Cssm::standard()))
48 // @@@ mDL.allocator(*static_cast<DatabaseSession *>(this));
49 mDL
->allocator(allocator());
50 mDL
->version(version
);
51 mDL
->subserviceId(subserviceId
);
52 mDL
->flags(attachFlags
);
55 SSDLSession::~SSDLSession()
57 // @@@ What about a catch?
58 StLock
<Mutex
> _1(mSSUniqueRecordLock
);
59 mSSUniqueRecordMap
.clear();
61 StLock
<Mutex
> _2(mDbHandleLock
);
62 DbHandleMap::iterator end
= mDbHandleMap
.end();
63 for (DbHandleMap::iterator it
= mDbHandleMap
.begin(); it
!= end
; ++it
)
72 SSDLSession::GetDbNames(CSSM_NAME_LIST_PTR
&outNameList
)
75 CSSM_DL_GetDbNames(mDL
->handle(), &outNameList
);
80 SSDLSession::FreeNameList(CSSM_NAME_LIST
&inNameList
)
83 CSSM_DL_FreeNameList(mDL
->handle(), &inNameList
);
88 SSDLSession::DbDelete(const char *inDbName
,
89 const CSSM_NET_ADDRESS
*inDbLocation
,
90 const AccessCredentials
*inAccessCred
)
92 SSDatabase
db(mSSCSPDLSession
.clientSession(), mDL
, inDbName
, inDbLocation
);
93 db
->accessCredentials(inAccessCred
);
97 // DbContext creation and destruction.
99 SSDLSession::DbCreate(const char *inDbName
,
100 const CSSM_NET_ADDRESS
*inDbLocation
,
101 const CSSM_DBINFO
&inDBInfo
,
102 CSSM_DB_ACCESS_TYPE inAccessRequest
,
103 const CSSM_RESOURCE_CONTROL_CONTEXT
*inCredAndAclEntry
,
104 const void *inOpenParameters
,
105 CSSM_DB_HANDLE
&outDbHandle
)
107 SSDatabase
db(mSSCSPDLSession
.clientSession(), mDL
, inDbName
, inDbLocation
);
108 db
->dbInfo(&inDBInfo
);
109 db
->accessRequest(inAccessRequest
);
110 db
->resourceControlContext(inCredAndAclEntry
);
111 db
->openParameters(inOpenParameters
);
112 db
->create(DLDbIdentifier(CssmSubserviceUid(plugin
.myGuid(), &version(), subserviceId(),
113 CSSM_SERVICE_DL
| CSSM_SERVICE_CSP
),
114 inDbName
, inDbLocation
));
116 outDbHandle
= makeDbHandle(db
);
120 SSDLSession::DbOpen(const char *inDbName
,
121 const CSSM_NET_ADDRESS
*inDbLocation
,
122 CSSM_DB_ACCESS_TYPE inAccessRequest
,
123 const AccessCredentials
*inAccessCred
,
124 const void *inOpenParameters
,
125 CSSM_DB_HANDLE
&outDbHandle
)
127 SSDatabase
db(mSSCSPDLSession
.clientSession(), mDL
, inDbName
, inDbLocation
);
128 db
->accessRequest(inAccessRequest
);
129 db
->accessCredentials(inAccessCred
);
130 db
->openParameters(inOpenParameters
);
131 db
->open(DLDbIdentifier(CssmSubserviceUid(plugin
.myGuid(), &version(), subserviceId(),
132 CSSM_SERVICE_DL
| CSSM_SERVICE_CSP
),
133 inDbName
, inDbLocation
));
134 outDbHandle
= makeDbHandle(db
);
137 // Operations using DbContext instances.
139 SSDLSession::DbClose(CSSM_DB_HANDLE inDbHandle
)
141 killDbHandle(inDbHandle
)->close();
145 SSDLSession::CreateRelation(CSSM_DB_HANDLE inDbHandle
,
146 CSSM_DB_RECORDTYPE inRelationID
,
147 const char *inRelationName
,
148 uint32 inNumberOfAttributes
,
149 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
&inAttributeInfo
,
150 uint32 inNumberOfIndexes
,
151 const CSSM_DB_SCHEMA_INDEX_INFO
&inIndexInfo
)
153 SSDatabase db
= findDbHandle(inDbHandle
);
154 // @@@ Fix inAttributeInfo and inIndexInfo arguments (might be NULL if NumberOf = 0)
155 db
->createRelation(inRelationID
, inRelationName
,
156 inNumberOfAttributes
, &inAttributeInfo
,
157 inNumberOfIndexes
, &inIndexInfo
);
161 SSDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle
,
162 CSSM_DB_RECORDTYPE inRelationID
)
164 // @@@ Check credentials.
165 SSDatabase db
= findDbHandle(inDbHandle
);
166 db
->destroyRelation(inRelationID
);
170 SSDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle
,
171 CSSM_DB_ACCESS_TYPE inAccessRequest
,
172 const AccessCredentials
&inAccessCred
)
174 // @@@ Use securityserver.
175 SSDatabase db
= findDbHandle(inDbHandle
);
176 db
->authenticate(inAccessRequest
, &inAccessCred
);
181 SSDLSession::GetDbAcl(CSSM_DB_HANDLE inDbHandle
,
182 const CSSM_STRING
*inSelectionTag
,
183 uint32
&outNumberOfAclInfos
,
184 CSSM_ACL_ENTRY_INFO_PTR
&outAclInfos
)
186 SSDatabase db
= findDbHandle(inDbHandle
);
187 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
191 SSDLSession::ChangeDbAcl(CSSM_DB_HANDLE inDbHandle
,
192 const AccessCredentials
&inAccessCred
,
193 const CSSM_ACL_EDIT
&inAclEdit
)
195 SSDatabase db
= findDbHandle(inDbHandle
);
196 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
200 SSDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle
,
201 CSSM_ACL_OWNER_PROTOTYPE
&outOwner
)
203 SSDatabase db
= findDbHandle(inDbHandle
);
204 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
208 SSDLSession::ChangeDbOwner(CSSM_DB_HANDLE inDbHandle
,
209 const AccessCredentials
&inAccessCred
,
210 const CSSM_ACL_OWNER_PROTOTYPE
&inNewOwner
)
212 SSDatabase db
= findDbHandle(inDbHandle
);
213 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
217 SSDLSession::GetDbNameFromHandle(CSSM_DB_HANDLE inDbHandle
,
220 SSDatabase db
= findDbHandle(inDbHandle
);
221 // @@@ Fix this functions signature.
222 db
->name(*outDbName
);
226 SSDLSession::DataInsert(CSSM_DB_HANDLE inDbHandle
,
227 CSSM_DB_RECORDTYPE inRecordType
,
228 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
229 const CssmData
*inData
,
230 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueId
)
232 SSDatabase db
= findDbHandle(inDbHandle
);
233 // @@@ Fix client lib.
234 SSUniqueRecord uniqueId
= db
->insert(inRecordType
, inAttributes
, inData
, true); // @@@ Fix me
235 outUniqueId
= makeSSUniqueRecord(uniqueId
);
236 // @@@ If this is a key do the right thing.
240 SSDLSession::DataDelete(CSSM_DB_HANDLE inDbHandle
,
241 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
)
243 SSDatabase db
= findDbHandle(inDbHandle
);
244 SSUniqueRecord uniqueId
= findSSUniqueRecord(inUniqueRecordIdentifier
);
245 uniqueId
->deleteRecord();
246 // @@@ If this is a key do the right thing.
251 SSDLSession::DataModify(CSSM_DB_HANDLE inDbHandle
,
252 CSSM_DB_RECORDTYPE inRecordType
,
253 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecordIdentifier
,
254 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributesToBeModified
,
255 const CssmData
*inDataToBeModified
,
256 CSSM_DB_MODIFY_MODE inModifyMode
)
258 SSDatabase db
= findDbHandle(inDbHandle
);
259 SSUniqueRecord uniqueId
= findSSUniqueRecord(inoutUniqueRecordIdentifier
);
260 uniqueId
->modify(inRecordType
, inAttributesToBeModified
, inDataToBeModified
, inModifyMode
);
261 // @@@ If this is a key do the right thing.
265 SSDLSession::DataGetFirst(CSSM_DB_HANDLE inDbHandle
,
266 const DLQuery
*inQuery
,
267 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
269 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
)
271 SSDatabase db
= findDbHandle(inDbHandle
);
272 CSSM_HANDLE resultsHandle
= CSSM_INVALID_HANDLE
;
273 SSUniqueRecord
uniqueId(db
);
275 // Setup so we always retrive the attributes even if the client
276 // doesn't want them so we can figure out if we just retrived a key.
277 CSSM_DB_RECORD_ATTRIBUTE_DATA attributes
;
278 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes
;
280 pAttributes
= inoutAttributes
;
283 pAttributes
= &attributes
;
284 memset(pAttributes
, 0, sizeof(attributes
));
287 // Retrive the record.
288 CSSM_RETURN result
= CSSM_DL_DataGetFirst(db
->handle(), inQuery
, &resultsHandle
,
289 pAttributes
, inoutData
, uniqueId
);
292 if (result
== CSSMERR_DL_ENDOFDATA
)
293 return CSSM_INVALID_HANDLE
;
295 CssmError::throwMe(result
);
298 uniqueId
->activate();
300 // If we the client didn't ask for data then it doesn't matter
301 // if this record is a key or not, just return it.
304 if (pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_PUBLIC_KEY
305 || pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_PRIVATE_KEY
306 || pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
308 // This record is a key, do the right thing (tm).
309 // Allocate storage for the key.
310 CssmKey
*outKey
= allocator().alloc
<CssmKey
>();
311 new SSKey(*this, *outKey
, db
, uniqueId
, pAttributes
->DataRecordType
, *inoutData
);
313 // Free the data we retrived (keyblob)
314 allocator().free(inoutData
->Data
);
316 // Set the length and data on the data we return to the client
317 inoutData
->Length
= sizeof(*outKey
);
318 inoutData
->Data
= reinterpret_cast<uint8
*>(outKey
);
322 outUniqueRecord
= makeSSUniqueRecord(uniqueId
);
323 return resultsHandle
;
327 SSDLSession::DataGetNext(CSSM_DB_HANDLE inDbHandle
,
328 CSSM_HANDLE inResultsHandle
,
329 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
331 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
)
333 // @@@ If this is a key do the right thing.
334 SSDatabase db
= findDbHandle(inDbHandle
);
335 SSUniqueRecord
uniqueId(db
);
337 // Setup so we always retrive the attributes even if the client
338 // doesn't want them so we can figure out if we just retrived a key.
339 CSSM_DB_RECORD_ATTRIBUTE_DATA attributes
;
340 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR pAttributes
;
342 pAttributes
= inoutAttributes
;
345 pAttributes
= &attributes
;
346 memset(pAttributes
, 0, sizeof(attributes
));
349 CSSM_RETURN result
= CSSM_DL_DataGetNext(db
->handle(), inResultsHandle
,
350 inoutAttributes
, inoutData
, uniqueId
);
353 if (result
== CSSMERR_DL_ENDOFDATA
)
356 CssmError::throwMe(result
);
359 uniqueId
->activate();
361 // If we the client didn't ask for data then it doesn't matter
362 // if this record is a key or not, just return it.
365 if (pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_PUBLIC_KEY
366 || pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_PRIVATE_KEY
367 || pAttributes
->DataRecordType
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
369 // This record is a key, do the right thing (tm).
370 // Allocate storage for the key.
371 CssmKey
*outKey
= allocator().alloc
<CssmKey
>();
372 new SSKey(*this, *outKey
, db
, uniqueId
, pAttributes
->DataRecordType
, *inoutData
);
374 // Free the data we retrived (keyblob)
375 allocator().free(inoutData
->Data
);
377 // Set the length and data on the data we return to the client
378 inoutData
->Length
= sizeof(*outKey
);
379 inoutData
->Data
= reinterpret_cast<uint8
*>(outKey
);
383 outUniqueRecord
= makeSSUniqueRecord(uniqueId
);
389 SSDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle
,
390 CSSM_HANDLE inResultsHandle
)
392 // @@@ If this is a key do the right thing.
393 SSDatabase db
= findDbHandle(inDbHandle
);
394 CSSM_RETURN result
= CSSM_DL_DataAbortQuery(db
->handle(), inResultsHandle
);
396 CssmError::throwMe(result
);
400 SSDLSession::DataGetFromUniqueRecordId(CSSM_DB_HANDLE inDbHandle
,
401 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
402 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
405 SSDatabase db
= findDbHandle(inDbHandle
);
406 const SSUniqueRecord uniqueId
= findSSUniqueRecord(inUniqueRecord
);
407 CSSM_RETURN result
= CSSM_DL_DataGetFromUniqueRecordId(db
->handle(), uniqueId
, inoutAttributes
, inoutData
);
409 CssmError::throwMe(result
);
410 // @@@ If this is a key do the right thing.
414 SSDLSession::FreeUniqueRecord(CSSM_DB_HANDLE inDbHandle
,
415 CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
)
417 killSSUniqueRecord(inUniqueRecordIdentifier
);
421 SSDLSession::PassThrough(CSSM_DB_HANDLE inDbHandle
,
422 uint32 inPassThroughId
,
423 const void *inInputParams
,
424 void **outOutputParams
)
426 SSDatabase db
= findDbHandle(inDbHandle
);
427 switch (inPassThroughId
)
429 case CSSM_APPLECSPDL_DB_LOCK
:
432 case CSSM_APPLECSPDL_DB_UNLOCK
:
434 db
->unlock(*reinterpret_cast<const CSSM_DATA
*>(inInputParams
));
438 case CSSM_APPLECSPDL_DB_GET_SETTINGS
:
440 if (!outOutputParams
)
441 CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER
);
443 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR params
=
444 allocator().alloc
<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS
>();
449 db
->getSettings(idleTimeout
, lockOnSleep
);
450 params
->idleTimeout
= idleTimeout
;
451 params
->lockOnSleep
= lockOnSleep
;
455 allocator().free(params
);
458 *reinterpret_cast<CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR
*>(outOutputParams
) = params
;
461 case CSSM_APPLECSPDL_DB_SET_SETTINGS
:
464 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
466 const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS
*params
=
467 reinterpret_cast<const CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS
*>(inInputParams
);
468 db
->setSettings(params
->idleTimeout
, params
->lockOnSleep
);
471 case CSSM_APPLECSPDL_DB_IS_LOCKED
:
473 if (!outOutputParams
)
474 CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER
);
476 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params
=
477 allocator().alloc
<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS
>();
480 params
->isLocked
= db
->isLocked();
484 allocator().free(params
);
487 *reinterpret_cast<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR
*>(outOutputParams
) = params
;
490 case CSSM_APPLECSPDL_DB_CHANGE_PASSWORD
:
493 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
495 const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS
*params
=
496 reinterpret_cast<const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS
*>(inInputParams
);
497 db
->changePassphrase(params
->accessCredentials
);
502 CSSM_RETURN result
= CSSM_DL_PassThrough(db
->handle(), inPassThroughId
, inInputParams
, outOutputParams
);
504 CssmError::throwMe(result
);
511 SSDLSession::makeDbHandle(SSDatabase
&inDb
)
513 StLock
<Mutex
> _(mDbHandleLock
);
514 CSSM_DB_HANDLE aDbHandle
= inDb
->handle().DBHandle
;
515 bool inserted
= mDbHandleMap
.insert(DbHandleMap::value_type(aDbHandle
, inDb
)).second
;
521 SSDLSession::killDbHandle(CSSM_DB_HANDLE inDbHandle
)
523 StLock
<Mutex
> _(mDbHandleLock
);
524 DbHandleMap::iterator it
= mDbHandleMap
.find(inDbHandle
);
525 if (it
== mDbHandleMap
.end())
526 CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE
);
528 SSDatabase db
= it
->second
;
529 mDbHandleMap
.erase(it
);
534 SSDLSession::findDbHandle(CSSM_DB_HANDLE inDbHandle
)
536 StLock
<Mutex
> _(mDbHandleLock
);
537 DbHandleMap::iterator it
= mDbHandleMap
.find(inDbHandle
);
538 if (it
== mDbHandleMap
.end())
539 CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE
);
544 CSSM_DB_UNIQUE_RECORD_PTR
545 SSDLSession::makeSSUniqueRecord(SSUniqueRecord
&uniqueId
)
547 StLock
<Mutex
> _(mSSUniqueRecordLock
);
548 CSSM_HANDLE ref
= CSSM_HANDLE(static_cast<CSSM_DB_UNIQUE_RECORD
*>(uniqueId
));
549 bool inserted
= mSSUniqueRecordMap
.insert(SSUniqueRecordMap::value_type(ref
, uniqueId
)).second
;
551 return createUniqueRecord(ref
);
555 SSDLSession::killSSUniqueRecord(CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
557 CSSM_HANDLE ref
= parseUniqueRecord(inUniqueRecord
);
558 StLock
<Mutex
> _(mSSUniqueRecordLock
);
559 SSUniqueRecordMap::iterator it
= mSSUniqueRecordMap
.find(ref
);
560 if (it
== mSSUniqueRecordMap
.end())
561 CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID
);
563 SSUniqueRecord uniqueRecord
= it
->second
;
564 mSSUniqueRecordMap
.erase(it
);
565 freeUniqueRecord(inUniqueRecord
);
570 SSDLSession::findSSUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
572 CSSM_HANDLE ref
= parseUniqueRecord(inUniqueRecord
);
573 StLock
<Mutex
> _(mSSUniqueRecordLock
);
574 SSUniqueRecordMap::iterator it
= mSSUniqueRecordMap
.find(ref
);
575 if (it
== mSSUniqueRecordMap
.end())
576 CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID
);
581 CSSM_DB_UNIQUE_RECORD_PTR
582 SSDLSession::createUniqueRecord(CSSM_HANDLE ref
)
584 CSSM_DB_UNIQUE_RECORD
*aUniqueRecord
= allocator().alloc
<CSSM_DB_UNIQUE_RECORD
>();
585 memset(aUniqueRecord
, 0, sizeof(CSSM_DB_UNIQUE_RECORD
));
586 aUniqueRecord
->RecordIdentifier
.Length
= sizeof(CSSM_HANDLE
);
589 aUniqueRecord
->RecordIdentifier
.Data
= allocator().alloc
<uint8
>(sizeof(CSSM_HANDLE
));
590 *reinterpret_cast<CSSM_HANDLE
*>(aUniqueRecord
->RecordIdentifier
.Data
) = ref
;
598 return aUniqueRecord
;
602 SSDLSession::parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
604 if (inUniqueRecord
.RecordIdentifier
.Length
!= sizeof(CSSM_HANDLE
))
605 CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID
);
607 return *reinterpret_cast<CSSM_HANDLE
*>(inUniqueRecord
.RecordIdentifier
.Data
);
611 SSDLSession::freeUniqueRecord(CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
613 if (inUniqueRecord
.RecordIdentifier
.Length
!= 0
614 && inUniqueRecord
.RecordIdentifier
.Data
!= NULL
)
616 inUniqueRecord
.RecordIdentifier
.Length
= 0;
617 allocator().free(inUniqueRecord
.RecordIdentifier
.Data
);
619 allocator().free(&inUniqueRecord
);