]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_client/dlclient.cpp
Security-164.1.tar.gz
[apple/security.git] / cdsa / cdsa_client / dlclient.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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/dlclient.h>
23 #include <Security/aclclient.h>
24 #include <Security/ssclient.h>
25
26 using namespace CssmClient;
27
28
29 //
30 // Manage DL attachments
31 //
32 DLImpl::DLImpl(const Guid &guid) : AttachmentImpl(guid, CSSM_SERVICE_DL)
33 {
34 }
35
36 DLImpl::DLImpl(const Module &module) : AttachmentImpl(module, CSSM_SERVICE_DL)
37 {
38 }
39
40 DLImpl::~DLImpl()
41 {
42 }
43
44 void
45 DLImpl::getDbNames(char **)
46 {
47 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
48 }
49
50 void
51 DLImpl::freeNameList(char **)
52 {
53 CssmError::throwMe(CSSMERR_DL_FUNCTION_NOT_IMPLEMENTED);
54 }
55
56 DbImpl *
57 DLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
58 {
59 return new DbImpl(DL(this), inDbName, inDbLocation);
60 }
61
62
63 //
64 // Db (database)
65 //
66 DbImpl::DbImpl(const DL &dl, const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
67 : ObjectImpl(dl), mDbName(inDbName, inDbLocation),
68 mAccessRequest(CSSM_DB_ACCESS_READ), mAccessCredentials(NULL),
69 mOpenParameters(NULL), mDbInfo(NULL), mResourceControlContext(NULL)
70 {
71 }
72
73 DbImpl::~DbImpl()
74 {
75 try
76 {
77 deactivate();
78 }
79 catch(...) {}
80 }
81
82 void
83 DbImpl::open()
84 {
85 if (!mActive)
86 {
87 assert(mDbInfo == nil);
88 mHandle.DLHandle = dl()->handle();
89 check(CSSM_DL_DbOpen(mHandle.DLHandle, name(), dbLocation(),
90 mAccessRequest, mAccessCredentials,
91 mOpenParameters, &mHandle.DBHandle));
92 mActive = true;
93 }
94 }
95
96 void
97 DbImpl::create()
98 {
99 if (mActive)
100 CssmError::throwMe(CSSMERR_DL_DATASTORE_ALREADY_EXISTS);
101
102 if (mDbInfo == nil) {
103 // handle a missing (null) mDbInfo as an all-zero one
104 static const CSSM_DBINFO nullDbInfo = { };
105 mDbInfo = &nullDbInfo;
106 }
107 mHandle.DLHandle = dl()->handle();
108
109 if (!mResourceControlContext && mAccessCredentials) {
110 AclFactory::AnyResourceContext ctx(mAccessCredentials);
111 check(CSSM_DL_DbCreate(mHandle.DLHandle, name(), dbLocation(), mDbInfo,
112 mAccessRequest, &ctx,
113 mOpenParameters, &mHandle.DBHandle));
114 } else {
115 check(CSSM_DL_DbCreate(mHandle.DLHandle, name(), dbLocation(), mDbInfo,
116 mAccessRequest, mResourceControlContext,
117 mOpenParameters, &mHandle.DBHandle));
118 }
119 mActive = true;
120 }
121
122 void
123 DbImpl::close()
124 {
125 check(CSSM_DL_DbClose(mHandle));
126 }
127
128 void
129 DbImpl::activate()
130 {
131 if (!mActive)
132 {
133 if (mDbInfo)
134 create();
135 else
136 open();
137 }
138 }
139
140 void
141 DbImpl::deactivate()
142 {
143 if (mActive)
144 {
145 mActive = false;
146 close();
147 }
148 }
149
150 void
151 DbImpl::deleteDb()
152 {
153 // Deactivate so the db gets closed if it was open.
154 deactivate();
155 // This call does not require the receiver to be active.
156 check(CSSM_DL_DbDelete(dl()->handle(), name(), dbLocation(),
157 mAccessCredentials));
158 }
159
160 void
161 DbImpl::rename(const char *newName)
162 {
163 // Deactivate so the db gets closed if it was open.
164 deactivate();
165 if (::rename(name(), newName))
166 UnixError::throwMe(errno);
167
168 // Change our DbName to reflect this rename.
169 mDbName = DbName(newName, mDbName.dbLocation());
170 }
171
172 void
173 DbImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
174 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
175 {
176 if (!mActive)
177 {
178 // XXX Could do the same for create but this would require sticking
179 // inAccessCredentials into mResourceControlContext.
180 if (!mDbInfo)
181 {
182 // We were not yet active. Just do an open.
183 accessRequest(inAccessRequest);
184 accessCredentials(inAccessCredentials);
185 activate();
186 return;
187 }
188 }
189
190 check(CSSM_DL_Authenticate(handle(), inAccessRequest, inAccessCredentials));
191 }
192
193 void
194 DbImpl::name(char *&outDbName)
195 {
196 check(CSSM_DL_GetDbNameFromHandle(handle(), &outDbName));
197 }
198
199 void
200 DbImpl::createRelation(CSSM_DB_RECORDTYPE inRelationID,
201 const char *inRelationName,
202 uint32 inNumberOfAttributes,
203 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
204 uint32 inNumberOfIndexes,
205 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo)
206 {
207 check(CSSM_DL_CreateRelation(handle(), inRelationID, inRelationName,
208 inNumberOfAttributes, pAttributeInfo,
209 inNumberOfIndexes, pIndexInfo));
210 }
211
212 void
213 DbImpl::destroyRelation(CSSM_DB_RECORDTYPE inRelationID)
214 {
215 check(CSSM_DL_DestroyRelation(handle(), inRelationID));
216 }
217
218 DbUniqueRecord
219 DbImpl::insert(CSSM_DB_RECORDTYPE recordType, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
220 const CSSM_DATA *data)
221 {
222 DbUniqueRecord uniqueId(Db(this));
223 check(CSSM_DL_DataInsert(handle(), recordType,
224 attributes,
225 data, uniqueId));
226 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
227 uniqueId->activate();
228 return uniqueId;
229 }
230
231
232 //
233 // Generic Passthrough interface
234 //
235 void DbImpl::passThrough(uint32 passThroughId, const void *in, void **out)
236 {
237 check(CSSM_DL_PassThrough(handle(), passThroughId, in, out));
238 }
239
240
241 //
242 // Passthrough functions (only implemented by AppleCSPDL).
243 //
244 void
245 DbImpl::lock()
246 {
247 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_LOCK, NULL, NULL));
248 }
249
250 void
251 DbImpl::unlock()
252 {
253 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, NULL, NULL));
254 }
255
256 void
257 DbImpl::unlock(const CSSM_DATA &password)
258 {
259 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_UNLOCK, &password, NULL));
260 }
261
262 void
263 DbImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
264 {
265 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS_PTR settings;
266 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_GET_SETTINGS,
267 NULL, reinterpret_cast<void **>(&settings)));
268 outIdleTimeout = settings->idleTimeout;
269 outLockOnSleep = settings->lockOnSleep;
270 allocator().free(settings);
271 }
272
273 void
274 DbImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
275 {
276 CSSM_APPLECSPDL_DB_SETTINGS_PARAMETERS settings;
277 settings.idleTimeout = inIdleTimeout;
278 settings.lockOnSleep = inLockOnSleep;
279 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_SET_SETTINGS, &settings, NULL));
280 }
281
282 bool
283 DbImpl::isLocked()
284 {
285 CSSM_APPLECSPDL_DB_IS_LOCKED_PARAMETERS_PTR params;
286 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_IS_LOCKED,
287 NULL, reinterpret_cast<void **>(&params)));
288 bool isLocked = params->isLocked;
289 allocator().free(params);
290 return isLocked;
291 }
292
293 void
294 DbImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
295 {
296 CSSM_APPLECSPDL_DB_CHANGE_PASSWORD_PARAMETERS params;
297 params.accessCredentials = const_cast<CSSM_ACCESS_CREDENTIALS *>(cred);
298 check(CSSM_DL_PassThrough(handle(), CSSM_APPLECSPDL_DB_CHANGE_PASSWORD, &params, NULL));
299 }
300
301 bool
302 DbImpl::getUnlockKeyIndex(CssmData &index)
303 {
304 try {
305 SecurityServer::DbHandle dbHandle;
306 if (CSSM_DL_PassThrough(handle(),
307 CSSM_APPLECSPDL_DB_GET_HANDLE, NULL, (void **)&dbHandle))
308 return false; // can't get index
309 SecurityServer::ClientSession ss(allocator(), allocator());
310 ss.getDbSuggestedIndex(dbHandle, index);
311 return true;
312 } catch (const CssmError &error) {
313 if (error.cssmError() == CSSMERR_DL_DATASTORE_DOESNOT_EXIST)
314 return false;
315 throw;
316 }
317 }
318
319
320 //
321 // DbCursorMaker
322 //
323 DbCursorImpl *
324 DbImpl::newDbCursor(const CSSM_QUERY &query, CssmAllocator &allocator)
325 {
326 return new DbDbCursorImpl(Db(this), query, allocator);
327 }
328
329 DbCursorImpl *
330 DbImpl::newDbCursor(uint32 capacity, CssmAllocator &allocator)
331 {
332 return new DbDbCursorImpl(Db(this), capacity, allocator);
333 }
334
335 //
336 // DbUniqueRecordMaker
337 //
338 DbUniqueRecordImpl *
339 DbImpl::newDbUniqueRecord()
340 {
341 return new DbUniqueRecordImpl(Db(this));
342 }
343
344
345 //
346 // Utility methods
347 //
348 DLDbIdentifier
349 DbImpl::dlDbIdentifier() const
350 {
351 return DLDbIdentifier(dl()->subserviceUid(), name(), dbLocation());
352 }
353
354
355 //
356 // DbDbCursorImpl
357 //
358 DbDbCursorImpl::DbDbCursorImpl(const Db &db, const CSSM_QUERY &query, CssmAllocator &allocator)
359 : DbCursorImpl(db, query, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
360 {
361 }
362
363 DbDbCursorImpl::DbDbCursorImpl(const Db &db, uint32 capacity, CssmAllocator &allocator)
364 : DbCursorImpl(db, capacity, allocator), mResultsHandle(CSSM_INVALID_HANDLE)
365 {
366 }
367
368 DbDbCursorImpl::~DbDbCursorImpl()
369 {
370 try
371 {
372 deactivate();
373 }
374 catch(...) {}
375 }
376
377 bool
378 DbDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, DbUniqueRecord &uniqueId)
379 {
380 if (attributes)
381 attributes->deleteValues();
382
383 if (data)
384 data->clear();
385
386 CSSM_RETURN result;
387 Db db(database());
388 DbUniqueRecord unique(db);
389 if (!mActive)
390 {
391 result = CSSM_DL_DataGetFirst(db->handle(),
392 this,
393 &mResultsHandle,
394 attributes,
395 data,
396 unique);
397 if (result == CSSM_OK)
398 mActive = true;
399 else if (data != NULL)
400 data->invalidate ();
401 }
402 else
403 {
404 result = CSSM_DL_DataGetNext(db->handle(),
405 mResultsHandle,
406 attributes,
407 data,
408 unique);
409
410 if (result != CSSM_OK && data != NULL)
411 {
412 data->invalidate ();
413 }
414 }
415
416 if (result == CSSMERR_DL_ENDOFDATA)
417 {
418 mActive = false;
419 return false;
420 }
421
422 check(result);
423
424 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
425 unique->activate();
426 uniqueId = unique;
427 return true;
428 }
429
430 void
431 DbDbCursorImpl::activate()
432 {
433 }
434
435 void
436 DbDbCursorImpl::deactivate()
437 {
438 if (mActive)
439 {
440 mActive = false;
441 check(CSSM_DL_DataAbortQuery(database()->handle(), mResultsHandle));
442 }
443 }
444
445
446 //
447 // DbCursorImpl
448 //
449 DbCursorImpl::DbCursorImpl(const Object &parent, const CSSM_QUERY &query, CssmAllocator &allocator) :
450 ObjectImpl(parent), CssmAutoQuery(query, allocator)
451 {
452 }
453
454 DbCursorImpl::DbCursorImpl(const Object &parent, uint32 capacity, CssmAllocator &allocator) :
455 ObjectImpl(parent), CssmAutoQuery(capacity, allocator)
456 {
457 }
458
459 CssmAllocator &
460 DbCursorImpl::allocator() const
461 {
462 return ObjectImpl::allocator();
463 }
464
465 void
466 DbCursorImpl::allocator(CssmAllocator &alloc)
467 {
468 ObjectImpl::allocator(alloc);
469 }
470
471
472 //
473 // DbUniqueRecord
474 //
475 DbUniqueRecordImpl::DbUniqueRecordImpl(const Db &db) : ObjectImpl(db)
476 {
477 }
478
479 DbUniqueRecordImpl::~DbUniqueRecordImpl()
480 {
481 try
482 {
483 deactivate();
484 }
485 catch(...) {}
486 }
487
488 void
489 DbUniqueRecordImpl::deleteRecord()
490 {
491 check(CSSM_DL_DataDelete(database()->handle(), mUniqueId));
492 }
493
494 void
495 DbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType,
496 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
497 const CSSM_DATA *data,
498 CSSM_DB_MODIFY_MODE modifyMode)
499 {
500 check(CSSM_DL_DataModify(database()->handle(), recordType, mUniqueId,
501 attributes,
502 data, modifyMode));
503 }
504
505 void
506 DbUniqueRecordImpl::get(DbAttributes *attributes,
507 ::CssmDataContainer *data)
508 {
509 if (attributes)
510 attributes->deleteValues();
511
512 if (data)
513 data->clear();
514
515 // @@@ Fix the allocators for attributes and data.
516 CSSM_RETURN result;
517 result = CSSM_DL_DataGetFromUniqueRecordId(database()->handle(), mUniqueId,
518 attributes,
519 data);
520
521 if (result != CSSM_OK && data != NULL) // the data returned is no longer valid
522 {
523 data->invalidate ();
524 }
525
526 check(result);
527 }
528
529 void
530 DbUniqueRecordImpl::activate()
531 {
532 mActive = true;
533 }
534
535 void
536 DbUniqueRecordImpl::deactivate()
537 {
538 if (mActive)
539 {
540 mActive = false;
541 check(CSSM_DL_FreeUniqueRecord(database()->handle(), mUniqueId));
542 }
543 }
544
545
546 //
547 // DbAttributes
548 //
549 DbAttributes::DbAttributes()
550 : CssmAutoDbRecordAttributeData(0, CssmAllocator::standard(), CssmAllocator::standard())
551 {
552 }
553
554 DbAttributes::DbAttributes(const Db &db, uint32 capacity, CssmAllocator &allocator)
555 : CssmAutoDbRecordAttributeData(capacity, db->allocator(), allocator)
556 {
557 }