Back to index

lightning-sunbird  0.9+nobinonly
pk11load.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 /*
00037  * The following handles the loading, unloading and management of
00038  * various PCKS #11 modules
00039  */
00040 #include "seccomon.h"
00041 #include "pkcs11.h"
00042 #include "secmod.h"
00043 #include "prlink.h"
00044 #include "pk11func.h"
00045 #include "secmodi.h"
00046 #include "secmodti.h"
00047 #include "nssilock.h"
00048 #include "secerr.h"
00049 
00050 extern void FC_GetFunctionList(void);
00051 extern void NSC_GetFunctionList(void);
00052 extern void NSC_ModuleDBFunc(void);
00053 
00054 #ifdef DEBUG
00055 #define DEBUG_MODULE 1
00056 #endif
00057 
00058 #ifdef DEBUG_MODULE
00059 static char *modToDBG = NULL;
00060 
00061 #include "debug_module.c"
00062 #endif
00063 
00064 /* build the PKCS #11 2.01 lock files */
00065 CK_RV PR_CALLBACK secmodCreateMutext(CK_VOID_PTR_PTR pmutex) {
00066     *pmutex = (CK_VOID_PTR) PZ_NewLock(nssILockOther);
00067     if ( *pmutex ) return CKR_OK;
00068     return CKR_HOST_MEMORY;
00069 }
00070 
00071 CK_RV PR_CALLBACK secmodDestroyMutext(CK_VOID_PTR mutext) {
00072     PZ_DestroyLock((PZLock *)mutext);
00073     return CKR_OK;
00074 }
00075 
00076 CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) {
00077     PZ_Lock((PZLock *)mutext);
00078     return CKR_OK;
00079 }
00080 
00081 CK_RV PR_CALLBACK secmodUnlockMutext(CK_VOID_PTR mutext) {
00082     PZ_Unlock((PZLock *)mutext);
00083     return CKR_OK;
00084 }
00085 
00086 static SECMODModuleID  nextModuleID = 1;
00087 static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
00088     secmodCreateMutext, secmodDestroyMutext, secmodLockMutext, 
00089     secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS|
00090        CKF_OS_LOCKING_OK
00091     ,NULL
00092 };
00093 
00094 static PRBool loadSingleThreadedModules = PR_TRUE;
00095 static PRBool enforceAlreadyInitializedError = PR_TRUE;
00096 static PRBool finalizeModules = PR_TRUE;
00097 
00098 /* set global options for NSS PKCS#11 module loader */
00099 SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
00100                                 PRBool allowAlreadyInitializedModules,
00101                                 PRBool dontFinalizeModules)
00102 {
00103     if (noSingleThreadedModules) {
00104         loadSingleThreadedModules = PR_FALSE;
00105     } else {
00106         loadSingleThreadedModules = PR_TRUE;
00107     }
00108     if (allowAlreadyInitializedModules) {
00109         enforceAlreadyInitializedError = PR_FALSE;
00110     } else {
00111         enforceAlreadyInitializedError = PR_TRUE;
00112     }
00113     if (dontFinalizeModules) {
00114         finalizeModules = PR_FALSE;
00115     } else {
00116         finalizeModules = PR_TRUE;
00117     }
00118     return SECSuccess;
00119 }
00120 
00121 PRBool pk11_getFinalizeModulesOption(void)
00122 {
00123     return finalizeModules;
00124 }
00125 
00126 /*
00127  * collect the steps we need to initialize a module in a single function
00128  */
00129 SECStatus
00130 secmod_ModuleInit(SECMODModule *mod, PRBool* alreadyLoaded)
00131 {
00132     CK_C_INITIALIZE_ARGS moduleArgs;
00133     CK_VOID_PTR pInitArgs;
00134     CK_RV crv;
00135 
00136     if (!mod || !alreadyLoaded) {
00137         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00138         return SECFailure;
00139     }
00140 
00141     if (mod->isThreadSafe == PR_FALSE) {
00142        pInitArgs = NULL;
00143     } else if (mod->libraryParams == NULL) {
00144        pInitArgs = (void *) &secmodLockFunctions;
00145     } else {
00146        moduleArgs = secmodLockFunctions;
00147        moduleArgs.LibraryParameters = (void *) mod->libraryParams;
00148        pInitArgs = &moduleArgs;
00149     }
00150     crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
00151     if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
00152         (!enforceAlreadyInitializedError)) {
00153         *alreadyLoaded = PR_TRUE;
00154         return SECSuccess;
00155     }
00156     if (crv != CKR_OK) {
00157        if (pInitArgs == NULL ||
00158               crv == CKR_NETSCAPE_CERTDB_FAILED ||
00159               crv == CKR_NETSCAPE_KEYDB_FAILED) {
00160            PORT_SetError(PK11_MapError(crv));
00161            return SECFailure;
00162        }
00163        if (!loadSingleThreadedModules) {
00164            PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
00165            return SECFailure;
00166        }
00167        mod->isThreadSafe = PR_FALSE;
00168        crv = PK11_GETTAB(mod)->C_Initialize(NULL);
00169        if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
00170            (!enforceAlreadyInitializedError)) {
00171            *alreadyLoaded = PR_TRUE;
00172            return SECSuccess;
00173        }
00174        if (crv != CKR_OK)  {
00175            PORT_SetError(PK11_MapError(crv));
00176            return SECFailure;
00177        }
00178     }
00179     return SECSuccess;
00180 }
00181 
00182 /*
00183  * set the hasRootCerts flags in the module so it can be stored back
00184  * into the database.
00185  */
00186 void
00187 SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) {
00188     PK11PreSlotInfo *psi = NULL;
00189     int i;
00190 
00191     if (slot->hasRootCerts) {
00192        for (i=0; i < mod->slotInfoCount; i++) {
00193            if (slot->slotID == mod->slotInfo[i].slotID) {
00194               psi = &mod->slotInfo[i];
00195               break;
00196            }
00197        }
00198        if (psi == NULL) {
00199           /* allocate more slots */
00200           PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
00201               PORT_ArenaAlloc(mod->arena,
00202                      (mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo));
00203           /* copy the old ones */
00204           if (mod->slotInfoCount > 0) {
00205               PORT_Memcpy(psi_list,mod->slotInfo,
00206                             (mod->slotInfoCount)*sizeof(PK11PreSlotInfo));
00207           }
00208           /* assign psi to the last new slot */
00209           psi = &psi_list[mod->slotInfoCount];
00210           psi->slotID = slot->slotID;
00211           psi->askpw = 0;
00212           psi->timeout = 0;
00213           psi ->defaultFlags = 0;
00214 
00215           /* increment module count & store new list */
00216           mod->slotInfo = psi_list;
00217           mod->slotInfoCount++;
00218           
00219        }
00220        psi->hasRootCerts = 1;
00221     }
00222 }
00223 
00224 /*
00225  * load a new module into our address space and initialize it.
00226  */
00227 SECStatus
00228 SECMOD_LoadPKCS11Module(SECMODModule *mod) {
00229     PRLibrary *library = NULL;
00230     CK_C_GetFunctionList entry = NULL;
00231     char * full_name;
00232     CK_INFO info;
00233     CK_ULONG slotCount = 0;
00234     SECStatus rv;
00235     PRBool alreadyLoaded = PR_FALSE;
00236 
00237     if (mod->loaded) return SECSuccess;
00238 
00239     /* intenal modules get loaded from their internal list */
00240     if (mod->internal) {
00241        /* internal, statically get the C_GetFunctionList function */
00242        if (mod->isFIPS) {
00243            entry = (CK_C_GetFunctionList) FC_GetFunctionList;
00244        } else {
00245            entry = (CK_C_GetFunctionList) NSC_GetFunctionList;
00246        }
00247        if (mod->isModuleDB) {
00248            mod->moduleDBFunc = (void *) NSC_ModuleDBFunc;
00249        }
00250        if (mod->moduleDBOnly) {
00251            mod->loaded = PR_TRUE;
00252            return SECSuccess;
00253        }
00254     } else {
00255        /* Not internal, load the DLL and look up C_GetFunctionList */
00256        if (mod->dllName == NULL) {
00257            return SECFailure;
00258        }
00259 
00260 #ifdef notdef
00261        /* look up the library name */
00262        full_name = PR_GetLibraryName(PR_GetLibraryPath(),mod->dllName);
00263        if (full_name == NULL) {
00264            return SECFailure;
00265        }
00266 #else
00267        full_name = PORT_Strdup(mod->dllName);
00268 #endif
00269 
00270        /* load the library. If this succeeds, then we have to remember to
00271         * unload the library if anything goes wrong from here on out...
00272         */
00273        library = PR_LoadLibrary(full_name);
00274        mod->library = (void *)library;
00275        PORT_Free(full_name);
00276        if (library == NULL) {
00277            return SECFailure;
00278        }
00279 
00280        /*
00281         * now we need to get the entry point to find the function pointers
00282         */
00283        if (!mod->moduleDBOnly) {
00284            entry = (CK_C_GetFunctionList)
00285                      PR_FindSymbol(library, "C_GetFunctionList");
00286        }
00287        if (mod->isModuleDB) {
00288            mod->moduleDBFunc = (void *)
00289                      PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
00290        }
00291        if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE;
00292        if (entry == NULL) {
00293            if (mod->isModuleDB) {
00294               mod->loaded = PR_TRUE;
00295               mod->moduleDBOnly = PR_TRUE;
00296               return SECSuccess;
00297            }
00298            PR_UnloadLibrary(library);
00299            return SECFailure;
00300        }
00301     }
00302 
00303     /*
00304      * We need to get the function list
00305      */
00306     if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK) 
00307                                                         goto fail;
00308 
00309 #ifdef DEBUG_MODULE
00310     if (PR_TRUE) {
00311        modToDBG = PR_GetEnv("NSS_DEBUG_PKCS11_MODULE");
00312        if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
00313            mod->functionList = (void *)nss_InsertDeviceLog(
00314                                   (CK_FUNCTION_LIST_PTR)mod->functionList);
00315        }
00316     }
00317 #endif
00318 
00319     mod->isThreadSafe = PR_TRUE;
00320 
00321     /* Now we initialize the module */
00322     rv = secmod_ModuleInit(mod, &alreadyLoaded);
00323     if (rv != SECSuccess) {
00324        goto fail;
00325     }
00326 
00327     /* check the version number */
00328     if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2;
00329     if (info.cryptokiVersion.major != 2) goto fail2;
00330     /* all 2.0 are a priori *not* thread safe */
00331     if (info.cryptokiVersion.minor < 1) {
00332         if (!loadSingleThreadedModules) {
00333             PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
00334             goto fail2;
00335         } else {
00336             mod->isThreadSafe = PR_FALSE;
00337         }
00338     }
00339     mod->cryptokiVersion = info.cryptokiVersion;
00340 
00341     /* If we don't have a common name, get it from the PKCS 11 module */
00342     if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
00343        mod->commonName = PK11_MakeString(mod->arena,NULL,
00344           (char *)info.libraryDescription, sizeof(info.libraryDescription));
00345        if (mod->commonName == NULL) goto fail2;
00346     }
00347     
00348 
00349     /* initialize the Slots */
00350     if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
00351        CK_SLOT_ID *slotIDs;
00352        int i;
00353        CK_RV crv;
00354 
00355        mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
00356                                    sizeof(PK11SlotInfo *) * slotCount);
00357        if (mod->slots == NULL) goto fail2;
00358 
00359        slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount);
00360        if (slotIDs == NULL) {
00361            goto fail2;
00362        }  
00363        crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
00364        if (crv != CKR_OK) {
00365            PORT_Free(slotIDs);
00366            goto fail2;
00367        }
00368 
00369        /* Initialize each slot */
00370        for (i=0; i < (int)slotCount; i++) {
00371            mod->slots[i] = PK11_NewSlotInfo(mod);
00372            PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
00373            /* look down the slot info table */
00374            PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
00375            SECMOD_SetRootCerts(mod->slots[i],mod);
00376        }
00377        mod->slotCount = slotCount;
00378        mod->slotInfoCount = 0;
00379        PORT_Free(slotIDs);
00380     }
00381     
00382     mod->loaded = PR_TRUE;
00383     mod->moduleID = nextModuleID++;
00384     return SECSuccess;
00385 fail2:
00386     if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
00387         PK11_GETTAB(mod)->C_Finalize(NULL);
00388     }
00389 fail:
00390     mod->functionList = NULL;
00391     if (library) PR_UnloadLibrary(library);
00392     return SECFailure;
00393 }
00394 
00395 SECStatus
00396 SECMOD_UnloadModule(SECMODModule *mod) {
00397     PRLibrary *library;
00398 
00399     if (!mod->loaded) {
00400        return SECFailure;
00401     }
00402     if (finalizeModules) {
00403         if (!mod->moduleDBOnly) PK11_GETTAB(mod)->C_Finalize(NULL);
00404     }
00405     mod->moduleID = 0;
00406     mod->loaded = PR_FALSE;
00407     
00408     /* do we want the semantics to allow unloading the internal library?
00409      * if not, we should change this to SECFailure and move it above the
00410      * mod->loaded = PR_FALSE; */
00411     if (mod->internal) {
00412        return SECSuccess;
00413     }
00414 
00415     library = (PRLibrary *)mod->library;
00416     /* paranoia */
00417     if (library == NULL) {
00418        return SECFailure;
00419     }
00420 
00421     PR_UnloadLibrary(library);
00422     return SECSuccess;
00423 }
00424 
00425 void
00426 nss_DumpModuleLog(void)
00427 {
00428 #ifdef DEBUG_MODULE
00429     if (modToDBG) {
00430        print_final_statistics();
00431     }
00432 #endif
00433 }