security/nss/lib/pk11wrap/pk11pars.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial