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
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.
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
52 #define DEBUG_MODULE 1
56 static char *modToDBG
= NULL
;
58 #include "debug_module.c"
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
);
73 CK_RV PR_CALLBACK
secmodLockMutext(CK_VOID_PTR mutext
) {
74 PZ_Lock((PZLock
*)mutext
);
78 CK_RV PR_CALLBACK
secmodUnlockMutext(CK_VOID_PTR mutext
) {
79 PZ_Unlock((PZLock
*)mutext
);
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
|
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
;
103 loadSingleThreadedModules
= PR_TRUE
;
105 if (allowAlreadyInitializedModules
) {
106 enforceAlreadyInitializedError
= PR_FALSE
;
108 enforceAlreadyInitializedError
= PR_TRUE
;
110 if (dontFinalizeModules
) {
111 finalizeModules
= PR_FALSE
;
113 finalizeModules
= PR_TRUE
;
118 PRBool
pk11_getFinalizeModulesOption(void)
120 return finalizeModules
;
124 * collect the steps we need to initialize a module in a single function
127 secmod_ModuleInit(SECMODModule
*mod
, PRBool
* alreadyLoaded
)
129 CK_C_INITIALIZE_ARGS moduleArgs
;
130 CK_VOID_PTR pInitArgs
;
133 if (!mod
|| !alreadyLoaded
) {
134 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
138 if (mod
->isThreadSafe
== PR_FALSE
) {
140 } else if (mod
->libraryParams
== NULL
) {
141 pInitArgs
= (void *) &secmodLockFunctions
;
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
;
154 if (pInitArgs
== NULL
||
155 crv
== CKR_NETSCAPE_CERTDB_FAILED
||
156 crv
== CKR_NETSCAPE_KEYDB_FAILED
) {
157 PORT_SetError(PK11_MapError(crv
));
160 if (!loadSingleThreadedModules
) {
161 PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11
);
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
;
172 PORT_SetError(PK11_MapError(crv
));
180 * set the hasRootCerts flags in the module so it can be stored back
184 SECMOD_SetRootCerts(PK11SlotInfo
*slot
, SECMODModule
*mod
) {
185 PK11PreSlotInfo
*psi
= NULL
;
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
];
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
;
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
;
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. */
240 softoken_LoadDSO( void )
243 const char * name
= softoken_default_name
;
246 PR_SetError(PR_LOAD_LIBRARY_ERROR
, 0);
250 handle
= loader_LoadLibrary(name
);
252 softokenLib
= handle
;
259 * load a new module into our address space and initialize it.
262 SECMOD_LoadPKCS11Module(SECMODModule
*mod
) {
263 PRLibrary
*library
= NULL
;
264 CK_C_GetFunctionList entry
= NULL
;
267 CK_ULONG slotCount
= 0;
269 PRBool alreadyLoaded
= PR_FALSE
;
270 char *disableUnload
= NULL
;
272 if (mod
->loaded
) return SECSuccess
;
274 /* intenal modules get loaded from their internal list */
277 * Loads softoken as a dynamic library,
278 * even though the rest of NSS assumes this as the "internal" module.
281 PR_SUCCESS
!= PR_CallOnce(&loadSoftokenOnce
, &softoken_LoadDSO
))
284 PR_AtomicIncrement(&softokenLoadCount
);
287 entry
= (CK_C_GetFunctionList
)
288 PR_FindSymbol(softokenLib
, "FC_GetFunctionList");
290 entry
= (CK_C_GetFunctionList
)
291 PR_FindSymbol(softokenLib
, "NSC_GetFunctionList");
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
;
307 /* Not internal, load the DLL and look up C_GetFunctionList */
308 if (mod
->dllName
== NULL
) {
313 /* look up the library name */
314 full_name
= PR_GetLibraryName(PR_GetLibraryPath(),mod
->dllName
);
315 if (full_name
== NULL
) {
319 full_name
= PORT_Strdup(mod
->dllName
);
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
;
328 PR_FreeLibraryName(full_name
);
330 PORT_Free(full_name
);
333 if (library
== NULL
) {
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
;
350 if (mod
->isModuleDB
) {
351 mod
->loaded
= PR_TRUE
;
352 mod
->moduleDBOnly
= PR_TRUE
;
355 PR_UnloadLibrary(library
);
361 * We need to get the function list
363 if ((*entry
)((CK_FUNCTION_LIST_PTR
*)&mod
->functionList
) != CKR_OK
)
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
);
376 mod
->isThreadSafe
= PR_TRUE
;
378 /* Now we initialize the module */
379 rv
= secmod_ModuleInit(mod
, &alreadyLoaded
);
380 if (rv
!= SECSuccess
) {
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
);
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
) {
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
) {
420 crv
= PK11_GETTAB(mod
)->C_GetSlotList(CK_FALSE
, slotIDs
, &slotCount
);
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;
439 mod
->loaded
= PR_TRUE
;
440 mod
->moduleID
= nextModuleID
++;
443 if (enforceAlreadyInitializedError
|| (!alreadyLoaded
)) {
444 PK11_GETTAB(mod
)->C_Finalize(NULL
);
447 mod
->functionList
= NULL
;
448 disableUnload
= PR_GetEnv("NSS_DISABLE_UNLOAD");
449 if (library
&& !disableUnload
) {
450 PR_UnloadLibrary(library
);
456 SECMOD_UnloadModule(SECMODModule
*mod
) {
458 char *disableUnload
= NULL
;
463 if (finalizeModules
) {
464 if (!mod
->moduleDBOnly
) PK11_GETTAB(mod
)->C_Finalize(NULL
);
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; */
473 if (0 == PR_AtomicDecrement(&softokenLoadCount
)) {
475 disableUnload
= PR_GetEnv("NSS_DISABLE_UNLOAD");
476 if (!disableUnload
) {
477 PRStatus status
= PR_UnloadLibrary(softokenLib
);
478 PORT_Assert(PR_SUCCESS
== status
);
482 loadSoftokenOnce
= pristineCallOnce
;
487 library
= (PRLibrary
*)mod
->library
;
489 if (library
== NULL
) {
493 disableUnload
= PR_GetEnv("NSS_DISABLE_UNLOAD");
494 if (!disableUnload
) {
495 PR_UnloadLibrary(library
);
501 nss_DumpModuleLog(void)
505 print_final_statistics();