Back to index

lightning-sunbird  0.9+nobinonly
devmod.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 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: devmod.c,v $ $Revision: 1.7 $ $Date: 2005/01/20 02:25:47 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef NSSCKEPV_H
00042 #include "nssckepv.h"
00043 #endif /* NSSCKEPV_H */
00044 
00045 #ifndef DEVM_H
00046 #include "devm.h"
00047 #endif /* DEVM_H */
00048 
00049 #ifndef CKHELPER_H
00050 #include "ckhelper.h"
00051 #endif /* CKHELPER_H */
00052 
00053 #ifdef PURE_STAN_CODE
00054 
00055 extern void FC_GetFunctionList(void);
00056 extern void NSC_GetFunctionList(void);
00057 extern void NSC_ModuleDBFunc(void);
00058 
00059 /* The list of boolean flags used to describe properties of a
00060  * module.
00061  */
00062 #define NSSMODULE_FLAGS_NOT_THREADSAFE 0x0001 /* isThreadSafe */
00063 #define NSSMODULE_FLAGS_INTERNAL       0x0002 /* isInternal   */
00064 #define NSSMODULE_FLAGS_FIPS           0x0004 /* isFIPS       */
00065 #define NSSMODULE_FLAGS_MODULE_DB      0x0008 /* isModuleDB   */
00066 #define NSSMODULE_FLAGS_MODULE_DB_ONLY 0x0010 /* moduleDBOnly */
00067 #define NSSMODULE_FLAGS_CRITICAL       0x0020 /* isCritical   */
00068 
00069 struct NSSModuleStr {
00070   struct nssDeviceBaseStr base;
00071   NSSUTF8 *libraryName;
00072   PRLibrary *library;
00073   char *libraryParams;
00074   void *moduleDBFunc;
00075   void *epv;
00076   CK_INFO info;
00077   NSSSlot **slots;
00078   PRUint32 numSlots;
00079   PRBool isLoaded;
00080   struct {
00081     PRInt32 trust;
00082     PRInt32 cipher;
00083     PRInt32 certStorage;
00084   } order;
00085 };
00086 
00087 #define NSSMODULE_IS_THREADSAFE(module) \
00088     (!(module->base.flags & NSSMODULE_FLAGS_NOT_THREADSAFE))
00089 
00090 #define NSSMODULE_IS_INTERNAL(module) \
00091     (module->base.flags & NSSMODULE_FLAGS_INTERNAL)
00092 
00093 #define NSSMODULE_IS_FIPS(module) \
00094     (module->base.flags & NSSMODULE_FLAGS_FIPS)
00095 
00096 #define NSSMODULE_IS_MODULE_DB(module) \
00097     (module->base.flags & NSSMODULE_FLAGS_MODULE_DB)
00098 
00099 #define NSSMODULE_IS_MODULE_DB_ONLY(module) \
00100     (module->base.flags & NSSMODULE_FLAGS_MODULE_DB_ONLY)
00101 
00102 #define NSSMODULE_IS_CRITICAL(module) \
00103     (module->base.flags & NSSMODULE_FLAGS_CRITICAL)
00104 
00105 /* Threading callbacks for C_Initialize.  Use NSPR threads. */
00106 
00107 CK_RV PR_CALLBACK 
00108 nss_ck_CreateMutex(CK_VOID_PTR_PTR pMutex)
00109 {
00110     CK_VOID_PTR mutex = (CK_VOID_PTR)PZ_NewLock(nssILockOther);
00111     if (mutex != NULL) {
00112        *pMutex = (CK_VOID_PTR)mutex;
00113        return CKR_OK;
00114     }
00115     return CKR_HOST_MEMORY;
00116 }
00117 
00118 CK_RV PR_CALLBACK
00119 nss_ck_DestroyMutex(CK_VOID_PTR mutex)
00120 {
00121     PZ_DestroyLock((PZLock *)mutex);
00122     return CKR_OK;
00123 }
00124 
00125 CK_RV PR_CALLBACK
00126 nss_ck_LockMutex(CK_VOID_PTR mutex)
00127 {
00128     PZ_Lock((PZLock *)mutex);
00129     return CKR_OK;
00130 }
00131 
00132 CK_RV PR_CALLBACK
00133 nss_ck_UnlockMutex(CK_VOID_PTR mutex)
00134 {
00135     return (PZ_Unlock((PZLock *)mutex) == PR_SUCCESS) ? 
00136        CKR_OK : CKR_MUTEX_NOT_LOCKED;
00137 }
00138 
00139 /* Default callback args to C_Initialize */
00140 /* XXX not const because we are modifying the pReserved argument in order
00141  *     to use the libraryParams extension.
00142  */
00143 static CK_C_INITIALIZE_ARGS 
00144 s_ck_initialize_args = {
00145     nss_ck_CreateMutex,         /* CreateMutex  */
00146     nss_ck_DestroyMutex,        /* DestroyMutex */
00147     nss_ck_LockMutex,           /* LockMutex    */
00148     nss_ck_UnlockMutex,         /* UnlockMutex  */
00149     CKF_LIBRARY_CANT_CREATE_OS_THREADS |
00150     CKF_OS_LOCKING_OK,          /* flags        */
00151     NULL                        /* pReserved    */
00152 };
00153 
00154 /* load all slots in a module. */
00155 static PRStatus
00156 module_load_slots(NSSModule *mod)
00157 {
00158     CK_ULONG i, ulNumSlots;
00159     CK_SLOT_ID *slotIDs;
00160     nssArenaMark *mark = NULL;
00161     NSSSlot **slots;
00162     PRStatus nssrv;
00163     CK_RV ckrv;
00164     /* Get the number of slots */
00165     ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, NULL, &ulNumSlots);
00166     if (ckrv != CKR_OK) {
00167        /* what is the error? */
00168        return PR_FAILURE;
00169     }
00170     /* Alloc memory for the array of slot ID's */
00171     slotIDs = nss_ZNEWARRAY(NULL, CK_SLOT_ID, ulNumSlots);
00172     if (!slotIDs) {
00173        goto loser;
00174     }
00175     /* Get the actual slot list */
00176     ckrv = CKAPI(mod->epv)->C_GetSlotList(CK_FALSE, slotIDs, &ulNumSlots);
00177     if (ckrv != CKR_OK) {
00178        /* what is the error? */
00179        goto loser;
00180     }
00181     /* Alloc memory for the array of slots, in the module's arena */
00182     mark = nssArena_Mark(mod->base.arena); /* why mark? it'll be destroyed */
00183     if (!mark) {
00184        return PR_FAILURE;
00185     }
00186     slots = nss_ZNEWARRAY(mod->base.arena, NSSSlot *, ulNumSlots);
00187     if (!slots) {
00188        goto loser;
00189     }
00190     /* Initialize each slot */
00191     for (i=0; i<ulNumSlots; i++) {
00192        slots[i] = nssSlot_Create(slotIDs[i], mod);
00193     }
00194     nss_ZFreeIf(slotIDs);
00195     nssrv = nssArena_Unmark(mod->base.arena, mark);
00196     if (nssrv != PR_SUCCESS) {
00197        goto loser;
00198     }
00199     mod->slots = slots;
00200     mod->numSlots = ulNumSlots;
00201     return PR_SUCCESS;
00202 loser:
00203     if (mark) {
00204        nssArena_Release(mod->base.arena, mark);
00205     }
00206     nss_ZFreeIf(slotIDs);
00207     return PR_FAILURE;
00208 }
00209 
00210 NSS_IMPLEMENT PRStatus
00211 nssModule_Load (
00212   NSSModule *mod
00213 )
00214 {
00215     PRLibrary *library = NULL;
00216     CK_C_GetFunctionList epv;
00217     CK_RV ckrv;
00218     if (NSSMODULE_IS_INTERNAL(mod)) {
00219        /* internal, statically get the C_GetFunctionList function */
00220        if (NSSMODULE_IS_FIPS(mod)) {
00221            epv = (CK_C_GetFunctionList) FC_GetFunctionList;
00222        } else {
00223            epv = (CK_C_GetFunctionList) NSC_GetFunctionList;
00224        }
00225        if (NSSMODULE_IS_MODULE_DB(mod)) {
00226            mod->moduleDBFunc = (void *) NSC_ModuleDBFunc;
00227        }
00228        if (NSSMODULE_IS_MODULE_DB_ONLY(mod)) {
00229            mod->isLoaded = PR_TRUE; /* XXX needed? */
00230            return PR_SUCCESS;
00231        }
00232     } else {
00233        /* Use NSPR to load the library */
00234        library = PR_LoadLibrary(mod->libraryName);
00235        if (!library) {
00236            /* what's the error to set? */
00237            return PR_FAILURE;
00238        }
00239        mod->library = library;
00240        /* Skip if only getting the db loader function */
00241        if (!NSSMODULE_IS_MODULE_DB_ONLY(mod)) {
00242            /* Load the cryptoki entry point function */
00243            epv = (CK_C_GetFunctionList)PR_FindSymbol(library, 
00244                                                      "C_GetFunctionList");
00245        }
00246        /* Load the module database loader function */
00247        if (NSSMODULE_IS_MODULE_DB(mod)) {
00248            mod->moduleDBFunc = (void *)PR_FindSymbol(library, 
00249                                                  "NSS_ReturnModuleSpecData");
00250        }
00251     }
00252     if (epv == NULL) {
00253        goto loser;
00254     }
00255     /* Load the cryptoki entry point vector (function list) */
00256     ckrv = (*epv)((CK_FUNCTION_LIST_PTR *)&mod->epv);
00257     if (ckrv != CKR_OK) {
00258        goto loser;
00259     }
00260     /* Initialize the module */
00261     if (mod->libraryParams) {
00262        s_ck_initialize_args.LibraryParameters = (void *)mod->libraryParams;
00263     } else {
00264        s_ck_initialize_args.LibraryParameters = NULL;
00265     }
00266     ckrv = CKAPI(mod->epv)->C_Initialize(&s_ck_initialize_args);
00267     if (ckrv != CKR_OK) {
00268        /* Apparently the token is not thread safe.  Retry without 
00269         * threading parameters. 
00270         */
00271         mod->base.flags |= NSSMODULE_FLAGS_NOT_THREADSAFE;
00272        ckrv = CKAPI(mod->epv)->C_Initialize((CK_VOID_PTR)NULL);
00273        if (ckrv != CKR_OK) {
00274            goto loser;
00275        }
00276     }
00277     /* TODO: check the version # using C_GetInfo */
00278     ckrv = CKAPI(mod->epv)->C_GetInfo(&mod->info);
00279     if (ckrv != CKR_OK) {
00280        goto loser;
00281     }
00282     /* TODO: if the name is not set, get it from info.libraryDescription */
00283     /* Now load the slots */
00284     if (module_load_slots(mod) != PR_SUCCESS) {
00285        goto loser;
00286     }
00287     /* Module has successfully loaded */
00288     mod->isLoaded = PR_TRUE;
00289     return PR_SUCCESS;
00290 loser:
00291     if (library) {
00292        PR_UnloadLibrary(library);
00293     }
00294     /* clear all values set above, they are invalid now */
00295     mod->library = NULL;
00296     mod->epv = NULL;
00297     return PR_FAILURE;
00298 }
00299 
00300 NSS_IMPLEMENT PRStatus
00301 nssModule_Unload (
00302   NSSModule *mod
00303 )
00304 {
00305     PRStatus nssrv = PR_SUCCESS;
00306     if (mod->library) {
00307        (void)CKAPI(mod->epv)->C_Finalize(NULL);
00308        nssrv = PR_UnloadLibrary(mod->library);
00309     }
00310     /* Free the slots, yes? */
00311     mod->library = NULL;
00312     mod->epv = NULL;
00313     mod->isLoaded = PR_FALSE;
00314     return nssrv;
00315 }
00316 
00317 /* Alloc memory for a module.  Copy in the module name and library path
00318  *  if provided.  XXX use the opaque arg also, right? 
00319  */
00320 NSS_IMPLEMENT NSSModule *
00321 nssModule_Create (
00322   NSSUTF8 *moduleOpt,
00323   NSSUTF8 *uriOpt,
00324   NSSUTF8 *opaqueOpt,
00325   void    *reserved
00326 )
00327 {
00328     NSSArena *arena;
00329     NSSModule *rvMod;
00330     arena = NSSArena_Create();
00331     if(!arena) {
00332        return (NSSModule *)NULL;
00333     }
00334     rvMod = nss_ZNEW(arena, NSSModule);
00335     if (!rvMod) {
00336        goto loser;
00337     }
00338     if (moduleOpt) {
00339        /* XXX making the gross assumption this is just the module name */
00340        /* if the name is a duplicate, should that be tested here?  or
00341         *  wait for Load? 
00342         */
00343        rvMod->base.name = nssUTF8_Duplicate(moduleOpt, arena);
00344        if (!rvMod->base.name) {
00345            goto loser;
00346        }
00347     }
00348     if (uriOpt) {
00349        /* Load the module from a URI. */
00350        /* XXX at this time - only file URI (even worse, no file:// for now) */
00351        rvMod->libraryName = nssUTF8_Duplicate(uriOpt, arena);
00352        if (!rvMod->libraryName) {
00353            goto loser;
00354        }
00355     }
00356     rvMod->base.arena = arena;
00357     rvMod->base.refCount = 1;
00358     rvMod->base.lock = PZ_NewLock(nssNSSILockOther);
00359     if (!rvMod->base.lock) {
00360        goto loser;
00361     }
00362     /* everything else is 0/NULL at this point. */
00363     return rvMod;
00364 loser:
00365     nssArena_Destroy(arena);
00366     return (NSSModule *)NULL;
00367 }
00368 
00369 NSS_EXTERN PRStatus
00370 nssCryptokiArgs_ParseNextPair (
00371   NSSUTF8 *start,
00372   NSSUTF8 **attrib,
00373   NSSUTF8 **value,
00374   NSSUTF8 **remainder,
00375   NSSArena *arenaOpt
00376 );
00377 
00378 static PRStatus
00379 parse_slot_flags (
00380   NSSSlot *slot,
00381   NSSUTF8 *slotFlags
00382 )
00383 {
00384     PRStatus nssrv = PR_SUCCESS;
00385 #if 0
00386     PRBool done = PR_FALSE;
00387     NSSUTF8 *mark, *last;
00388     last = mark = slotFlags;
00389     while (PR_TRUE) {
00390        while (*mark && *mark != ',') ++mark;
00391        if (!*mark) done = PR_TRUE;
00392        *mark = '\0';
00393        if (nssUTF8_Equal(last, "RANDOM", &nssrv)) {
00394            slot->base.flags |= NSSSLOT_FLAGS_HAS_RANDOM;
00395        } else if (nssUTF8_Equal(last, "RSA", &nssrv)) {
00396            slot->base.flags |= NSSSLOT_FLAGS_RSA;
00397        } else if (nssUTF8_Equal(last, "DSA", &nssrv)) {
00398            slot->base.flags |= NSSSLOT_FLAGS_DSA;
00399        } else if (nssUTF8_Equal(last, "DH", &nssrv)) {
00400            slot->base.flags |= NSSSLOT_FLAGS_DH;
00401        } else if (nssUTF8_Equal(last, "RC2", &nssrv)) {
00402            slot->base.flags |= NSSSLOT_FLAGS_RC2;
00403        } else if (nssUTF8_Equal(last, "RC4", &nssrv)) {
00404            slot->base.flags |= NSSSLOT_FLAGS_RC4;
00405        } else if (nssUTF8_Equal(last, "RC5", &nssrv)) {
00406            slot->base.flags |= NSSSLOT_FLAGS_RC5;
00407        } else if (nssUTF8_Equal(last, "DES", &nssrv)) {
00408            slot->base.flags |= NSSSLOT_FLAGS_DES;
00409        } else if (nssUTF8_Equal(last, "AES", &nssrv)) {
00410            slot->base.flags |= NSSSLOT_FLAGS_AES;
00411        } else if (nssUTF8_Equal(last, "SHA1", &nssrv)) {
00412            slot->base.flags |= NSSSLOT_FLAGS_SHA1;
00413        } else if (nssUTF8_Equal(last, "MD2", &nssrv)) {
00414            slot->base.flags |= NSSSLOT_FLAGS_MD2;
00415        } else if (nssUTF8_Equal(last, "MD5", &nssrv)) {
00416            slot->base.flags |= NSSSLOT_FLAGS_MD5;
00417        } else if (nssUTF8_Equal(last, "SSL", &nssrv)) {
00418            slot->base.flags |= NSSSLOT_FLAGS_SSL;
00419        } else if (nssUTF8_Equal(last, "TLS", &nssrv)) {
00420            slot->base.flags |= NSSSLOT_FLAGS_TLS;
00421        } else if (nssUTF8_Equal(last, "PublicCerts", &nssrv)) {
00422            slot->base.flags |= NSSSLOT_FLAGS_FRIENDLY;
00423        } else {
00424            return PR_FAILURE;
00425        }
00426        if (done) break;
00427        last = ++mark;
00428     }
00429 #endif
00430     return nssrv;
00431 }
00432 
00433 static PRStatus
00434 parse_slot_parameters (
00435   NSSSlot *slot,
00436   NSSUTF8 *slotParams,
00437   NSSArena *tmparena
00438 )
00439 {
00440     PRStatus nssrv = PR_SUCCESS;
00441     NSSUTF8 *current, *remainder;
00442     NSSUTF8 *attrib, *value;
00443     current = slotParams;
00444     while (nssrv == PR_SUCCESS) {
00445        nssrv = nssCryptokiArgs_ParseNextPair(current, 
00446                                              &attrib, &value, 
00447                                              &remainder, tmparena);
00448        if (nssrv != PR_SUCCESS) break;
00449        if (value) {
00450            if (nssUTF8_Equal(attrib, "slotFlags", &nssrv)) {
00451               nssrv = parse_slot_flags(slot, value);
00452            } else if (nssUTF8_Equal(attrib, "askpw", &nssrv)) {
00453            } else if (nssUTF8_Equal(attrib, "timeout", &nssrv)) {
00454            }
00455        }
00456        if (*remainder == '\0') break;
00457        current = remainder;
00458     }
00459     return nssrv;
00460 }
00461 
00462 /* softoken seems to use "0x0000001", but no standard yet...  perhaps this
00463  * should store the number as an ID, in case the input isn't 1,2,3,...?
00464  */
00465 static PRIntn
00466 get_slot_number(NSSUTF8* snString)
00467 {
00468     /* XXX super big hack */
00469     return atoi(&snString[strlen(snString)-1]);
00470 }
00471 
00472 static PRStatus
00473 parse_module_slot_parameters (
00474   NSSModule *mod,
00475   NSSUTF8 *slotParams
00476 )
00477 {
00478     PRStatus nssrv = PR_SUCCESS;
00479     NSSUTF8 *current, *remainder;
00480     NSSUTF8 *attrib, *value;
00481     NSSArena *tmparena;
00482     PRIntn slotNum;
00483     tmparena = nssArena_Create();
00484     if (!tmparena) {
00485        return PR_FAILURE;
00486     }
00487     current = slotParams;
00488     while (nssrv == PR_SUCCESS) {
00489        nssrv = nssCryptokiArgs_ParseNextPair(current, 
00490                                              &attrib, &value, 
00491                                              &remainder, tmparena);
00492        if (nssrv != PR_SUCCESS) break;
00493        if (value) {
00494            slotNum = get_slot_number(attrib);
00495            if (slotNum < 0 || slotNum > mod->numSlots) {
00496               return PR_FAILURE;
00497            }
00498            nssrv = parse_slot_parameters(mod->slots[slotNum], 
00499                                          value, tmparena);
00500            if (nssrv != PR_SUCCESS) break;
00501        }
00502        if (*remainder == '\0') break;
00503        current = remainder;
00504     }
00505     return nssrv;
00506 }
00507 
00508 static PRStatus
00509 parse_nss_flags (
00510   NSSModule *mod,
00511   NSSUTF8 *nssFlags
00512 )
00513 {
00514     PRStatus nssrv = PR_SUCCESS;
00515     PRBool done = PR_FALSE;
00516     NSSUTF8 *mark, *last;
00517     last = mark = nssFlags;
00518     while (PR_TRUE) {
00519        while (*mark && *mark != ',') ++mark;
00520        if (!*mark) done = PR_TRUE;
00521        *mark = '\0';
00522        if (nssUTF8_Equal(last, "internal", &nssrv)) {
00523            mod->base.flags |= NSSMODULE_FLAGS_INTERNAL;
00524        } else if (nssUTF8_Equal(last, "moduleDB", &nssrv)) {
00525            mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB;
00526        } else if (nssUTF8_Equal(last, "moduleDBOnly", &nssrv)) {
00527            mod->base.flags |= NSSMODULE_FLAGS_MODULE_DB_ONLY;
00528        } else if (nssUTF8_Equal(last, "critical", &nssrv)) {
00529            mod->base.flags |= NSSMODULE_FLAGS_CRITICAL;
00530        } else {
00531            return PR_FAILURE;
00532        }
00533        if (done) break;
00534        last = ++mark;
00535     }
00536     return nssrv;
00537 }
00538 
00539 static PRStatus
00540 parse_nss_parameters (
00541   NSSModule *mod,
00542   NSSUTF8 *nssParams,
00543   NSSArena *tmparena,
00544   NSSUTF8 **slotParams
00545 )
00546 {
00547     PRStatus nssrv = PR_SUCCESS;
00548     NSSUTF8 *current, *remainder;
00549     NSSUTF8 *attrib, *value;
00550     current = nssParams;
00551     while (nssrv == PR_SUCCESS) {
00552        nssrv = nssCryptokiArgs_ParseNextPair(current, 
00553                                              &attrib, &value, 
00554                                              &remainder, tmparena);
00555        if (nssrv != PR_SUCCESS) break;
00556        if (value) {
00557            if (nssUTF8_Equal(attrib, "flags", &nssrv) ||
00558                nssUTF8_Equal(attrib, "Flags", &nssrv)) {
00559               nssrv = parse_nss_flags(mod, value);
00560            } else if (nssUTF8_Equal(attrib, "trustOrder", &nssrv)) {
00561               mod->order.trust = atoi(value);
00562            } else if (nssUTF8_Equal(attrib, "cipherOrder", &nssrv)) {
00563               mod->order.cipher = atoi(value);
00564            } else if (nssUTF8_Equal(attrib, "ciphers", &nssrv)) {
00565            } else if (nssUTF8_Equal(attrib, "slotParams", &nssrv)) {
00566               /* slotParams doesn't get an arena, it is handled separately */
00567               *slotParams = nssUTF8_Duplicate(value, NULL);
00568            }
00569        }
00570        if (*remainder == '\0') break;
00571        current = remainder;
00572     }
00573     return nssrv;
00574 }
00575 
00576 static PRStatus
00577 parse_module_parameters (
00578   NSSModule *mod,
00579   NSSUTF8 *moduleParams,
00580   NSSUTF8 **slotParams
00581 )
00582 {
00583     PRStatus nssrv = PR_SUCCESS;
00584     NSSUTF8 *current, *remainder;
00585     NSSUTF8 *attrib, *value;
00586     NSSArena *arena = mod->base.arena;
00587     NSSArena *tmparena;
00588     current = moduleParams;
00589     tmparena = nssArena_Create();
00590     if (!tmparena) {
00591        return PR_FAILURE;
00592     }
00593     while (nssrv == PR_SUCCESS) {
00594        nssrv = nssCryptokiArgs_ParseNextPair(current, 
00595                                              &attrib, &value, 
00596                                              &remainder, tmparena);
00597        if (nssrv != PR_SUCCESS) break;
00598        if (value) {
00599            if (nssUTF8_Equal(attrib, "name", &nssrv)) {
00600               mod->base.name = nssUTF8_Duplicate(value, arena);
00601            } else if (nssUTF8_Equal(attrib, "library", &nssrv)) {
00602               mod->libraryName = nssUTF8_Duplicate(value, arena);
00603            } else if (nssUTF8_Equal(attrib, "parameters", &nssrv)) {
00604               mod->libraryParams = nssUTF8_Duplicate(value, arena);
00605            } else if (nssUTF8_Equal(attrib, "NSS", &nssrv)) {
00606               parse_nss_parameters(mod, value, tmparena, slotParams);
00607            }
00608        }
00609        if (*remainder == '\0') break;
00610        current = remainder;
00611     }
00612     nssArena_Destroy(tmparena);
00613     return nssrv;
00614 }
00615 
00616 static NSSUTF8 **
00617 get_module_specs (
00618   NSSModule *mod
00619 )
00620 {
00621     SECMODModuleDBFunc func = (SECMODModuleDBFunc)mod->moduleDBFunc;
00622     if (func) {
00623        return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
00624                       mod->libraryParams,
00625                       NULL);
00626     }
00627     return NULL;
00628 }
00629 
00630 /* XXX continue working on */
00631 NSS_IMPLEMENT NSSModule *
00632 nssModule_CreateFromSpec (
00633   NSSUTF8 *moduleSpec,
00634   NSSModule *parent,
00635   PRBool loadSubModules
00636 )
00637 {
00638     PRStatus nssrv;
00639     NSSModule *thisModule;
00640     NSSArena *arena;
00641     NSSUTF8 *slotParams = NULL;
00642     arena = nssArena_Create();
00643     if (!arena) {
00644        return NULL;
00645     }
00646     thisModule = nss_ZNEW(arena, NSSModule);
00647     if (!thisModule) {
00648        goto loser;
00649     }
00650     thisModule->base.lock = PZ_NewLock(nssILockOther);
00651     if (!thisModule->base.lock) {
00652        goto loser;
00653     }
00654     PR_AtomicIncrement(&thisModule->base.refCount);
00655     thisModule->base.arena = arena;
00656     thisModule->base.lock = PZ_NewLock(nssNSSILockOther);
00657     if (!thisModule->base.lock) {
00658        goto loser;
00659     }
00660     nssrv = parse_module_parameters(thisModule, moduleSpec, &slotParams);
00661     if (nssrv != PR_SUCCESS) {
00662        goto loser;
00663     }
00664     nssrv = nssModule_Load(thisModule);
00665     if (nssrv != PR_SUCCESS) {
00666        goto loser;
00667     }
00668     if (slotParams) {
00669        nssrv = parse_module_slot_parameters(thisModule, slotParams);
00670        nss_ZFreeIf(slotParams);
00671        if (nssrv != PR_SUCCESS) {
00672            goto loser;
00673        }
00674     }
00675     if (loadSubModules && NSSMODULE_IS_MODULE_DB(thisModule)) {
00676        NSSUTF8 **moduleSpecs;
00677        NSSUTF8 **index;
00678        /* get the array of sub modules one level below this module */
00679        moduleSpecs = get_module_specs(thisModule);
00680        /* iterate over the array */
00681        for (index = moduleSpecs; index && *index; index++) {
00682            NSSModule *child;
00683            /* load the child recursively */
00684            child = nssModule_CreateFromSpec(*index, thisModule, PR_TRUE);
00685            if (!child) {
00686               /* when children fail, does the parent? */
00687               nssrv = PR_FAILURE;
00688               break;
00689            }
00690            if (NSSMODULE_IS_CRITICAL(child) && !child->isLoaded) {
00691               nssrv = PR_FAILURE;
00692               nssModule_Destroy(child);
00693               break;
00694            }
00695            nssModule_Destroy(child);
00696            /*nss_ZFreeIf(*index);*/
00697        }
00698        /*nss_ZFreeIf(moduleSpecs);*/
00699     }
00700     /* The global list inherits the reference */
00701     nssrv = nssGlobalModuleList_Add(thisModule);
00702     if (nssrv != PR_SUCCESS) {
00703        goto loser;
00704     }
00705     return thisModule;
00706 loser:
00707     if (thisModule->base.lock) {
00708        PZ_DestroyLock(thisModule->base.lock);
00709     }
00710     nssArena_Destroy(arena);
00711     return (NSSModule *)NULL;
00712 }
00713 
00714 NSS_IMPLEMENT PRStatus
00715 nssModule_Destroy (
00716   NSSModule *mod
00717 )
00718 {
00719     PRUint32 i, numSlots;
00720     if (PR_AtomicDecrement(&mod->base.refCount) == 0) {
00721        if (mod->numSlots == 0) {
00722            (void)nssModule_Unload(mod);
00723            return nssArena_Destroy(mod->base.arena);
00724        } else {
00725            numSlots = mod->numSlots;
00726            for (i=0; i<numSlots; i++) {
00727               nssSlot_Destroy(mod->slots[i]);
00728            }
00729        }
00730     }
00731     return PR_SUCCESS;
00732 }
00733 
00734 NSS_IMPLEMENT PRStatus
00735 nssModule_DestroyFromSlot (
00736   NSSModule *mod,
00737   NSSSlot *slot
00738 )
00739 {
00740     PRUint32 i, numSlots = 0;
00741     PR_ASSERT(mod->base.refCount == 0);
00742     for (i=0; i<mod->numSlots; i++) {
00743        if (mod->slots[i] == slot) {
00744            mod->slots[i] = NULL;
00745        } else if (mod->slots[i]) {
00746            numSlots++;
00747        }
00748     }
00749     if (numSlots == 0) {
00750        (void)nssModule_Unload(mod);
00751        return nssArena_Destroy(mod->base.arena);
00752     }
00753     return PR_SUCCESS;
00754 }
00755 
00756 NSS_IMPLEMENT NSSModule *
00757 nssModule_AddRef (
00758   NSSModule *mod
00759 )
00760 {
00761     PR_AtomicIncrement(&mod->base.refCount);
00762     return mod;
00763 }
00764 
00765 NSS_IMPLEMENT NSSUTF8 *
00766 nssModule_GetName (
00767   NSSModule *mod
00768 )
00769 {
00770     return mod->base.name;
00771 }
00772 
00773 NSS_IMPLEMENT PRBool
00774 nssModule_IsThreadSafe (
00775   NSSModule *module
00776 )
00777 {
00778     return NSSMODULE_IS_THREADSAFE(module);
00779 }
00780 
00781 NSS_IMPLEMENT PRBool
00782 nssModule_IsInternal (
00783   NSSModule *mod
00784 )
00785 {
00786     return NSSMODULE_IS_INTERNAL(mod);
00787 }
00788 
00789 NSS_IMPLEMENT PRBool
00790 nssModule_IsModuleDBOnly (
00791   NSSModule *mod
00792 )
00793 {
00794     return NSSMODULE_IS_MODULE_DB_ONLY(mod);
00795 }
00796 
00797 NSS_IMPLEMENT void *
00798 nssModule_GetCryptokiEPV (
00799   NSSModule *mod
00800 )
00801 {
00802     return mod->epv;
00803 }
00804 
00805 NSS_IMPLEMENT NSSSlot **
00806 nssModule_GetSlots (
00807   NSSModule *mod
00808 )
00809 {
00810     PRUint32 i;
00811     NSSSlot **rvSlots;
00812     rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, mod->numSlots + 1);
00813     if (rvSlots) {
00814        for (i=0; i<mod->numSlots; i++) {
00815            rvSlots[i] = nssSlot_AddRef(mod->slots[i]);
00816        }
00817     }
00818     return rvSlots;
00819 }
00820 
00821 NSS_IMPLEMENT NSSSlot *
00822 nssModule_FindSlotByName (
00823   NSSModule *mod,
00824   NSSUTF8 *slotName
00825 )
00826 {
00827     PRUint32 i;
00828     PRStatus nssrv;
00829     NSSSlot *slot;
00830     NSSUTF8 *name;
00831     for (i=0; i<mod->numSlots; i++) {
00832        slot = mod->slots[i];
00833        name = nssSlot_GetName(slot);
00834        if (nssUTF8_Equal(name, slotName, &nssrv)) {
00835            return nssSlot_AddRef(slot);
00836        }
00837        if (nssrv != PR_SUCCESS) {
00838            break;
00839        }
00840     }
00841     return (NSSSlot *)NULL;
00842 }
00843 
00844 NSS_IMPLEMENT NSSToken *
00845 nssModule_FindTokenByName (
00846   NSSModule *mod,
00847   NSSUTF8 *tokenName
00848 )
00849 {
00850     PRUint32 i;
00851     PRStatus nssrv;
00852     NSSToken *tok;
00853     NSSUTF8 *name;
00854     for (i=0; i<mod->numSlots; i++) {
00855        tok = nssSlot_GetToken(mod->slots[i]);
00856        if (tok) {
00857            name = nssToken_GetName(tok);
00858            if (nssUTF8_Equal(name, tokenName, &nssrv)) {
00859               return tok;
00860            }
00861            if (nssrv != PR_SUCCESS) {
00862               break;
00863            }
00864        }
00865     }
00866     return (NSSToken *)NULL;
00867 }
00868 
00869 NSS_IMPLEMENT PRInt32
00870 nssModule_GetCertOrder (
00871   NSSModule *module
00872 )
00873 {
00874     return 1; /* XXX */
00875 }
00876 
00877 #endif /* PURE_STAN_BUILD */
00878