|
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 #include <stdio.h> |
|
6 #include <string.h> |
|
7 #include <stdlib.h> |
|
8 #include "nss.h" |
|
9 #include "secutil.h" |
|
10 #include "pk11pub.h" |
|
11 #include "cert.h" |
|
12 |
|
13 typedef struct commandDescriptStr { |
|
14 int required; |
|
15 char *arg; |
|
16 char *des; |
|
17 } commandDescript; |
|
18 |
|
19 enum optionNames { |
|
20 opt_liborder = 0, |
|
21 opt_mainDB, |
|
22 opt_lib1DB, |
|
23 opt_lib2DB, |
|
24 opt_mainRO, |
|
25 opt_lib1RO, |
|
26 opt_lib2RO, |
|
27 opt_mainCMD, |
|
28 opt_lib1CMD, |
|
29 opt_lib2CMD, |
|
30 opt_mainTokNam, |
|
31 opt_lib1TokNam, |
|
32 opt_lib2TokNam, |
|
33 opt_oldStyle, |
|
34 opt_verbose, |
|
35 opt_summary, |
|
36 opt_help, |
|
37 opt_last |
|
38 }; |
|
39 |
|
40 |
|
41 static const |
|
42 secuCommandFlag options_init[] = |
|
43 { |
|
44 { /* opt_liborder */ 'o', PR_TRUE, "1M2zmi", PR_TRUE, "order" }, |
|
45 { /* opt_mainDB */ 'd', PR_TRUE, 0, PR_FALSE, "main_db" }, |
|
46 { /* opt_lib1DB */ '1', PR_TRUE, 0, PR_FALSE, "lib1_db" }, |
|
47 { /* opt_lib2DB */ '2', PR_TRUE, 0, PR_FALSE, "lib2_db" }, |
|
48 { /* opt_mainRO */ 'r', PR_FALSE, 0, PR_FALSE, "main_readonly" }, |
|
49 { /* opt_lib1RO */ 0, PR_FALSE, 0, PR_FALSE, "lib1_readonly" }, |
|
50 { /* opt_lib2RO */ 0, PR_FALSE, 0, PR_FALSE, "lib2_readonly" }, |
|
51 { /* opt_mainCMD */ 'c', PR_TRUE, 0, PR_FALSE, "main_command" }, |
|
52 { /* opt_lib1CMD */ 0, PR_TRUE, 0, PR_FALSE, "lib1_command" }, |
|
53 { /* opt_lib2CMD */ 0, PR_TRUE, 0, PR_FALSE, "lib2_command" }, |
|
54 { /* opt_mainTokNam */'t', PR_TRUE, 0, PR_FALSE, "main_token_name" }, |
|
55 { /* opt_lib1TokNam */ 0, PR_TRUE, 0, PR_FALSE, "lib1_token_name" }, |
|
56 { /* opt_lib2TokNam */ 0, PR_TRUE, 0, PR_FALSE, "lib2_token_name" }, |
|
57 { /* opt_oldStype */ 's', PR_FALSE, 0, PR_FALSE, "oldStype" }, |
|
58 { /* opt_verbose */ 'v', PR_FALSE, 0, PR_FALSE, "verbose" }, |
|
59 { /* opt_summary */ 'z', PR_FALSE, 0, PR_FALSE, "summary" }, |
|
60 { /* opt_help */ 'h', PR_FALSE, 0, PR_FALSE, "help" } |
|
61 }; |
|
62 |
|
63 static const |
|
64 commandDescript options_des[] = |
|
65 { |
|
66 { /* opt_liborder */ PR_FALSE, "initOrder", |
|
67 " Specifies the order of NSS initialization and shutdown. Order is\n" |
|
68 " given as a string where each character represents either an init or\n" |
|
69 " a shutdown of the main program or one of the 2 test libraries\n" |
|
70 " (library 1 and library 2). The valid characters are as follows:\n" |
|
71 " M Init the main program\n 1 Init library 1\n" |
|
72 " 2 Init library 2\n" |
|
73 " m Shutdown the main program\n i Shutdown library 1\n" |
|
74 " z Shutdown library 2\n" }, |
|
75 { /* opt_mainDB */ PR_TRUE, "nss_db", |
|
76 " Specified the directory to open the nss database for the main\n" |
|
77 " program. Must be specified if \"M\" is given in the order string\n"}, |
|
78 { /* opt_lib1DB */ PR_FALSE, "nss_db", |
|
79 " Specified the directory to open the nss database for library 1.\n" |
|
80 " Must be specified if \"1\" is given in the order string\n"}, |
|
81 { /* opt_lib2DB */ PR_FALSE, "nss_db", |
|
82 " Specified the directory to open the nss database for library 2.\n" |
|
83 " Must be specified if \"2\" is given in the order string\n"}, |
|
84 { /* opt_mainRO */ PR_FALSE, NULL, |
|
85 " Open the main program's database read only.\n" }, |
|
86 { /* opt_lib1RO */ PR_FALSE, NULL, |
|
87 " Open library 1's database read only.\n" }, |
|
88 { /* opt_lib2RO */ PR_FALSE, NULL, |
|
89 " Open library 2's database read only.\n" }, |
|
90 { /* opt_mainCMD */ PR_FALSE, "nss_command", |
|
91 " Specifies the NSS command to execute in the main program.\n" |
|
92 " Valid commands are: \n" |
|
93 " key_slot, list_slots, list_certs, add_cert, none.\n" |
|
94 " Default is \"none\".\n" }, |
|
95 { /* opt_lib1CMD */ PR_FALSE, "nss_command", |
|
96 " Specifies the NSS command to execute in library 1.\n" }, |
|
97 { /* opt_lib2CMD */ PR_FALSE, "nss_command", |
|
98 " Specifies the NSS command to execute in library 2.\n" }, |
|
99 { /* opt_mainTokNam */PR_FALSE, "token_name", |
|
100 " Specifies the name of PKCS11 token for the main program's " |
|
101 "database.\n" }, |
|
102 { /* opt_lib1TokNam */PR_FALSE, "token_name", |
|
103 " Specifies the name of PKCS11 token for library 1's database.\n" }, |
|
104 { /* opt_lib2TokNam */PR_FALSE, "token_name", |
|
105 " Specifies the name of PKCS11 token for library 2's database.\n" }, |
|
106 { /* opt_oldStype */ PR_FALSE, NULL, |
|
107 " Use NSS_Shutdown rather than NSS_ShutdownContext in the main\n" |
|
108 " program.\n" }, |
|
109 { /* opt_verbose */ PR_FALSE, NULL, |
|
110 " Noisily output status to standard error\n" }, |
|
111 { /* opt_summarize */ PR_FALSE, NULL, |
|
112 "report a summary of the test results\n" }, |
|
113 { /* opt_help */ PR_FALSE, NULL, " give this message\n" } |
|
114 }; |
|
115 |
|
116 /* |
|
117 * output our short help (table driven). (does not exit). |
|
118 */ |
|
119 static void |
|
120 short_help(const char *prog) |
|
121 { |
|
122 int count = opt_last; |
|
123 int i,words_found; |
|
124 |
|
125 /* make sure all the tables are up to date before we allow compiles to |
|
126 * succeed */ |
|
127 PR_STATIC_ASSERT(sizeof(options_init)/sizeof(secuCommandFlag) == opt_last); |
|
128 PR_STATIC_ASSERT(sizeof(options_init)/sizeof(secuCommandFlag) == |
|
129 sizeof(options_des)/sizeof(commandDescript)); |
|
130 |
|
131 /* print the base usage */ |
|
132 fprintf(stderr,"usage: %s ",prog); |
|
133 for (i=0, words_found=0; i < count; i++) { |
|
134 if (!options_des[i].required) { |
|
135 fprintf(stderr,"["); |
|
136 } |
|
137 if (options_init[i].longform) { |
|
138 fprintf(stderr, "--%s", options_init[i].longform); |
|
139 words_found++; |
|
140 } else { |
|
141 fprintf(stderr, "-%c", options_init[i].flag); |
|
142 } |
|
143 if (options_init[i].needsArg) { |
|
144 if (options_des[i].arg) { |
|
145 fprintf(stderr," %s",options_des[i].arg); |
|
146 } else { |
|
147 fprintf(stderr," arg"); |
|
148 } |
|
149 words_found++; |
|
150 } |
|
151 if (!options_des[i].required) { |
|
152 fprintf(stderr,"]"); |
|
153 } |
|
154 if (i < count-1 ) { |
|
155 if (words_found >= 5) { |
|
156 fprintf(stderr,"\n "); |
|
157 words_found=0; |
|
158 } else { |
|
159 fprintf(stderr," "); |
|
160 } |
|
161 } |
|
162 } |
|
163 fprintf(stderr,"\n"); |
|
164 } |
|
165 |
|
166 /* |
|
167 * print out long help. like short_help, this does not exit |
|
168 */ |
|
169 static void |
|
170 long_help(const char *prog) |
|
171 { |
|
172 int i; |
|
173 int count = opt_last; |
|
174 |
|
175 short_help(prog); |
|
176 /* print the option descriptions */ |
|
177 fprintf(stderr,"\n"); |
|
178 for (i=0; i < count; i++) { |
|
179 fprintf(stderr," "); |
|
180 if (options_init[i].flag) { |
|
181 fprintf(stderr, "-%c", options_init[i].flag); |
|
182 if (options_init[i].longform) { |
|
183 fprintf(stderr,","); |
|
184 } |
|
185 } |
|
186 if (options_init[i].longform) { |
|
187 fprintf(stderr,"--%s", options_init[i].longform); |
|
188 } |
|
189 if (options_init[i].needsArg) { |
|
190 if (options_des[i].arg) { |
|
191 fprintf(stderr," %s",options_des[i].arg); |
|
192 } else { |
|
193 fprintf(stderr," arg"); |
|
194 } |
|
195 if (options_init[i].arg) { |
|
196 fprintf(stderr," (default = \"%s\")",options_init[i].arg); |
|
197 } |
|
198 } |
|
199 fprintf(stderr,"\n%s",options_des[i].des); |
|
200 } |
|
201 } |
|
202 |
|
203 /* |
|
204 * record summary data |
|
205 */ |
|
206 struct bufferData { |
|
207 char * data; /* lowest address of the buffer */ |
|
208 char * next; /* pointer to the next element on the buffer */ |
|
209 int len; /* length of the buffer */ |
|
210 }; |
|
211 |
|
212 /* our actual buffer. If data is NULL, then all append ops |
|
213 * except are noops */ |
|
214 static struct bufferData buffer= { NULL, NULL, 0 }; |
|
215 |
|
216 #define CHUNK_SIZE 1000 |
|
217 |
|
218 /* |
|
219 * get our initial data. and set the buffer variables up. on failure, |
|
220 * just don't initialize the buffer. |
|
221 */ |
|
222 static void |
|
223 initBuffer(void) |
|
224 { |
|
225 buffer.data = PORT_Alloc(CHUNK_SIZE); |
|
226 if (!buffer.data) { |
|
227 return; |
|
228 } |
|
229 buffer.next = buffer.data; |
|
230 buffer.len = CHUNK_SIZE; |
|
231 } |
|
232 |
|
233 /* |
|
234 * grow the buffer. If we can't get more data, record a 'D' in the second |
|
235 * to last record and allow the rest of the data to overwrite the last |
|
236 * element. |
|
237 */ |
|
238 static void |
|
239 growBuffer(void) |
|
240 { |
|
241 char *new = PORT_Realloc(buffer.data, buffer.len + CHUNK_SIZE); |
|
242 if (!new) { |
|
243 buffer.data[buffer.len-2] = 'D'; /* signal malloc failure in summary */ |
|
244 /* buffer must always point to good memory if it exists */ |
|
245 buffer.next = buffer.data + (buffer.len -1); |
|
246 return; |
|
247 } |
|
248 buffer.next = new + (buffer.next-buffer.data); |
|
249 buffer.data = new; |
|
250 buffer.len += CHUNK_SIZE; |
|
251 } |
|
252 |
|
253 /* |
|
254 * append a label, doubles as appending a single character. |
|
255 */ |
|
256 static void |
|
257 appendLabel(char label) |
|
258 { |
|
259 if (!buffer.data) { |
|
260 return; |
|
261 } |
|
262 |
|
263 *buffer.next++ = label; |
|
264 if (buffer.data+buffer.len >= buffer.next) { |
|
265 growBuffer(); |
|
266 } |
|
267 } |
|
268 |
|
269 /* |
|
270 * append a string onto the buffer. The result will be <string> |
|
271 */ |
|
272 static void |
|
273 appendString(char *string) |
|
274 { |
|
275 if (!buffer.data) { |
|
276 return; |
|
277 } |
|
278 |
|
279 appendLabel('<'); |
|
280 while (*string) { |
|
281 appendLabel(*string++); |
|
282 } |
|
283 appendLabel('>'); |
|
284 } |
|
285 |
|
286 /* |
|
287 * append a bool, T= true, F=false |
|
288 */ |
|
289 static void |
|
290 appendBool(PRBool bool) |
|
291 { |
|
292 if (!buffer.data) { |
|
293 return; |
|
294 } |
|
295 |
|
296 if (bool) { |
|
297 appendLabel('t'); |
|
298 } else { |
|
299 appendLabel('f'); |
|
300 } |
|
301 } |
|
302 |
|
303 /* |
|
304 * append a single hex nibble. |
|
305 */ |
|
306 static void |
|
307 appendHex(unsigned char nibble) |
|
308 { |
|
309 if (nibble <= 9) { |
|
310 appendLabel('0'+nibble); |
|
311 } else { |
|
312 appendLabel('a'+nibble-10); |
|
313 } |
|
314 } |
|
315 |
|
316 /* |
|
317 * append a secitem as colon separated hex bytes. |
|
318 */ |
|
319 static void |
|
320 appendItem(SECItem *item) |
|
321 { |
|
322 int i; |
|
323 |
|
324 if (!buffer.data) { |
|
325 return; |
|
326 } |
|
327 |
|
328 appendLabel(':'); |
|
329 for (i=0; i < item->len; i++) { |
|
330 unsigned char byte=item->data[i]; |
|
331 appendHex(byte >> 4); |
|
332 appendHex(byte & 0xf); |
|
333 appendLabel(':'); |
|
334 } |
|
335 } |
|
336 |
|
337 /* |
|
338 * append a 32 bit integer (even on a 64 bit platform). |
|
339 * for simplicity append it as a hex value, full extension with 0x prefix. |
|
340 */ |
|
341 static void |
|
342 appendInt(unsigned int value) |
|
343 { |
|
344 int i; |
|
345 |
|
346 if (!buffer.data) { |
|
347 return; |
|
348 } |
|
349 |
|
350 appendLabel('0'); |
|
351 appendLabel('x'); |
|
352 value = value & 0xffffffff; /* only look at the buttom 8 bytes */ |
|
353 for (i=0; i < 8; i++) { |
|
354 appendHex(value >> 28 ); |
|
355 value = value << 4; |
|
356 } |
|
357 } |
|
358 |
|
359 /* append a trust flag */ |
|
360 static void |
|
361 appendFlags(unsigned int flag) |
|
362 { |
|
363 char trust[10]; |
|
364 char *cp=trust; |
|
365 |
|
366 trust[0] = 0; |
|
367 printflags(trust, flag); |
|
368 while (*cp) { |
|
369 appendLabel(*cp++); |
|
370 } |
|
371 } |
|
372 |
|
373 /* |
|
374 * dump our buffer out with a result= flag so we can find it easily. |
|
375 * free the buffer as a side effect. |
|
376 */ |
|
377 static void |
|
378 dumpBuffer(void) |
|
379 { |
|
380 if (!buffer.data) { |
|
381 return; |
|
382 } |
|
383 |
|
384 appendLabel(0); /* terminate */ |
|
385 printf("\nresult=%s\n",buffer.data); |
|
386 PORT_Free(buffer.data); |
|
387 buffer.data = buffer.next = NULL; |
|
388 buffer.len = 0; |
|
389 } |
|
390 |
|
391 |
|
392 /* |
|
393 * usage, like traditional usage, automatically exit |
|
394 */ |
|
395 static void |
|
396 usage(const char *prog) |
|
397 { |
|
398 short_help(prog); |
|
399 dumpBuffer(); |
|
400 exit(1); |
|
401 } |
|
402 |
|
403 /* |
|
404 * like usage, except prints the long version of help |
|
405 */ |
|
406 static void |
|
407 usage_long(const char *prog) |
|
408 { |
|
409 long_help(prog); |
|
410 dumpBuffer(); |
|
411 exit(1); |
|
412 } |
|
413 |
|
414 static const char * |
|
415 bool2String(PRBool bool) |
|
416 { |
|
417 return bool ? "true" : "false"; |
|
418 } |
|
419 |
|
420 /* |
|
421 * print out interesting info about the given slot |
|
422 */ |
|
423 void |
|
424 print_slot(PK11SlotInfo *slot, int log) |
|
425 { |
|
426 if (log) { |
|
427 fprintf(stderr, "* Name=%s Token_Name=%s present=%s, ro=%s *\n", |
|
428 PK11_GetSlotName(slot), PK11_GetTokenName(slot), |
|
429 bool2String(PK11_IsPresent(slot)), |
|
430 bool2String(PK11_IsReadOnly(slot))); |
|
431 } |
|
432 appendLabel('S'); |
|
433 appendString(PK11_GetTokenName(slot)); |
|
434 appendBool(PK11_IsPresent(slot)); |
|
435 appendBool(PK11_IsReadOnly(slot)); |
|
436 } |
|
437 |
|
438 /* |
|
439 * list all our slots |
|
440 */ |
|
441 void |
|
442 do_list_slots(const char *progName, int log) |
|
443 { |
|
444 PK11SlotList *list; |
|
445 PK11SlotListElement *le; |
|
446 |
|
447 list= PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL); |
|
448 if (list == NULL) { |
|
449 fprintf(stderr,"ERROR: no tokens found %s\n", |
|
450 SECU_Strerror(PORT_GetError())); |
|
451 appendLabel('S'); |
|
452 appendString("none"); |
|
453 return; |
|
454 } |
|
455 |
|
456 for (le= PK11_GetFirstSafe(list); le; |
|
457 le = PK11_GetNextSafe(list,le,PR_TRUE)) { |
|
458 print_slot(le->slot, log); |
|
459 } |
|
460 PK11_FreeSlotList(list); |
|
461 } |
|
462 |
|
463 static PRBool |
|
464 sort_CN(CERTCertificate *certa, CERTCertificate *certb, void *arg) |
|
465 { |
|
466 char *commonNameA, *commonNameB; |
|
467 int ret; |
|
468 |
|
469 commonNameA = CERT_GetCommonName(&certa->subject); |
|
470 commonNameB = CERT_GetCommonName(&certb->subject); |
|
471 |
|
472 if (commonNameA == NULL) { |
|
473 PORT_Free(commonNameB); |
|
474 return PR_TRUE; |
|
475 } |
|
476 if (commonNameB == NULL) { |
|
477 PORT_Free(commonNameA); |
|
478 return PR_FALSE; |
|
479 } |
|
480 ret = PORT_Strcmp(commonNameA,commonNameB); |
|
481 PORT_Free(commonNameA); |
|
482 PORT_Free(commonNameB); |
|
483 return (ret < 0) ? PR_TRUE: PR_FALSE; |
|
484 } |
|
485 |
|
486 /* |
|
487 * list all the certs |
|
488 */ |
|
489 void |
|
490 do_list_certs(const char *progName, int log) |
|
491 { |
|
492 CERTCertList *list; |
|
493 CERTCertList *sorted; |
|
494 CERTCertListNode *node; |
|
495 CERTCertTrust trust; |
|
496 int i; |
|
497 |
|
498 list = PK11_ListCerts(PK11CertListUnique, NULL); |
|
499 if (list == NULL) { |
|
500 fprintf(stderr,"ERROR: no certs found %s\n", |
|
501 SECU_Strerror(PORT_GetError())); |
|
502 appendLabel('C'); |
|
503 appendString("none"); |
|
504 return; |
|
505 } |
|
506 |
|
507 sorted = CERT_NewCertList(); |
|
508 if (sorted == NULL) { |
|
509 fprintf(stderr,"ERROR: no certs found %s\n", |
|
510 SECU_Strerror(PORT_GetError())); |
|
511 appendLabel('C'); |
|
512 appendLabel('E'); |
|
513 appendInt(PORT_GetError()); |
|
514 return; |
|
515 } |
|
516 |
|
517 /* sort the list */ |
|
518 for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node,list); |
|
519 node = CERT_LIST_NEXT(node)) { |
|
520 CERT_AddCertToListSorted(sorted, node->cert, sort_CN, NULL); |
|
521 } |
|
522 |
|
523 |
|
524 for (node = CERT_LIST_HEAD(sorted); !CERT_LIST_END(node,sorted); |
|
525 node = CERT_LIST_NEXT(node)) { |
|
526 CERTCertificate *cert = node->cert; |
|
527 char *commonName; |
|
528 |
|
529 SECU_PrintCertNickname(node, stderr); |
|
530 if (log) { |
|
531 fprintf(stderr, "* Slot=%s*\n", cert->slot ? |
|
532 PK11_GetTokenName(cert->slot) : "none"); |
|
533 fprintf(stderr, "* Nickname=%s*\n", cert->nickname); |
|
534 fprintf(stderr, "* Subject=<%s>*\n", cert->subjectName); |
|
535 fprintf(stderr, "* Issuer=<%s>*\n", cert->issuerName); |
|
536 fprintf(stderr, "* SN="); |
|
537 for (i=0; i < cert->serialNumber.len; i++) { |
|
538 if (i!=0) fprintf(stderr,":"); |
|
539 fprintf(stderr, "%02x",cert->serialNumber.data[0]); |
|
540 } |
|
541 fprintf(stderr," *\n"); |
|
542 } |
|
543 appendLabel('C'); |
|
544 commonName = CERT_GetCommonName(&cert->subject); |
|
545 appendString(commonName?commonName:"*NoName*"); |
|
546 PORT_Free(commonName); |
|
547 if (CERT_GetCertTrust(cert, &trust) == SECSuccess) { |
|
548 appendFlags(trust.sslFlags); |
|
549 appendFlags(trust.emailFlags); |
|
550 appendFlags(trust.objectSigningFlags); |
|
551 } |
|
552 } |
|
553 CERT_DestroyCertList(list); |
|
554 |
|
555 } |
|
556 |
|
557 /* |
|
558 * need to implement yet... try to add a new certificate |
|
559 */ |
|
560 void |
|
561 do_add_cert(const char *progName, int log) |
|
562 { |
|
563 PORT_Assert(/* do_add_cert not implemented */ 0); |
|
564 } |
|
565 |
|
566 /* |
|
567 * display the current key slot |
|
568 */ |
|
569 void |
|
570 do_key_slot(const char *progName, int log) |
|
571 { |
|
572 PK11SlotInfo *slot = PK11_GetInternalKeySlot(); |
|
573 if (!slot) { |
|
574 fprintf(stderr,"ERROR: no internal key slot found %s\n", |
|
575 SECU_Strerror(PORT_GetError())); |
|
576 appendLabel('K'); |
|
577 appendLabel('S'); |
|
578 appendString("none"); |
|
579 } |
|
580 print_slot(slot, log); |
|
581 PK11_FreeSlot(slot); |
|
582 } |
|
583 |
|
584 /* |
|
585 * execute some NSS command. |
|
586 */ |
|
587 void |
|
588 do_command(const char *label, int initialized, secuCommandFlag *command, |
|
589 const char *progName, int log) |
|
590 { |
|
591 char * command_string; |
|
592 if (!initialized) { |
|
593 return; |
|
594 } |
|
595 |
|
596 if (command->activated) { |
|
597 command_string = command->arg; |
|
598 } else { |
|
599 command_string = "none"; |
|
600 } |
|
601 |
|
602 if (log) { |
|
603 fprintf(stderr, "*Executing nss command \"%s\" for %s*\n", |
|
604 command_string,label); |
|
605 } |
|
606 |
|
607 /* do something */ |
|
608 if (PORT_Strcasecmp(command_string, "list_slots") == 0) { |
|
609 do_list_slots(progName, log); |
|
610 } else if (PORT_Strcasecmp(command_string, "list_certs") == 0) { |
|
611 do_list_certs(progName, log); |
|
612 } else if (PORT_Strcasecmp(command_string, "add_cert") == 0) { |
|
613 do_add_cert(progName, log); |
|
614 } else if (PORT_Strcasecmp(command_string, "key_slot") == 0) { |
|
615 do_key_slot(progName, log); |
|
616 } else if (PORT_Strcasecmp(command_string, "none") != 0) { |
|
617 fprintf(stderr, ">> Unknown command (%s)\n", command_string); |
|
618 appendLabel('E'); |
|
619 appendString("bc"); |
|
620 usage_long(progName); |
|
621 } |
|
622 |
|
623 } |
|
624 |
|
625 |
|
626 /* |
|
627 * functions do handle |
|
628 * different library initializations. |
|
629 */ |
|
630 static int main_initialized; |
|
631 static int lib1_initialized; |
|
632 static int lib2_initialized; |
|
633 |
|
634 void |
|
635 main_Init(secuCommandFlag *db, secuCommandFlag *tokNam, |
|
636 int readOnly, const char *progName, int log) |
|
637 { |
|
638 SECStatus rv; |
|
639 if (log) { |
|
640 fprintf(stderr,"*NSS_Init for the main program*\n"); |
|
641 } |
|
642 appendLabel('M'); |
|
643 if (!db->activated) { |
|
644 fprintf(stderr, ">> No main_db has been specified\n"); |
|
645 usage(progName); |
|
646 } |
|
647 if (main_initialized) { |
|
648 fprintf(stderr,"Warning: Second initialization of Main\n"); |
|
649 appendLabel('E'); |
|
650 appendString("2M"); |
|
651 } |
|
652 if (tokNam->activated) { |
|
653 PK11_ConfigurePKCS11(NULL, NULL, NULL, tokNam->arg, |
|
654 NULL, NULL, NULL, NULL, 0, 0); |
|
655 } |
|
656 rv = NSS_Initialize(db->arg, "", "", "", |
|
657 NSS_INIT_NOROOTINIT|(readOnly?NSS_INIT_READONLY:0)); |
|
658 if (rv != SECSuccess) { |
|
659 appendLabel('E'); |
|
660 appendInt(PORT_GetError()); |
|
661 fprintf(stderr,">> %s\n", SECU_Strerror(PORT_GetError())); |
|
662 dumpBuffer(); |
|
663 exit(1); |
|
664 } |
|
665 main_initialized = 1; |
|
666 } |
|
667 |
|
668 void |
|
669 main_Do(secuCommandFlag *command, const char *progName, int log) |
|
670 { |
|
671 do_command("main", main_initialized, command, progName, log); |
|
672 } |
|
673 |
|
674 void |
|
675 main_Shutdown(int old_style, const char *progName, int log) |
|
676 { |
|
677 SECStatus rv; |
|
678 appendLabel('N'); |
|
679 if (log) { |
|
680 fprintf(stderr,"*NSS_Shutdown for the main program*\n"); |
|
681 } |
|
682 if (!main_initialized) { |
|
683 fprintf(stderr,"Warning: Main shutdown without corresponding init\n"); |
|
684 } |
|
685 if (old_style) { |
|
686 rv = NSS_Shutdown(); |
|
687 } else { |
|
688 rv = NSS_ShutdownContext(NULL); |
|
689 } |
|
690 fprintf(stderr, "Shutdown main state = %d\n", rv); |
|
691 if (rv != SECSuccess) { |
|
692 appendLabel('E'); |
|
693 appendInt(PORT_GetError()); |
|
694 fprintf(stderr,"ERROR: %s\n", SECU_Strerror(PORT_GetError())); |
|
695 } |
|
696 main_initialized = 0; |
|
697 } |
|
698 |
|
699 /* common library init */ |
|
700 NSSInitContext * |
|
701 lib_Init(const char *lableString, char label, int initialized, |
|
702 secuCommandFlag *db, secuCommandFlag *tokNam, int readonly, |
|
703 const char *progName, int log) |
|
704 { |
|
705 NSSInitContext *ctxt; |
|
706 NSSInitParameters initStrings; |
|
707 NSSInitParameters *initStringPtr = NULL; |
|
708 |
|
709 appendLabel(label); |
|
710 if (log) { |
|
711 fprintf(stderr,"*NSS_Init for %s*\n", lableString); |
|
712 } |
|
713 |
|
714 if (!db->activated) { |
|
715 fprintf(stderr, ">> No %s_db has been specified\n", lableString); |
|
716 usage(progName); |
|
717 } |
|
718 if (initialized) { |
|
719 fprintf(stderr,"Warning: Second initialization of %s\n", lableString); |
|
720 } |
|
721 if (tokNam->activated) { |
|
722 PORT_Memset(&initStrings, 0, sizeof(initStrings)); |
|
723 initStrings.length = sizeof(initStrings); |
|
724 initStrings.dbTokenDescription = tokNam->arg; |
|
725 initStringPtr = &initStrings; |
|
726 } |
|
727 ctxt = NSS_InitContext(db->arg, "", "", "", initStringPtr, |
|
728 NSS_INIT_NOROOTINIT|(readonly?NSS_INIT_READONLY:0)); |
|
729 if (ctxt == NULL) { |
|
730 appendLabel('E'); |
|
731 appendInt(PORT_GetError()); |
|
732 fprintf(stderr,">> %s\n",SECU_Strerror(PORT_GetError())); |
|
733 dumpBuffer(); |
|
734 exit(1); |
|
735 } |
|
736 return ctxt; |
|
737 } |
|
738 |
|
739 /* common library shutdown */ |
|
740 void |
|
741 lib_Shutdown(const char *labelString, char label, NSSInitContext *ctx, |
|
742 int initialize, const char *progName, int log) |
|
743 { |
|
744 SECStatus rv; |
|
745 appendLabel(label); |
|
746 if (log) { |
|
747 fprintf(stderr,"*NSS_Shutdown for %s\n*", labelString); |
|
748 } |
|
749 if (!initialize) { |
|
750 fprintf(stderr,"Warning: %s shutdown without corresponding init\n", |
|
751 labelString); |
|
752 } |
|
753 rv = NSS_ShutdownContext(ctx); |
|
754 fprintf(stderr, "Shutdown %s state = %d\n", labelString, rv); |
|
755 if (rv != SECSuccess) { |
|
756 appendLabel('E'); |
|
757 appendInt(PORT_GetError()); |
|
758 fprintf(stderr,"ERROR: %s\n", SECU_Strerror(PORT_GetError())); |
|
759 } |
|
760 } |
|
761 |
|
762 |
|
763 static NSSInitContext *lib1_context; |
|
764 static NSSInitContext *lib2_context; |
|
765 void |
|
766 lib1_Init(secuCommandFlag *db, secuCommandFlag *tokNam, |
|
767 int readOnly, const char *progName, int log) |
|
768 { |
|
769 lib1_context = lib_Init("lib1", '1', lib1_initialized, db, tokNam, |
|
770 readOnly, progName, log); |
|
771 lib1_initialized = 1; |
|
772 } |
|
773 |
|
774 void |
|
775 lib2_Init(secuCommandFlag *db, secuCommandFlag *tokNam, |
|
776 int readOnly, const char *progName, int log) |
|
777 { |
|
778 lib2_context = lib_Init("lib2", '2', lib2_initialized, |
|
779 db, tokNam, readOnly, progName, log); |
|
780 lib2_initialized = 1; |
|
781 } |
|
782 |
|
783 void |
|
784 lib1_Do(secuCommandFlag *command, const char *progName, int log) |
|
785 { |
|
786 do_command("lib1", lib1_initialized, command, progName, log); |
|
787 } |
|
788 |
|
789 void |
|
790 lib2_Do(secuCommandFlag *command, const char *progName, int log) |
|
791 { |
|
792 do_command("lib2", lib2_initialized, command, progName, log); |
|
793 } |
|
794 |
|
795 void |
|
796 lib1_Shutdown(const char *progName, int log) |
|
797 { |
|
798 lib_Shutdown("lib1", 'I', lib1_context, lib1_initialized, progName, log); |
|
799 lib1_initialized = 0; |
|
800 /* don't clear lib1_Context, so we can test multiple attempts to close |
|
801 * the same context produces correct errors*/ |
|
802 } |
|
803 |
|
804 void |
|
805 lib2_Shutdown(const char *progName, int log) |
|
806 { |
|
807 lib_Shutdown("lib2", 'Z', lib2_context, lib2_initialized, progName, log); |
|
808 lib2_initialized = 0; |
|
809 /* don't clear lib2_Context, so we can test multiple attempts to close |
|
810 * the same context produces correct errors*/ |
|
811 } |
|
812 |
|
813 int |
|
814 main(int argc, char **argv) |
|
815 { |
|
816 SECStatus rv; |
|
817 secuCommand libinit; |
|
818 char *progName; |
|
819 char *order; |
|
820 secuCommandFlag *options; |
|
821 int log = 0; |
|
822 |
|
823 progName = strrchr(argv[0], '/'); |
|
824 progName = progName ? progName+1 : argv[0]; |
|
825 |
|
826 libinit.numCommands = 0; |
|
827 libinit.commands = 0; |
|
828 libinit.numOptions = opt_last; |
|
829 options = (secuCommandFlag *)PORT_Alloc(sizeof(options_init)); |
|
830 if (options == NULL) { |
|
831 fprintf(stderr, ">> %s:Not enough free memory to run command\n", |
|
832 progName); |
|
833 exit(1); |
|
834 } |
|
835 PORT_Memcpy(options, options_init, sizeof(options_init)); |
|
836 libinit.options = options; |
|
837 |
|
838 rv = SECU_ParseCommandLine(argc, argv, progName, & libinit); |
|
839 if (rv != SECSuccess) { |
|
840 usage(progName); |
|
841 } |
|
842 |
|
843 if (libinit.options[opt_help].activated) { |
|
844 long_help(progName); |
|
845 exit (0); |
|
846 } |
|
847 |
|
848 log = libinit.options[opt_verbose].activated; |
|
849 if (libinit.options[opt_summary].activated) { |
|
850 initBuffer(); |
|
851 } |
|
852 |
|
853 order = libinit.options[opt_liborder].arg; |
|
854 if (!order) { |
|
855 usage(progName); |
|
856 } |
|
857 |
|
858 if (log) { |
|
859 fprintf(stderr,"* initializing with order \"%s\"*\n", order); |
|
860 } |
|
861 |
|
862 for (;*order; order++) { |
|
863 switch (*order) { |
|
864 case 'M': |
|
865 main_Init(&libinit.options[opt_mainDB], |
|
866 &libinit.options[opt_mainTokNam], |
|
867 libinit.options[opt_mainRO].activated, |
|
868 progName, log); |
|
869 break; |
|
870 case '1': |
|
871 lib1_Init(&libinit.options[opt_lib1DB], |
|
872 &libinit.options[opt_lib1TokNam], |
|
873 libinit.options[opt_lib1RO].activated, |
|
874 progName,log); |
|
875 break; |
|
876 case '2': |
|
877 lib2_Init(&libinit.options[opt_lib2DB], |
|
878 &libinit.options[opt_lib2TokNam], |
|
879 libinit.options[opt_lib2RO].activated, |
|
880 progName,log); |
|
881 break; |
|
882 case 'm': |
|
883 main_Shutdown(libinit.options[opt_oldStyle].activated, |
|
884 progName, log); |
|
885 break; |
|
886 case 'i': |
|
887 lib1_Shutdown(progName, log); |
|
888 break; |
|
889 case 'z': |
|
890 lib2_Shutdown(progName, log); |
|
891 break; |
|
892 default: |
|
893 fprintf(stderr,">> Unknown init/shutdown command \"%c\"", *order); |
|
894 usage_long(progName); |
|
895 } |
|
896 main_Do(&libinit.options[opt_mainCMD], progName, log); |
|
897 lib1_Do(&libinit.options[opt_lib1CMD], progName, log); |
|
898 lib2_Do(&libinit.options[opt_lib2CMD], progName, log); |
|
899 } |
|
900 |
|
901 if (NSS_IsInitialized()) { |
|
902 appendLabel('X'); |
|
903 fprintf(stderr, "Warning: NSS is initialized\n"); |
|
904 } |
|
905 dumpBuffer(); |
|
906 |
|
907 exit(0); |
|
908 } |
|
909 |