summaryrefslogtreecommitdiffstats
path: root/security/nss/cmd/modutil/modutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/cmd/modutil/modutil.c')
-rw-r--r--security/nss/cmd/modutil/modutil.c996
1 files changed, 996 insertions, 0 deletions
diff --git a/security/nss/cmd/modutil/modutil.c b/security/nss/cmd/modutil/modutil.c
new file mode 100644
index 0000000000..f04ad3d925
--- /dev/null
+++ b/security/nss/cmd/modutil/modutil.c
@@ -0,0 +1,996 @@
+/* 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/. */
+
+/* To edit this file, set TABSTOPS to 4 spaces.
+ * This is not the normal NSS convention.
+ */
+
+#include "modutil.h"
+#include "install.h"
+#include <plstr.h>
+#include "certdb.h" /* for CERT_DB_FILE_VERSION */
+#include "nss.h"
+
+static void install_error(char* message);
+static char* PR_fgets(char* buf, int size, PRFileDesc* file);
+static char* progName;
+
+/* This enum must be kept in sync with the commandNames list */
+typedef enum {
+ NO_COMMAND,
+ ADD_COMMAND,
+ CHANGEPW_COMMAND,
+ CREATE_COMMAND,
+ DEFAULT_COMMAND,
+ DELETE_COMMAND,
+ DISABLE_COMMAND,
+ ENABLE_COMMAND,
+ FIPS_COMMAND,
+ JAR_COMMAND,
+ LIST_COMMAND,
+ RAW_LIST_COMMAND,
+ RAW_ADD_COMMAND,
+ CHKFIPS_COMMAND,
+ UNDEFAULT_COMMAND
+} Command;
+
+/* This list must be kept in sync with the Command enum */
+static char* commandNames[] = {
+ "(no command)",
+ "-add",
+ "-changepw",
+ "-create",
+ "-default",
+ "-delete",
+ "-disable",
+ "-enable",
+ "-fips",
+ "-jar",
+ "-list",
+ "-rawlist",
+ "-rawadd",
+ "-chkfips",
+ "-undefault"
+};
+
+/* this enum must be kept in sync with the optionStrings list */
+typedef enum {
+ ADD_ARG = 0,
+ RAW_ADD_ARG,
+ CHANGEPW_ARG,
+ CIPHERS_ARG,
+ CREATE_ARG,
+ DBDIR_ARG,
+ DBPREFIX_ARG,
+ DEFAULT_ARG,
+ DELETE_ARG,
+ DISABLE_ARG,
+ ENABLE_ARG,
+ FIPS_ARG,
+ FORCE_ARG,
+ JAR_ARG,
+ LIBFILE_ARG,
+ LIST_ARG,
+ RAW_LIST_ARG,
+ MECHANISMS_ARG,
+ NEWPWFILE_ARG,
+ PWFILE_ARG,
+ SLOT_ARG,
+ UNDEFAULT_ARG,
+ INSTALLDIR_ARG,
+ TEMPDIR_ARG,
+ SECMOD_ARG,
+ NOCERTDB_ARG,
+ STRING_ARG,
+ CHKFIPS_ARG,
+
+ NUM_ARGS /* must be last */
+} Arg;
+
+/* This list must be kept in sync with the Arg enum */
+static char* optionStrings[] = {
+ "-add",
+ "-rawadd",
+ "-changepw",
+ "-ciphers",
+ "-create",
+ "-dbdir",
+ "-dbprefix",
+ "-default",
+ "-delete",
+ "-disable",
+ "-enable",
+ "-fips",
+ "-force",
+ "-jar",
+ "-libfile",
+ "-list",
+ "-rawlist",
+ "-mechanisms",
+ "-newpwfile",
+ "-pwfile",
+ "-slot",
+ "-undefault",
+ "-installdir",
+ "-tempdir",
+ "-secmod",
+ "-nocertdb",
+ "-string",
+ "-chkfips",
+};
+
+char* msgStrings[] = {
+ "FIPS mode enabled.\n",
+ "FIPS mode disabled.\n",
+ "Using database directory %s...\n",
+ "Creating \"%s\"...",
+ "Module \"%s\" added to database.\n",
+ "Module \"%s\" deleted from database.\n",
+ "Token \"%s\" password changed successfully.\n",
+ "Incorrect password, try again...\n",
+ "Passwords do not match, try again...\n",
+ "done.\n",
+ "Slot \"%s\" %s.\n",
+ "Successfully changed defaults.\n",
+ "Successfully changed defaults.\n",
+ "\nWARNING: Performing this operation while the browser is running could cause"
+ "\ncorruption of your security databases. If the browser is currently running,"
+ "\nyou should exit browser before continuing this operation. Type "
+ "\n'q <enter>' to abort, or <enter> to continue: ",
+ "\nAborting...\n",
+ "\nWARNING: Manually adding a module while p11-kit is enabled could cause"
+ "\nduplicate module registration in your security database. It is suggested "
+ "\nto configure the module through p11-kit configuration file instead.\n"
+ "\nType 'q <enter>' to abort, or <enter> to continue: "
+};
+
+/* Increment i if doing so would have i still be less than j. If you
+ are able to do this, return 0. Otherwise return 1. */
+#define TRY_INC(i, j) (((i + 1) < j) ? (++i, 0) : 1)
+
+/********************************************************************
+ *
+ * file-wide variables obtained from the command line
+ */
+static Command command = NO_COMMAND;
+static char* pwFile = NULL;
+static char* newpwFile = NULL;
+static char* moduleName = NULL;
+static char* moduleSpec = NULL;
+static char* slotName = NULL;
+static char* secmodName = NULL;
+static char* tokenName = NULL;
+static char* libFile = NULL;
+static char* dbdir = NULL;
+static char* dbprefix = "";
+static char* secmodString = NULL;
+static char* mechanisms = NULL;
+static char* ciphers = NULL;
+static char* fipsArg = NULL;
+static char* jarFile = NULL;
+static char* installDir = NULL;
+static char* tempDir = NULL;
+static short force = 0;
+static PRBool nocertdb = PR_FALSE;
+
+/*******************************************************************
+ *
+ * p a r s e _ a r g s
+ */
+static Error
+parse_args(int argc, char* argv[])
+{
+ int i;
+ char* arg;
+ int optionType;
+
+ /* Loop over all arguments */
+ for (i = 1; i < argc; i++) {
+ arg = argv[i];
+
+ /* Make sure this is an option and not some floating argument */
+ if (arg[0] != '-') {
+ PR_fprintf(PR_STDERR, errStrings[UNEXPECTED_ARG_ERR], argv[i]);
+ return UNEXPECTED_ARG_ERR;
+ }
+
+ /* Find which option this is */
+ for (optionType = 0; optionType < NUM_ARGS; optionType++) {
+ if (!strcmp(arg, optionStrings[optionType])) {
+ break;
+ }
+ }
+
+ /* Deal with this specific option */
+ switch (optionType) {
+ case NUM_ARGS:
+ default:
+ PR_fprintf(PR_STDERR, errStrings[UNKNOWN_OPTION_ERR], arg);
+ return UNKNOWN_OPTION_ERR;
+ break;
+ case ADD_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = ADD_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case CHANGEPW_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CHANGEPW_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ tokenName = argv[i];
+ break;
+ case CIPHERS_ARG:
+ if (ciphers != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ ciphers = argv[i];
+ break;
+ case CREATE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CREATE_COMMAND;
+ break;
+ case DBDIR_ARG:
+ if (dbdir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ dbdir = argv[i];
+ break;
+ case DBPREFIX_ARG:
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ dbprefix = argv[i];
+ break;
+ case UNDEFAULT_ARG:
+ case DEFAULT_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ if (optionType == DEFAULT_ARG) {
+ command = DEFAULT_COMMAND;
+ } else {
+ command = UNDEFAULT_COMMAND;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case DELETE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = DELETE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case DISABLE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = DISABLE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case ENABLE_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = ENABLE_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleName = argv[i];
+ break;
+ case FIPS_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = FIPS_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ fipsArg = argv[i];
+ break;
+ case CHKFIPS_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = CHKFIPS_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ fipsArg = argv[i];
+ break;
+ case FORCE_ARG:
+ force = 1;
+ break;
+ case NOCERTDB_ARG:
+ nocertdb = PR_TRUE;
+ break;
+ case INSTALLDIR_ARG:
+ if (installDir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ installDir = argv[i];
+ break;
+ case TEMPDIR_ARG:
+ if (tempDir != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ tempDir = argv[i];
+ break;
+ case JAR_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = JAR_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ jarFile = argv[i];
+ break;
+ case LIBFILE_ARG:
+ if (libFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ libFile = argv[i];
+ break;
+ case LIST_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = LIST_COMMAND;
+ /* This option may or may not have an argument */
+ if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
+ moduleName = argv[++i];
+ }
+ break;
+ case RAW_LIST_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = RAW_LIST_COMMAND;
+ /* This option may or may not have an argument */
+ if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
+ moduleName = argv[++i];
+ }
+ break;
+ case RAW_ADD_ARG:
+ if (command != NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
+ return MULTIPLE_COMMAND_ERR;
+ }
+ command = RAW_ADD_COMMAND;
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ moduleSpec = argv[i];
+ break;
+ case MECHANISMS_ARG:
+ if (mechanisms != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ mechanisms = argv[i];
+ break;
+ case NEWPWFILE_ARG:
+ if (newpwFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ newpwFile = argv[i];
+ break;
+ case PWFILE_ARG:
+ if (pwFile != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ pwFile = argv[i];
+ break;
+ case SLOT_ARG:
+ if (slotName != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ slotName = argv[i];
+ break;
+ case SECMOD_ARG:
+ if (secmodName != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ secmodName = argv[i];
+ break;
+ case STRING_ARG:
+ if (secmodString != NULL) {
+ PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
+ return DUPLICATE_OPTION_ERR;
+ }
+ if (TRY_INC(i, argc)) {
+ PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
+ return OPTION_NEEDS_ARG_ERR;
+ }
+ secmodString = argv[i];
+ break;
+ }
+ }
+ return SUCCESS;
+}
+
+/************************************************************************
+ *
+ * v e r i f y _ p a r a m s
+ */
+static Error
+verify_params()
+{
+ switch (command) {
+ case ADD_COMMAND:
+ if (libFile == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[ADD_COMMAND], optionStrings[LIBFILE_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ case CHANGEPW_COMMAND:
+ break;
+ case CREATE_COMMAND:
+ break;
+ case DELETE_COMMAND:
+ break;
+ case DISABLE_COMMAND:
+ break;
+ case ENABLE_COMMAND:
+ break;
+ case FIPS_COMMAND:
+ case CHKFIPS_COMMAND:
+ if (PL_strcasecmp(fipsArg, "true") &&
+ PL_strcasecmp(fipsArg, "false")) {
+ PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]);
+ return INVALID_FIPS_ARG;
+ }
+ break;
+ case JAR_COMMAND:
+ if (installDir == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[JAR_COMMAND], optionStrings[INSTALLDIR_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ case LIST_COMMAND:
+ case RAW_LIST_COMMAND:
+ break;
+ case RAW_ADD_COMMAND:
+ break;
+ case UNDEFAULT_COMMAND:
+ case DEFAULT_COMMAND:
+ if (mechanisms == NULL) {
+ PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
+ commandNames[command], optionStrings[MECHANISMS_ARG]);
+ return MISSING_PARAM_ERR;
+ }
+ break;
+ default:
+ /* Ignore this here */
+ break;
+ }
+
+ return SUCCESS;
+}
+
+/********************************************************************
+ *
+ * i n i t _ c r y p t o
+ *
+ * Does crypto initialization that all commands will require.
+ * If -nocertdb option is specified, don't open key or cert db (we don't
+ * need them if we aren't going to be verifying signatures). This is
+ * because serverland doesn't always have cert and key database files
+ * available.
+ *
+ * This function is ill advised. Names and locations of databases are
+ * private to NSS proper. Such functions only confuse other users.
+ *
+ */
+static Error
+check_crypto(PRBool create, PRBool readOnly)
+{
+ char* dir;
+ char* moddbname = NULL;
+ Error retval;
+ static const char multiaccess[] = { "multiaccess:" };
+
+ dir = SECU_ConfigDirectory(dbdir); /* dir is never NULL */
+ if (dir[0] == '\0') {
+ PR_fprintf(PR_STDERR, errStrings[NO_DBDIR_ERR]);
+ retval = NO_DBDIR_ERR;
+ goto loser;
+ }
+ if (strncmp(dir, multiaccess, sizeof multiaccess - 1) == 0) {
+ /* won't attempt to handle the multiaccess case. */
+ return SUCCESS;
+ }
+#ifdef notdef
+ /* Make sure db directory exists and is readable */
+ if (PR_Access(dir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dir);
+ retval = DIR_DOESNT_EXIST_ERR;
+ goto loser;
+ } else if (PR_Access(dir, PR_ACCESS_READ_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dir);
+ retval = DIR_NOT_READABLE_ERR;
+ goto loser;
+ }
+
+ if (secmodName == NULL) {
+ secmodName = "secmod.db";
+ }
+
+ moddbname = PR_smprintf("%s/%s", dir, secmodName);
+ if (!moddbname)
+ return OUT_OF_MEM_ERR;
+
+ /* Check for the proper permissions on databases */
+ if (create) {
+ /* Make sure dbs don't already exist, and the directory is
+ writeable */
+ if (PR_Access(moddbname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR],
+ moddbname);
+ retval = FILE_ALREADY_EXISTS_ERR;
+ goto loser;
+ } else if (PR_Access(dir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dir);
+ retval = DIR_NOT_WRITEABLE_ERR;
+ goto loser;
+ }
+ } else {
+ /* Make sure dbs are readable and writeable */
+ if (PR_Access(moddbname, PR_ACCESS_READ_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], moddbname);
+ retval = FILE_NOT_READABLE_ERR;
+ goto loser;
+ }
+
+ /* Check for write access if we'll be making changes */
+ if (!readOnly) {
+ if (PR_Access(moddbname, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
+ PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR],
+ moddbname);
+ retval = FILE_NOT_WRITEABLE_ERR;
+ goto loser;
+ }
+ }
+ PR_fprintf(PR_STDOUT, msgStrings[USING_DBDIR_MSG],
+ SECU_ConfigDirectory(NULL));
+ }
+#endif
+ retval = SUCCESS;
+loser:
+ if (moddbname) {
+ PR_Free(moddbname);
+ }
+ return retval;
+}
+
+static Error
+init_crypto(PRBool create, PRBool readOnly)
+{
+
+ PRUint32 flags = 0;
+ SECStatus rv;
+ Error retval;
+ /* Open/create key database */
+
+ if (readOnly)
+ flags |= NSS_INIT_READONLY;
+ if (nocertdb)
+ flags |= NSS_INIT_NOCERTDB;
+ rv = NSS_Initialize(SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
+ secmodName, flags);
+ if (rv != SECSuccess) {
+ SECU_PrintPRandOSError(progName);
+ retval = NSS_INITIALIZE_FAILED_ERR;
+ } else
+ retval = SUCCESS;
+
+ return retval;
+}
+
+/*************************************************************************
+ *
+ * u s a g e
+ */
+static void
+usage()
+{
+ PR_fprintf(PR_STDOUT,
+ "\nNetscape Cryptographic Module Utility\n"
+ "Usage: modutil [command] [options]\n\n"
+ " COMMANDS\n"
+ "---------------------------------------------------------------------------\n"
+ "-add MODULE_NAME Add the named module to the module database\n"
+ " -libfile LIBRARY_FILE The name of the file (.so or .dll)\n"
+ " containing the implementation of PKCS #11\n"
+ " [-ciphers CIPHER_LIST] Enable the given ciphers on this module\n"
+ " [-mechanisms MECHANISM_LIST] Make the module a default provider of the\n"
+ " given mechanisms\n"
+ " [-string CONFIG_STRING] Pass a configuration string to this module\n"
+ "-changepw TOKEN Change the password on the named token\n"
+ " [-pwfile FILE] The old password is in this file\n"
+ " [-newpwfile FILE] The new password is in this file\n"
+ "-chkfips [ true | false ] If true, verify FIPS mode. If false,\n"
+ " verify not FIPS mode\n"
+ "-create Create a new set of security databases\n"
+ "-default MODULE Make the given module a default provider\n"
+ " -mechanisms MECHANISM_LIST of the given mechanisms\n"
+ " [-slot SLOT] limit change to only the given slot\n"
+ "-delete MODULE Remove the named module from the module\n"
+ " database\n"
+ "-disable MODULE Disable the named module\n"
+ " [-slot SLOT] Disable only the named slot on the module\n"
+ "-enable MODULE Enable the named module\n"
+ " [-slot SLOT] Enable only the named slot on the module\n"
+ "-fips [ true | false ] If true, enable FIPS mode. If false,\n"
+ " disable FIPS mode\n"
+ "-force Do not run interactively\n"
+ "-jar JARFILE Install a PKCS #11 module from the given\n"
+ " JAR file in the PKCS #11 JAR format\n"
+ " -installdir DIR Use DIR as the root directory of the\n"
+ " installation\n"
+ " [-tempdir DIR] Use DIR as the temporary installation\n"
+ " directory. If not specified, the current\n"
+ " directory is used\n"
+ "-list [MODULE] Lists information about the specified module\n"
+ " or about all modules if none is specified\n"
+ "-rawadd MODULESPEC Add module spec string to secmod DB\n"
+ "-rawlist [MODULE] Display module spec(s) for one or all\n"
+ " loadable modules\n"
+ "-undefault MODULE The given module is NOT a default provider\n"
+ " -mechanisms MECHANISM_LIST of the listed mechanisms\n"
+ " [-slot SLOT] limit change to only the given slot\n"
+ "---------------------------------------------------------------------------\n"
+ "\n"
+ " OPTIONS\n"
+ "---------------------------------------------------------------------------\n"
+ "-dbdir DIR Directory DIR contains the security databases\n"
+ "-dbprefix prefix Prefix for the security databases\n"
+ "-nocertdb Do not load certificate or key databases. No\n"
+ " verification will be performed on JAR files.\n"
+ "-secmod secmodName Name of the security modules file\n"
+ "---------------------------------------------------------------------------\n"
+ "\n"
+ "Mechanism lists are colon-separated. The following mechanisms are recognized:\n"
+ "RSA, DSA, DH, RC2, RC4, RC5, AES, CAMELLIA, DES, MD2, MD5, SHA1, SHA256, SHA512,\n"
+ "SSL, TLS, RANDOM, and FRIENDLY\n"
+ "\n"
+ "Cipher lists are colon-separated. The following ciphers are recognized:\n"
+ "\n"
+ "\nQuestions or bug reports should be sent to modutil-support@netscape.com.\n");
+}
+
+/*************************************************************************
+ *
+ * m a i n
+ */
+int
+main(int argc, char* argv[])
+{
+ int errcode = SUCCESS;
+ PRBool createdb, readOnly;
+#define STDINBUF_SIZE 80
+ char stdinbuf[STDINBUF_SIZE];
+
+ progName = strrchr(argv[0], '/');
+ progName = progName ? progName + 1 : argv[0];
+
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ if (parse_args(argc, argv) != SUCCESS) {
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ if (verify_params() != SUCCESS) {
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ if (command == NO_COMMAND) {
+ PR_fprintf(PR_STDERR, errStrings[NO_COMMAND_ERR]);
+ usage();
+ errcode = INVALID_USAGE_ERR;
+ goto loser;
+ }
+
+ /* Set up crypto stuff */
+ createdb = command == CREATE_COMMAND;
+ readOnly = ((command == LIST_COMMAND) ||
+ (command == CHKFIPS_COMMAND) ||
+ (command == RAW_LIST_COMMAND));
+
+ /* Make sure browser is not running if we're writing to a database */
+ /* Do this before initializing crypto */
+ if (!readOnly && !force) {
+ char* response;
+
+ PR_fprintf(PR_STDOUT, msgStrings[BROWSER_RUNNING_MSG]);
+ if (!PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) {
+ PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]);
+ errcode = STDIN_READ_ERR;
+ goto loser;
+ }
+ if ((response = strtok(stdinbuf, " \r\n\t"))) {
+ if (!PL_strcasecmp(response, "q")) {
+ PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]);
+ errcode = SUCCESS;
+ goto loser;
+ }
+ }
+ PR_fprintf(PR_STDOUT, "\n");
+ }
+
+ errcode = check_crypto(createdb, readOnly);
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ if ((command == RAW_LIST_COMMAND) || (command == RAW_ADD_COMMAND)) {
+ if (!moduleName) {
+ char *readOnlyStr, *noCertDBStr, *sep;
+ if (!secmodName)
+ secmodName = "secmod.db";
+ if (!dbprefix)
+ dbprefix = "";
+ sep = ((command == RAW_LIST_COMMAND) && nocertdb) ? "," : " ";
+ readOnlyStr = (command == RAW_LIST_COMMAND) ? "readOnly" : "";
+ noCertDBStr = nocertdb ? "noCertDB" : "";
+ SECU_ConfigDirectory(dbdir);
+
+ moduleName = PR_smprintf(
+ "name=\"NSS default Module DB\" parameters=\"configdir=%s certPrefix=%s "
+ "keyPrefix=%s secmod=%s flags=%s%s%s\" NSS=\"flags=internal,moduleDB,"
+ "moduleDBOnly,critical\"",
+ SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
+ secmodName, readOnlyStr, sep, noCertDBStr);
+ }
+ if (command == RAW_LIST_COMMAND) {
+ errcode = RawListModule(moduleName);
+ } else {
+ PORT_Assert(moduleSpec);
+ errcode = RawAddModule(moduleName, moduleSpec);
+ }
+ goto loser;
+ }
+
+ errcode = init_crypto(createdb, readOnly);
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ errcode = LoadMechanismList();
+ if (errcode != SUCCESS) {
+ goto loser;
+ }
+
+ /* Warn if we are adding a module while p11-kit is enabled in the
+ * database. */
+ if ((command == ADD_COMMAND || command == RAW_ADD_COMMAND) &&
+ IsP11KitEnabled()) {
+ char* response;
+
+ PR_fprintf(PR_STDOUT, msgStrings[P11_KIT_ENABLED_MSG]);
+ if (!PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) {
+ PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]);
+ errcode = STDIN_READ_ERR;
+ goto loser;
+ }
+ if ((response = strtok(stdinbuf, " \r\n\t"))) {
+ if (!PL_strcasecmp(response, "q")) {
+ PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]);
+ errcode = SUCCESS;
+ goto loser;
+ }
+ }
+ PR_fprintf(PR_STDOUT, "\n");
+ }
+
+ /* Execute the command */
+ switch (command) {
+ case ADD_COMMAND:
+ errcode = AddModule(moduleName, libFile, ciphers, mechanisms, secmodString);
+ break;
+ case CHANGEPW_COMMAND:
+ errcode = ChangePW(tokenName, pwFile, newpwFile);
+ break;
+ case CREATE_COMMAND:
+ errcode = InitPW();
+ break;
+ case DEFAULT_COMMAND:
+ errcode = SetDefaultModule(moduleName, slotName, mechanisms);
+ break;
+ case DELETE_COMMAND:
+ errcode = DeleteModule(moduleName);
+ break;
+ case DISABLE_COMMAND:
+ errcode = EnableModule(moduleName, slotName, PR_FALSE);
+ break;
+ case ENABLE_COMMAND:
+ errcode = EnableModule(moduleName, slotName, PR_TRUE);
+ break;
+ case FIPS_COMMAND:
+ errcode = FipsMode(fipsArg);
+ break;
+ case CHKFIPS_COMMAND:
+ errcode = ChkFipsMode(fipsArg);
+ break;
+ case JAR_COMMAND:
+ Pk11Install_SetErrorHandler(install_error);
+ errcode = Pk11Install_DoInstall(jarFile, installDir, tempDir,
+ PR_STDOUT, force, nocertdb);
+ break;
+ case LIST_COMMAND:
+ if (moduleName) {
+ errcode = ListModule(moduleName);
+ } else {
+ errcode = ListModules();
+ }
+ break;
+ case UNDEFAULT_COMMAND:
+ errcode = UnsetDefaultModule(moduleName, slotName, mechanisms);
+ break;
+ default:
+ PR_fprintf(PR_STDERR, "This command is not supported yet.\n");
+ errcode = INVALID_USAGE_ERR;
+ break;
+ }
+
+ if (NSS_Shutdown() != SECSuccess) {
+ exit(1);
+ }
+
+loser:
+ PR_Cleanup();
+ return errcode;
+}
+
+/************************************************************************
+ *
+ * i n s t a l l _ e r r o r
+ *
+ * Callback function to handle errors in PK11 JAR file installation.
+ */
+static void
+install_error(char* message)
+{
+ PR_fprintf(PR_STDERR, "Install error: %s\n", message);
+}
+
+/*************************************************************************
+ *
+ * o u t _ o f _ m e m o r y
+ */
+void
+out_of_memory(void)
+{
+ PR_fprintf(PR_STDERR, errStrings[OUT_OF_MEM_ERR]);
+ exit(OUT_OF_MEM_ERR);
+}
+
+/**************************************************************************
+ *
+ * P R _ f g e t s
+ *
+ * fgets implemented with NSPR.
+ */
+static char*
+PR_fgets(char* buf, int size, PRFileDesc* file)
+{
+ int i;
+ int status;
+ char c;
+
+ i = 0;
+ while (i < size - 1) {
+ status = PR_Read(file, (void*)&c, 1);
+ if (status == -1) {
+ return NULL;
+ } else if (status == 0) {
+ break;
+ }
+ buf[i++] = c;
+ if (c == '\n') {
+ break;
+ }
+ }
+ buf[i] = '\0';
+
+ return buf;
+}