]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/AppleDatabase.h
Security-164.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / AppleDatabase.h
1 /*
2 * Copyright (c) 2000-2001, 2003 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 // AppleDatabase.h - Description t.b.d.
21 //
22 #ifndef _H_APPLEDATABASE
23 #define _H_APPLEDATABASE
24
25 #include "MetaRecord.h"
26 #include "SelectionPredicate.h"
27 #include "DbIndex.h"
28
29 #include <Security/AtomicFile.h>
30 #include <Security/Database.h>
31 #include <Security/DbContext.h>
32 #include <Security/handleobject.h>
33 #include <Security/refcount.h>
34 #include <memory>
35 #include <vector>
36
37 namespace Security
38 {
39
40 // Abstract database Cursor class.
41 class Cursor;
42 class DbVersion;
43 class CssmAutoQuery;
44
45 struct AppleDatabaseTableName
46 {
47 uint32 mTableId;
48 const char *mTableName;
49
50 // indices of meta-table entries in an array of table names
51
52 enum {
53 kSchemaInfo = 0,
54 kSchemaAttributes,
55 kSchemaIndexes,
56 kSchemaParsingModule,
57 kNumRequiredTableNames
58 };
59 };
60
61 //
62 // This is what the CDSA standard refers to as a Relation. We use
63 // the more conventional term Table.
64 //
65 class Table
66 {
67 NOCOPY(Table)
68 public:
69 // Type used to refer to a table.
70 typedef CSSM_DB_RECORDTYPE Id;
71
72 Table(const ReadSection &inTableSection);
73 ~Table();
74
75 // Return a newly created cursor satisfying inQuery on the receiving table
76 // The returned Cursor may or may not use indexes depending on their availability.
77 Cursor *createCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion) const;
78
79 const ReadSection getRecordSection(uint32 inRecordNumber) const;
80
81 const RecordId getRecord(const RecordId &inRecordId,
82 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
83 CssmData *inoutData,
84 CssmAllocator &inAllocator) const;
85
86 // Return the number of recordNumbers in use by this table including empty slots.
87 uint32 recordNumberCount() const { return mRecordNumbersCount; }
88 uint32 freeListHead() const { return mFreeListHead; }
89
90 // Return the record number corresponding to aFreeListHead and update
91 // aFreeListHead to point to the next availble recordNumber slot.
92 uint32 popFreeList(uint32 &aFreeListHead) const;
93
94 MetaRecord &getMetaRecord() { return mMetaRecord; }
95 const MetaRecord &getMetaRecord() const { return mMetaRecord; }
96
97 uint32 getRecordsCount() const { return mRecordsCount; }
98 const ReadSection getRecordsSection() const;
99
100 const ReadSection &getTableSection() const { return mTableSection; }
101
102 bool matchesTableId(Id inTableId) const;
103
104 void readIndexSection();
105
106 enum
107 {
108 OffsetSize = AtomSize * 0,
109 OffsetId = AtomSize * 1,
110 OffsetRecordsCount = AtomSize * 2,
111 OffsetRecords = AtomSize * 3,
112 OffsetIndexesOffset = AtomSize * 4,
113 OffsetFreeListHead = AtomSize * 5,
114 OffsetRecordNumbersCount = AtomSize * 6,
115 OffsetRecordNumbers = AtomSize * 7
116 };
117 protected:
118 friend class ModifiedTable;
119
120 MetaRecord mMetaRecord;
121 const ReadSection mTableSection;
122
123 uint32 mRecordsCount;
124 uint32 mFreeListHead;
125 // Number of record numbers (including freelist slots) in this table.
126 uint32 mRecordNumbersCount;
127
128 // all the table's indexes, mapped by index id
129 typedef map<uint32, DbConstIndex *> ConstIndexMap;
130 ConstIndexMap mIndexMap;
131 };
132
133 class ModifiedTable
134 {
135 NOCOPY(ModifiedTable)
136 public:
137 ModifiedTable(const Table *inTable);
138 ModifiedTable(MetaRecord *inMetaRecord); // Take over ownership of inMetaRecord
139 ~ModifiedTable();
140
141 // Mark the record with inRecordId as deleted.
142 void deleteRecord(const RecordId &inRecordId);
143 const RecordId insertRecord(uint32 inVersionId,
144 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
145 const CssmData *inData);
146 const RecordId updateRecord(const RecordId &inRecordId,
147 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
148 const CssmData *inData,
149 CSSM_DB_MODIFY_MODE inModifyMode);
150
151 // Return the MetaRecord this table should use for writes.
152 const MetaRecord &getMetaRecord() const;
153
154 // find, and create if needed, an index with the given id
155 DbMutableIndex &findIndex(uint32 indexId, const MetaRecord &metaRecord, bool isUniqueIndex);
156
157 // Write this table to inOutputFile at inSectionOffset and return the new offset.
158 uint32 writeTable(AtomicTempFile &inAtomicTempFile, uint32 inSectionOffset);
159
160 private:
161 // Return the next available record number for this table.
162 uint32 nextRecordNumber();
163
164 // Return the number of recordNumbers in use by this table including empty slots.
165 uint32 recordNumberCount() const;
166
167 void modifyTable();
168 void createMutableIndexes();
169 uint32 writeIndexSection(WriteSection &tableSection, uint32 offset);
170
171 // Optional, this is merly a reference, we do not own this object.
172 const Table *mTable;
173
174 // Optional, New MetaRecord. This is only present if it is different from the
175 // MetaRecord of mTable or mTable is nil.
176 const MetaRecord *mNewMetaRecord;
177
178 // Set of Records that have been deleted or modified.
179 typedef set<uint32> DeletedSet;
180 DeletedSet mDeletedSet;
181
182 // Set of Records that have been inserted or modified.
183 typedef map<uint32, WriteSection *> InsertedMap;
184 InsertedMap mInsertedMap;
185
186 // Next lowest available RecordNumber
187 uint32 mRecordNumberCount;
188 // Head of the free list (if there is one) or 0 if either we have no
189 // mTable of the free list has been exhausted.
190 uint32 mFreeListHead;
191
192 // has this table actually been modified?
193 bool mIsModified;
194
195 typedef map<uint32, DbMutableIndex *> MutableIndexMap;
196 MutableIndexMap mIndexMap;
197 };
198
199 //
200 // Read only snapshot of a database.
201 //
202 class Metadata
203 {
204 NOCOPY(Metadata)
205 protected:
206 Metadata() {}
207 enum
208 {
209 HeaderOffset = 0, // Absolute offset of header.
210 OffsetMagic = AtomSize * 0,
211 OffsetVersion = AtomSize * 1,
212 OffsetAuthOffset = AtomSize * 2,
213 OffsetSchemaOffset = AtomSize * 3,
214 HeaderSize = AtomSize * 4,
215
216 HeaderMagic = FOUR_CHAR_CODE('kych'),
217 HeaderVersion = 0x00010000
218 };
219
220 enum
221 {
222 OffsetSchemaSize = AtomSize * 0,
223 OffsetTablesCount = AtomSize * 1,
224 OffsetTables = AtomSize * 2
225 };
226 };
227
228 //
229 // Read only representation of a database
230 //
231 class DbVersion : public Metadata, public RefCount
232 {
233 NOCOPY(DbVersion)
234 public:
235 DbVersion(const class AppleDatabase &db, const RefPointer <AtomicBufferedFile> &inAtomicBufferedFile);
236 ~DbVersion();
237
238 uint32 getVersionId() const { return mVersionId; }
239 const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
240 CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
241 CssmData *inoutData, CssmAllocator &inAllocator) const;
242 Cursor *createCursor(const CSSM_QUERY *inQuery) const;
243 protected:
244 const Table &findTable(Table::Id inTableId) const;
245 Table &findTable(Table::Id inTableId);
246
247 private:
248 void open(); // Part of constructor contract.
249
250 ReadSection mDatabase;
251 uint32 mVersionId;
252
253 friend class DbModifier; // XXX Fixme
254 typedef map<Table::Id, Table *> TableMap;
255 TableMap mTableMap;
256 const class AppleDatabase &mDb;
257 RefPointer<AtomicBufferedFile> mBufferedFile;
258
259 public:
260 typedef Table value_type;
261 typedef const Table &const_reference;
262 typedef const Table *const_pointer;
263
264 // A const forward iterator.
265 class const_iterator
266 {
267 public:
268 const_iterator(const TableMap::const_iterator &it) : mIterator(it) {}
269
270 // Use default copy consturctor and assignment operator.
271 //const_iterator(const const_iterator &it) : mIterator(it.mIterator) {}
272 //const_iterator &operator=(const const_iterator &it) { mIterator = it.mIterator; return *this; }
273 const_reference operator*() const { return *mIterator->second; }
274 const_iterator &operator++() { mIterator.operator++(); return *this; }
275 const_iterator operator++(int i) { return const_iterator(mIterator.operator++(i)); }
276 bool operator!=(const const_iterator &other) const { return mIterator != other.mIterator; }
277 bool operator==(const const_iterator &other) const { return mIterator == other.mIterator; }
278
279 const_pointer operator->() const { return mIterator->second; } // Not really needed.
280
281 private:
282 TableMap::const_iterator mIterator;
283 };
284
285 const_iterator begin() const { return const_iterator(mTableMap.begin()); }
286 const_iterator end() const { return const_iterator(mTableMap.end()); }
287 };
288
289 //
290 // Cursor
291 //
292 class Cursor : public HandleObject
293 {
294 public:
295 virtual ~Cursor();
296 virtual bool next(Table::Id &outTableId,
297 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
298 CssmData *outData,
299 CssmAllocator &inAllocator,
300 RecordId &recordId) = 0;
301 };
302
303 //
304 // LinearCursor
305 //
306 class LinearCursor : public Cursor
307 {
308 NOCOPY(LinearCursor)
309 public:
310 LinearCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion,
311 const Table &inTable);
312 virtual ~LinearCursor();
313 virtual bool next(Table::Id &outTableId,
314 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
315 CssmData *outData,
316 CssmAllocator &inAllocator,
317 RecordId &recordId);
318
319 private:
320 const RefPointer<const DbVersion> mDbVersion;
321 uint32 mRecordsCount;
322 uint32 mRecord;
323 const ReadSection mRecordsSection;
324 uint32 mReadOffset;
325 const MetaRecord &mMetaRecord;
326
327 CSSM_DB_CONJUNCTIVE mConjunctive;
328 CSSM_QUERY_FLAGS mQueryFlags; // If CSSM_QUERY_RETURN_DATA is set return the raw key bits;
329 typedef vector<SelectionPredicate *> PredicateVector;
330
331 PredicateVector mPredicates;
332 };
333
334 //
335 // A cursor that uses an index.
336 //
337
338 class IndexCursor : public Cursor
339 {
340 NOCOPY(IndexCursor)
341 public:
342 IndexCursor(DbQueryKey *queryKey, const DbVersion &inDbVersion,
343 const Table &table, const DbConstIndex *index);
344 virtual ~IndexCursor();
345
346 virtual bool next(Table::Id &outTableId,
347 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
348 CssmData *outData,
349 CssmAllocator &inAllocator,
350 RecordId &recordId);
351
352 private:
353 auto_ptr<DbQueryKey> mQueryKey;
354 const DbVersion &mDbVersion;
355 const Table &mTable;
356 const DbConstIndex *mIndex;
357
358 DbIndexIterator mBegin, mEnd;
359 };
360
361 //
362 // MultiCursor
363 //
364 class MultiCursor : public Cursor
365 {
366 NOCOPY(MultiCursor)
367 public:
368 MultiCursor(const CSSM_QUERY *inQuery, const DbVersion &inDbVersion);
369 virtual ~MultiCursor();
370 virtual bool next(Table::Id &outTableId,
371 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR outAttributes,
372 CssmData *outData,
373 CssmAllocator &inAllocator,
374 RecordId &recordId);
375 private:
376 const RefPointer<const DbVersion> mDbVersion;
377 auto_ptr<CssmAutoQuery> mQuery;
378
379 DbVersion::const_iterator mTableIterator;
380 auto_ptr<Cursor> mCursor;
381 };
382
383 //
384 // A DbModifier contains all pending changes to be made to a DB.
385 // It also contains a DbVersion representing the state of the Database before any such changes
386 // No read-style operations are supported by DbModifier. If a DbModifier exists for a
387 // particular Database and a client wishes to perform a query commit() must be called and
388 // the client should perform the new query on the current database version after the commit.
389 // Otherwise a client will not see changes made since the DbModifier was instanciated.
390 //
391 class DbModifier : public Metadata
392 {
393 NOCOPY(DbModifier)
394 public:
395 DbModifier(AtomicFile &inAtomicFile, const class AppleDatabase &db);
396 ~DbModifier();
397
398 // Whole database affecting members.
399 void createDatabase(const CSSM_DBINFO &inDbInfo,
400 const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry,
401 mode_t mode);
402 void openDatabase(); // This is optional right now.
403 void closeDatabase();
404 void deleteDatabase();
405
406 void commit();
407 void rollback() throw();
408
409 // Record changing members
410 void deleteRecord(Table::Id inTableId, const RecordId &inRecordId);
411 const RecordId insertRecord(Table::Id inTableId,
412 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
413 const CssmData *inData);
414 const RecordId updateRecord(Table::Id inTableId, const RecordId &inRecordId,
415 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
416 const CssmData *inData,
417 CSSM_DB_MODIFY_MODE inModifyMode);
418
419 // Schema changing members
420 void insertTable(Table::Id inTableId, const string &inTableName,
421 uint32 inNumberOfAttributes,
422 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo,
423 uint32 inNumberOfIndexes,
424 const CSSM_DB_SCHEMA_INDEX_INFO *inIndexInfo);
425 void deleteTable(Table::Id inTableId);
426
427 // Record reading members
428 const RecordId getRecord(Table::Id inTableId, const RecordId &inRecordId,
429 CSSM_DB_RECORD_ATTRIBUTE_DATA *inoutAttributes,
430 CssmData *inoutData, CssmAllocator &inAllocator);
431 Cursor *createCursor(const CSSM_QUERY *inQuery);
432 protected:
433 void modifyDatabase();
434 const RefPointer<const DbVersion> getDbVersion();
435
436 ModifiedTable *createTable(MetaRecord *inMetaRecord); // Takes over ownership of inMetaRecord
437
438 void insertTableSchema(const CssmDbRecordAttributeInfo &inInfo,
439 const CSSM_DB_RECORD_INDEX_INFO *inIndexInfo = NULL);
440
441 void insertTable(const CssmDbRecordAttributeInfo &inInfo,
442 const CSSM_DB_RECORD_INDEX_INFO * inIndexInfo = NULL,
443 const CSSM_DB_PARSING_MODULE_INFO * inParsingModule = NULL);
444
445 ModifiedTable &findTable(Table::Id inTableId);
446
447 uint32 writeAuthSection(uint32 inSectionOffset);
448 uint32 writeSchemaSection(uint32 inSectionOffset);
449
450 private:
451
452 // Current DbVersion of this database before any changes we are going to make.
453 RefPointer<const DbVersion> mDbVersion;
454 Mutex mDbVersionLock;
455
456 AtomicFile &mAtomicFile;
457 uint32 mVersionId;
458 RefPointer<AtomicTempFile> mAtomicTempFile;
459
460 typedef map<Table::Id, ModifiedTable *> ModifiedTableMap;
461 ModifiedTableMap mModifiedTableMap;
462
463 const class AppleDatabase &mDb;
464 };
465
466 //
467 // AppleDatabaseManager
468 //
469 class AppleDatabaseManager : public DatabaseManager
470 {
471 public:
472 AppleDatabaseManager(const AppleDatabaseTableName *tableNames);
473 Database *make(const DbName &inDbName);
474
475 protected:
476 const AppleDatabaseTableName *mTableNames;
477 };
478
479 //
480 // AppleDbContext
481 //
482 class AppleDbContext : public DbContext
483 {
484 public:
485 AppleDbContext(Database &inDatabase,
486 DatabaseSession &inDatabaseSession,
487 CSSM_DB_ACCESS_TYPE inAccessRequest,
488 const AccessCredentials *inAccessCred,
489 const void *inOpenParameters);
490 virtual ~AppleDbContext();
491 bool autoCommit() const { return mAutoCommit; }
492 void autoCommit(bool on) { mAutoCommit = on; }
493 mode_t mode() const { return mMode; }
494
495 private:
496 bool mAutoCommit;
497 mode_t mMode;
498 };
499
500 //
501 // AppleDatabase
502 //
503 class AppleDatabase : public Database
504 {
505 public:
506 AppleDatabase(const DbName &inDbName, const AppleDatabaseTableName *tableNames);
507 virtual ~AppleDatabase();
508
509 virtual void
510 dbCreate(DbContext &inDbContext, const CSSM_DBINFO &inDBInfo,
511 const CSSM_ACL_ENTRY_INPUT *inInitialAclEntry);
512
513 virtual void
514 dbOpen(DbContext &inDbContext);
515
516 virtual void
517 dbClose();
518
519 virtual void
520 dbDelete(DatabaseSession &inDatabaseSession,
521 const AccessCredentials *inAccessCred);
522
523 virtual void
524 createRelation(DbContext &inDbContext,
525 CSSM_DB_RECORDTYPE inRelationID,
526 const char *inRelationName,
527 uint32 inNumberOfAttributes,
528 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO &inAttributeInfo,
529 uint32 inNumberOfIndexes,
530 const CSSM_DB_SCHEMA_INDEX_INFO &inIndexInfo);
531
532 virtual void
533 destroyRelation(DbContext &inDbContext,
534 CSSM_DB_RECORDTYPE inRelationID);
535
536 virtual void
537 authenticate(DbContext &inDbContext,
538 CSSM_DB_ACCESS_TYPE inAccessRequest,
539 const AccessCredentials &inAccessCred);
540
541 virtual void
542 getDbAcl(DbContext &inDbContext,
543 const CSSM_STRING *inSelectionTag,
544 uint32 &outNumberOfAclInfos,
545 CSSM_ACL_ENTRY_INFO_PTR &outAclInfos);
546
547 virtual void
548 changeDbAcl(DbContext &inDbContext,
549 const AccessCredentials &inAccessCred,
550 const CSSM_ACL_EDIT &inAclEdit);
551
552 virtual void
553 getDbOwner(DbContext &inDbContext, CSSM_ACL_OWNER_PROTOTYPE &outOwner);
554
555 virtual void
556 changeDbOwner(DbContext &inDbContext,
557 const AccessCredentials &inAccessCred,
558 const CSSM_ACL_OWNER_PROTOTYPE &inNewOwner);
559
560 virtual char *
561 getDbNameFromHandle(const DbContext &inDbContext) const;
562
563 virtual CSSM_DB_UNIQUE_RECORD_PTR
564 dataInsert(DbContext &inDbContext,
565 CSSM_DB_RECORDTYPE RecordType,
566 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
567 const CssmData *inData);
568
569 virtual void
570 dataDelete(DbContext &inDbContext,
571 const CSSM_DB_UNIQUE_RECORD &inUniqueRecordIdentifier);
572
573 virtual void
574 dataModify(DbContext &inDbContext,
575 CSSM_DB_RECORDTYPE inRecordType,
576 CSSM_DB_UNIQUE_RECORD &inoutUniqueRecordIdentifier,
577 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributesToBeModified,
578 const CssmData *inDataToBeModified,
579 CSSM_DB_MODIFY_MODE inModifyMode);
580
581 virtual CSSM_HANDLE
582 dataGetFirst(DbContext &inDbContext,
583 const DLQuery *inQuery,
584 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
585 CssmData *inoutData,
586 CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
587
588 virtual bool
589 dataGetNext(DbContext &inDbContext,
590 CSSM_HANDLE inResultsHandle,
591 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
592 CssmData *inoutData,
593 CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord);
594
595 virtual void
596 dataAbortQuery(DbContext &inDbContext,
597 CSSM_HANDLE inResultsHandle);
598
599 virtual void
600 dataGetFromUniqueRecordId(DbContext &inDbContext,
601 const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
602 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
603 CssmData *inoutData);
604
605 virtual void
606 freeUniqueRecord(DbContext &inDbContext,
607 CSSM_DB_UNIQUE_RECORD &inUniqueRecord);
608
609 virtual void passThrough(DbContext &dbContext,
610 uint32 passThroughId,
611 const void *inputParams,
612 void **outputParams);
613
614 // Subclasses must implement this method.
615 virtual DbContext *makeDbContext(DatabaseSession &inDatabaseSession,
616 CSSM_DB_ACCESS_TYPE inAccessRequest,
617 const AccessCredentials *inAccessCred,
618 const void *inOpenParameters);
619
620 const CssmDbRecordAttributeInfo schemaRelations;
621 const CssmDbRecordAttributeInfo schemaAttributes;
622 const CssmDbRecordAttributeInfo schemaIndexes;
623 const CssmDbRecordAttributeInfo schemaParsingModule;
624
625 const char *recordName(CSSM_DB_RECORDTYPE inRecordType) const;
626
627 private:
628 static void
629 AppleDatabase::updateUniqueRecord(DbContext &inDbContext,
630 CSSM_DB_RECORDTYPE inTableId,
631 const RecordId &inRecordId,
632 CSSM_DB_UNIQUE_RECORD &inoutUniqueRecord);
633
634 CSSM_DB_UNIQUE_RECORD_PTR
635 createUniqueRecord(DbContext &inDbContext, CSSM_DB_RECORDTYPE inTableId,
636 const RecordId &inRecordId);
637 const RecordId parseUniqueRecord(const CSSM_DB_UNIQUE_RECORD &inUniqueRecord,
638 CSSM_DB_RECORDTYPE &outTableId);
639
640 Mutex mWriteLock;
641 AtomicFile mAtomicFile;
642 DbModifier mDbModifier;
643 const AppleDatabaseTableName *mTableNames;
644 };
645
646 } // end namespace Security
647
648 #endif //_H_APPLEDATABASE