summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/multinit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /security/nss/cmd/multinit
parentInitial commit. (diff)
downloadfirefox-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/Makefile47
-rw-r--r--security/nss/cmd/multinit/manifest.mn13
-rw-r--r--security/nss/cmd/multinit/multinit.c878
-rw-r--r--security/nss/cmd/multinit/multinit.gyp24
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