OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * Initialize the PCKS 11 subsystem | |
6 */ | |
7 #include "seccomon.h" | |
8 #include "secmod.h" | |
9 #include "nssilock.h" | |
10 #include "secmodi.h" | |
11 #include "secmodti.h" | |
12 #include "pk11func.h" | |
13 #include "pki3hack.h" | |
14 #include "secerr.h" | |
15 #include "dev.h" | |
16 #include "utilpars.h" | |
17 | |
18 /* these are for displaying error messages */ | |
19 | |
20 static SECMODModuleList *modules = NULL; | |
21 static SECMODModuleList *modulesDB = NULL; | |
22 static SECMODModuleList *modulesUnload = NULL; | |
23 static SECMODModule *internalModule = NULL; | |
24 static SECMODModule *defaultDBModule = NULL; | |
25 static SECMODModule *pendingModule = NULL; | |
26 static SECMODListLock *moduleLock = NULL; | |
27 | |
28 int secmod_PrivateModuleCount = 0; | |
29 | |
30 extern const PK11DefaultArrayEntry PK11_DefaultArray[]; | |
31 extern const int num_pk11_default_mechanisms; | |
32 | |
33 | |
34 void | |
35 SECMOD_Init() | |
36 { | |
37 /* don't initialize twice */ | |
38 if (moduleLock) return; | |
39 | |
40 moduleLock = SECMOD_NewListLock(); | |
41 PK11_InitSlotLists(); | |
42 } | |
43 | |
44 | |
45 SECStatus | |
46 SECMOD_Shutdown() | |
47 { | |
48 /* destroy the lock */ | |
49 if (moduleLock) { | |
50 SECMOD_DestroyListLock(moduleLock); | |
51 moduleLock = NULL; | |
52 } | |
53 /* free the internal module */ | |
54 if (internalModule) { | |
55 SECMOD_DestroyModule(internalModule); | |
56 internalModule = NULL; | |
57 } | |
58 | |
59 /* free the default database module */ | |
60 if (defaultDBModule) { | |
61 SECMOD_DestroyModule(defaultDBModule); | |
62 defaultDBModule = NULL; | |
63 } | |
64 | |
65 /* destroy the list */ | |
66 if (modules) { | |
67 SECMOD_DestroyModuleList(modules); | |
68 modules = NULL; | |
69 } | |
70 | |
71 if (modulesDB) { | |
72 SECMOD_DestroyModuleList(modulesDB); | |
73 modulesDB = NULL; | |
74 } | |
75 | |
76 if (modulesUnload) { | |
77 SECMOD_DestroyModuleList(modulesUnload); | |
78 modulesUnload = NULL; | |
79 } | |
80 | |
81 /* make all the slots and the lists go away */ | |
82 PK11_DestroySlotLists(); | |
83 | |
84 nss_DumpModuleLog(); | |
85 | |
86 #ifdef DEBUG | |
87 if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) { | |
88 PORT_Assert(secmod_PrivateModuleCount == 0); | |
89 } | |
90 #endif | |
91 if (secmod_PrivateModuleCount) { | |
92 PORT_SetError(SEC_ERROR_BUSY); | |
93 return SECFailure; | |
94 } | |
95 return SECSuccess; | |
96 } | |
97 | |
98 | |
99 /* | |
100 * retrieve the internal module | |
101 */ | |
102 SECMODModule * | |
103 SECMOD_GetInternalModule(void) | |
104 { | |
105 return internalModule; | |
106 } | |
107 | |
108 | |
109 SECStatus | |
110 secmod_AddModuleToList(SECMODModuleList **moduleList,SECMODModule *newModule) | |
111 { | |
112 SECMODModuleList *mlp, *newListElement, *last = NULL; | |
113 | |
114 newListElement = SECMOD_NewModuleListElement(); | |
115 if (newListElement == NULL) { | |
116 return SECFailure; | |
117 } | |
118 | |
119 newListElement->module = SECMOD_ReferenceModule(newModule); | |
120 | |
121 SECMOD_GetWriteLock(moduleLock); | |
122 /* Added it to the end (This is very inefficient, but Adding a module | |
123 * on the fly should happen maybe 2-3 times through the life this program | |
124 * on a given computer, and this list should be *SHORT*. */ | |
125 for(mlp = *moduleList; mlp != NULL; mlp = mlp->next) { | |
126 last = mlp; | |
127 } | |
128 | |
129 if (last == NULL) { | |
130 *moduleList = newListElement; | |
131 } else { | |
132 SECMOD_AddList(last,newListElement,NULL); | |
133 } | |
134 SECMOD_ReleaseWriteLock(moduleLock); | |
135 return SECSuccess; | |
136 } | |
137 | |
138 SECStatus | |
139 SECMOD_AddModuleToList(SECMODModule *newModule) | |
140 { | |
141 if (newModule->internal && !internalModule) { | |
142 internalModule = SECMOD_ReferenceModule(newModule); | |
143 } | |
144 return secmod_AddModuleToList(&modules,newModule); | |
145 } | |
146 | |
147 SECStatus | |
148 SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule) | |
149 { | |
150 if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) { | |
151 SECMOD_DestroyModule(defaultDBModule); | |
152 defaultDBModule = SECMOD_ReferenceModule(newModule); | |
153 } else if (defaultDBModule == NULL) { | |
154 defaultDBModule = SECMOD_ReferenceModule(newModule); | |
155 } | |
156 return secmod_AddModuleToList(&modulesDB,newModule); | |
157 } | |
158 | |
159 SECStatus | |
160 SECMOD_AddModuleToUnloadList(SECMODModule *newModule) | |
161 { | |
162 return secmod_AddModuleToList(&modulesUnload,newModule); | |
163 } | |
164 | |
165 /* | |
166 * get the list of PKCS11 modules that are available. | |
167 */ | |
168 SECMODModuleList * SECMOD_GetDefaultModuleList() { return modules; } | |
169 SECMODModuleList *SECMOD_GetDeadModuleList() { return modulesUnload; } | |
170 SECMODModuleList *SECMOD_GetDBModuleList() { return modulesDB; } | |
171 | |
172 /* | |
173 * This lock protects the global module lists. | |
174 * it also protects changes to the slot array (module->slots[]) and slot count | |
175 * (module->slotCount) in each module. It is a read/write lock with multiple | |
176 * readers or one writer. Writes are uncommon. | |
177 * Because of legacy considerations protection of the slot array and count is | |
178 * only necessary in applications if the application calls | |
179 * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new | |
180 * applications are encouraged to acquire this lock when reading the | |
181 * slot array information directly. | |
182 */ | |
183 SECMODListLock *SECMOD_GetDefaultModuleListLock() { return moduleLock; } | |
184 | |
185 | |
186 | |
187 /* | |
188 * find a module by name, and add a reference to it. | |
189 * return that module. | |
190 */ | |
191 SECMODModule * | |
192 SECMOD_FindModule(const char *name) | |
193 { | |
194 SECMODModuleList *mlp; | |
195 SECMODModule *module = NULL; | |
196 | |
197 if (!moduleLock) { | |
198 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
199 return module; | |
200 } | |
201 SECMOD_GetReadLock(moduleLock); | |
202 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
203 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
204 module = mlp->module; | |
205 SECMOD_ReferenceModule(module); | |
206 break; | |
207 } | |
208 } | |
209 if (module) { | |
210 goto found; | |
211 } | |
212 for(mlp = modulesUnload; mlp != NULL; mlp = mlp->next) { | |
213 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
214 module = mlp->module; | |
215 SECMOD_ReferenceModule(module); | |
216 break; | |
217 } | |
218 } | |
219 | |
220 found: | |
221 SECMOD_ReleaseReadLock(moduleLock); | |
222 | |
223 return module; | |
224 } | |
225 | |
226 /* | |
227 * find a module by ID, and add a reference to it. | |
228 * return that module. | |
229 */ | |
230 SECMODModule * | |
231 SECMOD_FindModuleByID(SECMODModuleID id) | |
232 { | |
233 SECMODModuleList *mlp; | |
234 SECMODModule *module = NULL; | |
235 | |
236 if (!moduleLock) { | |
237 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
238 return module; | |
239 } | |
240 SECMOD_GetReadLock(moduleLock); | |
241 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
242 if (id == mlp->module->moduleID) { | |
243 module = mlp->module; | |
244 SECMOD_ReferenceModule(module); | |
245 break; | |
246 } | |
247 } | |
248 SECMOD_ReleaseReadLock(moduleLock); | |
249 if (module == NULL) { | |
250 PORT_SetError(SEC_ERROR_NO_MODULE); | |
251 } | |
252 return module; | |
253 } | |
254 | |
255 /* | |
256 * find the function pointer. | |
257 */ | |
258 SECMODModule * | |
259 secmod_FindModuleByFuncPtr(void *funcPtr) | |
260 { | |
261 SECMODModuleList *mlp; | |
262 SECMODModule *module = NULL; | |
263 | |
264 SECMOD_GetReadLock(moduleLock); | |
265 for(mlp = modules; mlp != NULL; mlp = mlp->next) { | |
266 /* paranoia, shouldn't ever happen */ | |
267 if (!mlp->module) { | |
268 continue; | |
269 } | |
270 if (funcPtr == mlp->module->functionList) { | |
271 module = mlp->module; | |
272 SECMOD_ReferenceModule(module); | |
273 break; | |
274 } | |
275 } | |
276 SECMOD_ReleaseReadLock(moduleLock); | |
277 if (module == NULL) { | |
278 PORT_SetError(SEC_ERROR_NO_MODULE); | |
279 } | |
280 return module; | |
281 } | |
282 | |
283 /* | |
284 * Find the Slot based on ID and the module. | |
285 */ | |
286 PK11SlotInfo * | |
287 SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID) | |
288 { | |
289 int i; | |
290 PK11SlotInfo *slot = NULL; | |
291 | |
292 if (!moduleLock) { | |
293 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
294 return slot; | |
295 } | |
296 SECMOD_GetReadLock(moduleLock); | |
297 for (i=0; i < module->slotCount; i++) { | |
298 PK11SlotInfo *cSlot = module->slots[i]; | |
299 | |
300 if (cSlot->slotID == slotID) { | |
301 slot = PK11_ReferenceSlot(cSlot); | |
302 break; | |
303 } | |
304 } | |
305 SECMOD_ReleaseReadLock(moduleLock); | |
306 | |
307 if (slot == NULL) { | |
308 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
309 } | |
310 return slot; | |
311 } | |
312 | |
313 /* | |
314 * lookup the Slot module based on it's module ID and slot ID. | |
315 */ | |
316 PK11SlotInfo * | |
317 SECMOD_LookupSlot(SECMODModuleID moduleID,CK_SLOT_ID slotID) | |
318 { | |
319 SECMODModule *module; | |
320 PK11SlotInfo *slot; | |
321 | |
322 module = SECMOD_FindModuleByID(moduleID); | |
323 if (module == NULL) return NULL; | |
324 | |
325 slot = SECMOD_FindSlotByID(module, slotID); | |
326 SECMOD_DestroyModule(module); | |
327 return slot; | |
328 } | |
329 | |
330 | |
331 /* | |
332 * find a module by name or module pointer and delete it off the module list. | |
333 * optionally remove it from secmod.db. | |
334 */ | |
335 SECStatus | |
336 SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod, | |
337 int *type, PRBool permdb) | |
338 { | |
339 SECMODModuleList *mlp; | |
340 SECMODModuleList **mlpp; | |
341 SECStatus rv = SECFailure; | |
342 | |
343 if (!moduleLock) { | |
344 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
345 return rv; | |
346 } | |
347 | |
348 *type = SECMOD_EXTERNAL; | |
349 | |
350 SECMOD_GetWriteLock(moduleLock); | |
351 for (mlpp = &modules,mlp = modules; | |
352 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
353 if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || | |
354 mod == mlp->module) { | |
355 /* don't delete the internal module */ | |
356 if (!mlp->module->internal) { | |
357 SECMOD_RemoveList(mlpp,mlp); | |
358 /* delete it after we release the lock */ | |
359 rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |
360 } else if (mlp->module->isFIPS) { | |
361 *type = SECMOD_FIPS; | |
362 } else { | |
363 *type = SECMOD_INTERNAL; | |
364 } | |
365 break; | |
366 } | |
367 } | |
368 if (mlp) { | |
369 goto found; | |
370 } | |
371 /* not on the internal list, check the unload list */ | |
372 for (mlpp = &modulesUnload,mlp = modulesUnload; | |
373 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
374 if ((name && (PORT_Strcmp(name,mlp->module->commonName) == 0)) || | |
375 mod == mlp->module) { | |
376 /* don't delete the internal module */ | |
377 if (!mlp->module->internal) { | |
378 SECMOD_RemoveList(mlpp,mlp); | |
379 rv = SECSuccess; | |
380 } else if (mlp->module->isFIPS) { | |
381 *type = SECMOD_FIPS; | |
382 } else { | |
383 *type = SECMOD_INTERNAL; | |
384 } | |
385 break; | |
386 } | |
387 } | |
388 found: | |
389 SECMOD_ReleaseWriteLock(moduleLock); | |
390 | |
391 | |
392 if (rv == SECSuccess) { | |
393 if (permdb) { | |
394 SECMOD_DeletePermDB(mlp->module); | |
395 } | |
396 SECMOD_DestroyModuleListElement(mlp); | |
397 } | |
398 return rv; | |
399 } | |
400 | |
401 /* | |
402 * find a module by name and delete it off the module list | |
403 */ | |
404 SECStatus | |
405 SECMOD_DeleteModule(const char *name, int *type) | |
406 { | |
407 return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE); | |
408 } | |
409 | |
410 /* | |
411 * find a module by name and delete it off the module list | |
412 */ | |
413 SECStatus | |
414 SECMOD_DeleteInternalModule(const char *name) | |
415 { | |
416 SECMODModuleList *mlp; | |
417 SECMODModuleList **mlpp; | |
418 SECStatus rv = SECFailure; | |
419 | |
420 if (pendingModule) { | |
421 PORT_SetError(SEC_ERROR_MODULE_STUCK); | |
422 return rv; | |
423 } | |
424 if (!moduleLock) { | |
425 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
426 return rv; | |
427 } | |
428 | |
429 SECMOD_GetWriteLock(moduleLock); | |
430 for(mlpp = &modules,mlp = modules; | |
431 mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) { | |
432 if (PORT_Strcmp(name,mlp->module->commonName) == 0) { | |
433 /* don't delete the internal module */ | |
434 if (mlp->module->internal) { | |
435 SECMOD_RemoveList(mlpp,mlp); | |
436 rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module); | |
437 } | |
438 break; | |
439 } | |
440 } | |
441 SECMOD_ReleaseWriteLock(moduleLock); | |
442 | |
443 if (rv == SECSuccess) { | |
444 SECMODModule *newModule,*oldModule; | |
445 | |
446 if (mlp->module->isFIPS) { | |
447 newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME, | |
448 NULL, SECMOD_INT_FLAGS); | |
449 } else { | |
450 newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME, | |
451 NULL, SECMOD_FIPS_FLAGS); | |
452 } | |
453 if (newModule) { | |
454 PK11SlotInfo *slot; | |
455 newModule->libraryParams = | |
456 PORT_ArenaStrdup(newModule->arena,mlp->module->libraryParams); | |
457 /* if an explicit internal key slot has been set, reset it */ | |
458 slot = pk11_SwapInternalKeySlot(NULL); | |
459 if (slot) { | |
460 secmod_SetInternalKeySlotFlag(newModule, PR_TRUE); | |
461 } | |
462 rv = SECMOD_AddModule(newModule); | |
463 if (rv != SECSuccess) { | |
464 /* load failed, restore the internal key slot */ | |
465 pk11_SetInternalKeySlot(slot); | |
466 SECMOD_DestroyModule(newModule); | |
467 newModule = NULL; | |
468 } | |
469 /* free the old explicit internal key slot, we now have a new one */ | |
470 if (slot) { | |
471 PK11_FreeSlot(slot); | |
472 } | |
473 } | |
474 if (newModule == NULL) { | |
475 SECMODModuleList *last = NULL,*mlp2; | |
476 /* we're in pretty deep trouble if this happens...Security | |
477 * not going to work well... try to put the old module back on | |
478 * the list */ | |
479 SECMOD_GetWriteLock(moduleLock); | |
480 for(mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) { | |
481 last = mlp2; | |
482 } | |
483 | |
484 if (last == NULL) { | |
485 modules = mlp; | |
486 } else { | |
487 SECMOD_AddList(last,mlp,NULL); | |
488 } | |
489 SECMOD_ReleaseWriteLock(moduleLock); | |
490 return SECFailure; | |
491 } | |
492 pendingModule = oldModule = internalModule; | |
493 internalModule = NULL; | |
494 SECMOD_DestroyModule(oldModule); | |
495 SECMOD_DeletePermDB(mlp->module); | |
496 SECMOD_DestroyModuleListElement(mlp); | |
497 internalModule = newModule; /* adopt the module */ | |
498 } | |
499 return rv; | |
500 } | |
501 | |
502 SECStatus | |
503 SECMOD_AddModule(SECMODModule *newModule) | |
504 { | |
505 SECStatus rv; | |
506 SECMODModule *oldModule; | |
507 | |
508 /* Test if a module w/ the same name already exists */ | |
509 /* and return SECWouldBlock if so. */ | |
510 /* We should probably add a new return value such as */ | |
511 /* SECDublicateModule, but to minimize ripples, I'll */ | |
512 /* give SECWouldBlock a new meaning */ | |
513 if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) { | |
514 SECMOD_DestroyModule(oldModule); | |
515 return SECWouldBlock; | |
516 /* module already exists. */ | |
517 } | |
518 | |
519 rv = secmod_LoadPKCS11Module(newModule, NULL); | |
520 if (rv != SECSuccess) { | |
521 return rv; | |
522 } | |
523 | |
524 if (newModule->parent == NULL) { | |
525 newModule->parent = SECMOD_ReferenceModule(defaultDBModule); | |
526 } | |
527 | |
528 SECMOD_AddPermDB(newModule); | |
529 SECMOD_AddModuleToList(newModule); | |
530 | |
531 rv = STAN_AddModuleToDefaultTrustDomain(newModule); | |
532 | |
533 return rv; | |
534 } | |
535 | |
536 PK11SlotInfo * | |
537 SECMOD_FindSlot(SECMODModule *module,const char *name) | |
538 { | |
539 int i; | |
540 char *string; | |
541 PK11SlotInfo *retSlot = NULL; | |
542 | |
543 if (!moduleLock) { | |
544 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
545 return retSlot; | |
546 } | |
547 SECMOD_GetReadLock(moduleLock); | |
548 for (i=0; i < module->slotCount; i++) { | |
549 PK11SlotInfo *slot = module->slots[i]; | |
550 | |
551 if (PK11_IsPresent(slot)) { | |
552 string = PK11_GetTokenName(slot); | |
553 } else { | |
554 string = PK11_GetSlotName(slot); | |
555 } | |
556 if (PORT_Strcmp(name,string) == 0) { | |
557 retSlot = PK11_ReferenceSlot(slot); | |
558 break; | |
559 } | |
560 } | |
561 SECMOD_ReleaseReadLock(moduleLock); | |
562 | |
563 if (retSlot == NULL) { | |
564 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
565 } | |
566 return retSlot; | |
567 } | |
568 | |
569 SECStatus | |
570 PK11_GetModInfo(SECMODModule *mod,CK_INFO *info) | |
571 { | |
572 CK_RV crv; | |
573 | |
574 if (mod->functionList == NULL) return SECFailure; | |
575 crv = PK11_GETTAB(mod)->C_GetInfo(info); | |
576 if (crv != CKR_OK) { | |
577 PORT_SetError(PK11_MapError(crv)); | |
578 } | |
579 return (crv == CKR_OK) ? SECSuccess : SECFailure; | |
580 } | |
581 | |
582 /* Determine if we have the FIP's module loaded as the default | |
583 * module to trigger other bogus FIPS requirements in PKCS #12 and | |
584 * SSL | |
585 */ | |
586 PRBool | |
587 PK11_IsFIPS(void) | |
588 { | |
589 SECMODModule *mod = SECMOD_GetInternalModule(); | |
590 | |
591 if (mod && mod->internal) { | |
592 return mod->isFIPS; | |
593 } | |
594 | |
595 return PR_FALSE; | |
596 } | |
597 | |
598 /* combines NewModule() & AddModule */ | |
599 /* give a string for the module name & the full-path for the dll, */ | |
600 /* installs the PKCS11 module & update registry */ | |
601 SECStatus | |
602 SECMOD_AddNewModuleEx(const char* moduleName, const char* dllPath, | |
603 unsigned long defaultMechanismFlags, | |
604 unsigned long cipherEnableFlags, | |
605 char* modparms, char* nssparms) | |
606 { | |
607 SECMODModule *module; | |
608 SECStatus result = SECFailure; | |
609 int s,i; | |
610 PK11SlotInfo* slot; | |
611 | |
612 PR_SetErrorText(0, NULL); | |
613 if (!moduleLock) { | |
614 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
615 return result; | |
616 } | |
617 | |
618 module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms); | |
619 | |
620 if (module == NULL) { | |
621 return result; | |
622 } | |
623 | |
624 if (module->dllName != NULL) { | |
625 if (module->dllName[0] != 0) { | |
626 result = SECMOD_AddModule(module); | |
627 if (result == SECSuccess) { | |
628 /* turn on SSL cipher enable flags */ | |
629 module->ssl[0] = cipherEnableFlags; | |
630 | |
631 SECMOD_GetReadLock(moduleLock); | |
632 /* check each slot to turn on appropriate mechanisms */ | |
633 for (s = 0; s < module->slotCount; s++) { | |
634 slot = (module->slots)[s]; | |
635 /* for each possible mechanism */ | |
636 for (i=0; i < num_pk11_default_mechanisms; i++) { | |
637 /* we are told to turn it on by default ? */ | |
638 PRBool add = | |
639 (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? | |
640 PR_TRUE: PR_FALSE; | |
641 result = PK11_UpdateSlotAttribute(slot, | |
642 &(PK11_DefaultArray[i]), add); | |
643 if (result != SECSuccess) { | |
644 SECMOD_ReleaseReadLock(moduleLock); | |
645 SECMOD_DestroyModule(module); | |
646 return result; | |
647 } | |
648 } /* for each mechanism */ | |
649 /* disable each slot if the defaultFlags say so */ | |
650 if (defaultMechanismFlags & PK11_DISABLE_FLAG) { | |
651 PK11_UserDisableSlot(slot); | |
652 } | |
653 } /* for each slot of this module */ | |
654 SECMOD_ReleaseReadLock(moduleLock); | |
655 | |
656 /* delete and re-add module in order to save changes | |
657 * to the module */ | |
658 result = SECMOD_UpdateModule(module); | |
659 } | |
660 } | |
661 } | |
662 SECMOD_DestroyModule(module); | |
663 return result; | |
664 } | |
665 | |
666 SECStatus | |
667 SECMOD_AddNewModule(const char* moduleName, const char* dllPath, | |
668 unsigned long defaultMechanismFlags, | |
669 unsigned long cipherEnableFlags) | |
670 { | |
671 return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags, | |
672 cipherEnableFlags, | |
673 NULL, NULL); /* don't pass module or nss params */ | |
674 } | |
675 | |
676 SECStatus | |
677 SECMOD_UpdateModule(SECMODModule *module) | |
678 { | |
679 SECStatus result; | |
680 | |
681 result = SECMOD_DeletePermDB(module); | |
682 | |
683 if (result == SECSuccess) { | |
684 result = SECMOD_AddPermDB(module); | |
685 } | |
686 return result; | |
687 } | |
688 | |
689 /* Public & Internal(Security Library) representation of | |
690 * encryption mechanism flags conversion */ | |
691 | |
692 /* Currently, the only difference is that internal representation | |
693 * puts RANDOM_FLAG at bit 31 (Most-significant bit), but | |
694 * public representation puts this bit at bit 28 | |
695 */ | |
696 unsigned long | |
697 SECMOD_PubMechFlagstoInternal(unsigned long publicFlags) | |
698 { | |
699 unsigned long internalFlags = publicFlags; | |
700 | |
701 if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) { | |
702 internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG; | |
703 internalFlags |= SECMOD_RANDOM_FLAG; | |
704 } | |
705 return internalFlags; | |
706 } | |
707 | |
708 unsigned long | |
709 SECMOD_InternaltoPubMechFlags(unsigned long internalFlags) | |
710 { | |
711 unsigned long publicFlags = internalFlags; | |
712 | |
713 if (internalFlags & SECMOD_RANDOM_FLAG) { | |
714 publicFlags &= ~SECMOD_RANDOM_FLAG; | |
715 publicFlags |= PUBLIC_MECH_RANDOM_FLAG; | |
716 } | |
717 return publicFlags; | |
718 } | |
719 | |
720 | |
721 /* Public & Internal(Security Library) representation of */ | |
722 /* cipher flags conversion */ | |
723 /* Note: currently they are just stubs */ | |
724 unsigned long | |
725 SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags) | |
726 { | |
727 return publicFlags; | |
728 } | |
729 | |
730 unsigned long | |
731 SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags) | |
732 { | |
733 return internalFlags; | |
734 } | |
735 | |
736 /* Funtion reports true if module of modType is installed/configured */ | |
737 PRBool | |
738 SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ) | |
739 { | |
740 PRBool result = PR_FALSE; | |
741 SECMODModuleList *mods; | |
742 | |
743 if (!moduleLock) { | |
744 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
745 return result; | |
746 } | |
747 SECMOD_GetReadLock(moduleLock); | |
748 mods = SECMOD_GetDefaultModuleList(); | |
749 for ( ; mods != NULL; mods = mods->next) { | |
750 if (mods->module->ssl[0] & | |
751 SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) { | |
752 result = PR_TRUE; | |
753 } | |
754 } | |
755 | |
756 SECMOD_ReleaseReadLock(moduleLock); | |
757 return result; | |
758 } | |
759 | |
760 /* create a new ModuleListElement */ | |
761 SECMODModuleList *SECMOD_NewModuleListElement(void) | |
762 { | |
763 SECMODModuleList *newModList; | |
764 | |
765 newModList= (SECMODModuleList *) PORT_Alloc(sizeof(SECMODModuleList)); | |
766 if (newModList) { | |
767 newModList->next = NULL; | |
768 newModList->module = NULL; | |
769 } | |
770 return newModList; | |
771 } | |
772 | |
773 /* | |
774 * make a new reference to a module so It doesn't go away on us | |
775 */ | |
776 SECMODModule * | |
777 SECMOD_ReferenceModule(SECMODModule *module) | |
778 { | |
779 PZ_Lock(module->refLock); | |
780 PORT_Assert(module->refCount > 0); | |
781 | |
782 module->refCount++; | |
783 PZ_Unlock(module->refLock); | |
784 return module; | |
785 } | |
786 | |
787 | |
788 /* destroy an existing module */ | |
789 void | |
790 SECMOD_DestroyModule(SECMODModule *module) | |
791 { | |
792 PRBool willfree = PR_FALSE; | |
793 int slotCount; | |
794 int i; | |
795 | |
796 PZ_Lock(module->refLock); | |
797 if (module->refCount-- == 1) { | |
798 willfree = PR_TRUE; | |
799 } | |
800 PORT_Assert(willfree || (module->refCount > 0)); | |
801 PZ_Unlock(module->refLock); | |
802 | |
803 if (!willfree) { | |
804 return; | |
805 } | |
806 | |
807 if (module->parent != NULL) { | |
808 SECMODModule *parent = module->parent; | |
809 /* paranoia, don't loop forever if the modules are looped */ | |
810 module->parent = NULL; | |
811 SECMOD_DestroyModule(parent); | |
812 } | |
813 | |
814 /* slots can't really disappear until our module starts freeing them, | |
815 * so this check is safe */ | |
816 slotCount = module->slotCount; | |
817 if (slotCount == 0) { | |
818 SECMOD_SlotDestroyModule(module,PR_FALSE); | |
819 return; | |
820 } | |
821 | |
822 /* now free all out slots, when they are done, they will cause the | |
823 * module to disappear altogether */ | |
824 for (i=0 ; i < slotCount; i++) { | |
825 if (!module->slots[i]->disabled) { | |
826 PK11_ClearSlotList(module->slots[i]); | |
827 } | |
828 PK11_FreeSlot(module->slots[i]); | |
829 } | |
830 /* WARNING: once the last slot has been freed is it possible (even likely) | |
831 * that module is no more... touching it now is a good way to go south */ | |
832 } | |
833 | |
834 | |
835 /* we can only get here if we've destroyed the module, or some one has | |
836 * erroneously freed a slot that wasn't referenced. */ | |
837 void | |
838 SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot) | |
839 { | |
840 PRBool willfree = PR_FALSE; | |
841 if (fromSlot) { | |
842 PORT_Assert(module->refCount == 0); | |
843 PZ_Lock(module->refLock); | |
844 if (module->slotCount-- == 1) { | |
845 willfree = PR_TRUE; | |
846 } | |
847 PORT_Assert(willfree || (module->slotCount > 0)); | |
848 PZ_Unlock(module->refLock); | |
849 if (!willfree) return; | |
850 } | |
851 | |
852 if (module == pendingModule) { | |
853 pendingModule = NULL; | |
854 } | |
855 | |
856 if (module->loaded) { | |
857 SECMOD_UnloadModule(module); | |
858 } | |
859 PZ_DestroyLock(module->refLock); | |
860 PORT_FreeArena(module->arena,PR_FALSE); | |
861 secmod_PrivateModuleCount--; | |
862 } | |
863 | |
864 /* destroy a list element | |
865 * this destroys a single element, and returns the next element | |
866 * on the chain. It makes it easy to implement for loops to delete | |
867 * the chain. It also make deleting a single element easy */ | |
868 SECMODModuleList * | |
869 SECMOD_DestroyModuleListElement(SECMODModuleList *element) | |
870 { | |
871 SECMODModuleList *next = element->next; | |
872 | |
873 if (element->module) { | |
874 SECMOD_DestroyModule(element->module); | |
875 element->module = NULL; | |
876 } | |
877 PORT_Free(element); | |
878 return next; | |
879 } | |
880 | |
881 | |
882 /* | |
883 * Destroy an entire module list | |
884 */ | |
885 void | |
886 SECMOD_DestroyModuleList(SECMODModuleList *list) | |
887 { | |
888 SECMODModuleList *lp; | |
889 | |
890 for ( lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp)) ; | |
891 } | |
892 | |
893 PRBool | |
894 SECMOD_CanDeleteInternalModule(void) | |
895 { | |
896 return (PRBool) (pendingModule == NULL); | |
897 } | |
898 | |
899 /* | |
900 * check to see if the module has added new slots. PKCS 11 v2.20 allows for | |
901 * modules to add new slots, but never remove them. Slots cannot be added | |
902 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent | |
903 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently | |
904 * grow on the caller. It is permissible for the slots to increase between | |
905 * successive calls with NULL to get the size. | |
906 */ | |
907 SECStatus | |
908 SECMOD_UpdateSlotList(SECMODModule *mod) | |
909 { | |
910 CK_RV crv; | |
911 CK_ULONG count; | |
912 CK_ULONG i, oldCount; | |
913 PRBool freeRef = PR_FALSE; | |
914 void *mark = NULL; | |
915 CK_ULONG *slotIDs = NULL; | |
916 PK11SlotInfo **newSlots = NULL; | |
917 PK11SlotInfo **oldSlots = NULL; | |
918 | |
919 if (!moduleLock) { | |
920 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
921 return SECFailure; | |
922 } | |
923 | |
924 /* C_GetSlotList is not a session function, make sure | |
925 * calls are serialized */ | |
926 PZ_Lock(mod->refLock); | |
927 freeRef = PR_TRUE; | |
928 /* see if the number of slots have changed */ | |
929 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); | |
930 if (crv != CKR_OK) { | |
931 PORT_SetError(PK11_MapError(crv)); | |
932 goto loser; | |
933 } | |
934 /* nothing new, blow out early, we want this function to be quick | |
935 * and cheap in the normal case */ | |
936 if (count == mod->slotCount) { | |
937 PZ_Unlock(mod->refLock); | |
938 return SECSuccess; | |
939 } | |
940 if (count < (CK_ULONG)mod->slotCount) { | |
941 /* shouldn't happen with a properly functioning PKCS #11 module */ | |
942 PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); | |
943 goto loser; | |
944 } | |
945 | |
946 /* get the new slot list */ | |
947 slotIDs = PORT_NewArray(CK_SLOT_ID, count); | |
948 if (slotIDs == NULL) { | |
949 goto loser; | |
950 } | |
951 | |
952 crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); | |
953 if (crv != CKR_OK) { | |
954 PORT_SetError(PK11_MapError(crv)); | |
955 goto loser; | |
956 } | |
957 freeRef = PR_FALSE; | |
958 PZ_Unlock(mod->refLock); | |
959 mark = PORT_ArenaMark(mod->arena); | |
960 if (mark == NULL) { | |
961 goto loser; | |
962 } | |
963 newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); | |
964 | |
965 /* walk down the new slot ID list returned from the module. We keep | |
966 * the old slots which match a returned ID, and we initialize the new | |
967 * slots. */ | |
968 for (i=0; i < count; i++) { | |
969 PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); | |
970 | |
971 if (!slot) { | |
972 /* we have a new slot create a new slot data structure */ | |
973 slot = PK11_NewSlotInfo(mod); | |
974 if (!slot) { | |
975 goto loser; | |
976 } | |
977 PK11_InitSlot(mod, slotIDs[i], slot); | |
978 STAN_InitTokenForSlotInfo(NULL, slot); | |
979 } | |
980 newSlots[i] = slot; | |
981 } | |
982 STAN_ResetTokenInterator(NULL); | |
983 PORT_Free(slotIDs); | |
984 slotIDs = NULL; | |
985 PORT_ArenaUnmark(mod->arena, mark); | |
986 | |
987 /* until this point we're still using the old slot list. Now we update | |
988 * module slot list. We update the slots (array) first then the count, | |
989 * since we've already guarrenteed that count has increased (just in case | |
990 * someone is looking at the slots field of module without holding the | |
991 * moduleLock */ | |
992 SECMOD_GetWriteLock(moduleLock); | |
993 oldCount =mod->slotCount; | |
994 oldSlots = mod->slots; | |
995 mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is | |
996 * allocated out of the module arena and won't | |
997 * be freed until the module is freed */ | |
998 mod->slotCount = count; | |
999 SECMOD_ReleaseWriteLock(moduleLock); | |
1000 /* free our old references before forgetting about oldSlot*/ | |
1001 for (i=0; i < oldCount; i++) { | |
1002 PK11_FreeSlot(oldSlots[i]); | |
1003 } | |
1004 return SECSuccess; | |
1005 | |
1006 loser: | |
1007 if (freeRef) { | |
1008 PZ_Unlock(mod->refLock); | |
1009 } | |
1010 if (slotIDs) { | |
1011 PORT_Free(slotIDs); | |
1012 } | |
1013 /* free all the slots we allocated. newSlots are part of the | |
1014 * mod arena. NOTE: the newSlots array contain both new and old | |
1015 * slots, but we kept a reference to the old slots when we built the new | |
1016 * array, so we need to free all the slots in newSlots array. */ | |
1017 if (newSlots) { | |
1018 for (i=0; i < count; i++) { | |
1019 if (newSlots[i] == NULL) { | |
1020 break; /* hit the last one */ | |
1021 } | |
1022 PK11_FreeSlot(newSlots[i]); | |
1023 } | |
1024 } | |
1025 /* must come after freeing newSlots */ | |
1026 if (mark) { | |
1027 PORT_ArenaRelease(mod->arena, mark); | |
1028 } | |
1029 return SECFailure; | |
1030 } | |
1031 | |
1032 /* | |
1033 * this handles modules that do not support C_WaitForSlotEvent(). | |
1034 * The internal flags are stored. Note that C_WaitForSlotEvent() does not | |
1035 * have a timeout, so we don't have one for handleWaitForSlotEvent() either. | |
1036 */ | |
1037 PK11SlotInfo * | |
1038 secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags, | |
1039 PRIntervalTime latency) | |
1040 { | |
1041 PRBool removableSlotsFound = PR_FALSE; | |
1042 int i; | |
1043 int error = SEC_ERROR_NO_EVENT; | |
1044 | |
1045 if (!moduleLock) { | |
1046 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1047 return NULL; | |
1048 } | |
1049 PZ_Lock(mod->refLock); | |
1050 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1051 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1052 PZ_Unlock(mod->refLock); | |
1053 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1054 return NULL; | |
1055 } | |
1056 mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT; | |
1057 while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
1058 PZ_Unlock(mod->refLock); | |
1059 /* now is a good time to see if new slots have been added */ | |
1060 SECMOD_UpdateSlotList(mod); | |
1061 | |
1062 /* loop through all the slots on a module */ | |
1063 SECMOD_GetReadLock(moduleLock); | |
1064 for (i=0; i < mod->slotCount; i++) { | |
1065 PK11SlotInfo *slot = mod->slots[i]; | |
1066 PRUint16 series; | |
1067 PRBool present; | |
1068 | |
1069 /* perm modules do not change */ | |
1070 if (slot->isPerm) { | |
1071 continue; | |
1072 } | |
1073 removableSlotsFound = PR_TRUE; | |
1074 /* simulate the PKCS #11 module flags. are the flags different | |
1075 * from the last time we called? */ | |
1076 series = slot->series; | |
1077 present = PK11_IsPresent(slot); | |
1078 if ((slot->flagSeries != series) || (slot->flagState != present)) { | |
1079 slot->flagState = present; | |
1080 slot->flagSeries = series; | |
1081 SECMOD_ReleaseReadLock(moduleLock); | |
1082 PZ_Lock(mod->refLock); | |
1083 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1084 PZ_Unlock(mod->refLock); | |
1085 return PK11_ReferenceSlot(slot); | |
1086 } | |
1087 } | |
1088 SECMOD_ReleaseReadLock(moduleLock); | |
1089 /* if everything was perm modules, don't lock up forever */ | |
1090 if ((mod->slotCount !=0) && !removableSlotsFound) { | |
1091 error =SEC_ERROR_NO_SLOT_SELECTED; | |
1092 PZ_Lock(mod->refLock); | |
1093 break; | |
1094 } | |
1095 if (flags & CKF_DONT_BLOCK) { | |
1096 PZ_Lock(mod->refLock); | |
1097 break; | |
1098 } | |
1099 PR_Sleep(latency); | |
1100 PZ_Lock(mod->refLock); | |
1101 } | |
1102 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1103 PZ_Unlock(mod->refLock); | |
1104 PORT_SetError(error); | |
1105 return NULL; | |
1106 } | |
1107 | |
1108 /* | |
1109 * this function waits for a token event on any slot of a given module | |
1110 * This function should not be called from more than one thread of the | |
1111 * same process (though other threads can make other library calls | |
1112 * on this module while this call is blocked). | |
1113 */ | |
1114 PK11SlotInfo * | |
1115 SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags, | |
1116 PRIntervalTime latency) | |
1117 { | |
1118 CK_SLOT_ID id; | |
1119 CK_RV crv; | |
1120 PK11SlotInfo *slot; | |
1121 | |
1122 if (!pk11_getFinalizeModulesOption() || | |
1123 ((mod->cryptokiVersion.major == 2) && | |
1124 (mod->cryptokiVersion.minor < 1))) { | |
1125 /* if we are sharing the module with other software in our | |
1126 * address space, we can't reliably use C_WaitForSlotEvent(), | |
1127 * and if the module is version 2.0, C_WaitForSlotEvent() doesn't | |
1128 * exist */ | |
1129 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
1130 } | |
1131 /* first the the PKCS #11 call */ | |
1132 PZ_Lock(mod->refLock); | |
1133 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1134 goto end_wait; | |
1135 } | |
1136 mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT; | |
1137 PZ_Unlock(mod->refLock); | |
1138 crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL); | |
1139 PZ_Lock(mod->refLock); | |
1140 mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT; | |
1141 /* if we are in end wait, short circuit now, don't even risk | |
1142 * going into secmod_HandleWaitForSlotEvent */ | |
1143 if (mod->evControlMask & SECMOD_END_WAIT) { | |
1144 goto end_wait; | |
1145 } | |
1146 PZ_Unlock(mod->refLock); | |
1147 if (crv == CKR_FUNCTION_NOT_SUPPORTED) { | |
1148 /* module doesn't support that call, simulate it */ | |
1149 return secmod_HandleWaitForSlotEvent(mod, flags, latency); | |
1150 } | |
1151 if (crv != CKR_OK) { | |
1152 /* we can get this error if finalize was called while we were | |
1153 * still running. This is the only way to force a C_WaitForSlotEvent() | |
1154 * to return in PKCS #11. In this case, just return that there | |
1155 * was no event. */ | |
1156 if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) { | |
1157 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1158 } else { | |
1159 PORT_SetError(PK11_MapError(crv)); | |
1160 } | |
1161 return NULL; | |
1162 } | |
1163 slot = SECMOD_FindSlotByID(mod, id); | |
1164 if (slot == NULL) { | |
1165 /* possibly a new slot that was added? */ | |
1166 SECMOD_UpdateSlotList(mod); | |
1167 slot = SECMOD_FindSlotByID(mod, id); | |
1168 } | |
1169 /* if we are in the delay period for the "isPresent" call, reset | |
1170 * the delay since we know things have probably changed... */ | |
1171 if (slot && slot->nssToken && slot->nssToken->slot) { | |
1172 nssSlot_ResetDelay(slot->nssToken->slot); | |
1173 } | |
1174 return slot; | |
1175 | |
1176 /* must be called with the lock on. */ | |
1177 end_wait: | |
1178 mod->evControlMask &= ~SECMOD_END_WAIT; | |
1179 PZ_Unlock(mod->refLock); | |
1180 PORT_SetError(SEC_ERROR_NO_EVENT); | |
1181 return NULL; | |
1182 } | |
1183 | |
1184 /* | |
1185 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic | |
1186 * function, possibly bringing down the pkcs #11 module in question. This | |
1187 * should be OK because 1) it does reinitialize, and 2) it should only be | |
1188 * called when we are on our way to tear the whole system down anyway. | |
1189 */ | |
1190 SECStatus | |
1191 SECMOD_CancelWait(SECMODModule *mod) | |
1192 { | |
1193 unsigned long controlMask; | |
1194 SECStatus rv = SECSuccess; | |
1195 CK_RV crv; | |
1196 | |
1197 PZ_Lock(mod->refLock); | |
1198 mod->evControlMask |= SECMOD_END_WAIT; | |
1199 controlMask = mod->evControlMask; | |
1200 if (controlMask & SECMOD_WAIT_PKCS11_EVENT) { | |
1201 if (!pk11_getFinalizeModulesOption()) { | |
1202 /* can't get here unless pk11_getFinalizeModulesOption is set */ | |
1203 PORT_Assert(0); | |
1204 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
1205 rv = SECFailure; | |
1206 goto loser; | |
1207 } | |
1208 /* NOTE: this call will drop all transient keys, in progress | |
1209 * operations, and any authentication. This is the only documented | |
1210 * way to get WaitForSlotEvent to return. Also note: for non-thread | |
1211 * safe tokens, we need to hold the module lock, this is not yet at | |
1212 * system shutdown/startup time, so we need to protect these calls */ | |
1213 crv = PK11_GETTAB(mod)->C_Finalize(NULL); | |
1214 /* ok, we slammed the module down, now we need to reinit it in case | |
1215 * we intend to use it again */ | |
1216 if (CKR_OK == crv) { | |
1217 PRBool alreadyLoaded; | |
1218 secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
1219 } else { | |
1220 /* Finalized failed for some reason, notify the application | |
1221 * so maybe it has a prayer of recovering... */ | |
1222 PORT_SetError(PK11_MapError(crv)); | |
1223 rv = SECFailure; | |
1224 } | |
1225 } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) { | |
1226 mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT; | |
1227 /* Simulated events will eventually timeout | |
1228 * and wake up in the loop */ | |
1229 } | |
1230 loser: | |
1231 PZ_Unlock(mod->refLock); | |
1232 return rv; | |
1233 } | |
1234 | |
1235 /* | |
1236 * check to see if the module has removable slots that we may need to | |
1237 * watch for. | |
1238 */ | |
1239 PRBool | |
1240 SECMOD_HasRemovableSlots(SECMODModule *mod) | |
1241 { | |
1242 int i; | |
1243 PRBool ret = PR_FALSE; | |
1244 | |
1245 if (!moduleLock) { | |
1246 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1247 return ret; | |
1248 } | |
1249 SECMOD_GetReadLock(moduleLock); | |
1250 for (i=0; i < mod->slotCount; i++) { | |
1251 PK11SlotInfo *slot = mod->slots[i]; | |
1252 /* perm modules are not inserted or removed */ | |
1253 if (slot->isPerm) { | |
1254 continue; | |
1255 } | |
1256 ret = PR_TRUE; | |
1257 break; | |
1258 } | |
1259 if (mod->slotCount == 0 ) { | |
1260 ret = PR_TRUE; | |
1261 } | |
1262 SECMOD_ReleaseReadLock(moduleLock); | |
1263 return ret; | |
1264 } | |
1265 | |
1266 /* | |
1267 * helper function to actually create and destroy user defined slots | |
1268 */ | |
1269 static SECStatus | |
1270 secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass, | |
1271 const char *sendSpec) | |
1272 { | |
1273 CK_OBJECT_HANDLE dummy; | |
1274 CK_ATTRIBUTE template[2] ; | |
1275 CK_ATTRIBUTE *attrs = template; | |
1276 CK_RV crv; | |
1277 | |
1278 PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; | |
1279 PK11_SETATTRS(attrs, CKA_NETSCAPE_MODULE_SPEC , (unsigned char *)sendSpec, | |
1280 strlen(sendSpec)+1); attrs++; | |
1281 | |
1282 PORT_Assert(attrs-template <= 2); | |
1283 | |
1284 | |
1285 PK11_EnterSlotMonitor(slot); | |
1286 crv = PK11_CreateNewObject(slot, slot->session, | |
1287 template, attrs-template, PR_FALSE, &dummy); | |
1288 PK11_ExitSlotMonitor(slot); | |
1289 | |
1290 if (crv != CKR_OK) { | |
1291 PORT_SetError(PK11_MapError(crv)); | |
1292 return SECFailure; | |
1293 } | |
1294 return SECMOD_UpdateSlotList(slot->module); | |
1295 } | |
1296 | |
1297 /* | |
1298 * return true if the selected slot ID is not present or doesn't exist | |
1299 */ | |
1300 static PRBool | |
1301 secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID) | |
1302 { | |
1303 PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID); | |
1304 if (slot) { | |
1305 PRBool present = PK11_IsPresent(slot); | |
1306 PK11_FreeSlot(slot); | |
1307 if (present) { | |
1308 return PR_FALSE; | |
1309 } | |
1310 } | |
1311 /* it doesn't exist or isn't present, it's available */ | |
1312 return PR_TRUE; | |
1313 } | |
1314 | |
1315 /* | |
1316 * Find an unused slot id in module. | |
1317 */ | |
1318 static CK_SLOT_ID | |
1319 secmod_FindFreeSlot(SECMODModule *mod) | |
1320 { | |
1321 CK_SLOT_ID i, minSlotID, maxSlotID; | |
1322 | |
1323 /* look for a free slot id on the internal module */ | |
1324 if (mod->internal && mod->isFIPS) { | |
1325 minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID; | |
1326 maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID; | |
1327 } else { | |
1328 minSlotID = SFTK_MIN_USER_SLOT_ID; | |
1329 maxSlotID = SFTK_MAX_USER_SLOT_ID; | |
1330 } | |
1331 for (i=minSlotID; i < maxSlotID; i++) { | |
1332 if (secmod_SlotIsEmpty(mod,i)) { | |
1333 return i; | |
1334 } | |
1335 } | |
1336 PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED); | |
1337 return (CK_SLOT_ID) -1; | |
1338 } | |
1339 | |
1340 /* | |
1341 * Attempt to open a new slot. | |
1342 * | |
1343 * This works the same os OpenUserDB except it can be called against | |
1344 * any module that understands the softoken protocol for opening new | |
1345 * slots, not just the softoken itself. If the selected module does not | |
1346 * understand the protocol, C_CreateObject will fail with | |
1347 * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set | |
1348 * SEC_ERROR_BAD_DATA. | |
1349 * | |
1350 * NewSlots can be closed with SECMOD_CloseUserDB(); | |
1351 * | |
1352 * Modulespec is module dependent. | |
1353 */ | |
1354 PK11SlotInfo * | |
1355 SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec) | |
1356 { | |
1357 CK_SLOT_ID slotID = 0; | |
1358 PK11SlotInfo *slot; | |
1359 char *escSpec; | |
1360 char *sendSpec; | |
1361 SECStatus rv; | |
1362 | |
1363 slotID = secmod_FindFreeSlot(mod); | |
1364 if (slotID == (CK_SLOT_ID) -1) { | |
1365 return NULL; | |
1366 } | |
1367 | |
1368 if (mod->slotCount == 0) { | |
1369 return NULL; | |
1370 } | |
1371 | |
1372 /* just grab the first slot in the module, any present slot should work */ | |
1373 slot = PK11_ReferenceSlot(mod->slots[0]); | |
1374 if (slot == NULL) { | |
1375 return NULL; | |
1376 } | |
1377 | |
1378 /* we've found the slot, now build the moduleSpec */ | |
1379 escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']'); | |
1380 if (escSpec == NULL) { | |
1381 PK11_FreeSlot(slot); | |
1382 return NULL; | |
1383 } | |
1384 sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec); | |
1385 PORT_Free(escSpec); | |
1386 | |
1387 if (sendSpec == NULL) { | |
1388 /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */ | |
1389 PK11_FreeSlot(slot); | |
1390 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
1391 return NULL; | |
1392 } | |
1393 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_NEWSLOT, sendSpec); | |
1394 PR_smprintf_free(sendSpec); | |
1395 PK11_FreeSlot(slot); | |
1396 if (rv != SECSuccess) { | |
1397 return NULL; | |
1398 } | |
1399 | |
1400 slot = SECMOD_FindSlotByID(mod, slotID); | |
1401 if (slot) { | |
1402 /* if we are in the delay period for the "isPresent" call, reset | |
1403 * the delay since we know things have probably changed... */ | |
1404 if (slot->nssToken && slot->nssToken->slot) { | |
1405 nssSlot_ResetDelay(slot->nssToken->slot); | |
1406 } | |
1407 /* force the slot info structures to properly reset */ | |
1408 (void)PK11_IsPresent(slot); | |
1409 } | |
1410 return slot; | |
1411 } | |
1412 | |
1413 /* | |
1414 * Open a new database using the softoken. The caller is responsible for making | |
1415 * sure the module spec is correct and usable. The caller should ask for one | |
1416 * new database per call if the caller wants to get meaningful information | |
1417 * about the new database. | |
1418 * | |
1419 * moduleSpec is the same data that you would pass to softoken at | |
1420 * initialization time under the 'tokens' options. For example, if you were | |
1421 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']> | |
1422 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your | |
1423 * module spec here. The slot ID will be calculated for you by | |
1424 * SECMOD_OpenUserDB(). | |
1425 * | |
1426 * Typical parameters here are configdir, tokenDescription and flags. | |
1427 * | |
1428 * a Full list is below: | |
1429 * | |
1430 * | |
1431 * configDir - The location of the databases for this token. If configDir is | |
1432 * not specified, and noCertDB and noKeyDB is not specified, the load | |
1433 * will fail. | |
1434 * certPrefix - Cert prefix for this token. | |
1435 * keyPrefix - Prefix for the key database for this token. (if not specified, | |
1436 * certPrefix will be used). | |
1437 * tokenDescription - The label value for this token returned in the | |
1438 * CK_TOKEN_INFO structure with an internationalize string (UTF8). | |
1439 * This value will be truncated at 32 bytes (no NULL, partial UTF8 | |
1440 * characters dropped). You should specify a user friendly name here | |
1441 * as this is the value the token will be referred to in most | |
1442 * application UI's. You should make sure tokenDescription is unique. | |
1443 * slotDescription - The slotDescription value for this token returned | |
1444 * in the CK_SLOT_INFO structure with an internationalize string | |
1445 * (UTF8). This value will be truncated at 64 bytes (no NULL, partial | |
1446 * UTF8 characters dropped). This name will not change after the | |
1447 * database is closed. It should have some number to make this unique. | |
1448 * minPWLen - minimum password length for this token. | |
1449 * flags - comma separated list of flag values, parsed case-insensitive. | |
1450 * Valid flags are: | |
1451 * readOnly - Databases should be opened read only. | |
1452 * noCertDB - Don't try to open a certificate database. | |
1453 * noKeyDB - Don't try to open a key database. | |
1454 * forceOpen - Don't fail to initialize the token if the | |
1455 * databases could not be opened. | |
1456 * passwordRequired - zero length passwords are not acceptable | |
1457 * (valid only if there is a keyDB). | |
1458 * optimizeSpace - allocate smaller hash tables and lock tables. | |
1459 * When this flag is not specified, Softoken will allocate | |
1460 * large tables to prevent lock contention. | |
1461 */ | |
1462 PK11SlotInfo * | |
1463 SECMOD_OpenUserDB(const char *moduleSpec) | |
1464 { | |
1465 SECMODModule *mod; | |
1466 | |
1467 if (moduleSpec == NULL) { | |
1468 return NULL; | |
1469 } | |
1470 | |
1471 /* NOTE: unlike most PK11 function, this does not return a reference | |
1472 * to the module */ | |
1473 mod = SECMOD_GetInternalModule(); | |
1474 if (!mod) { | |
1475 /* shouldn't happen */ | |
1476 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
1477 return NULL; | |
1478 } | |
1479 return SECMOD_OpenNewSlot(mod, moduleSpec); | |
1480 } | |
1481 | |
1482 | |
1483 /* | |
1484 * close an already opened user database. NOTE: the database must be | |
1485 * in the internal token, and must be one created with SECMOD_OpenUserDB(). | |
1486 * Once the database is closed, the slot will remain as an empty slot | |
1487 * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot(). | |
1488 */ | |
1489 SECStatus | |
1490 SECMOD_CloseUserDB(PK11SlotInfo *slot) | |
1491 { | |
1492 SECStatus rv; | |
1493 char *sendSpec; | |
1494 | |
1495 sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID); | |
1496 if (sendSpec == NULL) { | |
1497 /* PR_smprintf does not set no memory error */ | |
1498 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
1499 return SECFailure; | |
1500 } | |
1501 rv = secmod_UserDBOp(slot, CKO_NETSCAPE_DELSLOT, sendSpec); | |
1502 PR_smprintf_free(sendSpec); | |
1503 /* if we are in the delay period for the "isPresent" call, reset | |
1504 * the delay since we know things have probably changed... */ | |
1505 if (slot->nssToken && slot->nssToken->slot) { | |
1506 nssSlot_ResetDelay(slot->nssToken->slot); | |
1507 /* force the slot info structures to properly reset */ | |
1508 (void)PK11_IsPresent(slot); | |
1509 } | |
1510 return rv; | |
1511 } | |
1512 | |
1513 /* | |
1514 * Restart PKCS #11 modules after a fork(). See secmod.h for more information. | |
1515 */ | |
1516 SECStatus | |
1517 SECMOD_RestartModules(PRBool force) | |
1518 { | |
1519 SECMODModuleList *mlp; | |
1520 SECStatus rrv = SECSuccess; | |
1521 int lastError = 0; | |
1522 | |
1523 if (!moduleLock) { | |
1524 PORT_SetError(SEC_ERROR_NOT_INITIALIZED); | |
1525 return SECFailure; | |
1526 } | |
1527 | |
1528 /* Only need to restart the PKCS #11 modules that were initialized */ | |
1529 SECMOD_GetReadLock(moduleLock); | |
1530 for (mlp = modules; mlp != NULL; mlp = mlp->next) { | |
1531 SECMODModule *mod = mlp->module; | |
1532 CK_ULONG count; | |
1533 SECStatus rv; | |
1534 int i; | |
1535 | |
1536 /* If the module needs to be reset, do so */ | |
1537 if (force || (PK11_GETTAB(mod)-> | |
1538 C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) { | |
1539 PRBool alreadyLoaded; | |
1540 /* first call Finalize. This is not required by PKCS #11, but some | |
1541 * older modules require it, and it doesn't hurt (compliant modules | |
1542 * will return CKR_NOT_INITIALIZED */ | |
1543 (void) PK11_GETTAB(mod)->C_Finalize(NULL); | |
1544 /* now initialize the module, this function reinitializes | |
1545 * a module in place, preserving existing slots (even if they | |
1546 * no longer exist) */ | |
1547 rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded); | |
1548 if (rv != SECSuccess) { | |
1549 /* save the last error code */ | |
1550 lastError = PORT_GetError(); | |
1551 rrv = rv; | |
1552 /* couldn't reinit the module, disable all its slots */ | |
1553 for (i=0; i < mod->slotCount; i++) { | |
1554 mod->slots[i]->disabled = PR_TRUE; | |
1555 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
1556 } | |
1557 continue; | |
1558 } | |
1559 for (i=0; i < mod->slotCount; i++) { | |
1560 /* get new token sessions, bump the series up so that | |
1561 * we refresh other old sessions. This will tell much of | |
1562 * NSS to flush cached handles it may hold as well */ | |
1563 rv = PK11_InitToken(mod->slots[i],PR_TRUE); | |
1564 /* PK11_InitToken could fail if the slot isn't present. | |
1565 * If it is present, though, something is wrong and we should | |
1566 * disable the slot and let the caller know. */ | |
1567 if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) { | |
1568 /* save the last error code */ | |
1569 lastError = PORT_GetError(); | |
1570 rrv = rv; | |
1571 /* disable the token */ | |
1572 mod->slots[i]->disabled = PR_TRUE; | |
1573 mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN; | |
1574 } | |
1575 } | |
1576 } | |
1577 } | |
1578 SECMOD_ReleaseReadLock(moduleLock); | |
1579 | |
1580 /* | |
1581 * on multiple failures, we are only returning the lastError. The caller | |
1582 * can determine which slots are bad by calling PK11_IsDisabled(). | |
1583 */ | |
1584 if (rrv != SECSuccess) { | |
1585 /* restore the last error code */ | |
1586 PORT_SetError(lastError); | |
1587 } | |
1588 | |
1589 return rrv; | |
1590 } | |
OLD | NEW |