]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/dlclient.cpp
Security-59754.80.3.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 StLock<Mutex> _(mActivateMutex);
199 if (!mActive)
200 {
201 if (mDbInfo)
202 create();
203 else
204 open();
205 }
206 }
207
208 void
209 DbImpl::deactivate()
210 {
211 StLock<Mutex> _(mActivateMutex);
212 if (mActive)
213 {
214 mActive = false;
215 close();
216 }
217 }
218
219 void
220 DbImpl::deleteDb()
221 {
222 // Deactivate so the db gets closed if it was open.
223 deactivate();
224 // This call does not require the receiver to be active.
225 check(CSSM_DL_DbDelete(dl()->handle(), mDbName.canonicalName(), dbLocation(),
226 mAccessCredentials));
227 }
228
229 void
230 DbImpl::rename(const char *newName)
231 {
232 // Deactivate so the db gets closed if it was open.
233 deactivate();
234 if (::rename(mDbName.canonicalName(), newName))
235 UnixError::throwMe(errno);
236
237 // Change our DbName to reflect this rename.
238 mDbName = DbName(newName, dbLocation());
239 }
240
241 void
242 DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
243 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
244 {
245 if (!mActive)
246 {
247 // XXX Could do the same for create but this would require sticking
248 // inAccessCredentials into mResourceControlContext.
249 if (!mDbInfo)
250 {
251 // We were not yet active. Just do an open.
252 accessRequest(inAccessRequest);
253 accessCredentials(inAccessCredentials);
254 activate();
255 return;
256 }
257 }
258
259 check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
260 }
261
262 void
263 DbImpl::name(char *&outDbName)
264 {
265 check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
266 }
267
268 const char *
269 DbImpl::name()
270 {
271 if (mUseNameFromHandle)
272 {
273 if (mNameFromHandle
274 || !CSSM_DL_GetDbNameFromHandle(handle(), &mNameFromHandle))
275 {
276 return mNameFromHandle;
277 }
278
279 // We failed to get the name from the handle so use the passed
280 // in name instead
281 mUseNameFromHandle = false;
282 }
283
284 return mDbName.canonicalName();
285 }
286
287 void
288 DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
289 const char *inRelationName,
290 uint32 inNumberOfAttributes,
291 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
292 uint32 inNumberOfIndexes,
293 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
294 {
295 check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
296 inNumberOfAttributes, pAttributeInfo,
297 inNumberOfIndexes, pIndexInfo));
298 }
299
300 void
301 DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
302 {
303 check(CSSM_DL_DestroyRelation(handle(), inRelationID));
304 }
305
306 DbUniqueRecord
307 DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
308 const CSSM_DATA *data)
309 {
310 DbUniqueRecord uniqueId(Db(this));
311 check(CSSM_DL_DataInsert(handle(), recordType,
312 attributes,
313 data, uniqueId));
314 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
315 uniqueId->activate();
316 return uniqueId;
317 }
318
319
320 DbUniqueRecord
321 DbImpl::insertWithoutEncryption(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
322 CSSM_DATA *data)
323 {
324 DbUniqueRecord uniqueId(Db(this));
325
326 // fill out the parameters
327 CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION_PARAMETERS params;
328 params.recordType = recordType;
329 params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
330 params.data = *data;
331
332 // for clarity, call the overloaded operator to produce a unique record pointer
333 CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = uniqueId;
334
335 // make the call
336 passThrough (CSSM_APPLECSPDL_DB_INSERT_WITHOUT_ENCRYPTION, &params, (void**) uniquePtr);
337
338 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
339 uniqueId->activate();
340 return uniqueId;
341 }
342
343
344 //
345 // Generic Passthrough interface
346 //
347 void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
348 {
349 check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
350 }
351
352
353 //
354 // Passthrough functions (only implemented by AppleCSPDL).
355 //
356 void
357 DbImpl::lock()
358 {
359 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
360 }
361
362 void
363 DbImpl::unlock()
364 {
365 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
366 }
367
368 void
369 DbImpl::unlock(const CSSM_DATA &password)
370 {
371 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
372 }
373
374 void
375 DbImpl::stash()
376 {
377 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH, NULL, NULL));
378 }
379
380 void
381 DbImpl::stashCheck()
382 {
383 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_STASH_CHECK, NULL, NULL));
384 }
385
386 void
387 DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
388 {
389 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
390 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
391 NULL, reinterpret_cast<void **>(&settings)));
392 outIdleTimeout = settings->idleTimeout;
393 outLockOnSleep = settings->lockOnSleep;
394 allocator().free(settings);
395 }
396
397 void
398 DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
399 {
400 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
401 settings.idleTimeout = inIdleTimeout;
402 settings.lockOnSleep = inLockOnSleep;
403 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
404 }
405
406 bool
407 DbImpl::isLocked()
408 {
409 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
410 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
411 NULL, reinterpret_cast<void **>(&params)));
412 bool isLocked = params->isLocked;
413 allocator().free(params);
414 return isLocked;
415 }
416
417 void
418 DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
419 {
420 CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
421 params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
422 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, &params, NULL));
423 }
424
425 void DbImpl::recode(const CSSM_DATA &data, const CSSM_DATA &extraData)
426 {
427 // setup parameters for the recode call
428 CSSM_APPLECSPDL_RECODE_PARAMETERS params;
429 params.dbBlob = data;
430 params.extraData = extraData;
431
432 // do the call
433 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_CSP_RECODE, &params, NULL));
434 }
435
436 void DbImpl::copyBlob (CssmData &data)
437 {
438 // do the call
439 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_COPY_BLOB, NULL, (void**) (CSSM_DATA*) &data));
440 }
441
442 void DbImpl::setBatchMode(Boolean mode, Boolean rollback)
443 {
444 //
445 // We need the DL_DB_Handle of the underyling DL in order to use CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
446 //
447 CSSM_RETURN result;
448 CSSM_DL_DB_HANDLE dldbHandleOfUnderlyingDL;
449 result = CSSM_DL_PassThrough(handle(),
450 CSSM_APPLECSPDL_DB_GET_HANDLE,
451 NULL,
452 (void **)&dldbHandleOfUnderlyingDL);
453 //
454 // Now, toggle the autocommit...
455 //
456 if ( result == errSecSuccess )
457 {
458 CSSM_BOOL modeToUse = !mode;
459 if (rollback)
460 {
461 result = (OSStatus)CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
462 CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
463 }
464
465 result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
466 CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
467 (void *)((size_t) modeToUse),
468 NULL);
469 if (!rollback && modeToUse)
470 result = CSSM_DL_PassThrough(dldbHandleOfUnderlyingDL,
471 CSSM_APPLEFILEDL_COMMIT,
472 NULL,
473 NULL);
474 }
475 }
476
477 uint32 DbImpl::dbBlobVersion() {
478 uint32 dbBlobVersion = 0;
479 uint32* dbBlobVersionPtr = &dbBlobVersion;
480
481 // We only have a blob version if we're an apple CSPDL
482 if(dl()->guid() == gGuidAppleCSPDL) {
483 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_BLOB_VERSION, NULL, (void**) &dbBlobVersionPtr));
484 } else {
485 secnotice("integrity", "Non-Apple CSPDL keychains don't have keychain versions");
486 }
487 return dbBlobVersion;
488 }
489
490 uint32 DbImpl::recodeDbToVersion(uint32 version) {
491 uint32 newDbVersion;
492 uint32* newDbVersionPtr = &newDbVersion;
493 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_TO_BLOB_VERSION, &version, (void**) &newDbVersionPtr));
494 return newDbVersion;
495 }
496
497 void DbImpl::recodeFinished() {
498 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_RECODE_FINISHED, NULL, NULL));
499 }
500
501 void DbImpl::takeFileLock() {
502 passThrough(CSSM_APPLECSPDL_DB_TAKE_FILE_LOCK, NULL, NULL);
503 }
504
505 void DbImpl::releaseFileLock(bool success) {
506 passThrough(CSSM_APPLECSPDL_DB_RELEASE_FILE_LOCK, &success, NULL);
507 }
508
509 void DbImpl::makeBackup() {
510 passThrough(CSSM_APPLECSPDL_DB_MAKE_BACKUP, NULL, NULL);
511 }
512
513 void DbImpl::makeCopy(const char* path) {
514 passThrough(CSSM_APPLECSPDL_DB_MAKE_COPY, path, NULL);
515 }
516
517 void DbImpl::deleteFile() {
518 passThrough(CSSM_APPLECSPDL_DB_DELETE_FILE, NULL, NULL);
519 }
520
521 void DbImpl::transferTo(const DLDbIdentifier& dldbidentifier) {
522 if (dldbidentifier.ssuid().subserviceType() & CSSM_SERVICE_CSP) {
523 // if we're an Apple CSPDL, do the fancy transfer:
524 // clone the file, clone the db, remove the original file
525 string oldPath = name();
526
527 CSSM_DB_HANDLE dbhandle;
528 passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
529
530 mDbName = dldbidentifier.dbName();
531 mHandle.DBHandle = dbhandle;
532
533 unlink(oldPath.c_str());
534
535 // Don't cache this name
536 if (mNameFromHandle) {
537 allocator().free(mNameFromHandle);
538 mNameFromHandle = NULL;
539 }
540 } else {
541 // if we're not an Apple CSPDL, just call rename
542 this->rename(dldbidentifier.dbName());
543 }
544 }
545
546
547 // cloneTo only makes sense if you're on an Apple CSPDL
548 Db DbImpl::cloneTo(const DLDbIdentifier& dldbidentifier) {
549 CSSM_DB_HANDLE dbhandle;
550 passThrough(CSSM_APPLECSPDL_DB_CLONE, &dldbidentifier, &dbhandle);
551
552 // This is the only reasonable way to make a SSDbImpl at this layer.
553 CssmClient::Db db(dl(), dldbidentifier.dbName(), dldbidentifier.dbLocation());
554 db->mHandle.DBHandle = dbhandle;
555
556 return db;
557 }
558
559 //
560 // DbCursorMaker
561 //
562 DbCursorImpl *
563 DbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator)
564 {
565 return new DbDbCursorImpl(Db(this), query, allocator);
566 }
567
568 DbCursorImpl *
569 DbImpl::newDbCursor(uint32 capacity, Allocator &allocator)
570 {
571 return new DbDbCursorImpl(Db(this), capacity, allocator);
572 }
573
574
575 //
576 // Db adapters for AclBearer
577 //
578 void DbImpl::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
579 {
580 aclInfos.allocator(allocator());
581 check(CSSM_DL_GetDbAcl(const_cast<DbImpl*>(this)->handle(),
582 reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
583 }
584
585 void DbImpl::changeAcl(const CSSM_ACL_EDIT &aclEdit,
586 const CSSM_ACCESS_CREDENTIALS *accessCred)
587 {
588 check(CSSM_DL_ChangeDbAcl(handle(), AccessCredentials::needed(accessCred), &aclEdit));
589 }
590
591 void DbImpl::getOwner(AutoAclOwnerPrototype &owner) const
592 {
593 owner.allocator(allocator());
594 check(CSSM_DL_GetDbOwner(const_cast<DbImpl*>(this)->handle(), owner));
595 }
596
597 void DbImpl::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
598 const CSSM_ACCESS_CREDENTIALS *accessCred)
599 {
600 check(CSSM_DL_ChangeDbOwner(handle(),
601 AccessCredentials::needed(accessCred), &newOwner));
602 }
603
604 void DbImpl::defaultCredentials(DefaultCredentialsMaker *maker)
605 {
606 mDefaultCredentials = maker;
607 }
608
609
610 //
611 // Abstract DefaultCredentialsMakers
612 //
613 DbImpl::DefaultCredentialsMaker::~DefaultCredentialsMaker()
614 { /* virtual */ }
615
616
617 //
618 // Db adapters for DLAccess
619 //
620 CSSM_HANDLE Db::dlGetFirst(const CSSM_QUERY &query, CSSM_DB_RECORD_ATTRIBUTE_DATA &attributes,
621 CSSM_DATA *data, CSSM_DB_UNIQUE_RECORD *&id)
622 {
623 CSSM_HANDLE result;
624 switch (CSSM_RETURN rc = CSSM_DL_DataGetFirst(handle(), &query, &result, &attributes, data, &id)) {
625 case CSSM_OK:
626 return result;
627 case CSSMERR_DL_ENDOFDATA:
628 return CSSM_INVALID_HANDLE;
629 default:
630 CssmError::throwMe(rc);
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 }
646 }
647
648 void Db::dlAbortQuery(CSSM_HANDLE query)
649 {
650 CssmError::check(CSSM_DL_DataAbortQuery(handle(), query));
651 }
652
653 void Db::dlFreeUniqueId(CSSM_DB_UNIQUE_RECORD *id)
654 {
655 CssmError::check(CSSM_DL_FreeUniqueRecord(handle(), id));
656 }
657
658 void Db::dlDeleteRecord(CSSM_DB_UNIQUE_RECORD *id)
659 {
660 CssmError::check(CSSM_DL_DataDelete(handle(), id));
661 }
662
663 Allocator &Db::allocator()
664 {
665 return Object::allocator();
666 }
667
668
669 //
670 // DbUniqueRecordMaker
671 //
672 DbUniqueRecordImpl *
673 DbImpl::newDbUniqueRecord()
674 {
675 return new DbUniqueRecordImpl(Db(this));
676 }
677
678
679 //
680 // Utility methods
681 //
682 DLDbIdentifier
683 DbImpl::dlDbIdentifier()
684 {
685 // Always use the same dbName and dbLocation that were passed in during
686 // construction
687 return DLDbIdentifier(dl()->subserviceUid(), mDbName.canonicalName(), dbLocation());
688 }
689
690
691 //
692 // DbDbCursorImpl
693 //
694 DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, Allocator &allocator)
695 : DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
696 {
697 }
698
699 DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, Allocator &allocator)
700 : DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
701 {
702 }
703
704 DbDbCursorImpl::~DbDbCursorImpl()
705 {
706 try
707 {
708 deactivate();
709 }
710 catch(...) {}
711 }
712
713 bool
714 DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
715 {
716 if (attributes)
717 attributes->deleteValues();
718
719 if (data)
720 data->clear();
721
722 CSSM_RETURN result;
723 Db db(database());
724 DbUniqueRecord unique(db);
725 if (!mActive)
726 {
727 // ask the CSP/DL if the requested record type exists
728 CSSM_BOOL boolResult;
729 CSSM_DL_PassThrough(db->handle(), CSSM_APPLECSPDL_DB_RELATION_EXISTS, &RecordType, (void**) &boolResult);
730 if (!boolResult)
731 {
732 if (data != NULL)
733 {
734 data->invalidate();
735 }
736
737 return false;
738 }
739
740 result = CSSM_DL_DataGetFirst(db->handle(),
741 this,
742 &mResultsHandle,
743 attributes,
744 data,
745 unique);
746
747 StLock<Mutex> _(mActivateMutex);
748 if (result == CSSM_OK)
749 mActive = true;
750 else if (data != NULL)
751 data->invalidate ();
752 }
753 else
754 {
755 result = CSSM_DL_DataGetNext(db->handle(),
756 mResultsHandle,
757 attributes,
758 data,
759 unique);
760
761 if (result != CSSM_OK && data != NULL)
762 {
763 data->invalidate ();
764 }
765 }
766
767 if (result != CSSM_OK && attributes != NULL)
768 {
769 attributes->invalidate();
770 }
771
772 if (result == CSSMERR_DL_ENDOFDATA)
773 {
774 StLock<Mutex> _(mActivateMutex);
775 mActive = false;
776 return false;
777 }
778
779 check(result);
780
781 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
782 unique->activate();
783 uniqueId = unique;
784 return true;
785 }
786
787 void
788 DbDbCursorImpl::activate()
789 {
790 }
791
792 void
793 DbDbCursorImpl::deactivate()
794 {
795 StLock<Mutex> _(mActivateMutex);
796 if (mActive)
797 {
798 mActive = false;
799 check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
800 }
801 }
802
803
804 //
805 // DbCursorImpl
806 //
807 DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, Allocator &allocator) :
808 ObjectImpl(parent), CssmAutoQuery(query, allocator)
809 {
810 }
811
812 DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, Allocator &allocator) :
813 ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
814 {
815 }
816
817 Allocator &
818 DbCursorImpl::allocator() const
819 {
820 return ObjectImpl::allocator();
821 }
822
823 void
824 DbCursorImpl::allocator(Allocator &alloc)
825 {
826 ObjectImpl::allocator(alloc);
827 }
828
829
830 //
831 // DbUniqueRecord
832 //
833 DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db), mDestroyID (false)
834 {
835 }
836
837 DbUniqueRecordImpl::~DbUniqueRecordImpl()
838 {
839 try
840 {
841 if (mDestroyID)
842 {
843 allocator ().free (mUniqueId);
844 }
845
846 deactivate();
847 }
848 catch(...) {}
849 }
850
851 void
852 DbUniqueRecordImpl::deleteRecord()
853 {
854 check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
855 }
856
857 void
858 DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
859 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
860 const CSSM_DATA *data,
861 CSSM_DB_MODIFY_MODE modifyMode)
862 {
863 check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
864 attributes,
865 data, modifyMode));
866 }
867
868 void
869 DbUniqueRecordImpl::modifyWithoutEncryption(CSSM_DB_RECORDTYPE recordType,
870 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
871 const CSSM_DATA *data,
872 CSSM_DB_MODIFY_MODE modifyMode)
873 {
874 // fill out the parameters
875 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION_PARAMETERS params;
876 params.recordType = recordType;
877 params.uniqueID = mUniqueId;
878 params.attributes = const_cast<CSSM_DB_RECORD_ATTRIBUTE_DATA*>(attributes);
879 params.data = (CSSM_DATA*) data;
880 params.modifyMode = modifyMode;
881
882 // modify the data
883 check(CSSM_DL_PassThrough(database()->handle(),
884 CSSM_APPLECSPDL_DB_MODIFY_WITHOUT_ENCRYPTION,
885 &params,
886 NULL));
887 }
888
889 void
890 DbUniqueRecordImpl::get(DbAttributes *attributes,
891 ::CssmDataContainer *data)
892 {
893 if (attributes)
894 attributes->deleteValues();
895
896 if (data)
897 data->clear();
898
899 // @@@ Fix the allocators for attributes and data.
900 CSSM_RETURN result;
901 result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
902 attributes,
903 data);
904
905 if (result != CSSM_OK)
906 {
907 if (attributes)
908 attributes->invalidate();
909 if (data != NULL) // the data returned is no longer valid
910 {
911 data->invalidate ();
912 }
913 }
914
915 check(result);
916 }
917
918 void
919 DbUniqueRecordImpl::getWithoutEncryption(DbAttributes *attributes,
920 ::CssmDataContainer *data)
921 {
922 if (attributes)
923 attributes->deleteValues();
924
925 if (data)
926 data->clear();
927
928 // @@@ Fix the allocators for attributes and data.
929 CSSM_RETURN result;
930
931 // make the parameter block
932 CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION_PARAMETERS params;
933 params.uniqueID = mUniqueId;
934 params.attributes = attributes;
935
936 // get the data
937 ::CssmDataContainer recordData;
938 result = CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_WITHOUT_ENCRYPTION, &params,
939 (void**) data);
940 check (result);
941 }
942
943 void
944 DbUniqueRecordImpl::activate()
945 {
946 StLock<Mutex> _(mActivateMutex);
947 mActive = true;
948 }
949
950 void
951 DbUniqueRecordImpl::deactivate()
952 {
953 StLock<Mutex> _(mActivateMutex);
954 if (mActive)
955 {
956 mActive = false;
957 check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
958 }
959 }
960
961 void
962 DbUniqueRecordImpl::getRecordIdentifier(CSSM_DATA &data)
963 {
964 check(CSSM_DL_PassThrough(database()->handle(), CSSM_APPLECSPDL_DB_GET_RECORD_IDENTIFIER,
965 mUniqueId, (void**) &data));
966 }
967
968 void DbUniqueRecordImpl::setUniqueRecordPtr(CSSM_DB_UNIQUE_RECORD_PTR uniquePtr)
969 {
970 // clone the record
971 mUniqueId = (CSSM_DB_UNIQUE_RECORD_PTR) allocator ().malloc (sizeof (CSSM_DB_UNIQUE_RECORD));
972 *mUniqueId = *uniquePtr;
973 mDestroyID = true;
974 }
975
976 //
977 // DbAttributes
978 //
979 DbAttributes::DbAttributes()
980 : CssmAutoDbRecordAttributeData(0, Allocator::standard(), Allocator::standard())
981 {
982 }
983
984 DbAttributes::DbAttributes(const Db &db, uint32 capacity, Allocator &allocator)
985 : CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
986 {
987 }
988
989 void DbAttributes::updateWithDbAttributes(DbAttributes* newValues) {
990 if(!newValues) {
991 return;
992 }
993
994 canonicalize();
995 newValues->canonicalize();
996
997 updateWith(newValues);
998 }
999
1000 void
1001 DbAttributes::canonicalize() {
1002 for(int i = 0; i < size(); i++) {
1003 CssmDbAttributeData& data = attributes()[i];
1004 CssmDbAttributeInfo& datainfo = data.info();
1005
1006 // Calling Schema::attributeInfo is the best way to canonicalize.
1007 // There's no way around the try-catch structure, since it throws if it
1008 // can't find something.
1009
1010 try {
1011 if(datainfo.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER) {
1012 data.info() = Security::KeychainCore::Schema::attributeInfo(datainfo.intName());
1013 }
1014 } catch(...) {
1015 // Don't worry about it
1016 }
1017 }
1018 }