1/* 2 * Copyright (c) 2000-2008 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// database - database session management 27// 28#include "database.h" 29#include "agentquery.h" 30#include "key.h" 31#include "server.h" 32#include "session.h" 33#include "notifications.h" 34#include <security_agent_client/agentclient.h> 35#include <securityd_client/dictionary.h> 36#include <security_cdsa_utilities/acl_any.h> // for default owner ACLs 37#include <security_cdsa_client/wrapkey.h> 38#include <security_utilities/endian.h> 39 40using namespace UnixPlusPlus; 41 42 43// 44// DbCommon basics 45// 46DbCommon::DbCommon(Session &session) 47{ 48 referent(session); 49} 50 51Session &DbCommon::session() const 52{ 53 return referent<Session>(); 54} 55 56 57// 58// Database basics 59// 60Database::Database(Process &proc) 61{ 62 referent(proc); 63} 64 65 66Process& Database::process() const 67{ 68 return referent<Process>(); 69} 70 71 72// 73// Send a keychain-related notification event about this database 74// 75void DbCommon::notify(NotificationEvent event, const DLDbIdentifier &ident) 76{ 77 // form the data (encoded DLDbIdentifier) 78 NameValueDictionary nvd; 79 NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(ident, nvd); 80 CssmData data; 81 nvd.Export(data); 82 83 // inject notification into Security event system 84 Listener::notify(kNotificationDomainDatabase, event, data); 85 86 // clean up 87 free (data.data()); 88} 89 90 91// 92// Default behaviors 93// 94void DbCommon::sleepProcessing() 95{ 96 // nothing 97} 98 99void DbCommon::lockProcessing() 100{ 101 // nothing 102} 103 104bool DbCommon::belongsToSystem() const 105{ 106 return false; 107} 108 109 110void Database::releaseKey(Key &key) 111{ 112 kill(key); 113} 114 115void Database::releaseSearch(Search &search) 116{ 117 kill(search); 118} 119 120void Database::releaseRecord(Record &record) 121{ 122 kill(record); 123} 124 125void Database::dbName(const char *name) 126{ 127 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 128} 129 130 131// 132// Functions that aren't implemented at the Database level but can stay that way 133// 134void Database::findFirst(const CssmQuery &query, 135 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, 136 CssmData *data, RefPointer<Key> &key, RefPointer<Search> &search, RefPointer<Record> &record, 137 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) 138{ 139 secdebug("database", "%p calling unimplemented findFirst", this); 140 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 141} 142 143void Database::findNext(Search *search, 144 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, 145 CssmData *data, RefPointer<Key> &key, RefPointer<Record> &record, 146 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) 147{ 148 secdebug("database", "%p calling unimplemented findNext", this); 149 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 150} 151 152void Database::findRecordHandle(Record *record, 153 CssmDbRecordAttributeData *inAttributes, mach_msg_type_number_t inAttributesLength, 154 CssmData *data, RefPointer<Key> &key, 155 CssmDbRecordAttributeData * &outAttributes, mach_msg_type_number_t &outAttributesLength) 156{ 157 secdebug("database", "%p calling unimplemented findRecordHandle", this); 158 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 159} 160 161void Database::insertRecord(CSSM_DB_RECORDTYPE recordtype, 162 const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, 163 const CssmData &data, RecordHandle &record) 164{ 165 secdebug("database", "%p calling unimplemented insertRecord", this); 166 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 167} 168 169void Database::modifyRecord(CSSM_DB_RECORDTYPE recordtype, Record *record, 170 const CssmDbRecordAttributeData *attributes, mach_msg_type_number_t inAttributesLength, 171 const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode) 172{ 173 secdebug("database", "%p calling unimplemented modifyRecord", this); 174 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 175} 176 177void Database::deleteRecord(Database::Record *record) 178{ 179 secdebug("database", "%p calling unimplemented deleteRecord", this); 180 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 181} 182 183void Database::authenticate(CSSM_DB_ACCESS_TYPE, const AccessCredentials *) 184{ 185 secdebug("database", "%p calling unimplemented authenticate", this); 186 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 187} 188 189SecurityServerAcl &Database::acl() 190{ 191 secdebug("database", "%p has no ACL implementation", this); 192 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 193} 194 195bool Database::isLocked() 196{ 197 secdebug("database", "%p calling unimplemented isLocked", this); 198 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); 199} 200 201 202// 203// SecurityServerAcl personality implementation. 204// This is the trivial (type coding) stuff. The hard stuff is virtually mixed in. 205// 206Database *Database::relatedDatabase() 207{ 208 return this; 209} 210 211AclKind Database::aclKind() const 212{ 213 return dbAcl; 214} 215 216 217// 218// Remote validation is not, by default, supported 219// 220bool Database::validateSecret(const AclSubject *, const AccessCredentials *) 221{ 222 return false; 223} 224 225 226// 227// Implementation of a "system keychain unlock key store" 228// 229SystemKeychainKey::SystemKeychainKey(const char *path) 230 : mPath(path), mValid(false) 231{ 232 // explicitly set up a key header for a raw 3DES key 233 CssmKey::Header &hdr = mKey.header(); 234 hdr.blobType(CSSM_KEYBLOB_RAW); 235 hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING); 236 hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY); 237 hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE); 238 hdr.KeyAttr = 0; 239 hdr.KeyUsage = CSSM_KEYUSE_ANY; 240 mKey = CssmData::wrap(mBlob.masterKey); 241} 242 243SystemKeychainKey::~SystemKeychainKey() 244{ 245} 246 247bool SystemKeychainKey::matches(const DbBlob::Signature &signature) 248{ 249 return update() && signature == mBlob.signature; 250} 251 252bool SystemKeychainKey::update() 253{ 254 // if we checked recently, just assume it's okay 255 if (mValid && mUpdateThreshold > Time::now()) 256 return mValid; 257 258 // check the file 259 struct stat st; 260 if (::stat(mPath.c_str(), &st)) { 261 // something wrong with the file; can't use it 262 mUpdateThreshold = Time::now() + Time::Interval(checkDelay); 263 return mValid = false; 264 } 265 if (mValid && Time::Absolute(st.st_mtimespec) == mCachedDate) 266 return true; 267 mUpdateThreshold = Time::now() + Time::Interval(checkDelay); 268 269 try { 270 secdebug("syskc", "reading system unlock record from %s", mPath.c_str()); 271 AutoFileDesc fd(mPath, O_RDONLY); 272 if (fd.read(mBlob) != sizeof(mBlob)) 273 return false; 274 if (mBlob.isValid()) { 275 mCachedDate = st.st_mtimespec; 276 return mValid = true; 277 } else 278 return mValid = false; 279 } catch (...) { 280 secdebug("syskc", "system unlock record not available"); 281 return false; 282 } 283} 284