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