tor-browser

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

multinit.c (24887B)


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