]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | #include "dltests.h" |
2 | #include "csptests.h" | |
3 | #include "attributes.h" | |
4 | #include <security_cdsa_client/multidldb.h> | |
5 | #include <vector> | |
6 | #include <security_cdsa_client/securestorage.h> // For CSPDL. | |
7 | #include <security_cdsa_client/genkey.h> | |
8 | #include <security_utilities/trackingallocator.h> | |
9 | ||
10 | using namespace CssmClient; | |
11 | ||
12 | // Configuration. | |
13 | #define HEX_DIGITS_PER_LINE 20 | |
14 | #define INDENT_SIZE 2 | |
15 | ||
16 | ||
17 | const CSSM_GUID* gSelectedFileGuid = &gGuidAppleFileDL; | |
18 | ||
19 | ||
20 | ||
21 | static void testDLCreate(const Guid &dlGuid); | |
22 | static void testDLDelete(const Guid &dlGuid, bool throwOnError); | |
23 | static void testGen(const Guid &cspDlGuid); | |
24 | static void testDLCrypt(const Guid &cspDlGuid); | |
25 | static void testMultiDLDb(const Guid &dlGuid); | |
26 | static void dumpRelation(uint32 indent, Db &db, uint32 relationID, const char *relationName, bool printSchema); | |
27 | static void dumpRecord(uint32 indent, const DbAttributes &record, const CssmData &data, const DbUniqueRecord &uniqueId); | |
28 | ||
29 | #define CSSM_DB_RELATION(RELATIONID) RecordAttrInfo ## RELATIONID | |
30 | ||
31 | #define CSSM_DB_DEFINE_RELATION_BEGIN(RELATIONID) \ | |
32 | static const CSSM_DB_ATTRIBUTE_INFO AttrInfo ## RELATIONID[] = | |
33 | ||
34 | #define CSSM_DB_DEFINE_RELATION_END(RELATIONID) \ | |
35 | ; \ | |
36 | static const CSSM_DB_RECORD_ATTRIBUTE_INFO CSSM_DB_RELATION(RELATIONID) = \ | |
37 | { \ | |
38 | RELATIONID, \ | |
39 | sizeof(AttrInfo ## RELATIONID) / sizeof(CSSM_DB_ATTRIBUTE_INFO), \ | |
40 | const_cast<CSSM_DB_ATTRIBUTE_INFO_PTR>(AttrInfo ## RELATIONID) \ | |
41 | } | |
42 | ||
43 | // GENERIC PASSWORDS | |
44 | CSSM_DB_DEFINE_RELATION_BEGIN(CSSM_DL_DB_RECORD_GENERIC_PASSWORD) | |
45 | { | |
46 | CSSM_DB_ATTR(Attributes::Class), | |
47 | CSSM_DB_ATTR(Attributes::CreationDate), | |
48 | CSSM_DB_ATTR(Attributes::ModDate), | |
49 | CSSM_DB_ATTR(Attributes::Description), | |
50 | CSSM_DB_ATTR(Attributes::Comment), | |
51 | CSSM_DB_ATTR(Attributes::Creator), | |
52 | CSSM_DB_ATTR(Attributes::Type), | |
53 | CSSM_DB_ATTR(Attributes::ScrCode), | |
54 | CSSM_DB_ATTR(Attributes::Label), | |
55 | CSSM_DB_ATTR(Attributes::Invisible), | |
56 | CSSM_DB_ATTR(Attributes::Negative), | |
57 | CSSM_DB_ATTR(Attributes::Custom), | |
58 | //CSSM_DB_ATTR(Attributes::Protected), | |
59 | CSSM_DB_ATTR(Attributes::Account), | |
60 | CSSM_DB_ATTR(Attributes::Service), | |
61 | CSSM_DB_ATTR(Attributes::Generic) | |
62 | } | |
63 | CSSM_DB_DEFINE_RELATION_END(CSSM_DL_DB_RECORD_GENERIC_PASSWORD); | |
64 | ||
65 | ||
66 | // APPLESHARE PASSWORDS | |
67 | CSSM_DB_DEFINE_RELATION_BEGIN(CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD) | |
68 | { | |
69 | CSSM_DB_ATTR(Attributes::Class), | |
70 | CSSM_DB_ATTR(Attributes::CreationDate), | |
71 | CSSM_DB_ATTR(Attributes::ModDate), | |
72 | CSSM_DB_ATTR(Attributes::Description), | |
73 | CSSM_DB_ATTR(Attributes::Comment), | |
74 | CSSM_DB_ATTR(Attributes::Creator), | |
75 | CSSM_DB_ATTR(Attributes::Type), | |
76 | CSSM_DB_ATTR(Attributes::ScrCode), | |
77 | CSSM_DB_ATTR(Attributes::Label), | |
78 | CSSM_DB_ATTR(Attributes::Invisible), | |
79 | CSSM_DB_ATTR(Attributes::Negative), | |
80 | CSSM_DB_ATTR(Attributes::Custom), | |
81 | //CSSM_DB_ATTR(Attributes::Protected), | |
82 | CSSM_DB_ATTR(Attributes::Volume), | |
83 | CSSM_DB_ATTR(Attributes::Addr), | |
84 | CSSM_DB_ATTR(Attributes::Signature), | |
85 | CSSM_DB_ATTR(Attributes::ProtocolType) | |
86 | } | |
87 | CSSM_DB_DEFINE_RELATION_END(CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD); | |
88 | ||
89 | // INTERNET PASSWORDS | |
90 | CSSM_DB_DEFINE_RELATION_BEGIN(CSSM_DL_DB_RECORD_INTERNET_PASSWORD) | |
91 | { | |
92 | CSSM_DB_ATTR(Attributes::Class), | |
93 | CSSM_DB_ATTR(Attributes::CreationDate), | |
94 | CSSM_DB_ATTR(Attributes::ModDate), | |
95 | CSSM_DB_ATTR(Attributes::Description), | |
96 | CSSM_DB_ATTR(Attributes::Comment), | |
97 | CSSM_DB_ATTR(Attributes::Creator), | |
98 | CSSM_DB_ATTR(Attributes::Type), | |
99 | CSSM_DB_ATTR(Attributes::ScrCode), | |
100 | CSSM_DB_ATTR(Attributes::Label), | |
101 | CSSM_DB_ATTR(Attributes::Invisible), | |
102 | CSSM_DB_ATTR(Attributes::Negative), | |
103 | CSSM_DB_ATTR(Attributes::Custom), | |
104 | //CSSM_DB_ATTR(Attributes::Protected), | |
105 | CSSM_DB_ATTR(Attributes::Account), | |
106 | CSSM_DB_ATTR(Attributes::SecDomain), | |
107 | CSSM_DB_ATTR(Attributes::Server), | |
108 | CSSM_DB_ATTR(Attributes::AuthType), | |
109 | CSSM_DB_ATTR(Attributes::Port), | |
110 | CSSM_DB_ATTR(Attributes::Path), | |
111 | CSSM_DB_ATTR(Attributes::ProtocolType) | |
112 | } | |
113 | CSSM_DB_DEFINE_RELATION_END(CSSM_DL_DB_RECORD_INTERNET_PASSWORD); | |
114 | ||
115 | // INTERNET PASSWORDS | |
116 | CSSM_DB_DEFINE_RELATION_BEGIN(CSSM_DL_DB_RECORD_SYMMETRIC_KEY) | |
117 | { | |
118 | CSSM_DB_ATTR(Attributes::KeyClass), | |
119 | CSSM_DB_ATTR(Attributes::PrintName), | |
120 | CSSM_DB_ATTR(Attributes::Alias), | |
121 | CSSM_DB_ATTR(Attributes::Permanent), | |
122 | CSSM_DB_ATTR(Attributes::Private), | |
123 | CSSM_DB_ATTR(Attributes::Modifiable), | |
124 | CSSM_DB_ATTR(Attributes::Label), | |
125 | CSSM_DB_ATTR(Attributes::ApplicationTag), | |
126 | CSSM_DB_ATTR(Attributes::KeyCreator), | |
127 | CSSM_DB_ATTR(Attributes::KeyType), | |
128 | CSSM_DB_ATTR(Attributes::KeySizeInBits), | |
129 | CSSM_DB_ATTR(Attributes::EffectiveKeySize), | |
130 | CSSM_DB_ATTR(Attributes::StartDate), | |
131 | CSSM_DB_ATTR(Attributes::EndDate), | |
132 | CSSM_DB_ATTR(Attributes::Sensitive), | |
133 | CSSM_DB_ATTR(Attributes::AlwaysSensitive), | |
134 | CSSM_DB_ATTR(Attributes::Extractable), | |
135 | CSSM_DB_ATTR(Attributes::NeverExtractable), | |
136 | CSSM_DB_ATTR(Attributes::Encrypt), | |
137 | CSSM_DB_ATTR(Attributes::Decrypt), | |
138 | CSSM_DB_ATTR(Attributes::Derive), | |
139 | CSSM_DB_ATTR(Attributes::Sign), | |
140 | CSSM_DB_ATTR(Attributes::Verify), | |
141 | CSSM_DB_ATTR(Attributes::SignRecover), | |
142 | CSSM_DB_ATTR(Attributes::VerifyRecover), | |
143 | CSSM_DB_ATTR(Attributes::Wrap), | |
144 | CSSM_DB_ATTR(Attributes::UnWrap) | |
145 | } | |
146 | CSSM_DB_DEFINE_RELATION_END(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); | |
147 | ||
148 | ||
149 | static const CSSM_DB_RECORD_ATTRIBUTE_INFO KCAttrs[] = | |
150 | { | |
151 | CSSM_DB_RELATION(CSSM_DL_DB_RECORD_GENERIC_PASSWORD), | |
152 | CSSM_DB_RELATION(CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD), | |
153 | CSSM_DB_RELATION(CSSM_DL_DB_RECORD_INTERNET_PASSWORD) | |
154 | //CSSM_DB_RELATION(CSSM_DL_DB_RECORD_SYMMETRIC_KEY) | |
155 | }; | |
156 | ||
157 | static const CSSM_DB_RECORD_INDEX_INFO recordIndex = | |
158 | { | |
159 | CSSM_DB_RECORDTYPE_APP_DEFINED_START, // CSSM_DB_RECORDTYPE | |
160 | 0, //%%% for now | |
161 | NULL //%%% for now | |
162 | }; | |
163 | static const CSSM_DB_RECORD_INDEX_INFO recordIndexes[] = {recordIndex, recordIndex, recordIndex}; | |
164 | ||
165 | // parse info (to improve later) | |
166 | static const CSSM_DB_PARSING_MODULE_INFO parseInfo = | |
167 | { | |
168 | CSSM_DB_RECORDTYPE_APP_DEFINED_START, | |
169 | { | |
170 | {0,0,0,{0}}, | |
171 | {0,0}, | |
172 | 0, | |
173 | 0 | |
174 | } | |
175 | }; | |
176 | static const CSSM_DB_PARSING_MODULE_INFO parseInfos[] = {parseInfo, parseInfo, parseInfo}; | |
177 | ||
178 | static const CSSM_DBINFO KCDBInfo = | |
179 | { | |
180 | sizeof(KCAttrs) / sizeof(CSSM_DB_RECORD_ATTRIBUTE_INFO), | |
181 | const_cast<CSSM_DB_PARSING_MODULE_INFO_PTR>(parseInfos), | |
182 | const_cast<CSSM_DB_RECORD_ATTRIBUTE_INFO_PTR>(KCAttrs), | |
183 | const_cast<CSSM_DB_RECORD_INDEX_INFO_PTR>(recordIndexes), | |
184 | CSSM_TRUE, | |
185 | NULL, | |
186 | NULL | |
187 | }; | |
188 | ||
189 | ||
190 | ||
191 | void dltests(bool autoCommit) | |
192 | { | |
193 | testDLDelete(gGuidAppleFileDL, false); | |
194 | testDLCreate(gGuidAppleFileDL); | |
195 | testMultiDLDb(gGuidAppleFileDL); | |
196 | ||
197 | testDLDelete(gGuidAppleCSPDL, false); | |
198 | testDLCreate(gGuidAppleCSPDL); | |
199 | testGen(gGuidAppleCSPDL); | |
200 | testDLCrypt(gGuidAppleCSPDL); | |
201 | testMultiDLDb(gGuidAppleCSPDL); | |
202 | //testDLDelete(gGuidAppleCSPDL, true); | |
203 | } | |
204 | ||
205 | static void testDLCreate(const Guid &dlGuid) | |
206 | { | |
207 | DL appledl(dlGuid); | |
208 | Db testDb(appledl, DBNAME1); | |
209 | testDb->dbInfo(&KCDBInfo); | |
210 | testDb->create(); | |
211 | } | |
212 | ||
213 | static void testDLDelete(const Guid &dlGuid, bool throwOnError) | |
214 | { | |
215 | DL appledl(dlGuid); | |
216 | Db testDb(appledl, DBNAME1); | |
217 | try | |
218 | { | |
219 | testDb->deleteDb(); | |
220 | } | |
221 | catch(CssmError e) | |
222 | { | |
223 | if (throwOnError || e.osStatus() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST) | |
224 | throw; | |
225 | } | |
226 | } | |
227 | ||
228 | static void testGen(const Guid &cspDlGuid) | |
229 | { | |
230 | printf("\n* performing CSP/DL keygen test...\n"); | |
231 | CSPDL cspdl(cspDlGuid); | |
232 | Db db(cspdl, DBNAME1); | |
233 | ||
234 | printf("Generating permanent key\n"); | |
235 | GenerateKey genKey(cspdl, CSSM_ALGID_DES, 64); | |
236 | genKey.database(db); | |
237 | CssmPolyData label("First Key!"); | |
238 | Key key = genKey(KeySpec(CSSM_KEYUSE_ANY, | |
239 | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE, | |
240 | label)); | |
241 | printf("done\n"); | |
242 | } | |
243 | ||
244 | static void testDLCrypt(const Guid &cspDlGuid) | |
245 | { | |
246 | printf("\n* performing encrypt/decrypt test...\n"); | |
247 | CSPDL cspdl(cspDlGuid); | |
248 | Db db(cspdl, DBNAME1); | |
249 | ||
250 | printf("Finding key\n"); | |
251 | DbCursor cursor(db); | |
252 | cursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); | |
253 | DbUniqueRecord keyId; | |
254 | CssmDataContainer keyData; | |
255 | if (!cursor->next(NULL, &keyData, keyId)) | |
256 | CssmError::throwMe(CSSMERR_DL_ENDOFDATA); | |
257 | ||
258 | Key key(cspdl, *reinterpret_cast<CSSM_KEY *>(keyData.Data)); | |
259 | ||
260 | printf("done\n"); | |
261 | ||
262 | // Gnerate IV | |
263 | printf("Generating iv\n"); | |
264 | //CssmData iv = Random(csp, CSSM_ALGID_SHARandom)(8); | |
265 | CssmPolyData iv("12345678"); | |
266 | ||
267 | CssmPolyData in("Om mani padme hum"); | |
268 | printf("input="); | |
269 | dump(in); | |
270 | ||
271 | // Encrypt | |
272 | printf("Encrypting\n"); | |
273 | ||
274 | Encrypt encrypt(cspdl, CSSM_ALGID_DES); | |
275 | encrypt.mode(CSSM_ALGMODE_CBCPadIV8); | |
276 | encrypt.padding(CSSM_PADDING_PKCS1); | |
277 | encrypt.initVector(iv); | |
278 | encrypt.key(key); | |
279 | CssmData cipher; | |
280 | CssmData remcipher; | |
281 | encrypt.encrypt(&in, 1, &cipher, 1); | |
282 | encrypt.final(remcipher); | |
283 | printf("ciphertext="); | |
284 | dump(cipher); | |
285 | printf("remainder="); | |
286 | dump(remcipher); | |
287 | ||
288 | // Decrypt | |
289 | printf("Decrypting\n"); | |
290 | ||
291 | Decrypt decrypt(cspdl, CSSM_ALGID_DES); | |
292 | decrypt.key(key); | |
293 | decrypt.mode(CSSM_ALGMODE_CBCPadIV8); | |
294 | decrypt.padding(CSSM_PADDING_PKCS1); | |
295 | decrypt.initVector(iv); | |
296 | CssmData plain; | |
297 | CssmData remplain; | |
298 | CssmData inp[] = { cipher, remcipher }; | |
299 | decrypt.decrypt(inp, 2, &plain, 1); | |
300 | decrypt.final(remplain); | |
301 | printf("plaintext="); | |
302 | dump(plain); | |
303 | printf("remainder="); | |
304 | dump(remplain); | |
305 | ||
306 | printf("end encrypt/decrypt test\n"); | |
307 | } | |
308 | ||
309 | static void print(sint32 value) | |
310 | { | |
311 | printf("%ld", value); | |
312 | } | |
313 | ||
314 | static void print(double value) | |
315 | { | |
316 | printf("%g", value); | |
317 | } | |
318 | ||
319 | static void print(uint32 value) | |
320 | { | |
321 | uint8 *bytes = reinterpret_cast<uint8 *>(&value); | |
322 | bool ascii = true; | |
323 | for (uint32 ix = 0; ix < sizeof(uint32); ++ix) | |
324 | if (bytes[ix] < 0x20 || bytes[ix] > 0x7f) | |
325 | { | |
326 | ascii = false; | |
327 | break; | |
328 | } | |
329 | ||
330 | if (ascii) | |
331 | { | |
332 | putchar('\''); | |
333 | for (uint32 ix = 0; ix < sizeof(uint32); ++ix) | |
334 | putchar(bytes[ix]); | |
335 | ||
336 | printf("' (0x%08lx)", value); | |
337 | } | |
338 | else | |
339 | printf("0x%08lx", value); | |
340 | } | |
341 | ||
342 | static void printAsString(uint32 indent, const CSSM_DATA &value) | |
343 | { | |
344 | printf("%.*s", static_cast<int>(value.Length), value.Data); | |
345 | } | |
346 | ||
347 | static void print(uint32 indent, const char *value) | |
348 | { | |
349 | printf("%s", value); | |
350 | } | |
351 | ||
352 | static void printIndent(uint32 indent) | |
353 | { | |
354 | //if (indent == 0) | |
355 | // return; | |
356 | ||
357 | putchar('\n'); | |
358 | for (uint32 ix = 0; ix < indent; ++ix) | |
359 | putchar(' '); | |
360 | } | |
361 | ||
362 | static void printRange(uint32 length, const uint8 *data) | |
363 | { | |
364 | for (uint32 ix = 0; ix < HEX_DIGITS_PER_LINE; ++ix) | |
365 | { | |
366 | if (ix && ix % 4 == 0) | |
367 | putchar(' '); | |
368 | ||
369 | if (ix < length) | |
370 | printf("%02x", static_cast<unsigned int>(data[ix])); | |
371 | else | |
372 | printf(" "); | |
373 | } | |
374 | ||
375 | printf(" "); | |
376 | for (uint32 ix = 0; ix < length; ++ix) | |
377 | { | |
378 | if (data[ix] < 0x20 || data[ix] > 0x7f) | |
379 | putchar('.'); | |
380 | else | |
381 | putchar(data[ix]); | |
382 | } | |
383 | } | |
384 | ||
385 | static void print(uint32 indent, const CSSM_DATA &value) | |
386 | { | |
387 | if (value.Length == 0) | |
388 | return; | |
389 | ||
390 | if (value.Length > HEX_DIGITS_PER_LINE) | |
391 | { | |
392 | uint32 ix; | |
393 | for (ix = 0; ix < value.Length - HEX_DIGITS_PER_LINE; ix += HEX_DIGITS_PER_LINE) | |
394 | { | |
395 | printIndent(indent); | |
396 | printRange(HEX_DIGITS_PER_LINE, &value.Data[ix]); | |
397 | } | |
398 | printIndent(indent); | |
399 | printRange(value.Length - ix, &value.Data[ix]); | |
400 | printIndent(indent - INDENT_SIZE); | |
401 | } | |
402 | else | |
403 | printRange(value.Length, value.Data); | |
404 | } | |
405 | ||
406 | static void printOID(uint32 indent, const CSSM_OID &value) | |
407 | { | |
408 | print(indent, value); | |
409 | } | |
410 | ||
411 | static const char *format(CSSM_DB_ATTRIBUTE_FORMAT format) | |
412 | { | |
413 | switch(format) | |
414 | { | |
415 | case CSSM_DB_ATTRIBUTE_FORMAT_STRING: return "string"; | |
416 | case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: return "sint32"; | |
417 | case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: return "uint32"; | |
418 | case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM: return "big_num"; | |
419 | case CSSM_DB_ATTRIBUTE_FORMAT_REAL: return "real"; | |
420 | case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE: return "time_date"; | |
421 | case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: return "blob"; | |
422 | case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32: return "multi_uint32"; | |
423 | case CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX: return "complex"; | |
424 | default: abort(); | |
425 | } | |
426 | } | |
427 | ||
428 | static void print(uint32 indent, const CssmDbAttributeData &attr) | |
429 | { | |
430 | bool multiValues = false; | |
431 | if (attr.size() == 0) | |
432 | { | |
433 | printf("<array/>"); | |
434 | return; | |
435 | } | |
436 | ||
437 | if (attr.size() != 1) | |
438 | { | |
439 | printIndent(indent); | |
440 | printf("<array>"); | |
441 | indent += INDENT_SIZE; | |
442 | multiValues = true; | |
443 | } | |
444 | ||
445 | for (uint32 ix = 0; ix < attr.size(); ++ix) | |
446 | { | |
447 | if (multiValues) | |
448 | printIndent(indent); | |
449 | ||
450 | printf("<%s>", format(attr.format())); | |
451 | switch (attr.format()) | |
452 | { | |
453 | case CSSM_DB_ATTRIBUTE_FORMAT_STRING: | |
454 | printAsString(indent + INDENT_SIZE, attr.at(ix)); | |
455 | break; | |
456 | case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: | |
457 | print(attr.at<uint32>(ix)); | |
458 | break; | |
459 | case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: | |
460 | print(attr.at<sint32>(ix)); | |
461 | break; | |
462 | case CSSM_DB_ATTRIBUTE_FORMAT_REAL: | |
463 | print(attr.at<double>(ix)); | |
464 | break; | |
465 | case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE: | |
466 | printf("%*s", 15, attr.at<const char *>(ix)); | |
467 | break; | |
468 | case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32: | |
469 | case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM: | |
470 | case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: | |
471 | case CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX: | |
472 | default: | |
473 | print(indent + INDENT_SIZE, attr.at<const CssmData &>(ix)); | |
474 | break; | |
475 | } | |
476 | printf("</%s>", format(attr.format())); | |
477 | } | |
478 | ||
479 | if (multiValues) | |
480 | { | |
481 | indent -= INDENT_SIZE; | |
482 | printIndent(indent); | |
483 | printf("</array>"); | |
484 | } | |
485 | } | |
486 | ||
487 | static void print(uint32 indent, const CssmDbAttributeInfo &info) | |
488 | { | |
489 | switch (info.nameFormat()) | |
490 | { | |
491 | case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: | |
492 | { | |
493 | printf("<string>"); | |
494 | print(indent + INDENT_SIZE, info.Label.AttributeName); | |
495 | printf("</string>"); | |
496 | break; | |
497 | } | |
498 | case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: | |
499 | { | |
500 | printf("<integer>"); | |
501 | print(info.Label.AttributeID); | |
502 | printf("</integer>"); | |
503 | break; | |
504 | } | |
505 | case CSSM_DB_ATTRIBUTE_NAME_AS_OID: | |
506 | { | |
507 | printf("<oid>"); | |
508 | printOID(indent + INDENT_SIZE, info.Label.AttributeOID); | |
509 | printf("</oid>"); | |
510 | break; | |
511 | } | |
512 | default: | |
513 | throw Error(CSSMERR_DL_DATABASE_CORRUPT); | |
514 | } | |
515 | } | |
516 | ||
517 | void dumpDb(char *dbName, bool printSchema) | |
518 | { | |
519 | DL appledl(*gSelectedFileGuid); | |
520 | Db db(appledl, dbName); | |
521 | DbCursor relations(db); | |
522 | relations->recordType(CSSM_DL_DB_SCHEMA_INFO); | |
523 | DbAttributes schemaRecord(db, 2); | |
524 | schemaRecord.add(Attributes::RelationID); | |
525 | schemaRecord.add(Attributes::RelationName); | |
526 | CssmDataContainer data; | |
527 | DbUniqueRecord uniqueId(db); | |
528 | ||
529 | uint32 indent = 0; | |
530 | printf("<database>"); | |
531 | indent += INDENT_SIZE; | |
532 | printIndent(indent); | |
533 | printf("<name>%s</name>", dbName); | |
534 | while (relations->next(&schemaRecord, &data, uniqueId)) | |
535 | { | |
536 | uint32 relationID = schemaRecord.at(0); | |
537 | if (!printSchema && CSSM_DB_RECORDTYPE_SCHEMA_START <= relationID | |
538 | && relationID < CSSM_DB_RECORDTYPE_SCHEMA_END) | |
539 | continue; | |
540 | ||
541 | printIndent(indent); | |
542 | printf("<relation>"); | |
543 | string relationName = schemaRecord.at(1); | |
544 | dumpRelation(indent + INDENT_SIZE, db, relationID, relationName.c_str(), printSchema); | |
545 | printIndent(indent); | |
546 | printf("</relation>"); | |
547 | } | |
548 | ||
549 | indent -= INDENT_SIZE; | |
550 | printIndent(indent); | |
551 | printf("</database>\n"); | |
552 | } | |
553 | ||
554 | static void dumpRelation(uint32 indent, Db &db, uint32 relationID, const char *relationName, bool printSchema) | |
555 | { | |
556 | TrackingAllocator anAllocator(Allocator::standard()); | |
557 | ||
558 | printIndent(indent); | |
559 | printf("<name>"); | |
560 | print(indent + INDENT_SIZE, relationName); | |
561 | printf("</name>"); | |
562 | printIndent(indent); | |
563 | printf("<id>"); | |
564 | print(relationID); | |
565 | printf("</id>"); | |
566 | ||
567 | // Create a cursor on the SCHEMA_ATTRIBUTES table for records with RelationID == relationID | |
568 | DbCursor attributes(db); | |
569 | attributes->recordType(CSSM_DL_DB_SCHEMA_ATTRIBUTES); | |
570 | attributes->add(CSSM_DB_EQUAL, Attributes::RelationID, relationID); | |
571 | ||
572 | // Set up a record for retriving the SCHEMA_ATTRIBUTES | |
573 | DbAttributes schemaRecord(db, 5); | |
574 | schemaRecord.add(Attributes::AttributeNameFormat); | |
575 | schemaRecord.add(Attributes::AttributeFormat); | |
576 | schemaRecord.add(Attributes::AttributeName); | |
577 | schemaRecord.add(Attributes::AttributeID); | |
578 | schemaRecord.add(Attributes::AttributeNameID); | |
579 | ||
580 | DbAttributes record(db); | |
581 | CssmDataContainer data; | |
582 | DbUniqueRecord uniqueId(db); | |
583 | ||
584 | if (printSchema) | |
585 | { | |
586 | printIndent(indent); | |
587 | printf("<schema>"); | |
588 | indent += INDENT_SIZE; | |
589 | } | |
590 | ||
591 | while (attributes->next(&schemaRecord, &data, uniqueId)) | |
592 | { | |
593 | CssmDbAttributeInfo &anInfo = record.add().info(); | |
594 | anInfo.AttributeNameFormat = schemaRecord.at(0); | |
595 | anInfo.AttributeFormat = schemaRecord.at(1); | |
596 | switch (anInfo.AttributeNameFormat) | |
597 | { | |
598 | case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: | |
599 | { | |
600 | CssmDbAttributeData &anAttributeName = schemaRecord.at(2); | |
601 | ||
602 | string name = static_cast<string>(anAttributeName); | |
603 | anInfo.Label.AttributeName = reinterpret_cast<char *>(anAllocator.malloc(name.size() + 1)); | |
604 | strcpy(anInfo.Label.AttributeName, name.c_str()); | |
605 | ||
606 | // XXX Need to copy the memory. For now avoid it being freed. | |
607 | anAttributeName.Value[0].Data = NULL; | |
608 | anAttributeName.Value[0].Length = 0; | |
609 | break; | |
610 | } | |
611 | case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: | |
612 | { | |
613 | CssmDbAttributeData &anAttributeID = schemaRecord.at(3); | |
614 | anInfo.Label.AttributeID = anAttributeID; | |
615 | break; | |
616 | } | |
617 | case CSSM_DB_ATTRIBUTE_NAME_AS_OID: | |
618 | { | |
619 | CssmDbAttributeData &anAttributeOID = schemaRecord.at(4); | |
620 | anInfo.Label.AttributeOID = anAttributeOID; | |
621 | ||
622 | // XXX Need to copy the memory. For now avoid it being freed. | |
623 | anAttributeOID.Value[0].Data = NULL; | |
624 | anAttributeOID.Value[0].Length = 0; | |
625 | break; | |
626 | } | |
627 | default: | |
628 | throw Error(CSSMERR_DL_DATABASE_CORRUPT); | |
629 | } | |
630 | ||
631 | if (printSchema) | |
632 | { | |
633 | printIndent(indent); | |
634 | print(indent, anInfo); | |
635 | printf("<format>%s</format>", format(anInfo.format())); | |
636 | } | |
637 | } | |
638 | ||
639 | if (printSchema) | |
640 | { | |
641 | indent -= INDENT_SIZE; | |
642 | printIndent(indent); | |
643 | printf("</schema>"); | |
644 | } | |
645 | ||
646 | DbCursor records(db); | |
647 | records->recordType(relationID); | |
648 | printIndent(indent); | |
649 | printf("<records>"); | |
650 | indent += INDENT_SIZE; | |
651 | while (records->next(&record, &data, uniqueId)) | |
652 | dumpRecord(indent, record, data, uniqueId); | |
653 | ||
654 | indent -= INDENT_SIZE; | |
655 | printIndent(indent); | |
656 | printf("</records>"); | |
657 | } | |
658 | ||
659 | static void | |
660 | dumpRecord(uint32 indent, const DbAttributes &record, const CssmData &data, const DbUniqueRecord &uniqueId) | |
661 | { | |
662 | const CSSM_DB_UNIQUE_RECORD *recId = static_cast<const DbUniqueRecord &>(uniqueId); | |
663 | uint32 recCount = recId->RecordIdentifier.Length; | |
664 | const uint32 *recArray = reinterpret_cast<const uint32 *>(recId->RecordIdentifier.Data); | |
665 | printIndent(indent); | |
666 | printf("<recid>"); | |
667 | for (uint32 ix = 0; ix < recCount / 4; ++ix) | |
668 | { | |
669 | if (ix != 0) | |
670 | putchar(' '); | |
671 | printf("0x%08lx", recArray[ix]); | |
672 | } | |
673 | printf("</recid>"); | |
674 | ||
675 | // Print the attributes | |
676 | printIndent(indent); | |
677 | if (record.size() == 0) | |
678 | { | |
679 | printf("<attributes/>"); | |
680 | } | |
681 | else | |
682 | { | |
683 | printf("<attributes>"); | |
684 | indent += INDENT_SIZE; | |
685 | for (uint32 ix = 0; ix < record.size(); ix++) | |
686 | { | |
687 | const CssmDbAttributeData &anAttr = record.at(ix); | |
688 | if (anAttr.size()) // Skip zero valued attributes. | |
689 | { | |
690 | printIndent(indent); | |
691 | print(indent + INDENT_SIZE, anAttr.info()); | |
692 | print(indent + INDENT_SIZE, anAttr); | |
693 | } | |
694 | } | |
695 | ||
696 | indent -= INDENT_SIZE; | |
697 | printIndent(indent); | |
698 | printf("</attributes>"); | |
699 | } | |
700 | ||
701 | // Print the data | |
702 | printIndent(indent); | |
703 | if (data.length()) | |
704 | { | |
705 | printf("<data>"); | |
706 | print(indent + INDENT_SIZE, data); | |
707 | printf("</data>"); | |
708 | } | |
709 | else | |
710 | printf("<data/>"); | |
711 | } | |
712 | ||
713 | static void testMultiDLDb(const Guid &dlGuid) | |
714 | { | |
715 | // Setup a list of DLDbIdentifier object to hand off the MultiDLDb. | |
716 | vector<DLDbIdentifier> list; | |
717 | list.push_back(DLDbIdentifier(CssmSubserviceUid(dlGuid), "multidb1.db", NULL)); | |
718 | list.push_back(DLDbIdentifier(CssmSubserviceUid(dlGuid), "multidb2.db", NULL)); | |
719 | ||
720 | // Create MultiDLDb instance. | |
721 | MultiDLDb multiDLDb(list, false); | |
722 | ||
723 | // Get a handle for the first and second Db. | |
724 | Db db1(multiDLDb->database(list[0])); | |
725 | Db db2(multiDLDb->database(list[1])); | |
726 | ||
727 | // Until this point no CSSM API's have been called! | |
728 | ||
729 | // Delete both databases if they exist. | |
730 | try | |
731 | { db1->deleteDb(); } | |
732 | catch(CssmError e) | |
733 | { if (e.osStatus() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST) throw; } | |
734 | ||
735 | try | |
736 | { db2->deleteDb(); } | |
737 | catch(CssmError e) | |
738 | { if (e.osStatus() != CSSMERR_DL_DATASTORE_DOESNOT_EXIST) throw; } | |
739 | ||
740 | // XXX Note to self if you set the schema but do not call create() | |
741 | // explicitly maybe the db should only be created if it did not yet exist... | |
742 | ||
743 | // Set the schema of both databases so they get created on activate. | |
744 | db1->dbInfo(&KCDBInfo); | |
745 | db2->dbInfo(&KCDBInfo); | |
746 | ||
747 | // Insert a record into each database. | |
748 | DbAttributes attrs(db1); | |
749 | attrs.add(Attributes::Comment, "This is the first comment").add("This is the second comment", attrs); | |
750 | attrs.add(Attributes::Label, "Item1"); | |
751 | CssmPolyData testdata1("testdata1"); | |
752 | db1->insert(CSSM_DL_DB_RECORD_GENERIC_PASSWORD, &attrs, &testdata1); | |
753 | ||
754 | attrs.clear(); | |
755 | attrs.add(Attributes::Comment, "This is the second comment"); | |
756 | attrs.add(Attributes::Label, "Item (in database2)."); | |
757 | CssmPolyData testdata2("testdata2"); | |
758 | db2->insert(CSSM_DL_DB_RECORD_GENERIC_PASSWORD, &attrs, &testdata2); | |
759 | ||
760 | // Create a cursor on the multiDLDb. | |
761 | DbCursor cursor(multiDLDb); | |
762 | // Set the type of records we wish to query. | |
763 | cursor->recordType(CSSM_DL_DB_RECORD_GENERIC_PASSWORD); | |
764 | cursor->add(CSSM_DB_EQUAL, Attributes::Comment, "This is the second comment"); | |
765 | ||
766 | DbUniqueRecord uniqueId; // Empty uniqueId calling cursor.next will initialize. | |
767 | CssmDataContainer data; // XXX Think about data's allocator. | |
768 | ||
769 | // Iterate over the records in all the db's in the multiDLDb. | |
770 | while (cursor->next(&attrs, &data, uniqueId)) | |
771 | { | |
772 | // Print the record data. | |
773 | dumpRecord(0, attrs, data, uniqueId); | |
774 | } | |
775 | } | |
776 | ||
777 | #if 0 | |
778 | CssmDb::Impl *CssmDL::Impl::newDb(args) { new CssmDbImpl(args); } | |
779 | ||
780 | SecureStorage ss(Guid); | |
781 | CssmDb db(ss, DBNAME); | |
782 | CssmUniqueId unique; | |
783 | db.insert(attr, data, unique); | |
784 | ||
785 | Cursor cursor(db); | |
786 | CssmKey key; | |
787 | cursor.next(key); | |
788 | ||
789 | Cssm cssm; | |
790 | Module module(cssm); | |
791 | CSPDL cspdl(module); | |
792 | ||
793 | ||
794 | SecureStorage ss(Guid); | |
795 | CssmDb db = ss->db(DBNAME); | |
796 | CssmUniqueId unique; | |
797 | db->insert(attr, data, unique); | |
798 | ||
799 | Cursor cursor(db); | |
800 | CssmKey key; | |
801 | cursor->next(key); | |
802 | ||
803 | ||
804 | #endif |