/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifdef DEBUG static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.6 $ $Date: 2004/04/25 15:03:06 $ $Name: $"; #endif /* DEBUG */ #ifndef NSSCKEPV_H #include "nssckepv.h" #endif /* NSSCKEPV_H */ #ifndef DEVM_H #include "devm.h" #endif /* DEVM_H */ #ifndef CKHELPER_H #include "ckhelper.h" #endif /* CKHELPER_H */ #ifdef PURE_STAN_CODE extern void FC_GetFunctionList(void); extern void NSC_GetFunctionList(void); extern void NSC_ModuleDBFunc(void); /* The list of boolean flags used to describe properties of a * module. */ #define NSSMODULE_FLAGS_NOT_THREADSAFE 0x0001 /* isThreadSafe */ #define NSSMODULE_FLAGS_INTERNAL 0x0002 /* isInternal */ #define NSSMODULE_FLAGS_FIPS 0x0004 /* isFIPS */ #define NSSMODULE_FLAGS_MODULE_DB 0x0008 /* isModuleDB */ #define NSSMODULE_FLAGS_MODULE_DB_ONLY 0x0010 /* moduleDBOnly */ #define NSSMODULE_FLAGS_CRITICAL 0x0020 /* isCritical */ struct NSSModuleStr { struct nssDeviceBaseStr base; NSSUTF8 *libraryName; PRLibrary *library; char *libraryParams; void *moduleDBFunc; void *epv; CK_INFO info; NSSSlot **slots; PRUint32 numSlots; PRBool isLoaded; struct { PRInt32 trust; PRInt32 cipher; PRInt32 certStorage; } order; }; #define NSSMODULE_IS_THREADSAFE(module) \ (!(module->base.flags & NSSMODULE_FLAGS_NOT_THREADSAFE)) #define NSSMODULE_IS_INTERNAL(module) \ (module->base.flags & NSSMODULE_FLAGS_INTERNAL) #define NSSMODULE_IS_FIPS(module) \ (module->base.flags & NSSMODULE_FLAGS_FIPS) #define NSSMODULE_IS_MODULE_DB(module) \ (module->base.flags & NSSMODULE_FLAGS_MODULE_DB) #define NSSMODULE_IS_MODULE_DB_ONLY(module) \ (module->base.flags & NSSMODULE_FLAGS_MODULE_DB_ONLY) #define NSSMODULE_IS_CRITICAL(module) \ (module->base.flags & NSSMODULE_FLAGS_CRITICAL) /* Threading callbacks for C_Initialize. Use NSPR threads. */ CK_RV PR_CALLBACK nss_ck_CreateMutex(CK_VOID_PTR_PTR pMutex) { CK_VOID_PTR mutex = (CK_VOID_PTR)PZ_NewLock(nssILockOther); if (mutex != NULL) { *pMutex = (CK_VOID_PTR)mutex; return CKR_OK; } return CKR_HOST_MEMORY; } CK_RV PR_CALLBACK nss_ck_DestroyMutex(CK_VOID_PTR mutex) { PZ_DestroyLock((PZLock *)mutex); return CKR_OK; } CK_RV PR_CALLBACK nss_ck_LockMutex(CK_VOID_PTR mutex) { PZ_Lock((PZLock *)mutex); return CKR_OK; } CK_RV PR_CALLBACK nss_ck_UnlockMutex(CK_VOID_PTR mutex) { return (PZ_Unlock((PZLock *)mutex) == PR_SUCCESS) ? CKR_OK : CKR_MUTEX_NOT_LOCKED; } /* Default callback args to C_Initialize */ /* XXX not const because we are modifying the pReserved argument in order * to use the libraryParams extension. */ static CK_C_INITIALIZE_ARGS s_ck_initialize_args = { nss_ck_CreateMutex, /* CreateMutex */ nss_ck_DestroyMutex, /* DestroyMutex */ nss_ck_LockMutex, /* LockMutex */ nss_ck_UnlockMutex, /* UnlockMutex */ CKF_LIBRARY_CANT_CREATE_OS_THREADS | CKF_OS_LOCKING_OK, /* flags */ NULL /* pReserved */ }; /* load all slots in a module. */ static PRStatus module_load_slots(NSSModule *mod) { CK_ULONG i, ulNumSlots; CK_SLOT_ID *slotIDs; nssArenaMark *mark = NULL; NSSSlot **slots; PRStatus nssrv; CK_RV ckrv; /* Get the number of slots */ ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, NULL, &ulNumSlots); if (ckrv != CKR_OK) { /* what is the error? */ return PR_FAILURE; } /* Alloc memory for the array of slot ID's */ slotIDs = nss_ZNEWARRAY(NULL, CK_SLOT_ID, ulNumSlots); if (!slotIDs) { goto loser; } /* Get the actual slot list */ ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, slotIDs, &ulNumSlots); if (ckrv != CKR_OK) { /* what is the error? */ goto loser; } /* Alloc memory for the array of slots, in the module's arena */ mark = nssArena_Mark(mod->base.arena); /* why mark? it'll be destroyed */ if (!mark) { return PR_FAILURE; } slots = nss_ZNEWARRAY(mod->base.arena, NSSSlot *, ulNumSlots); if (!slots) { goto loser; } /* Initialize each slot */ for (i=0; ibase.arena, mark); if (nssrv != PR_SUCCESS) { goto loser; } mod->slots = slots; mod->numSlots = ulNumSlots; return PR_SUCCESS; loser: if (mark) { nssArena_Release(mod->base.arena, mark); } nss_ZFreeIf(slotIDs); return PR_FAILURE; } NSS_IMPLEMENT PRStatus nssModule_Load ( NSSModule *mod ) { PRLibrary *library = NULL; CK_C_GetFunctionList epv; CK_RV ckrv; if (NSSMODULE_IS_INTERNAL(mod)) { /* internal, statically get the C_GetFunctionList function */ if (NSSMODULE_IS_FIPS(mod)) { epv = (CK_C_GetFunctionList) FC_GetFunctionList; } else { epv = (CK_C_GetFunctionList) NSC_GetFunctionList; } if (NSSMODULE_IS_MODULE_DB(mod)) { mod->moduleDBFunc = (void *) NSC_ModuleDBFunc; } if (NSSMODULE_IS_MODULE_DB_ONLY(mod)) { mod->isLoaded = PR_TRUE; /* XXX needed? */ return PR_SUCCESS; } } else { /* Use NSPR to load the library */ library = PR_LoadLibrary(mod->libraryName); if (!library) { /* what's the error to set? */ return PR_FAILURE; } mod->library = library; /* Skip if only getting the db loader function */ if (!NSSMODULE_IS_MODULE_DB_ONLY(mod)) { /* Load the cryptoki entry point function */ epv = (CK_C_GetFunctionList)PR_FindSymbol(library, "C_GetFunctionList"); } /* Load the module database loader function */ if (NSSMODULE_IS_MODULE_DB(mod)) { mod->moduleDBFunc = (void *)PR_FindSymbol(library, "NSS_ReturnModuleSpecData"); } } if (epv == NULL) { goto loser; } /* Load the cryptoki entry point vector (function list) */ ckrv = (*epv)((CK_FUNCTION_LIST_PTR *)&mod->epv); if (ckrv != CKR_OK) { goto loser; } /* Initialize the module */ if (mod->libraryParams) { s_ck_initialize_args.LibraryParameters = (void *)mod->libraryParams; } else { s_ck_initialize_args.LibraryParameters = NULL; } ckrv = CKAPI(mod->epv)->C_Initialize(&s_ck_initialize_args); if (ckrv != CKR_OK) { /* Apparently the token is not thread safe. Retry without * threading parameters. */ mod->base.flags |= NSSMODULE_FLAGS_NOT_THREADSAFE; ckrv = CKAPI(mod->epv)->C_Initialize((CK_VOID_PTR)NULL); if (ckrv != CKR_OK) { goto loser; } } /* TODO: check the version # using C_GetInfo */ ckrv = CKAPI(mod->epv)->C_GetInfo(&mod->info); if (ckrv != CKR_OK) { goto loser; } /* TODO: if the name is not set, get it from info.libraryDescription */ /* Now load the slots */ if (module_load_slots(mod) != PR_SUCCESS) { goto loser; } /* Module has successfully loaded */ mod->isLoaded = PR_TRUE; return PR_SUCCESS; loser: if (library) { PR_UnloadLibrary(library); } /* clear all values set above, they are invalid now */ mod->library = NULL; mod->epv = NULL; return PR_FAILURE; } NSS_IMPLEMENT PRStatus nssModule_Unload ( NSSModule *mod ) { PRStatus nssrv = PR_SUCCESS; if (mod->library) { (void)CKAPI(mod->epv)->C_Finalize(NULL); nssrv = PR_UnloadLibrary(mod->library); } /* Free the slots, yes? */ mod->library = NULL; mod->epv = NULL; mod->isLoaded = PR_FALSE; return nssrv; } /* Alloc memory for a module. Copy in the module name and library path * if provided. XXX use the opaque arg also, right? */ NSS_IMPLEMENT NSSModule * nssModule_Create ( NSSUTF8 *moduleOpt, NSSUTF8 *uriOpt, NSSUTF8 *opaqueOpt, void *reserved ) { NSSArena *arena; NSSModule *rvMod; arena = NSSArena_Create(); if(!arena) { return (NSSModule *)NULL; } rvMod = nss_ZNEW(arena, NSSModule); if (!rvMod) { goto loser; } if (moduleOpt) { /* XXX making the gross assumption this is just the module name */ /* if the name is a duplicate, should that be tested here? or * wait for Load? */ rvMod->base.name = nssUTF8_Duplicate(moduleOpt, arena); if (!rvMod->base.name) { goto loser; } } if (uriOpt) { /* Load the module from a URI. */ /* XXX at this time - only file URI (even worse, no file:// for now) */ rvMod->libraryName = nssUTF8_Duplicate(uriOpt, arena); if (!rvMod->libraryName) { goto loser; } } rvMod->base.arena = arena; rvMod->base.refCount = 1; rvMod->base.lock = PZ_NewLock(nssNSSILockOther); if (!rvMod->base.lock) { goto loser; } /* everything else is 0/NULL at this point. */ return rvMod; loser: nssArena_Destroy(arena); return (NSSModule *)NULL; } NSS_EXTERN PRStatus nssCryptokiArgs_ParseNextPair ( NSSUTF8 *start, NSSUTF8 **attrib, NSSUTF8 **value, NSSUTF8 **remainder, NSSArena *arenaOpt ); static PRStatus parse_slot_flags ( NSSSlot *slot, NSSUTF8 *slotFlags ) { PRStatus nssrv = PR_SUCCESS; #if 0 PRBool done = PR_FALSE; NSSUTF8 *mark, *last; last = mark = slotFlags; while (PR_TRUE) { while (*mark && *mark != ',') ++mark; if (!*mark) done = PR_TRUE; *mark = '\0'; if (nssUTF8_Equal(last, "RANDOM", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_HAS_RANDOM; } else if (nssUTF8_Equal(last, "RSA", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_RSA; } else if (nssUTF8_Equal(last, "DSA", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_DSA; } else if (nssUTF8_Equal(last, "DH", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_DH; } else if (nssUTF8_Equal(last, "RC2", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_RC2; } else if (nssUTF8_Equal(last, "RC4", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_RC4; } else if (nssUTF8_Equal(last, "RC5", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_RC5; } else if (nssUTF8_Equal(last, "DES", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_DES; } else if (nssUTF8_Equal(last, "AES", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_AES; } else if (nssUTF8_Equal(last, "SHA1", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_SHA1; } else if (nssUTF8_Equal(last, "MD2", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_MD2; } else if (nssUTF8_Equal(last, "MD5", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_MD5; } else if (nssUTF8_Equal(last, "SSL", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_SSL; } else if (nssUTF8_Equal(last, "TLS", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_TLS; } else if (nssUTF8_Equal(last, "PublicCerts", &nssrv)) { slot->base.flags |= NSSSLOT_FLAGS_FRIENDLY; } else { return PR_FAILURE; } if (done) break; last = ++mark; } #endif return nssrv; } static PRStatus parse_slot_parameters ( NSSSlot *slot, NSSUTF8 *slotParams, NSSArena *tmparena ) { PRStatus nssrv = PR_SUCCESS; NSSUTF8 *current, *remainder; NSSUTF8 *attrib, *value; current = slotParams; while (nssrv == PR_SUCCESS) { nssrv = nssCryptokiArgs_ParseNextPair(current, &attrib, &value, &remainder, tmparena); if (nssrv != PR_SUCCESS) break; if (value) { if (nssUTF8_Equal(attrib, "slotFlags", &nssrv)) { nssrv = parse_slot_flags(slot, value); } else if (nssUTF8_Equal(attrib, "askpw", &nssrv)) { } else if (nssUTF8_Equal(attrib, "timeout", &nssrv)) { } } if (*remainder == '\0') break; current = remainder; } return nssrv; } /* softoken seems to use "0x0000001", but no standard yet... perhaps this * should store the number as an ID, in case the input isn't 1,2,3,...? */ static PRIntn get_slot_number(NSSUTF8* snString) { /* XXX super big hack */ return atoi(&snString[strlen(snString)-1]); } static PRStatus parse_module_slot_parameters ( NSSModule *mod, NSSUTF8 *slotParams ) { PRStatus nssrv = PR_SUCCESS; NSSUTF8 *current, *remainder; NSSUTF8 *attrib, *value; NSSArena *tmparena; PRIntn slotNum; tmparena = nssArena_Create(); if (!tmparena) { return PR_FAILURE; } current = slotParams; while (nssrv == PR_SUCCESS) { nssrv = nssCryptokiArgs_ParseNextPair(current, &attrib, &value, &remainder, tmparena); if (nssrv != PR_SUCCESS) break; if (value) { slotNum = get_slot_number(attrib); if (slotNum < 0 || slotNum > mod->numSlots) { return PR_FAILURE; } nssrv = parse_slot_parameters(mod->slots[slotNum], value, tmparena); if (nssrv != PR_SUCCESS) break; } if (*remainder == '\0') break; current = remainder; } return nssrv; } static PRStatus parse_nss_flags ( NSSModule *mod, NSSUTF8 *nssFlags ) { PRStatus nssrv = PR_SUCCESS; PRBool done = PR_FALSE; NSSUTF8 *mark, *last; last = mark = nssFlags; while (PR_TRUE) { while (*mark && *mark != ',') ++mark; if (!*mark) done = PR_TRUE; *mark = '\0'; if (nssUTF8_Equal(last, "internal", &nssrv)) { mod->base.flags |= NSSMODULE_FLAGS_INTERNAL; } else if (nssUTF8_Equal(last, "moduleDB", &nssrv)) { mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB; } else if (nssUTF8_Equal(last, "moduleDBOnly", &nssrv)) { mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB_ONLY; } else if (nssUTF8_Equal(last, "critical", &nssrv)) { mod->base.flags |= NSSMODULE_FLAGS_CRITICAL; } else { return PR_FAILURE; } if (done) break; last = ++mark; } return nssrv; } static PRStatus parse_nss_parameters ( NSSModule *mod, NSSUTF8 *nssParams, NSSArena *tmparena, NSSUTF8 **slotParams ) { PRStatus nssrv = PR_SUCCESS; NSSUTF8 *current, *remainder; NSSUTF8 *attrib, *value; current = nssParams; while (nssrv == PR_SUCCESS) { nssrv = nssCryptokiArgs_ParseNextPair(current, &attrib, &value, &remainder, tmparena); if (nssrv != PR_SUCCESS) break; if (value) { if (nssUTF8_Equal(attrib, "flags", &nssrv) || nssUTF8_Equal(attrib, "Flags", &nssrv)) { nssrv = parse_nss_flags(mod, value); } else if (nssUTF8_Equal(attrib, "trustOrder", &nssrv)) { mod->order.trust = atoi(value); } else if (nssUTF8_Equal(attrib, "cipherOrder", &nssrv)) { mod->order.cipher = atoi(value); } else if (nssUTF8_Equal(attrib, "ciphers", &nssrv)) { } else if (nssUTF8_Equal(attrib, "slotParams", &nssrv)) { /* slotParams doesn't get an arena, it is handled separately */ *slotParams = nssUTF8_Duplicate(value, NULL); } } if (*remainder == '\0') break; current = remainder; } return nssrv; } static PRStatus parse_module_parameters ( NSSModule *mod, NSSUTF8 *moduleParams, NSSUTF8 **slotParams ) { PRStatus nssrv = PR_SUCCESS; NSSUTF8 *current, *remainder; NSSUTF8 *attrib, *value; NSSArena *arena = mod->base.arena; NSSArena *tmparena; current = moduleParams; tmparena = nssArena_Create(); if (!tmparena) { return PR_FAILURE; } while (nssrv == PR_SUCCESS) { nssrv = nssCryptokiArgs_ParseNextPair(current, &attrib, &value, &remainder, tmparena); if (nssrv != PR_SUCCESS) break; if (value) { if (nssUTF8_Equal(attrib, "name", &nssrv)) { mod->base.name = nssUTF8_Duplicate(value, arena); } else if (nssUTF8_Equal(attrib, "library", &nssrv)) { mod->libraryName = nssUTF8_Duplicate(value, arena); } else if (nssUTF8_Equal(attrib, "parameters", &nssrv)) { mod->libraryParams = nssUTF8_Duplicate(value, arena); } else if (nssUTF8_Equal(attrib, "NSS", &nssrv)) { parse_nss_parameters(mod, value, tmparena, slotParams); } } if (*remainder == '\0') break; current = remainder; } nssArena_Destroy(tmparena); return nssrv; } static NSSUTF8 ** get_module_specs ( NSSModule *mod ) { SECMODModuleDBFunc func = (SECMODModuleDBFunc)mod->moduleDBFunc; if (func) { return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND, mod->libraryParams, NULL); } return NULL; } /* XXX continue working on */ NSS_IMPLEMENT NSSModule * nssModule_CreateFromSpec ( NSSUTF8 *moduleSpec, NSSModule *parent, PRBool loadSubModules ) { PRStatus nssrv; NSSModule *thisModule; NSSArena *arena; NSSUTF8 *slotParams = NULL; arena = nssArena_Create(); if (!arena) { return NULL; } thisModule = nss_ZNEW(arena, NSSModule); if (!thisModule) { goto loser; } thisModule->base.lock = PZ_NewLock(nssILockOther); if (!thisModule->base.lock) { goto loser; } PR_AtomicIncrement(&thisModule->base.refCount); thisModule->base.arena = arena; thisModule->base.lock = PZ_NewLock(nssNSSILockOther); if (!thisModule->base.lock) { goto loser; } nssrv = parse_module_parameters(thisModule, moduleSpec, &slotParams); if (nssrv != PR_SUCCESS) { goto loser; } nssrv = nssModule_Load(thisModule); if (nssrv != PR_SUCCESS) { goto loser; } if (slotParams) { nssrv = parse_module_slot_parameters(thisModule, slotParams); nss_ZFreeIf(slotParams); if (nssrv != PR_SUCCESS) { goto loser; } } if (loadSubModules && NSSMODULE_IS_MODULE_DB(thisModule)) { NSSUTF8 **moduleSpecs; NSSUTF8 **index; /* get the array of sub modules one level below this module */ moduleSpecs = get_module_specs(thisModule); /* iterate over the array */ for (index = moduleSpecs; index && *index; index++) { NSSModule *child; /* load the child recursively */ child = nssModule_CreateFromSpec(*index, thisModule, PR_TRUE); if (!child) { /* when children fail, does the parent? */ nssrv = PR_FAILURE; break; } if (NSSMODULE_IS_CRITICAL(child) && !child->isLoaded) { nssrv = PR_FAILURE; nssModule_Destroy(child); break; } nssModule_Destroy(child); /*nss_ZFreeIf(*index);*/ } /*nss_ZFreeIf(moduleSpecs);*/ } /* The global list inherits the reference */ nssrv = nssGlobalModuleList_Add(thisModule); if (nssrv != PR_SUCCESS) { goto loser; } return thisModule; loser: if (thisModule->base.lock) { PZ_DestroyLock(thisModule->base.lock); } nssArena_Destroy(arena); return (NSSModule *)NULL; } NSS_IMPLEMENT PRStatus nssModule_Destroy ( NSSModule *mod ) { PRUint32 i, numSlots; if (PR_AtomicDecrement(&mod->base.refCount) == 0) { if (mod->numSlots == 0) { (void)nssModule_Unload(mod); return nssArena_Destroy(mod->base.arena); } else { numSlots = mod->numSlots; for (i=0; islots[i]); } } } return PR_SUCCESS; } NSS_IMPLEMENT PRStatus nssModule_DestroyFromSlot ( NSSModule *mod, NSSSlot *slot ) { PRUint32 i, numSlots = 0; PR_ASSERT(mod->base.refCount == 0); for (i=0; inumSlots; i++) { if (mod->slots[i] == slot) { mod->slots[i] = NULL; } else if (mod->slots[i]) { numSlots++; } } if (numSlots == 0) { (void)nssModule_Unload(mod); return nssArena_Destroy(mod->base.arena); } return PR_SUCCESS; } NSS_IMPLEMENT NSSModule * nssModule_AddRef ( NSSModule *mod ) { PR_AtomicIncrement(&mod->base.refCount); return mod; } NSS_IMPLEMENT NSSUTF8 * nssModule_GetName ( NSSModule *mod ) { return mod->base.name; } NSS_IMPLEMENT PRBool nssModule_IsThreadSafe ( NSSModule *module ) { return NSSMODULE_IS_THREADSAFE(module); } NSS_IMPLEMENT PRBool nssModule_IsInternal ( NSSModule *mod ) { return NSSMODULE_IS_INTERNAL(mod); } NSS_IMPLEMENT PRBool nssModule_IsModuleDBOnly ( NSSModule *mod ) { return NSSMODULE_IS_MODULE_DB_ONLY(mod); } NSS_IMPLEMENT void * nssModule_GetCryptokiEPV ( NSSModule *mod ) { return mod->epv; } NSS_IMPLEMENT NSSSlot ** nssModule_GetSlots ( NSSModule *mod ) { PRUint32 i; NSSSlot **rvSlots; rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, mod->numSlots + 1); if (rvSlots) { for (i=0; inumSlots; i++) { rvSlots[i] = nssSlot_AddRef(mod->slots[i]); } } return rvSlots; } NSS_IMPLEMENT NSSSlot * nssModule_FindSlotByName ( NSSModule *mod, NSSUTF8 *slotName ) { PRUint32 i; PRStatus nssrv; NSSSlot *slot; NSSUTF8 *name; for (i=0; inumSlots; i++) { slot = mod->slots[i]; name = nssSlot_GetName(slot); if (nssUTF8_Equal(name, slotName, &nssrv)) { return nssSlot_AddRef(slot); } if (nssrv != PR_SUCCESS) { break; } } return (NSSSlot *)NULL; } NSS_IMPLEMENT NSSToken * nssModule_FindTokenByName ( NSSModule *mod, NSSUTF8 *tokenName ) { PRUint32 i; PRStatus nssrv; NSSToken *tok; NSSUTF8 *name; for (i=0; inumSlots; i++) { tok = nssSlot_GetToken(mod->slots[i]); if (tok) { name = nssToken_GetName(tok); if (nssUTF8_Equal(name, tokenName, &nssrv)) { return tok; } if (nssrv != PR_SUCCESS) { break; } } } return (NSSToken *)NULL; } NSS_IMPLEMENT PRInt32 nssModule_GetCertOrder ( NSSModule *module ) { return 1; /* XXX */ } #endif /* PURE_STAN_BUILD */