Back to index

lightning-sunbird  0.9+nobinonly
pk11db.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 /* 
00037  *  The following code handles the storage of PKCS 11 modules used by the
00038  * NSS. This file is written to abstract away how the modules are
00039  * stored so we can deside that later.
00040  */
00041 
00042 #include "pk11pars.h"
00043 #include "pkcs11i.h"
00044 #include "mcom_db.h"
00045 #include "cdbhdl.h"
00046 #include "secerr.h"
00047 
00048 #define FREE_CLEAR(p) if (p) { PORT_Free(p); p = NULL; }
00049 
00050 static void
00051 secmod_parseTokenFlags(char *tmp, sftk_token_parameters *parsed) { 
00052     parsed->readOnly = secmod_argHasFlag("flags","readOnly",tmp);
00053     parsed->noCertDB = secmod_argHasFlag("flags","noCertDB",tmp);
00054     parsed->noKeyDB = secmod_argHasFlag("flags","noKeyDB",tmp);
00055     parsed->forceOpen = secmod_argHasFlag("flags","forceOpen",tmp);
00056     parsed->pwRequired = secmod_argHasFlag("flags","passwordRequired",tmp);
00057     parsed->optimizeSpace = secmod_argHasFlag("flags","optimizeSpace",tmp);
00058     return;
00059 }
00060 
00061 static void
00062 secmod_parseFlags(char *tmp, sftk_parameters *parsed) { 
00063     parsed->noModDB = secmod_argHasFlag("flags","noModDB",tmp);
00064     parsed->readOnly = secmod_argHasFlag("flags","readOnly",tmp);
00065     /* keep legacy interface working */
00066     parsed->noCertDB = secmod_argHasFlag("flags","noCertDB",tmp);
00067     parsed->forceOpen = secmod_argHasFlag("flags","forceOpen",tmp);
00068     parsed->pwRequired = secmod_argHasFlag("flags","passwordRequired",tmp);
00069     parsed->optimizeSpace = secmod_argHasFlag("flags","optimizeSpace",tmp);
00070     return;
00071 }
00072 
00073 CK_RV
00074 secmod_parseTokenParameters(char *param, sftk_token_parameters *parsed) 
00075 {
00076     int next;
00077     char *tmp;
00078     char *index;
00079     index = secmod_argStrip(param);
00080 
00081     while (*index) {
00082        SECMOD_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
00083        SECMOD_HANDLE_STRING_ARG(index,parsed->certPrefix,"certPrefix=",;)
00084        SECMOD_HANDLE_STRING_ARG(index,parsed->keyPrefix,"keyPrefix=",;)
00085        SECMOD_HANDLE_STRING_ARG(index,parsed->tokdes,"tokenDescription=",;)
00086        SECMOD_HANDLE_STRING_ARG(index,parsed->slotdes,"slotDescription=",;)
00087        SECMOD_HANDLE_STRING_ARG(index,tmp,"minPWLen=", 
00088                      if(tmp) { parsed->minPW=atoi(tmp); PORT_Free(tmp); })
00089        SECMOD_HANDLE_STRING_ARG(index,tmp,"flags=", 
00090           if(tmp) { secmod_parseTokenFlags(param,parsed); PORT_Free(tmp); })
00091        SECMOD_HANDLE_FINAL_ARG(index)
00092    }
00093    return CKR_OK;
00094 }
00095 
00096 static void
00097 secmod_parseTokens(char *tokenParams, sftk_parameters *parsed)
00098 {
00099     char *tokenIndex;
00100     sftk_token_parameters *tokens = NULL;
00101     int i=0,count = 0,next;
00102 
00103     if ((tokenParams == NULL) || (*tokenParams == 0))  return;
00104 
00105     /* first count the number of slots */
00106     for (tokenIndex = secmod_argStrip(tokenParams); *tokenIndex;
00107         tokenIndex = secmod_argStrip(secmod_argSkipParameter(tokenIndex))) {
00108        count++;
00109     }
00110 
00111     /* get the data structures */
00112     tokens = (sftk_token_parameters *) 
00113                      PORT_ZAlloc(count*sizeof(sftk_token_parameters));
00114     if (tokens == NULL) return;
00115 
00116     for (tokenIndex = secmod_argStrip(tokenParams), i = 0;
00117                                    *tokenIndex && i < count ; i++ ) {
00118        char *name;
00119        name = secmod_argGetName(tokenIndex,&next);
00120        tokenIndex += next;
00121 
00122        tokens[i].slotID = secmod_argDecodeNumber(name);
00123         tokens[i].readOnly = PR_FALSE;
00124        tokens[i].noCertDB = PR_FALSE;
00125        tokens[i].noKeyDB = PR_FALSE;
00126        if (!secmod_argIsBlank(*tokenIndex)) {
00127            char *args = secmod_argFetchValue(tokenIndex,&next);
00128            tokenIndex += next;
00129            if (args) {
00130               secmod_parseTokenParameters(args,&tokens[i]);
00131               PORT_Free(args);
00132            }
00133        }
00134        if (name) PORT_Free(name);
00135        tokenIndex = secmod_argStrip(tokenIndex);
00136     }
00137     parsed->token_count = i;
00138     parsed->tokens = tokens;
00139     return; 
00140 }
00141 
00142 CK_RV
00143 secmod_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS) 
00144 {
00145     int next;
00146     char *tmp;
00147     char *index;
00148     char *certPrefix = NULL, *keyPrefix = NULL;
00149     char *tokdes = NULL, *ptokdes = NULL;
00150     char *slotdes = NULL, *pslotdes = NULL;
00151     char *fslotdes = NULL, *fpslotdes = NULL;
00152     char *minPW = NULL;
00153     index = secmod_argStrip(param);
00154 
00155     PORT_Memset(parsed, 0, sizeof(sftk_parameters));
00156 
00157     while (*index) {
00158        SECMOD_HANDLE_STRING_ARG(index,parsed->configdir,"configDir=",;)
00159        SECMOD_HANDLE_STRING_ARG(index,parsed->secmodName,"secmod=",;)
00160        SECMOD_HANDLE_STRING_ARG(index,parsed->man,"manufacturerID=",;)
00161        SECMOD_HANDLE_STRING_ARG(index,parsed->libdes,"libraryDescription=",;)
00162        /* constructed values, used so legacy interfaces still work */
00163        SECMOD_HANDLE_STRING_ARG(index,certPrefix,"certPrefix=",;)
00164         SECMOD_HANDLE_STRING_ARG(index,keyPrefix,"keyPrefix=",;)
00165         SECMOD_HANDLE_STRING_ARG(index,tokdes,"cryptoTokenDescription=",;)
00166         SECMOD_HANDLE_STRING_ARG(index,ptokdes,"dbTokenDescription=",;)
00167         SECMOD_HANDLE_STRING_ARG(index,slotdes,"cryptoSlotDescription=",;)
00168         SECMOD_HANDLE_STRING_ARG(index,pslotdes,"dbSlotDescription=",;)
00169         SECMOD_HANDLE_STRING_ARG(index,fslotdes,"FIPSSlotDescription=",;)
00170         SECMOD_HANDLE_STRING_ARG(index,fpslotdes,"FIPSTokenDescription=",;)
00171        SECMOD_HANDLE_STRING_ARG(index,minPW,"minPWLen=",;)
00172 
00173        SECMOD_HANDLE_STRING_ARG(index,tmp,"flags=", 
00174               if(tmp) { secmod_parseFlags(param,parsed); PORT_Free(tmp); })
00175        SECMOD_HANDLE_STRING_ARG(index,tmp,"tokens=", 
00176               if(tmp) { secmod_parseTokens(tmp,parsed); PORT_Free(tmp); })
00177        SECMOD_HANDLE_FINAL_ARG(index)
00178     }
00179     if (parsed->tokens == NULL) {
00180        int  count = isFIPS ? 1 : 2;
00181        int  index = count-1;
00182        sftk_token_parameters *tokens = NULL;
00183 
00184        tokens = (sftk_token_parameters *) 
00185                      PORT_ZAlloc(count*sizeof(sftk_token_parameters));
00186        if (tokens == NULL) {
00187            goto loser;
00188        }
00189        parsed->tokens = tokens;
00190        parsed->token_count = count;
00191        tokens[index].slotID = isFIPS ? FIPS_SLOT_ID : PRIVATE_KEY_SLOT_ID;
00192        tokens[index].certPrefix = certPrefix;
00193        tokens[index].keyPrefix = keyPrefix;
00194        tokens[index].minPW = minPW ? atoi(minPW) : 0;
00195        tokens[index].readOnly = parsed->readOnly;
00196        tokens[index].noCertDB = parsed->noCertDB;
00197        tokens[index].noKeyDB = parsed->noCertDB;
00198        tokens[index].forceOpen = parsed->forceOpen;
00199        tokens[index].pwRequired = parsed->pwRequired;
00200        tokens[index].optimizeSpace = parsed->optimizeSpace;
00201        tokens[0].optimizeSpace = parsed->optimizeSpace;
00202        certPrefix = NULL;
00203        keyPrefix = NULL;
00204        if (isFIPS) {
00205            tokens[index].tokdes = fslotdes;
00206            tokens[index].slotdes = fpslotdes;
00207            fslotdes = NULL;
00208            fpslotdes = NULL;
00209        } else {
00210            tokens[index].tokdes = ptokdes;
00211            tokens[index].slotdes = pslotdes;
00212            tokens[0].slotID = NETSCAPE_SLOT_ID;
00213            tokens[0].tokdes = tokdes;
00214            tokens[0].slotdes = slotdes;
00215            tokens[0].noCertDB = PR_TRUE;
00216            tokens[0].noKeyDB = PR_TRUE;
00217            ptokdes = NULL;
00218            pslotdes = NULL;
00219            tokdes = NULL;
00220            slotdes = NULL;
00221        }
00222     }
00223 
00224 loser:
00225     FREE_CLEAR(certPrefix);
00226     FREE_CLEAR(keyPrefix);
00227     FREE_CLEAR(tokdes);
00228     FREE_CLEAR(ptokdes);
00229     FREE_CLEAR(slotdes);
00230     FREE_CLEAR(pslotdes);
00231     FREE_CLEAR(fslotdes);
00232     FREE_CLEAR(fpslotdes);
00233     FREE_CLEAR(minPW);
00234     return CKR_OK;
00235 }
00236 
00237 void
00238 secmod_freeParams(sftk_parameters *params)
00239 {
00240     int i;
00241 
00242     for (i=0; i < params->token_count; i++) {
00243        FREE_CLEAR(params->tokens[i].configdir);
00244        FREE_CLEAR(params->tokens[i].certPrefix);
00245        FREE_CLEAR(params->tokens[i].keyPrefix);
00246        FREE_CLEAR(params->tokens[i].tokdes);
00247        FREE_CLEAR(params->tokens[i].slotdes);
00248     }
00249 
00250     FREE_CLEAR(params->configdir);
00251     FREE_CLEAR(params->secmodName);
00252     FREE_CLEAR(params->man);
00253     FREE_CLEAR(params->libdes); 
00254     FREE_CLEAR(params->tokens);
00255 }
00256 
00257 
00258 char *
00259 secmod_getSecmodName(char *param, char **appName, char **filename,PRBool *rw)
00260 {
00261     int next;
00262     char *configdir = NULL;
00263     char *secmodName = NULL;
00264     char *value = NULL;
00265     char *save_params = param;
00266     const char *lconfigdir;
00267     param = secmod_argStrip(param);
00268        
00269 
00270     while (*param) {
00271        SECMOD_HANDLE_STRING_ARG(param,configdir,"configDir=",;)
00272        SECMOD_HANDLE_STRING_ARG(param,secmodName,"secmod=",;)
00273        SECMOD_HANDLE_FINAL_ARG(param)
00274    }
00275 
00276    *rw = PR_TRUE;
00277    if (secmod_argHasFlag("flags","readOnly",save_params) ||
00278        secmod_argHasFlag("flags","noModDB",save_params)) *rw = PR_FALSE;
00279 
00280    if (!secmodName || *secmodName == '\0') {
00281        if (secmodName) PORT_Free(secmodName);
00282        secmodName = PORT_Strdup(SECMOD_DB);
00283    }
00284    *filename = secmodName;
00285 
00286    lconfigdir = sftk_EvaluateConfigDir(configdir, appName);
00287 
00288    if (lconfigdir) {
00289        value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName);
00290    } else {
00291        value = PR_smprintf("%s",secmodName);
00292    }
00293    if (configdir) PORT_Free(configdir);
00294    return value;
00295 }
00296 
00297 /* Construct a database key for a given module */
00298 static SECStatus secmod_MakeKey(DBT *key, char * module) {
00299     int len = 0;
00300     char *commonName;
00301 
00302     commonName = secmod_argGetParamValue("name",module);
00303     if (commonName == NULL) {
00304        commonName = secmod_argGetParamValue("library",module);
00305     }
00306     if (commonName == NULL) return SECFailure;
00307     len = PORT_Strlen(commonName);
00308     key->data = commonName;
00309     key->size = len;
00310     return SECSuccess;
00311 }
00312 
00313 /* free out constructed database key */
00314 static void 
00315 secmod_FreeKey(DBT *key) 
00316 {
00317     if (key->data) {
00318        PORT_Free(key->data);
00319     }
00320     key->data = NULL;
00321     key->size = 0;
00322 }
00323 
00324 typedef struct secmodDataStr secmodData;
00325 typedef struct secmodSlotDataStr secmodSlotData;
00326 struct secmodDataStr {
00327     unsigned char major;
00328     unsigned char minor;
00329     unsigned char nameStart[2];
00330     unsigned char slotOffset[2];
00331     unsigned char internal;
00332     unsigned char fips;
00333     unsigned char ssl[8];
00334     unsigned char trustOrder[4];
00335     unsigned char cipherOrder[4];
00336     unsigned char reserved1;
00337     unsigned char isModuleDB;
00338     unsigned char isModuleDBOnly;
00339     unsigned char isCritical;
00340     unsigned char reserved[4];
00341     unsigned char names[6]; /* enough space for the length fields */
00342 };
00343 
00344 struct secmodSlotDataStr {
00345     unsigned char slotID[4];
00346     unsigned char defaultFlags[4];
00347     unsigned char timeout[4];
00348     unsigned char askpw;
00349     unsigned char hasRootCerts;
00350     unsigned char reserved[18]; /* this makes it a round 32 bytes */
00351 };
00352 
00353 #define SECMOD_DB_VERSION_MAJOR 0
00354 #define SECMOD_DB_VERSION_MINOR 6
00355 #define SECMOD_DB_EXT1_VERSION_MAJOR 0
00356 #define SECMOD_DB_EXT1_VERSION_MINOR 6
00357 #define SECMOD_DB_NOUI_VERSION_MAJOR 0
00358 #define SECMOD_DB_NOUI_VERSION_MINOR 4
00359 
00360 #define SECMOD_PUTSHORT(dest,src) \
00361        (dest)[1] = (unsigned char) ((src)&0xff); \
00362        (dest)[0] = (unsigned char) (((src) >> 8) & 0xff);
00363 #define SECMOD_PUTLONG(dest,src) \
00364        (dest)[3] = (unsigned char) ((src)&0xff); \
00365        (dest)[2] = (unsigned char) (((src) >> 8) & 0xff); \
00366        (dest)[1] = (unsigned char) (((src) >> 16) & 0xff); \
00367        (dest)[0] = (unsigned char) (((src) >> 24) & 0xff);
00368 #define SECMOD_GETSHORT(src) \
00369        ((unsigned short) (((src)[0] << 8) | (src)[1]))
00370 #define SECMOD_GETLONG(src) \
00371        ((unsigned long) (( (unsigned long) (src)[0] << 24) | \
00372                      ( (unsigned long) (src)[1] << 16)  | \
00373                      ( (unsigned long) (src)[2] << 8) | \
00374                      (unsigned long) (src)[3]))
00375 
00376 /*
00377  * build a data base entry from a module 
00378  */
00379 static SECStatus 
00380 secmod_EncodeData(DBT *data, char * module) 
00381 {
00382     secmodData *encoded = NULL;
00383     secmodSlotData *slot;
00384     unsigned char *dataPtr;
00385     unsigned short len, len2 = 0, len3 = 0;
00386     int count = 0;
00387     unsigned short offset;
00388     int dataLen, i;
00389     unsigned long order;
00390     unsigned long  ssl[2];
00391     char *commonName = NULL , *dllName = NULL, *param = NULL, *nss = NULL;
00392     char *slotParams, *ciphers;
00393     PK11PreSlotInfo *slotInfo = NULL;
00394     SECStatus rv = SECFailure;
00395 
00396     rv = secmod_argParseModuleSpec(module,&dllName,&commonName,&param,&nss);
00397     if (rv != SECSuccess) return rv;
00398     rv = SECFailure;
00399 
00400     if (commonName == NULL) {
00401        /* set error */
00402        goto loser;
00403     }
00404 
00405     len = PORT_Strlen(commonName);
00406     if (dllName) {
00407        len2 = PORT_Strlen(dllName);
00408     }
00409     if (param) {
00410        len3 = PORT_Strlen(param);
00411     }
00412 
00413     slotParams = secmod_argGetParamValue("slotParams",nss); 
00414     slotInfo = secmod_argParseSlotInfo(NULL,slotParams,&count);
00415     if (slotParams) PORT_Free(slotParams);
00416 
00417     if (count && slotInfo == NULL) {
00418        /* set error */
00419        goto loser;
00420     }
00421 
00422     dataLen = sizeof(secmodData) + len + len2 + len3 + sizeof(unsigned short) +
00423                              count*sizeof(secmodSlotData);
00424 
00425     data->data = (unsigned char *) PORT_ZAlloc(dataLen);
00426     encoded = (secmodData *)data->data;
00427     dataPtr = (unsigned char *) data->data;
00428     data->size = dataLen;
00429 
00430     if (encoded == NULL) {
00431        /* set error */
00432        goto loser;
00433     }
00434 
00435     encoded->major = SECMOD_DB_VERSION_MAJOR;
00436     encoded->minor = SECMOD_DB_VERSION_MINOR;
00437     encoded->internal = (unsigned char) 
00438                      (secmod_argHasFlag("flags","internal",nss) ? 1 : 0);
00439     encoded->fips = (unsigned char) 
00440                      (secmod_argHasFlag("flags","FIPS",nss) ? 1 : 0);
00441     encoded->isModuleDB = (unsigned char) 
00442                      (secmod_argHasFlag("flags","isModuleDB",nss) ? 1 : 0);
00443     encoded->isModuleDBOnly = (unsigned char) 
00444                   (secmod_argHasFlag("flags","isModuleDBOnly",nss) ? 1 : 0);
00445     encoded->isCritical = (unsigned char) 
00446                      (secmod_argHasFlag("flags","critical",nss) ? 1 : 0);
00447 
00448     order = secmod_argReadLong("trustOrder", nss, SECMOD_DEFAULT_TRUST_ORDER, 
00449                                NULL);
00450     SECMOD_PUTLONG(encoded->trustOrder,order);
00451     order = secmod_argReadLong("cipherOrder", nss, SECMOD_DEFAULT_CIPHER_ORDER, 
00452                                NULL);
00453     SECMOD_PUTLONG(encoded->cipherOrder,order);
00454 
00455    
00456     ciphers = secmod_argGetParamValue("ciphers",nss); 
00457     secmod_argSetNewCipherFlags(&ssl[0], ciphers);
00458     SECMOD_PUTLONG(encoded->ssl,ssl[0]);
00459     SECMOD_PUTLONG(&encoded->ssl[4],ssl[1]);
00460     if (ciphers) PORT_Free(ciphers);
00461 
00462     offset = (unsigned short) &(((secmodData *)0)->names[0]);
00463     SECMOD_PUTSHORT(encoded->nameStart,offset);
00464     offset = offset + len + len2 + len3 + 3*sizeof(unsigned short);
00465     SECMOD_PUTSHORT(encoded->slotOffset,offset);
00466 
00467 
00468     SECMOD_PUTSHORT(&dataPtr[offset],((unsigned short)count));
00469     slot = (secmodSlotData *)(dataPtr+offset+sizeof(unsigned short));
00470 
00471     offset = 0;
00472     SECMOD_PUTSHORT(encoded->names,len);
00473     offset += sizeof(unsigned short);
00474     PORT_Memcpy(&encoded->names[offset],commonName,len);
00475     offset += len;
00476 
00477 
00478     SECMOD_PUTSHORT(&encoded->names[offset],len2);
00479     offset += sizeof(unsigned short);
00480     if (len2) PORT_Memcpy(&encoded->names[offset],dllName,len2);
00481     offset += len2;
00482 
00483     SECMOD_PUTSHORT(&encoded->names[offset],len3);
00484     offset += sizeof(unsigned short);
00485     if (len3) PORT_Memcpy(&encoded->names[offset],param,len3);
00486     offset += len3;
00487 
00488     if (count) {
00489        for (i=0; i < count; i++) {
00490            SECMOD_PUTLONG(slot[i].slotID, slotInfo[i].slotID);
00491            SECMOD_PUTLONG(slot[i].defaultFlags,
00492                                    slotInfo[i].defaultFlags);
00493            SECMOD_PUTLONG(slot[i].timeout,slotInfo[i].timeout);
00494            slot[i].askpw = slotInfo[i].askpw;
00495            slot[i].hasRootCerts = slotInfo[i].hasRootCerts;
00496            PORT_Memset(slot[i].reserved, 0, sizeof(slot[i].reserved));
00497        }
00498     }
00499     rv = SECSuccess;
00500 
00501 loser:
00502     if (commonName) PORT_Free(commonName);
00503     if (dllName) PORT_Free(dllName);
00504     if (param) PORT_Free(param);
00505     if (slotInfo) PORT_Free(slotInfo);
00506     if (nss) PORT_Free(nss);
00507     return rv;
00508 
00509 }
00510 
00511 static void 
00512 secmod_FreeData(DBT *data)
00513 {
00514     if (data->data) {
00515        PORT_Free(data->data);
00516     }
00517 }
00518 
00519 static void
00520 secmod_FreeSlotStrings(char **slotStrings, int count)
00521 {
00522     int i;
00523 
00524     for (i=0; i < count; i++) {
00525        if (slotStrings[i]) {
00526            PR_smprintf_free(slotStrings[i]);
00527            slotStrings[i] = NULL;
00528        }
00529     }
00530 }
00531 
00532 /*
00533  * build a module from the data base entry.
00534  */
00535 static char *
00536 secmod_DecodeData(char *defParams, DBT *data, PRBool *retInternal)
00537 {
00538     secmodData *encoded;
00539     secmodSlotData *slots;
00540     PLArenaPool *arena;
00541     char *commonName               = NULL;
00542     char *dllName                  = NULL;
00543     char *parameters               = NULL;
00544     char *nss;
00545     char *moduleSpec;
00546     char **slotStrings             = NULL;
00547     unsigned char *names;
00548     unsigned long slotCount;
00549     unsigned long ssl0             =0;
00550     unsigned long ssl1             =0;
00551     unsigned long slotID;
00552     unsigned long defaultFlags;
00553     unsigned long timeout;
00554     unsigned long trustOrder       =SECMOD_DEFAULT_TRUST_ORDER;
00555     unsigned long cipherOrder      =SECMOD_DEFAULT_CIPHER_ORDER;
00556     unsigned short len;
00557     unsigned short namesOffset  = 0;      /* start of the names block */
00558     unsigned long namesRunningOffset;     /* offset to name we are 
00559                                     * currently processing */
00560     unsigned short slotOffset;
00561     PRBool isOldVersion     = PR_FALSE;
00562     PRBool internal;
00563     PRBool isFIPS;
00564     PRBool isModuleDB       =PR_FALSE;
00565     PRBool isModuleDBOnly   =PR_FALSE;
00566     PRBool extended         =PR_FALSE;
00567     int i;
00568 
00569 
00570     arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
00571     if (arena == NULL) 
00572        return NULL;
00573 
00574 #define CHECK_SIZE(x) \
00575     if ((unsigned int) data->size < (unsigned int)(x)) goto db_loser
00576 
00577     /* -------------------------------------------------------------
00578     ** Process the buffer header, which is the secmodData struct. 
00579     ** It may be an old or new version.  Check the length for each. 
00580     */
00581 
00582     CHECK_SIZE( offsetof(secmodData, trustOrder[0]) );
00583 
00584     encoded = (secmodData *)data->data;
00585 
00586     internal = (encoded->internal != 0) ? PR_TRUE: PR_FALSE;
00587     isFIPS   = (encoded->fips     != 0) ? PR_TRUE: PR_FALSE;
00588 
00589     if (retInternal)
00590        *retInternal = internal;
00591     if (internal) {
00592        parameters = PORT_ArenaStrdup(arena,defParams);
00593        if (parameters == NULL) 
00594            goto loser;
00595     }
00596     if (internal && (encoded->major == SECMOD_DB_NOUI_VERSION_MAJOR) &&
00597        (encoded->minor <= SECMOD_DB_NOUI_VERSION_MINOR)) {
00598        isOldVersion = PR_TRUE;
00599     }
00600     if ((encoded->major == SECMOD_DB_EXT1_VERSION_MAJOR) &&
00601        (encoded->minor >= SECMOD_DB_EXT1_VERSION_MINOR)) {
00602        CHECK_SIZE( sizeof(secmodData));
00603        trustOrder     = SECMOD_GETLONG(encoded->trustOrder);
00604        cipherOrder    = SECMOD_GETLONG(encoded->cipherOrder);
00605        isModuleDB     = (encoded->isModuleDB != 0) ? PR_TRUE: PR_FALSE;
00606        isModuleDBOnly = (encoded->isModuleDBOnly != 0) ? PR_TRUE: PR_FALSE;
00607        extended       = PR_TRUE;
00608     } 
00609     if (internal && !extended) {
00610        trustOrder = 0;
00611        cipherOrder = 100;
00612     }
00613     /* decode SSL cipher enable flags */
00614     ssl0 = SECMOD_GETLONG(encoded->ssl);
00615     ssl1 = SECMOD_GETLONG(encoded->ssl + 4);
00616 
00617     slotOffset  = SECMOD_GETSHORT(encoded->slotOffset);
00618     namesOffset = SECMOD_GETSHORT(encoded->nameStart);
00619 
00620 
00621     /*--------------------------------------------------------------
00622     ** Now process the variable length set of names.                
00623     ** The names have this structure:
00624     ** struct {
00625     **     BYTE  commonNameLen[ 2 ];
00626     **     BYTE  commonName   [ commonNameLen ];
00627     **     BTTE  libNameLen   [ 2 ];
00628     **     BYTE  libName      [ libNameLen ];
00629     ** If it is "extended" it also has these members:
00630     **     BYTE  initStringLen[ 2 ];
00631     **     BYTE  initString   [ initStringLen ];
00632     ** }
00633     */
00634 
00635     namesRunningOffset = namesOffset;
00636     /* copy the module's common name */
00637     CHECK_SIZE( namesRunningOffset + 2);
00638     names = (unsigned char *)data->data;
00639     len   = SECMOD_GETSHORT(names+namesRunningOffset);
00640 
00641     CHECK_SIZE( namesRunningOffset + 2 + len);
00642     commonName = (char*)PORT_ArenaAlloc(arena,len+1);
00643     if (commonName == NULL) 
00644        goto loser;
00645     PORT_Memcpy(commonName, names + namesRunningOffset + 2, len);
00646     commonName[len] = 0;
00647     namesRunningOffset += len + 2;
00648 
00649     /* copy the module's shared library file name. */
00650     CHECK_SIZE( namesRunningOffset + 2);
00651     len = SECMOD_GETSHORT(names + namesRunningOffset);
00652     if (len) {
00653        CHECK_SIZE( namesRunningOffset + 2 + len);
00654        dllName = (char*)PORT_ArenaAlloc(arena,len + 1);
00655        if (dllName == NULL) 
00656            goto loser;
00657        PORT_Memcpy(dllName, names + namesRunningOffset + 2, len);
00658        dllName[len] = 0;
00659     }
00660     namesRunningOffset += len + 2;
00661 
00662     /* copy the module's initialization string, if present. */
00663     if (!internal && extended) {
00664        CHECK_SIZE( namesRunningOffset + 2);
00665        len = SECMOD_GETSHORT(names+namesRunningOffset);
00666        if (len) {
00667            CHECK_SIZE( namesRunningOffset + 2 + len );
00668            parameters = (char*)PORT_ArenaAlloc(arena,len + 1);
00669            if (parameters == NULL) 
00670               goto loser;
00671            PORT_Memcpy(parameters,names + namesRunningOffset + 2, len);
00672            parameters[len] = 0;
00673        }
00674        namesRunningOffset += len + 2;
00675     }
00676 
00677     /* 
00678      * Consistency check: Make sure the slot and names blocks don't
00679      * overlap. These blocks can occur in any order, so this check is made 
00680      * in 2 parts. First we check the case where the slot block starts 
00681      * after the name block. Later, when we have the slot block length,
00682      * we check the case where slot block starts before the name block.
00683      * NOTE: in most cases any overlap will likely be detected by invalid 
00684      * data read from the blocks, but it's better to find out sooner 
00685      * than later.
00686      */
00687     if (slotOffset >= namesOffset) { /* slot block starts after name block */
00688        if (slotOffset < namesRunningOffset) {
00689            goto db_loser;
00690        }
00691     }
00692 
00693     /* ------------------------------------------------------------------
00694     ** Part 3, process the slot table.
00695     ** This part has this structure:
00696     ** struct {
00697     **     BYTE slotCount [ 2 ];
00698     **     secmodSlotData [ slotCount ];
00699     ** {
00700     */
00701 
00702     CHECK_SIZE( slotOffset + 2 );
00703     slotCount = SECMOD_GETSHORT((unsigned char *)data->data + slotOffset);
00704 
00705     /* 
00706      * Consistency check: Part 2. We now have the slot block length, we can 
00707      * check the case where the slotblock procedes the name block.
00708      */
00709     if (slotOffset < namesOffset) { /* slot block starts before name block */
00710        if (namesOffset < slotOffset + 2 + slotCount*sizeof(secmodSlotData)) {
00711            goto db_loser;
00712        }
00713     }
00714 
00715     CHECK_SIZE( (slotOffset + 2 + slotCount * sizeof(secmodSlotData)));
00716     slots = (secmodSlotData *) ((unsigned char *)data->data + slotOffset + 2);
00717 
00718     /*  slotCount; */
00719     slotStrings = (char **)PORT_ArenaZAlloc(arena, slotCount * sizeof(char *));
00720     if (slotStrings == NULL)
00721        goto loser;
00722     for (i=0; i < (int) slotCount; i++, slots++) {
00723        PRBool hasRootCerts  =PR_FALSE;
00724        PRBool hasRootTrust  =PR_FALSE;
00725        slotID       = SECMOD_GETLONG(slots->slotID);
00726        defaultFlags = SECMOD_GETLONG(slots->defaultFlags);
00727        timeout      = SECMOD_GETLONG(slots->timeout);
00728        hasRootCerts = slots->hasRootCerts;
00729        if (isOldVersion && internal && (slotID != 2)) {
00730               unsigned long internalFlags=
00731                      secmod_argSlotFlags("slotFlags",SECMOD_SLOT_FLAGS);
00732               defaultFlags |= internalFlags;
00733        }
00734        if (hasRootCerts && !extended) {
00735            trustOrder = 100;
00736        }
00737 
00738        slotStrings[i] = secmod_mkSlotString(slotID, defaultFlags, timeout, 
00739                                           (unsigned char)slots->askpw, 
00740                                           hasRootCerts, hasRootTrust);
00741        if (slotStrings[i] == NULL) {
00742            secmod_FreeSlotStrings(slotStrings,i);
00743            goto loser;
00744        }
00745     }
00746 
00747     nss = secmod_mkNSS(slotStrings, slotCount, internal, isFIPS, isModuleDB, 
00748                    isModuleDBOnly, internal, trustOrder, cipherOrder, 
00749                    ssl0, ssl1);
00750     secmod_FreeSlotStrings(slotStrings,slotCount);
00751     /* it's permissible (and normal) for nss to be NULL. it simply means
00752      * there are no NSS specific parameters in the database */
00753     moduleSpec = secmod_mkNewModuleSpec(dllName,commonName,parameters,nss);
00754     PR_smprintf_free(nss);
00755     PORT_FreeArena(arena,PR_TRUE);
00756     return moduleSpec;
00757 
00758 db_loser:
00759     PORT_SetError(SEC_ERROR_BAD_DATABASE);
00760 loser:
00761     PORT_FreeArena(arena,PR_TRUE);
00762     return NULL;
00763 }
00764 
00765 
00766 
00767 static DB *
00768 secmod_OpenDB(const char *appName, const char *filename, const char *dbName, 
00769                             PRBool readOnly, PRBool update)
00770 {
00771     DB *pkcs11db = NULL;
00772 
00773 
00774     if (appName) {
00775        char *secname = PORT_Strdup(filename);
00776        int len = strlen(secname);
00777        int status = RDB_FAIL;
00778 
00779        if (len >= 3 && PORT_Strcmp(&secname[len-3],".db") == 0) {
00780           secname[len-3] = 0;
00781        }
00782        pkcs11db=
00783           rdbopen(appName, "", secname, readOnly ? NO_RDONLY:NO_RDWR, NULL);
00784        if (update && !pkcs11db) {
00785            DB *updatedb;
00786 
00787            pkcs11db = rdbopen(appName, "", secname, NO_CREATE, &status);
00788            if (!pkcs11db) {
00789               if (status == RDB_RETRY) {
00790                   pkcs11db= rdbopen(appName, "", secname, 
00791                                    readOnly ? NO_RDONLY:NO_RDWR, NULL);
00792               }
00793               PORT_Free(secname);
00794               return pkcs11db;
00795            }
00796            updatedb = dbopen(dbName, NO_RDONLY, 0600, DB_HASH, 0);
00797            if (updatedb) {
00798               db_Copy(pkcs11db,updatedb);
00799               (*updatedb->close)(updatedb);
00800            } else {
00801               (*pkcs11db->close)(pkcs11db);
00802               PORT_Free(secname);
00803               return NULL;
00804           }
00805        }
00806        PORT_Free(secname);
00807        return pkcs11db;
00808     }
00809   
00810     /* I'm sure we should do more checks here sometime... */
00811     pkcs11db = dbopen(dbName, readOnly ? NO_RDONLY : NO_RDWR, 0600, DB_HASH, 0);
00812 
00813     /* didn't exist? create it */
00814     if (pkcs11db == NULL) {
00815         if (readOnly) 
00816             return NULL;
00817 
00818         pkcs11db = dbopen( dbName, NO_CREATE, 0600, DB_HASH, 0 );
00819         if (pkcs11db) 
00820             (* pkcs11db->sync)(pkcs11db, 0);
00821     }
00822     return pkcs11db;
00823 }
00824 
00825 static void 
00826 secmod_CloseDB(DB *pkcs11db) 
00827 {
00828      (*pkcs11db->close)(pkcs11db);
00829 }
00830 
00831 static char *
00832 secmod_addEscape(const char *string, char quote)
00833 {
00834     char *newString = 0;
00835     int escapes = 0, size = 0;
00836     const char *src;
00837     char *dest;
00838 
00839     for (src=string; *src ; src++) {
00840        if ((*src == quote) || (*src == '\\')) escapes++;
00841        size++;
00842     }
00843 
00844     newString = PORT_ZAlloc(escapes+size+1); 
00845     if (newString == NULL) {
00846        return NULL;
00847     }
00848 
00849     for (src=string, dest=newString; *src; src++,dest++) {
00850        if ((*src == '\\') || (*src == quote)) {
00851            *dest++ = '\\';
00852        }
00853        *dest = *src;
00854     }
00855 
00856     return newString;
00857 }
00858 
00859 #define SECMOD_STEP 10
00860 #define SFTK_DEFAULT_INTERNAL_INIT "library= name=\"NSS Internal PKCS #11 Module\" parameters=\"%s\" NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={%s askpw=any timeout=30})\""
00861 /*
00862  * Read all the existing modules in
00863  */
00864 char **
00865 secmod_ReadPermDB(const char *appName, const char *filename,
00866                             const char *dbname, char *params, PRBool rw)
00867 {
00868     DBT key,data;
00869     int ret;
00870     DB *pkcs11db = NULL;
00871     char **moduleList = NULL, **newModuleList = NULL;
00872     int moduleCount = 1;
00873     int useCount = SECMOD_STEP;
00874 
00875     moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **));
00876     if (moduleList == NULL) return NULL;
00877 
00878     pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_TRUE,rw);
00879     if (pkcs11db == NULL) goto done;
00880 
00881     /* read and parse the file or data base */
00882     ret = (*pkcs11db->seq)(pkcs11db, &key, &data, R_FIRST);
00883     if (ret)  goto done;
00884 
00885 
00886     do {
00887        char *moduleString;
00888        PRBool internal = PR_FALSE;
00889        if ((moduleCount+1) >= useCount) {
00890            useCount += SECMOD_STEP;
00891            newModuleList =
00892               (char **)PORT_Realloc(moduleList,useCount*sizeof(char *));
00893            if (newModuleList == NULL) goto done;
00894            moduleList = newModuleList;
00895            PORT_Memset(&moduleList[moduleCount+1],0,
00896                                           sizeof(char *)*SECMOD_STEP);
00897        }
00898        moduleString = secmod_DecodeData(params,&data,&internal);
00899        if (internal) {
00900            moduleList[0] = moduleString;
00901        } else {
00902            moduleList[moduleCount] = moduleString;
00903            moduleCount++;
00904        }
00905     } while ( (*pkcs11db->seq)(pkcs11db, &key, &data, R_NEXT) == 0);
00906 
00907 done:
00908     if (!moduleList[0]) {
00909        char * newparams = secmod_addEscape(params,'"');
00910        if (newparams) {
00911            moduleList[0] = PR_smprintf(SFTK_DEFAULT_INTERNAL_INIT,newparams,
00912                                           SECMOD_SLOT_FLAGS);
00913            PORT_Free(newparams);
00914        }
00915     }
00916     /* deal with trust cert db here */
00917 
00918     if (pkcs11db) {
00919        secmod_CloseDB(pkcs11db);
00920     } else if (moduleList[0] && rw) {
00921        secmod_AddPermDB(appName,filename,dbname,moduleList[0], rw) ;
00922     }
00923     if (!moduleList[0]) {
00924        PORT_Free(moduleList);
00925        moduleList = NULL;
00926     }
00927     return moduleList;
00928 }
00929 
00930 SECStatus
00931 secmod_ReleasePermDBData(const char *appName, const char *filename, 
00932                      const char *dbname, char **moduleSpecList, PRBool rw)
00933 {
00934     if (moduleSpecList) {
00935        char **index;
00936        for(index = moduleSpecList; *index; index++) {
00937            PR_smprintf_free(*index);
00938        }
00939        PORT_Free(moduleSpecList);
00940     }
00941     return SECSuccess;
00942 }
00943 
00944 /*
00945  * Delete a module from the Data Base
00946  */
00947 SECStatus
00948 secmod_DeletePermDB(const char *appName, const char *filename, 
00949                      const char *dbname, char *args, PRBool rw)
00950 {
00951     DBT key;
00952     SECStatus rv = SECFailure;
00953     DB *pkcs11db = NULL;
00954     int ret;
00955 
00956     if (!rw) return SECFailure;
00957 
00958     /* make sure we have a db handle */
00959     pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE);
00960     if (pkcs11db == NULL) {
00961        return SECFailure;
00962     }
00963 
00964     rv = secmod_MakeKey(&key,args);
00965     if (rv != SECSuccess) goto done;
00966     rv = SECFailure;
00967     ret = (*pkcs11db->del)(pkcs11db, &key, 0);
00968     secmod_FreeKey(&key);
00969     if (ret != 0) goto done;
00970 
00971 
00972     ret = (*pkcs11db->sync)(pkcs11db, 0);
00973     if (ret == 0) rv = SECSuccess;
00974 
00975 done:
00976     secmod_CloseDB(pkcs11db);
00977     return rv;
00978 }
00979 
00980 /*
00981  * Add a module to the Data base 
00982  */
00983 SECStatus
00984 secmod_AddPermDB(const char *appName, const char *filename, 
00985                      const char *dbname, char *module, PRBool rw)
00986 {
00987     DBT key,data;
00988     SECStatus rv = SECFailure;
00989     DB *pkcs11db = NULL;
00990     int ret;
00991 
00992 
00993     if (!rw) return SECFailure;
00994 
00995     /* make sure we have a db handle */
00996     pkcs11db = secmod_OpenDB(appName,filename,dbname,PR_FALSE,PR_FALSE);
00997     if (pkcs11db == NULL) {
00998        return SECFailure;
00999     }
01000 
01001     rv = secmod_MakeKey(&key,module);
01002     if (rv != SECSuccess) goto done;
01003     rv = secmod_EncodeData(&data,module);
01004     if (rv != SECSuccess) {
01005        secmod_FreeKey(&key);
01006        goto done;
01007     }
01008     rv = SECFailure;
01009     ret = (*pkcs11db->put)(pkcs11db, &key, &data, 0);
01010     secmod_FreeKey(&key);
01011     secmod_FreeData(&data);
01012     if (ret != 0) goto done;
01013 
01014     ret = (*pkcs11db->sync)(pkcs11db, 0);
01015     if (ret == 0) rv = SECSuccess;
01016 
01017 done:
01018     secmod_CloseDB(pkcs11db);
01019     return rv;
01020 }