PageRenderTime 144ms CodeModel.GetById 62ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/pk11wrap/pk11pars.c

http://github.com/zpao/v8monkey
C | 1245 lines | 884 code | 133 blank | 228 comment | 219 complexity | 38452803650482f5d04fc273c48abbf0 MD5 | raw file
   1/* ***** BEGIN LICENSE BLOCK *****
   2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
   3 *
   4 * The contents of this file are subject to the Mozilla Public License Version
   5 * 1.1 (the "License"); you may not use this file except in compliance with
   6 * the License. You may obtain a copy of the License at
   7 * http://www.mozilla.org/MPL/
   8 *
   9 * Software distributed under the License is distributed on an "AS IS" basis,
  10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11 * for the specific language governing rights and limitations under the
  12 * License.
  13 *
  14 * The Original Code is the Netscape security libraries.
  15 *
  16 * The Initial Developer of the Original Code is
  17 * Netscape Communications Corporation.
  18 * Portions created by the Initial Developer are Copyright (C) 2001
  19 * the Initial Developer. All Rights Reserved.
  20 *
  21 * Contributor(s):
  22 *
  23 * Alternatively, the contents of this file may be used under the terms of
  24 * either the GNU General Public License Version 2 or later (the "GPL"), or
  25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  26 * in which case the provisions of the GPL or the LGPL are applicable instead
  27 * of those above. If you wish to allow use of your version of this file only
  28 * under the terms of either the GPL or the LGPL, and not to allow others to
  29 * use your version of this file under the terms of the MPL, indicate your
  30 * decision by deleting the provisions above and replace them with the notice
  31 * and other provisions required by the GPL or the LGPL. If you do not delete
  32 * the provisions above, a recipient may use your version of this file under
  33 * the terms of any one of the MPL, the GPL or the LGPL.
  34 *
  35 * ***** END LICENSE BLOCK ***** */
  36/*
  37 * The following handles the loading, unloading and management of
  38 * various PCKS #11 modules
  39 */
  40
  41#include <ctype.h>
  42#include "pkcs11.h"
  43#include "seccomon.h"
  44#include "secmod.h"
  45#include "secmodi.h"
  46#include "secmodti.h"
  47#include "pki3hack.h"
  48#include "secerr.h"
  49   
  50#include "pk11pars.h" 
  51
  52/* create a new module */
  53static  SECMODModule *
  54secmod_NewModule(void)
  55{
  56    SECMODModule *newMod;
  57    PRArenaPool *arena;
  58
  59
  60    /* create an arena in which dllName and commonName can be
  61     * allocated.
  62     */
  63    arena = PORT_NewArena(512);
  64    if (arena == NULL) {
  65	return NULL;
  66    }
  67
  68    newMod = (SECMODModule *)PORT_ArenaAlloc(arena,sizeof (SECMODModule));
  69    if (newMod == NULL) {
  70	PORT_FreeArena(arena,PR_FALSE);
  71	return NULL;
  72    }
  73
  74    /*
  75     * initialize of the fields of the module
  76     */
  77    newMod->arena = arena;
  78    newMod->internal = PR_FALSE;
  79    newMod->loaded = PR_FALSE;
  80    newMod->isFIPS = PR_FALSE;
  81    newMod->dllName = NULL;
  82    newMod->commonName = NULL;
  83    newMod->library = NULL;
  84    newMod->functionList = NULL;
  85    newMod->slotCount = 0;
  86    newMod->slots = NULL;
  87    newMod->slotInfo = NULL;
  88    newMod->slotInfoCount = 0;
  89    newMod->refCount = 1;
  90    newMod->ssl[0] = 0;
  91    newMod->ssl[1] = 0;
  92    newMod->libraryParams = NULL;
  93    newMod->moduleDBFunc = NULL;
  94    newMod->parent = NULL;
  95    newMod->isCritical = PR_FALSE;
  96    newMod->isModuleDB = PR_FALSE;
  97    newMod->moduleDBOnly = PR_FALSE;
  98    newMod->trustOrder = 0;
  99    newMod->cipherOrder = 0;
 100    newMod->evControlMask = 0;
 101    newMod->refLock = PZ_NewLock(nssILockRefLock);
 102    if (newMod->refLock == NULL) {
 103	PORT_FreeArena(arena,PR_FALSE);
 104	return NULL;
 105    }
 106    return newMod;
 107    
 108}
 109
 110/* private flags for isModuleDB (field in SECMODModule). */
 111/* The meaing of these flags is as follows:
 112 *
 113 * SECMOD_FLAG_MODULE_DB_IS_MODULE_DB - This is a module that accesses the 
 114 *   database of other modules to load. Module DBs are loadable modules that
 115 *   tells NSS which PKCS #11 modules to load and when. These module DBs are 
 116 *   chainable. That is, one module DB can load another one. NSS system init 
 117 *   design takes advantage of this feature. In system NSS, a fixed system 
 118 *   module DB loads the system defined libraries, then chains out to the 
 119 *   traditional module DBs to load any system or user configured modules 
 120 *   (like smart cards). This bit is the same as the already existing meaning 
 121 *   of  isModuleDB = PR_TRUE. None of the other module db flags should be set 
 122 *   if this flag isn't on.
 123 *
 124 * SECMOD_FLAG_MODULE_DB_SKIP_FIRST - This flag tells NSS to skip the first 
 125 *   PKCS #11 module presented by a module DB. This allows the OS to load a 
 126 *   softoken from the system module, then ask the existing module DB code to 
 127 *   load the other PKCS #11 modules in that module DB (skipping it's request 
 128 *   to load softoken). This gives the system init finer control over the 
 129 *   configuration of that softoken module.
 130 *
 131 * SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB - This flag allows system init to mark a 
 132 *   different module DB as the 'default' module DB (the one in which 
 133 *   'Add module' changes will go). Without this flag NSS takes the first 
 134 *   module as the default Module DB, but in system NSS, that first module 
 135 *   is the system module, which is likely read only (at least to the user).
 136 *   This  allows system NSS to delegate those changes to the user's module DB, 
 137 *   preserving the user's ability to load new PKCS #11 modules (which only 
 138 *   affect him), from existing applications like Firefox.
 139 */
 140#define SECMOD_FLAG_MODULE_DB_IS_MODULE_DB  0x01 /* must be set if any of the 
 141						  *other flags are set */
 142#define SECMOD_FLAG_MODULE_DB_SKIP_FIRST    0x02
 143#define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04
 144
 145
 146/* private flags for internal (field in SECMODModule). */
 147/* The meaing of these flags is as follows:
 148 *
 149 * SECMOD_FLAG_INTERNAL_IS_INTERNAL - This is a marks the the module is
 150 *   the internal module (that is, softoken). This bit is the same as the 
 151 *   already existing meaning of internal = PR_TRUE. None of the other 
 152 *   internal flags should be set if this flag isn't on.
 153 *
 154 * SECMOD_FLAG_MODULE_INTERNAL_KEY_SLOT - This flag allows system init to mark 
 155 *   a  different slot returned byt PK11_GetInternalKeySlot(). The 'primary'
 156 *   slot defined by this module will be the new internal key slot.
 157 */
 158#define SECMOD_FLAG_INTERNAL_IS_INTERNAL       0x01 /* must be set if any of 
 159						     *the other flags are set */
 160#define SECMOD_FLAG_INTERNAL_KEY_SLOT          0x02
 161
 162/*
 163 * for 3.4 we continue to use the old SECMODModule structure
 164 */
 165SECMODModule *
 166SECMOD_CreateModule(const char *library, const char *moduleName, 
 167				const char *parameters, const char *nss)
 168{
 169    SECMODModule *mod = secmod_NewModule();
 170    char *slotParams,*ciphers;
 171    /* pk11pars.h still does not have const char * interfaces */
 172    char *nssc = (char *)nss;
 173    if (mod == NULL) return NULL;
 174
 175    mod->commonName = PORT_ArenaStrdup(mod->arena,moduleName ? moduleName : "");
 176    if (library) {
 177	mod->dllName = PORT_ArenaStrdup(mod->arena,library);
 178    }
 179    /* new field */
 180    if (parameters) {
 181	mod->libraryParams = PORT_ArenaStrdup(mod->arena,parameters);
 182    }
 183    mod->internal   = secmod_argHasFlag("flags","internal",nssc);
 184    mod->isFIPS     = secmod_argHasFlag("flags","FIPS",nssc);
 185    mod->isCritical = secmod_argHasFlag("flags","critical",nssc);
 186    slotParams      = secmod_argGetParamValue("slotParams",nssc);
 187    mod->slotInfo   = secmod_argParseSlotInfo(mod->arena,slotParams,
 188							&mod->slotInfoCount);
 189    if (slotParams) PORT_Free(slotParams);
 190    /* new field */
 191    mod->trustOrder  = secmod_argReadLong("trustOrder",nssc,
 192					SECMOD_DEFAULT_TRUST_ORDER,NULL);
 193    /* new field */
 194    mod->cipherOrder = secmod_argReadLong("cipherOrder",nssc,
 195					SECMOD_DEFAULT_CIPHER_ORDER,NULL);
 196    /* new field */
 197    mod->isModuleDB   = secmod_argHasFlag("flags","moduleDB",nssc);
 198    mod->moduleDBOnly = secmod_argHasFlag("flags","moduleDBOnly",nssc);
 199    if (mod->moduleDBOnly) mod->isModuleDB = PR_TRUE;
 200
 201    /* we need more bits, but we also want to preserve binary compatibility 
 202     * so we overload the isModuleDB PRBool with additional flags. 
 203     * These flags are only valid if mod->isModuleDB is already set.
 204     * NOTE: this depends on the fact that PRBool is at least a char on 
 205     * all platforms. These flags are only valid if moduleDB is set, so 
 206     * code checking if (mod->isModuleDB) will continue to work correctly. */
 207    if (mod->isModuleDB) {
 208	char flags = SECMOD_FLAG_MODULE_DB_IS_MODULE_DB;
 209	if (secmod_argHasFlag("flags","skipFirst",nssc)) {
 210	    flags |= SECMOD_FLAG_MODULE_DB_SKIP_FIRST;
 211	}
 212	if (secmod_argHasFlag("flags","defaultModDB",nssc)) {
 213	    flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB;
 214	}
 215	/* additional moduleDB flags could be added here in the future */
 216	mod->isModuleDB = (PRBool) flags;
 217    }
 218
 219    if (mod->internal) {
 220	char flags = SECMOD_FLAG_INTERNAL_IS_INTERNAL;
 221
 222	if (secmod_argHasFlag("flags", "internalKeySlot", nssc)) {
 223	    flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
 224	}
 225	mod->internal = (PRBool) flags;
 226    }
 227
 228    ciphers = secmod_argGetParamValue("ciphers",nssc);
 229    secmod_argSetNewCipherFlags(&mod->ssl[0],ciphers);
 230    if (ciphers) PORT_Free(ciphers);
 231
 232    secmod_PrivateModuleCount++;
 233
 234    return mod;
 235}
 236
 237PRBool
 238SECMOD_GetSkipFirstFlag(SECMODModule *mod)
 239{
 240   char flags = (char) mod->isModuleDB;
 241
 242   return (flags & SECMOD_FLAG_MODULE_DB_SKIP_FIRST) ? PR_TRUE : PR_FALSE;
 243}
 244
 245PRBool
 246SECMOD_GetDefaultModDBFlag(SECMODModule *mod)
 247{
 248   char flags = (char) mod->isModuleDB;
 249
 250   return (flags & SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE;
 251}
 252
 253PRBool
 254secmod_IsInternalKeySlot(SECMODModule *mod)
 255{
 256   char flags = (char) mod->internal;
 257
 258   return (flags & SECMOD_FLAG_INTERNAL_KEY_SLOT) ? PR_TRUE : PR_FALSE;
 259}
 260
 261void
 262secmod_SetInternalKeySlotFlag(SECMODModule *mod, PRBool val)
 263{
 264   char flags = (char) mod->internal;
 265
 266   if (val)  {
 267	flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
 268   } else {
 269	flags &= ~SECMOD_FLAG_INTERNAL_KEY_SLOT;
 270   }
 271   mod->internal = flags;
 272}
 273
 274/* forward declarations */
 275static int secmod_escapeSize(const char *string, char quote);
 276static char *secmod_addEscape(const char *string, char quote);
 277
 278/*
 279 * copy desc and value into target. Target is known to be big enough to
 280 * hold desc +2 +value, which is good because the result of this will be
 281 * *desc"*value". We may, however, have to add some escapes for special
 282 * characters imbedded into value (rare). This string potentially comes from
 283 * a user, so we don't want the user overflowing the target buffer by using
 284 * excessive escapes. To prevent this we count the escapes we need to add and
 285 * try to expand the buffer with Realloc.
 286 */
 287static char *
 288secmod_doDescCopy(char *target, int *targetLen, const char *desc,
 289			int descLen, char *value)
 290{
 291    int diff, esc_len;
 292
 293    esc_len = secmod_escapeSize(value, '\"') - 1;
 294    diff = esc_len - strlen(value);
 295    if (diff > 0) {
 296	/* we need to escape... expand newSpecPtr as well to make sure
 297	 * we don't overflow it */
 298	char *newPtr = PORT_Realloc(target, *targetLen * diff);
 299	if (!newPtr) {
 300	    return target; /* not enough space, just drop the whole copy */
 301	}
 302	*targetLen += diff;
 303	target = newPtr;
 304	value = secmod_addEscape(value, '\"');
 305	if (value == NULL) {
 306	    return target; /* couldn't escape value, just drop the copy */
 307	}
 308    }
 309    PORT_Memcpy(target, desc, descLen);
 310    target += descLen;
 311    *target++='\"';
 312    PORT_Memcpy(target, value, esc_len);
 313    target += esc_len;
 314    *target++='\"';
 315    return target;
 316}
 317
 318#define SECMOD_SPEC_COPY(new, start, end)    \
 319  if (end > start) {                         \
 320	int _cnt = end - start;	             \
 321	PORT_Memcpy(new, start, _cnt);       \
 322	new += _cnt;                         \
 323  }
 324#define SECMOD_TOKEN_DESCRIPTION "tokenDescription="
 325#define SECMOD_SLOT_DESCRIPTION   "slotDescription="
 326
 327
 328/*
 329 * Find any tokens= values in the module spec. 
 330 * Always return a new spec which does not have any tokens= arguments.
 331 * If tokens= arguments are found, Split the the various tokens defined into
 332 * an array of child specs to return.
 333 *
 334 * Caller is responsible for freeing the child spec and the new token
 335 * spec.
 336 */
 337char *
 338secmod_ParseModuleSpecForTokens(PRBool convert, PRBool isFIPS, 
 339				char *moduleSpec, char ***children, 
 340				CK_SLOT_ID **ids)
 341{
 342    int        newSpecLen   = PORT_Strlen(moduleSpec)+2;
 343    char       *newSpec     = PORT_Alloc(newSpecLen);
 344    char       *newSpecPtr  = newSpec;
 345    char       *modulePrev  = moduleSpec;
 346    char       *target      = NULL;
 347    char *tmp = NULL;
 348    char       **childArray = NULL;
 349    char       *tokenIndex;
 350    CK_SLOT_ID *idArray     = NULL;
 351    int        tokenCount = 0;
 352    int        i;
 353
 354    if (newSpec == NULL) {
 355	return NULL;
 356    }
 357
 358    *children = NULL;
 359    if (ids) {
 360	*ids = NULL;
 361    }
 362    moduleSpec = secmod_argStrip(moduleSpec);
 363    SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
 364
 365    /* Notes on 'convert' and 'isFIPS' flags: The base parameters for opening 
 366     * a new softoken module takes the following parameters to name the 
 367     * various tokens:
 368     *  
 369     *  cryptoTokenDescription: name of the non-fips crypto token.
 370     *  cryptoSlotDescription: name of the non-fips crypto slot.
 371     *  dbTokenDescription: name of the non-fips db token.
 372     *  dbSlotDescription: name of the non-fips db slot.
 373     *  FIPSTokenDescription: name of the fips db/crypto token.
 374     *  FIPSSlotDescription: name of the fips db/crypto slot.
 375     *
 376     * if we are opening a new slot, we need to have the following
 377     * parameters:
 378     *  tokenDescription: name of the token.
 379     *  slotDescription: name of the slot.
 380     *
 381     *
 382     * The convert flag tells us to drop the unnecessary *TokenDescription 
 383     * and *SlotDescription arguments and convert the appropriate pair 
 384     * (either db or FIPS based on the isFIPS flag) to tokenDescription and 
 385     * slotDescription).
 386     */
 387    /*
 388     * walk down the list. if we find a tokens= argument, save it,
 389     * otherise copy the argument.
 390     */
 391    while (*moduleSpec) {
 392	int next;
 393	modulePrev = moduleSpec;
 394	SECMOD_HANDLE_STRING_ARG(moduleSpec, target, "tokens=",
 395			modulePrev = moduleSpec; /* skip copying */ )
 396	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoTokenDescription=",
 397			if (convert) { modulePrev = moduleSpec; } );
 398	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoSlotDescription=",
 399			if (convert) { modulePrev = moduleSpec; } );
 400	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "dbTokenDescription=",
 401			if (convert) {
 402			    modulePrev = moduleSpec; 
 403			    if (!isFIPS) {
 404				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
 405				    &newSpecLen, SECMOD_TOKEN_DESCRIPTION, 
 406				    sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp);
 407			    }
 408			});
 409	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "dbSlotDescription=",
 410			if (convert) {
 411			    modulePrev = moduleSpec; /* skip copying */ 
 412			    if (!isFIPS) {
 413				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
 414				    &newSpecLen, SECMOD_SLOT_DESCRIPTION, 
 415				    sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp);
 416			    }
 417			} );
 418	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSTokenDescription=",
 419			if (convert) {
 420			    modulePrev = moduleSpec; /* skip copying */ 
 421			    if (isFIPS) {
 422				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
 423				    &newSpecLen, SECMOD_TOKEN_DESCRIPTION, 
 424				    sizeof(SECMOD_TOKEN_DESCRIPTION)-1, tmp);
 425			    }
 426			} );
 427	SECMOD_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSSlotDescription=",
 428			if (convert) {
 429			    modulePrev = moduleSpec; /* skip copying */ 
 430			    if (isFIPS) {
 431				newSpecPtr = secmod_doDescCopy(newSpecPtr, 
 432				    &newSpecLen, SECMOD_SLOT_DESCRIPTION, 
 433				    sizeof(SECMOD_SLOT_DESCRIPTION)-1, tmp);
 434			    }
 435			} );
 436	SECMOD_HANDLE_FINAL_ARG(moduleSpec)
 437	SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
 438    }
 439    if (tmp) {
 440	PORT_Free(tmp);
 441	tmp = NULL;
 442    }
 443    *newSpecPtr = 0;
 444
 445    /* no target found, return the newSpec */
 446    if (target == NULL) {
 447	return newSpec;
 448    }
 449
 450    /* now build the child array from target */
 451    /*first count them */
 452    for (tokenIndex = secmod_argStrip(target); *tokenIndex;
 453	tokenIndex = secmod_argStrip(secmod_argSkipParameter(tokenIndex))) {
 454	tokenCount++;
 455    }
 456
 457    childArray = PORT_NewArray(char *, tokenCount+1);
 458    if (childArray == NULL) {
 459	/* just return the spec as is then */
 460	PORT_Free(target);
 461	return newSpec;
 462    }
 463    if (ids) {
 464	idArray = PORT_NewArray(CK_SLOT_ID, tokenCount+1);
 465	if (idArray == NULL) {
 466	    PORT_Free(childArray);
 467	    PORT_Free(target);
 468	    return newSpec;
 469	}
 470    }
 471
 472    /* now fill them in */
 473    for (tokenIndex = secmod_argStrip(target), i=0 ; 
 474			*tokenIndex && (i < tokenCount); 
 475			tokenIndex=secmod_argStrip(tokenIndex)) {
 476	int next;
 477	char *name = secmod_argGetName(tokenIndex, &next);
 478	tokenIndex += next;
 479
 480 	if (idArray) {
 481	   idArray[i] = secmod_argDecodeNumber(name);
 482	}
 483
 484	PORT_Free(name); /* drop the explicit number */
 485
 486	/* if anything is left, copy the args to the child array */
 487	if (!secmod_argIsBlank(*tokenIndex)) {
 488	    childArray[i++] = secmod_argFetchValue(tokenIndex, &next);
 489	    tokenIndex += next;
 490	}
 491    }
 492
 493    PORT_Free(target);
 494    childArray[i] = 0;
 495    if (idArray) {
 496	idArray[i] = 0;
 497    }
 498
 499    /* return it */
 500    *children = childArray;
 501    if (ids) {
 502	*ids = idArray;
 503    }
 504    return newSpec;
 505}
 506
 507/* get the database and flags from the spec */
 508static char *
 509secmod_getConfigDir(char *spec, char **certPrefix, char **keyPrefix,
 510			  PRBool *readOnly)
 511{
 512    char * config = NULL;
 513
 514    *certPrefix = NULL;
 515    *keyPrefix = NULL;
 516    *readOnly = secmod_argHasFlag("flags","readOnly",spec);
 517
 518    spec = secmod_argStrip(spec);
 519    while (*spec) {
 520	int next;
 521	SECMOD_HANDLE_STRING_ARG(spec, config, "configdir=", ;)
 522	SECMOD_HANDLE_STRING_ARG(spec, *certPrefix, "certPrefix=", ;)
 523	SECMOD_HANDLE_STRING_ARG(spec, *keyPrefix, "keyPrefix=", ;)
 524	SECMOD_HANDLE_FINAL_ARG(spec)
 525    }
 526    return config;
 527}
 528
 529struct SECMODConfigListStr {
 530    char *config;
 531    char *certPrefix;
 532    char *keyPrefix;
 533    PRBool isReadOnly;
 534};
 535
 536/*
 537 * return an array of already openned databases from a spec list.
 538 */
 539SECMODConfigList *
 540secmod_GetConfigList(PRBool isFIPS, char *spec, int *count)
 541{
 542    char **children;
 543    CK_SLOT_ID *ids;
 544    char *strippedSpec;
 545    int childCount;
 546    SECMODConfigList *conflist = NULL;
 547    int i;
 548
 549    strippedSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, isFIPS, 
 550						spec,&children,&ids);
 551    if (strippedSpec == NULL) {
 552	return NULL;
 553    }
 554
 555    for (childCount=0; children && children[childCount]; childCount++) ;
 556    *count = childCount+1; /* include strippedSpec */
 557    conflist = PORT_NewArray(SECMODConfigList,*count);
 558    if (conflist == NULL) {
 559	*count = 0;
 560	goto loser;
 561    }
 562
 563    conflist[0].config = secmod_getConfigDir(strippedSpec, 
 564					    &conflist[0].certPrefix, 
 565					    &conflist[0].keyPrefix,
 566					    &conflist[0].isReadOnly);
 567    for (i=0; i < childCount; i++) {
 568	conflist[i+1].config = secmod_getConfigDir(children[i], 
 569					    &conflist[i+1].certPrefix, 
 570					    &conflist[i+1].keyPrefix,
 571					    &conflist[i+1].isReadOnly);
 572    }
 573
 574loser:
 575    secmod_FreeChildren(children, ids);
 576    PORT_Free(strippedSpec);
 577    return conflist;
 578}
 579
 580/*
 581 * determine if we are trying to open an old dbm database. For this test
 582 * RDB databases should return PR_FALSE.
 583 */
 584static PRBool
 585secmod_configIsDBM(char *configDir)
 586{
 587    char *env;
 588
 589    /* explicit dbm open */
 590    if (strncmp(configDir, "dbm:", 4) == 0) {
 591	return PR_TRUE;
 592    }
 593    /* explicit open of a non-dbm database */
 594    if ((strncmp(configDir, "sql:",4) == 0) 
 595	|| (strncmp(configDir, "rdb:", 4) == 0)
 596	|| (strncmp(configDir, "extern:", 7) == 0)) {
 597	return PR_FALSE;
 598    }
 599    env = PR_GetEnv("NSS_DEFAULT_DB_TYPE");
 600    /* implicit dbm open */
 601    if ((env == NULL) || (strcmp(env,"dbm") == 0)) {
 602	return PR_TRUE;
 603    }
 604    /* implicit non-dbm open */
 605    return PR_FALSE;
 606}
 607
 608/*
 609 * match two prefixes. prefix may be NULL. NULL patches '\0'
 610 */
 611static PRBool
 612secmod_matchPrefix(char *prefix1, char *prefix2)
 613{
 614    if ((prefix1 == NULL) || (*prefix1 == 0)) {
 615	if ((prefix2 == NULL) || (*prefix2 == 0)) {
 616	    return PR_TRUE;
 617	}
 618	return PR_FALSE;
 619    }
 620    if (strcmp(prefix1, prefix2) == 0) {
 621	return PR_TRUE;
 622    }
 623    return PR_FALSE;
 624}
 625
 626/*
 627 * return true if we are requesting a database that is already openned.
 628 */
 629PRBool
 630secmod_MatchConfigList(char *spec, SECMODConfigList *conflist, int count)
 631{
 632    char *config;
 633    char *certPrefix;
 634    char *keyPrefix;
 635    PRBool isReadOnly;
 636    PRBool ret=PR_FALSE;
 637    int i;
 638
 639    config = secmod_getConfigDir(spec, &certPrefix, &keyPrefix, &isReadOnly);
 640    if (!config) {
 641	ret=PR_TRUE;
 642	goto done;
 643    }
 644
 645    /* NOTE: we dbm isn't multiple open safe. If we open the same database 
 646     * twice from two different locations, then we can corrupt our database
 647     * (the cache will be inconsistent). Protect against this by claiming
 648     * for comparison only that we are always openning dbm databases read only.
 649     */
 650    if (secmod_configIsDBM(config)) {
 651	isReadOnly = 1;
 652    }
 653    for (i=0; i < count; i++) {
 654	if ((strcmp(config,conflist[i].config) == 0)  &&
 655	    secmod_matchPrefix(certPrefix, conflist[i].certPrefix) &&
 656	    secmod_matchPrefix(keyPrefix, conflist[i].keyPrefix) &&
 657	    /* this last test -- if we just need the DB open read only,
 658	     * than any open will suffice, but if we requested it read/write
 659	     * and it's only open read only, we need to open it again */
 660	    (isReadOnly || !conflist[i].isReadOnly)) {
 661	    ret = PR_TRUE;
 662	    goto done;
 663	}
 664    }
 665
 666    ret = PR_FALSE;
 667done:
 668    PORT_Free(config);
 669    PORT_Free(certPrefix);
 670    PORT_Free(keyPrefix);
 671    return ret;
 672}
 673
 674void
 675secmod_FreeConfigList(SECMODConfigList *conflist, int count)
 676{
 677    int i;
 678    for (i=0; i < count; i++) {
 679	PORT_Free(conflist[i].config);
 680	PORT_Free(conflist[i].certPrefix);
 681	PORT_Free(conflist[i].keyPrefix);
 682    }
 683    PORT_Free(conflist);
 684}
 685
 686void
 687secmod_FreeChildren(char **children, CK_SLOT_ID *ids)
 688{
 689    char **thisChild;
 690
 691    if (!children) {
 692	return;
 693    }
 694
 695    for (thisChild = children; thisChild && *thisChild; thisChild++ ) {
 696	PORT_Free(*thisChild);
 697    }
 698    PORT_Free(children);
 699    if (ids) {
 700	PORT_Free(ids);
 701    }
 702    return;
 703}
 704
 705
 706static int
 707secmod_escapeSize(const char *string, char quote)
 708{
 709    int escapes = 0, size = 0;
 710    const char *src;
 711    for (src=string; *src ; src++) {
 712        if ((*src == quote) || (*src == '\\')) escapes++;
 713        size++;
 714    }
 715
 716    return escapes+size+1;
 717}
 718
 719
 720/*
 721 * add escapes to protect quote characters...
 722 */
 723static char *
 724secmod_addEscape(const char *string, char quote)
 725{
 726    char *newString = 0;
 727    int size = 0;
 728    const char *src;
 729    char *dest;
 730
 731
 732    size = secmod_escapeSize(string,quote);
 733    newString = PORT_ZAlloc(size);
 734    if (newString == NULL) {
 735        return NULL;
 736    }
 737
 738    for (src=string, dest=newString; *src; src++,dest++) {
 739        if ((*src == '\\') || (*src == quote)) {
 740            *dest++ = '\\';
 741        }
 742        *dest = *src;
 743    }
 744
 745    return newString;
 746}
 747
 748static int
 749secmod_doubleEscapeSize(const char *string, char quote1, char quote2)
 750{
 751    int escapes = 0, size = 0;
 752    const char *src;
 753    for (src=string; *src ; src++) {
 754        if (*src == '\\')   escapes+=3; /* \\\\ */
 755        if (*src == quote1) escapes+=2; /* \\quote1 */
 756        if (*src == quote2) escapes++;   /* \quote2 */
 757        size++;
 758    }
 759
 760    return escapes+size+1;
 761}
 762
 763char *
 764secmod_DoubleEscape(const char *string, char quote1, char quote2)
 765{
 766    char *round1 = NULL;
 767    char *retValue = NULL;
 768    if (string == NULL) {
 769        goto done;
 770    }
 771    round1 = secmod_addEscape(string,quote1);
 772    if (round1) {
 773        retValue = secmod_addEscape(round1,quote2);
 774        PORT_Free(round1);
 775    }
 776
 777done:
 778    if (retValue == NULL) {
 779        retValue = PORT_Strdup("");
 780    }
 781    return retValue;
 782}
 783
 784
 785/*
 786 * caclulate the length of each child record:
 787 * " 0x{id}=<{escaped_child}>"
 788 */
 789static int
 790secmod_getChildLength(char *child, CK_SLOT_ID id)
 791{
 792    int length = secmod_doubleEscapeSize(child, '>', ']');
 793    if (id == 0) {
 794	length++;
 795    }
 796    while (id) {
 797	length++;
 798	id = id >> 4;
 799    }
 800    length += 6; /* {sp}0x[id]=<{child}> */
 801    return length;
 802}
 803
 804/*
 805 * Build a child record:
 806 * " 0x{id}=<{escaped_child}>"
 807 */
 808static SECStatus
 809secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id)
 810{
 811    int len;
 812    char *escSpec;
 813
 814    len = PR_snprintf(*next, *length, " 0x%x=<",id);
 815    if (len < 0) {
 816	return SECFailure;
 817    }
 818    *next += len;
 819    *length -= len;
 820    escSpec = secmod_DoubleEscape(child, '>', ']');
 821    if (escSpec == NULL) {
 822	return SECFailure;
 823    }
 824    if (*child && (*escSpec == 0)) {
 825	PORT_Free(escSpec);
 826	return SECFailure;
 827    }
 828    len = strlen(escSpec);
 829    if (len+1 > *length) {
 830	PORT_Free(escSpec);
 831	return SECFailure;
 832    }
 833    PORT_Memcpy(*next,escSpec, len);
 834    *next += len;
 835    *length -= len;
 836    PORT_Free(escSpec);
 837    **next = '>';
 838    (*next)++;
 839    (*length)--;
 840    return SECSuccess;
 841}
 842
 843#define TOKEN_STRING " tokens=["
 844
 845char *
 846secmod_MkAppendTokensList(PRArenaPool *arena, char *oldParam, char *newToken, 
 847			CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids)
 848{
 849    char *rawParam = NULL;	/* oldParam with tokens stripped off */
 850    char *newParam = NULL;	/* space for the return parameter */
 851    char *nextParam = NULL;	/* current end of the new parameter */
 852    char **oldChildren = NULL;
 853    CK_SLOT_ID *oldIds = NULL;
 854    void *mark = NULL;         /* mark the arena pool in case we need 
 855				* to release it */
 856    int length, i, tmpLen;
 857    SECStatus rv;
 858
 859    /* first strip out and save the old tokenlist */
 860    rawParam = secmod_ParseModuleSpecForTokens(PR_FALSE,PR_FALSE, 
 861					oldParam,&oldChildren,&oldIds);
 862    if (!rawParam) {
 863	goto loser;
 864    }
 865
 866    /* now calculate the total length of the new buffer */
 867    /* First the 'fixed stuff', length of rawparam (does not include a NULL),
 868     * length of the token string (does include the NULL), closing bracket */
 869    length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1;
 870    /* now add then length of all the old children */
 871    for (i=0; oldChildren && oldChildren[i]; i++) {
 872	length += secmod_getChildLength(oldChildren[i], oldIds[i]);
 873    }
 874
 875    /* add the new token */
 876    length += secmod_getChildLength(newToken, newID);
 877
 878    /* and it's new children */
 879    for (i=0; children && children[i]; i++) {
 880	if (ids[i] == -1) {
 881	    continue;
 882	}
 883	length += secmod_getChildLength(children[i], ids[i]);
 884    }
 885
 886    /* now allocate and build the string */
 887    mark = PORT_ArenaMark(arena);
 888    if (!mark) {
 889	goto loser;
 890    }
 891    newParam =  PORT_ArenaAlloc(arena,length);
 892    if (!newParam) {
 893	goto loser;
 894    }
 895
 896    PORT_Strcpy(newParam, oldParam);
 897    tmpLen = strlen(oldParam);
 898    nextParam = newParam + tmpLen;
 899    length -= tmpLen;
 900    PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING)-1);
 901    nextParam += sizeof(TOKEN_STRING)-1;
 902    length -= sizeof(TOKEN_STRING)-1;
 903
 904    for (i=0; oldChildren && oldChildren[i]; i++) {
 905	rv = secmod_mkTokenChild(&nextParam,&length,oldChildren[i],oldIds[i]);
 906	if (rv != SECSuccess) {
 907	    goto loser;
 908	}
 909    }
 910
 911    rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID);
 912    if (rv != SECSuccess) {
 913	goto loser;
 914    }
 915
 916    for (i=0; children && children[i]; i++) {
 917	if (ids[i] == -1) {
 918	    continue;
 919	}
 920	rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]);
 921	if (rv != SECSuccess) {
 922	    goto loser;
 923	}
 924    }
 925
 926    if (length < 2) {
 927	goto loser;
 928    }
 929
 930    *nextParam++ = ']';
 931    *nextParam++ = 0;
 932
 933    /* we are going to return newParam now, don't release the mark */
 934    PORT_ArenaUnmark(arena, mark);
 935    mark = NULL;
 936
 937loser:
 938    if (mark) {
 939	PORT_ArenaRelease(arena, mark);
 940	newParam = NULL; /* if the mark is still active, 
 941			  * don't return the param */
 942    }
 943    if (rawParam) {
 944	PORT_Free(rawParam);
 945    }
 946    if (oldChildren) {
 947	secmod_FreeChildren(oldChildren, oldIds);
 948    }
 949    return newParam;
 950}
 951    
 952static char *
 953secmod_mkModuleSpec(SECMODModule * module)
 954{
 955    char *nss = NULL, *modSpec = NULL, **slotStrings = NULL;
 956    int slotCount, i, si;
 957    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
 958
 959    /* allocate target slot info strings */
 960    slotCount = 0;
 961
 962    SECMOD_GetReadLock(moduleLock);
 963    if (module->slotCount) {
 964	for (i=0; i < module->slotCount; i++) {
 965	    if (module->slots[i]->defaultFlags !=0) {
 966		slotCount++;
 967	    }
 968	}
 969    } else {
 970	slotCount = module->slotInfoCount;
 971    }
 972
 973    slotStrings = (char **)PORT_ZAlloc(slotCount*sizeof(char *));
 974    if (slotStrings == NULL) {
 975        SECMOD_ReleaseReadLock(moduleLock);
 976	goto loser;
 977    }
 978
 979
 980    /* build the slot info strings */
 981    if (module->slotCount) {
 982	for (i=0, si= 0; i < module->slotCount; i++) {
 983	    if (module->slots[i]->defaultFlags) {
 984		PORT_Assert(si < slotCount);
 985		if (si >= slotCount) break;
 986		slotStrings[si] = secmod_mkSlotString(module->slots[i]->slotID,
 987			module->slots[i]->defaultFlags,
 988			module->slots[i]->timeout,
 989			module->slots[i]->askpw,
 990			module->slots[i]->hasRootCerts,
 991			module->slots[i]->hasRootTrust);
 992		si++;
 993	    }
 994	}
 995     } else {
 996	for (i=0; i < slotCount; i++) {
 997		slotStrings[i] = secmod_mkSlotString(module->slotInfo[i].slotID,
 998			module->slotInfo[i].defaultFlags,
 999			module->slotInfo[i].timeout,
1000			module->slotInfo[i].askpw,
1001			module->slotInfo[i].hasRootCerts,
1002			module->slotInfo[i].hasRootTrust);
1003	}
1004    }
1005
1006    SECMOD_ReleaseReadLock(moduleLock);
1007    nss = secmod_mkNSS(slotStrings,slotCount,module->internal, module->isFIPS,
1008		       module->isModuleDB, module->moduleDBOnly, 
1009		       module->isCritical, module->trustOrder,
1010		       module->cipherOrder,module->ssl[0],module->ssl[1]);
1011    modSpec= secmod_mkNewModuleSpec(module->dllName,module->commonName,
1012						module->libraryParams,nss);
1013    PORT_Free(slotStrings);
1014    PR_smprintf_free(nss);
1015loser:
1016    return (modSpec);
1017}
1018    
1019
1020char **
1021SECMOD_GetModuleSpecList(SECMODModule *module)
1022{
1023    SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc;
1024    if (func) {
1025	return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
1026		module->libraryParams,NULL);
1027    }
1028    return NULL;
1029}
1030
1031SECStatus
1032SECMOD_AddPermDB(SECMODModule *module)
1033{
1034    SECMODModuleDBFunc func;
1035    char *moduleSpec;
1036    char **retString;
1037
1038    if (module->parent == NULL) return SECFailure;
1039
1040    func  = (SECMODModuleDBFunc) module->parent->moduleDBFunc;
1041    if (func) {
1042	moduleSpec = secmod_mkModuleSpec(module);
1043	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_ADD,
1044		module->parent->libraryParams,moduleSpec);
1045	PORT_Free(moduleSpec);
1046	if (retString != NULL) return SECSuccess;
1047    }
1048    return SECFailure;
1049}
1050
1051SECStatus
1052SECMOD_DeletePermDB(SECMODModule *module)
1053{
1054    SECMODModuleDBFunc func;
1055    char *moduleSpec;
1056    char **retString;
1057
1058    if (module->parent == NULL) return SECFailure;
1059
1060    func  = (SECMODModuleDBFunc) module->parent->moduleDBFunc;
1061    if (func) {
1062	moduleSpec = secmod_mkModuleSpec(module);
1063	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_DEL,
1064		module->parent->libraryParams,moduleSpec);
1065	PORT_Free(moduleSpec);
1066	if (retString != NULL) return SECSuccess;
1067    }
1068    return SECFailure;
1069}
1070
1071SECStatus
1072SECMOD_FreeModuleSpecList(SECMODModule *module, char **moduleSpecList)
1073{
1074    SECMODModuleDBFunc func = (SECMODModuleDBFunc) module->moduleDBFunc;
1075    char **retString;
1076    if (func) {
1077	retString = (*func)(SECMOD_MODULE_DB_FUNCTION_RELEASE,
1078		module->libraryParams,moduleSpecList);
1079	if (retString != NULL) return SECSuccess;
1080    }
1081    return SECFailure;
1082}
1083
1084/*
1085 * load a PKCS#11 module but do not add it to the default NSS trust domain
1086 */
1087SECMODModule *
1088SECMOD_LoadModule(char *modulespec,SECMODModule *parent, PRBool recurse)
1089{
1090    char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss= NULL;
1091    SECStatus status;
1092    SECMODModule *module = NULL;
1093    SECMODModule *oldModule = NULL;
1094    SECStatus rv;
1095
1096    /* initialize the underlying module structures */
1097    SECMOD_Init();
1098
1099    status = secmod_argParseModuleSpec(modulespec, &library, &moduleName, 
1100							&parameters, &nss);
1101    if (status != SECSuccess) {
1102	goto loser;
1103    }
1104
1105    module = SECMOD_CreateModule(library, moduleName, parameters, nss);
1106    if (library) PORT_Free(library);
1107    if (moduleName) PORT_Free(moduleName);
1108    if (parameters) PORT_Free(parameters);
1109    if (nss) PORT_Free(nss);
1110    if (!module) {
1111	goto loser;
1112    }
1113    if (parent) {
1114    	module->parent = SECMOD_ReferenceModule(parent);
1115	if (module->internal && secmod_IsInternalKeySlot(parent)) {
1116	    module->internal = parent->internal;
1117	}
1118    }
1119
1120    /* load it */
1121    rv = secmod_LoadPKCS11Module(module, &oldModule);
1122    if (rv != SECSuccess) {
1123	goto loser;
1124    }
1125
1126    /* if we just reload an old module, no need to add it to any lists.
1127     * we simple release all our references */
1128    if (oldModule) {
1129	/* This module already exists, don't link it anywhere. This
1130	 * will probably destroy this module */
1131	SECMOD_DestroyModule(module);
1132	return oldModule;
1133    }
1134
1135    if (recurse && module->isModuleDB) {
1136	char ** moduleSpecList;
1137	PORT_SetError(0);
1138
1139	moduleSpecList = SECMOD_GetModuleSpecList(module);
1140	if (moduleSpecList) {
1141	    char **index;
1142
1143	    index = moduleSpecList;
1144	    if (*index && SECMOD_GetSkipFirstFlag(module)) {
1145		index++;
1146	    }
1147
1148	    for (; *index; index++) {
1149		SECMODModule *child;
1150		if (0 == PORT_Strcmp(*index, modulespec)) {
1151		    /* avoid trivial infinite recursion */
1152		    PORT_SetError(SEC_ERROR_NO_MODULE);
1153		    rv = SECFailure;
1154		    break;
1155		}
1156		child = SECMOD_LoadModule(*index,module,PR_TRUE);
1157		if (!child) break;
1158		if (child->isCritical && !child->loaded) {
1159		    int err = PORT_GetError();
1160		    if (!err)  
1161			err = SEC_ERROR_NO_MODULE;
1162		    SECMOD_DestroyModule(child);
1163		    PORT_SetError(err);
1164		    rv = SECFailure;
1165		    break;
1166		}
1167		SECMOD_DestroyModule(child);
1168	    }
1169	    SECMOD_FreeModuleSpecList(module,moduleSpecList);
1170	} else {
1171	    if (!PORT_GetError())
1172		PORT_SetError(SEC_ERROR_NO_MODULE);
1173	    rv = SECFailure;
1174	}
1175    }
1176
1177    if (rv != SECSuccess) {
1178	goto loser;
1179    }
1180
1181
1182    /* inherit the reference */
1183    if (!module->moduleDBOnly) {
1184	SECMOD_AddModuleToList(module);
1185    } else {
1186	SECMOD_AddModuleToDBOnlyList(module);
1187    }
1188   
1189    /* handle any additional work here */
1190    return module;
1191
1192loser:
1193    if (module) {
1194	if (module->loaded) {
1195	    SECMOD_UnloadModule(module);
1196	}
1197	SECMOD_AddModuleToUnloadList(module);
1198    }
1199    return module;
1200}
1201
1202/*
1203 * load a PKCS#11 module and add it to the default NSS trust domain
1204 */
1205SECMODModule *
1206SECMOD_LoadUserModule(char *modulespec,SECMODModule *parent, PRBool recurse)
1207{
1208    SECStatus rv = SECSuccess;
1209    SECMODModule * newmod = SECMOD_LoadModule(modulespec, parent, recurse);
1210    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
1211
1212    if (newmod) {
1213	SECMOD_GetReadLock(moduleLock);
1214        rv = STAN_AddModuleToDefaultTrustDomain(newmod);
1215	SECMOD_ReleaseReadLock(moduleLock);
1216        if (SECSuccess != rv) {
1217            SECMOD_DestroyModule(newmod);
1218            return NULL;
1219        }
1220    }
1221    return newmod;
1222}
1223
1224/*
1225 * remove the PKCS#11 module from the default NSS trust domain, call
1226 * C_Finalize, and destroy the module structure
1227 */
1228SECStatus SECMOD_UnloadUserModule(SECMODModule *mod)
1229{
1230    SECStatus rv = SECSuccess;
1231    int atype = 0;
1232    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
1233    if (!mod) {
1234        return SECFailure;
1235    }
1236
1237    SECMOD_GetReadLock(moduleLock);
1238    rv = STAN_RemoveModuleFromDefaultTrustDomain(mod);
1239    SECMOD_ReleaseReadLock(moduleLock);
1240    if (SECSuccess != rv) {
1241        return SECFailure;
1242    }
1243    return SECMOD_DeleteModuleEx(NULL, mod, &atype, PR_FALSE);
1244}
1245