Milán Major

netscape-revival

1 branch
Code

security/lib/pkcs11/pk11load.c

/*
 * The following handles the loading, unloading and management of
 * various PCKS #11 modules
 */
#include "seccomon.h"
#include "pkcs11.h"
#include "secmod.h"
#include "prlink.h"
#include "pk11func.h"
#include "secmodi.h"

extern void FC_GetFunctionList(void);

/*
 * load a new module into our address space and initialize it.
 */
SECStatus
SECMOD_LoadModule(SECMODModule *mod) {
    PRLibrary *library = NULL;
    CK_C_GetFunctionList entry;
    char * full_name;
    CK_INFO info;
    CK_ULONG slotCount = 0;


    if (mod->loaded) return SECSuccess;

    /* intenal modules get loaded from their internal list */
    if (mod->internal) {
	/* internal, statically get the C_GetFunctionList function */
	if (mod->isFIPS) {
	    entry = (CK_C_GetFunctionList) FC_GetFunctionList;
	} else {
	    entry = C_GetFunctionList;
	}
    } else {
	/* Not internal, load the DLL and look up C_GetFunctionList */
	if (mod->dllName == NULL) {
	    return SECFailure;
	}

#ifdef POSSIBLY_EVIL
	/* look up the library name */
#ifndef NSPR20
	full_name = PR_GetLibName(PR_GetLibraryPath(),mod->dllName);
#else
	full_name = PR_GetLibraryName(PR_GetLibraryPath(),mod->dllName);
#endif /* NSPR20 */
	if (full_name == NULL) {
	    return SECFailure;
	}
#else
	full_name = PORT_Strdup(mod->dllName);
#endif

	/* load the library. If this succeeds, then we have to remember to
	 * unload the library if anything goes wrong from here on out...
	 */
	library = PR_LoadLibrary(full_name);
	mod->library = (void *)library;
	PORT_Free(full_name);
	if (library == NULL) {
	    return SECFailure;
	}

	/*
	 * now we need to get the entry point to find the function pointers
	 */
	entry = (CK_C_GetFunctionList)
#ifndef NSPR20
			PR_FindSymbol("C_GetFunctionList",library);
#else
			PR_FindSymbol(library, "C_GetFunctionList");
#endif /* NSPR20 */
	if (entry == NULL) {
	    PR_UnloadLibrary(library);
	    return SECFailure;
	}
    }

    /*
     * We need to get the function list
     */
    if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK) 
								goto fail;

    /* Now we initialize the module */
    if (PK11_GETTAB(mod)->C_Initialize(NULL) != CKR_OK) goto fail;

    /* check the version number */
    if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2;
    if (info.cryptokiVersion.major != 2) goto fail2;


    /* If we don't have a common name, get it from the PKCS 11 module */
    if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
	mod->commonName = PK11_MakeString(mod->arena,NULL,
	   (char *)info.libraryDescription, sizeof(info.libraryDescription));
	if (mod->commonName == NULL) goto fail2;
    }
    

    /* initialize the Slots */
    if (PK11_GETTAB(mod)->C_GetSlotList(FALSE, NULL, &slotCount) == CKR_OK) {
	CK_SLOT_ID *slotIDs;
	int i;
	CK_RV rv;

	mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
					sizeof(PK11SlotInfo *) * slotCount);
	if (mod->slots == NULL) goto fail2;

	slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount);
	if (slotIDs == NULL) {
	    goto fail2;
	}  
	rv = PK11_GETTAB(mod)->C_GetSlotList(FALSE, slotIDs, &slotCount);
	if (rv != CKR_OK) {
	    PORT_Free(slotIDs);
	    goto fail2;
	}

	/* Initialize each slot */
	for (i=0; i < slotCount; i++) {
	    mod->slots[i] = PK11_NewSlotInfo();
	    PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
	    /* look down the slot info table */
	    PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
	}
	mod->slotCount = slotCount;
	PORT_Free(slotIDs);
    }
	


    
    mod->loaded = PR_TRUE;
    return SECSuccess;
fail2:
    PK11_GETTAB(mod)->C_Finalize(NULL);
fail:
    mod->functionList = NULL;
    if (library) PR_UnloadLibrary(library);
    return SECFailure;
}

SECStatus
SECMOD_UnloadModule(SECMODModule *mod) {
    PRLibrary *library;

    if (!mod->loaded) {
	return SECFailure;
    }

    PK11_GETTAB(mod)->C_Finalize(NULL);
    mod->loaded = PR_FALSE;
    
    /* do we want the semantics to allow unloading the internal library?
     * if not, we should change this to SECFailure and move it above the
     * mod->loaded = PR_FALSE; */
    if (mod->internal) {
	return SECSuccess;
    }

    library = (PRLibrary *)mod->library;
    /* paranoia */
    if (library == NULL) {
	return SECFailure;
    }

    PR_UnloadLibrary(library);
    return SECSuccess;
}