]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/dlclient.cpp
Security-57740.1.18.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 secnotice("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::recodeFinished() {
497 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_FINISHED, NULL, NULL));
498 }
499
500 void DbImpl::takeFileLock() {
501 passThrough(CSSM_APPLECSPDL_DB_TAKE_FILE_LOCK, NULL, NULL);
502 }
503
504 void DbImpl::releaseFileLock(bool success) {
505 passThrough(CSSM_APPLECSPDL_DB_RELEASE_FILE_LOCK, &success, NULL);
506 }
507
508 void DbImpl::makeBackup() {
509 passThrough(CSSM_APPLECSPDL_DB_MAKE_BACKUP, NULL, NULL);
510 }
511
512 void DbImpl::makeCopy(const char* path) {
513 passThrough(CSSM_APPLECSPDL_DB_MAKE_COPY, path, NULL);
514 }
515
516 void DbImpl::deleteFile() {
517 passThrough(CSSM_APPLECSPDL_DB_DELETE_FILE, NULL, NULL);
518 }
519
520 void DbImpl::transferTo(const DLDbIdentifier& dldbidentifier) {
521 if (dldbidentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP) {
522 // if we're an Apple CSPDL, do the fancy transfer:
523 // clone the file, clone the db, remove the original file
524 string oldPath = name();
525
526 CSSM_DB_HANDLE dbhandle;
527 passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
528
529 mDbName = dldbidentifier.dbName();
530 mHandle.DBHandle = dbhandle;
531
532 unlink(oldPath.c_str());
533
534 // Don't cache this name
535 if (mNameFromHandle) {
536 allocator().free(mNameFromHandle);
537 mNameFromHandle = NULL;
538 }
539 } else {
540 // if we're not an Apple CSPDL, just call rename
541 this->rename(dldbidentifier.dbName());
542 }
543 }
544
545
546 // cloneTo only makes sense if you're on an Apple CSPDL
547 Db DbImpl::cloneTo(const DLDbIdentifier& dldbidentifier) {
548 CSSM_DB_HANDLE dbhandle;
549 passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
550
551 // This is the only reasonable way to make a SSDbImpl at this layer.
552 CssmClient::Db db(dl(), dldbidentifier.dbName(), dldbidentifier.dbLocation());
553 db->mHandle.DBHandle = dbhandle;
554
555 return db;
556 }
557
558 //
559 // DbCursorMaker
560 //
561 DbCursorImpl *
562 DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
563 {
564 return new DbDbCursorImpl(Db(this), query, allocator);
565 }
566
567 DbCursorImpl *
568 DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
569 {
570 return new DbDbCursorImpl(Db(this), capacity, allocator);
571 }
572
573
574 //
575 // Db adapters for AclBearer
576 //
577 void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
578 {
579 aclInfos.allocator(allocator());
580 check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
581 reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
582 }
583
584 void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
585 const CSSM_ACCESS_CREDENTIALS *accessCred)
586 {
587 check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
588 }
589
590 void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
591 {
592 owner.allocator(allocator());
593 check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
594 }
595
596 void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
597 const CSSM_ACCESS_CREDENTIALS *accessCred)
598 {
599 check(CSSM_DL_ChangeDbOwner(handle(),
600 AccessCredentials::needed(accessCred), &newOwner));
601 }
602
603 void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
604 {
605 mDefaultCredentials = maker;
606 }
607
608
609 //
610 // Abstract DefaultCredentialsMakers
611 //
612 DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
613 { /* virtual */ }
614
615
616 //
617 // Db adapters for DLAccess
618 //
619 CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
620 CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
621 {
622 CSSM_HANDLE result;
623 switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
624 case CSSM_OK:
625 return result;
626 case CSSMERR_DL_ENDOFDATA:
627 return CSSM_INVALID_HANDLE;
628 default:
629 CssmError::throwMe(rc);
630 return CSSM_INVALID_HANDLE; // placebo
631 }
632 }
633
634 bool Db::dlGetNext(CSSM_HANDLE query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
635 CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
636 {
637 CSSM_RETURN rc = CSSM_DL_DataGetNext(handle(), query, &attributes, data, &id);
638 switch (rc) {
639 case CSSM_OK:
640 return true;
641 case CSSMERR_DL_ENDOFDATA:
642 return false;
643 default:
644 CssmError::throwMe(rc);
645 return false; // placebo
646 }
647 }
648
649 void Db::dlAbortQuery(CSSM_HANDLE query)
650 {
651 CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
652 }
653
654 void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
655 {
656 CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
657 }
658
659 void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
660 {
661 CssmError::check(CSSM_DL_DataDelete(handle(), id));
662 }
663
664 Allocator &Db::allocator()
665 {
666 return Object::allocator();
667 }
668
669
670 //
671 // DbUniqueRecordMaker
672 //
673 DbUniqueRecordImpl *
674 DbImpl::newDbUniqueRecord()
675 {
676 return new DbUniqueRecordImpl(Db(this));
677 }
678
679
680 //
681 // Utility methods
682 //
683 DLDbIdentifier
684 DbImpl::dlDbIdentifier()
685 {
686 // Always use the same dbName and dbLocation that were passed in during
687 // construction
688 return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
689 }
690
691
692 //
693 // DbDbCursorImpl
694 //
695 DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
696 : DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
697 {
698 }
699
700 DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
701 : DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
702 {
703 }
704
705 DbDbCursorImpl::~DbDbCursorImpl()
706 {
707 try
708 {
709 deactivate();
710 }
711 catch(...) {}
712 }
713
714 bool
715 DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
716 {
717 if (attributes)
718 attributes->deleteValues();
719
720 if (data)
721 data->clear();
722
723 CSSM_RETURN result;
724 Db db(database());
725 DbUniqueRecord unique(db);
726 if (!mActive)
727 {
728 // ask the CSP/DL if the requested record type exists
729 CSSM_BOOL boolResult;
730 CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
731 if (!boolResult)
732 {
733 if (data != NULL)
734 {
735 data->invalidate();
736 }
737
738 return false;
739 }
740
741 result = CSSM_DL_DataGetFirst(db->handle(),
742 this,
743 &mResultsHandle,
744 attributes,
745 data,
746 unique);
747
748 StLock<Mutex> _(mActivateMutex);
749 if (result == CSSM_OK)
750 mActive = true;
751 else if (data != NULL)
752 data->invalidate ();
753 }
754 else
755 {
756 result = CSSM_DL_DataGetNext(db->handle(),
757 mResultsHandle,
758 attributes,
759 data,
760 unique);
761
762 if (result != CSSM_OK && data != NULL)
763 {
764 data->invalidate ();
765 }
766 }
767
768 if (result != CSSM_OK && attributes != NULL)
769 {
770 attributes->invalidate();
771 }
772
773 if (result == CSSMERR_DL_ENDOFDATA)
774 {
775 StLock<Mutex> _(mActivateMutex);
776 mActive = false;
777 return false;
778 }
779
780 check(result);
781
782 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
783 unique->activate();
784 uniqueId = unique;
785 return true;
786 }
787
788 void
789 DbDbCursorImpl::activate()
790 {
791 }
792
793 void
794 DbDbCursorImpl::deactivate()
795 {
796 StLock<Mutex> _(mActivateMutex);
797 if (mActive)
798 {
799 mActive = false;
800 check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
801 }
802 }
803
804
805 //
806 // DbCursorImpl
807 //
808 DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
809 ObjectImpl(parent), CssmAutoQuery(query, allocator)
810 {
811 }
812
813 DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
814 ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
815 {
816 }
817
818 Allocator &
819 DbCursorImpl::allocator() const
820 {
821 return ObjectImpl::allocator();
822 }
823
824 void
825 DbCursorImpl::allocator(Allocator &alloc)
826 {
827 ObjectImpl::allocator(alloc);
828 }
829
830
831 //
832 // DbUniqueRecord
833 //
834 DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
835 {
836 }
837
838 DbUniqueRecordImpl::~DbUniqueRecordImpl()
839 {
840 try
841 {
842 if (mDestroyID)
843 {
844 allocator ().free (mUniqueId);
845 }
846
847 deactivate();
848 }
849 catch(...) {}
850 }
851
852 void
853 DbUniqueRecordImpl::deleteRecord()
854 {
855 check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
856 }
857
858 void
859 DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
860 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
861 const CSSM_DATA *data,
862 CSSM_DB_MODIFY_MODE modifyMode)
863 {
864 check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
865 attributes,
866 data, modifyMode));
867 }
868
869 void
870 DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
871 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
872 const CSSM_DATA *data,
873 CSSM_DB_MODIFY_MODE modifyMode)
874 {
875 // fill out the parameters
876 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
877 params.recordType = recordType;
878 params.uniqueID = mUniqueId;
879 params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
880 params.data = (CSSM_DATA*) data;
881 params.modifyMode = modifyMode;
882
883 // modify the data
884 check(CSSM_DL_PassThrough(database()->handle(),
885 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
886 &params,
887 NULL));
888 }
889
890 void
891 DbUniqueRecordImpl::get(DbAttributes *attributes,
892 ::CssmDataContainer *data)
893 {
894 if (attributes)
895 attributes->deleteValues();
896
897 if (data)
898 data->clear();
899
900 // @@@ Fix the allocators for attributes and data.
901 CSSM_RETURN result;
902 result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
903 attributes,
904 data);
905
906 if (result != CSSM_OK)
907 {
908 if (attributes)
909 attributes->invalidate();
910 if (data != NULL) // the data returned is no longer valid
911 {
912 data->invalidate ();
913 }
914 }
915
916 check(result);
917 }
918
919 void
920 DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
921 ::CssmDataContainer *data)
922 {
923 if (attributes)
924 attributes->deleteValues();
925
926 if (data)
927 data->clear();
928
929 // @@@ Fix the allocators for attributes and data.
930 CSSM_RETURN result;
931
932 // make the parameter block
933 CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
934 params.uniqueID = mUniqueId;
935 params.attributes = attributes;
936
937 // get the data
938 ::CssmDataContainer recordData;
939 result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, &params,
940 (void**) data);
941 check (result);
942 }
943
944 void
945 DbUniqueRecordImpl::activate()
946 {
947 StLock<Mutex> _(mActivateMutex);
948 mActive = true;
949 }
950
951 void
952 DbUniqueRecordImpl::deactivate()
953 {
954 StLock<Mutex> _(mActivateMutex);
955 if (mActive)
956 {
957 mActive = false;
958 check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
959 }
960 }
961
962 void
963 DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
964 {
965 check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
966 mUniqueId, (void**) &data));
967 }
968
969 void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
970 {
971 // clone the record
972 mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
973 *mUniqueId = *uniquePtr;
974 mDestroyID = true;
975 }
976
977 //
978 // DbAttributes
979 //
980 DbAttributes::DbAttributes()
981 : CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
982 {
983 }
984
985 DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
986 : CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
987 {
988 }
989
990 void DbAttributes::updateWithDbAttributes(DbAttributes* newValues) {
991 if(!newValues) {
992 return;
993 }
994
995 canonicalize();
996 newValues->canonicalize();
997
998 updateWith(newValues);
999 }
1000
1001 void
1002 DbAttributes::canonicalize() {
1003 for(int i = 0; i < size(); i++) {
1004 CssmDbAttributeData& data = attributes()[i];
1005 CssmDbAttributeInfo& datainfo = data.info();
1006
1007 // Calling Schema::attributeInfo is the best way to canonicalize.
1008 // There's no way around the try-catch structure, since it throws if it
1009 // can't find something.
1010
1011 try {
1012 if(datainfo.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER) {
1013 data.info() = Security::KeychainCore::Schema::attributeInfo(datainfo.intName());
1014 }
1015 } catch(...) {
1016 // Don't worry about it
1017 }
1018 }
1019 }