/* * 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 Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ #ifdef DEBUG static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.2 $ $Date: 2001-11-28 16:23:39 $ $Name: not supported by cvs2svn $"; #endif /* DEBUG */ #include "nspr.h" #ifndef DEV_H #include "dev.h" #endif /* DEV_H */ #ifndef DEVM_H #include "devm.h" #endif /* DEVM_H */ #ifndef NSSCKEPV_H #include "nssckepv.h" #endif /* NSSCKEPV_H */ #ifndef CKHELPER_H #include "ckhelper.h" #endif /* CKHELPER_H */ #ifndef BASE_H #include "base.h" #endif /* BASE_H */ /* 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 */ 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 */ }; /* 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->name = nssUTF8_Duplicate(moduleOpt, arena); if (!rvMod->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->libraryPath = nssUTF8_Duplicate(uriOpt, arena); if (!rvMod->libraryPath) { goto loser; } } rvMod->arena = arena; rvMod->refCount = 1; /* everything else is 0/NULL at this point. */ return rvMod; loser: nssArena_Destroy(arena); return (NSSModule *)NULL; } /* 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)->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)->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->arena); if (!mark) { return PR_FAILURE; } slots = nss_ZNEWARRAY(mod->arena, NSSSlot *, ulNumSlots); if (!slots) { goto loser; } /* Initialize each slot */ for (i=0; iarena, slotIDs[i], mod); } nss_ZFreeIf(slotIDs); nssrv = nssArena_Unmark(mod->arena, mark); if (nssrv != PR_SUCCESS) { goto loser; } mod->slots = slots; mod->numSlots = ulNumSlots; return PR_SUCCESS; loser: if (mark) { nssArena_Release(mod->arena, mark); } nss_ZFreeIf(slotIDs); return PR_FAILURE; } /* This is going to take much more thought. The module has a list of slots, * each of which points to a token. Presumably, all are ref counted. Some * kind of consistency check is needed here, or perhaps at a higher level. */ NSS_IMPLEMENT PRStatus nssModule_Destroy ( NSSModule *mod ) { PRUint32 i; if (--mod->refCount == 0) { /* Ignore any failure here. */ for (i=0; inumSlots; i++) { nssSlot_Destroy(mod->slots[i]); } (void)nssModule_Unload(mod); return NSSArena_Destroy(mod->arena); } return PR_SUCCESS; } NSS_IMPLEMENT NSSModule * nssModule_AddRef ( NSSModule *mod ) { ++mod->refCount; return mod; } NSS_IMPLEMENT PRStatus nssModule_Load ( NSSModule *mod ) { PRLibrary *library = NULL; CK_C_GetFunctionList ep; CK_RV ckrv; /* Use NSPR to load the library */ library = PR_LoadLibrary((char *)mod->libraryPath); if (!library) { /* what's the error to set? */ return PR_FAILURE; } mod->library = library; /* TODO: semantics here in SECMOD_LoadModule about module db */ /* Load the cryptoki entry point function */ ep = (CK_C_GetFunctionList)PR_FindSymbol(library, "C_GetFunctionList"); if (ep == NULL) { goto loser; } /* Load the cryptoki entry point vector (function list) */ ckrv = (*ep)((CK_FUNCTION_LIST_PTR *)&mod->epv); if (ckrv != CKR_OK) { goto loser; } /* Initialize the module */ /* XXX This is where some additional parameters may need to come in, * SECMOD_LoadModule has LibraryParameters */ ckrv = CKAPI(mod)->C_Initialize(&s_ck_initialize_args); if (ckrv != CKR_OK) { /* Apparently the token is not thread safe. Retry without * threading parameters. */ mod->flags |= NSSMODULE_FLAGS_NOT_THREADSAFE; ckrv = CKAPI(mod)->C_Initialize((CK_VOID_PTR)NULL); if (ckrv != CKR_OK) { goto loser; } } /* TODO: check the version # using C_GetInfo */ /* 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 */ 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)->C_Finalize(NULL); nssrv = PR_UnloadLibrary(mod->library); } /* Free the slots, yes? */ mod->library = NULL; mod->epv = NULL; return nssrv; } NSS_IMPLEMENT NSSSlot * nssModule_FindSlotByName ( NSSModule *mod, NSSUTF8 *slotName ) { PRUint32 i; PRStatus nssrv; for (i=0; inumSlots; i++) { if (nssUTF8_Equal(mod->slots[i]->name, slotName, &nssrv)) { return nssSlot_AddRef(mod->slots[i]); } if (nssrv != PR_SUCCESS) { break; } } return (NSSSlot *)NULL; } NSS_EXTERN NSSToken * nssModule_FindTokenByName ( NSSModule *mod, NSSUTF8 *tokenName ) { PRUint32 i; PRStatus nssrv; NSSToken *tok; for (i=0; inumSlots; i++) { tok = mod->slots[i]->token; if (nssUTF8_Equal(tok->name, tokenName, &nssrv)) { return nssToken_AddRef(tok); } if (nssrv != PR_SUCCESS) { break; } } return (NSSToken *)NULL; } NSS_IMPLEMENT PRStatus * nssModule_TraverseCertificates ( NSSModule *mod, PRStatus (*callback)(NSSCertificate *c, void *arg), void *arg ) { return NULL; } #ifdef DEBUG void nssModule_Debug(NSSModule *m) { PRUint32 i; printf("\n"); printf("Module Name: %s\n", m->name); printf("Module Path: %s\n", m->libraryPath); printf("Number of Slots in Module: %d\n\n", m->numSlots); for (i=0; inumSlots; i++) { printf("\tSlot #%d\n", i); if (m->slots[i]->name) { printf("\tSlot Name: %s\n", m->slots[i]->name); } else { printf("\tSlot Name: \n"); } if (m->slots[i]->token) { printf("\tToken Name: %s\n", m->slots[i]->token->name); } else { printf("\tToken: \n"); } } } #endif