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