--- /dev/null
+/* 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;
+}