Index: mozilla/security/nss/lib/softoken/sftkmod.c |
=================================================================== |
--- mozilla/security/nss/lib/softoken/sftkmod.c (revision 166571) |
+++ mozilla/security/nss/lib/softoken/sftkmod.c (working copy) |
@@ -1,731 +0,0 @@ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
-/* |
- * The following code handles the storage of PKCS 11 modules used by the |
- * NSS. For the rest of NSS, only one kind of database handle exists: |
- * |
- * SFTKDBHandle |
- * |
- * There is one SFTKDBHandle for the each key database and one for each cert |
- * database. These databases are opened as associated pairs, one pair per |
- * slot. SFTKDBHandles are reference counted objects. |
- * |
- * Each SFTKDBHandle points to a low level database handle (SDB). This handle |
- * represents the underlying physical database. These objects are not |
- * reference counted, an are 'owned' by their respective SFTKDBHandles. |
- * |
- * |
- */ |
-#include "sftkdb.h" |
-#include "sftkpars.h" |
-#include "prprf.h" |
-#include "prsystem.h" |
-#include "lgglue.h" |
-#include "secerr.h" |
-#include "secmodt.h" |
-#if defined (_WIN32) |
-#include <io.h> |
-#endif |
- |
-/**************************************************************** |
- * |
- * Secmod database. |
- * |
- * The new secmod database is simply a text file with each of the module |
- * entries. in the following form: |
- * |
- * # |
- * # This is a comment The next line is the library to load |
- * library=libmypkcs11.so |
- * name="My PKCS#11 module" |
- * params="my library's param string" |
- * nss="NSS parameters" |
- * other="parameters for other libraries and applications" |
- * |
- * library=libmynextpk11.so |
- * name="My other PKCS#11 module" |
- */ |
- |
-static char * |
-sftkdb_quote(const char *string, char quote) |
-{ |
- char *newString = 0; |
- int escapes = 0, size = 0; |
- const char *src; |
- char *dest; |
- |
- size=2; |
- for (src=string; *src ; src++) { |
- if ((*src == quote) || (*src == '\\')) escapes++; |
- size++; |
- } |
- |
- dest = newString = PORT_ZAlloc(escapes+size+1); |
- if (newString == NULL) { |
- return NULL; |
- } |
- |
- *dest++=quote; |
- for (src=string; *src; src++,dest++) { |
- if ((*src == '\\') || (*src == quote)) { |
- *dest++ = '\\'; |
- } |
- *dest = *src; |
- } |
- *dest=quote; |
- |
- return newString; |
-} |
- |
-/* |
- * Smart string cat functions. Automatically manage the memory. |
- * The first parameter is the source string. If it's null, we |
- * allocate memory for it. If it's not, we reallocate memory |
- * so the the concanenated string fits. |
- */ |
-static char * |
-sftkdb_DupnCat(char *baseString, const char *str, int str_len) |
-{ |
- int len = (baseString ? PORT_Strlen(baseString) : 0) + 1; |
- char *newString; |
- |
- len += str_len; |
- newString = (char *) PORT_Realloc(baseString,len); |
- if (newString == NULL) { |
- PORT_Free(baseString); |
- return NULL; |
- } |
- if (baseString == NULL) *newString = 0; |
- return PORT_Strncat(newString,str, str_len); |
-} |
- |
-/* Same as sftkdb_DupnCat except it concatenates the full string, not a |
- * partial one */ |
-static char * |
-sftkdb_DupCat(char *baseString, const char *str) |
-{ |
- return sftkdb_DupnCat(baseString, str, PORT_Strlen(str)); |
-} |
- |
-/* function to free up all the memory associated with a null terminated |
- * array of module specs */ |
-static SECStatus |
-sftkdb_releaseSpecList(char **moduleSpecList) |
-{ |
- if (moduleSpecList) { |
- char **index; |
- for(index = moduleSpecList; *index; index++) { |
- PORT_Free(*index); |
- } |
- PORT_Free(moduleSpecList); |
- } |
- return SECSuccess; |
-} |
- |
-#define SECMOD_STEP 10 |
-static SECStatus |
-sftkdb_growList(char ***pModuleList, int *useCount, int last) |
-{ |
- char **newModuleList; |
- |
- *useCount += SECMOD_STEP; |
- newModuleList = (char **)PORT_Realloc(*pModuleList, |
- *useCount*sizeof(char *)); |
- if (newModuleList == NULL) { |
- return SECFailure; |
- } |
- PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); |
- *pModuleList = newModuleList; |
- return SECSuccess; |
-} |
- |
-static |
-char *sftk_getOldSecmodName(const char *dbname,const char *filename) |
-{ |
- char *file = NULL; |
- char *dirPath = PORT_Strdup(dbname); |
- char *sep; |
- |
- sep = PORT_Strrchr(dirPath,*PATH_SEPARATOR); |
-#ifdef _WIN32 |
- if (!sep) { |
- /* pkcs11i.h defines PATH_SEPARATOR as "/" for all platforms. */ |
- sep = PORT_Strrchr(dirPath,'\\'); |
- } |
-#endif |
- if (sep) { |
- *sep = 0; |
- file = PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, filename); |
- } else { |
- file = PR_smprintf("%s", filename); |
- } |
- PORT_Free(dirPath); |
- return file; |
-} |
- |
-#ifdef XP_UNIX |
-#include <unistd.h> |
-#endif |
-#include <fcntl.h> |
- |
-#ifndef WINCE |
-/* same as fopen, except it doesn't use umask, but explicit */ |
-FILE * |
-lfopen(const char *name, const char *mode, int flags) |
-{ |
- int fd; |
- FILE *file; |
- |
- fd = open(name, flags, 0600); |
- if (fd < 0) { |
- return NULL; |
- } |
- file = fdopen(fd, mode); |
- if (!file) { |
- close(fd); |
- } |
- /* file inherits fd */ |
- return file; |
-} |
-#endif |
- |
-#define MAX_LINE_LENGTH 2048 |
-#define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters=" |
-#define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={" |
-#define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\"" |
- |
-/* |
- * Read all the existing modules in out of the file. |
- */ |
-char ** |
-sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, |
- const char *filename, const char *dbname, |
- char *params, PRBool rw) |
-{ |
- FILE *fd = NULL; |
- char **moduleList = NULL; |
- int moduleCount = 1; |
- int useCount = SECMOD_STEP; |
- char line[MAX_LINE_LENGTH]; |
- PRBool internal = PR_FALSE; |
- PRBool skipParams = PR_FALSE; |
- char *moduleString = NULL; |
- char *paramsValue=NULL; |
- PRBool failed = PR_TRUE; |
- |
- if ((dbname != NULL) && |
- ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS))) { |
- return sftkdbCall_ReadSecmodDB(appName, filename, dbname, params, rw); |
- } |
- |
- moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); |
- if (moduleList == NULL) return NULL; |
- |
- if (dbname == NULL) { |
- goto return_default; |
- } |
- |
- /* do we really want to use streams here */ |
- fd = fopen(dbname, "r"); |
- if (fd == NULL) goto done; |
- |
- /* |
- * the following loop takes line separated config lines and collapses |
- * the lines to a single string, escaping and quoting as necessary. |
- */ |
- /* loop state variables */ |
- moduleString = NULL; /* current concatenated string */ |
- internal = PR_FALSE; /* is this an internal module */ |
- skipParams = PR_FALSE; /* did we find an override parameter block*/ |
- paramsValue = NULL; /* the current parameter block value */ |
- while (fgets(line, sizeof(line), fd) != NULL) { |
- int len = PORT_Strlen(line); |
- |
- /* remove the ending newline */ |
- if (len && line[len-1] == '\n') { |
- len--; |
- line[len] = 0; |
- } |
- if (*line == '#') { |
- continue; |
- } |
- if (*line != 0) { |
- /* |
- * The PKCS #11 group standard assumes blocks of strings |
- * separated by new lines, clumped by new lines. Internally |
- * we take strings separated by spaces, so we may need to escape |
- * certain spaces. |
- */ |
- char *value = PORT_Strchr(line,'='); |
- |
- /* there is no value, write out the stanza as is */ |
- if (value == NULL || value[1] == 0) { |
- if (moduleString) { |
- moduleString = sftkdb_DupnCat(moduleString," ", 1); |
- if (moduleString == NULL) goto loser; |
- } |
- moduleString = sftkdb_DupCat(moduleString, line); |
- if (moduleString == NULL) goto loser; |
- /* value is already quoted, just write it out */ |
- } else if (value[1] == '"') { |
- if (moduleString) { |
- moduleString = sftkdb_DupnCat(moduleString," ", 1); |
- if (moduleString == NULL) goto loser; |
- } |
- moduleString = sftkdb_DupCat(moduleString, line); |
- if (moduleString == NULL) goto loser; |
- /* we have an override parameter section, remember that |
- * we found this (see following comment about why this |
- * is necessary). */ |
- if (PORT_Strncasecmp(line, "parameters", 10) == 0) { |
- skipParams = PR_TRUE; |
- } |
- /* |
- * The internal token always overrides it's parameter block |
- * from the passed in parameters, so wait until then end |
- * before we include the parameter block in case we need to |
- * override it. NOTE: if the parameter block is quoted with ("), |
- * this override does not happen. This allows you to override |
- * the application's parameter configuration. |
- * |
- * parameter block state is controlled by the following variables: |
- * skipParams - Bool : set to true of we have an override param |
- * block (all other blocks, either implicit or explicit are |
- * ignored). |
- * paramsValue - char * : pointer to the current param block. In |
- * the absence of overrides, paramsValue is set to the first |
- * parameter block we find. All subsequent blocks are ignored. |
- * When we find an internal token, the application passed |
- * parameters take precident. |
- */ |
- } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { |
- /* already have parameters */ |
- if (paramsValue) { |
- continue; |
- } |
- paramsValue = sftkdb_quote(&value[1], '"'); |
- if (paramsValue == NULL) goto loser; |
- continue; |
- } else { |
- /* may need to quote */ |
- char *newLine; |
- if (moduleString) { |
- moduleString = sftkdb_DupnCat(moduleString," ", 1); |
- if (moduleString == NULL) goto loser; |
- } |
- moduleString = sftkdb_DupnCat(moduleString,line,value-line+1); |
- if (moduleString == NULL) goto loser; |
- newLine = sftkdb_quote(&value[1],'"'); |
- if (newLine == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString,newLine); |
- PORT_Free(newLine); |
- if (moduleString == NULL) goto loser; |
- } |
- |
- /* check to see if it's internal? */ |
- if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { |
- /* This should be case insensitive! reviewers make |
- * me fix it if it's not */ |
- if (PORT_Strstr(line,"internal")) { |
- internal = PR_TRUE; |
- /* override the parameters */ |
- if (paramsValue) { |
- PORT_Free(paramsValue); |
- } |
- paramsValue = sftkdb_quote(params, '"'); |
- } |
- } |
- continue; |
- } |
- if ((moduleString == NULL) || (*moduleString == 0)) { |
- continue; |
- } |
- |
- /* |
- * if we are here, we have found a complete stanza. Now write out |
- * any param section we may have found. |
- */ |
- if (paramsValue) { |
- /* we had an override */ |
- if (!skipParams) { |
- moduleString = sftkdb_DupnCat(moduleString," parameters=", 12); |
- if (moduleString == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString, paramsValue); |
- if (moduleString == NULL) goto loser; |
- } |
- PORT_Free(paramsValue); |
- paramsValue = NULL; |
- } |
- |
- if ((moduleCount+1) >= useCount) { |
- SECStatus rv; |
- rv = sftkdb_growList(&moduleList, &useCount, moduleCount+1); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- } |
- |
- if (internal) { |
- moduleList[0] = moduleString; |
- } else { |
- moduleList[moduleCount] = moduleString; |
- moduleCount++; |
- } |
- moduleString = NULL; |
- internal = PR_FALSE; |
- skipParams = PR_FALSE; |
- } |
- |
- if (moduleString) { |
- PORT_Free(moduleString); |
- moduleString = NULL; |
- } |
-done: |
- /* If we couldn't open a pkcs11 database, look for the old one. |
- * This is necessary to maintain the semantics of the transition from |
- * old to new DB's. If there is an old DB and not new DB, we will |
- * automatically use the old DB. If the DB was opened read/write, we |
- * create a new db and upgrade it from the old one. */ |
- if (fd == NULL) { |
- char *olddbname = sftk_getOldSecmodName(dbname,filename); |
- PRStatus status; |
- char **oldModuleList; |
- int i; |
- |
- /* couldn't get the old name */ |
- if (!olddbname) { |
- goto bail; |
- } |
- |
- /* old one doesn't exist */ |
- status = PR_Access(olddbname, PR_ACCESS_EXISTS); |
- if (status != PR_SUCCESS) { |
- goto bail; |
- } |
- |
- oldModuleList = sftkdbCall_ReadSecmodDB(appName, filename, |
- olddbname, params, rw); |
- /* old one had no modules */ |
- if (!oldModuleList) { |
- goto bail; |
- } |
- |
- /* count the modules */ |
- for (i=0; oldModuleList[i]; i++) { } |
- |
- /* grow the moduleList if necessary */ |
- if (i >= useCount) { |
- SECStatus rv; |
- rv = sftkdb_growList(&moduleList,&useCount,moduleCount+1); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- } |
- |
- /* write each module out, and copy it */ |
- for (i=0; oldModuleList[i]; i++) { |
- if (rw) { |
- sftkdb_AddSecmodDB(dbType,appName,filename,dbname, |
- oldModuleList[i],rw); |
- } |
- if (moduleList[i]) { |
- PORT_Free(moduleList[i]); |
- } |
- moduleList[i] = PORT_Strdup(oldModuleList[i]); |
- } |
- |
- /* done with the old module list */ |
- sftkdbCall_ReleaseSecmodDBData(appName, filename, olddbname, |
- oldModuleList, rw); |
-bail: |
- if (olddbname) { |
- PR_smprintf_free(olddbname); |
- } |
- } |
- |
-return_default: |
- |
- if (!moduleList[0]) { |
- char * newParams; |
- moduleString = PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1); |
- newParams = sftkdb_quote(params,'"'); |
- if (newParams == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString, newParams); |
- PORT_Free(newParams); |
- if (moduleString == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT2); |
- if (moduleString == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString, SECMOD_SLOT_FLAGS); |
- if (moduleString == NULL) goto loser; |
- moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT3); |
- if (moduleString == NULL) goto loser; |
- moduleList[0] = moduleString; |
- moduleString = NULL; |
- } |
- failed = PR_FALSE; |
- |
-loser: |
- /* |
- * cleanup |
- */ |
- /* deal with trust cert db here */ |
- if (moduleString) { |
- PORT_Free(moduleString); |
- moduleString = NULL; |
- } |
- if (paramsValue) { |
- PORT_Free(paramsValue); |
- paramsValue = NULL; |
- } |
- if (failed || (moduleList[0] == NULL)) { |
- /* This is wrong! FIXME */ |
- sftkdb_releaseSpecList(moduleList); |
- moduleList = NULL; |
- failed = PR_TRUE; |
- } |
- if (fd != NULL) { |
- fclose(fd); |
- } else if (!failed && rw) { |
- /* update our internal module */ |
- sftkdb_AddSecmodDB(dbType,appName,filename,dbname,moduleList[0],rw); |
- } |
- return moduleList; |
-} |
- |
-SECStatus |
-sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName, |
- const char *filename, const char *dbname, |
- char **moduleSpecList, PRBool rw) |
-{ |
- if ((dbname != NULL) && |
- ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS))) { |
- return sftkdbCall_ReleaseSecmodDBData(appName, filename, dbname, |
- moduleSpecList, rw); |
- } |
- if (moduleSpecList) { |
- sftkdb_releaseSpecList(moduleSpecList); |
- } |
- return SECSuccess; |
-} |
- |
- |
-/* |
- * Delete a module from the Data Base |
- */ |
-SECStatus |
-sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, |
- const char *filename, const char *dbname, |
- char *args, PRBool rw) |
-{ |
- /* SHDB_FIXME implement */ |
- FILE *fd = NULL; |
- FILE *fd2 = NULL; |
- char line[MAX_LINE_LENGTH]; |
- char *dbname2 = NULL; |
- char *block = NULL; |
- char *name = NULL; |
- char *lib = NULL; |
- int name_len, lib_len; |
- PRBool skip = PR_FALSE; |
- PRBool found = PR_FALSE; |
- |
- if (dbname == NULL) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- |
- if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { |
- return sftkdbCall_DeleteSecmodDB(appName, filename, dbname, args, rw); |
- } |
- |
- if (!rw) { |
- PORT_SetError(SEC_ERROR_READ_ONLY); |
- return SECFailure; |
- } |
- |
- dbname2 = strdup(dbname); |
- if (dbname2 == NULL) goto loser; |
- dbname2[strlen(dbname)-1]++; |
- |
- /* do we really want to use streams here */ |
- fd = fopen(dbname, "r"); |
- if (fd == NULL) goto loser; |
-#ifdef WINCE |
- fd2 = fopen(dbname2, "w+"); |
-#else |
- fd2 = lfopen(dbname2, "w+", O_CREAT|O_RDWR|O_TRUNC); |
-#endif |
- if (fd2 == NULL) goto loser; |
- |
- name = sftk_argGetParamValue("name",args); |
- if (name) { |
- name_len = PORT_Strlen(name); |
- } |
- lib = sftk_argGetParamValue("library",args); |
- if (lib) { |
- lib_len = PORT_Strlen(lib); |
- } |
- |
- |
- /* |
- * the following loop takes line separated config files and collapses |
- * the lines to a single string, escaping and quoting as necessary. |
- */ |
- /* loop state variables */ |
- block = NULL; |
- skip = PR_FALSE; |
- while (fgets(line, sizeof(line), fd) != NULL) { |
- /* If we are processing a block (we haven't hit a blank line yet */ |
- if (*line != '\n') { |
- /* skip means we are in the middle of a block we are deleting */ |
- if (skip) { |
- continue; |
- } |
- /* if we haven't found the block yet, check to see if this block |
- * matches our requirements */ |
- if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) && |
- (PORT_Strncmp(line+5,name,name_len) == 0)) || |
- (lib && (PORT_Strncasecmp(line,"library=",8) == 0) && |
- (PORT_Strncmp(line+8,lib,lib_len) == 0)))) { |
- |
- /* yup, we don't need to save any more data, */ |
- PORT_Free(block); |
- block=NULL; |
- /* we don't need to collect more of this block */ |
- skip = PR_TRUE; |
- /* we don't need to continue searching for the block */ |
- found =PR_TRUE; |
- continue; |
- } |
- /* not our match, continue to collect data in this block */ |
- block = sftkdb_DupCat(block,line); |
- continue; |
- } |
- /* we've collected a block of data that wasn't the module we were |
- * looking for, write it out */ |
- if (block) { |
- fwrite(block, PORT_Strlen(block), 1, fd2); |
- PORT_Free(block); |
- block = NULL; |
- } |
- /* If we didn't just delete the this block, keep the blank line */ |
- if (!skip) { |
- fputs(line,fd2); |
- } |
- /* we are definately not in a deleted block anymore */ |
- skip = PR_FALSE; |
- } |
- fclose(fd); |
- fclose(fd2); |
- if (found) { |
- /* rename dbname2 to dbname */ |
- PR_Delete(dbname); |
- PR_Rename(dbname2,dbname); |
- } else { |
- PR_Delete(dbname2); |
- } |
- PORT_Free(dbname2); |
- PORT_Free(lib); |
- PORT_Free(name); |
- PORT_Free(block); |
- return SECSuccess; |
- |
-loser: |
- if (fd != NULL) { |
- fclose(fd); |
- } |
- if (fd2 != NULL) { |
- fclose(fd2); |
- } |
- if (dbname2) { |
- PR_Delete(dbname2); |
- PORT_Free(dbname2); |
- } |
- PORT_Free(lib); |
- PORT_Free(name); |
- return SECFailure; |
-} |
- |
-/* |
- * Add a module to the Data base |
- */ |
-SECStatus |
-sftkdb_AddSecmodDB(SDBType dbType, const char *appName, |
- const char *filename, const char *dbname, |
- char *module, PRBool rw) |
-{ |
- FILE *fd = NULL; |
- char *block = NULL; |
- PRBool libFound = PR_FALSE; |
- |
- if (dbname == NULL) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- |
- if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { |
- return sftkdbCall_AddSecmodDB(appName, filename, dbname, module, rw); |
- } |
- |
- /* can't write to a read only module */ |
- if (!rw) { |
- PORT_SetError(SEC_ERROR_READ_ONLY); |
- return SECFailure; |
- } |
- |
- /* remove the previous version if it exists */ |
- (void) sftkdb_DeleteSecmodDB(dbType, appName, filename, dbname, module, rw); |
- |
-#ifdef WINCE |
- fd = fopen(dbname, "a+"); |
-#else |
- fd = lfopen(dbname, "a+", O_CREAT|O_RDWR|O_APPEND); |
-#endif |
- if (fd == NULL) { |
- return SECFailure; |
- } |
- module = sftk_argStrip(module); |
- while (*module) { |
- int count; |
- char *keyEnd = PORT_Strchr(module,'='); |
- char *value; |
- |
- if (PORT_Strncmp(module, "library=", 8) == 0) { |
- libFound=PR_TRUE; |
- } |
- if (keyEnd == NULL) { |
- block = sftkdb_DupCat(block, module); |
- break; |
- } |
- block = sftkdb_DupnCat(block, module, keyEnd-module+1); |
- if (block == NULL) { goto loser; } |
- value = sftk_argFetchValue(&keyEnd[1], &count); |
- if (value) { |
- block = sftkdb_DupCat(block, sftk_argStrip(value)); |
- PORT_Free(value); |
- } |
- if (block == NULL) { goto loser; } |
- block = sftkdb_DupnCat(block, "\n", 1); |
- module = keyEnd + 1 + count; |
- module = sftk_argStrip(module); |
- } |
- if (block) { |
- if (!libFound) { |
- fprintf(fd,"library=\n"); |
- } |
- fwrite(block, PORT_Strlen(block), 1, fd); |
- fprintf(fd,"\n"); |
- PORT_Free(block); |
- block = NULL; |
- } |
- fclose(fd); |
- return SECSuccess; |
- |
-loser: |
- PORT_Free(block); |
- fclose(fd); |
- return SECFailure; |
-} |
- |
- |