Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / lib / pk11wrap / pk11load.c
blob49d826dbe2ea98dfc275e0982b683dc0254c921d
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 * The following handles the loading, unloading and management of
38 * various PCKS #11 modules
40 #include "seccomon.h"
41 #include "pkcs11.h"
42 #include "secmod.h"
43 #include "prlink.h"
44 #include "pk11func.h"
45 #include "secmodi.h"
46 #include "secmodti.h"
47 #include "nssilock.h"
48 #include "secerr.h"
49 #include "prenv.h"
51 #ifdef DEBUG
52 #define DEBUG_MODULE 1
53 #endif
55 #ifdef DEBUG_MODULE
56 static char *modToDBG = NULL;
58 #include "debug_module.c"
59 #endif
61 /* build the PKCS #11 2.01 lock files */
62 CK_RV PR_CALLBACK secmodCreateMutext(CK_VOID_PTR_PTR pmutex) {
63 *pmutex = (CK_VOID_PTR) PZ_NewLock(nssILockOther);
64 if ( *pmutex ) return CKR_OK;
65 return CKR_HOST_MEMORY;
68 CK_RV PR_CALLBACK secmodDestroyMutext(CK_VOID_PTR mutext) {
69 PZ_DestroyLock((PZLock *)mutext);
70 return CKR_OK;
73 CK_RV PR_CALLBACK secmodLockMutext(CK_VOID_PTR mutext) {
74 PZ_Lock((PZLock *)mutext);
75 return CKR_OK;
78 CK_RV PR_CALLBACK secmodUnlockMutext(CK_VOID_PTR mutext) {
79 PZ_Unlock((PZLock *)mutext);
80 return CKR_OK;
83 static SECMODModuleID nextModuleID = 1;
84 static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
85 secmodCreateMutext, secmodDestroyMutext, secmodLockMutext,
86 secmodUnlockMutext, CKF_LIBRARY_CANT_CREATE_OS_THREADS|
87 CKF_OS_LOCKING_OK
88 ,NULL
91 static PRBool loadSingleThreadedModules = PR_TRUE;
92 static PRBool enforceAlreadyInitializedError = PR_TRUE;
93 static PRBool finalizeModules = PR_TRUE;
95 /* set global options for NSS PKCS#11 module loader */
96 SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
97 PRBool allowAlreadyInitializedModules,
98 PRBool dontFinalizeModules)
100 if (noSingleThreadedModules) {
101 loadSingleThreadedModules = PR_FALSE;
102 } else {
103 loadSingleThreadedModules = PR_TRUE;
105 if (allowAlreadyInitializedModules) {
106 enforceAlreadyInitializedError = PR_FALSE;
107 } else {
108 enforceAlreadyInitializedError = PR_TRUE;
110 if (dontFinalizeModules) {
111 finalizeModules = PR_FALSE;
112 } else {
113 finalizeModules = PR_TRUE;
115 return SECSuccess;
118 PRBool pk11_getFinalizeModulesOption(void)
120 return finalizeModules;
124 * collect the steps we need to initialize a module in a single function
126 SECStatus
127 secmod_ModuleInit(SECMODModule *mod, PRBool* alreadyLoaded)
129 CK_C_INITIALIZE_ARGS moduleArgs;
130 CK_VOID_PTR pInitArgs;
131 CK_RV crv;
133 if (!mod || !alreadyLoaded) {
134 PORT_SetError(SEC_ERROR_INVALID_ARGS);
135 return SECFailure;
138 if (mod->isThreadSafe == PR_FALSE) {
139 pInitArgs = NULL;
140 } else if (mod->libraryParams == NULL) {
141 pInitArgs = (void *) &secmodLockFunctions;
142 } else {
143 moduleArgs = secmodLockFunctions;
144 moduleArgs.LibraryParameters = (void *) mod->libraryParams;
145 pInitArgs = &moduleArgs;
147 crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
148 if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
149 (!enforceAlreadyInitializedError)) {
150 *alreadyLoaded = PR_TRUE;
151 return SECSuccess;
153 if (crv != CKR_OK) {
154 if (pInitArgs == NULL ||
155 crv == CKR_NETSCAPE_CERTDB_FAILED ||
156 crv == CKR_NETSCAPE_KEYDB_FAILED) {
157 PORT_SetError(PK11_MapError(crv));
158 return SECFailure;
160 if (!loadSingleThreadedModules) {
161 PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
162 return SECFailure;
164 mod->isThreadSafe = PR_FALSE;
165 crv = PK11_GETTAB(mod)->C_Initialize(NULL);
166 if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
167 (!enforceAlreadyInitializedError)) {
168 *alreadyLoaded = PR_TRUE;
169 return SECSuccess;
171 if (crv != CKR_OK) {
172 PORT_SetError(PK11_MapError(crv));
173 return SECFailure;
176 return SECSuccess;
180 * set the hasRootCerts flags in the module so it can be stored back
181 * into the database.
183 void
184 SECMOD_SetRootCerts(PK11SlotInfo *slot, SECMODModule *mod) {
185 PK11PreSlotInfo *psi = NULL;
186 int i;
188 if (slot->hasRootCerts) {
189 for (i=0; i < mod->slotInfoCount; i++) {
190 if (slot->slotID == mod->slotInfo[i].slotID) {
191 psi = &mod->slotInfo[i];
192 break;
195 if (psi == NULL) {
196 /* allocate more slots */
197 PK11PreSlotInfo *psi_list = (PK11PreSlotInfo *)
198 PORT_ArenaAlloc(mod->arena,
199 (mod->slotInfoCount+1)* sizeof(PK11PreSlotInfo));
200 /* copy the old ones */
201 if (mod->slotInfoCount > 0) {
202 PORT_Memcpy(psi_list,mod->slotInfo,
203 (mod->slotInfoCount)*sizeof(PK11PreSlotInfo));
205 /* assign psi to the last new slot */
206 psi = &psi_list[mod->slotInfoCount];
207 psi->slotID = slot->slotID;
208 psi->askpw = 0;
209 psi->timeout = 0;
210 psi ->defaultFlags = 0;
212 /* increment module count & store new list */
213 mod->slotInfo = psi_list;
214 mod->slotInfoCount++;
217 psi->hasRootCerts = 1;
221 static const char* NameOfThisSharedLib =
222 SHLIB_PREFIX"nss"SHLIB_VERSION"."SHLIB_SUFFIX;
223 static const char* softoken_default_name =
224 SHLIB_PREFIX"softokn"SOFTOKEN_SHLIB_VERSION"."SHLIB_SUFFIX;
225 static const PRCallOnceType pristineCallOnce;
226 static PRCallOnceType loadSoftokenOnce;
227 static PRLibrary* softokenLib;
228 static PRInt32 softokenLoadCount;
230 #include "prio.h"
231 #include "prprf.h"
232 #include <stdio.h>
233 #include "prsystem.h"
235 #include "../freebl/genload.c"
237 /* This function must be run only once. */
238 /* determine if hybrid platform, then actually load the DSO. */
239 static PRStatus
240 softoken_LoadDSO( void )
242 PRLibrary * handle;
243 const char * name = softoken_default_name;
245 if (!name) {
246 PR_SetError(PR_LOAD_LIBRARY_ERROR, 0);
247 return PR_FAILURE;
250 handle = loader_LoadLibrary(name);
251 if (handle) {
252 softokenLib = handle;
253 return PR_SUCCESS;
255 return PR_FAILURE;
259 * load a new module into our address space and initialize it.
261 SECStatus
262 SECMOD_LoadPKCS11Module(SECMODModule *mod) {
263 PRLibrary *library = NULL;
264 CK_C_GetFunctionList entry = NULL;
265 char * full_name;
266 CK_INFO info;
267 CK_ULONG slotCount = 0;
268 SECStatus rv;
269 PRBool alreadyLoaded = PR_FALSE;
270 char *disableUnload = NULL;
272 if (mod->loaded) return SECSuccess;
274 /* intenal modules get loaded from their internal list */
275 if (mod->internal) {
277 * Loads softoken as a dynamic library,
278 * even though the rest of NSS assumes this as the "internal" module.
280 if (!softokenLib &&
281 PR_SUCCESS != PR_CallOnce(&loadSoftokenOnce, &softoken_LoadDSO))
282 return SECFailure;
284 PR_AtomicIncrement(&softokenLoadCount);
286 if (mod->isFIPS) {
287 entry = (CK_C_GetFunctionList)
288 PR_FindSymbol(softokenLib, "FC_GetFunctionList");
289 } else {
290 entry = (CK_C_GetFunctionList)
291 PR_FindSymbol(softokenLib, "NSC_GetFunctionList");
294 if (!entry)
295 return SECFailure;
297 if (mod->isModuleDB) {
298 mod->moduleDBFunc = (CK_C_GetFunctionList)
299 PR_FindSymbol(softokenLib, "NSC_ModuleDBFunc");
302 if (mod->moduleDBOnly) {
303 mod->loaded = PR_TRUE;
304 return SECSuccess;
306 } else {
307 /* Not internal, load the DLL and look up C_GetFunctionList */
308 if (mod->dllName == NULL) {
309 return SECFailure;
312 #ifdef notdef
313 /* look up the library name */
314 full_name = PR_GetLibraryName(PR_GetLibraryPath(),mod->dllName);
315 if (full_name == NULL) {
316 return SECFailure;
318 #else
319 full_name = PORT_Strdup(mod->dllName);
320 #endif
322 /* load the library. If this succeeds, then we have to remember to
323 * unload the library if anything goes wrong from here on out...
325 library = PR_LoadLibrary(full_name);
326 mod->library = (void *)library;
327 #ifdef notdef
328 PR_FreeLibraryName(full_name);
329 #else
330 PORT_Free(full_name);
331 #endif
333 if (library == NULL) {
334 return SECFailure;
338 * now we need to get the entry point to find the function pointers
340 if (!mod->moduleDBOnly) {
341 entry = (CK_C_GetFunctionList)
342 PR_FindSymbol(library, "C_GetFunctionList");
344 if (mod->isModuleDB) {
345 mod->moduleDBFunc = (void *)
346 PR_FindSymbol(library, "NSS_ReturnModuleSpecData");
348 if (mod->moduleDBFunc == NULL) mod->isModuleDB = PR_FALSE;
349 if (entry == NULL) {
350 if (mod->isModuleDB) {
351 mod->loaded = PR_TRUE;
352 mod->moduleDBOnly = PR_TRUE;
353 return SECSuccess;
355 PR_UnloadLibrary(library);
356 return SECFailure;
361 * We need to get the function list
363 if ((*entry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
364 goto fail;
366 #ifdef DEBUG_MODULE
367 if (PR_TRUE) {
368 modToDBG = PR_GetEnv("NSS_DEBUG_PKCS11_MODULE");
369 if (modToDBG && strcmp(mod->commonName, modToDBG) == 0) {
370 mod->functionList = (void *)nss_InsertDeviceLog(
371 (CK_FUNCTION_LIST_PTR)mod->functionList);
374 #endif
376 mod->isThreadSafe = PR_TRUE;
378 /* Now we initialize the module */
379 rv = secmod_ModuleInit(mod, &alreadyLoaded);
380 if (rv != SECSuccess) {
381 goto fail;
384 /* check the version number */
385 if (PK11_GETTAB(mod)->C_GetInfo(&info) != CKR_OK) goto fail2;
386 if (info.cryptokiVersion.major != 2) goto fail2;
387 /* all 2.0 are a priori *not* thread safe */
388 if (info.cryptokiVersion.minor < 1) {
389 if (!loadSingleThreadedModules) {
390 PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
391 goto fail2;
392 } else {
393 mod->isThreadSafe = PR_FALSE;
396 mod->cryptokiVersion = info.cryptokiVersion;
398 /* If we don't have a common name, get it from the PKCS 11 module */
399 if ((mod->commonName == NULL) || (mod->commonName[0] == 0)) {
400 mod->commonName = PK11_MakeString(mod->arena,NULL,
401 (char *)info.libraryDescription, sizeof(info.libraryDescription));
402 if (mod->commonName == NULL) goto fail2;
406 /* initialize the Slots */
407 if (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &slotCount) == CKR_OK) {
408 CK_SLOT_ID *slotIDs;
409 int i;
410 CK_RV crv;
412 mod->slots = (PK11SlotInfo **)PORT_ArenaAlloc(mod->arena,
413 sizeof(PK11SlotInfo *) * slotCount);
414 if (mod->slots == NULL) goto fail2;
416 slotIDs = (CK_SLOT_ID *) PORT_Alloc(sizeof(CK_SLOT_ID)*slotCount);
417 if (slotIDs == NULL) {
418 goto fail2;
420 crv = PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, slotIDs, &slotCount);
421 if (crv != CKR_OK) {
422 PORT_Free(slotIDs);
423 goto fail2;
426 /* Initialize each slot */
427 for (i=0; i < (int)slotCount; i++) {
428 mod->slots[i] = PK11_NewSlotInfo(mod);
429 PK11_InitSlot(mod,slotIDs[i],mod->slots[i]);
430 /* look down the slot info table */
431 PK11_LoadSlotList(mod->slots[i],mod->slotInfo,mod->slotInfoCount);
432 SECMOD_SetRootCerts(mod->slots[i],mod);
434 mod->slotCount = slotCount;
435 mod->slotInfoCount = 0;
436 PORT_Free(slotIDs);
439 mod->loaded = PR_TRUE;
440 mod->moduleID = nextModuleID++;
441 return SECSuccess;
442 fail2:
443 if (enforceAlreadyInitializedError || (!alreadyLoaded)) {
444 PK11_GETTAB(mod)->C_Finalize(NULL);
446 fail:
447 mod->functionList = NULL;
448 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
449 if (library && !disableUnload) {
450 PR_UnloadLibrary(library);
452 return SECFailure;
455 SECStatus
456 SECMOD_UnloadModule(SECMODModule *mod) {
457 PRLibrary *library;
458 char *disableUnload = NULL;
460 if (!mod->loaded) {
461 return SECFailure;
463 if (finalizeModules) {
464 if (!mod->moduleDBOnly) PK11_GETTAB(mod)->C_Finalize(NULL);
466 mod->moduleID = 0;
467 mod->loaded = PR_FALSE;
469 /* do we want the semantics to allow unloading the internal library?
470 * if not, we should change this to SECFailure and move it above the
471 * mod->loaded = PR_FALSE; */
472 if (mod->internal) {
473 if (0 == PR_AtomicDecrement(&softokenLoadCount)) {
474 if (softokenLib) {
475 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
476 if (!disableUnload) {
477 PRStatus status = PR_UnloadLibrary(softokenLib);
478 PORT_Assert(PR_SUCCESS == status);
480 softokenLib = NULL;
482 loadSoftokenOnce = pristineCallOnce;
484 return SECSuccess;
487 library = (PRLibrary *)mod->library;
488 /* paranoia */
489 if (library == NULL) {
490 return SECFailure;
493 disableUnload = PR_GetEnv("NSS_DISABLE_UNLOAD");
494 if (!disableUnload) {
495 PR_UnloadLibrary(library);
497 return SECSuccess;
500 void
501 nss_DumpModuleLog(void)
503 #ifdef DEBUG_MODULE
504 if (modToDBG) {
505 print_final_statistics();
507 #endif