1 /* Copyright (c) 2002-2006 Apple Computer, Inc.
3 * dbTool.cpp - DL/DB tool.
10 #include <Security/cssm.h>
11 #include <Security/cssmapple.h>
12 #include <Security/cssmapplePriv.h>
17 #include "cspdlTesting.h"
20 static void usage(char **argv
)
22 printf("usage: %s dbFileName command [options]\n", argv
[0]);
23 printf("Commands:\n");
24 printf(" r Dump Schema Relations\n");
25 printf(" k Dump all keys\n");
26 printf(" c Dump certs\n");
27 printf(" a Dump all records\n");
28 printf(" d Delete records (interactively)\n");
29 printf(" D Delete records (noninteractively, requires really arg)\n");
30 printf(" i Import bad cert and its (good) private key\n");
32 printf(" v verbose\n");
34 printf(" R really! (for D command)\n");
35 printf(" d dump data\n");
36 printf(" c=certFile\n");
37 printf(" k=keyFile\n");
42 static unsigned indentVal
= 0;
43 static void indentIncr()
48 static void indentDecr()
55 static void doIndent()
58 for(i
=0; i
<indentVal
; i
++) {
63 #define NORM_KEY_LEN 20
65 /* print an attribute name, padding out to NORM_KEY_LEN columns */
66 static void printName(
67 const CSSM_DB_ATTRIBUTE_INFO
*attrInfo
)
69 switch(attrInfo
->AttributeNameFormat
) {
70 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
:
72 char *attrName
= attrInfo
->Label
.AttributeName
;
73 printf("%s", attrName
);
74 int len
= strlen(attrName
);
75 if(len
> NORM_KEY_LEN
) {
78 int numSpaces
= NORM_KEY_LEN
- len
;
79 for(int i
=0; i
<numSpaces
; i
++) {
84 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
:
86 /* OSType, endian dependent... */
87 char *cp
= (char *)&(attrInfo
->Label
.AttributeID
);
88 for(unsigned i
=0; i
<4; i
++) {
95 printf("Unknown attribute name format (%u)\n",
96 (unsigned)attrInfo
->AttributeNameFormat
);
102 * Attempt to print a numeric value as a string, per a NameValuePair table.
103 * If the value is in fact a collection of legal values (per the nameValues
104 * array), the value will just be printed in hex.
106 static void printValueAsString(
108 const NameValuePair
*nameValues
)
110 if(nameValues
!= NULL
) {
111 while(nameValues
->name
!= NULL
) {
112 if(nameValues
->value
== val
) {
113 printf("%s", nameValues
->name
);
123 static void safePrint(
127 for(unsigned i
=0; i
<len
; i
++) {
132 /* See if a blob is printable. Used for BLOB and UINT32 types, the latter of
133 * which is sometimes used for OSType representation of attr name. */
137 bool printable
= true;
138 uint8
*cp
= dp
->Data
;
139 for(unsigned i
=0; i
<dp
->Length
; i
++) {
141 if(i
!= (dp
->Length
- 1)) {
142 /* data contains NULL character before end */
145 /* else end of string */
157 #define MAX_BLOB_TO_PRINT 12
158 static void printBlob(
159 const CSSM_DATA
*data
)
161 unsigned toPrint
= data
->Length
;
162 if(toPrint
> MAX_BLOB_TO_PRINT
) {
163 toPrint
= MAX_BLOB_TO_PRINT
;
165 for(unsigned i
=0; i
<toPrint
; i
++) {
166 unsigned dat
= data
->Data
[i
];
167 printf("%02X ", dat
);
169 if(toPrint
< data
->Length
) {
174 static void printAttrData(
175 const CSSM_DB_ATTRIBUTE_INFO
*attrInfo
,
176 const CSSM_DATA
*attrData
,
177 const NameValuePair
*nameValues
) // optional
179 void *data
= attrData
->Data
;
181 switch(attrInfo
->AttributeFormat
) {
183 case CSSM_DB_ATTRIBUTE_FORMAT_STRING
:
185 safePrint(attrData
->Data
, attrData
->Length
);
188 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
189 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
191 unsigned val
= *(unsigned *)data
;
192 printValueAsString(val
, nameValues
);
195 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB
:
197 printf("BLOB length %u : ", (unsigned)attrData
->Length
);
198 /* see if it happens to be a printable string */
199 if(isPrintable(attrData
)) {
201 safePrint(attrData
->Data
, attrData
->Length
);
209 case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
:
211 printf("multi_int[");
212 uint32 numInts
= attrData
->Length
/ sizeof(uint32
);
213 uint32
*uip
= (uint32
*)data
;
214 for(unsigned i
=0; i
<numInts
; i
++) {
218 printValueAsString(*uip
++, nameValues
);
223 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
:
225 safePrint(attrData
->Data
, attrData
->Length
);
230 printf("***UNKNOWN FORMAT (%u), Length %u",
231 (unsigned)attrInfo
->AttributeFormat
, (unsigned)attrData
->Length
);
236 /* free attribute(s) allocated by DL */
237 static void freeAttrs(
238 CSSM_DB_RECORD_ATTRIBUTE_DATA
*recordAttrs
)
242 for(i
=0; i
<recordAttrs
->NumberOfAttributes
; i
++) {
243 CSSM_DB_ATTRIBUTE_DATA_PTR attrData
= &recordAttrs
->AttributeData
[i
];
244 if(attrData
== NULL
) {
245 /* fault of caller, who allocated the CSSM_DB_ATTRIBUTE_DATA */
246 printf("***freeAttrs screwup: NULL attrData\n");
250 for(j
=0; j
<attrData
->NumberOfValues
; j
++) {
251 CSSM_DATA_PTR data
= &attrData
->Value
[j
];
253 /* fault of MDS, who said there was a value here */
254 printf("***freeAttrs screwup: NULL data\n");
257 CSSM_FREE(data
->Data
);
261 CSSM_FREE(attrData
->Value
);
262 attrData
->Value
= NULL
;
266 static void dumpDataBlob(
267 const CSSM_DATA
*datap
)
270 printf("Record data length %lu ", datap
->Length
);
271 if(datap
->Length
!= 0) {
278 static void dumpRecordAttrs(
279 const CSSM_DB_RECORD_ATTRIBUTE_DATA
*recordAttrs
,
280 const NameValuePair
**nameValues
, // parallel to recordAttrs
281 const CSSM_DATA
*recordData
= NULL
) // optional data
286 for(dex
=0; dex
<recordAttrs
->NumberOfAttributes
; dex
++) {
287 const CSSM_DB_ATTRIBUTE_DATA
*attrData
= &recordAttrs
->AttributeData
[dex
];
289 printName(&attrData
->Info
);
291 if(attrData
->NumberOfValues
== 0) {
292 printf("<<not present>>\n");
295 for(valNum
=0; valNum
<attrData
->NumberOfValues
; valNum
++) {
296 printAttrData(&attrData
->Info
, &attrData
->Value
[valNum
], nameValues
[dex
]);
297 if(valNum
< (attrData
->NumberOfValues
- 1)) {
304 dumpDataBlob(recordData
);
308 static void dumpRelation(
309 CSSM_DL_DB_HANDLE dlDbHand
,
310 const RelationInfo
*relInfo
,
314 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
316 CSSM_HANDLE resultHand
;
317 CSSM_DB_ATTRIBUTE_DATA
*attrs
;
318 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
321 uint32 numAttrs
= relInfo
->NumberOfAttributes
;
322 CSSM_DATA data
= {0, NULL
};
323 CSSM_DATA_PTR datap
= NULL
;
329 /* build an attr array from known schema */
330 attrs
= (CSSM_DB_ATTRIBUTE_DATA
*)CSSM_MALLOC(
331 sizeof(CSSM_DB_ATTRIBUTE_DATA
) * numAttrs
);
332 memset(attrs
, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA
) * numAttrs
);
333 for(attrDex
=0; attrDex
<numAttrs
; attrDex
++) {
334 attrs
[attrDex
].Info
= relInfo
->AttributeInfo
[attrDex
];
336 recordAttrs
.DataRecordType
= relInfo
->DataRecordType
;
337 recordAttrs
.NumberOfAttributes
= numAttrs
;
338 recordAttrs
.AttributeData
= attrs
;
340 /* just search by recordType, no predicates */
341 query
.RecordType
= relInfo
->DataRecordType
;
342 query
.Conjunctive
= CSSM_DB_NONE
;
343 query
.NumSelectionPredicates
= 0;
344 query
.SelectionPredicate
= NULL
;
345 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
346 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
347 query
.QueryFlags
= 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
349 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
358 case CSSMERR_DL_ENDOFDATA
:
359 printf("%s: no record found\n", relInfo
->relationName
);
363 printError("DataGetFirst", crtn
);
367 printf("%s:\n", relInfo
->relationName
);
368 printf(" record %d; numAttrs %d:\n",
369 recNum
++, (int)recordAttrs
.NumberOfAttributes
);
372 dumpRecordAttrs(&recordAttrs
, relInfo
->nameValues
, datap
);
373 CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
374 freeAttrs(&recordAttrs
);
376 CSSM_FREE(datap
->Data
);
379 /* now the rest of them */
380 /* hopefully we don't have to re-init the recordAttr array */
382 crtn
= CSSM_DL_DataGetNext(dlDbHand
,
389 printf(" record %d; numAttrs %d:\n",
390 recNum
++, (int)recordAttrs
.NumberOfAttributes
);
391 dumpRecordAttrs(&recordAttrs
, relInfo
->nameValues
, datap
);
392 CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
393 freeAttrs(&recordAttrs
);
395 CSSM_FREE(datap
->Data
);
397 break; // and go again
398 case CSSMERR_DL_ENDOFDATA
:
399 /* normal termination */
402 printError("DataGetNext", crtn
);
405 if(crtn
!= CSSM_OK
) {
414 * Given a record type and a CSSM_DB_UNIQUE_RECORD, fetch and parse all the
417 static void fetchParseRecord(
418 CSSM_DL_DB_HANDLE dlDbHand
,
419 CSSM_DB_RECORD_ATTRIBUTE_DATA
*inRecordAttrs
,
420 CSSM_DB_UNIQUE_RECORD_PTR record
,
421 const CSSM_DATA_PTR datap
,
424 const RelationInfo
*relInfo
= NULL
;
426 /* infer RelationInfo from recordType */
427 switch(inRecordAttrs
->DataRecordType
) {
428 case CSSM_DL_DB_RECORD_PUBLIC_KEY
:
429 case CSSM_DL_DB_RECORD_PRIVATE_KEY
:
430 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
:
431 relInfo
= &allKeysRelation
;
433 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
:
434 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
:
435 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
:
436 relInfo
= &genericKcRelation
;
438 case CSSM_DL_DB_RECORD_CERT
:
439 relInfo
= &certRecordRelation
;
441 case CSSM_DL_DB_RECORD_X509_CERTIFICATE
:
442 relInfo
= &x509CertRecordRelation
;
444 case CSSM_DL_DB_RECORD_X509_CRL
:
445 relInfo
= &x509CrlRecordRelation
;
447 case CSSM_DL_DB_RECORD_USER_TRUST
:
448 relInfo
= &userTrustRelation
;
450 case CSSM_DL_DB_RECORD_UNLOCK_REFERRAL
:
451 relInfo
= &referralRecordRelation
;
453 case CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
:
454 relInfo
= &extendedAttrRelation
;
456 case DBBlobRelationID
:
459 printf("--- No attributes ---\n");
466 printf("<<unparsed>>\n");
469 printf("Record blob (length %ld): ", datap
->Length
);
476 CSSM_DB_ATTRIBUTE_DATA
*attrs
= NULL
;
477 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
479 uint32 numAttrs
= relInfo
->NumberOfAttributes
;
481 CSSM_DATA recordData
= {0, NULL
};
482 CSSM_DATA_PTR recordDataP
= dumpData
? &recordData
: NULL
;
484 /* build an attr array from known schema */
485 attrs
= (CSSM_DB_ATTRIBUTE_DATA
*)CSSM_MALLOC(
486 sizeof(CSSM_DB_ATTRIBUTE_DATA
) * numAttrs
);
487 memset(attrs
, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA
) * numAttrs
);
488 for(attrDex
=0; attrDex
<numAttrs
; attrDex
++) {
489 attrs
[attrDex
].Info
= relInfo
->AttributeInfo
[attrDex
];
492 /* from inRecordAttrs, not the relInfo, which could be a typeless template */
493 recordAttrs
.DataRecordType
= relInfo
->DataRecordType
;
494 recordAttrs
.NumberOfAttributes
= numAttrs
;
495 recordAttrs
.AttributeData
= attrs
;
497 crtn
= CSSM_DL_DataGetFromUniqueRecordId(dlDbHand
,
502 printError("CSSM_DL_DataGetFromUniqueRecordId", crtn
);
505 dumpRecordAttrs(&recordAttrs
, relInfo
->nameValues
, recordDataP
);
506 freeAttrs(&recordAttrs
);
507 if(recordData
.Data
) {
508 CSSM_FREE(recordData
.Data
);
517 static void deleteRecord(
518 CSSM_DL_DB_HANDLE dlDbHand
,
519 CSSM_DB_UNIQUE_RECORD_PTR record
,
524 printf("\nDelete this record [y/anything] ? ");
525 char resp
= getchar();
531 crtn
= CSSM_DL_DataDelete(dlDbHand
, record
);
533 printError("CSSM_DL_DataDelete", crtn
);
536 printf("...record deleted\n\n");
541 * In this case we search for CSSM_DL_DB_RECORD_ANY. The current schema results
542 * in no single attribute which all interesting records have in common, so we
543 * can't grab any attributes at GetFirst/GetNext time. Instead we have
544 * to deal with the returned record per its record type.
546 static void dumpAllRecords(
547 CSSM_DL_DB_HANDLE dlDbHand
,
553 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
555 CSSM_HANDLE resultHand
;
556 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
557 CSSM_DATA data
= {0, NULL
};
558 CSSM_DATA_PTR datap
= NULL
;
564 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_ANY
;
565 recordAttrs
.NumberOfAttributes
= 0;
566 recordAttrs
.AttributeData
= NULL
;
568 /* just search by recordType, no predicates */
569 query
.RecordType
= CSSM_DL_DB_RECORD_ANY
;
570 query
.Conjunctive
= CSSM_DB_NONE
;
571 query
.NumSelectionPredicates
= 0;
572 query
.SelectionPredicate
= NULL
;
573 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
574 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
575 query
.QueryFlags
= 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
577 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
586 case CSSMERR_DL_ENDOFDATA
:
587 printf("CSSM_DL_DB_RECORD_ANY: no record found\n");
590 printError("DataGetFirst", crtn
);
594 /* could be anything; check it out */
597 printValueAsString(recordAttrs
.DataRecordType
, recordTypeNames
);
600 fetchParseRecord(dlDbHand
, &recordAttrs
, record
, datap
, dumpData
);
603 if(deleteAll
&& (recordAttrs
.DataRecordType
!= DBBlobRelationID
)) {
604 /* NEVER delete a DBBlob */
605 deleteRecord(dlDbHand
, record
, interact
);
607 CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
609 /* now the rest of them */
610 /* hopefully we don't have to re-init the recordAttr array */
612 crtn
= CSSM_DL_DataGetNext(dlDbHand
,
621 printValueAsString(recordAttrs
.DataRecordType
, recordTypeNames
);
624 fetchParseRecord(dlDbHand
, &recordAttrs
, record
, datap
, dumpData
);
627 if(deleteAll
&& (recordAttrs
.DataRecordType
!= DBBlobRelationID
)) {
628 /* NEVER delete a DBBlob */
629 deleteRecord(dlDbHand
, record
, interact
);
631 CSSM_DL_FreeUniqueRecord(dlDbHand
, record
);
632 break; // and go again
633 case CSSMERR_DL_ENDOFDATA
:
634 /* normal termination */
637 printError("DataGetNext", crtn
);
640 if(crtn
!= CSSM_OK
) {
654 CSSM_DL_DB_HANDLE dlDbHand
;
655 CSSM_BOOL verbose
= CSSM_FALSE
;
656 CSSM_BOOL quiet
= CSSM_FALSE
;
657 char *certFile
= NULL
;
658 char *keyFile
= NULL
;
659 CSSM_BOOL interact
= CSSM_TRUE
;
660 CSSM_BOOL dumpData
= CSSM_FALSE
;
662 /* should be cmd line opts */
663 CSSM_ALGORITHMS keyAlg
= CSSM_ALGID_RSA
;
664 CSSM_BOOL pemFormat
= CSSM_FALSE
;
665 CSSM_KEYBLOB_FORMAT keyFormat
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
666 CSSM_RETURN crtn
= CSSM_OK
;
671 dbFileName
= argv
[1];
674 for(arg
=3; arg
<argc
; arg
++) {
685 interact
= CSSM_FALSE
;
689 dumpData
= CSSM_TRUE
;
703 dlDbHand
.DLHandle
= dlStartup();
704 if(dlDbHand
.DLHandle
== 0) {
708 crtn
= importBadCert(dlDbHand
.DLHandle
, dbFileName
, certFile
,
709 keyFile
, keyAlg
, pemFormat
, keyFormat
, verbose
);
712 crtn
= dbCreateOpen(dlDbHand
.DLHandle
, dbFileName
,
713 CSSM_FALSE
, CSSM_FALSE
, NULL
, &dlDbHand
.DBHandle
);
719 dumpRelation(dlDbHand
, &schemaInfoRelation
, dumpData
);
722 dumpRelation(dlDbHand
, &allKeysRelation
, dumpData
);
725 dumpRelation(dlDbHand
, &x509CertRecordRelation
, dumpData
);
728 dumpAllRecords(dlDbHand
, CSSM_FALSE
, CSSM_TRUE
, dumpData
);
732 dumpAllRecords(dlDbHand
, CSSM_TRUE
, interact
, dumpData
);
734 /* we ignored errors.... */
736 printf("...DB %s wiped clean\n", dbFileName
);
743 CSSM_DL_DbClose(dlDbHand
);
745 CSSM_ModuleDetach(dlDbHand
.DLHandle
);