2 * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // SDDLSession.h - DL session for security server CSP/DL.
28 #include "SDDLSession.h"
30 #include "SDCSPDLPlugin.h"
32 #include <security_cdsa_utilities/cssmbridge.h>
33 #include <security_utilities/trackingallocator.h>
34 #include <Security/cssmapplePriv.h>
36 using namespace CssmClient
;
37 using namespace SecurityServer
;
41 // SDDLSession -- Security Server DL session
43 SDDLSession::SDDLSession(CSSM_MODULE_HANDLE handle
,
45 const CSSM_VERSION
&version
,
47 CSSM_SERVICE_TYPE subserviceType
,
48 CSSM_ATTACH_FLAGS attachFlags
,
49 const CSSM_UPCALLS
&upcalls
,
50 DatabaseManager
&databaseManager
,
51 SDCSPDLSession
&ssCSPDLSession
) :
52 DLPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
,
53 attachFlags
, upcalls
, databaseManager
),
54 mSDCSPDLSession(ssCSPDLSession
),
55 mClientSession(Allocator::standard(), static_cast<PluginSession
&>(*this))
56 //mAttachment(mClientSession.attach(version, subserviceId, subserviceType, attachFlags))
60 SDDLSession::~SDDLSession()
66 SDDLSession::GetDbNames(CSSM_NAME_LIST_PTR
&outNameList
)
68 outNameList
->String
= this->PluginSession::alloc
<char *>();
69 outNameList
->NumStrings
= 1;
70 outNameList
->String
[0] = (char*) ""; // empty name will trigger dynamic lookup
75 SDDLSession::FreeNameList(CSSM_NAME_LIST
&inNameList
)
77 this->PluginSession::free(inNameList
.String
);
82 SDDLSession::DbDelete(const char *inDbName
,
83 const CSSM_NET_ADDRESS
*inDbLocation
,
84 const AccessCredentials
*inAccessCred
)
89 // DbContext creation and destruction.
91 SDDLSession::DbCreate(const char *inDbName
,
92 const CSSM_NET_ADDRESS
*inDbLocation
,
93 const CSSM_DBINFO
&inDBInfo
,
94 CSSM_DB_ACCESS_TYPE inAccessRequest
,
95 const CSSM_RESOURCE_CONTROL_CONTEXT
*inCredAndAclEntry
,
96 const void *inOpenParameters
,
97 CSSM_DB_HANDLE
&outDbHandle
)
103 SDDLSession::DbOpen(const char *inDbName
,
104 const CSSM_NET_ADDRESS
*inDbLocation
,
105 CSSM_DB_ACCESS_TYPE inAccessRequest
,
106 const AccessCredentials
*inAccessCred
,
107 const void *inOpenParameters
,
108 CSSM_DB_HANDLE
&outDbHandle
)
110 outDbHandle
= mClientSession
.openToken(subserviceId(), inAccessCred
, inDbName
);
113 // Operations using DbContext instances.
115 SDDLSession::DbClose(CSSM_DB_HANDLE inDbHandle
)
117 mClientSession
.releaseDb(ClientSession::toIPCHandle(inDbHandle
));
121 SDDLSession::CreateRelation(CSSM_DB_HANDLE inDbHandle
,
122 CSSM_DB_RECORDTYPE inRelationID
,
123 const char *inRelationName
,
124 uint32 inNumberOfAttributes
,
125 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*inAttributeInfo
,
126 uint32 inNumberOfIndexes
,
127 const CSSM_DB_SCHEMA_INDEX_INFO
&inIndexInfo
)
133 SDDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle
,
134 CSSM_DB_RECORDTYPE inRelationID
)
140 SDDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle
,
141 CSSM_DB_ACCESS_TYPE inAccessRequest
,
142 const AccessCredentials
&inAccessCred
)
144 mClientSession
.authenticateDb((DbHandle
)inDbHandle
, inAccessRequest
, &inAccessCred
);
149 SDDLSession::GetDbAcl(CSSM_DB_HANDLE inDbHandle
,
150 const CSSM_STRING
*inSelectionTag
,
151 uint32
&outNumberOfAclInfos
,
152 CSSM_ACL_ENTRY_INFO_PTR
&outAclInfos
)
154 // @@@ inSelectionTag shouldn't be a CSSM_STRING * but just a CSSM_STRING.
155 mClientSession
.getDbAcl(ClientSession::toIPCHandle(inDbHandle
), *inSelectionTag
, outNumberOfAclInfos
,
156 AclEntryInfo::overlayVar(outAclInfos
));
160 SDDLSession::ChangeDbAcl(CSSM_DB_HANDLE inDbHandle
,
161 const AccessCredentials
&inAccessCred
,
162 const CSSM_ACL_EDIT
&inAclEdit
)
164 mClientSession
.changeDbAcl(ClientSession::toIPCHandle(inDbHandle
), inAccessCred
, AclEdit::overlay(inAclEdit
));
168 SDDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle
,
169 CSSM_ACL_OWNER_PROTOTYPE
&outOwner
)
171 mClientSession
.getDbOwner(ClientSession::toIPCHandle(inDbHandle
), AclOwnerPrototype::overlay(outOwner
));
175 SDDLSession::ChangeDbOwner(CSSM_DB_HANDLE inDbHandle
,
176 const AccessCredentials
&inAccessCred
,
177 const CSSM_ACL_OWNER_PROTOTYPE
&inNewOwner
)
179 mClientSession
.changeDbOwner(ClientSession::toIPCHandle(inDbHandle
), inAccessCred
, AclOwnerPrototype::overlay(inNewOwner
));
183 SDDLSession::GetDbNameFromHandle(CSSM_DB_HANDLE inDbHandle
,
187 mClientSession
.getDbName(ClientSession::toIPCHandle(inDbHandle
), name
);
188 memcpy(Required(outDbName
) = static_cast<char *>(this->malloc(name
.length() + 1)),
189 name
.c_str(), name
.length() + 1);
193 SDDLSession::DataInsert(CSSM_DB_HANDLE inDbHandle
,
194 CSSM_DB_RECORDTYPE inRecordType
,
195 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributes
,
196 const CssmData
*inData
,
197 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueId
)
200 record
= mClientSession
.insertRecord(ClientSession::toIPCHandle(inDbHandle
),
202 CssmDbRecordAttributeData::overlay(inAttributes
),
204 outUniqueId
= makeDbUniqueRecord(record
);
208 SDDLSession::DataDelete(CSSM_DB_HANDLE inDbHandle
,
209 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
)
211 RecordHandle record
= ClientSession::toIPCHandle(findDbUniqueRecord(inUniqueRecordIdentifier
));
212 mClientSession
.deleteRecord(ClientSession::toIPCHandle(inDbHandle
), record
);
217 SDDLSession::DataModify(CSSM_DB_HANDLE inDbHandle
,
218 CSSM_DB_RECORDTYPE inRecordType
,
219 CSSM_DB_UNIQUE_RECORD
&inoutUniqueRecordIdentifier
,
220 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*inAttributesToBeModified
,
221 const CssmData
*inDataToBeModified
,
222 CSSM_DB_MODIFY_MODE inModifyMode
)
224 RecordHandle record
= ClientSession::toIPCHandle(findDbUniqueRecord(inoutUniqueRecordIdentifier
));
225 mClientSession
.modifyRecord(ClientSession::toIPCHandle(inDbHandle
), record
, inRecordType
,
226 CssmDbRecordAttributeData::overlay(inAttributesToBeModified
),
227 inDataToBeModified
, inModifyMode
);
228 //@@@ make a (new) unique record out of possibly modified "record"...
232 SDDLSession::postGetRecord(RecordHandle record
, U32HandleObject::Handle resultsHandle
,
234 CssmDbRecordAttributeData
*pAttributes
,
235 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
236 CssmData
*inoutData
, KeyHandle hKey
)
238 // If the client didn't ask for data then it doesn't matter
239 // if this record is a key or not, just return it.
242 CSSM_DB_RECORDTYPE recordType
= pAttributes
->DataRecordType
;
243 if (!inoutAttributes
)
245 // @@@ Free pAttributes
248 if (recordType
== CSSM_DL_DB_RECORD_PUBLIC_KEY
249 || recordType
== CSSM_DL_DB_RECORD_PRIVATE_KEY
250 || recordType
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
)
252 // This record is a key. The data returned is a CSSM_KEY
253 // (with empty key data) with the header filled in.
256 if (hKey
== noKey
) // tokend error - should have returned key handle
257 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
258 // Allocate storage for the key.
259 CssmKey
*outKey
= inoutData
->interpretedAs
<CssmKey
>();
260 new SDKey(*this, *outKey
, hKey
, db
, record
, recordType
, *inoutData
);
264 try { mClientSession
.releaseRecord(record
); }
265 catch(...) { secinfo("ssCrypt", "releaseRecord threw during catch"); }
266 if (resultsHandle
!= CSSM_INVALID_HANDLE
)
268 try { mClientSession
.releaseSearch(resultsHandle
); }
269 catch(...) { secinfo("ssCrypt", "releaseSearch threw during catch"); }
273 } else { // not a key
275 try { mClientSession
.releaseRecord(record
); }
276 catch(...) { secinfo("ssCrypt", "failed releasing bogus key handle"); }
277 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
284 SDDLSession::DataGetFirst(CSSM_DB_HANDLE inDbHandle
,
285 const CssmQuery
*inQuery
,
286 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
288 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
)
290 // Setup so we always retrieve the attributes if the client asks for data,
291 // even if the client doesn't want them so we can figure out if we just
293 CssmDbRecordAttributeData attributes
;
294 CssmDbRecordAttributeData
*pAttributes
;
296 pAttributes
= CssmDbRecordAttributeData::overlay(inoutAttributes
);
299 pAttributes
= &attributes
;
300 memset(pAttributes
, 0, sizeof(attributes
));
304 SearchHandle resultsHandle
= noSearch
;
305 KeyHandle keyId
= noKey
;
306 record
= mClientSession
.findFirst(ClientSession::toIPCHandle(inDbHandle
),
307 CssmQuery::required(inQuery
),
312 return CSSM_INVALID_HANDLE
;
314 postGetRecord(record
, resultsHandle
, inDbHandle
, pAttributes
, inoutAttributes
, inoutData
, keyId
);
315 outUniqueRecord
= makeDbUniqueRecord(record
);
316 return resultsHandle
;
320 SDDLSession::DataGetNext(CSSM_DB_HANDLE inDbHandle
,
321 CSSM_HANDLE inResultsHandle
,
322 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
324 CSSM_DB_UNIQUE_RECORD_PTR
&outUniqueRecord
)
326 // Setup so we always retrieve the attributes if the client asks for data,
327 // even if the client doesn't want them so we can figure out if we just
329 CssmDbRecordAttributeData attributes
;
330 CssmDbRecordAttributeData
*pAttributes
;
332 pAttributes
= CssmDbRecordAttributeData::overlay(inoutAttributes
);
335 pAttributes
= &attributes
;
336 memset(pAttributes
, 0, sizeof(attributes
));
340 KeyHandle keyId
= noKey
;
341 record
= mClientSession
.findNext(ClientSession::toIPCHandle(inResultsHandle
),
347 postGetRecord(record
, CSSM_INVALID_HANDLE
, inDbHandle
, pAttributes
,
348 inoutAttributes
, inoutData
, keyId
);
349 outUniqueRecord
= makeDbUniqueRecord(record
);
354 SDDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle
,
355 CSSM_HANDLE inResultsHandle
)
357 mClientSession
.releaseSearch(ClientSession::toIPCHandle(inResultsHandle
));
361 SDDLSession::DataGetFromUniqueRecordId(CSSM_DB_HANDLE inDbHandle
,
362 const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
,
363 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
,
366 // Setup so we always retrieve the attributes if the client asks for data,
367 // even if the client doesn't want them so we can figure out if we just
369 CssmDbRecordAttributeData attributes
;
370 CssmDbRecordAttributeData
*pAttributes
;
372 pAttributes
= CssmDbRecordAttributeData::overlay(inoutAttributes
);
375 pAttributes
= &attributes
;
376 memset(pAttributes
, 0, sizeof(attributes
));
379 RecordHandle record
= ClientSession::toIPCHandle(findDbUniqueRecord(inUniqueRecord
));
380 KeyHandle keyId
= noKey
;
381 mClientSession
.findRecordHandle(record
, pAttributes
, inoutData
, keyId
);
382 postGetRecord(record
, CSSM_INVALID_HANDLE
, inDbHandle
, pAttributes
,
383 inoutAttributes
, inoutData
, keyId
);
387 SDDLSession::FreeUniqueRecord(CSSM_DB_HANDLE inDbHandle
,
388 CSSM_DB_UNIQUE_RECORD
&inUniqueRecordIdentifier
)
390 RecordHandle record
= ClientSession::toIPCHandle(findDbUniqueRecord(inUniqueRecordIdentifier
));
391 freeDbUniqueRecord(inUniqueRecordIdentifier
);
392 mClientSession
.releaseRecord(record
);
396 SDDLSession::PassThrough(CSSM_DB_HANDLE inDbHandle
,
397 uint32 inPassThroughId
,
398 const void *inInputParams
,
399 void **outOutputParams
)
401 switch (inPassThroughId
)
403 case CSSM_APPLECSPDL_DB_LOCK
:
404 mClientSession
.lock(ClientSession::toIPCHandle(inDbHandle
));
406 case CSSM_APPLECSPDL_DB_UNLOCK
:
408 TrackingAllocator
track(Allocator::standard());
409 AutoCredentials
creds(track
);
412 creds
+= TypedList(track
, CSSM_SAMPLE_TYPE_PASSWORD
,
413 new (track
) ListElement(track
,
414 *reinterpret_cast<const CssmData
*>(inInputParams
)));
416 creds
+= TypedList(track
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
,
417 new (track
) ListElement(track
, CssmData()));
419 Authenticate(inDbHandle
, CSSM_DB_ACCESS_READ
, creds
);
422 case CSSM_APPLECSPDL_DB_IS_LOCKED
:
424 if (!outOutputParams
)
425 CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER
);
427 bool isLocked
= mClientSession
.isLocked(ClientSession::toIPCHandle(inDbHandle
));
428 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params
=
429 DatabaseSession::alloc
<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS
>();
430 params
->isLocked
= isLocked
;
431 *reinterpret_cast<CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR
*>
432 (outOutputParams
) = params
;
435 case CSSM_APPLECSPDL_DB_CHANGE_PASSWORD
:
438 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
);
440 const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS
*params
=
442 <const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS
*>
445 AutoAclEntryInfoList acls
/* (mClientSession.allocator()) */;
446 CSSM_STRING tag
= { 'P', 'I', 'N', '1' };
447 GetDbAcl(inDbHandle
, &tag
,
448 *static_cast<uint32
*>(acls
),
449 *static_cast<CSSM_ACL_ENTRY_INFO
**>(acls
));
450 if (acls
.size() == 0)
451 CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND
);
453 const AclEntryInfo
&slot
= acls
.at(0);
456 "Using entry handle %ld from %d total candidates",
457 slot
.handle(), acls
.size());
458 AclEdit
edit(slot
.handle(), slot
.proto());
459 ChangeDbAcl(inDbHandle
,
460 AccessCredentials::required(params
->accessCredentials
), edit
);
463 case CSSM_APPLECSPDL_DB_RELATION_EXISTS
:
465 // We always return true so that the individual tokend can decide
466 if (!outOutputParams
)
467 CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER
);
468 *reinterpret_cast<CSSM_BOOL
*>(outOutputParams
) = true;
472 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID
);
476 CSSM_DB_UNIQUE_RECORD_PTR
477 SDDLSession::makeDbUniqueRecord(RecordHandle uniqueId
)
479 CSSM_DB_UNIQUE_RECORD
*aUniqueRecord
= DatabaseSession::alloc
<CSSM_DB_UNIQUE_RECORD
>();
480 memset(aUniqueRecord
, 0, sizeof(CSSM_DB_UNIQUE_RECORD
));
481 aUniqueRecord
->RecordIdentifier
.Length
= sizeof(CSSM_HANDLE
);
484 aUniqueRecord
->RecordIdentifier
.Data
= DatabaseSession::alloc
<uint8
>(sizeof(CSSM_HANDLE
));
485 *reinterpret_cast<CSSM_HANDLE
*>(aUniqueRecord
->RecordIdentifier
.Data
) = uniqueId
;
489 allocator().free(aUniqueRecord
);
493 return aUniqueRecord
;
496 // formerly returned a RecordHandle, but redefining them to be 32-bit made
499 SDDLSession::findDbUniqueRecord(const CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
501 if (inUniqueRecord
.RecordIdentifier
.Length
!= sizeof(CSSM_HANDLE
))
502 CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID
);
504 return *reinterpret_cast<CSSM_HANDLE
*>(inUniqueRecord
.RecordIdentifier
.Data
);
508 SDDLSession::freeDbUniqueRecord(CSSM_DB_UNIQUE_RECORD
&inUniqueRecord
)
510 if (inUniqueRecord
.RecordIdentifier
.Length
!= 0
511 && inUniqueRecord
.RecordIdentifier
.Data
!= NULL
)
513 inUniqueRecord
.RecordIdentifier
.Length
= 0;
514 allocator().free(inUniqueRecord
.RecordIdentifier
.Data
);
516 allocator().free(&inUniqueRecord
);