diff options
author | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-07-18 20:31:20 +0100 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-07-18 20:31:20 +0100 |
commit | e43ad1f4ce7f1504e6f01fc8a90d5c0398013383 (patch) | |
tree | 03504d9d81336081b899c9f34cc0f66801caf67c /mozilla/security/nss/lib/softoken/sftkmod.c | |
download | nss-e43ad1f4ce7f1504e6f01fc8a90d5c0398013383.tar.gz |
Tarball conversion
Diffstat (limited to 'mozilla/security/nss/lib/softoken/sftkmod.c')
-rw-r--r-- | mozilla/security/nss/lib/softoken/sftkmod.c | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/softoken/sftkmod.c b/mozilla/security/nss/lib/softoken/sftkmod.c new file mode 100644 index 0000000..c89b7da --- /dev/null +++ b/mozilla/security/nss/lib/softoken/sftkmod.c @@ -0,0 +1,734 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * 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 "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 WINDOWS + if (!sep) { + sep = PORT_Strrchr(dirPath,'/'); + } +#endif + if (sep) { + *(sep)=0; + } + file= PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, 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 ((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; + + /* 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 colapses + * 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 */ + 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); + } + } + + 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 ((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 ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_DeleteSecmodDB(appName, filename, dbname, args, rw); + } + + if (!rw) { + 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 colapses + * 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); + 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 ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) { + return sftkdbCall_AddSecmodDB(appName, filename, dbname, module, rw); + } + + /* can't write to a read only module */ + if (!rw) { + 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; +} + + |