1/* Copyright (c) 2002-2006 Apple Computer, Inc. 2 * 3 * dbTool.cpp - DL/DB tool. 4 */ 5#include <stdlib.h> 6#include <stdio.h> 7#include <time.h> 8#include <strings.h> 9#include <ctype.h> 10#include <Security/cssm.h> 11#include <Security/cssmapple.h> 12#include <Security/cssmapplePriv.h> 13#include "cspwrap.h" 14#include "common.h" 15#include "dbAttrs.h" 16#include "dbCert.h" 17#include "cspdlTesting.h" 18 19 20static void usage(char **argv) 21{ 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"); 31 printf("Options:\n"); 32 printf(" v verbose\n"); 33 printf(" q quiet\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"); 38 exit(1); 39} 40 41 42static unsigned indentVal = 0; 43static void indentIncr() 44{ 45 indentVal += 3; 46} 47 48static void indentDecr() 49{ 50 if(indentVal) { 51 indentVal -= 3; 52 } 53} 54 55static void doIndent() 56{ 57 unsigned i; 58 for(i=0; i<indentVal; i++) { 59 printf(" "); 60 } 61} 62 63#define NORM_KEY_LEN 20 64 65/* print an attribute name, padding out to NORM_KEY_LEN columns */ 66static void printName( 67 const CSSM_DB_ATTRIBUTE_INFO *attrInfo) 68{ 69 switch(attrInfo->AttributeNameFormat) { 70 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: 71 { 72 char *attrName = attrInfo->Label.AttributeName; 73 printf("%s", attrName); 74 int len = strlen(attrName); 75 if(len > NORM_KEY_LEN) { 76 return; 77 } 78 int numSpaces = NORM_KEY_LEN - len; 79 for(int i=0; i<numSpaces; i++) { 80 putchar(' '); 81 } 82 break; 83 } 84 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: 85 { 86 /* OSType, endian dependent... */ 87 char *cp = (char *)&(attrInfo->Label.AttributeID); 88 for(unsigned i=0; i<4; i++) { 89 putchar(*cp++); 90 } 91 printf(" "); 92 break; 93 } 94 default: 95 printf("Unknown attribute name format (%u)\n", 96 (unsigned)attrInfo->AttributeNameFormat); 97 break; 98 } 99} 100 101/* 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. 105 */ 106static void printValueAsString( 107 unsigned val, 108 const NameValuePair *nameValues) 109{ 110 if(nameValues != NULL) { 111 while(nameValues->name != NULL) { 112 if(nameValues->value == val) { 113 printf("%s", nameValues->name); 114 return; 115 } 116 nameValues++; 117 } 118 } 119 /* Oh well */ 120 printf("0x%x", val); 121} 122 123static void safePrint( 124 uint8 *cp, 125 uint32 len) 126{ 127 for(unsigned i=0; i<len; i++) { 128 printf("%c", *cp++); 129 } 130} 131 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. */ 134bool isPrintable( 135 const CSSM_DATA *dp) 136{ 137 bool printable = true; 138 uint8 *cp = dp->Data; 139 for(unsigned i=0; i<dp->Length; i++) { 140 if(*cp == 0) { 141 if(i != (dp->Length - 1)) { 142 /* data contains NULL character before end */ 143 printable = false; 144 } 145 /* else end of string */ 146 break; 147 } 148 if(!isprint(*cp)) { 149 printable = false; 150 break; 151 } 152 cp++; 153 } 154 return printable; 155} 156 157#define MAX_BLOB_TO_PRINT 12 158static void printBlob( 159 const CSSM_DATA *data) 160{ 161 unsigned toPrint = data->Length; 162 if(toPrint > MAX_BLOB_TO_PRINT) { 163 toPrint = MAX_BLOB_TO_PRINT; 164 } 165 for(unsigned i=0; i<toPrint; i++) { 166 unsigned dat = data->Data[i]; 167 printf("%02X ", dat); 168 } 169 if(toPrint < data->Length) { 170 printf("..."); 171 } 172} 173 174static void printAttrData( 175 const CSSM_DB_ATTRIBUTE_INFO *attrInfo, 176 const CSSM_DATA *attrData, 177 const NameValuePair *nameValues) // optional 178{ 179 void *data = attrData->Data; 180 181 switch(attrInfo->AttributeFormat) { 182 183 case CSSM_DB_ATTRIBUTE_FORMAT_STRING: 184 putchar('\''); 185 safePrint(attrData->Data, attrData->Length); 186 putchar('\''); 187 break; 188 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: 189 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: 190 { 191 unsigned val = *(unsigned *)data; 192 printValueAsString(val, nameValues); 193 break; 194 } 195 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: 196 { 197 printf("BLOB length %u : ", (unsigned)attrData->Length); 198 /* see if it happens to be a printable string */ 199 if(isPrintable(attrData)) { 200 putchar('\''); 201 safePrint(attrData->Data, attrData->Length); 202 putchar('\''); 203 } 204 else { 205 printBlob(attrData); 206 } 207 break; 208 } 209 case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32: 210 { 211 printf("multi_int["); 212 uint32 numInts = attrData->Length / sizeof(uint32); 213 uint32 *uip = (uint32 *)data; 214 for(unsigned i=0; i<numInts; i++) { 215 if(i > 0) { 216 printf(", "); 217 } 218 printValueAsString(*uip++, nameValues); 219 } 220 printf("]"); 221 break; 222 } 223 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE: 224 putchar('\''); 225 safePrint(attrData->Data, attrData->Length); 226 putchar('\''); 227 break; 228 229 default: 230 printf("***UNKNOWN FORMAT (%u), Length %u", 231 (unsigned)attrInfo->AttributeFormat, (unsigned)attrData->Length); 232 break; 233 } 234} 235 236/* free attribute(s) allocated by DL */ 237static void freeAttrs( 238 CSSM_DB_RECORD_ATTRIBUTE_DATA *recordAttrs) 239{ 240 unsigned i; 241 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"); 247 return; 248 } 249 unsigned j; 250 for(j=0; j<attrData->NumberOfValues; j++) { 251 CSSM_DATA_PTR data = &attrData->Value[j]; 252 if(data == NULL) { 253 /* fault of MDS, who said there was a value here */ 254 printf("***freeAttrs screwup: NULL data\n"); 255 return; 256 } 257 CSSM_FREE(data->Data); 258 data->Data = NULL; 259 data->Length = 0; 260 } 261 CSSM_FREE(attrData->Value); 262 attrData->Value = NULL; 263 } 264} 265 266static void dumpDataBlob( 267 const CSSM_DATA *datap) 268{ 269 doIndent(); 270 printf("Record data length %lu ", datap->Length); 271 if(datap->Length != 0) { 272 printf(" : "); 273 printBlob(datap); 274 } 275 printf("\n"); 276} 277 278static 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 282{ 283 unsigned valNum; 284 unsigned dex; 285 286 for(dex=0; dex<recordAttrs->NumberOfAttributes; dex++) { 287 const CSSM_DB_ATTRIBUTE_DATA *attrData = &recordAttrs->AttributeData[dex]; 288 doIndent(); 289 printName(&attrData->Info); 290 printf(": "); 291 if(attrData->NumberOfValues == 0) { 292 printf("<<not present>>\n"); 293 continue; 294 } 295 for(valNum=0; valNum<attrData->NumberOfValues; valNum++) { 296 printAttrData(&attrData->Info, &attrData->Value[valNum], nameValues[dex]); 297 if(valNum < (attrData->NumberOfValues - 1)) { 298 printf(", "); 299 } 300 } 301 printf("\n"); 302 } 303 if(recordData) { 304 dumpDataBlob(recordData); 305 } 306} 307 308static void dumpRelation( 309 CSSM_DL_DB_HANDLE dlDbHand, 310 const RelationInfo *relInfo, 311 CSSM_BOOL dumpData) 312{ 313 CSSM_QUERY query; 314 CSSM_DB_UNIQUE_RECORD_PTR record = NULL; 315 CSSM_RETURN crtn; 316 CSSM_HANDLE resultHand; 317 CSSM_DB_ATTRIBUTE_DATA *attrs; 318 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; 319 unsigned attrDex; 320 unsigned recNum = 0; 321 uint32 numAttrs = relInfo->NumberOfAttributes; 322 CSSM_DATA data = {0, NULL}; 323 CSSM_DATA_PTR datap = NULL; 324 325 if(dumpData) { 326 datap = &data; 327 } 328 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]; 335 } 336 recordAttrs.DataRecordType = relInfo->DataRecordType; 337 recordAttrs.NumberOfAttributes = numAttrs; 338 recordAttrs.AttributeData = attrs; 339 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? 348 349 crtn = CSSM_DL_DataGetFirst(dlDbHand, 350 &query, 351 &resultHand, 352 &recordAttrs, 353 datap, 354 &record); 355 switch(crtn) { 356 case CSSM_OK: 357 break; // proceed 358 case CSSMERR_DL_ENDOFDATA: 359 printf("%s: no record found\n", relInfo->relationName); 360 CSSM_FREE(attrs); 361 return; 362 default: 363 printError("DataGetFirst", crtn); 364 CSSM_FREE(attrs); 365 return; 366 } 367 printf("%s:\n", relInfo->relationName); 368 printf(" record %d; numAttrs %d:\n", 369 recNum++, (int)recordAttrs.NumberOfAttributes); 370 indentIncr(); 371 372 dumpRecordAttrs(&recordAttrs, relInfo->nameValues, datap); 373 CSSM_DL_FreeUniqueRecord(dlDbHand, record); 374 freeAttrs(&recordAttrs); 375 if(datap) { 376 CSSM_FREE(datap->Data); 377 } 378 379 /* now the rest of them */ 380 /* hopefully we don't have to re-init the recordAttr array */ 381 for(;;) { 382 crtn = CSSM_DL_DataGetNext(dlDbHand, 383 resultHand, 384 &recordAttrs, 385 datap, 386 &record); 387 switch(crtn) { 388 case CSSM_OK: 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); 394 if(datap) { 395 CSSM_FREE(datap->Data); 396 } 397 break; // and go again 398 case CSSMERR_DL_ENDOFDATA: 399 /* normal termination */ 400 break; 401 default: 402 printError("DataGetNext", crtn); 403 break; 404 } 405 if(crtn != CSSM_OK) { 406 break; 407 } 408 } 409 indentDecr(); 410 CSSM_FREE(attrs); 411} 412 413/* 414 * Given a record type and a CSSM_DB_UNIQUE_RECORD, fetch and parse all the 415 * attributes we can. 416 */ 417static 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, 422 CSSM_BOOL dumpData) 423{ 424 const RelationInfo *relInfo = NULL; 425 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; 432 break; 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; 437 break; 438 case CSSM_DL_DB_RECORD_CERT: 439 relInfo = &certRecordRelation; 440 break; 441 case CSSM_DL_DB_RECORD_X509_CERTIFICATE: 442 relInfo = &x509CertRecordRelation; 443 break; 444 case CSSM_DL_DB_RECORD_X509_CRL: 445 relInfo = &x509CrlRecordRelation; 446 break; 447 case CSSM_DL_DB_RECORD_USER_TRUST: 448 relInfo = &userTrustRelation; 449 break; 450 case CSSM_DL_DB_RECORD_UNLOCK_REFERRAL: 451 relInfo = &referralRecordRelation; 452 break; 453 case CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE: 454 relInfo = &extendedAttrRelation; 455 break; 456 case DBBlobRelationID: 457 relInfo = NULL; 458 doIndent(); 459 printf("--- No attributes ---\n"); 460 if(dumpData) { 461 dumpDataBlob(datap); 462 } 463 return; 464 default: 465 doIndent(); 466 printf("<<unparsed>>\n"); 467 if(dumpData) { 468 doIndent(); 469 printf("Record blob (length %ld): ", datap->Length); 470 printBlob(datap); 471 printf("\n"); 472 } 473 return; 474 } 475 476 CSSM_DB_ATTRIBUTE_DATA *attrs = NULL; 477 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; 478 unsigned attrDex; 479 uint32 numAttrs = relInfo->NumberOfAttributes; 480 CSSM_RETURN crtn; 481 CSSM_DATA recordData = {0, NULL}; 482 CSSM_DATA_PTR recordDataP = dumpData ? &recordData : NULL; 483 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]; 490 } 491 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; 496 497 crtn = CSSM_DL_DataGetFromUniqueRecordId(dlDbHand, 498 record, 499 &recordAttrs, 500 recordDataP); 501 if(crtn) { 502 printError("CSSM_DL_DataGetFromUniqueRecordId", crtn); 503 goto abort; 504 } 505 dumpRecordAttrs(&recordAttrs, relInfo->nameValues, recordDataP); 506 freeAttrs(&recordAttrs); 507 if(recordData.Data) { 508 CSSM_FREE(recordData.Data); 509 } 510abort: 511 if(attrs) { 512 CSSM_FREE(attrs); 513 } 514 return; 515} 516 517static void deleteRecord( 518 CSSM_DL_DB_HANDLE dlDbHand, 519 CSSM_DB_UNIQUE_RECORD_PTR record, 520 CSSM_BOOL interact) 521{ 522 if(interact) { 523 fpurge(stdin); 524 printf("\nDelete this record [y/anything] ? "); 525 char resp = getchar(); 526 if(resp != 'y') { 527 return; 528 } 529 } 530 CSSM_RETURN crtn; 531 crtn = CSSM_DL_DataDelete(dlDbHand, record); 532 if(crtn) { 533 printError("CSSM_DL_DataDelete", crtn); 534 } 535 else if(interact) { 536 printf("...record deleted\n\n"); 537 } 538} 539 540/* 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. 545 */ 546static void dumpAllRecords( 547 CSSM_DL_DB_HANDLE dlDbHand, 548 CSSM_BOOL deleteAll, 549 CSSM_BOOL interact, 550 CSSM_BOOL dumpData) 551{ 552 CSSM_QUERY query; 553 CSSM_DB_UNIQUE_RECORD_PTR record = NULL; 554 CSSM_RETURN crtn; 555 CSSM_HANDLE resultHand; 556 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; 557 CSSM_DATA data = {0, NULL}; 558 CSSM_DATA_PTR datap = NULL; 559 560 if(dumpData) { 561 datap = &data; 562 } 563 564 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_ANY; 565 recordAttrs.NumberOfAttributes = 0; 566 recordAttrs.AttributeData = NULL; 567 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? 576 577 crtn = CSSM_DL_DataGetFirst(dlDbHand, 578 &query, 579 &resultHand, 580 &recordAttrs, 581 datap, 582 &record); 583 switch(crtn) { 584 case CSSM_OK: 585 break; // proceed 586 case CSSMERR_DL_ENDOFDATA: 587 printf("CSSM_DL_DB_RECORD_ANY: no record found\n"); 588 return; 589 default: 590 printError("DataGetFirst", crtn); 591 return; 592 } 593 594 /* could be anything; check it out */ 595 if(interact) { 596 doIndent(); 597 printValueAsString(recordAttrs.DataRecordType, recordTypeNames); 598 printf("\n"); 599 indentIncr(); 600 fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData); 601 indentDecr(); 602 } 603 if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) { 604 /* NEVER delete a DBBlob */ 605 deleteRecord(dlDbHand, record, interact); 606 } 607 CSSM_DL_FreeUniqueRecord(dlDbHand, record); 608 609 /* now the rest of them */ 610 /* hopefully we don't have to re-init the recordAttr array */ 611 for(;;) { 612 crtn = CSSM_DL_DataGetNext(dlDbHand, 613 resultHand, 614 &recordAttrs, 615 datap, 616 &record); 617 switch(crtn) { 618 case CSSM_OK: 619 if(interact) { 620 doIndent(); 621 printValueAsString(recordAttrs.DataRecordType, recordTypeNames); 622 printf("\n"); 623 indentIncr(); 624 fetchParseRecord(dlDbHand, &recordAttrs, record, datap, dumpData); 625 indentDecr(); 626 } 627 if(deleteAll && (recordAttrs.DataRecordType != DBBlobRelationID)) { 628 /* NEVER delete a DBBlob */ 629 deleteRecord(dlDbHand, record, interact); 630 } 631 CSSM_DL_FreeUniqueRecord(dlDbHand, record); 632 break; // and go again 633 case CSSMERR_DL_ENDOFDATA: 634 /* normal termination */ 635 break; 636 default: 637 printError("DataGetNext", crtn); 638 break; 639 } 640 if(crtn != CSSM_OK) { 641 break; 642 } 643 } 644} 645 646int main( 647 int argc, 648 char **argv) 649{ 650 int arg; 651 char *argp; 652 char *dbFileName; 653 char cmd; 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; 661 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; 667 668 if(argc < 3) { 669 usage(argv); 670 } 671 dbFileName = argv[1]; 672 cmd = argv[2][0]; 673 674 for(arg=3; arg<argc; arg++) { 675 argp = argv[arg]; 676 switch(argp[0]) { 677 case 'v': 678 verbose = CSSM_TRUE; 679 break; 680 case 'q': 681 quiet = CSSM_TRUE; 682 break; 683 case 'R': 684 if(cmd == 'D') { 685 interact = CSSM_FALSE; 686 } 687 break; 688 case 'd': 689 dumpData = CSSM_TRUE; 690 break; 691 case 'c': 692 certFile = &argp[2]; 693 break; 694 case 'k': 695 keyFile = &argp[2]; 696 break; 697 case 'h': 698 default: 699 usage(argv); 700 } 701 } 702 703 dlDbHand.DLHandle = dlStartup(); 704 if(dlDbHand.DLHandle == 0) { 705 exit(1); 706 } 707 if(cmd == 'i') { 708 crtn = importBadCert(dlDbHand.DLHandle, dbFileName, certFile, 709 keyFile, keyAlg, pemFormat, keyFormat, verbose); 710 goto done; 711 } 712 crtn = dbCreateOpen(dlDbHand.DLHandle, dbFileName, 713 CSSM_FALSE, CSSM_FALSE, NULL, &dlDbHand.DBHandle); 714 if(crtn) { 715 exit(1); 716 } 717 switch(cmd) { 718 case 'r': 719 dumpRelation(dlDbHand, &schemaInfoRelation, dumpData); 720 break; 721 case 'k': 722 dumpRelation(dlDbHand, &allKeysRelation, dumpData); 723 break; 724 case 'c': 725 dumpRelation(dlDbHand, &x509CertRecordRelation, dumpData); 726 break; 727 case 'a': 728 dumpAllRecords(dlDbHand, CSSM_FALSE, CSSM_TRUE, dumpData); 729 break; 730 case 'd': 731 case 'D': 732 dumpAllRecords(dlDbHand, CSSM_TRUE, interact, dumpData); 733 if(!interact) { 734 /* we ignored errors.... */ 735 if(!quiet) { 736 printf("...DB %s wiped clean\n", dbFileName); 737 } 738 } 739 break; 740 default: 741 usage(argv); 742 } 743 CSSM_DL_DbClose(dlDbHand); 744done: 745 CSSM_ModuleDetach(dlDbHand.DLHandle); 746 return crtn; 747} 748