]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/dbTool/dbTool.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / dbTool / dbTool.cpp
diff --git a/SecurityTests/cspxutils/dbTool/dbTool.cpp b/SecurityTests/cspxutils/dbTool/dbTool.cpp
new file mode 100644 (file)
index 0000000..937d88e
--- /dev/null
@@ -0,0 +1,747 @@
+/* Copyright (c) 2002-2006 Apple Computer, Inc.
+ *
+ * dbTool.cpp - DL/DB tool.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <strings.h>
+#include <ctype.h>
+#include <Security/cssm.h>
+#include <Security/cssmapple.h>
+#include <Security/cssmapplePriv.h>
+#include "cspwrap.h"
+#include "common.h"
+#include "dbAttrs.h"
+#include "dbCert.h"
+#include "cspdlTesting.h"
+
+
+static void usage(char **argv)
+{
+       printf("usage: %s dbFileName command [options]\n", argv[0]);
+       printf("Commands:\n");
+       printf("   r   Dump Schema Relations\n");
+       printf("   k   Dump all keys\n");
+       printf("   c   Dump certs\n");
+       printf("   a   Dump all records\n");
+       printf("   d   Delete records (interactively)\n");
+       printf("   D   Delete records (noninteractively, requires really arg)\n");
+       printf("   i   Import bad cert and its (good) private key\n");
+       printf("Options:\n");
+       printf("   v   verbose\n");
+       printf("   q   quiet\n");
+       printf("   R   really! (for D command)\n");
+       printf("   d   dump data\n");
+       printf("   c=certFile\n");
+       printf("   k=keyFile\n");
+       exit(1);
+}
+
+
+static unsigned indentVal = 0;
+static void indentIncr()
+{
+       indentVal += 3;
+}
+
+static void indentDecr()
+{
+       if(indentVal) {
+               indentVal -= 3;
+       }
+}
+
+static void doIndent()
+{
+       unsigned i;
+       for(i=0; i<indentVal; i++) {
+               printf(" ");
+       }
+}
+
+#define NORM_KEY_LEN   20
+
+/* print an attribute name, padding out to NORM_KEY_LEN columns */
+static void printName(
+       const CSSM_DB_ATTRIBUTE_INFO *attrInfo)
+{
+       switch(attrInfo->AttributeNameFormat) {
+               case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
+               {
+                       char *attrName = attrInfo->Label.AttributeName;
+                       printf("%s", attrName);
+                       int len = strlen(attrName);
+                       if(len > NORM_KEY_LEN) {
+                               return;
+                       }
+                       int numSpaces = NORM_KEY_LEN - len;
+                       for(int i=0; i<numSpaces; i++) {
+                               putchar(' ');
+                       }
+                       break;
+               }
+               case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
+               {
+                       /* OSType, endian dependent... */
+                       char *cp = (char *)&(attrInfo->Label.AttributeID);
+                       for(unsigned i=0; i<4; i++) {
+                               putchar(*cp++);
+                       }
+                       printf("                ");
+                       break;
+               }
+               default:
+                       printf("Unknown attribute name format (%u)\n", 
+                               (unsigned)attrInfo->AttributeNameFormat);
+                       break;
+       }
+}
+
+/*
+ * Attempt to print a numeric value as a string, per a NameValuePair table.
+ * If the value is in fact a collection of legal values (per the nameValues
+ * array), the value will just be printed in hex.  
+ */
+static void printValueAsString(
+       unsigned val, 
+       const NameValuePair *nameValues)
+{
+       if(nameValues != NULL) {
+               while(nameValues->name != NULL) {
+                       if(nameValues->value == val) {
+                               printf("%s", nameValues->name);
+                               return;
+                       }
+                       nameValues++;
+               }
+       }
+       /* Oh well */
+       printf("0x%x", val);
+}
+
+static void safePrint(
+       uint8 *cp, 
+       uint32 len)
+{
+       for(unsigned i=0; i<len; i++) {
+               printf("%c", *cp++);
+       }
+}
+
+/* See if a blob is printable. Used for BLOB and UINT32 types, the latter of 
+ * which is sometimes used for OSType representation of attr name. */
+bool isPrintable(
+       const CSSM_DATA *dp)
+{
+       bool printable = true;
+       uint8 *cp = dp->Data;
+       for(unsigned i=0; i<dp->Length; i++) {
+               if(*cp == 0) {
+                       if(i != (dp->Length - 1)) {
+                               /* data contains NULL character before end */
+                               printable = false;
+                       }
+                       /* else end of string */
+                       break;
+               }
+               if(!isprint(*cp)) {
+                       printable = false;
+                       break;
+               }
+               cp++;
+       }
+       return printable;
+}
+
+#define MAX_BLOB_TO_PRINT      12
+static void printBlob(
+       const CSSM_DATA *data)
+{
+       unsigned toPrint = data->Length;
+       if(toPrint > MAX_BLOB_TO_PRINT) {
+               toPrint = MAX_BLOB_TO_PRINT;
+       }
+       for(unsigned i=0; i<toPrint; i++) {
+               unsigned dat = data->Data[i];
+               printf("%02X ", dat);
+       }
+       if(toPrint < data->Length) {
+               printf("...");
+       }
+}
+
+static void printAttrData(
+       const CSSM_DB_ATTRIBUTE_INFO *attrInfo,
+       const CSSM_DATA *attrData,
+       const NameValuePair *nameValues)                // optional
+{
+       void *data = attrData->Data;
+       
+       switch(attrInfo->AttributeFormat) {
+       
+               case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
+                       putchar('\'');
+                       safePrint(attrData->Data, attrData->Length);
+                       putchar('\'');
+                       break;
+               case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
+               case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
+               {
+                       unsigned val = *(unsigned *)data;
+                       printValueAsString(val, nameValues);
+                       break;
+               }
+               case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
+               {
+                       printf("BLOB length %u : ", (unsigned)attrData->Length);
+                       /* see if it happens to be a printable string */
+                       if(isPrintable(attrData)) {
+                               putchar('\'');
+                               safePrint(attrData->Data, attrData->Length);
+                               putchar('\'');
+                       }
+                       else {
+                               printBlob(attrData);
+                       }
+                       break;
+               }
+               case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
+               {
+                       printf("multi_int[");
+                       uint32 numInts = attrData->Length / sizeof(uint32);
+                       uint32 *uip = (uint32 *)data;
+                       for(unsigned i=0; i<numInts; i++) {
+                               if(i > 0) {
+                                       printf(", ");
+                               }
+                               printValueAsString(*uip++, nameValues);
+                       }
+                       printf("]");
+                       break;
+               }
+               case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
+                       putchar('\'');
+                       safePrint(attrData->Data, attrData->Length);
+                       putchar('\'');
+                       break;
+                       
+               default:
+                       printf("***UNKNOWN FORMAT (%u), Length %u",
+                               (unsigned)attrInfo->AttributeFormat, (unsigned)attrData->Length);
+                       break;
+       }
+}
+
+/* free attribute(s) allocated by DL */
+static void freeAttrs(
+       CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs)
+{
+       unsigned i;
+       
+       for(i=0; i<recordAttrs->NumberOfAttributes; i++) {
+               CSSM_DB_ATTRIBUTE_DATA_PTR attrData = &recordAttrs->AttributeData[i];
+               if(attrData == NULL) {
+                       /* fault of caller, who allocated the CSSM_DB_ATTRIBUTE_DATA */
+                       printf("***freeAttrs screwup: NULL attrData\n");
+                       return;
+               }
+               unsigned j;
+               for(j=0; j<attrData->NumberOfValues; j++) {
+                       CSSM_DATA_PTR data = &attrData->Value[j];
+                       if(data == NULL) {
+                               /* fault of MDS, who said there was a value here */
+                               printf("***freeAttrs screwup: NULL data\n");
+                               return;
+                       }
+                       CSSM_FREE(data->Data);
+                       data->Data = NULL;
+                       data->Length = 0;
+               }
+               CSSM_FREE(attrData->Value);
+               attrData->Value = NULL;
+       }
+}
+
+static void dumpDataBlob(
+       const CSSM_DATA *datap)
+{
+       doIndent();
+       printf("Record data length %lu ", datap->Length);
+       if(datap->Length != 0) {
+               printf(" : ");
+               printBlob(datap);
+       }
+       printf("\n");
+}
+
+static void dumpRecordAttrs(
+       const CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs,
+       const NameValuePair                             **nameValues,           // parallel to recordAttrs
+       const CSSM_DATA                                         *recordData = NULL)     // optional data
+{
+       unsigned valNum;
+       unsigned dex;
+
+       for(dex=0; dex<recordAttrs->NumberOfAttributes; dex++) {
+               const CSSM_DB_ATTRIBUTE_DATA *attrData = &recordAttrs->AttributeData[dex];
+               doIndent();
+               printName(&attrData->Info);
+               printf(": ");
+               if(attrData->NumberOfValues == 0) {
+                       printf("<<not present>>\n");
+                       continue;
+               }
+               for(valNum=0; valNum<attrData->NumberOfValues; valNum++) {
+                       printAttrData(&attrData->Info, &attrData->Value[valNum], nameValues[dex]);
+                       if(valNum < (attrData->NumberOfValues - 1)) {
+                               printf(", ");
+                       }
+               }
+               printf("\n");
+       }
+       if(recordData) {
+               dumpDataBlob(recordData);
+       }
+}
+
+static void dumpRelation(
+       CSSM_DL_DB_HANDLE               dlDbHand, 
+       const RelationInfo              *relInfo,
+       CSSM_BOOL                               dumpData)
+{
+       CSSM_QUERY                                              query;
+       CSSM_DB_UNIQUE_RECORD_PTR               record = NULL;
+       CSSM_RETURN                                             crtn;
+       CSSM_HANDLE                                             resultHand;
+       CSSM_DB_ATTRIBUTE_DATA                  *attrs;
+       CSSM_DB_RECORD_ATTRIBUTE_DATA   recordAttrs;
+       unsigned                                                attrDex;
+       unsigned                                                recNum = 0;
+       uint32                                                  numAttrs = relInfo->NumberOfAttributes;
+       CSSM_DATA                                               data = {0, NULL};
+       CSSM_DATA_PTR                                   datap = NULL;
+       
+       if(dumpData) {
+               datap = &data;
+       }
+       
+       /* build an attr array from known schema */
+       attrs = (CSSM_DB_ATTRIBUTE_DATA *)CSSM_MALLOC(
+               sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
+       memset(attrs, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
+       for(attrDex=0; attrDex<numAttrs; attrDex++) {
+               attrs[attrDex].Info = relInfo->AttributeInfo[attrDex];
+       }
+       recordAttrs.DataRecordType = relInfo->DataRecordType;
+       recordAttrs.NumberOfAttributes = numAttrs;
+       recordAttrs.AttributeData = attrs;
+       
+       /* just search by recordType, no predicates */
+       query.RecordType = relInfo->DataRecordType;
+       query.Conjunctive = CSSM_DB_NONE;
+       query.NumSelectionPredicates = 0;
+       query.SelectionPredicate = NULL;
+       query.QueryLimits.TimeLimit = 0;                        // FIXME - meaningful?
+       query.QueryLimits.SizeLimit = 1;                        // FIXME - meaningful?
+       query.QueryFlags = 0;           // CSSM_QUERY_RETURN_DATA...FIXME - used?
+
+       crtn = CSSM_DL_DataGetFirst(dlDbHand,
+               &query,
+               &resultHand,
+               &recordAttrs,
+               datap,
+               &record);
+       switch(crtn) {
+               case CSSM_OK:
+                       break;          // proceed
+               case CSSMERR_DL_ENDOFDATA:
+                       printf("%s: no record found\n", relInfo->relationName);
+                       CSSM_FREE(attrs);
+                       return;
+               default:
+                       printError("DataGetFirst", crtn);
+                       CSSM_FREE(attrs);
+                       return;
+       }
+       printf("%s:\n", relInfo->relationName);
+       printf("   record %d; numAttrs %d:\n", 
+               recNum++, (int)recordAttrs.NumberOfAttributes);
+       indentIncr();
+       
+       dumpRecordAttrs(&recordAttrs, relInfo->nameValues, datap);
+       CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+       freeAttrs(&recordAttrs);
+       if(datap) {
+               CSSM_FREE(datap->Data);
+       }
+       
+       /* now the rest of them */
+       /* hopefully we don't have to re-init the recordAttr array */
+       for(;;) {
+               crtn = CSSM_DL_DataGetNext(dlDbHand,
+                       resultHand, 
+                       &recordAttrs,
+                       datap,
+                       &record);
+               switch(crtn) {
+                       case CSSM_OK:
+                               printf("   record %d; numAttrs %d:\n", 
+                                       recNum++, (int)recordAttrs.NumberOfAttributes);
+                               dumpRecordAttrs(&recordAttrs, relInfo->nameValues, datap);
+                               CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+                               freeAttrs(&recordAttrs);
+                               if(datap) {
+                                       CSSM_FREE(datap->Data);
+                               }
+                               break;          // and go again 
+                       case CSSMERR_DL_ENDOFDATA:
+                               /* normal termination */
+                               break;
+                       default:
+                               printError("DataGetNext", crtn);
+                               break;
+               }
+               if(crtn != CSSM_OK) {
+                       break;
+               }
+       }
+       indentDecr();
+       CSSM_FREE(attrs);
+}
+
+/*
+ * Given a record type and a CSSM_DB_UNIQUE_RECORD, fetch and parse all the 
+ * attributes we can.
+ */
+static void fetchParseRecord(
+       CSSM_DL_DB_HANDLE                               dlDbHand,
+       CSSM_DB_RECORD_ATTRIBUTE_DATA   *inRecordAttrs,
+       CSSM_DB_UNIQUE_RECORD_PTR               record,
+       const CSSM_DATA_PTR                             datap,
+       CSSM_BOOL                                               dumpData)
+{
+       const RelationInfo *relInfo = NULL;
+       
+       /* infer RelationInfo from recordType */
+       switch(inRecordAttrs->DataRecordType) {
+               case CSSM_DL_DB_RECORD_PUBLIC_KEY:
+               case CSSM_DL_DB_RECORD_PRIVATE_KEY:
+               case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
+                       relInfo = &allKeysRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
+               case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
+               case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
+                       relInfo = &genericKcRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_CERT:
+                       relInfo = &certRecordRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_X509_CERTIFICATE:
+                       relInfo = &x509CertRecordRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_X509_CRL:
+                       relInfo = &x509CrlRecordRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_USER_TRUST:
+                       relInfo = &userTrustRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_UNLOCK_REFERRAL:
+                       relInfo = &referralRecordRelation;
+                       break;
+               case CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE:
+                       relInfo = &extendedAttrRelation;
+                       break;
+               case DBBlobRelationID:
+                       relInfo = NULL;
+                       doIndent();
+                       printf("--- No attributes ---\n");
+                       if(dumpData) {
+                               dumpDataBlob(datap);
+                       }
+                       return;
+               default:
+                       doIndent();
+                       printf("<<unparsed>>\n");
+                       if(dumpData) {
+                               doIndent();
+                               printf("Record blob (length %ld): ", datap->Length);
+                               printBlob(datap);
+                               printf("\n");
+                       }
+                       return;
+       }
+       
+       CSSM_DB_ATTRIBUTE_DATA                  *attrs = NULL;
+       CSSM_DB_RECORD_ATTRIBUTE_DATA   recordAttrs;
+       unsigned                                                attrDex;
+       uint32                                                  numAttrs = relInfo->NumberOfAttributes;
+       CSSM_RETURN                                             crtn;
+       CSSM_DATA                                               recordData = {0, NULL};
+       CSSM_DATA_PTR                                   recordDataP = dumpData ? &recordData : NULL;
+       
+       /* build an attr array from known schema */
+       attrs = (CSSM_DB_ATTRIBUTE_DATA *)CSSM_MALLOC(
+               sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
+       memset(attrs, 0, sizeof(CSSM_DB_ATTRIBUTE_DATA) * numAttrs);
+       for(attrDex=0; attrDex<numAttrs; attrDex++) {
+               attrs[attrDex].Info = relInfo->AttributeInfo[attrDex];
+       }
+
+       /* from inRecordAttrs, not the relInfo, which could be a typeless template */
+       recordAttrs.DataRecordType = relInfo->DataRecordType;
+       recordAttrs.NumberOfAttributes = numAttrs;
+       recordAttrs.AttributeData = attrs;
+
+       crtn =  CSSM_DL_DataGetFromUniqueRecordId(dlDbHand,
+               record,
+               &recordAttrs,
+               recordDataP);
+       if(crtn) {
+               printError("CSSM_DL_DataGetFromUniqueRecordId", crtn);
+               goto abort;
+       }
+       dumpRecordAttrs(&recordAttrs, relInfo->nameValues, recordDataP);
+       freeAttrs(&recordAttrs);
+       if(recordData.Data) {
+               CSSM_FREE(recordData.Data);
+       }
+abort:
+       if(attrs) {
+               CSSM_FREE(attrs);
+       }
+       return;
+}
+       
+static void deleteRecord(
+       CSSM_DL_DB_HANDLE                       dlDbHand,
+       CSSM_DB_UNIQUE_RECORD_PTR       record,
+       CSSM_BOOL                                       interact)
+{
+       if(interact) {
+               fpurge(stdin);
+               printf("\nDelete this record [y/anything] ? ");
+               char resp = getchar();
+               if(resp != 'y') {
+                       return;
+               }
+       }
+       CSSM_RETURN crtn;
+       crtn = CSSM_DL_DataDelete(dlDbHand, record);
+       if(crtn) {
+               printError("CSSM_DL_DataDelete", crtn);
+       }
+       else if(interact) {
+               printf("...record deleted\n\n");
+       }
+}
+
+/*
+ * In this case we search for CSSM_DL_DB_RECORD_ANY. The current schema results
+ * in no single attribute which all interesting records have in common, so we
+ * can't grab any attributes at GetFirst/GetNext time. Instead we have
+ * to deal with the returned record per its record type. 
+ */
+static void dumpAllRecords(
+       CSSM_DL_DB_HANDLE               dlDbHand,
+       CSSM_BOOL                               deleteAll,
+       CSSM_BOOL                               interact,
+       CSSM_BOOL                               dumpData)
+{
+       CSSM_QUERY                                              query;
+       CSSM_DB_UNIQUE_RECORD_PTR               record = NULL;
+       CSSM_RETURN                                             crtn;
+       CSSM_HANDLE                                             resultHand;
+       CSSM_DB_RECORD_ATTRIBUTE_DATA   recordAttrs;
+       CSSM_DATA                                               data = {0, NULL};
+       CSSM_DATA_PTR                                   datap = NULL;
+       
+       if(dumpData) {
+               datap = &data;
+       }
+       
+       recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_ANY;
+       recordAttrs.NumberOfAttributes = 0;
+       recordAttrs.AttributeData = NULL;
+       
+       /* just search by recordType, no predicates */
+       query.RecordType = CSSM_DL_DB_RECORD_ANY;
+       query.Conjunctive = CSSM_DB_NONE;
+       query.NumSelectionPredicates = 0;
+       query.SelectionPredicate = NULL;
+       query.QueryLimits.TimeLimit = 0;                        // FIXME - meaningful?
+       query.QueryLimits.SizeLimit = 1;                        // FIXME - meaningful?
+       query.QueryFlags = 0;           // CSSM_QUERY_RETURN_DATA...FIXME - used?
+
+       crtn = CSSM_DL_DataGetFirst(dlDbHand,
+               &query,
+               &resultHand,
+               &recordAttrs,
+               datap,  
+               &record);
+       switch(crtn) {
+               case CSSM_OK:
+                       break;          // proceed
+               case CSSMERR_DL_ENDOFDATA:
+                       printf("CSSM_DL_DB_RECORD_ANY: no record found\n");
+                       return;
+               default:
+                       printError("DataGetFirst", crtn);
+                       return;
+       }
+
+       /* could be anything; check it out */
+       if(interact) {
+               doIndent();
+               printValueAsString(recordAttrs.DataRecordType, recordTypeNames);
+               printf("\n");
+               indentIncr();
+               fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData);
+               indentDecr();
+       }
+       if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) {
+               /* NEVER delete a DBBlob */
+               deleteRecord(dlDbHand, record, interact);
+       }
+       CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+       
+       /* now the rest of them */
+       /* hopefully we don't have to re-init the recordAttr array */
+       for(;;) {
+               crtn = CSSM_DL_DataGetNext(dlDbHand,
+                       resultHand, 
+                       &recordAttrs,
+                       datap,
+                       &record);
+               switch(crtn) {
+                       case CSSM_OK:
+                               if(interact) {
+                                       doIndent();
+                                       printValueAsString(recordAttrs.DataRecordType, recordTypeNames);
+                                       printf("\n");
+                                       indentIncr();
+                                       fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData);
+                                       indentDecr();
+                               }
+                               if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) {
+                                       /* NEVER delete a DBBlob */
+                                       deleteRecord(dlDbHand, record, interact);
+                               }
+                               CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+                               break;          // and go again 
+                       case CSSMERR_DL_ENDOFDATA:
+                               /* normal termination */
+                               break;
+                       default:
+                               printError("DataGetNext", crtn);
+                               break;
+               }
+               if(crtn != CSSM_OK) {
+                       break;
+               }
+       }
+}
+
+int main(
+       int argc, 
+       char **argv)
+{
+       int                                     arg;
+       char                            *argp;
+       char                            *dbFileName;
+       char                            cmd;
+       CSSM_DL_DB_HANDLE       dlDbHand;
+       CSSM_BOOL                       verbose = CSSM_FALSE;
+       CSSM_BOOL                       quiet = CSSM_FALSE;
+       char                            *certFile = NULL;
+       char                            *keyFile = NULL;
+       CSSM_BOOL                       interact = CSSM_TRUE;
+       CSSM_BOOL                       dumpData = CSSM_FALSE;
+       
+       /* should be cmd line opts */
+       CSSM_ALGORITHMS         keyAlg = CSSM_ALGID_RSA;
+       CSSM_BOOL                       pemFormat = CSSM_FALSE;
+       CSSM_KEYBLOB_FORMAT     keyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
+       CSSM_RETURN             crtn = CSSM_OK;
+       
+       if(argc < 3) {
+               usage(argv);
+       }
+       dbFileName = argv[1];
+       cmd = argv[2][0];
+       
+       for(arg=3; arg<argc; arg++) {
+               argp = argv[arg];
+               switch(argp[0]) {
+                       case 'v':
+                               verbose = CSSM_TRUE;
+                               break;
+                       case 'q':
+                               quiet = CSSM_TRUE;
+                               break;
+                       case 'R':
+                               if(cmd == 'D') {
+                                       interact = CSSM_FALSE;
+                               }
+                               break;
+                       case 'd':
+                               dumpData = CSSM_TRUE;
+                               break;
+                       case 'c':
+                               certFile = &argp[2];
+                               break;
+                       case 'k':
+                               keyFile = &argp[2];
+                               break;
+                   case 'h':
+                   default:
+                               usage(argv);
+               }
+       }
+       
+       dlDbHand.DLHandle = dlStartup();
+       if(dlDbHand.DLHandle == 0) {
+               exit(1);
+       }
+       if(cmd == 'i') {
+               crtn = importBadCert(dlDbHand.DLHandle, dbFileName, certFile, 
+                       keyFile, keyAlg, pemFormat, keyFormat, verbose);
+               goto done;
+       }
+       crtn = dbCreateOpen(dlDbHand.DLHandle, dbFileName, 
+               CSSM_FALSE, CSSM_FALSE, NULL, &dlDbHand.DBHandle);
+       if(crtn) {
+               exit(1);
+       }
+       switch(cmd) {
+               case 'r':
+                       dumpRelation(dlDbHand, &schemaInfoRelation, dumpData);
+                       break;
+               case 'k':
+                       dumpRelation(dlDbHand, &allKeysRelation, dumpData);
+                       break;
+               case 'c':
+                       dumpRelation(dlDbHand, &x509CertRecordRelation, dumpData);
+                       break;
+               case 'a':
+                       dumpAllRecords(dlDbHand, CSSM_FALSE, CSSM_TRUE, dumpData);
+                       break;
+               case 'd':
+               case 'D':
+                       dumpAllRecords(dlDbHand, CSSM_TRUE, interact, dumpData);
+                       if(!interact) {
+                               /* we ignored errors.... */
+                               if(!quiet) {
+                                       printf("...DB %s wiped clean\n", dbFileName);
+                               }
+                       }
+                       break;
+               default:
+                       usage(argv);
+       }
+       CSSM_DL_DbClose(dlDbHand);
+done:
+       CSSM_ModuleDetach(dlDbHand.DLHandle);
+       return crtn;
+}