]> git.saurik.com Git - apple/security.git/blame - Security/libsecurity_sd_cspdl/lib/SDDLSession.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_sd_cspdl / lib / SDDLSession.cpp
CommitLineData
b1ab9ed8 1/*
d8f41ccd 2 * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved.
b1ab9ed8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// SDDLSession.h - DL session for security server CSP/DL.
27//
28#include "SDDLSession.h"
29
30#include "SDCSPDLPlugin.h"
31#include "SDKey.h"
32#include <security_cdsa_utilities/cssmbridge.h>
33#include <security_utilities/trackingallocator.h>
34#include <Security/cssmapplePriv.h>
35
36using namespace CssmClient;
37using namespace SecurityServer;
38using namespace std;
39
40//
41// SDDLSession -- Security Server DL session
42//
43SDDLSession::SDDLSession(CSSM_MODULE_HANDLE handle,
44 SDCSPDLPlugin &plug,
45 const CSSM_VERSION &version,
46 uint32 subserviceId,
47 CSSM_SERVICE_TYPE subserviceType,
48 CSSM_ATTACH_FLAGS attachFlags,
49 const CSSM_UPCALLS &upcalls,
50 DatabaseManager &databaseManager,
51 SDCSPDLSession &ssCSPDLSession) :
52DLPluginSession(handle, plug, version, subserviceId, subserviceType,
53 attachFlags, upcalls, databaseManager),
54mSDCSPDLSession(ssCSPDLSession),
55mClientSession(Allocator::standard(), static_cast<PluginSession &>(*this))
56//mAttachment(mClientSession.attach(version, subserviceId, subserviceType, attachFlags))
57{
58}
59
60SDDLSession::~SDDLSession()
61{
62}
63
64// Utility functions
65void
66SDDLSession::GetDbNames(CSSM_NAME_LIST_PTR &outNameList)
67{
68 outNameList->String = this->PluginSession::alloc<char *>();
69 outNameList->NumStrings = 1;
70 outNameList->String[0] = (char*) ""; // empty name will trigger dynamic lookup
71}
72
73
74void
75SDDLSession::FreeNameList(CSSM_NAME_LIST &inNameList)
76{
77 this->PluginSession::free(inNameList.String);
78}
79
80
81void
82SDDLSession::DbDelete(const char *inDbName,
83 const CSSM_NET_ADDRESS *inDbLocation,
84 const AccessCredentials *inAccessCred)
85{
86 unimplemented();
87}
88
89// DbContext creation and destruction.
90void
91SDDLSession::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)
98{
99 unimplemented();
100}
101
102void
103SDDLSession::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)
109{
110 outDbHandle = mClientSession.openToken(subserviceId(), inAccessCred, inDbName);
111}
112
113// Operations using DbContext instances.
114void
115SDDLSession::DbClose(CSSM_DB_HANDLE inDbHandle)
116{
117 mClientSession.releaseDb(ClientSession::toIPCHandle(inDbHandle));
118}
119
120void
121SDDLSession::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)
128{
129 unimplemented();
130}
131
132void
133SDDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle,
134 CSSM_DB_RECORDTYPE inRelationID)
135{
136 unimplemented();
137}
138
139void
140SDDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle,
141 CSSM_DB_ACCESS_TYPE inAccessRequest,
142 const AccessCredentials &inAccessCred)
143{
427c49bc 144 mClientSession.authenticateDb((DbHandle)inDbHandle, inAccessRequest, &inAccessCred);
b1ab9ed8
A
145}
146
147
148void
149SDDLSession::GetDbAcl(CSSM_DB_HANDLE inDbHandle,
150 const CSSM_STRING *inSelectionTag,
151 uint32 &outNumberOfAclInfos,
152 CSSM_ACL_ENTRY_INFO_PTR &outAclInfos)
153{
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));
157}
158
159void
160SDDLSession::ChangeDbAcl(CSSM_DB_HANDLE inDbHandle,
161 const AccessCredentials &inAccessCred,
162 const CSSM_ACL_EDIT &inAclEdit)
163{
164 mClientSession.changeDbAcl(ClientSession::toIPCHandle(inDbHandle), inAccessCred, AclEdit::overlay(inAclEdit));
165}
166
167void
168SDDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle,
169 CSSM_ACL_OWNER_PROTOTYPE &outOwner)
170{
171 mClientSession.getDbOwner(ClientSession::toIPCHandle(inDbHandle), AclOwnerPrototype::overlay(outOwner));
172}
173
174void
175SDDLSession::ChangeDbOwner(CSSM_DB_HANDLE inDbHandle,
176 const AccessCredentials &inAccessCred,
177 const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner)
178{
179 mClientSession.changeDbOwner(ClientSession::toIPCHandle(inDbHandle), inAccessCred, AclOwnerPrototype::overlay(inNewOwner));
180}
181
182void
183SDDLSession::GetDbNameFromHandle(CSSM_DB_HANDLE inDbHandle,
184 char **outDbName)
185{
186 string name;
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);
190}
191
192void
193SDDLSession::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)
198{
199 RecordHandle record;
200 record = mClientSession.insertRecord(ClientSession::toIPCHandle(inDbHandle),
201 inRecordType,
202 CssmDbRecordAttributeData::overlay(inAttributes),
203 inData);
204 outUniqueId = makeDbUniqueRecord(record);
205}
206
207void
208SDDLSession::DataDelete(CSSM_DB_HANDLE inDbHandle,
209 const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
210{
211 RecordHandle record = ClientSession::toIPCHandle(findDbUniqueRecord(inUniqueRecordIdentifier));
212 mClientSession.deleteRecord(ClientSession::toIPCHandle(inDbHandle), record);
213}
214
215
216void
217SDDLSession::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)
223{
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"...
229}
230
231void
232SDDLSession::postGetRecord(RecordHandle record, U32HandleObject::Handle resultsHandle,
233 CSSM_DB_HANDLE db,
234 CssmDbRecordAttributeData *pAttributes,
235 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
236 CssmData *inoutData, KeyHandle hKey)
237{
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.
240 if (inoutData)
241 {
242 CSSM_DB_RECORDTYPE recordType = pAttributes->DataRecordType;
243 if (!inoutAttributes)
244 {
245 // @@@ Free pAttributes
246 }
247
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)
251 {
252 // This record is a key. The data returned is a CSSM_KEY
253 // (with empty key data) with the header filled in.
254 try
255 {
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);
261 }
262 catch (...)
263 {
264 try { mClientSession.releaseRecord(record); }
265 catch(...) { secdebug("ssCrypt", "releaseRecord threw during catch"); }
266 if (resultsHandle != CSSM_INVALID_HANDLE)
267 {
268 try { mClientSession.releaseSearch(resultsHandle); }
269 catch(...) { secdebug("ssCrypt", "releaseSearch threw during catch"); }
270 }
271 throw;
272 }
273 } else { // not a key
274 if (hKey != noKey) {
275 try { mClientSession.releaseRecord(record); }
276 catch(...) { secdebug("ssCrypt", "failed releasing bogus key handle"); }
277 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
278 }
279 }
280 }
281}
282
283CSSM_HANDLE
284SDDLSession::DataGetFirst(CSSM_DB_HANDLE inDbHandle,
285 const CssmQuery *inQuery,
286 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
287 CssmData *inoutData,
288 CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
289{
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
292 // retrieved a key.
293 CssmDbRecordAttributeData attributes;
294 CssmDbRecordAttributeData *pAttributes;
295 if (inoutAttributes)
296 pAttributes = CssmDbRecordAttributeData::overlay(inoutAttributes);
297 else
298 {
299 pAttributes = &attributes;
300 memset(pAttributes, 0, sizeof(attributes));
301 }
302
303 RecordHandle record;
304 SearchHandle resultsHandle = noSearch;
305 KeyHandle keyId = noKey;
306 record = mClientSession.findFirst(ClientSession::toIPCHandle(inDbHandle),
307 CssmQuery::required(inQuery),
308 resultsHandle,
309 pAttributes,
310 inoutData, keyId);
311 if (!record)
312 return CSSM_INVALID_HANDLE;
313
314 postGetRecord(record, resultsHandle, inDbHandle, pAttributes, inoutAttributes, inoutData, keyId);
315 outUniqueRecord = makeDbUniqueRecord(record);
316 return resultsHandle;
317}
318
319bool
320SDDLSession::DataGetNext(CSSM_DB_HANDLE inDbHandle,
321 CSSM_HANDLE inResultsHandle,
322 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
323 CssmData *inoutData,
324 CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
325{
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
328 // retrieved a key.
329 CssmDbRecordAttributeData attributes;
330 CssmDbRecordAttributeData *pAttributes;
331 if (inoutAttributes)
332 pAttributes = CssmDbRecordAttributeData::overlay(inoutAttributes);
333 else
334 {
335 pAttributes = &attributes;
336 memset(pAttributes, 0, sizeof(attributes));
337 }
338
339 RecordHandle record;
340 KeyHandle keyId = noKey;
341 record = mClientSession.findNext(ClientSession::toIPCHandle(inResultsHandle),
342 pAttributes,
343 inoutData, keyId);
344 if (!record)
345 return false;
346
347 postGetRecord(record, CSSM_INVALID_HANDLE, inDbHandle, pAttributes,
348 inoutAttributes, inoutData, keyId);
349 outUniqueRecord = makeDbUniqueRecord(record);
350 return true;
351}
352
353void
354SDDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle,
355 CSSM_HANDLE inResultsHandle)
356{
357 mClientSession.releaseSearch(ClientSession::toIPCHandle(inResultsHandle));
358}
359
360void
361SDDLSession::DataGetFromUniqueRecordId(CSSM_DB_HANDLE inDbHandle,
362 const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
363 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
364 CssmData *inoutData)
365{
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
368 // retrieved a key.
369 CssmDbRecordAttributeData attributes;
370 CssmDbRecordAttributeData *pAttributes;
371 if (inoutAttributes)
372 pAttributes = CssmDbRecordAttributeData::overlay(inoutAttributes);
373 else
374 {
375 pAttributes = &attributes;
376 memset(pAttributes, 0, sizeof(attributes));
377 }
378
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);
384}
385
386void
387SDDLSession::FreeUniqueRecord(CSSM_DB_HANDLE inDbHandle,
388 CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier)
389{
390 RecordHandle record = ClientSession::toIPCHandle(findDbUniqueRecord(inUniqueRecordIdentifier));
391 freeDbUniqueRecord(inUniqueRecordIdentifier);
392 mClientSession.releaseRecord(record);
393}
394
395void
396SDDLSession::PassThrough(CSSM_DB_HANDLE inDbHandle,
397 uint32 inPassThroughId,
398 const void *inInputParams,
399 void **outOutputParams)
400{
401 switch (inPassThroughId)
402 {
403 case CSSM_APPLECSPDL_DB_LOCK:
404 mClientSession.lock(ClientSession::toIPCHandle(inDbHandle));
405 break;
406 case CSSM_APPLECSPDL_DB_UNLOCK:
407 {
408 TrackingAllocator track(Allocator::standard());
409 AutoCredentials creds(track);
410 creds.tag("PIN1");
411 if (inInputParams)
412 creds += TypedList(track, CSSM_SAMPLE_TYPE_PASSWORD,
413 new (track) ListElement(track,
414 *reinterpret_cast<const CssmData *>(inInputParams)));
415 else
416 creds += TypedList(track, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
417 new (track) ListElement(track, CssmData()));
418
419 Authenticate(inDbHandle, CSSM_DB_ACCESS_READ, creds);
420 break;
421 }
422 case CSSM_APPLECSPDL_DB_IS_LOCKED:
423 {
424 if (!outOutputParams)
425 CssmError::throwMe(CSSM_ERRCODE_INVALID_OUTPUT_POINTER);
426
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;
433 break;
434 }
435 case CSSM_APPLECSPDL_DB_CHANGE_PASSWORD:
436 {
437 if (!inInputParams)
438 CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
439
440 const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *params =
441 reinterpret_cast
442 <const CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS *>
443 (inInputParams);
444
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);
452
453 const AclEntryInfo &slot = acls.at(0);
454 if (acls.size() > 1)
455 secdebug("acl",
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);
461 break;
462 }
463 case CSSM_APPLECSPDL_DB_RELATION_EXISTS:
464 {
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;
469 break;
470 }
471 default:
472 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
473 }
474}
475
476CSSM_DB_UNIQUE_RECORD_PTR
477SDDLSession::makeDbUniqueRecord(RecordHandle uniqueId)
478{
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);
482 try
483 {
484 aUniqueRecord->RecordIdentifier.Data = DatabaseSession::alloc<uint8>(sizeof(CSSM_HANDLE));
485 *reinterpret_cast<CSSM_HANDLE *>(aUniqueRecord->RecordIdentifier.Data) = uniqueId;
486 }
487 catch(...)
488 {
489 allocator().free(aUniqueRecord);
490 throw;
491 }
492
493 return aUniqueRecord;
494}
495
496// formerly returned a RecordHandle, but redefining them to be 32-bit made
497// that untenable
498CSSM_HANDLE
499SDDLSession::findDbUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
500{
501 if (inUniqueRecord.RecordIdentifier.Length != sizeof(CSSM_HANDLE))
502 CssmError::throwMe(CSSMERR_DL_INVALID_RECORD_UID);
503
504 return *reinterpret_cast<CSSM_HANDLE *>(inUniqueRecord.RecordIdentifier.Data);
505}
506
507void
508SDDLSession::freeDbUniqueRecord(CSSM_DB_UNIQUE_RECORD &inUniqueRecord)
509{
510 if (inUniqueRecord.RecordIdentifier.Length != 0
511 && inUniqueRecord.RecordIdentifier.Data != NULL)
512 {
513 inUniqueRecord.RecordIdentifier.Length = 0;
514 allocator().free(inUniqueRecord.RecordIdentifier.Data);
515 }
516 allocator().free(&inUniqueRecord);
517}