]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_sd_cspdl/lib/SDDLSession.cpp
Security-59306.120.7.tar.gz
[apple/security.git] / OSX / libsecurity_sd_cspdl / lib / SDDLSession.cpp
1 /*
2 * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved.
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
36 using namespace CssmClient;
37 using namespace SecurityServer;
38 using namespace std;
39
40 //
41 // SDDLSession -- Security Server DL session
42 //
43 SDDLSession::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) :
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))
57 {
58 }
59
60 SDDLSession::~SDDLSession()
61 {
62 }
63
64 // Utility functions
65 void
66 SDDLSession::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
74 void
75 SDDLSession::FreeNameList(CSSM_NAME_LIST &inNameList)
76 {
77 this->PluginSession::free(inNameList.String);
78 }
79
80
81 void
82 SDDLSession::DbDelete(const char *inDbName,
83 const CSSM_NET_ADDRESS *inDbLocation,
84 const AccessCredentials *inAccessCred)
85 {
86 unimplemented();
87 }
88
89 // DbContext creation and destruction.
90 void
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)
98 {
99 unimplemented();
100 }
101
102 void
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)
109 {
110 outDbHandle = mClientSession.openToken(subserviceId(), inAccessCred, inDbName);
111 }
112
113 // Operations using DbContext instances.
114 void
115 SDDLSession::DbClose(CSSM_DB_HANDLE inDbHandle)
116 {
117 mClientSession.releaseDb(ClientSession::toIPCHandle(inDbHandle));
118 }
119
120 void
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)
128 {
129 unimplemented();
130 }
131
132 void
133 SDDLSession::DestroyRelation(CSSM_DB_HANDLE inDbHandle,
134 CSSM_DB_RECORDTYPE inRelationID)
135 {
136 unimplemented();
137 }
138
139 void
140 SDDLSession::Authenticate(CSSM_DB_HANDLE inDbHandle,
141 CSSM_DB_ACCESS_TYPE inAccessRequest,
142 const AccessCredentials &inAccessCred)
143 {
144 mClientSession.authenticateDb((DbHandle)inDbHandle, inAccessRequest, &inAccessCred);
145 }
146
147
148 void
149 SDDLSession::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
159 void
160 SDDLSession::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
167 void
168 SDDLSession::GetDbOwner(CSSM_DB_HANDLE inDbHandle,
169 CSSM_ACL_OWNER_PROTOTYPE &outOwner)
170 {
171 mClientSession.getDbOwner(ClientSession::toIPCHandle(inDbHandle), AclOwnerPrototype::overlay(outOwner));
172 }
173
174 void
175 SDDLSession::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
182 void
183 SDDLSession::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
192 void
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)
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
207 void
208 SDDLSession::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
216 void
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)
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
231 void
232 SDDLSession::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(...) { secinfo("ssCrypt", "releaseRecord threw during catch"); }
266 if (resultsHandle != CSSM_INVALID_HANDLE)
267 {
268 try { mClientSession.releaseSearch(resultsHandle); }
269 catch(...) { secinfo("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(...) { secinfo("ssCrypt", "failed releasing bogus key handle"); }
277 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
278 }
279 }
280 }
281 }
282
283 CSSM_HANDLE
284 SDDLSession::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
319 bool
320 SDDLSession::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
353 void
354 SDDLSession::DataAbortQuery(CSSM_DB_HANDLE inDbHandle,
355 CSSM_HANDLE inResultsHandle)
356 {
357 mClientSession.releaseSearch(ClientSession::toIPCHandle(inResultsHandle));
358 }
359
360 void
361 SDDLSession::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
386 void
387 SDDLSession::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
395 void
396 SDDLSession::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 secinfo("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
476 CSSM_DB_UNIQUE_RECORD_PTR
477 SDDLSession::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
498 CSSM_HANDLE
499 SDDLSession::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
507 void
508 SDDLSession::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 }