| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| /* |
| * The following code handles the storage of PKCS 11 modules used by the |
| * NSS. This file is written to abstract away how the modules are |
| * stored so we can decide that later. |
| */ |
| #include "secport.h" |
| #include "prprf.h" |
| #include "prenv.h" |
| #include "utilpars.h" |
| #include "utilmodt.h" |
| |
| /* |
| * return the expected matching quote value for the one specified |
| */ |
| PRBool |
| NSSUTIL_ArgGetPair(char c) |
| { |
| switch (c) { |
| case '\'': |
| return c; |
| case '\"': |
| return c; |
| case '<': |
| return '>'; |
| case '{': |
| return '}'; |
| case '[': |
| return ']'; |
| case '(': |
| return ')'; |
| default: |
| break; |
| } |
| return ' '; |
| } |
| |
| PRBool |
| NSSUTIL_ArgIsBlank(char c) |
| { |
| return isspace((unsigned char)c); |
| } |
| |
| PRBool |
| NSSUTIL_ArgIsEscape(char c) |
| { |
| return c == '\\'; |
| } |
| |
| PRBool |
| NSSUTIL_ArgIsQuote(char c) |
| { |
| switch (c) { |
| case '\'': |
| case '\"': |
| case '<': |
| case '{': /* } end curly to keep vi bracket matching working */ |
| case '(': /* ) */ |
| case '[': /* ] */ |
| return PR_TRUE; |
| default: |
| break; |
| } |
| return PR_FALSE; |
| } |
| |
| const char * |
| NSSUTIL_ArgStrip(const char *c) |
| { |
| while (*c && NSSUTIL_ArgIsBlank(*c)) |
| c++; |
| return c; |
| } |
| |
| /* |
| * find the end of the current tag/value pair. string should be pointing just |
| * after the equal sign. Handles quoted characters. |
| */ |
| const char * |
| NSSUTIL_ArgFindEnd(const char *string) |
| { |
| char endChar = ' '; |
| PRBool lastEscape = PR_FALSE; |
| |
| if (NSSUTIL_ArgIsQuote(*string)) { |
| endChar = NSSUTIL_ArgGetPair(*string); |
| string++; |
| } |
| |
| for (; *string; string++) { |
| if (lastEscape) { |
| lastEscape = PR_FALSE; |
| continue; |
| } |
| if (NSSUTIL_ArgIsEscape(*string) && !lastEscape) { |
| lastEscape = PR_TRUE; |
| continue; |
| } |
| if ((endChar == ' ') && NSSUTIL_ArgIsBlank(*string)) |
| break; |
| if (*string == endChar) { |
| break; |
| } |
| } |
| |
| return string; |
| } |
| |
| /* |
| * get the value pointed to by string. string should be pointing just beyond |
| * the equal sign. |
| */ |
| char * |
| NSSUTIL_ArgFetchValue(const char *string, int *pcount) |
| { |
| const char *end = NSSUTIL_ArgFindEnd(string); |
| char *retString, *copyString; |
| PRBool lastEscape = PR_FALSE; |
| int len; |
| |
| len = end - string; |
| if (len == 0) { |
| *pcount = 0; |
| return NULL; |
| } |
| |
| copyString = retString = (char *)PORT_Alloc(len + 1); |
| |
| if (*end) |
| len++; |
| *pcount = len; |
| if (retString == NULL) |
| return NULL; |
| |
| if (NSSUTIL_ArgIsQuote(*string)) |
| string++; |
| for (; string < end; string++) { |
| if (NSSUTIL_ArgIsEscape(*string) && !lastEscape) { |
| lastEscape = PR_TRUE; |
| continue; |
| } |
| lastEscape = PR_FALSE; |
| *copyString++ = *string; |
| } |
| *copyString = 0; |
| return retString; |
| } |
| |
| /* |
| * point to the next parameter in string |
| */ |
| const char * |
| NSSUTIL_ArgSkipParameter(const char *string) |
| { |
| const char *end; |
| /* look for the end of the <name>= */ |
| for (; *string; string++) { |
| if (*string == '=') { |
| string++; |
| break; |
| } |
| if (NSSUTIL_ArgIsBlank(*string)) |
| return (string); |
| } |
| |
| end = NSSUTIL_ArgFindEnd(string); |
| if (*end) |
| end++; |
| return end; |
| } |
| |
| /* |
| * get the value from that tag value pair. |
| */ |
| char * |
| NSSUTIL_ArgGetParamValue(const char *paramName, const char *parameters) |
| { |
| char searchValue[256]; |
| size_t paramLen = strlen(paramName); |
| char *returnValue = NULL; |
| int next; |
| |
| if ((parameters == NULL) || (*parameters == 0)) |
| return NULL; |
| |
| PORT_Assert(paramLen + 2 < sizeof(searchValue)); |
| |
| PORT_Strcpy(searchValue, paramName); |
| PORT_Strcat(searchValue, "="); |
| while (*parameters) { |
| if (PORT_Strncasecmp(parameters, searchValue, paramLen + 1) == 0) { |
| parameters += paramLen + 1; |
| returnValue = NSSUTIL_ArgFetchValue(parameters, &next); |
| break; |
| } else { |
| parameters = NSSUTIL_ArgSkipParameter(parameters); |
| } |
| parameters = NSSUTIL_ArgStrip(parameters); |
| } |
| return returnValue; |
| } |
| |
| /* |
| * find the next flag in the parameter list |
| */ |
| const char * |
| NSSUTIL_ArgNextFlag(const char *flags) |
| { |
| for (; *flags; flags++) { |
| if (*flags == ',') { |
| flags++; |
| break; |
| } |
| } |
| return flags; |
| } |
| |
| /* |
| * return true if the flag is set in the label parameter. |
| */ |
| PRBool |
| NSSUTIL_ArgHasFlag(const char *label, const char *flag, const char *parameters) |
| { |
| char *flags; |
| const char *index; |
| int len = strlen(flag); |
| PRBool found = PR_FALSE; |
| |
| flags = NSSUTIL_ArgGetParamValue(label, parameters); |
| if (flags == NULL) |
| return PR_FALSE; |
| |
| for (index = flags; *index; index = NSSUTIL_ArgNextFlag(index)) { |
| if (PORT_Strncasecmp(index, flag, len) == 0) { |
| found = PR_TRUE; |
| break; |
| } |
| } |
| PORT_Free(flags); |
| return found; |
| } |
| |
| /* |
| * decode a number. handle octal (leading '0'), hex (leading '0x') or decimal |
| */ |
| long |
| NSSUTIL_ArgDecodeNumber(const char *num) |
| { |
| int radix = 10; |
| unsigned long value = 0; |
| long retValue = 0; |
| int sign = 1; |
| int digit; |
| |
| if (num == NULL) |
| return retValue; |
| |
| num = NSSUTIL_ArgStrip(num); |
| |
| if (*num == '-') { |
| sign = -1; |
| num++; |
| } |
| |
| if (*num == '0') { |
| radix = 8; |
| num++; |
| if ((*num == 'x') || (*num == 'X')) { |
| radix = 16; |
| num++; |
| } |
| } |
| |
| for (; *num; num++) { |
| if (isdigit(*num)) { |
| digit = *num - '0'; |
| } else if ((*num >= 'a') && (*num <= 'f')) { |
| digit = *num - 'a' + 10; |
| } else if ((*num >= 'A') && (*num <= 'F')) { |
| digit = *num - 'A' + 10; |
| } else { |
| break; |
| } |
| if (digit >= radix) |
| break; |
| value = value * radix + digit; |
| } |
| |
| retValue = ((int)value) * sign; |
| return retValue; |
| } |
| |
| /* |
| * parameters are tag value pairs. This function returns the tag or label (the |
| * value before the equal size. |
| */ |
| char * |
| NSSUTIL_ArgGetLabel(const char *inString, int *next) |
| { |
| char *name = NULL; |
| const char *string; |
| int len; |
| |
| /* look for the end of the <label>= */ |
| for (string = inString; *string; string++) { |
| if (*string == '=') { |
| break; |
| } |
| if (NSSUTIL_ArgIsBlank(*string)) |
| break; |
| } |
| |
| len = string - inString; |
| |
| *next = len; |
| if (*string == '=') |
| (*next) += 1; |
| if (len > 0) { |
| name = PORT_Alloc(len + 1); |
| PORT_Strncpy(name, inString, len); |
| name[len] = 0; |
| } |
| return name; |
| } |
| |
| /* |
| * read an argument at a Long integer |
| */ |
| long |
| NSSUTIL_ArgReadLong(const char *label, const char *params, |
| long defValue, PRBool *isdefault) |
| { |
| char *value; |
| long retValue; |
| if (isdefault) |
| *isdefault = PR_FALSE; |
| |
| value = NSSUTIL_ArgGetParamValue(label, params); |
| if (value == NULL) { |
| if (isdefault) |
| *isdefault = PR_TRUE; |
| return defValue; |
| } |
| retValue = NSSUTIL_ArgDecodeNumber(value); |
| if (value) |
| PORT_Free(value); |
| |
| return retValue; |
| } |
| |
| /* |
| * prepare a string to be quoted with 'quote' marks. We do that by adding |
| * appropriate escapes. |
| */ |
| static int |
| nssutil_escapeQuotesSize(const char *string, char quote, PRBool addquotes) |
| { |
| int escapes = 0, size = 0; |
| const char *src; |
| |
| size = addquotes ? 2 : 0; |
| for (src = string; *src; src++) { |
| if ((*src == quote) || (*src == '\\')) |
| escapes++; |
| size++; |
| } |
| return size + escapes + 1; |
| } |
| |
| static char * |
| nssutil_escapeQuotes(const char *string, char quote, PRBool addquotes) |
| { |
| char *newString = 0; |
| int size = 0; |
| const char *src; |
| char *dest; |
| |
| size = nssutil_escapeQuotesSize(string, quote, addquotes); |
| |
| dest = newString = PORT_ZAlloc(size); |
| if (newString == NULL) { |
| return NULL; |
| } |
| |
| if (addquotes) |
| *dest++ = quote; |
| for (src = string; *src; src++, dest++) { |
| if ((*src == '\\') || (*src == quote)) { |
| *dest++ = '\\'; |
| } |
| *dest = *src; |
| } |
| if (addquotes) |
| *dest = quote; |
| |
| return newString; |
| } |
| |
| int |
| NSSUTIL_EscapeSize(const char *string, char quote) |
| { |
| return nssutil_escapeQuotesSize(string, quote, PR_FALSE); |
| } |
| |
| char * |
| NSSUTIL_Escape(const char *string, char quote) |
| { |
| return nssutil_escapeQuotes(string, quote, PR_FALSE); |
| } |
| |
| int |
| NSSUTIL_QuoteSize(const char *string, char quote) |
| { |
| return nssutil_escapeQuotesSize(string, quote, PR_TRUE); |
| } |
| |
| char * |
| NSSUTIL_Quote(const char *string, char quote) |
| { |
| return nssutil_escapeQuotes(string, quote, PR_TRUE); |
| } |
| |
| int |
| NSSUTIL_DoubleEscapeSize(const char *string, char quote1, char quote2) |
| { |
| int escapes = 0, size = 0; |
| const char *src; |
| for (src = string; *src; src++) { |
| if (*src == '\\') |
| escapes += 3; /* \\\\ */ |
| if (*src == quote1) |
| escapes += 2; /* \\quote1 */ |
| if (*src == quote2) |
| escapes++; /* \quote2 */ |
| size++; |
| } |
| |
| return escapes + size + 1; |
| } |
| |
| char * |
| NSSUTIL_DoubleEscape(const char *string, char quote1, char quote2) |
| { |
| char *round1 = NULL; |
| char *retValue = NULL; |
| if (string == NULL) { |
| goto done; |
| } |
| round1 = nssutil_escapeQuotes(string, quote1, PR_FALSE); |
| if (round1) { |
| retValue = nssutil_escapeQuotes(round1, quote2, PR_FALSE); |
| PORT_Free(round1); |
| } |
| |
| done: |
| if (retValue == NULL) { |
| retValue = PORT_Strdup(""); |
| } |
| return retValue; |
| } |
| |
| /************************************************************************ |
| * These functions are used in contructing strings. |
| * NOTE: they will always return a string, but sometimes it will return |
| * a specific NULL string. These strings must be freed with util_freePair. |
| */ |
| |
| /* string to return on error... */ |
| static char *nssutil_nullString = ""; |
| |
| static char * |
| nssutil_formatValue(PLArenaPool *arena, char *value, char quote) |
| { |
| char *vp, *vp2, *retval; |
| int size = 0, escapes = 0; |
| |
| for (vp = value; *vp; vp++) { |
| if ((*vp == quote) || (*vp == NSSUTIL_ARG_ESCAPE)) |
| escapes++; |
| size++; |
| } |
| if (arena) { |
| retval = PORT_ArenaZAlloc(arena, size + escapes + 1); |
| } else { |
| retval = PORT_ZAlloc(size + escapes + 1); |
| } |
| if (retval == NULL) |
| return NULL; |
| vp2 = retval; |
| for (vp = value; *vp; vp++) { |
| if ((*vp == quote) || (*vp == NSSUTIL_ARG_ESCAPE)) |
| *vp2++ = NSSUTIL_ARG_ESCAPE; |
| *vp2++ = *vp; |
| } |
| return retval; |
| } |
| |
| static PRBool |
| nssutil_argHasChar(char *v, char c) |
| { |
| for (; *v; v++) { |
| if (*v == c) |
| return PR_TRUE; |
| } |
| return PR_FALSE; |
| } |
| |
| static PRBool |
| nssutil_argHasBlanks(char *v) |
| { |
| for (; *v; v++) { |
| if (NSSUTIL_ArgIsBlank(*v)) |
| return PR_TRUE; |
| } |
| return PR_FALSE; |
| } |
| |
| static char * |
| nssutil_formatPair(char *name, char *value, char quote) |
| { |
| char openQuote = quote; |
| char closeQuote = NSSUTIL_ArgGetPair(quote); |
| char *newValue = NULL; |
| char *returnValue; |
| PRBool need_quote = PR_FALSE; |
| |
| if (!value || (*value == 0)) |
| return nssutil_nullString; |
| |
| if (nssutil_argHasBlanks(value) || NSSUTIL_ArgIsQuote(value[0])) |
| need_quote = PR_TRUE; |
| |
| if ((need_quote && nssutil_argHasChar(value, closeQuote)) || nssutil_argHasChar(value, NSSUTIL_ARG_ESCAPE)) { |
| value = newValue = nssutil_formatValue(NULL, value, quote); |
| if (newValue == NULL) |
| return nssutil_nullString; |
| } |
| if (need_quote) { |
| returnValue = PR_smprintf("%s=%c%s%c", name, openQuote, value, closeQuote); |
| } else { |
| returnValue = PR_smprintf("%s=%s", name, value); |
| } |
| if (returnValue == NULL) |
| returnValue = nssutil_nullString; |
| |
| if (newValue) |
| PORT_Free(newValue); |
| |
| return returnValue; |
| } |
| |
| static char * |
| nssutil_formatIntPair(char *name, unsigned long value, |
| unsigned long def) |
| { |
| char *returnValue; |
| |
| if (value == def) |
| return nssutil_nullString; |
| |
| returnValue = PR_smprintf("%s=%d", name, value); |
| |
| return returnValue; |
| } |
| |
| static void |
| nssutil_freePair(char *pair) |
| { |
| if (pair && pair != nssutil_nullString) { |
| PR_smprintf_free(pair); |
| } |
| } |
| |
| /************************************************************************ |
| * Parse the Slot specific parameters in the NSS params. |
| */ |
| |
| struct nssutilArgSlotFlagTable { |
| char *name; |
| int len; |
| unsigned long value; |
| }; |
| |
| #define NSSUTIL_ARG_ENTRY(arg, flag) \ |
| { \ |
| #arg, sizeof(#arg) - 1, flag \ |
| } |
| static struct nssutilArgSlotFlagTable nssutil_argSlotFlagTable[] = { |
| NSSUTIL_ARG_ENTRY(RSA, SECMOD_RSA_FLAG), |
| NSSUTIL_ARG_ENTRY(ECC, SECMOD_ECC_FLAG), |
| NSSUTIL_ARG_ENTRY(DSA, SECMOD_RSA_FLAG), |
| NSSUTIL_ARG_ENTRY(RC2, SECMOD_RC4_FLAG), |
| NSSUTIL_ARG_ENTRY(RC4, SECMOD_RC2_FLAG), |
| NSSUTIL_ARG_ENTRY(DES, SECMOD_DES_FLAG), |
| NSSUTIL_ARG_ENTRY(DH, SECMOD_DH_FLAG), |
| NSSUTIL_ARG_ENTRY(FORTEZZA, SECMOD_FORTEZZA_FLAG), |
| NSSUTIL_ARG_ENTRY(RC5, SECMOD_RC5_FLAG), |
| NSSUTIL_ARG_ENTRY(SHA1, SECMOD_SHA1_FLAG), |
| NSSUTIL_ARG_ENTRY(SHA256, SECMOD_SHA256_FLAG), |
| NSSUTIL_ARG_ENTRY(SHA512, SECMOD_SHA512_FLAG), |
| NSSUTIL_ARG_ENTRY(MD5, SECMOD_MD5_FLAG), |
| NSSUTIL_ARG_ENTRY(MD2, SECMOD_MD2_FLAG), |
| NSSUTIL_ARG_ENTRY(SSL, SECMOD_SSL_FLAG), |
| NSSUTIL_ARG_ENTRY(TLS, SECMOD_TLS_FLAG), |
| NSSUTIL_ARG_ENTRY(AES, SECMOD_AES_FLAG), |
| NSSUTIL_ARG_ENTRY(Camellia, SECMOD_CAMELLIA_FLAG), |
| NSSUTIL_ARG_ENTRY(SEED, SECMOD_SEED_FLAG), |
| NSSUTIL_ARG_ENTRY(PublicCerts, SECMOD_FRIENDLY_FLAG), |
| NSSUTIL_ARG_ENTRY(RANDOM, SECMOD_RANDOM_FLAG), |
| NSSUTIL_ARG_ENTRY(Disable, SECMOD_DISABLE_FLAG), |
| }; |
| |
| static int nssutil_argSlotFlagTableSize = |
| sizeof(nssutil_argSlotFlagTable) / sizeof(nssutil_argSlotFlagTable[0]); |
| |
| /* turn the slot flags into a bit mask */ |
| unsigned long |
| NSSUTIL_ArgParseSlotFlags(const char *label, const char *params) |
| { |
| char *flags; |
| const char *index; |
| unsigned long retValue = 0; |
| int i; |
| PRBool all = PR_FALSE; |
| |
| flags = NSSUTIL_ArgGetParamValue(label, params); |
| if (flags == NULL) |
| return 0; |
| |
| if (PORT_Strcasecmp(flags, "all") == 0) |
| all = PR_TRUE; |
| |
| for (index = flags; *index; index = NSSUTIL_ArgNextFlag(index)) { |
| for (i = 0; i < nssutil_argSlotFlagTableSize; i++) { |
| if (all || |
| (PORT_Strncasecmp(index, nssutil_argSlotFlagTable[i].name, |
| nssutil_argSlotFlagTable[i].len) == 0)) { |
| retValue |= nssutil_argSlotFlagTable[i].value; |
| } |
| } |
| } |
| PORT_Free(flags); |
| return retValue; |
| } |
| |
| /* parse a single slot specific parameter */ |
| static void |
| nssutil_argDecodeSingleSlotInfo(char *name, char *params, |
| struct NSSUTILPreSlotInfoStr *slotInfo) |
| { |
| char *askpw; |
| |
| slotInfo->slotID = NSSUTIL_ArgDecodeNumber(name); |
| slotInfo->defaultFlags = NSSUTIL_ArgParseSlotFlags("slotFlags", params); |
| slotInfo->timeout = NSSUTIL_ArgReadLong("timeout", params, 0, NULL); |
| |
| askpw = NSSUTIL_ArgGetParamValue("askpw", params); |
| slotInfo->askpw = 0; |
| |
| if (askpw) { |
| if (PORT_Strcasecmp(askpw, "every") == 0) { |
| slotInfo->askpw = -1; |
| } else if (PORT_Strcasecmp(askpw, "timeout") == 0) { |
| slotInfo->askpw = 1; |
| } |
| PORT_Free(askpw); |
| slotInfo->defaultFlags |= PK11_OWN_PW_DEFAULTS; |
| } |
| slotInfo->hasRootCerts = NSSUTIL_ArgHasFlag("rootFlags", "hasRootCerts", |
| params); |
| slotInfo->hasRootTrust = NSSUTIL_ArgHasFlag("rootFlags", "hasRootTrust", |
| params); |
| } |
| |
| /* parse all the slot specific parameters. */ |
| struct NSSUTILPreSlotInfoStr * |
| NSSUTIL_ArgParseSlotInfo(PLArenaPool *arena, const char *slotParams, |
| int *retCount) |
| { |
| const char *slotIndex; |
| struct NSSUTILPreSlotInfoStr *slotInfo = NULL; |
| int i = 0, count = 0, next; |
| |
| *retCount = 0; |
| if ((slotParams == NULL) || (*slotParams == 0)) |
| return NULL; |
| |
| /* first count the number of slots */ |
| for (slotIndex = NSSUTIL_ArgStrip(slotParams); *slotIndex; |
| slotIndex = NSSUTIL_ArgStrip(NSSUTIL_ArgSkipParameter(slotIndex))) { |
| count++; |
| } |
| |
| /* get the data structures */ |
| if (arena) { |
| slotInfo = PORT_ArenaZNewArray(arena, |
| struct NSSUTILPreSlotInfoStr, count); |
| } else { |
| slotInfo = PORT_ZNewArray(struct NSSUTILPreSlotInfoStr, count); |
| } |
| if (slotInfo == NULL) |
| return NULL; |
| |
| for (slotIndex = NSSUTIL_ArgStrip(slotParams), i = 0; |
| *slotIndex && i < count;) { |
| char *name; |
| name = NSSUTIL_ArgGetLabel(slotIndex, &next); |
| slotIndex += next; |
| |
| if (!NSSUTIL_ArgIsBlank(*slotIndex)) { |
| char *args = NSSUTIL_ArgFetchValue(slotIndex, &next); |
| slotIndex += next; |
| if (args) { |
| nssutil_argDecodeSingleSlotInfo(name, args, &slotInfo[i]); |
| i++; |
| PORT_Free(args); |
| } |
| } |
| if (name) |
| PORT_Free(name); |
| slotIndex = NSSUTIL_ArgStrip(slotIndex); |
| } |
| *retCount = i; |
| return slotInfo; |
| } |
| |
| /************************************************************************ |
| * make a new slot specific parameter |
| */ |
| /* first make the slot flags */ |
| static char * |
| nssutil_mkSlotFlags(unsigned long defaultFlags) |
| { |
| char *flags = NULL; |
| unsigned int i; |
| int j; |
| |
| for (i = 0; i < sizeof(defaultFlags) * 8; i++) { |
| if (defaultFlags & (1UL << i)) { |
| char *string = NULL; |
| |
| for (j = 0; j < nssutil_argSlotFlagTableSize; j++) { |
| if (nssutil_argSlotFlagTable[j].value == (1UL << i)) { |
| string = nssutil_argSlotFlagTable[j].name; |
| break; |
| } |
| } |
| if (string) { |
| if (flags) { |
| char *tmp; |
| tmp = PR_smprintf("%s,%s", flags, string); |
| PR_smprintf_free(flags); |
| flags = tmp; |
| } else { |
| flags = PR_smprintf("%s", string); |
| } |
| } |
| } |
| } |
| |
| return flags; |
| } |
| |
| /* now make the root flags */ |
| #define NSSUTIL_MAX_ROOT_FLAG_SIZE sizeof("hasRootCerts") + sizeof("hasRootTrust") |
| static char * |
| nssutil_mkRootFlags(PRBool hasRootCerts, PRBool hasRootTrust) |
| { |
| char *flags = (char *)PORT_ZAlloc(NSSUTIL_MAX_ROOT_FLAG_SIZE); |
| PRBool first = PR_TRUE; |
| |
| PORT_Memset(flags, 0, NSSUTIL_MAX_ROOT_FLAG_SIZE); |
| if (hasRootCerts) { |
| PORT_Strcat(flags, "hasRootCerts"); |
| first = PR_FALSE; |
| } |
| if (hasRootTrust) { |
| if (!first) |
| PORT_Strcat(flags, ","); |
| PORT_Strcat(flags, "hasRootTrust"); |
| } |
| return flags; |
| } |
| |
| /* now make a full slot string */ |
| char * |
| NSSUTIL_MkSlotString(unsigned long slotID, unsigned long defaultFlags, |
| unsigned long timeout, unsigned char askpw_in, |
| PRBool hasRootCerts, PRBool hasRootTrust) |
| { |
| char *askpw, *flags, *rootFlags, *slotString; |
| char *flagPair, *rootFlagsPair; |
| |
| switch (askpw_in) { |
| case 0xff: |
| askpw = "every"; |
| break; |
| case 1: |
| askpw = "timeout"; |
| break; |
| default: |
| askpw = "any"; |
| break; |
| } |
| flags = nssutil_mkSlotFlags(defaultFlags); |
| rootFlags = nssutil_mkRootFlags(hasRootCerts, hasRootTrust); |
| flagPair = nssutil_formatPair("slotFlags", flags, '\''); |
| rootFlagsPair = nssutil_formatPair("rootFlags", rootFlags, '\''); |
| if (flags) |
| PR_smprintf_free(flags); |
| if (rootFlags) |
| PORT_Free(rootFlags); |
| if (defaultFlags & PK11_OWN_PW_DEFAULTS) { |
| slotString = PR_smprintf("0x%08lx=[%s askpw=%s timeout=%d %s]", |
| (PRUint32)slotID, flagPair, askpw, timeout, |
| rootFlagsPair); |
| } else { |
| slotString = PR_smprintf("0x%08lx=[%s %s]", |
| (PRUint32)slotID, flagPair, rootFlagsPair); |
| } |
| nssutil_freePair(flagPair); |
| nssutil_freePair(rootFlagsPair); |
| return slotString; |
| } |
| |
| /************************************************************************ |
| * Parse Full module specs into: library, commonName, module parameters, |
| * and NSS specifi parameters. |
| */ |
| SECStatus |
| NSSUTIL_ArgParseModuleSpecEx(const char *modulespec, char **lib, char **mod, |
| char **parameters, char **nss, |
| char **config) |
| { |
| int next; |
| modulespec = NSSUTIL_ArgStrip(modulespec); |
| |
| *lib = *mod = *parameters = *nss = *config = 0; |
| |
| while (*modulespec) { |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *lib, "library=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *mod, "name=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *parameters, "parameters=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *nss, "nss=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *config, "config=", ;) |
| NSSUTIL_HANDLE_FINAL_ARG(modulespec) |
| } |
| return SECSuccess; |
| } |
| |
| /************************************************************************ |
| * Parse Full module specs into: library, commonName, module parameters, |
| * and NSS specifi parameters. |
| */ |
| SECStatus |
| NSSUTIL_ArgParseModuleSpec(const char *modulespec, char **lib, char **mod, |
| char **parameters, char **nss) |
| { |
| int next; |
| modulespec = NSSUTIL_ArgStrip(modulespec); |
| |
| *lib = *mod = *parameters = *nss = 0; |
| |
| while (*modulespec) { |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *lib, "library=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *mod, "name=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *parameters, "parameters=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(modulespec, *nss, "nss=", ;) |
| NSSUTIL_HANDLE_FINAL_ARG(modulespec) |
| } |
| return SECSuccess; |
| } |
| |
| /************************************************************************ |
| * make a new module spec from it's components */ |
| char * |
| NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName, char *parameters, |
| char *NSS, |
| char *config) |
| { |
| char *moduleSpec; |
| char *lib, *name, *param, *nss, *conf; |
| |
| /* |
| * now the final spec |
| */ |
| lib = nssutil_formatPair("library", dllName, '\"'); |
| name = nssutil_formatPair("name", commonName, '\"'); |
| param = nssutil_formatPair("parameters", parameters, '\"'); |
| nss = nssutil_formatPair("NSS", NSS, '\"'); |
| if (config) { |
| conf = nssutil_formatPair("config", config, '\"'); |
| moduleSpec = PR_smprintf("%s %s %s %s %s", lib, name, param, nss, conf); |
| nssutil_freePair(conf); |
| } else { |
| moduleSpec = PR_smprintf("%s %s %s %s", lib, name, param, nss); |
| } |
| nssutil_freePair(lib); |
| nssutil_freePair(name); |
| nssutil_freePair(param); |
| nssutil_freePair(nss); |
| return (moduleSpec); |
| } |
| |
| /************************************************************************ |
| * make a new module spec from it's components */ |
| char * |
| NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters, |
| char *NSS) |
| { |
| return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL); |
| } |
| |
| /************************************************************************ |
| * add a single flag to the Flags= section inside the spec's NSS= section */ |
| char * |
| NSSUTIL_AddNSSFlagToModuleSpec(char *spec, char *addFlag) |
| { |
| const char *prefix = "flags="; |
| const size_t prefixLen = strlen(prefix); |
| char *lib = NULL, *name = NULL, *param = NULL, *nss = NULL, *conf = NULL; |
| char *nss2 = NULL, *result = NULL; |
| SECStatus rv; |
| |
| rv = NSSUTIL_ArgParseModuleSpecEx(spec, &lib, &name, ¶m, &nss, &conf); |
| if (rv != SECSuccess) { |
| return NULL; |
| } |
| |
| if (nss && NSSUTIL_ArgHasFlag("flags", addFlag, nss)) { |
| /* It's already there, nothing to do! */ |
| PORT_Free(lib); |
| PORT_Free(name); |
| PORT_Free(param); |
| PORT_Free(nss); |
| PORT_Free(conf); |
| return PORT_Strdup(spec); |
| } |
| |
| if (!nss || !strlen(nss)) { |
| nss2 = PORT_Alloc(prefixLen + strlen(addFlag) + 1); |
| PORT_Strcpy(nss2, prefix); |
| PORT_Strcat(nss2, addFlag); |
| } else { |
| const char *iNss = nss; |
| PRBool alreadyAdded = PR_FALSE; |
| size_t maxSize = strlen(nss) + strlen(addFlag) + prefixLen + 2; /* space and null terminator */ |
| nss2 = PORT_Alloc(maxSize); |
| *nss2 = 0; |
| while (*iNss) { |
| iNss = NSSUTIL_ArgStrip(iNss); |
| if (PORT_Strncasecmp(iNss, prefix, prefixLen) == 0) { |
| /* We found an existing Flags= section. */ |
| char *oldFlags; |
| const char *valPtr; |
| int valSize; |
| valPtr = iNss + prefixLen; |
| oldFlags = NSSUTIL_ArgFetchValue(valPtr, &valSize); |
| iNss = valPtr + valSize; |
| PORT_Strcat(nss2, prefix); |
| PORT_Strcat(nss2, oldFlags); |
| PORT_Strcat(nss2, ","); |
| PORT_Strcat(nss2, addFlag); |
| PORT_Strcat(nss2, " "); |
| PORT_Free(oldFlags); |
| alreadyAdded = PR_TRUE; |
| iNss = NSSUTIL_ArgStrip(iNss); |
| PORT_Strcat(nss2, iNss); /* remainder of input */ |
| break; |
| } else { |
| /* Append this other name=value pair and continue. */ |
| const char *startOfNext = NSSUTIL_ArgSkipParameter(iNss); |
| PORT_Strncat(nss2, iNss, (startOfNext - iNss)); |
| if (nss2[strlen(nss2) - 1] != ' ') { |
| PORT_Strcat(nss2, " "); |
| } |
| iNss = startOfNext; |
| } |
| iNss = NSSUTIL_ArgStrip(iNss); |
| } |
| if (!alreadyAdded) { |
| /* nss wasn't empty, and it didn't contain a Flags section. We can |
| * assume that other content from nss has already been added to |
| * nss2, which means we already have a trailing space separator. */ |
| PORT_Strcat(nss2, prefix); |
| PORT_Strcat(nss2, addFlag); |
| } |
| } |
| |
| result = NSSUTIL_MkModuleSpecEx(lib, name, param, nss2, conf); |
| PORT_Free(lib); |
| PORT_Free(name); |
| PORT_Free(param); |
| PORT_Free(nss); |
| PORT_Free(nss2); |
| PORT_Free(conf); |
| return result; |
| } |
| |
| #define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA" |
| /****************************************************************************** |
| * Parse the cipher flags from the NSS parameter |
| */ |
| void |
| NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers, const char *cipherList) |
| { |
| newCiphers[0] = newCiphers[1] = 0; |
| if ((cipherList == NULL) || (*cipherList == 0)) |
| return; |
| |
| for (; *cipherList; cipherList = NSSUTIL_ArgNextFlag(cipherList)) { |
| if (PORT_Strncasecmp(cipherList, NSSUTIL_ARG_FORTEZZA_FLAG, |
| sizeof(NSSUTIL_ARG_FORTEZZA_FLAG) - 1) == 0) { |
| newCiphers[0] |= SECMOD_FORTEZZA_FLAG; |
| } |
| |
| /* add additional flags here as necessary */ |
| /* direct bit mapping escape */ |
| if (*cipherList == 0) { |
| if (cipherList[1] == 'l') { |
| newCiphers[1] |= atoi(&cipherList[2]); |
| } else { |
| newCiphers[0] |= atoi(&cipherList[2]); |
| } |
| } |
| } |
| } |
| |
| /********************************************************************* |
| * make NSS parameter... |
| */ |
| /* First make NSS specific flags */ |
| #define MAX_FLAG_SIZE sizeof("internal") + sizeof("FIPS") + sizeof("moduleDB") + \ |
| sizeof("moduleDBOnly") + sizeof("critical") |
| static char * |
| nssutil_mkNSSFlags(PRBool internal, PRBool isFIPS, |
| PRBool isModuleDB, PRBool isModuleDBOnly, PRBool isCritical) |
| { |
| char *flags = (char *)PORT_ZAlloc(MAX_FLAG_SIZE); |
| PRBool first = PR_TRUE; |
| |
| PORT_Memset(flags, 0, MAX_FLAG_SIZE); |
| if (internal) { |
| PORT_Strcat(flags, "internal"); |
| first = PR_FALSE; |
| } |
| if (isFIPS) { |
| if (!first) |
| PORT_Strcat(flags, ","); |
| PORT_Strcat(flags, "FIPS"); |
| first = PR_FALSE; |
| } |
| if (isModuleDB) { |
| if (!first) |
| PORT_Strcat(flags, ","); |
| PORT_Strcat(flags, "moduleDB"); |
| first = PR_FALSE; |
| } |
| if (isModuleDBOnly) { |
| if (!first) |
| PORT_Strcat(flags, ","); |
| PORT_Strcat(flags, "moduleDBOnly"); |
| first = PR_FALSE; |
| } |
| if (isCritical) { |
| if (!first) |
| PORT_Strcat(flags, ","); |
| PORT_Strcat(flags, "critical"); |
| } |
| return flags; |
| } |
| |
| /* construct the NSS cipher flags */ |
| static char * |
| nssutil_mkCipherFlags(unsigned long ssl0, unsigned long ssl1) |
| { |
| char *cipher = NULL; |
| unsigned int i; |
| |
| for (i = 0; i < sizeof(ssl0) * 8; i++) { |
| if (ssl0 & (1UL << i)) { |
| char *string; |
| if ((1UL << i) == SECMOD_FORTEZZA_FLAG) { |
| string = PR_smprintf("%s", NSSUTIL_ARG_FORTEZZA_FLAG); |
| } else { |
| string = PR_smprintf("0h0x%08lx", 1UL << i); |
| } |
| if (cipher) { |
| char *tmp; |
| tmp = PR_smprintf("%s,%s", cipher, string); |
| PR_smprintf_free(cipher); |
| PR_smprintf_free(string); |
| cipher = tmp; |
| } else { |
| cipher = string; |
| } |
| } |
| } |
| for (i = 0; i < sizeof(ssl0) * 8; i++) { |
| if (ssl1 & (1UL << i)) { |
| if (cipher) { |
| char *tmp; |
| tmp = PR_smprintf("%s,0l0x%08lx", cipher, 1UL << i); |
| PR_smprintf_free(cipher); |
| cipher = tmp; |
| } else { |
| cipher = PR_smprintf("0l0x%08lx", 1UL << i); |
| } |
| } |
| } |
| |
| return cipher; |
| } |
| |
| /* Assemble a full NSS string. */ |
| char * |
| NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal, |
| PRBool isFIPS, PRBool isModuleDB, PRBool isModuleDBOnly, |
| PRBool isCritical, unsigned long trustOrder, |
| unsigned long cipherOrder, unsigned long ssl0, unsigned long ssl1) |
| { |
| int slotLen, i; |
| char *slotParams, *ciphers, *nss, *nssFlags; |
| const char *tmp; |
| char *trustOrderPair, *cipherOrderPair, *slotPair, *cipherPair, *flagPair; |
| |
| /* now let's build up the string |
| * first the slot infos |
| */ |
| slotLen = 0; |
| for (i = 0; i < (int)slotCount; i++) { |
| slotLen += PORT_Strlen(slotStrings[i]) + 1; |
| } |
| slotLen += 1; /* space for the final NULL */ |
| |
| slotParams = (char *)PORT_ZAlloc(slotLen); |
| PORT_Memset(slotParams, 0, slotLen); |
| for (i = 0; i < (int)slotCount; i++) { |
| PORT_Strcat(slotParams, slotStrings[i]); |
| PORT_Strcat(slotParams, " "); |
| PR_smprintf_free(slotStrings[i]); |
| slotStrings[i] = NULL; |
| } |
| |
| /* |
| * now the NSS structure |
| */ |
| nssFlags = nssutil_mkNSSFlags(internal, isFIPS, isModuleDB, isModuleDBOnly, |
| isCritical); |
| /* for now only the internal module is critical */ |
| ciphers = nssutil_mkCipherFlags(ssl0, ssl1); |
| |
| trustOrderPair = nssutil_formatIntPair("trustOrder", trustOrder, |
| NSSUTIL_DEFAULT_TRUST_ORDER); |
| cipherOrderPair = nssutil_formatIntPair("cipherOrder", cipherOrder, |
| NSSUTIL_DEFAULT_CIPHER_ORDER); |
| slotPair = nssutil_formatPair("slotParams", slotParams, '{'); /* } */ |
| if (slotParams) |
| PORT_Free(slotParams); |
| cipherPair = nssutil_formatPair("ciphers", ciphers, '\''); |
| if (ciphers) |
| PR_smprintf_free(ciphers); |
| flagPair = nssutil_formatPair("Flags", nssFlags, '\''); |
| if (nssFlags) |
| PORT_Free(nssFlags); |
| nss = PR_smprintf("%s %s %s %s %s", trustOrderPair, |
| cipherOrderPair, slotPair, cipherPair, flagPair); |
| nssutil_freePair(trustOrderPair); |
| nssutil_freePair(cipherOrderPair); |
| nssutil_freePair(slotPair); |
| nssutil_freePair(cipherPair); |
| nssutil_freePair(flagPair); |
| tmp = NSSUTIL_ArgStrip(nss); |
| if (*tmp == '\0') { |
| PR_smprintf_free(nss); |
| nss = NULL; |
| } |
| return nss; |
| } |
| |
| /***************************************************************************** |
| * |
| * Private calls for use by softoken and utilmod.c |
| */ |
| |
| #define SQLDB "sql:" |
| #define EXTERNDB "extern:" |
| #define LEGACY "dbm:" |
| #define MULTIACCESS "multiaccess:" |
| #define SECMOD_DB "secmod.db" |
| const char * |
| _NSSUTIL_EvaluateConfigDir(const char *configdir, |
| NSSDBType *pdbType, char **appName) |
| { |
| NSSDBType dbType; |
| PRBool checkEnvDefaultDB = PR_FALSE; |
| *appName = NULL; |
| /* force the default */ |
| dbType = NSS_DB_TYPE_SQL; |
| if (configdir == NULL) { |
| checkEnvDefaultDB = PR_TRUE; |
| } else if (PORT_Strncmp(configdir, MULTIACCESS, sizeof(MULTIACCESS) - 1) == 0) { |
| char *cdir; |
| dbType = NSS_DB_TYPE_MULTIACCESS; |
| |
| *appName = PORT_Strdup(configdir + sizeof(MULTIACCESS) - 1); |
| if (*appName == NULL) { |
| return configdir; |
| } |
| cdir = *appName; |
| while (*cdir && *cdir != ':') { |
| cdir++; |
| } |
| if (*cdir == ':') { |
| *cdir = 0; |
| cdir++; |
| } |
| configdir = cdir; |
| } else if (PORT_Strncmp(configdir, SQLDB, sizeof(SQLDB) - 1) == 0) { |
| dbType = NSS_DB_TYPE_SQL; |
| configdir = configdir + sizeof(SQLDB) - 1; |
| } else if (PORT_Strncmp(configdir, EXTERNDB, sizeof(EXTERNDB) - 1) == 0) { |
| dbType = NSS_DB_TYPE_EXTERN; |
| configdir = configdir + sizeof(EXTERNDB) - 1; |
| } else if (PORT_Strncmp(configdir, LEGACY, sizeof(LEGACY) - 1) == 0) { |
| dbType = NSS_DB_TYPE_LEGACY; |
| configdir = configdir + sizeof(LEGACY) - 1; |
| } else { |
| checkEnvDefaultDB = PR_TRUE; |
| } |
| |
| /* look up the default from the environment */ |
| if (checkEnvDefaultDB) { |
| char *defaultType = PR_GetEnvSecure("NSS_DEFAULT_DB_TYPE"); |
| if (defaultType != NULL) { |
| if (PORT_Strncmp(defaultType, SQLDB, sizeof(SQLDB) - 2) == 0) { |
| dbType = NSS_DB_TYPE_SQL; |
| } else if (PORT_Strncmp(defaultType, EXTERNDB, sizeof(EXTERNDB) - 2) == 0) { |
| dbType = NSS_DB_TYPE_EXTERN; |
| } else if (PORT_Strncmp(defaultType, LEGACY, sizeof(LEGACY) - 2) == 0) { |
| dbType = NSS_DB_TYPE_LEGACY; |
| } |
| } |
| } |
| /* if the caller has already set a type, don't change it */ |
| if (*pdbType == NSS_DB_TYPE_NONE) { |
| *pdbType = dbType; |
| } |
| return configdir; |
| } |
| |
| char * |
| _NSSUTIL_GetSecmodName(const char *param, NSSDBType *dbType, char **appName, |
| char **filename, PRBool *rw) |
| { |
| int next; |
| char *configdir = NULL; |
| char *secmodName = NULL; |
| char *value = NULL; |
| const char *save_params = param; |
| const char *lconfigdir; |
| PRBool noModDB = PR_FALSE; |
| param = NSSUTIL_ArgStrip(param); |
| |
| while (*param) { |
| NSSUTIL_HANDLE_STRING_ARG(param, configdir, "configDir=", ;) |
| NSSUTIL_HANDLE_STRING_ARG(param, secmodName, "secmod=", ;) |
| NSSUTIL_HANDLE_FINAL_ARG(param) |
| } |
| |
| *rw = PR_TRUE; |
| if (NSSUTIL_ArgHasFlag("flags", "readOnly", save_params)) { |
| *rw = PR_FALSE; |
| } |
| |
| if (!secmodName || *secmodName == '\0') { |
| if (secmodName) |
| PORT_Free(secmodName); |
| secmodName = PORT_Strdup(SECMOD_DB); |
| } |
| |
| *filename = secmodName; |
| lconfigdir = _NSSUTIL_EvaluateConfigDir(configdir, dbType, appName); |
| |
| if (NSSUTIL_ArgHasFlag("flags", "noModDB", save_params)) { |
| /* there isn't a module db, don't load the legacy support */ |
| noModDB = PR_TRUE; |
| *dbType = NSS_DB_TYPE_SQL; |
| PORT_Free(*filename); |
| *filename = NULL; |
| *rw = PR_FALSE; |
| } |
| |
| /* only use the renamed secmod for legacy databases */ |
| if ((*dbType != NSS_DB_TYPE_LEGACY) && |
| (*dbType != NSS_DB_TYPE_MULTIACCESS) && |
| !NSSUTIL_ArgHasFlag("flags", "forceSecmodChoice", save_params)) { |
| secmodName = "pkcs11.txt"; |
| } |
| |
| if (noModDB) { |
| value = NULL; |
| } else if (lconfigdir && lconfigdir[0] != '\0') { |
| value = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s", |
| lconfigdir, secmodName); |
| } else { |
| value = PR_smprintf("%s", secmodName); |
| } |
| if (configdir) |
| PORT_Free(configdir); |
| return value; |
| } |