diff options
Diffstat (limited to 'security/nss/lib/util/utilpars.c')
-rw-r--r-- | security/nss/lib/util/utilpars.c | 1314 |
1 files changed, 1314 insertions, 0 deletions
diff --git a/security/nss/lib/util/utilpars.c b/security/nss/lib/util/utilpars.c new file mode 100644 index 0000000000..dd3d2326a9 --- /dev/null +++ b/security/nss/lib/util/utilpars.c @@ -0,0 +1,1314 @@ +/* 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; +} |