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
parse_args(int argc,char * argv[])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
verify_params()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
check_crypto(PRBool create,PRBool readOnly)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
init_crypto(PRBool create,PRBool readOnly)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
usage()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
main(int argc,char * argv[])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
install_error(char * message)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
out_of_memory(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*
PR_fgets(char * buf,int size,PRFileDesc * file)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 }
997