]> git.saurik.com Git - apple/security.git/blob - SecurityTests/testclient/dltests.cpp
Security-57740.20.22.tar.gz
[apple/security.git] / SecurityTests / testclient / dltests.cpp
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