2 * Copyright (c) 2000-2001,2011-2014 Apple Inc. All Rights Reserved.
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
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.
20 // SSDatabase.cpp - Security Server database object
22 #include "SSDatabase.h"
24 #include <security_cdsa_utilities/KeySchema.h>
26 using namespace CssmClient
;
27 using namespace SecurityServer
;
29 const char *const SSDatabaseImpl::DBBlobRelationName
= "DBBlob";
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
)
38 SSDatabaseImpl::~SSDatabaseImpl()
41 if (mSSDbHandle
!= noDb
)
42 mClientSession
.releaseDb(mSSDbHandle
);
49 SSDatabaseImpl::insert(CSSM_DB_RECORDTYPE recordType
,
50 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*attributes
,
51 const CSSM_DATA
*data
, bool)
53 SSUniqueRecord
uniqueId(SSDatabase(this));
54 check(CSSM_DL_DataInsert(handle(), recordType
,
57 // Activate uniqueId so CSSM_DL_FreeUniqueRecord() gets called when it goes out of scope.
63 SSDatabaseImpl::authenticate(CSSM_DB_ACCESS_TYPE inAccessRequest
,
64 const CSSM_ACCESS_CREDENTIALS
*inAccessCredentials
)
66 mClientSession
.authenticateDb(dbHandle(), inAccessRequest
,
67 AccessCredentials::overlay(inAccessCredentials
));
71 SSDatabaseImpl::lock()
73 mClientSession
.lock(dbHandle());
78 SSDatabaseImpl::unlock()
80 mClientSession
.unlock(dbHandle());
84 SSDatabaseImpl::unlock(const CSSM_DATA
&password
)
86 mClientSession
.unlock(dbHandle(), CssmData::overlay(password
));
90 SSDatabaseImpl::stash()
92 mClientSession
.stashDb(dbHandle());
96 SSDatabaseImpl::stashCheck()
98 mClientSession
.stashDbCheck(dbHandle());
102 SSDatabaseImpl::getSettings(uint32
&outIdleTimeout
, bool &outLockOnSleep
)
104 DBParameters parameters
;
105 mClientSession
.getDbParameters(dbHandle(), parameters
);
106 outIdleTimeout
= parameters
.idleTimeout
;
107 outLockOnSleep
= parameters
.lockOnSleep
;
111 SSDatabaseImpl::setSettings(uint32 inIdleTimeout
, bool inLockOnSleep
)
113 DBParameters parameters
;
114 parameters
.idleTimeout
= inIdleTimeout
;
115 parameters
.lockOnSleep
= inLockOnSleep
;
116 mClientSession
.setDbParameters(dbHandle(), parameters
);
118 // Reencode the db blob.
119 CssmDataContainer
dbb(allocator());
120 mClientSession
.encodeDb(mSSDbHandle
, dbb
, allocator());
121 getDbBlobId()->modify(DBBlobRelationID
, NULL
, &dbb
, CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
125 SSDatabaseImpl::isLocked()
127 return mClientSession
.isLocked(dbHandle());
131 SSDatabaseImpl::changePassphrase(const CSSM_ACCESS_CREDENTIALS
*cred
)
133 mClientSession
.changePassphrase(dbHandle(), AccessCredentials::overlay(cred
));
135 // Reencode the db blob.
136 CssmDataContainer
dbb(allocator());
137 mClientSession
.encodeDb(mSSDbHandle
, dbb
, allocator());
138 getDbBlobId()->modify(DBBlobRelationID
, NULL
, &dbb
, CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
142 SSDatabaseImpl::dbHandle()
146 // re-establish the dbHandle with the SecurityServer
147 CssmDataContainer
dbb(allocator());
149 mSSDbHandle
= mClientSession
.decodeDb(mIdentifier
,
150 AccessCredentials::overlay(accessCredentials()), dbb
);
156 SSDatabaseImpl::commonCreate(const DLDbIdentifier
&dlDbIdentifier
, bool &autoCommit
)
158 mIdentifier
= dlDbIdentifier
;
159 // Set to false if autocommit should remain off after the create.
162 // OpenParameters to use
163 CSSM_APPLEDL_OPEN_PARAMETERS newOpenParameters
=
165 sizeof(CSSM_APPLEDL_OPEN_PARAMETERS
),
166 CSSM_APPLEDL_OPEN_PARAMETERS_VERSION
,
167 CSSM_FALSE
, // do not auto-commit
168 0 // mask - do not use following fields
171 // Get the original openParameters and apply them to the ones we
173 const CSSM_APPLEDL_OPEN_PARAMETERS
*inOpenParameters
=
174 reinterpret_cast<const CSSM_APPLEDL_OPEN_PARAMETERS
*>(openParameters());
175 if (inOpenParameters
)
177 switch (inOpenParameters
->version
)
180 if (inOpenParameters
->length
< sizeof(CSSM_APPLEDL_OPEN_PARAMETERS
))
181 CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS
);
183 newOpenParameters
.mask
= inOpenParameters
->mask
;
184 newOpenParameters
.mode
= inOpenParameters
->mode
;
187 //if (inOpenParameters->length < sizeof(CSSM_APPLEDL_OPEN_PARAMETERS_V0))
188 // CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS);
190 // This will determine whether we leave autocommit off or not.
191 autoCommit
= inOpenParameters
->autoCommit
== CSSM_FALSE
? false : true;
195 CssmError::throwMe(CSSMERR_APPLEDL_INVALID_OPEN_PARAMETERS
);
199 // Use the new openParameters
200 openParameters(&newOpenParameters
);
204 // Restore the original openparameters again.
205 openParameters(inOpenParameters
);
209 // Make sure restore the original openparameters again even if
211 openParameters(inOpenParameters
);
215 // @@@ The CSSM_DB_SCHEMA_ATTRIBUTE_INFO and CSSM_DB_SCHEMA_INDEX_INFO
216 // arguments should be optional.
217 createRelation(DBBlobRelationID
, DBBlobRelationName
,
218 0, (CSSM_DB_SCHEMA_ATTRIBUTE_INFO
*)42,
219 0, (CSSM_DB_SCHEMA_INDEX_INFO
*)42);
221 // @@@ Only iff not already in mDbInfo
222 createRelation(CSSM_DL_DB_RECORD_PUBLIC_KEY
, "CSSM_DL_DB_RECORD_PUBLIC_KEY",
223 KeySchema::KeySchemaAttributeCount
, KeySchema::KeySchemaAttributeList
,
224 KeySchema::KeySchemaIndexCount
, KeySchema::KeySchemaIndexList
);
226 // @@@ Only iff not already in mDbInfo
227 createRelation(CSSM_DL_DB_RECORD_PRIVATE_KEY
, "CSSM_DL_DB_RECORD_PRIVATE_KEY",
228 KeySchema::KeySchemaAttributeCount
, KeySchema::KeySchemaAttributeList
,
229 KeySchema::KeySchemaIndexCount
, KeySchema::KeySchemaIndexList
);
231 // @@@ Only iff not already in mDbInfo
232 createRelation(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, "CSSM_DL_DB_RECORD_SYMMETRIC_KEY",
233 KeySchema::KeySchemaAttributeCount
, KeySchema::KeySchemaAttributeList
,
234 KeySchema::KeySchemaIndexCount
, KeySchema::KeySchemaIndexList
);
238 SSDatabaseImpl::create(const DLDbIdentifier
&dlDbIdentifier
)
243 commonCreate(dlDbIdentifier
, autoCommit
);
245 DBParameters dbParameters
;
246 memset(&dbParameters
, 0, sizeof(DBParameters
));
247 dbParameters
.idleTimeout
= kDefaultIdleTimeout
;
248 dbParameters
.lockOnSleep
= kDefaultLockOnSleep
;
250 const AccessCredentials
*cred
= NULL
;
251 const AclEntryInput
*owner
= NULL
;
252 if (resourceControlContext())
254 cred
= AccessCredentials::overlay(resourceControlContext()->AccessCred
);
255 owner
= &AclEntryInput::overlay(resourceControlContext()->InitialAclEntry
);
257 mSSDbHandle
= mClientSession
.createDb(dlDbIdentifier
, cred
, owner
, dbParameters
);
258 CssmDataContainer
dbb(allocator());
259 mClientSession
.encodeDb(mSSDbHandle
, dbb
, allocator());
260 Db::Impl::insert(DBBlobRelationID
, NULL
, &dbb
);
263 passThrough(CSSM_APPLEFILEDL_COMMIT
, NULL
);
264 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
265 reinterpret_cast<const void *>(1));
270 if (e
.error
!= CSSMERR_DL_DATASTORE_ALREADY_EXISTS
)
284 SSDatabaseImpl::createWithBlob(const DLDbIdentifier
&dlDbIdentifier
, const CSSM_DATA
&blob
)
289 commonCreate(dlDbIdentifier
, autoCommit
);
290 Db::Impl::insert(DBBlobRelationID
, NULL
, &blob
);
293 passThrough(CSSM_APPLEFILEDL_COMMIT
, NULL
);
294 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
295 reinterpret_cast<const void *>(1));
306 SSDatabaseImpl::open(const DLDbIdentifier
&dlDbIdentifier
)
308 mIdentifier
= dlDbIdentifier
;
311 CssmDataContainer
dbb(allocator());
314 mSSDbHandle
= mClientSession
.decodeDb(dlDbIdentifier
, AccessCredentials::overlay(accessCredentials()), dbb
);
318 SSDatabaseImpl::recode(const CssmData
&data
, const CssmData
&extraData
)
320 // Start a transaction (Implies activate()).
321 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
, 0);
325 CssmDataContainer
dbb(allocator());
326 // Make sure mSSDbHandle is valid.
327 CssmClient::DbUniqueRecord dbBlobId
= getDbBlobId(&dbb
);
329 // re-establish the dbHandle with the SecurityServer
330 mSSDbHandle
= mClientSession
.decodeDb(mIdentifier
,
331 AccessCredentials::overlay(accessCredentials()), dbb
);
335 DbHandle successfulHdl
= mClientSession
.authenticateDbsForSync(data
, extraData
);
337 // Create a newDbHandle using the master secrets from the dbBlob we are
339 SecurityServer::DbHandle clonedDbHandle
=
340 mClientSession
.recodeDbForSync(successfulHdl
, mSSDbHandle
);
342 // @@@ If the dbb changed since we fetched it we should abort or
343 // retry the operation here.
346 DbCursor
cursor(SSDatabase(this));
347 cursor
->recordType(CSSM_DL_DB_RECORD_ALL_KEYS
);
348 CssmDataContainer
keyBlob(allocator());
349 CssmClient::DbUniqueRecord keyBlobId
;
350 DbAttributes attributes
;
351 while (cursor
->next(&attributes
, &keyBlob
, keyBlobId
))
353 // Decode the old key
354 CssmKey::Header header
;
355 KeyHandle keyHandle
=
356 mClientSession
.decodeKey(mSSDbHandle
, keyBlob
, header
);
358 CssmDataContainer
newKeyBlob(mClientSession
.returnAllocator
);
359 mClientSession
.recodeKey(mSSDbHandle
, keyHandle
, clonedDbHandle
,
361 mClientSession
.releaseKey(keyHandle
);
362 // Write the recoded key blob to the database
363 keyBlobId
->modify(attributes
.recordType(), NULL
, &newKeyBlob
,
364 CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
367 // Commit the new blob to securityd, reencode the db blob, release the
368 // cloned db handle and commit the new blob to the db.
369 mClientSession
.commitDbForSync(mSSDbHandle
, clonedDbHandle
,
371 dbBlobId
->modify(DBBlobRelationID
, NULL
, &dbb
,
372 CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
374 // Commit the transaction to the db
375 passThrough(CSSM_APPLEFILEDL_COMMIT
, NULL
);
376 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
377 reinterpret_cast<const void *>(1));
381 // Something went wrong rollback the transaction
382 passThrough(CSSM_APPLEFILEDL_ROLLBACK
, NULL
);
383 passThrough(CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT
,
384 reinterpret_cast<const void *>(1));
389 void SSDatabaseImpl::getRecordIdentifier(CSSM_DB_UNIQUE_RECORD_PTR uniqueRecord
, CSSM_DATA
&recordID
)
391 // the unique ID is composed of three uint32s (plus one filler word). Pull
392 // them out and byte swap them
393 recordID
.Length
= sizeof (uint32
) * kNumIDWords
;
394 recordID
.Data
= (uint8
*) allocator().malloc(recordID
.Length
);
397 uint32
* dest
= (uint32
*) recordID
.Data
;
398 uint32
* src
= (uint32
*) uniqueRecord
->RecordIdentifier
.Data
;
400 dest
[0] = htonl (src
[0]);
401 dest
[1] = htonl (src
[1]);
402 dest
[2] = htonl (src
[2]);
406 void SSDatabaseImpl::copyBlob(CSSM_DATA
&data
)
408 // get the blob from the database
409 CssmDataContainer
dbb(allocator());
412 // copy the data back
413 data
.Data
= dbb
.Data
;
414 data
.Length
= dbb
.Length
;
416 // zap the return structure so that we don't get zapped when dbb goes out of scope...
422 SSDatabaseImpl::newDbUniqueRecord()
424 return new SSUniqueRecordImpl(SSDatabase(this));
427 CssmClient::DbUniqueRecord
428 SSDatabaseImpl::getDbBlobId(CssmDataContainer
*dbb
)
430 CssmClient::DbUniqueRecord dbBlobId
;
432 DbCursor
cursor(SSDatabase(this));
433 cursor
->recordType(DBBlobRelationID
);
434 if (!cursor
->next(NULL
, dbb
, dbBlobId
))
435 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT
);
442 SSUniqueRecordImpl::SSUniqueRecordImpl(const SSDatabase
&db
)
443 : DbUniqueRecord::Impl(db
)
447 SSUniqueRecordImpl::~SSUniqueRecordImpl()
452 SSUniqueRecordImpl::database() const
454 return parent
<SSDatabase
>();