tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

modutil.c (35317B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /* To edit this file, set TABSTOPS to 4 spaces.
      6 * This is not the normal NSS convention.
      7 */
      8 
      9 #include "modutil.h"
     10 #include "install.h"
     11 #include <plstr.h>
     12 #include "certdb.h" /* for CERT_DB_FILE_VERSION */
     13 #include "nss.h"
     14 
     15 static void install_error(char* message);
     16 static char* PR_fgets(char* buf, int size, PRFileDesc* file);
     17 static char* progName;
     18 
     19 /* This enum must be kept in sync with the commandNames list */
     20 typedef enum {
     21    NO_COMMAND,
     22    ADD_COMMAND,
     23    CHANGEPW_COMMAND,
     24    CREATE_COMMAND,
     25    DEFAULT_COMMAND,
     26    DELETE_COMMAND,
     27    DISABLE_COMMAND,
     28    ENABLE_COMMAND,
     29    FIPS_COMMAND,
     30    JAR_COMMAND,
     31    LIST_COMMAND,
     32    RAW_LIST_COMMAND,
     33    RAW_ADD_COMMAND,
     34    CHKFIPS_COMMAND,
     35    UNDEFAULT_COMMAND
     36 } Command;
     37 
     38 /* This list must be kept in sync with the Command enum */
     39 static char* commandNames[] = {
     40    "(no command)",
     41    "-add",
     42    "-changepw",
     43    "-create",
     44    "-default",
     45    "-delete",
     46    "-disable",
     47    "-enable",
     48    "-fips",
     49    "-jar",
     50    "-list",
     51    "-rawlist",
     52    "-rawadd",
     53    "-chkfips",
     54    "-undefault"
     55 };
     56 
     57 /* this enum must be kept in sync with the optionStrings list */
     58 typedef enum {
     59    ADD_ARG = 0,
     60    RAW_ADD_ARG,
     61    CHANGEPW_ARG,
     62    CIPHERS_ARG,
     63    CREATE_ARG,
     64    DBDIR_ARG,
     65    DBPREFIX_ARG,
     66    DEFAULT_ARG,
     67    DELETE_ARG,
     68    DISABLE_ARG,
     69    ENABLE_ARG,
     70    FIPS_ARG,
     71    FORCE_ARG,
     72    JAR_ARG,
     73    LIBFILE_ARG,
     74    LIST_ARG,
     75    RAW_LIST_ARG,
     76    MECHANISMS_ARG,
     77    NEWPWFILE_ARG,
     78    PWFILE_ARG,
     79    SLOT_ARG,
     80    UNDEFAULT_ARG,
     81    INSTALLDIR_ARG,
     82    TEMPDIR_ARG,
     83    SECMOD_ARG,
     84    NOCERTDB_ARG,
     85    STRING_ARG,
     86    CHKFIPS_ARG,
     87 
     88    NUM_ARGS /* must be last */
     89 } Arg;
     90 
     91 /* This list must be kept in sync with the Arg enum */
     92 static char* optionStrings[] = {
     93    "-add",
     94    "-rawadd",
     95    "-changepw",
     96    "-ciphers",
     97    "-create",
     98    "-dbdir",
     99    "-dbprefix",
    100    "-default",
    101    "-delete",
    102    "-disable",
    103    "-enable",
    104    "-fips",
    105    "-force",
    106    "-jar",
    107    "-libfile",
    108    "-list",
    109    "-rawlist",
    110    "-mechanisms",
    111    "-newpwfile",
    112    "-pwfile",
    113    "-slot",
    114    "-undefault",
    115    "-installdir",
    116    "-tempdir",
    117    "-secmod",
    118    "-nocertdb",
    119    "-string",
    120    "-chkfips",
    121 };
    122 
    123 char* msgStrings[] = {
    124    "FIPS mode enabled.\n",
    125    "FIPS mode disabled.\n",
    126    "Using database directory %s...\n",
    127    "Creating \"%s\"...",
    128    "Module \"%s\" added to database.\n",
    129    "Module \"%s\" deleted from database.\n",
    130    "Token \"%s\" password changed successfully.\n",
    131    "Incorrect password, try again...\n",
    132    "Passwords do not match, try again...\n",
    133    "done.\n",
    134    "Slot \"%s\" %s.\n",
    135    "Successfully changed defaults.\n",
    136    "Successfully changed defaults.\n",
    137    "\nWARNING: Performing this operation while the browser is running could cause"
    138    "\ncorruption of your security databases. If the browser is currently running,"
    139    "\nyou should exit browser before continuing this operation. Type "
    140    "\n'q <enter>' to abort, or <enter> to continue: ",
    141    "\nAborting...\n",
    142    "\nWARNING: Manually adding a module while p11-kit is enabled could cause"
    143    "\nduplicate module registration in your security database. It is suggested "
    144    "\nto configure the module through p11-kit configuration file instead.\n"
    145    "\nType 'q <enter>' to abort, or <enter> to continue: "
    146 };
    147 
    148 /* Increment i if doing so would have i still be less than j.  If you
    149   are able to do this, return 0.  Otherwise return 1. */
    150 #define TRY_INC(i, j) (((i + 1) < j) ? (++i, 0) : 1)
    151 
    152 /********************************************************************
    153 *
    154 * file-wide variables obtained from the command line
    155 */
    156 static Command command = NO_COMMAND;
    157 static char* pwFile = NULL;
    158 static char* newpwFile = NULL;
    159 static char* moduleName = NULL;
    160 static char* moduleSpec = NULL;
    161 static char* slotName = NULL;
    162 static char* secmodName = NULL;
    163 static char* tokenName = NULL;
    164 static char* libFile = NULL;
    165 static char* dbdir = NULL;
    166 static char* dbprefix = "";
    167 static char* secmodString = NULL;
    168 static char* mechanisms = NULL;
    169 static char* ciphers = NULL;
    170 static char* fipsArg = NULL;
    171 static char* jarFile = NULL;
    172 static char* installDir = NULL;
    173 static char* tempDir = NULL;
    174 static short force = 0;
    175 static PRBool nocertdb = PR_FALSE;
    176 
    177 /*******************************************************************
    178 *
    179 * p a r s e _ a r g s
    180 */
    181 static Error
    182 parse_args(int argc, char* argv[])
    183 {
    184    int i;
    185    char* arg;
    186    int optionType;
    187 
    188    /* Loop over all arguments */
    189    for (i = 1; i < argc; i++) {
    190        arg = argv[i];
    191 
    192        /* Make sure this is an option and not some floating argument */
    193        if (arg[0] != '-') {
    194            PR_fprintf(PR_STDERR, errStrings[UNEXPECTED_ARG_ERR], argv[i]);
    195            return UNEXPECTED_ARG_ERR;
    196        }
    197 
    198        /* Find which option this is */
    199        for (optionType = 0; optionType < NUM_ARGS; optionType++) {
    200            if (!strcmp(arg, optionStrings[optionType])) {
    201                break;
    202            }
    203        }
    204 
    205        /* Deal with this specific option */
    206        switch (optionType) {
    207            case NUM_ARGS:
    208            default:
    209                PR_fprintf(PR_STDERR, errStrings[UNKNOWN_OPTION_ERR], arg);
    210                return UNKNOWN_OPTION_ERR;
    211                break;
    212            case ADD_ARG:
    213                if (command != NO_COMMAND) {
    214                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    215                    return MULTIPLE_COMMAND_ERR;
    216                }
    217                command = ADD_COMMAND;
    218                if (TRY_INC(i, argc)) {
    219                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    220                    return OPTION_NEEDS_ARG_ERR;
    221                }
    222                moduleName = argv[i];
    223                break;
    224            case CHANGEPW_ARG:
    225                if (command != NO_COMMAND) {
    226                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    227                    return MULTIPLE_COMMAND_ERR;
    228                }
    229                command = CHANGEPW_COMMAND;
    230                if (TRY_INC(i, argc)) {
    231                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    232                    return OPTION_NEEDS_ARG_ERR;
    233                }
    234                tokenName = argv[i];
    235                break;
    236            case CIPHERS_ARG:
    237                if (ciphers != NULL) {
    238                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    239                    return DUPLICATE_OPTION_ERR;
    240                }
    241                if (TRY_INC(i, argc)) {
    242                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    243                    return OPTION_NEEDS_ARG_ERR;
    244                }
    245                ciphers = argv[i];
    246                break;
    247            case CREATE_ARG:
    248                if (command != NO_COMMAND) {
    249                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    250                    return MULTIPLE_COMMAND_ERR;
    251                }
    252                command = CREATE_COMMAND;
    253                break;
    254            case DBDIR_ARG:
    255                if (dbdir != NULL) {
    256                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    257                    return DUPLICATE_OPTION_ERR;
    258                }
    259                if (TRY_INC(i, argc)) {
    260                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    261                    return OPTION_NEEDS_ARG_ERR;
    262                }
    263                dbdir = argv[i];
    264                break;
    265            case DBPREFIX_ARG:
    266                if (TRY_INC(i, argc)) {
    267                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    268                    return OPTION_NEEDS_ARG_ERR;
    269                }
    270                dbprefix = argv[i];
    271                break;
    272            case UNDEFAULT_ARG:
    273            case DEFAULT_ARG:
    274                if (command != NO_COMMAND) {
    275                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    276                    return MULTIPLE_COMMAND_ERR;
    277                }
    278                if (optionType == DEFAULT_ARG) {
    279                    command = DEFAULT_COMMAND;
    280                } else {
    281                    command = UNDEFAULT_COMMAND;
    282                }
    283                if (TRY_INC(i, argc)) {
    284                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    285                    return OPTION_NEEDS_ARG_ERR;
    286                }
    287                moduleName = argv[i];
    288                break;
    289            case DELETE_ARG:
    290                if (command != NO_COMMAND) {
    291                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    292                    return MULTIPLE_COMMAND_ERR;
    293                }
    294                command = DELETE_COMMAND;
    295                if (TRY_INC(i, argc)) {
    296                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    297                    return OPTION_NEEDS_ARG_ERR;
    298                }
    299                moduleName = argv[i];
    300                break;
    301            case DISABLE_ARG:
    302                if (command != NO_COMMAND) {
    303                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    304                    return MULTIPLE_COMMAND_ERR;
    305                }
    306                command = DISABLE_COMMAND;
    307                if (TRY_INC(i, argc)) {
    308                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    309                    return OPTION_NEEDS_ARG_ERR;
    310                }
    311                moduleName = argv[i];
    312                break;
    313            case ENABLE_ARG:
    314                if (command != NO_COMMAND) {
    315                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    316                    return MULTIPLE_COMMAND_ERR;
    317                }
    318                command = ENABLE_COMMAND;
    319                if (TRY_INC(i, argc)) {
    320                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    321                    return OPTION_NEEDS_ARG_ERR;
    322                }
    323                moduleName = argv[i];
    324                break;
    325            case FIPS_ARG:
    326                if (command != NO_COMMAND) {
    327                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    328                    return MULTIPLE_COMMAND_ERR;
    329                }
    330                command = FIPS_COMMAND;
    331                if (TRY_INC(i, argc)) {
    332                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    333                    return OPTION_NEEDS_ARG_ERR;
    334                }
    335                fipsArg = argv[i];
    336                break;
    337            case CHKFIPS_ARG:
    338                if (command != NO_COMMAND) {
    339                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    340                    return MULTIPLE_COMMAND_ERR;
    341                }
    342                command = CHKFIPS_COMMAND;
    343                if (TRY_INC(i, argc)) {
    344                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    345                    return OPTION_NEEDS_ARG_ERR;
    346                }
    347                fipsArg = argv[i];
    348                break;
    349            case FORCE_ARG:
    350                force = 1;
    351                break;
    352            case NOCERTDB_ARG:
    353                nocertdb = PR_TRUE;
    354                break;
    355            case INSTALLDIR_ARG:
    356                if (installDir != NULL) {
    357                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    358                    return DUPLICATE_OPTION_ERR;
    359                }
    360                if (TRY_INC(i, argc)) {
    361                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    362                    return OPTION_NEEDS_ARG_ERR;
    363                }
    364                installDir = argv[i];
    365                break;
    366            case TEMPDIR_ARG:
    367                if (tempDir != NULL) {
    368                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    369                    return DUPLICATE_OPTION_ERR;
    370                }
    371                if (TRY_INC(i, argc)) {
    372                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    373                    return OPTION_NEEDS_ARG_ERR;
    374                }
    375                tempDir = argv[i];
    376                break;
    377            case JAR_ARG:
    378                if (command != NO_COMMAND) {
    379                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    380                    return MULTIPLE_COMMAND_ERR;
    381                }
    382                command = JAR_COMMAND;
    383                if (TRY_INC(i, argc)) {
    384                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    385                    return OPTION_NEEDS_ARG_ERR;
    386                }
    387                jarFile = argv[i];
    388                break;
    389            case LIBFILE_ARG:
    390                if (libFile != NULL) {
    391                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    392                    return DUPLICATE_OPTION_ERR;
    393                }
    394                if (TRY_INC(i, argc)) {
    395                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    396                    return OPTION_NEEDS_ARG_ERR;
    397                }
    398                libFile = argv[i];
    399                break;
    400            case LIST_ARG:
    401                if (command != NO_COMMAND) {
    402                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    403                    return MULTIPLE_COMMAND_ERR;
    404                }
    405                command = LIST_COMMAND;
    406                /* This option may or may not have an argument */
    407                if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
    408                    moduleName = argv[++i];
    409                }
    410                break;
    411            case RAW_LIST_ARG:
    412                if (command != NO_COMMAND) {
    413                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    414                    return MULTIPLE_COMMAND_ERR;
    415                }
    416                command = RAW_LIST_COMMAND;
    417                /* This option may or may not have an argument */
    418                if ((i + 1 < argc) && (argv[i + 1][0] != '-')) {
    419                    moduleName = argv[++i];
    420                }
    421                break;
    422            case RAW_ADD_ARG:
    423                if (command != NO_COMMAND) {
    424                    PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg);
    425                    return MULTIPLE_COMMAND_ERR;
    426                }
    427                command = RAW_ADD_COMMAND;
    428                if (TRY_INC(i, argc)) {
    429                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    430                    return OPTION_NEEDS_ARG_ERR;
    431                }
    432                moduleSpec = argv[i];
    433                break;
    434            case MECHANISMS_ARG:
    435                if (mechanisms != NULL) {
    436                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    437                    return DUPLICATE_OPTION_ERR;
    438                }
    439                if (TRY_INC(i, argc)) {
    440                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    441                    return OPTION_NEEDS_ARG_ERR;
    442                }
    443                mechanisms = argv[i];
    444                break;
    445            case NEWPWFILE_ARG:
    446                if (newpwFile != NULL) {
    447                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    448                    return DUPLICATE_OPTION_ERR;
    449                }
    450                if (TRY_INC(i, argc)) {
    451                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    452                    return OPTION_NEEDS_ARG_ERR;
    453                }
    454                newpwFile = argv[i];
    455                break;
    456            case PWFILE_ARG:
    457                if (pwFile != NULL) {
    458                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    459                    return DUPLICATE_OPTION_ERR;
    460                }
    461                if (TRY_INC(i, argc)) {
    462                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    463                    return OPTION_NEEDS_ARG_ERR;
    464                }
    465                pwFile = argv[i];
    466                break;
    467            case SLOT_ARG:
    468                if (slotName != NULL) {
    469                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    470                    return DUPLICATE_OPTION_ERR;
    471                }
    472                if (TRY_INC(i, argc)) {
    473                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    474                    return OPTION_NEEDS_ARG_ERR;
    475                }
    476                slotName = argv[i];
    477                break;
    478            case SECMOD_ARG:
    479                if (secmodName != NULL) {
    480                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    481                    return DUPLICATE_OPTION_ERR;
    482                }
    483                if (TRY_INC(i, argc)) {
    484                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    485                    return OPTION_NEEDS_ARG_ERR;
    486                }
    487                secmodName = argv[i];
    488                break;
    489            case STRING_ARG:
    490                if (secmodString != NULL) {
    491                    PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg);
    492                    return DUPLICATE_OPTION_ERR;
    493                }
    494                if (TRY_INC(i, argc)) {
    495                    PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg);
    496                    return OPTION_NEEDS_ARG_ERR;
    497                }
    498                secmodString = argv[i];
    499                break;
    500        }
    501    }
    502    return SUCCESS;
    503 }
    504 
    505 /************************************************************************
    506 *
    507 * v e r i f y _ p a r a m s
    508 */
    509 static Error
    510 verify_params()
    511 {
    512    switch (command) {
    513        case ADD_COMMAND:
    514            if (libFile == NULL) {
    515                PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
    516                           commandNames[ADD_COMMAND], optionStrings[LIBFILE_ARG]);
    517                return MISSING_PARAM_ERR;
    518            }
    519            break;
    520        case CHANGEPW_COMMAND:
    521            break;
    522        case CREATE_COMMAND:
    523            break;
    524        case DELETE_COMMAND:
    525            break;
    526        case DISABLE_COMMAND:
    527            break;
    528        case ENABLE_COMMAND:
    529            break;
    530        case FIPS_COMMAND:
    531        case CHKFIPS_COMMAND:
    532            if (PL_strcasecmp(fipsArg, "true") &&
    533                PL_strcasecmp(fipsArg, "false")) {
    534                PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]);
    535                return INVALID_FIPS_ARG;
    536            }
    537            break;
    538        case JAR_COMMAND:
    539            if (installDir == NULL) {
    540                PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
    541                           commandNames[JAR_COMMAND], optionStrings[INSTALLDIR_ARG]);
    542                return MISSING_PARAM_ERR;
    543            }
    544            break;
    545        case LIST_COMMAND:
    546        case RAW_LIST_COMMAND:
    547            break;
    548        case RAW_ADD_COMMAND:
    549            break;
    550        case UNDEFAULT_COMMAND:
    551        case DEFAULT_COMMAND:
    552            if (mechanisms == NULL) {
    553                PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR],
    554                           commandNames[command], optionStrings[MECHANISMS_ARG]);
    555                return MISSING_PARAM_ERR;
    556            }
    557            break;
    558        default:
    559            /* Ignore this here */
    560            break;
    561    }
    562 
    563    return SUCCESS;
    564 }
    565 
    566 /********************************************************************
    567 *
    568 * i n i t _ c r y p t o
    569 *
    570 * Does crypto initialization that all commands will require.
    571 * If -nocertdb option is specified, don't open key or cert db (we don't
    572 * need them if we aren't going to be verifying signatures).  This is
    573 * because serverland doesn't always have cert and key database files
    574 * available.
    575 *
    576 * This function is ill advised. Names and locations of databases are
    577 * private to NSS proper. Such functions only confuse other users.
    578 *
    579 */
    580 static Error
    581 check_crypto(PRBool create, PRBool readOnly)
    582 {
    583    char* dir;
    584    char* moddbname = NULL;
    585    Error retval;
    586    static const char multiaccess[] = { "multiaccess:" };
    587 
    588    dir = SECU_ConfigDirectory(dbdir); /* dir is never NULL */
    589    if (dir[0] == '\0') {
    590        PR_fprintf(PR_STDERR, errStrings[NO_DBDIR_ERR]);
    591        retval = NO_DBDIR_ERR;
    592        goto loser;
    593    }
    594    if (strncmp(dir, multiaccess, sizeof multiaccess - 1) == 0) {
    595        /* won't attempt to handle the multiaccess case. */
    596        return SUCCESS;
    597    }
    598 #ifdef notdef
    599    /* Make sure db directory exists and is readable */
    600    if (PR_Access(dir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
    601        PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dir);
    602        retval = DIR_DOESNT_EXIST_ERR;
    603        goto loser;
    604    } else if (PR_Access(dir, PR_ACCESS_READ_OK) != PR_SUCCESS) {
    605        PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dir);
    606        retval = DIR_NOT_READABLE_ERR;
    607        goto loser;
    608    }
    609 
    610    if (secmodName == NULL) {
    611        secmodName = "secmod.db";
    612    }
    613 
    614    moddbname = PR_smprintf("%s/%s", dir, secmodName);
    615    if (!moddbname)
    616        return OUT_OF_MEM_ERR;
    617 
    618    /* Check for the proper permissions on databases */
    619    if (create) {
    620        /* Make sure dbs don't already exist, and the directory is
    621            writeable */
    622        if (PR_Access(moddbname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
    623            PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR],
    624                       moddbname);
    625            retval = FILE_ALREADY_EXISTS_ERR;
    626            goto loser;
    627        } else if (PR_Access(dir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
    628            PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dir);
    629            retval = DIR_NOT_WRITEABLE_ERR;
    630            goto loser;
    631        }
    632    } else {
    633        /* Make sure dbs are readable and writeable */
    634        if (PR_Access(moddbname, PR_ACCESS_READ_OK) != PR_SUCCESS) {
    635            PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], moddbname);
    636            retval = FILE_NOT_READABLE_ERR;
    637            goto loser;
    638        }
    639 
    640        /* Check for write access if we'll be making changes */
    641        if (!readOnly) {
    642            if (PR_Access(moddbname, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
    643                PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR],
    644                           moddbname);
    645                retval = FILE_NOT_WRITEABLE_ERR;
    646                goto loser;
    647            }
    648        }
    649        PR_fprintf(PR_STDOUT, msgStrings[USING_DBDIR_MSG],
    650                   SECU_ConfigDirectory(NULL));
    651    }
    652 #endif
    653    retval = SUCCESS;
    654 loser:
    655    if (moddbname) {
    656        PR_Free(moddbname);
    657    }
    658    return retval;
    659 }
    660 
    661 static Error
    662 init_crypto(PRBool create, PRBool readOnly)
    663 {
    664 
    665    PRUint32 flags = 0;
    666    SECStatus rv;
    667    Error retval;
    668    /* Open/create key database */
    669 
    670    if (readOnly)
    671        flags |= NSS_INIT_READONLY;
    672    if (nocertdb)
    673        flags |= NSS_INIT_NOCERTDB;
    674    rv = NSS_Initialize(SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
    675                        secmodName, flags);
    676    if (rv != SECSuccess) {
    677        SECU_PrintPRandOSError(progName);
    678        retval = NSS_INITIALIZE_FAILED_ERR;
    679    } else
    680        retval = SUCCESS;
    681 
    682    return retval;
    683 }
    684 
    685 /*************************************************************************
    686 *
    687 * u s a g e
    688 */
    689 static void
    690 usage()
    691 {
    692    PR_fprintf(PR_STDOUT,
    693               "\nNetscape Cryptographic Module Utility\n"
    694               "Usage: modutil [command] [options]\n\n"
    695               "                            COMMANDS\n"
    696               "---------------------------------------------------------------------------\n"
    697               "-add MODULE_NAME                 Add the named module to the module database\n"
    698               "   -libfile LIBRARY_FILE         The name of the file (.so or .dll)\n"
    699               "                                 containing the implementation of PKCS #11\n"
    700               "   [-ciphers CIPHER_LIST]        Enable the given ciphers on this module\n"
    701               "   [-mechanisms MECHANISM_LIST]  Make the module a default provider of the\n"
    702               "                                 given mechanisms\n"
    703               "   [-string CONFIG_STRING]       Pass a configuration string to this module\n"
    704               "-changepw TOKEN                  Change the password on the named token\n"
    705               "   [-pwfile FILE]                The old password is in this file\n"
    706               "   [-newpwfile FILE]             The new password is in this file\n"
    707               "-chkfips [ true | false ]        If true, verify  FIPS mode.  If false,\n"
    708               "                                 verify not FIPS mode\n"
    709               "-create                          Create a new set of security databases\n"
    710               "-default MODULE                  Make the given module a default provider\n"
    711               "   -mechanisms MECHANISM_LIST    of the given mechanisms\n"
    712               "   [-slot SLOT]                  limit change to only the given slot\n"
    713               "-delete MODULE                   Remove the named module from the module\n"
    714               "                                 database\n"
    715               "-disable MODULE                  Disable the named module\n"
    716               "   [-slot SLOT]                  Disable only the named slot on the module\n"
    717               "-enable MODULE                   Enable the named module\n"
    718               "   [-slot SLOT]                  Enable only the named slot on the module\n"
    719               "-fips [ true | false ]           If true, enable FIPS mode.  If false,\n"
    720               "                                 disable FIPS mode\n"
    721               "-force                           Do not run interactively\n"
    722               "-jar JARFILE                     Install a PKCS #11 module from the given\n"
    723               "                                 JAR file in the PKCS #11 JAR format\n"
    724               "   -installdir DIR               Use DIR as the root directory of the\n"
    725               "                                 installation\n"
    726               "   [-tempdir DIR]                Use DIR as the temporary installation\n"
    727               "                                 directory. If not specified, the current\n"
    728               "                                 directory is used\n"
    729               "-list [MODULE]                   Lists information about the specified module\n"
    730               "                                 or about all modules if none is specified\n"
    731               "-rawadd MODULESPEC               Add module spec string to secmod DB\n"
    732               "-rawlist [MODULE]                Display module spec(s) for one or all\n"
    733               "                                 loadable modules\n"
    734               "-undefault MODULE                The given module is NOT a default provider\n"
    735               "   -mechanisms MECHANISM_LIST    of the listed mechanisms\n"
    736               "   [-slot SLOT]                  limit change to only the given slot\n"
    737               "---------------------------------------------------------------------------\n"
    738               "\n"
    739               "                             OPTIONS\n"
    740               "---------------------------------------------------------------------------\n"
    741               "-dbdir DIR                       Directory DIR contains the security databases\n"
    742               "-dbprefix prefix                 Prefix for the security databases\n"
    743               "-nocertdb                        Do not load certificate or key databases. No\n"
    744               "                                 verification will be performed on JAR files.\n"
    745               "-secmod secmodName               Name of the security modules file\n"
    746               "---------------------------------------------------------------------------\n"
    747               "\n"
    748               "Mechanism lists are colon-separated.  The following mechanisms are recognized:\n"
    749               "RSA, DSA, DH, RC2, RC4, RC5, AES, CAMELLIA, DES, MD2, MD5, SHA1, SHA256, SHA512,\n"
    750               "SSL, TLS, RANDOM, and FRIENDLY\n"
    751               "\n"
    752               "Cipher lists are colon-separated.  The following ciphers are recognized:\n"
    753               "\n"
    754               "\nQuestions or bug reports should be sent to modutil-support@netscape.com.\n");
    755 }
    756 
    757 /*************************************************************************
    758 *
    759 * m a i n
    760 */
    761 int
    762 main(int argc, char* argv[])
    763 {
    764    int errcode = SUCCESS;
    765    PRBool createdb, readOnly;
    766 #define STDINBUF_SIZE 80
    767    char stdinbuf[STDINBUF_SIZE];
    768 
    769    progName = strrchr(argv[0], '/');
    770    progName = progName ? progName + 1 : argv[0];
    771 
    772    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
    773 
    774    if (parse_args(argc, argv) != SUCCESS) {
    775        usage();
    776        errcode = INVALID_USAGE_ERR;
    777        goto loser;
    778    }
    779 
    780    if (verify_params() != SUCCESS) {
    781        usage();
    782        errcode = INVALID_USAGE_ERR;
    783        goto loser;
    784    }
    785 
    786    if (command == NO_COMMAND) {
    787        PR_fprintf(PR_STDERR, errStrings[NO_COMMAND_ERR]);
    788        usage();
    789        errcode = INVALID_USAGE_ERR;
    790        goto loser;
    791    }
    792 
    793    /* Set up crypto stuff */
    794    createdb = command == CREATE_COMMAND;
    795    readOnly = ((command == LIST_COMMAND) ||
    796                (command == CHKFIPS_COMMAND) ||
    797                (command == RAW_LIST_COMMAND));
    798 
    799    /* Make sure browser is not running if we're writing to a database */
    800    /* Do this before initializing crypto */
    801    if (!readOnly && !force) {
    802        char* response;
    803 
    804        PR_fprintf(PR_STDOUT, msgStrings[BROWSER_RUNNING_MSG]);
    805        if (!PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) {
    806            PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]);
    807            errcode = STDIN_READ_ERR;
    808            goto loser;
    809        }
    810        if ((response = strtok(stdinbuf, " \r\n\t"))) {
    811            if (!PL_strcasecmp(response, "q")) {
    812                PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]);
    813                errcode = SUCCESS;
    814                goto loser;
    815            }
    816        }
    817        PR_fprintf(PR_STDOUT, "\n");
    818    }
    819 
    820    errcode = check_crypto(createdb, readOnly);
    821    if (errcode != SUCCESS) {
    822        goto loser;
    823    }
    824 
    825    if ((command == RAW_LIST_COMMAND) || (command == RAW_ADD_COMMAND)) {
    826        if (!moduleName) {
    827            char *readOnlyStr, *noCertDBStr, *sep;
    828            if (!secmodName)
    829                secmodName = "secmod.db";
    830            if (!dbprefix)
    831                dbprefix = "";
    832            sep = ((command == RAW_LIST_COMMAND) && nocertdb) ? "," : " ";
    833            readOnlyStr = (command == RAW_LIST_COMMAND) ? "readOnly" : "";
    834            noCertDBStr = nocertdb ? "noCertDB" : "";
    835            SECU_ConfigDirectory(dbdir);
    836 
    837            moduleName = PR_smprintf(
    838                "name=\"NSS default Module DB\" parameters=\"configdir=%s certPrefix=%s "
    839                "keyPrefix=%s secmod=%s flags=%s%s%s\" NSS=\"flags=internal,moduleDB,"
    840                "moduleDBOnly,critical\"",
    841                SECU_ConfigDirectory(NULL), dbprefix, dbprefix,
    842                secmodName, readOnlyStr, sep, noCertDBStr);
    843        }
    844        if (command == RAW_LIST_COMMAND) {
    845            errcode = RawListModule(moduleName);
    846        } else {
    847            PORT_Assert(moduleSpec);
    848            errcode = RawAddModule(moduleName, moduleSpec);
    849        }
    850        goto loser;
    851    }
    852 
    853    errcode = init_crypto(createdb, readOnly);
    854    if (errcode != SUCCESS) {
    855        goto loser;
    856    }
    857 
    858    errcode = LoadMechanismList();
    859    if (errcode != SUCCESS) {
    860        goto loser;
    861    }
    862 
    863    /* Warn if we are adding a module while p11-kit is enabled in the
    864     * database. */
    865    if ((command == ADD_COMMAND || command == RAW_ADD_COMMAND) &&
    866        IsP11KitEnabled()) {
    867        char* response;
    868 
    869        PR_fprintf(PR_STDOUT, msgStrings[P11_KIT_ENABLED_MSG]);
    870        if (!PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) {
    871            PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]);
    872            errcode = STDIN_READ_ERR;
    873            goto loser;
    874        }
    875        if ((response = strtok(stdinbuf, " \r\n\t"))) {
    876            if (!PL_strcasecmp(response, "q")) {
    877                PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]);
    878                errcode = SUCCESS;
    879                goto loser;
    880            }
    881        }
    882        PR_fprintf(PR_STDOUT, "\n");
    883    }
    884 
    885    /* Execute the command */
    886    switch (command) {
    887        case ADD_COMMAND:
    888            errcode = AddModule(moduleName, libFile, ciphers, mechanisms, secmodString);
    889            break;
    890        case CHANGEPW_COMMAND:
    891            errcode = ChangePW(tokenName, pwFile, newpwFile);
    892            break;
    893        case CREATE_COMMAND:
    894            errcode = InitPW();
    895            break;
    896        case DEFAULT_COMMAND:
    897            errcode = SetDefaultModule(moduleName, slotName, mechanisms);
    898            break;
    899        case DELETE_COMMAND:
    900            errcode = DeleteModule(moduleName);
    901            break;
    902        case DISABLE_COMMAND:
    903            errcode = EnableModule(moduleName, slotName, PR_FALSE);
    904            break;
    905        case ENABLE_COMMAND:
    906            errcode = EnableModule(moduleName, slotName, PR_TRUE);
    907            break;
    908        case FIPS_COMMAND:
    909            errcode = FipsMode(fipsArg);
    910            break;
    911        case CHKFIPS_COMMAND:
    912            errcode = ChkFipsMode(fipsArg);
    913            break;
    914        case JAR_COMMAND:
    915            Pk11Install_SetErrorHandler(install_error);
    916            errcode = Pk11Install_DoInstall(jarFile, installDir, tempDir,
    917                                            PR_STDOUT, force, nocertdb);
    918            break;
    919        case LIST_COMMAND:
    920            if (moduleName) {
    921                errcode = ListModule(moduleName);
    922            } else {
    923                errcode = ListModules();
    924            }
    925            break;
    926        case UNDEFAULT_COMMAND:
    927            errcode = UnsetDefaultModule(moduleName, slotName, mechanisms);
    928            break;
    929        default:
    930            PR_fprintf(PR_STDERR, "This command is not supported yet.\n");
    931            errcode = INVALID_USAGE_ERR;
    932            break;
    933    }
    934 
    935    if (NSS_Shutdown() != SECSuccess) {
    936        exit(1);
    937    }
    938 
    939 loser:
    940    PR_Cleanup();
    941    return errcode;
    942 }
    943 
    944 /************************************************************************
    945 *
    946 * i n s t a l l _ e r r o r
    947 *
    948 * Callback function to handle errors in PK11 JAR file installation.
    949 */
    950 static void
    951 install_error(char* message)
    952 {
    953    PR_fprintf(PR_STDERR, "Install error: %s\n", message);
    954 }
    955 
    956 /*************************************************************************
    957 *
    958 * o u t _ o f _ m e m o r y
    959 */
    960 void
    961 out_of_memory(void)
    962 {
    963    PR_fprintf(PR_STDERR, errStrings[OUT_OF_MEM_ERR]);
    964    exit(OUT_OF_MEM_ERR);
    965 }
    966 
    967 /**************************************************************************
    968 *
    969 * P R _ f g e t s
    970 *
    971 * fgets implemented with NSPR.
    972 */
    973 static char*
    974 PR_fgets(char* buf, int size, PRFileDesc* file)
    975 {
    976    int i;
    977    int status;
    978    char c;
    979 
    980    i = 0;
    981    while (i < size - 1) {
    982        status = PR_Read(file, (void*)&c, 1);
    983        if (status == -1) {
    984            return NULL;
    985        } else if (status == 0) {
    986            break;
    987        }
    988        buf[i++] = c;
    989        if (c == '\n') {
    990            break;
    991        }
    992    }
    993    buf[i] = '\0';
    994 
    995    return buf;
    996 }