]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_cspdl/lib/SSDatabase.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_cspdl / lib / SSDatabase.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 // SSDatabase.cpp - Security Server database object
21 //
22 #include "SSDatabase.h"
23
24 #include <security_cdsa_utilities/KeySchema.h>
25
26 using namespace CssmClient;
27 using namespace SecurityServer;
28
29 const char *const SSDatabaseImpl::DBBlobRelationName = "DBBlob";
30
31
32 SSDatabaseImpl::SSDatabaseImpl(ClientSession &inClientSession, const CssmClient::DL &dl,
33 const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation)
34 : Db::Impl(dl, inDbName, inDbLocation), mClientSession(inClientSession), mSSDbHandle(noDb)
35 {
36 }
37
38 SSDatabaseImpl::~SSDatabaseImpl()
39 {
40 if (mSSDbHandle != noDb)
41 mClientSession.releaseDb(mSSDbHandle);
42 }
43
44 SSUniqueRecord
45 SSDatabaseImpl::insert(CSSM_DB_RECORDTYPE recordType,
46 const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
47 const CSSM_DATA *data, bool)
48 {
49 SSUniqueRecord uniqueId(SSDatabase(this));
50 check(CSSM_DL_DataInsert(handle(), recordType,
51 attributes,
52 data, uniqueId));
53 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
54 uniqueId->activate();
55 return uniqueId;
56 }
57
58 void
59 SSDatabaseImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest,
60 const CSSM_ACCESS_CREDENTIALS *inAccessCredentials)
61 {
62 mClientSession.authenticateDb(dbHandle(), inAccessRequest,
63 AccessCredentials::overlay(inAccessCredentials));
64 }
65
66 void
67 SSDatabaseImpl::lock()
68 {
69 mClientSession.lock(dbHandle());
70
71 }
72
73 void
74 SSDatabaseImpl::unlock()
75 {
76 mClientSession.unlock(dbHandle());
77 }
78
79 void
80 SSDatabaseImpl::unlock(const CSSM_DATA &password)
81 {
82 mClientSession.unlock(dbHandle(), CssmData::overlay(password));
83 }
84
85 void
86 SSDatabaseImpl::getSettings(uint32 &outIdleTimeout, bool &outLockOnSleep)
87 {
88 DBParameters parameters;
89 mClientSession.getDbParameters(dbHandle(), parameters);
90 outIdleTimeout = parameters.idleTimeout;
91 outLockOnSleep = parameters.lockOnSleep;
92 }
93
94 void
95 SSDatabaseImpl::setSettings(uint32 inIdleTimeout, bool inLockOnSleep)
96 {
97 DBParameters parameters;
98 parameters.idleTimeout = inIdleTimeout;
99 parameters.lockOnSleep = inLockOnSleep;
100 mClientSession.setDbParameters(dbHandle(), parameters);
101
102 // Reencode the db blob.
103 CssmDataContainer dbb(allocator());
104 mClientSession.encodeDb(mSSDbHandle, dbb, allocator());
105 getDbBlobId()->modify(DBBlobRelationID, NULL, &dbb, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
106 }
107
108 bool
109 SSDatabaseImpl::isLocked()
110 {
111 return mClientSession.isLocked(dbHandle());
112 }
113
114 void
115 SSDatabaseImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS *cred)
116 {
117 mClientSession.changePassphrase(dbHandle(), AccessCredentials::overlay(cred));
118
119 // Reencode the db blob.
120 CssmDataContainer dbb(allocator());
121 mClientSession.encodeDb(mSSDbHandle, dbb, allocator());
122 getDbBlobId()->modify(DBBlobRelationID, NULL, &dbb, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
123 }
124
125 DbHandle
126 SSDatabaseImpl::dbHandle()
127 {
128 activate();
129 if (mForked()) {
130 // re-establish the dbHandle with the SecurityServer
131 CssmDataContainer dbb(allocator());
132 getDbBlobId(&dbb);
133 mSSDbHandle = mClientSession.decodeDb(mIdentifier,
134 AccessCredentials::overlay(accessCredentials()), dbb);
135 }
136 return mSSDbHandle;
137 }
138
139 void
140 SSDatabaseImpl::commonCreate(const DLDbIdentifier &dlDbIdentifier, bool &autoCommit)
141 {
142 mIdentifier = dlDbIdentifier;
143 // Set to false if autocommit should remain off after the create.
144 autoCommit = true;
145
146 // OpenParameters to use
147 CSSM_APPLEDL_OPEN_PARAMETERS newOpenParameters =
148 {
149 sizeof(CSSM_APPLEDL_OPEN_PARAMETERS),
150 CSSM_APPLEDL_OPEN_PARAMETERS_VERSION,
151 CSSM_FALSE, // do not auto-commit
152 0 // mask - do not use following fields
153 };
154
155 // Get the original openParameters and apply them to the ones we
156 // are passing in.
157 const CSSM_APPLEDL_OPEN_PARAMETERS *inOpenParameters =
158 reinterpret_cast<const CSSM_APPLEDL_OPEN_PARAMETERS *>(openParameters());
159 if (inOpenParameters)
160 {
161 switch (inOpenParameters->version)
162 {
163 case 1:
164 if (inOpenParameters->length < sizeof(CSSM_APPLEDL_OPEN_PARAMETERS))
165 CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
166
167 newOpenParameters.mask = inOpenParameters->mask;
168 newOpenParameters.mode = inOpenParameters->mode;
169 /*DROPTHROUGH*/
170 case 0:
171 //if (inOpenParameters->length < sizeof(CSSM_APPLEDL_OPEN_PARAMETERS_V0))
172 // CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
173
174 // This will determine whether we leave autocommit off or not.
175 autoCommit = inOpenParameters->autoCommit == CSSM_FALSE ? false : true;
176 break;
177
178 default:
179 CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
180 }
181 }
182
183 // Use the new openParameters
184 openParameters(&newOpenParameters);
185 try
186 {
187 DbImpl::create();
188 // Restore the original openparameters again.
189 openParameters(inOpenParameters);
190 }
191 catch (...)
192 {
193 // Make sure restore the original openparameters again even if
194 // create throws.
195 openParameters(inOpenParameters);
196 throw;
197 }
198
199 // @@@ The CSSM_DB_SCHEMA_ATTRIBUTE_INFO and CSSM_DB_SCHEMA_INDEX_INFO
200 // arguments should be optional.
201 createRelation(DBBlobRelationID, DBBlobRelationName,
202 0, (CSSM_DB_SCHEMA_ATTRIBUTE_INFO *)42,
203 0, (CSSM_DB_SCHEMA_INDEX_INFO *)42);
204
205 // @@@ Only iff not already in mDbInfo
206 createRelation(CSSM_DL_DB_RECORD_PUBLIC_KEY, "CSSM_DL_DB_RECORD_PUBLIC_KEY",
207 KeySchema::KeySchemaAttributeCount, KeySchema::KeySchemaAttributeList,
208 KeySchema::KeySchemaIndexCount, KeySchema::KeySchemaIndexList);
209
210 // @@@ Only iff not already in mDbInfo
211 createRelation(CSSM_DL_DB_RECORD_PRIVATE_KEY, "CSSM_DL_DB_RECORD_PRIVATE_KEY",
212 KeySchema::KeySchemaAttributeCount, KeySchema::KeySchemaAttributeList,
213 KeySchema::KeySchemaIndexCount, KeySchema::KeySchemaIndexList);
214
215 // @@@ Only iff not already in mDbInfo
216 createRelation(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, "CSSM_DL_DB_RECORD_SYMMETRIC_KEY",
217 KeySchema::KeySchemaAttributeCount, KeySchema::KeySchemaAttributeList,
218 KeySchema::KeySchemaIndexCount, KeySchema::KeySchemaIndexList);
219 }
220
221 void
222 SSDatabaseImpl::create(const DLDbIdentifier &dlDbIdentifier)
223 {
224 try
225 {
226 bool autoCommit;
227 commonCreate(dlDbIdentifier, autoCommit);
228
229 DBParameters dbParameters;
230 memset(&dbParameters, 0, sizeof(DBParameters));
231 dbParameters.idleTimeout = kDefaultIdleTimeout;
232 dbParameters.lockOnSleep = kDefaultLockOnSleep;
233
234 const AccessCredentials *cred = NULL;
235 const AclEntryInput *owner = NULL;
236 if (resourceControlContext())
237 {
238 cred = AccessCredentials::overlay(resourceControlContext()->AccessCred);
239 owner = &AclEntryInput::overlay(resourceControlContext()->InitialAclEntry);
240 }
241 mSSDbHandle = mClientSession.createDb(dlDbIdentifier, cred, owner, dbParameters);
242 CssmDataContainer dbb(allocator());
243 mClientSession.encodeDb(mSSDbHandle, dbb, allocator());
244 Db::Impl::insert(DBBlobRelationID, NULL, &dbb);
245 if (autoCommit)
246 {
247 passThrough(CSSM_APPLEFILEDL_COMMIT, NULL);
248 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
249 reinterpret_cast<const void *>(1));
250 }
251 }
252 catch(CssmError e)
253 {
254 if (e.error != CSSMERR_DL_DATASTORE_ALREADY_EXISTS)
255 {
256 DbImpl::deleteDb();
257 }
258 throw;
259 }
260 catch(...)
261 {
262 DbImpl::deleteDb();
263 throw;
264 }
265 }
266
267 void
268 SSDatabaseImpl::createWithBlob(const DLDbIdentifier &dlDbIdentifier, const CSSM_DATA &blob)
269 {
270 try
271 {
272 bool autoCommit;
273 commonCreate(dlDbIdentifier, autoCommit);
274 Db::Impl::insert(DBBlobRelationID, NULL, &blob);
275 if (autoCommit)
276 {
277 passThrough(CSSM_APPLEFILEDL_COMMIT, NULL);
278 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
279 reinterpret_cast<const void *>(1));
280 }
281 }
282 catch(...)
283 {
284 DbImpl::deleteDb();
285 throw;
286 }
287 }
288
289 void
290 SSDatabaseImpl::open(const DLDbIdentifier &dlDbIdentifier)
291 {
292 mIdentifier = dlDbIdentifier;
293 Db::Impl::open();
294
295 CssmDataContainer dbb(allocator());
296 getDbBlobId(&dbb);
297
298 mSSDbHandle = mClientSession.decodeDb(dlDbIdentifier, AccessCredentials::overlay(accessCredentials()), dbb);
299 }
300
301 void
302 SSDatabaseImpl::recode(const CssmData &data, const CssmData &extraData)
303 {
304 // Start a transaction (Implies activate()).
305 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, 0);
306
307 try
308 {
309 CssmDataContainer dbb(allocator());
310 // Make sure mSSDbHandle is valid.
311 CssmClient::DbUniqueRecord dbBlobId = getDbBlobId(&dbb);
312 if (mForked()) {
313 // re-establish the dbHandle with the SecurityServer
314 mSSDbHandle = mClientSession.decodeDb(mIdentifier,
315 AccessCredentials::overlay(accessCredentials()), dbb);
316 }
317 dbb.clear();
318
319 DbHandle successfulHdl = mClientSession.authenticateDbsForSync(data, extraData);
320
321 // Create a newDbHandle using the master secrets from the dbBlob we are
322 // recoding to.
323 SecurityServer::DbHandle clonedDbHandle =
324 mClientSession.recodeDbForSync(successfulHdl, mSSDbHandle);
325
326 // @@@ If the dbb changed since we fetched it we should abort or
327 // retry the operation here.
328
329 // Recode all keys
330 DbCursor cursor(SSDatabase(this));
331 cursor->recordType(CSSM_DL_DB_RECORD_ALL_KEYS);
332 CssmDataContainer keyBlob(allocator());
333 CssmClient::DbUniqueRecord keyBlobId;
334 DbAttributes attributes;
335 while (cursor->next(&attributes, &keyBlob, keyBlobId))
336 {
337 // Decode the old key
338 CssmKey::Header header;
339 KeyHandle keyHandle =
340 mClientSession.decodeKey(mSSDbHandle, keyBlob, header);
341 // Recode the key
342 CssmDataContainer newKeyBlob(mClientSession.returnAllocator);
343 mClientSession.recodeKey(mSSDbHandle, keyHandle, clonedDbHandle,
344 newKeyBlob);
345 mClientSession.releaseKey(keyHandle);
346 // Write the recoded key blob to the database
347 keyBlobId->modify(attributes.recordType(), NULL, &newKeyBlob,
348 CSSM_DB_MODIFY_ATTRIBUTE_NONE);
349 }
350
351 // Commit the new blob to securityd, reencode the db blob, release the
352 // cloned db handle and commit the new blob to the db.
353 mClientSession.commitDbForSync(mSSDbHandle, clonedDbHandle,
354 dbb, allocator());
355 dbBlobId->modify(DBBlobRelationID, NULL, &dbb,
356 CSSM_DB_MODIFY_ATTRIBUTE_NONE);
357
358 // Commit the transaction to the db
359 passThrough(CSSM_APPLEFILEDL_COMMIT, NULL);
360 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
361 reinterpret_cast<const void *>(1));
362 }
363 catch (...)
364 {
365 // Something went wrong rollback the transaction
366 passThrough(CSSM_APPLEFILEDL_ROLLBACK, NULL);
367 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
368 reinterpret_cast<const void *>(1));
369 throw;
370 }
371 }
372
373 void SSDatabaseImpl::getRecordIdentifier(CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord, CSSM_DATA &recordID)
374 {
375 // the unique ID is composed of three uint32s (plus one filler word). Pull
376 // them out and byte swap them
377 recordID.Length = sizeof (uint32) * kNumIDWords;
378 recordID.Data = (uint8*) allocator().malloc(recordID.Length);
379
380 // copy the data
381 uint32* dest = (uint32*) recordID.Data;
382 uint32* src = (uint32*) uniqueRecord->RecordIdentifier.Data;
383
384 dest[0] = htonl (src[0]);
385 dest[1] = htonl (src[1]);
386 dest[2] = htonl (src[2]);
387 dest[3] = 0;
388 }
389
390 void SSDatabaseImpl::copyBlob(CSSM_DATA &data)
391 {
392 // get the blob from the database
393 CssmDataContainer dbb(allocator());
394 getDbBlobId(&dbb);
395
396 // copy the data back
397 data.Data = dbb.Data;
398 data.Length = dbb.Length;
399
400 // zap the return structure so that we don't get zapped when dbb goes out of scope...
401 dbb.Data = NULL;
402 dbb.Length = 0;
403 }
404
405 DbUniqueRecordImpl *
406 SSDatabaseImpl::newDbUniqueRecord()
407 {
408 return new SSUniqueRecordImpl(SSDatabase(this));
409 }
410
411 CssmClient::DbUniqueRecord
412 SSDatabaseImpl::getDbBlobId(CssmDataContainer *dbb)
413 {
414 CssmClient::DbUniqueRecord dbBlobId;
415
416 DbCursor cursor(SSDatabase(this));
417 cursor->recordType(DBBlobRelationID);
418 if (!cursor->next(NULL, dbb, dbBlobId))
419 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
420
421 return dbBlobId;
422 }
423
424
425
426 SSUniqueRecordImpl::SSUniqueRecordImpl(const SSDatabase &db)
427 : DbUniqueRecord::Impl(db)
428 {
429 }
430
431 SSUniqueRecordImpl::~SSUniqueRecordImpl()
432 {
433 }
434
435 SSDatabase
436 SSUniqueRecordImpl::database() const
437 {
438 return parent<SSDatabase>();
439 }