michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "nss.h" michael@0: #include "secutil.h" michael@0: #include "pk11pub.h" michael@0: #include "cert.h" michael@0: michael@0: typedef struct commandDescriptStr { michael@0: int required; michael@0: char *arg; michael@0: char *des; michael@0: } commandDescript; michael@0: michael@0: enum optionNames { michael@0: opt_liborder = 0, michael@0: opt_mainDB, michael@0: opt_lib1DB, michael@0: opt_lib2DB, michael@0: opt_mainRO, michael@0: opt_lib1RO, michael@0: opt_lib2RO, michael@0: opt_mainCMD, michael@0: opt_lib1CMD, michael@0: opt_lib2CMD, michael@0: opt_mainTokNam, michael@0: opt_lib1TokNam, michael@0: opt_lib2TokNam, michael@0: opt_oldStyle, michael@0: opt_verbose, michael@0: opt_summary, michael@0: opt_help, michael@0: opt_last michael@0: }; michael@0: michael@0: michael@0: static const michael@0: secuCommandFlag options_init[] = michael@0: { michael@0: { /* opt_liborder */ 'o', PR_TRUE, "1M2zmi", PR_TRUE, "order" }, michael@0: { /* opt_mainDB */ 'd', PR_TRUE, 0, PR_FALSE, "main_db" }, michael@0: { /* opt_lib1DB */ '1', PR_TRUE, 0, PR_FALSE, "lib1_db" }, michael@0: { /* opt_lib2DB */ '2', PR_TRUE, 0, PR_FALSE, "lib2_db" }, michael@0: { /* opt_mainRO */ 'r', PR_FALSE, 0, PR_FALSE, "main_readonly" }, michael@0: { /* opt_lib1RO */ 0, PR_FALSE, 0, PR_FALSE, "lib1_readonly" }, michael@0: { /* opt_lib2RO */ 0, PR_FALSE, 0, PR_FALSE, "lib2_readonly" }, michael@0: { /* opt_mainCMD */ 'c', PR_TRUE, 0, PR_FALSE, "main_command" }, michael@0: { /* opt_lib1CMD */ 0, PR_TRUE, 0, PR_FALSE, "lib1_command" }, michael@0: { /* opt_lib2CMD */ 0, PR_TRUE, 0, PR_FALSE, "lib2_command" }, michael@0: { /* opt_mainTokNam */'t', PR_TRUE, 0, PR_FALSE, "main_token_name" }, michael@0: { /* opt_lib1TokNam */ 0, PR_TRUE, 0, PR_FALSE, "lib1_token_name" }, michael@0: { /* opt_lib2TokNam */ 0, PR_TRUE, 0, PR_FALSE, "lib2_token_name" }, michael@0: { /* opt_oldStype */ 's', PR_FALSE, 0, PR_FALSE, "oldStype" }, michael@0: { /* opt_verbose */ 'v', PR_FALSE, 0, PR_FALSE, "verbose" }, michael@0: { /* opt_summary */ 'z', PR_FALSE, 0, PR_FALSE, "summary" }, michael@0: { /* opt_help */ 'h', PR_FALSE, 0, PR_FALSE, "help" } michael@0: }; michael@0: michael@0: static const michael@0: commandDescript options_des[] = michael@0: { michael@0: { /* opt_liborder */ PR_FALSE, "initOrder", michael@0: " Specifies the order of NSS initialization and shutdown. Order is\n" michael@0: " given as a string where each character represents either an init or\n" michael@0: " a shutdown of the main program or one of the 2 test libraries\n" michael@0: " (library 1 and library 2). The valid characters are as follows:\n" michael@0: " M Init the main program\n 1 Init library 1\n" michael@0: " 2 Init library 2\n" michael@0: " m Shutdown the main program\n i Shutdown library 1\n" michael@0: " z Shutdown library 2\n" }, michael@0: { /* opt_mainDB */ PR_TRUE, "nss_db", michael@0: " Specified the directory to open the nss database for the main\n" michael@0: " program. Must be specified if \"M\" is given in the order string\n"}, michael@0: { /* opt_lib1DB */ PR_FALSE, "nss_db", michael@0: " Specified the directory to open the nss database for library 1.\n" michael@0: " Must be specified if \"1\" is given in the order string\n"}, michael@0: { /* opt_lib2DB */ PR_FALSE, "nss_db", michael@0: " Specified the directory to open the nss database for library 2.\n" michael@0: " Must be specified if \"2\" is given in the order string\n"}, michael@0: { /* opt_mainRO */ PR_FALSE, NULL, michael@0: " Open the main program's database read only.\n" }, michael@0: { /* opt_lib1RO */ PR_FALSE, NULL, michael@0: " Open library 1's database read only.\n" }, michael@0: { /* opt_lib2RO */ PR_FALSE, NULL, michael@0: " Open library 2's database read only.\n" }, michael@0: { /* opt_mainCMD */ PR_FALSE, "nss_command", michael@0: " Specifies the NSS command to execute in the main program.\n" michael@0: " Valid commands are: \n" michael@0: " key_slot, list_slots, list_certs, add_cert, none.\n" michael@0: " Default is \"none\".\n" }, michael@0: { /* opt_lib1CMD */ PR_FALSE, "nss_command", michael@0: " Specifies the NSS command to execute in library 1.\n" }, michael@0: { /* opt_lib2CMD */ PR_FALSE, "nss_command", michael@0: " Specifies the NSS command to execute in library 2.\n" }, michael@0: { /* opt_mainTokNam */PR_FALSE, "token_name", michael@0: " Specifies the name of PKCS11 token for the main program's " michael@0: "database.\n" }, michael@0: { /* opt_lib1TokNam */PR_FALSE, "token_name", michael@0: " Specifies the name of PKCS11 token for library 1's database.\n" }, michael@0: { /* opt_lib2TokNam */PR_FALSE, "token_name", michael@0: " Specifies the name of PKCS11 token for library 2's database.\n" }, michael@0: { /* opt_oldStype */ PR_FALSE, NULL, michael@0: " Use NSS_Shutdown rather than NSS_ShutdownContext in the main\n" michael@0: " program.\n" }, michael@0: { /* opt_verbose */ PR_FALSE, NULL, michael@0: " Noisily output status to standard error\n" }, michael@0: { /* opt_summarize */ PR_FALSE, NULL, michael@0: "report a summary of the test results\n" }, michael@0: { /* opt_help */ PR_FALSE, NULL, " give this message\n" } michael@0: }; michael@0: michael@0: /* michael@0: * output our short help (table driven). (does not exit). michael@0: */ michael@0: static void michael@0: short_help(const char *prog) michael@0: { michael@0: int count = opt_last; michael@0: int i,words_found; michael@0: michael@0: /* make sure all the tables are up to date before we allow compiles to michael@0: * succeed */ michael@0: PR_STATIC_ASSERT(sizeof(options_init)/sizeof(secuCommandFlag) == opt_last); michael@0: PR_STATIC_ASSERT(sizeof(options_init)/sizeof(secuCommandFlag) == michael@0: sizeof(options_des)/sizeof(commandDescript)); michael@0: michael@0: /* print the base usage */ michael@0: fprintf(stderr,"usage: %s ",prog); michael@0: for (i=0, words_found=0; i < count; i++) { michael@0: if (!options_des[i].required) { michael@0: fprintf(stderr,"["); michael@0: } michael@0: if (options_init[i].longform) { michael@0: fprintf(stderr, "--%s", options_init[i].longform); michael@0: words_found++; michael@0: } else { michael@0: fprintf(stderr, "-%c", options_init[i].flag); michael@0: } michael@0: if (options_init[i].needsArg) { michael@0: if (options_des[i].arg) { michael@0: fprintf(stderr," %s",options_des[i].arg); michael@0: } else { michael@0: fprintf(stderr," arg"); michael@0: } michael@0: words_found++; michael@0: } michael@0: if (!options_des[i].required) { michael@0: fprintf(stderr,"]"); michael@0: } michael@0: if (i < count-1 ) { michael@0: if (words_found >= 5) { michael@0: fprintf(stderr,"\n "); michael@0: words_found=0; michael@0: } else { michael@0: fprintf(stderr," "); michael@0: } michael@0: } michael@0: } michael@0: fprintf(stderr,"\n"); michael@0: } michael@0: michael@0: /* michael@0: * print out long help. like short_help, this does not exit michael@0: */ michael@0: static void michael@0: long_help(const char *prog) michael@0: { michael@0: int i; michael@0: int count = opt_last; michael@0: michael@0: short_help(prog); michael@0: /* print the option descriptions */ michael@0: fprintf(stderr,"\n"); michael@0: for (i=0; i < count; i++) { michael@0: fprintf(stderr," "); michael@0: if (options_init[i].flag) { michael@0: fprintf(stderr, "-%c", options_init[i].flag); michael@0: if (options_init[i].longform) { michael@0: fprintf(stderr,","); michael@0: } michael@0: } michael@0: if (options_init[i].longform) { michael@0: fprintf(stderr,"--%s", options_init[i].longform); michael@0: } michael@0: if (options_init[i].needsArg) { michael@0: if (options_des[i].arg) { michael@0: fprintf(stderr," %s",options_des[i].arg); michael@0: } else { michael@0: fprintf(stderr," arg"); michael@0: } michael@0: if (options_init[i].arg) { michael@0: fprintf(stderr," (default = \"%s\")",options_init[i].arg); michael@0: } michael@0: } michael@0: fprintf(stderr,"\n%s",options_des[i].des); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * record summary data michael@0: */ michael@0: struct bufferData { michael@0: char * data; /* lowest address of the buffer */ michael@0: char * next; /* pointer to the next element on the buffer */ michael@0: int len; /* length of the buffer */ michael@0: }; michael@0: michael@0: /* our actual buffer. If data is NULL, then all append ops michael@0: * except are noops */ michael@0: static struct bufferData buffer= { NULL, NULL, 0 }; michael@0: michael@0: #define CHUNK_SIZE 1000 michael@0: michael@0: /* michael@0: * get our initial data. and set the buffer variables up. on failure, michael@0: * just don't initialize the buffer. michael@0: */ michael@0: static void michael@0: initBuffer(void) michael@0: { michael@0: buffer.data = PORT_Alloc(CHUNK_SIZE); michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: buffer.next = buffer.data; michael@0: buffer.len = CHUNK_SIZE; michael@0: } michael@0: michael@0: /* michael@0: * grow the buffer. If we can't get more data, record a 'D' in the second michael@0: * to last record and allow the rest of the data to overwrite the last michael@0: * element. michael@0: */ michael@0: static void michael@0: growBuffer(void) michael@0: { michael@0: char *new = PORT_Realloc(buffer.data, buffer.len + CHUNK_SIZE); michael@0: if (!new) { michael@0: buffer.data[buffer.len-2] = 'D'; /* signal malloc failure in summary */ michael@0: /* buffer must always point to good memory if it exists */ michael@0: buffer.next = buffer.data + (buffer.len -1); michael@0: return; michael@0: } michael@0: buffer.next = new + (buffer.next-buffer.data); michael@0: buffer.data = new; michael@0: buffer.len += CHUNK_SIZE; michael@0: } michael@0: michael@0: /* michael@0: * append a label, doubles as appending a single character. michael@0: */ michael@0: static void michael@0: appendLabel(char label) michael@0: { michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: *buffer.next++ = label; michael@0: if (buffer.data+buffer.len >= buffer.next) { michael@0: growBuffer(); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * append a string onto the buffer. The result will be michael@0: */ michael@0: static void michael@0: appendString(char *string) michael@0: { michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: appendLabel('<'); michael@0: while (*string) { michael@0: appendLabel(*string++); michael@0: } michael@0: appendLabel('>'); michael@0: } michael@0: michael@0: /* michael@0: * append a bool, T= true, F=false michael@0: */ michael@0: static void michael@0: appendBool(PRBool bool) michael@0: { michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: if (bool) { michael@0: appendLabel('t'); michael@0: } else { michael@0: appendLabel('f'); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * append a single hex nibble. michael@0: */ michael@0: static void michael@0: appendHex(unsigned char nibble) michael@0: { michael@0: if (nibble <= 9) { michael@0: appendLabel('0'+nibble); michael@0: } else { michael@0: appendLabel('a'+nibble-10); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * append a secitem as colon separated hex bytes. michael@0: */ michael@0: static void michael@0: appendItem(SECItem *item) michael@0: { michael@0: int i; michael@0: michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: appendLabel(':'); michael@0: for (i=0; i < item->len; i++) { michael@0: unsigned char byte=item->data[i]; michael@0: appendHex(byte >> 4); michael@0: appendHex(byte & 0xf); michael@0: appendLabel(':'); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * append a 32 bit integer (even on a 64 bit platform). michael@0: * for simplicity append it as a hex value, full extension with 0x prefix. michael@0: */ michael@0: static void michael@0: appendInt(unsigned int value) michael@0: { michael@0: int i; michael@0: michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: appendLabel('0'); michael@0: appendLabel('x'); michael@0: value = value & 0xffffffff; /* only look at the buttom 8 bytes */ michael@0: for (i=0; i < 8; i++) { michael@0: appendHex(value >> 28 ); michael@0: value = value << 4; michael@0: } michael@0: } michael@0: michael@0: /* append a trust flag */ michael@0: static void michael@0: appendFlags(unsigned int flag) michael@0: { michael@0: char trust[10]; michael@0: char *cp=trust; michael@0: michael@0: trust[0] = 0; michael@0: printflags(trust, flag); michael@0: while (*cp) { michael@0: appendLabel(*cp++); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * dump our buffer out with a result= flag so we can find it easily. michael@0: * free the buffer as a side effect. michael@0: */ michael@0: static void michael@0: dumpBuffer(void) michael@0: { michael@0: if (!buffer.data) { michael@0: return; michael@0: } michael@0: michael@0: appendLabel(0); /* terminate */ michael@0: printf("\nresult=%s\n",buffer.data); michael@0: PORT_Free(buffer.data); michael@0: buffer.data = buffer.next = NULL; michael@0: buffer.len = 0; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * usage, like traditional usage, automatically exit michael@0: */ michael@0: static void michael@0: usage(const char *prog) michael@0: { michael@0: short_help(prog); michael@0: dumpBuffer(); michael@0: exit(1); michael@0: } michael@0: michael@0: /* michael@0: * like usage, except prints the long version of help michael@0: */ michael@0: static void michael@0: usage_long(const char *prog) michael@0: { michael@0: long_help(prog); michael@0: dumpBuffer(); michael@0: exit(1); michael@0: } michael@0: michael@0: static const char * michael@0: bool2String(PRBool bool) michael@0: { michael@0: return bool ? "true" : "false"; michael@0: } michael@0: michael@0: /* michael@0: * print out interesting info about the given slot michael@0: */ michael@0: void michael@0: print_slot(PK11SlotInfo *slot, int log) michael@0: { michael@0: if (log) { michael@0: fprintf(stderr, "* Name=%s Token_Name=%s present=%s, ro=%s *\n", michael@0: PK11_GetSlotName(slot), PK11_GetTokenName(slot), michael@0: bool2String(PK11_IsPresent(slot)), michael@0: bool2String(PK11_IsReadOnly(slot))); michael@0: } michael@0: appendLabel('S'); michael@0: appendString(PK11_GetTokenName(slot)); michael@0: appendBool(PK11_IsPresent(slot)); michael@0: appendBool(PK11_IsReadOnly(slot)); michael@0: } michael@0: michael@0: /* michael@0: * list all our slots michael@0: */ michael@0: void michael@0: do_list_slots(const char *progName, int log) michael@0: { michael@0: PK11SlotList *list; michael@0: PK11SlotListElement *le; michael@0: michael@0: list= PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL); michael@0: if (list == NULL) { michael@0: fprintf(stderr,"ERROR: no tokens found %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: appendLabel('S'); michael@0: appendString("none"); michael@0: return; michael@0: } michael@0: michael@0: for (le= PK11_GetFirstSafe(list); le; michael@0: le = PK11_GetNextSafe(list,le,PR_TRUE)) { michael@0: print_slot(le->slot, log); michael@0: } michael@0: PK11_FreeSlotList(list); michael@0: } michael@0: michael@0: static PRBool michael@0: sort_CN(CERTCertificate *certa, CERTCertificate *certb, void *arg) michael@0: { michael@0: char *commonNameA, *commonNameB; michael@0: int ret; michael@0: michael@0: commonNameA = CERT_GetCommonName(&certa->subject); michael@0: commonNameB = CERT_GetCommonName(&certb->subject); michael@0: michael@0: if (commonNameA == NULL) { michael@0: PORT_Free(commonNameB); michael@0: return PR_TRUE; michael@0: } michael@0: if (commonNameB == NULL) { michael@0: PORT_Free(commonNameA); michael@0: return PR_FALSE; michael@0: } michael@0: ret = PORT_Strcmp(commonNameA,commonNameB); michael@0: PORT_Free(commonNameA); michael@0: PORT_Free(commonNameB); michael@0: return (ret < 0) ? PR_TRUE: PR_FALSE; michael@0: } michael@0: michael@0: /* michael@0: * list all the certs michael@0: */ michael@0: void michael@0: do_list_certs(const char *progName, int log) michael@0: { michael@0: CERTCertList *list; michael@0: CERTCertList *sorted; michael@0: CERTCertListNode *node; michael@0: CERTCertTrust trust; michael@0: int i; michael@0: michael@0: list = PK11_ListCerts(PK11CertListUnique, NULL); michael@0: if (list == NULL) { michael@0: fprintf(stderr,"ERROR: no certs found %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: appendLabel('C'); michael@0: appendString("none"); michael@0: return; michael@0: } michael@0: michael@0: sorted = CERT_NewCertList(); michael@0: if (sorted == NULL) { michael@0: fprintf(stderr,"ERROR: no certs found %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: appendLabel('C'); michael@0: appendLabel('E'); michael@0: appendInt(PORT_GetError()); michael@0: return; michael@0: } michael@0: michael@0: /* sort the list */ michael@0: for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node,list); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: CERT_AddCertToListSorted(sorted, node->cert, sort_CN, NULL); michael@0: } michael@0: michael@0: michael@0: for (node = CERT_LIST_HEAD(sorted); !CERT_LIST_END(node,sorted); michael@0: node = CERT_LIST_NEXT(node)) { michael@0: CERTCertificate *cert = node->cert; michael@0: char *commonName; michael@0: michael@0: SECU_PrintCertNickname(node, stderr); michael@0: if (log) { michael@0: fprintf(stderr, "* Slot=%s*\n", cert->slot ? michael@0: PK11_GetTokenName(cert->slot) : "none"); michael@0: fprintf(stderr, "* Nickname=%s*\n", cert->nickname); michael@0: fprintf(stderr, "* Subject=<%s>*\n", cert->subjectName); michael@0: fprintf(stderr, "* Issuer=<%s>*\n", cert->issuerName); michael@0: fprintf(stderr, "* SN="); michael@0: for (i=0; i < cert->serialNumber.len; i++) { michael@0: if (i!=0) fprintf(stderr,":"); michael@0: fprintf(stderr, "%02x",cert->serialNumber.data[0]); michael@0: } michael@0: fprintf(stderr," *\n"); michael@0: } michael@0: appendLabel('C'); michael@0: commonName = CERT_GetCommonName(&cert->subject); michael@0: appendString(commonName?commonName:"*NoName*"); michael@0: PORT_Free(commonName); michael@0: if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { michael@0: appendFlags(trust.sslFlags); michael@0: appendFlags(trust.emailFlags); michael@0: appendFlags(trust.objectSigningFlags); michael@0: } michael@0: } michael@0: CERT_DestroyCertList(list); michael@0: michael@0: } michael@0: michael@0: /* michael@0: * need to implement yet... try to add a new certificate michael@0: */ michael@0: void michael@0: do_add_cert(const char *progName, int log) michael@0: { michael@0: PORT_Assert(/* do_add_cert not implemented */ 0); michael@0: } michael@0: michael@0: /* michael@0: * display the current key slot michael@0: */ michael@0: void michael@0: do_key_slot(const char *progName, int log) michael@0: { michael@0: PK11SlotInfo *slot = PK11_GetInternalKeySlot(); michael@0: if (!slot) { michael@0: fprintf(stderr,"ERROR: no internal key slot found %s\n", michael@0: SECU_Strerror(PORT_GetError())); michael@0: appendLabel('K'); michael@0: appendLabel('S'); michael@0: appendString("none"); michael@0: } michael@0: print_slot(slot, log); michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: michael@0: /* michael@0: * execute some NSS command. michael@0: */ michael@0: void michael@0: do_command(const char *label, int initialized, secuCommandFlag *command, michael@0: const char *progName, int log) michael@0: { michael@0: char * command_string; michael@0: if (!initialized) { michael@0: return; michael@0: } michael@0: michael@0: if (command->activated) { michael@0: command_string = command->arg; michael@0: } else { michael@0: command_string = "none"; michael@0: } michael@0: michael@0: if (log) { michael@0: fprintf(stderr, "*Executing nss command \"%s\" for %s*\n", michael@0: command_string,label); michael@0: } michael@0: michael@0: /* do something */ michael@0: if (PORT_Strcasecmp(command_string, "list_slots") == 0) { michael@0: do_list_slots(progName, log); michael@0: } else if (PORT_Strcasecmp(command_string, "list_certs") == 0) { michael@0: do_list_certs(progName, log); michael@0: } else if (PORT_Strcasecmp(command_string, "add_cert") == 0) { michael@0: do_add_cert(progName, log); michael@0: } else if (PORT_Strcasecmp(command_string, "key_slot") == 0) { michael@0: do_key_slot(progName, log); michael@0: } else if (PORT_Strcasecmp(command_string, "none") != 0) { michael@0: fprintf(stderr, ">> Unknown command (%s)\n", command_string); michael@0: appendLabel('E'); michael@0: appendString("bc"); michael@0: usage_long(progName); michael@0: } michael@0: michael@0: } michael@0: michael@0: michael@0: /* michael@0: * functions do handle michael@0: * different library initializations. michael@0: */ michael@0: static int main_initialized; michael@0: static int lib1_initialized; michael@0: static int lib2_initialized; michael@0: michael@0: void michael@0: main_Init(secuCommandFlag *db, secuCommandFlag *tokNam, michael@0: int readOnly, const char *progName, int log) michael@0: { michael@0: SECStatus rv; michael@0: if (log) { michael@0: fprintf(stderr,"*NSS_Init for the main program*\n"); michael@0: } michael@0: appendLabel('M'); michael@0: if (!db->activated) { michael@0: fprintf(stderr, ">> No main_db has been specified\n"); michael@0: usage(progName); michael@0: } michael@0: if (main_initialized) { michael@0: fprintf(stderr,"Warning: Second initialization of Main\n"); michael@0: appendLabel('E'); michael@0: appendString("2M"); michael@0: } michael@0: if (tokNam->activated) { michael@0: PK11_ConfigurePKCS11(NULL, NULL, NULL, tokNam->arg, michael@0: NULL, NULL, NULL, NULL, 0, 0); michael@0: } michael@0: rv = NSS_Initialize(db->arg, "", "", "", michael@0: NSS_INIT_NOROOTINIT|(readOnly?NSS_INIT_READONLY:0)); michael@0: if (rv != SECSuccess) { michael@0: appendLabel('E'); michael@0: appendInt(PORT_GetError()); michael@0: fprintf(stderr,">> %s\n", SECU_Strerror(PORT_GetError())); michael@0: dumpBuffer(); michael@0: exit(1); michael@0: } michael@0: main_initialized = 1; michael@0: } michael@0: michael@0: void michael@0: main_Do(secuCommandFlag *command, const char *progName, int log) michael@0: { michael@0: do_command("main", main_initialized, command, progName, log); michael@0: } michael@0: michael@0: void michael@0: main_Shutdown(int old_style, const char *progName, int log) michael@0: { michael@0: SECStatus rv; michael@0: appendLabel('N'); michael@0: if (log) { michael@0: fprintf(stderr,"*NSS_Shutdown for the main program*\n"); michael@0: } michael@0: if (!main_initialized) { michael@0: fprintf(stderr,"Warning: Main shutdown without corresponding init\n"); michael@0: } michael@0: if (old_style) { michael@0: rv = NSS_Shutdown(); michael@0: } else { michael@0: rv = NSS_ShutdownContext(NULL); michael@0: } michael@0: fprintf(stderr, "Shutdown main state = %d\n", rv); michael@0: if (rv != SECSuccess) { michael@0: appendLabel('E'); michael@0: appendInt(PORT_GetError()); michael@0: fprintf(stderr,"ERROR: %s\n", SECU_Strerror(PORT_GetError())); michael@0: } michael@0: main_initialized = 0; michael@0: } michael@0: michael@0: /* common library init */ michael@0: NSSInitContext * michael@0: lib_Init(const char *lableString, char label, int initialized, michael@0: secuCommandFlag *db, secuCommandFlag *tokNam, int readonly, michael@0: const char *progName, int log) michael@0: { michael@0: NSSInitContext *ctxt; michael@0: NSSInitParameters initStrings; michael@0: NSSInitParameters *initStringPtr = NULL; michael@0: michael@0: appendLabel(label); michael@0: if (log) { michael@0: fprintf(stderr,"*NSS_Init for %s*\n", lableString); michael@0: } michael@0: michael@0: if (!db->activated) { michael@0: fprintf(stderr, ">> No %s_db has been specified\n", lableString); michael@0: usage(progName); michael@0: } michael@0: if (initialized) { michael@0: fprintf(stderr,"Warning: Second initialization of %s\n", lableString); michael@0: } michael@0: if (tokNam->activated) { michael@0: PORT_Memset(&initStrings, 0, sizeof(initStrings)); michael@0: initStrings.length = sizeof(initStrings); michael@0: initStrings.dbTokenDescription = tokNam->arg; michael@0: initStringPtr = &initStrings; michael@0: } michael@0: ctxt = NSS_InitContext(db->arg, "", "", "", initStringPtr, michael@0: NSS_INIT_NOROOTINIT|(readonly?NSS_INIT_READONLY:0)); michael@0: if (ctxt == NULL) { michael@0: appendLabel('E'); michael@0: appendInt(PORT_GetError()); michael@0: fprintf(stderr,">> %s\n",SECU_Strerror(PORT_GetError())); michael@0: dumpBuffer(); michael@0: exit(1); michael@0: } michael@0: return ctxt; michael@0: } michael@0: michael@0: /* common library shutdown */ michael@0: void michael@0: lib_Shutdown(const char *labelString, char label, NSSInitContext *ctx, michael@0: int initialize, const char *progName, int log) michael@0: { michael@0: SECStatus rv; michael@0: appendLabel(label); michael@0: if (log) { michael@0: fprintf(stderr,"*NSS_Shutdown for %s\n*", labelString); michael@0: } michael@0: if (!initialize) { michael@0: fprintf(stderr,"Warning: %s shutdown without corresponding init\n", michael@0: labelString); michael@0: } michael@0: rv = NSS_ShutdownContext(ctx); michael@0: fprintf(stderr, "Shutdown %s state = %d\n", labelString, rv); michael@0: if (rv != SECSuccess) { michael@0: appendLabel('E'); michael@0: appendInt(PORT_GetError()); michael@0: fprintf(stderr,"ERROR: %s\n", SECU_Strerror(PORT_GetError())); michael@0: } michael@0: } michael@0: michael@0: michael@0: static NSSInitContext *lib1_context; michael@0: static NSSInitContext *lib2_context; michael@0: void michael@0: lib1_Init(secuCommandFlag *db, secuCommandFlag *tokNam, michael@0: int readOnly, const char *progName, int log) michael@0: { michael@0: lib1_context = lib_Init("lib1", '1', lib1_initialized, db, tokNam, michael@0: readOnly, progName, log); michael@0: lib1_initialized = 1; michael@0: } michael@0: michael@0: void michael@0: lib2_Init(secuCommandFlag *db, secuCommandFlag *tokNam, michael@0: int readOnly, const char *progName, int log) michael@0: { michael@0: lib2_context = lib_Init("lib2", '2', lib2_initialized, michael@0: db, tokNam, readOnly, progName, log); michael@0: lib2_initialized = 1; michael@0: } michael@0: michael@0: void michael@0: lib1_Do(secuCommandFlag *command, const char *progName, int log) michael@0: { michael@0: do_command("lib1", lib1_initialized, command, progName, log); michael@0: } michael@0: michael@0: void michael@0: lib2_Do(secuCommandFlag *command, const char *progName, int log) michael@0: { michael@0: do_command("lib2", lib2_initialized, command, progName, log); michael@0: } michael@0: michael@0: void michael@0: lib1_Shutdown(const char *progName, int log) michael@0: { michael@0: lib_Shutdown("lib1", 'I', lib1_context, lib1_initialized, progName, log); michael@0: lib1_initialized = 0; michael@0: /* don't clear lib1_Context, so we can test multiple attempts to close michael@0: * the same context produces correct errors*/ michael@0: } michael@0: michael@0: void michael@0: lib2_Shutdown(const char *progName, int log) michael@0: { michael@0: lib_Shutdown("lib2", 'Z', lib2_context, lib2_initialized, progName, log); michael@0: lib2_initialized = 0; michael@0: /* don't clear lib2_Context, so we can test multiple attempts to close michael@0: * the same context produces correct errors*/ michael@0: } michael@0: michael@0: int michael@0: main(int argc, char **argv) michael@0: { michael@0: SECStatus rv; michael@0: secuCommand libinit; michael@0: char *progName; michael@0: char *order; michael@0: secuCommandFlag *options; michael@0: int log = 0; michael@0: michael@0: progName = strrchr(argv[0], '/'); michael@0: progName = progName ? progName+1 : argv[0]; michael@0: michael@0: libinit.numCommands = 0; michael@0: libinit.commands = 0; michael@0: libinit.numOptions = opt_last; michael@0: options = (secuCommandFlag *)PORT_Alloc(sizeof(options_init)); michael@0: if (options == NULL) { michael@0: fprintf(stderr, ">> %s:Not enough free memory to run command\n", michael@0: progName); michael@0: exit(1); michael@0: } michael@0: PORT_Memcpy(options, options_init, sizeof(options_init)); michael@0: libinit.options = options; michael@0: michael@0: rv = SECU_ParseCommandLine(argc, argv, progName, & libinit); michael@0: if (rv != SECSuccess) { michael@0: usage(progName); michael@0: } michael@0: michael@0: if (libinit.options[opt_help].activated) { michael@0: long_help(progName); michael@0: exit (0); michael@0: } michael@0: michael@0: log = libinit.options[opt_verbose].activated; michael@0: if (libinit.options[opt_summary].activated) { michael@0: initBuffer(); michael@0: } michael@0: michael@0: order = libinit.options[opt_liborder].arg; michael@0: if (!order) { michael@0: usage(progName); michael@0: } michael@0: michael@0: if (log) { michael@0: fprintf(stderr,"* initializing with order \"%s\"*\n", order); michael@0: } michael@0: michael@0: for (;*order; order++) { michael@0: switch (*order) { michael@0: case 'M': michael@0: main_Init(&libinit.options[opt_mainDB], michael@0: &libinit.options[opt_mainTokNam], michael@0: libinit.options[opt_mainRO].activated, michael@0: progName, log); michael@0: break; michael@0: case '1': michael@0: lib1_Init(&libinit.options[opt_lib1DB], michael@0: &libinit.options[opt_lib1TokNam], michael@0: libinit.options[opt_lib1RO].activated, michael@0: progName,log); michael@0: break; michael@0: case '2': michael@0: lib2_Init(&libinit.options[opt_lib2DB], michael@0: &libinit.options[opt_lib2TokNam], michael@0: libinit.options[opt_lib2RO].activated, michael@0: progName,log); michael@0: break; michael@0: case 'm': michael@0: main_Shutdown(libinit.options[opt_oldStyle].activated, michael@0: progName, log); michael@0: break; michael@0: case 'i': michael@0: lib1_Shutdown(progName, log); michael@0: break; michael@0: case 'z': michael@0: lib2_Shutdown(progName, log); michael@0: break; michael@0: default: michael@0: fprintf(stderr,">> Unknown init/shutdown command \"%c\"", *order); michael@0: usage_long(progName); michael@0: } michael@0: main_Do(&libinit.options[opt_mainCMD], progName, log); michael@0: lib1_Do(&libinit.options[opt_lib1CMD], progName, log); michael@0: lib2_Do(&libinit.options[opt_lib2CMD], progName, log); michael@0: } michael@0: michael@0: if (NSS_IsInitialized()) { michael@0: appendLabel('X'); michael@0: fprintf(stderr, "Warning: NSS is initialized\n"); michael@0: } michael@0: dumpBuffer(); michael@0: michael@0: exit(0); michael@0: } michael@0: