]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/dlclient.cpp
Security-57337.60.2.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_client / lib / dlclient.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // dlclient - client interface to CSSM DLs and their operations
21 //
22 #include <security_cdsa_client/dlclient.h>
23 #include <security_cdsa_client/aclclient.h>
24 #include <Security/cssmapple.h>
25 #include <Security/cssmapplePriv.h>
26 #include <Security/SecBase.h>
27 #include <security_cdsa_utilities/Schema.h>
28
29 using namespace CssmClient;
30
31 #pragma clang diagnostic push
32 #pragma clang diagnostic ignored "-Wunused-const-variable"
33 // blob type for blobs created by these classes -- done so that we can change the formats later
34 const uint32 kBlobType = 0x1;
35 #pragma clang diagnostic pop
36
37 //
38 // Abstract classes
39 //
40 DbMaker::~DbMaker()
41 { /* virtual */ }
42
43 DbCursorMaker::~DbCursorMaker()
44 { /* virtual */ }
45
46 DbUniqueRecordMaker::~DbUniqueRecordMaker()
47 { /* virtual */ }
48
49
50 //
51 // Manage DL attachments
52 //
53 DLImpl::DLImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_DL)
54 {
55 }
56
57 DLImpl::DLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_DL)
58 {
59 }
60
61 DLImpl::~DLImpl()
62 {
63 }
64
65 void
66 DLImpl::getDbNames(char **)
67 {
68 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
69 }
70
71 void
72 DLImpl::freeNameList(char **)
73 {
74 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
75 }
76
77 DbImpl *
78 DLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
79 {
80 return new DbImpl(DL(this), inDbName, inDbLocation);
81 }
82
83
84 //
85 // Db (database)
86 //
87 DbImpl::DbImpl(const DL &dl, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
88 : ObjectImpl(dl), mDbName(inDbName, inDbLocation),
89 mUseNameFromHandle(!inDbName), mNameFromHandle(NULL),
90 mAccessRequest(CSSM_DB_ACCESS_READ), mAccessCredentials(NULL),
91 mDefaultCredentials(NULL), mOpenParameters(NULL), mDbInfo(NULL),
92 mResourceControlContext(NULL)
93 {
94 }
95
96 DbImpl::~DbImpl()
97 {
98 try
99 {
100 if (mNameFromHandle)
101 allocator().free(mNameFromHandle);
102 deactivate();
103 }
104 catch(...) {}
105 }
106
107 void
108 DbImpl::open()
109 {
110 {
111 StLock<Mutex> _(mActivateMutex);
112 if (!mActive)
113 {
114 assert(mDbInfo == nil);
115 mHandle.DLHandle = dl()->handle();
116 check(CSSM_DL_DbOpen(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
117 mAccessRequest, mAccessCredentials,
118 mOpenParameters, &mHandle.DBHandle));
119
120 mActive = true;
121 }
122 }
123
124 if (!mAccessCredentials && mDefaultCredentials)
125 if (const AccessCredentials *creds = mDefaultCredentials->makeCredentials())
126 CSSM_DL_Authenticate(handle(), mAccessRequest, creds); // ignore error
127 }
128
129 void
130 DbImpl::createWithBlob(CssmData &blob)
131 {
132 if (mActive)
133 CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
134
135 if (mDbInfo == nil) {
136 // handle a missing (null) mDbInfo as an all-zero one
137 static const CSSM_DBINFO nullDbInfo = { };
138 mDbInfo = &nullDbInfo;
139 }
140
141 mHandle.DLHandle = dl()->handle();
142
143 // create a parameter block for our call to the passthrough
144 CSSM_APPLE_CSPDL_DB_CREATE_WITH_BLOB_PARAMETERS params;
145
146 params.dbName = mDbName.canonicalName ();
147 params.dbLocation = dbLocation ();
148 params.dbInfo = mDbInfo;
149 params.accessRequest = mAccessRequest;
150 params.credAndAclEntry = NULL;
151 params.openParameters = mOpenParameters;
152 params.blob = &blob;
153
154 check(CSSM_DL_PassThrough (mHandle, CSSM_APPLECSPDL_DB_CREATE_WITH_BLOB, &params, (void**) &mHandle.DBHandle));
155 }
156
157 void
158 DbImpl::create()
159 {
160 StLock<Mutex> _(mActivateMutex);
161 if (mActive)
162 CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
163
164 if (mDbInfo == nil) {
165 // handle a missing (null) mDbInfo as an all-zero one
166 static const CSSM_DBINFO nullDbInfo = { };
167 mDbInfo = &nullDbInfo;
168 }
169 mHandle.DLHandle = dl()->handle();
170
171 if (!mResourceControlContext && mAccessCredentials) {
172 AclFactory::AnyResourceContext ctx(mAccessCredentials);
173 check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
174 mDbInfo, mAccessRequest, &ctx,
175 mOpenParameters, &mHandle.DBHandle));
176 } else {
177 check(CSSM_DL_DbCreate(mHandle.DLHandle, mDbName.canonicalName(), dbLocation(),
178 mDbInfo, mAccessRequest, mResourceControlContext,
179 mOpenParameters, &mHandle.DBHandle));
180 }
181 mActive = true;
182 }
183
184 void
185 DbImpl::close()
186 {
187 StLock<Mutex> _(mActivateMutex);
188 if (mActive)
189 {
190 check(CSSM_DL_DbClose (mHandle));
191 mActive = false;
192 }
193 }
194
195 void
196 DbImpl::activate()
197 {
198 if (!mActive)
199 {
200 if (mDbInfo)
201 create();
202 else
203 open();
204 }
205 }
206
207 void
208 DbImpl::deactivate()
209 {
210 StLock<Mutex> _(mActivateMutex);
211 if (mActive)
212 {
213 mActive = false;
214 close();
215 }
216 }
217
218 void
219 DbImpl::deleteDb()
220 {
221 // Deactivate so the db gets closed if it was open.
222 deactivate();
223 // This call does not require the receiver to be active.
224 check(CSSM_DL_DbDelete(dl()->handle(), mDbName.canonicalName(), dbLocation(),
225 mAccessCredentials));
226 }
227
228 void
229 DbImpl::rename(const char *newName)
230 {
231 // Deactivate so the db gets closed if it was open.
232 deactivate();
233 if (::rename(mDbName.canonicalName(), newName))
234 UnixError::throwMe(errno);
235
236 // Change our DbName to reflect this rename.
237 mDbName = DbName(newName, dbLocation());
238 }
239
240 void
241 DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
242 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
243 {
244 if (!mActive)
245 {
246 // XXX Could do the same for create but this would require sticking
247 // inAccessCredentials into mResourceControlContext.
248 if (!mDbInfo)
249 {
250 // We were not yet active. Just do an open.
251 accessRequest(inAccessRequest);
252 accessCredentials(inAccessCredentials);
253 activate();
254 return;
255 }
256 }
257
258 check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
259 }
260
261 void
262 DbImpl::name(char *&outDbName)
263 {
264 check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
265 }
266
267 const char *
268 DbImpl::name()
269 {
270 if (mUseNameFromHandle)
271 {
272 if (mNameFromHandle
273 || !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle))
274 {
275 return mNameFromHandle;
276 }
277
278 // We failed to get the name from the handle so use the passed
279 // in name instead
280 mUseNameFromHandle = false;
281 }
282
283 return mDbName.canonicalName();
284 }
285
286 void
287 DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
288 const char *inRelationName,
289 uint32 inNumberOfAttributes,
290 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
291 uint32 inNumberOfIndexes,
292 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
293 {
294 check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
295 inNumberOfAttributes, pAttributeInfo,
296 inNumberOfIndexes, pIndexInfo));
297 }
298
299 void
300 DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
301 {
302 check(CSSM_DL_DestroyRelation(handle(), inRelationID));
303 }
304
305 DbUniqueRecord
306 DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
307 const CSSM_DATA *data)
308 {
309 DbUniqueRecord uniqueId(Db(this));
310 check(CSSM_DL_DataInsert(handle(), recordType,
311 attributes,
312 data, uniqueId));
313 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
314 uniqueId->activate();
315 return uniqueId;
316 }
317
318
319 DbUniqueRecord
320 DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
321 CSSM_DATA *data)
322 {
323 DbUniqueRecord uniqueId(Db(this));
324
325 // fill out the parameters
326 CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params;
327 params.recordType = recordType;
328 params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
329 params.data = *data;
330
331 // for clarity, call the overloaded operator to produce a unique record pointer
332 CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = uniqueId;
333
334 // make the call
335 passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION, &params, (void**) uniquePtr);
336
337 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
338 uniqueId->activate();
339 return uniqueId;
340 }
341
342
343 //
344 // Generic Passthrough interface
345 //
346 void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
347 {
348 check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
349 }
350
351
352 //
353 // Passthrough functions (only implemented by AppleCSPDL).
354 //
355 void
356 DbImpl::lock()
357 {
358 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
359 }
360
361 void
362 DbImpl::unlock()
363 {
364 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
365 }
366
367 void
368 DbImpl::unlock(const CSSM_DATA &password)
369 {
370 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
371 }
372
373 void
374 DbImpl::stash()
375 {
376 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH, NULL, NULL));
377 }
378
379 void
380 DbImpl::stashCheck()
381 {
382 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH_CHECK, NULL, NULL));
383 }
384
385 void
386 DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
387 {
388 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
389 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
390 NULL, reinterpret_cast<void **>(&settings)));
391 outIdleTimeout = settings->idleTimeout;
392 outLockOnSleep = settings->lockOnSleep;
393 allocator().free(settings);
394 }
395
396 void
397 DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
398 {
399 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
400 settings.idleTimeout = inIdleTimeout;
401 settings.lockOnSleep = inLockOnSleep;
402 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
403 }
404
405 bool
406 DbImpl::isLocked()
407 {
408 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
409 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
410 NULL, reinterpret_cast<void **>(&params)));
411 bool isLocked = params->isLocked;
412 allocator().free(params);
413 return isLocked;
414 }
415
416 void
417 DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
418 {
419 CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
420 params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
421 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, &params, NULL));
422 }
423
424 void DbImpl::recode(const CSSM_DATA &data, const CSSM_DATA &extraData)
425 {
426 // setup parameters for the recode call
427 CSSM_APPLECSPDL_RECODE_PARAMETERS params;
428 params.dbBlob = data;
429 params.extraData = extraData;
430
431 // do the call
432 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE, &params, NULL));
433 }
434
435 void DbImpl::copyBlob (CssmData &data)
436 {
437 // do the call
438 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB, NULL, (void**) (CSSM_DATA*) &data));
439 }
440
441 void DbImpl::setBatchMode(Boolean mode, Boolean rollback)
442 {
443 //
444 // We need the DL_DB_Handle of the underyling DL in order to use CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
445 //
446 CSSM_RETURN result;
447 CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL;
448 result = CSSM_DL_PassThrough(handle(),
449 CSSM_APPLECSPDL_DB_GET_HANDLE,
450 NULL,
451 (void **)&dldbHandleOfUnderlyingDL);
452 //
453 // Now, toggle the autocommit...
454 //
455 if ( result == errSecSuccess )
456 {
457 CSSM_BOOL modeToUse = !mode;
458 if (rollback)
459 {
460 result = (OSStatus)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
461 CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
462 }
463
464 result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
465 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
466 (void *)((size_t) modeToUse),
467 NULL);
468 if (!rollback && modeToUse)
469 result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
470 CSSM_APPLEFILEDL_COMMIT,
471 NULL,
472 NULL);
473 }
474 }
475
476 uint32 DbImpl::dbBlobVersion() {
477 uint32 dbBlobVersion = 0;
478 uint32* dbBlobVersionPtr = &dbBlobVersion;
479
480 // We only have a blob version if we're an apple CSPDL
481 if(dl()->guid() == gGuidAppleCSPDL) {
482 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_BLOB_VERSION, NULL, (void**) &dbBlobVersionPtr));
483 } else {
484 secdebugfunc("integrity", "Non-Apple CSPDL keychains don't have keychain versions");
485 }
486 return dbBlobVersion;
487 }
488
489 uint32 DbImpl::recodeDbToVersion(uint32 version) {
490 uint32 newDbVersion;
491 uint32* newDbVersionPtr = &newDbVersion;
492 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_TO_BLOB_VERSION, &version, (void**) &newDbVersionPtr));
493 return newDbVersion;
494 }
495
496 void DbImpl::takeFileLock() {
497 passThrough(CSSM_APPLECSPDL_DB_TAKE_FILE_LOCK, NULL, NULL);
498 }
499
500 void DbImpl::releaseFileLock(bool success) {
501 passThrough(CSSM_APPLECSPDL_DB_RELEASE_FILE_LOCK, &success, NULL);
502 }
503
504 void DbImpl::makeBackup() {
505 passThrough(CSSM_APPLECSPDL_DB_MAKE_BACKUP, NULL, NULL);
506 }
507
508 //
509 // DbCursorMaker
510 //
511 DbCursorImpl *
512 DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
513 {
514 return new DbDbCursorImpl(Db(this), query, allocator);
515 }
516
517 DbCursorImpl *
518 DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
519 {
520 return new DbDbCursorImpl(Db(this), capacity, allocator);
521 }
522
523
524 //
525 // Db adapters for AclBearer
526 //
527 void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
528 {
529 aclInfos.allocator(allocator());
530 check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
531 reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
532 }
533
534 void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
535 const CSSM_ACCESS_CREDENTIALS *accessCred)
536 {
537 check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
538 }
539
540 void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
541 {
542 owner.allocator(allocator());
543 check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
544 }
545
546 void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
547 const CSSM_ACCESS_CREDENTIALS *accessCred)
548 {
549 check(CSSM_DL_ChangeDbOwner(handle(),
550 AccessCredentials::needed(accessCred), &newOwner));
551 }
552
553 void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
554 {
555 mDefaultCredentials = maker;
556 }
557
558
559 //
560 // Abstract DefaultCredentialsMakers
561 //
562 DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
563 { /* virtual */ }
564
565
566 //
567 // Db adapters for DLAccess
568 //
569 CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
570 CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
571 {
572 CSSM_HANDLE result;
573 switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
574 case CSSM_OK:
575 return result;
576 case CSSMERR_DL_ENDOFDATA:
577 return CSSM_INVALID_HANDLE;
578 default:
579 CssmError::throwMe(rc);
580 return CSSM_INVALID_HANDLE; // placebo
581 }
582 }
583
584 bool Db::dlGetNext(CSSM_HANDLE query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
585 CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
586 {
587 CSSM_RETURN rc = CSSM_DL_DataGetNext(handle(), query, &attributes, data, &id);
588 switch (rc) {
589 case CSSM_OK:
590 return true;
591 case CSSMERR_DL_ENDOFDATA:
592 return false;
593 default:
594 CssmError::throwMe(rc);
595 return false; // placebo
596 }
597 }
598
599 void Db::dlAbortQuery(CSSM_HANDLE query)
600 {
601 CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
602 }
603
604 void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
605 {
606 CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
607 }
608
609 void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
610 {
611 CssmError::check(CSSM_DL_DataDelete(handle(), id));
612 }
613
614 Allocator &Db::allocator()
615 {
616 return Object::allocator();
617 }
618
619
620 //
621 // DbUniqueRecordMaker
622 //
623 DbUniqueRecordImpl *
624 DbImpl::newDbUniqueRecord()
625 {
626 return new DbUniqueRecordImpl(Db(this));
627 }
628
629
630 //
631 // Utility methods
632 //
633 DLDbIdentifier
634 DbImpl::dlDbIdentifier()
635 {
636 // Always use the same dbName and dbLocation that were passed in during
637 // construction
638 return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
639 }
640
641
642 //
643 // DbDbCursorImpl
644 //
645 DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
646 : DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
647 {
648 }
649
650 DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
651 : DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
652 {
653 }
654
655 DbDbCursorImpl::~DbDbCursorImpl()
656 {
657 try
658 {
659 deactivate();
660 }
661 catch(...) {}
662 }
663
664 bool
665 DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
666 {
667 if (attributes)
668 attributes->deleteValues();
669
670 if (data)
671 data->clear();
672
673 CSSM_RETURN result;
674 Db db(database());
675 DbUniqueRecord unique(db);
676 if (!mActive)
677 {
678 // ask the CSP/DL if the requested record type exists
679 CSSM_BOOL boolResult;
680 CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
681 if (!boolResult)
682 {
683 if (data != NULL)
684 {
685 data->invalidate();
686 }
687
688 return false;
689 }
690
691 result = CSSM_DL_DataGetFirst(db->handle(),
692 this,
693 &mResultsHandle,
694 attributes,
695 data,
696 unique);
697
698 StLock<Mutex> _(mActivateMutex);
699 if (result == CSSM_OK)
700 mActive = true;
701 else if (data != NULL)
702 data->invalidate ();
703 }
704 else
705 {
706 result = CSSM_DL_DataGetNext(db->handle(),
707 mResultsHandle,
708 attributes,
709 data,
710 unique);
711
712 if (result != CSSM_OK && data != NULL)
713 {
714 data->invalidate ();
715 }
716 }
717
718 if (result != CSSM_OK && attributes != NULL)
719 {
720 attributes->invalidate();
721 }
722
723 if (result == CSSMERR_DL_ENDOFDATA)
724 {
725 StLock<Mutex> _(mActivateMutex);
726 mActive = false;
727 return false;
728 }
729
730 check(result);
731
732 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
733 unique->activate();
734 uniqueId = unique;
735 return true;
736 }
737
738 void
739 DbDbCursorImpl::activate()
740 {
741 }
742
743 void
744 DbDbCursorImpl::deactivate()
745 {
746 StLock<Mutex> _(mActivateMutex);
747 if (mActive)
748 {
749 mActive = false;
750 check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
751 }
752 }
753
754
755 //
756 // DbCursorImpl
757 //
758 DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
759 ObjectImpl(parent), CssmAutoQuery(query, allocator)
760 {
761 }
762
763 DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
764 ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
765 {
766 }
767
768 Allocator &
769 DbCursorImpl::allocator() const
770 {
771 return ObjectImpl::allocator();
772 }
773
774 void
775 DbCursorImpl::allocator(Allocator &alloc)
776 {
777 ObjectImpl::allocator(alloc);
778 }
779
780
781 //
782 // DbUniqueRecord
783 //
784 DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
785 {
786 }
787
788 DbUniqueRecordImpl::~DbUniqueRecordImpl()
789 {
790 try
791 {
792 if (mDestroyID)
793 {
794 allocator ().free (mUniqueId);
795 }
796
797 deactivate();
798 }
799 catch(...) {}
800 }
801
802 void
803 DbUniqueRecordImpl::deleteRecord()
804 {
805 check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
806 }
807
808 void
809 DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
810 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
811 const CSSM_DATA *data,
812 CSSM_DB_MODIFY_MODE modifyMode)
813 {
814 check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
815 attributes,
816 data, modifyMode));
817 }
818
819 void
820 DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
821 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
822 const CSSM_DATA *data,
823 CSSM_DB_MODIFY_MODE modifyMode)
824 {
825 // fill out the parameters
826 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
827 params.recordType = recordType;
828 params.uniqueID = mUniqueId;
829 params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
830 params.data = (CSSM_DATA*) data;
831 params.modifyMode = modifyMode;
832
833 // modify the data
834 check(CSSM_DL_PassThrough(database()->handle(),
835 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
836 &params,
837 NULL));
838 }
839
840 void
841 DbUniqueRecordImpl::get(DbAttributes *attributes,
842 ::CssmDataContainer *data)
843 {
844 if (attributes)
845 attributes->deleteValues();
846
847 if (data)
848 data->clear();
849
850 // @@@ Fix the allocators for attributes and data.
851 CSSM_RETURN result;
852 result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
853 attributes,
854 data);
855
856 if (result != CSSM_OK)
857 {
858 if (attributes)
859 attributes->invalidate();
860 if (data != NULL) // the data returned is no longer valid
861 {
862 data->invalidate ();
863 }
864 }
865
866 check(result);
867 }
868
869 void
870 DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
871 ::CssmDataContainer *data)
872 {
873 if (attributes)
874 attributes->deleteValues();
875
876 if (data)
877 data->clear();
878
879 // @@@ Fix the allocators for attributes and data.
880 CSSM_RETURN result;
881
882 // make the parameter block
883 CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
884 params.uniqueID = mUniqueId;
885 params.attributes = attributes;
886
887 // get the data
888 ::CssmDataContainer recordData;
889 result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, &params,
890 (void**) data);
891 check (result);
892 }
893
894 void
895 DbUniqueRecordImpl::activate()
896 {
897 StLock<Mutex> _(mActivateMutex);
898 mActive = true;
899 }
900
901 void
902 DbUniqueRecordImpl::deactivate()
903 {
904 StLock<Mutex> _(mActivateMutex);
905 if (mActive)
906 {
907 mActive = false;
908 check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
909 }
910 }
911
912 void
913 DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
914 {
915 check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
916 mUniqueId, (void**) &data));
917 }
918
919 void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
920 {
921 // clone the record
922 mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
923 *mUniqueId = *uniquePtr;
924 mDestroyID = true;
925 }
926
927 //
928 // DbAttributes
929 //
930 DbAttributes::DbAttributes()
931 : CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
932 {
933 }
934
935 DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
936 : CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
937 {
938 }
939
940 void DbAttributes::updateWithDbAttributes(DbAttributes* newValues) {
941 if(!newValues) {
942 return;
943 }
944
945 canonicalize();
946 newValues->canonicalize();
947
948 updateWith(newValues);
949 }
950
951 void
952 DbAttributes::canonicalize() {
953 for(int i = 0; i < size(); i++) {
954 CssmDbAttributeData& data = attributes()[i];
955 CssmDbAttributeInfo& datainfo = data.info();
956
957 // Calling Schema::attributeInfo is the best way to canonicalize.
958 // There's no way around the try-catch structure, since it throws if it
959 // can't find something.
960
961 try {
962 if(datainfo.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER) {
963 data.info() = Security::KeychainCore::Schema::attributeInfo(datainfo.intName());
964 }
965 } catch(...) {
966 // Don't worry about it
967 }
968 }
969 }