Mercurial > trustbridge > nss-cmake-static
diff nss/lib/util/utilmod.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nss/lib/util/utilmod.c Mon Jul 28 10:47:06 2014 +0200 @@ -0,0 +1,736 @@ +/* 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 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, and are 'owned' by their respective SFTKDBHandles. + */ + +#include "prprf.h" +#include "prsystem.h" +#include "secport.h" +#include "utilpars.h" +#include "secerr.h" + +#if defined (_WIN32) +#include <io.h> +#endif +#ifdef XP_UNIX +#include <unistd.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#if defined (_WIN32) +#define os_open _open +#define os_fdopen _fdopen +#define os_stat _stat +#define os_truncate_open_flags _O_CREAT|_O_RDWR|_O_TRUNC +#define os_append_open_flags _O_CREAT|_O_RDWR|_O_APPEND +#define os_open_permissions_type int +#define os_open_permissions_default _S_IREAD | _S_IWRITE +#define os_stat_type struct _stat +#else +#define os_open open +#define os_fdopen fdopen +#define os_stat stat +#define os_truncate_open_flags O_CREAT|O_RDWR|O_TRUNC +#define os_append_open_flags O_CREAT|O_RDWR|O_APPEND +#define os_open_permissions_type mode_t +#define os_open_permissions_default 0600 +#define os_stat_type struct stat +#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" + */ + + +/* + * 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 * +nssutil_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 nssutil_DupnCat except it concatenates the full string, not a + * partial one */ +static char * +nssutil_DupCat(char *baseString, const char *str) +{ + return nssutil_DupnCat(baseString, str, PORT_Strlen(str)); +} + +/* function to free up all the memory associated with a null terminated + * array of module specs */ +static SECStatus +nssutil_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 +nssutil_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 *_NSSUTIL_GetOldSecmodName(const char *dbname,const char *filename) +{ + char *file = NULL; + char *dirPath = PORT_Strdup(dbname); + char *sep; + + sep = PORT_Strrchr(dirPath,*NSSUTIL_PATH_SEPARATOR); +#ifdef _WIN32 + if (!sep) { + /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all + * platforms. */ + sep = PORT_Strrchr(dirPath,'\\'); + } +#endif + if (sep) { + *sep = 0; + file = PR_smprintf("%s"NSSUTIL_PATH_SEPARATOR"%s", dirPath, filename); + } else { + file = PR_smprintf("%s", filename); + } + PORT_Free(dirPath); + return file; +} + +static SECStatus nssutil_AddSecmodDBEntry(const char *appName, + const char *filename, + const char *dbname, + char *module, PRBool rw); + +enum lfopen_mode { lfopen_truncate, lfopen_append }; + +FILE * +lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) +{ + int fd; + FILE *file; + + fd = os_open(name, + (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, + open_perms); + if (fd < 0) { + return NULL; + } + file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); + if (!file) { + close(fd); + } + /* file inherits fd */ + return file; +} + +#define MAX_LINE_LENGTH 2048 + +/* + * Read all the existing modules in out of the file. + */ +static char ** +nssutil_ReadSecmodDB(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; + + 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 = nssutil_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = nssutil_DupCat(moduleString, line); + if (moduleString == NULL) goto loser; + /* value is already quoted, just write it out */ + } else if (value[1] == '"') { + if (moduleString) { + moduleString = nssutil_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = nssutil_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 = NSSUTIL_Quote(&value[1], '"'); + if (paramsValue == NULL) goto loser; + continue; + } else { + /* may need to quote */ + char *newLine; + if (moduleString) { + moduleString = nssutil_DupnCat(moduleString," ", 1); + if (moduleString == NULL) goto loser; + } + moduleString = nssutil_DupnCat(moduleString,line,value-line+1); + if (moduleString == NULL) goto loser; + newLine = NSSUTIL_Quote(&value[1],'"'); + if (newLine == NULL) goto loser; + moduleString = nssutil_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 = NSSUTIL_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 = nssutil_DupnCat(moduleString," parameters=", 12); + if (moduleString == NULL) goto loser; + moduleString = nssutil_DupCat(moduleString, paramsValue); + if (moduleString == NULL) goto loser; + } + PORT_Free(paramsValue); + paramsValue = NULL; + } + + if ((moduleCount+1) >= useCount) { + SECStatus rv; + rv = nssutil_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 = _NSSUTIL_GetOldSecmodName(dbname,filename); + PRStatus status; + + /* couldn't get the old name */ + if (!olddbname) { + goto bail; + } + + /* old one exists */ + status = PR_Access(olddbname, PR_ACCESS_EXISTS); + if (status == PR_SUCCESS) { + PR_smprintf_free(olddbname); + PORT_ZFree(moduleList, useCount*sizeof(char **)); + PORT_SetError(SEC_ERROR_LEGACY_DATABASE); + return NULL; + } + +bail: + if (olddbname) { + PR_smprintf_free(olddbname); + } + } + +return_default: + + if (!moduleList[0]) { + char * newParams; + moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1); + newParams = NSSUTIL_Quote(params,'"'); + if (newParams == NULL) goto loser; + moduleString = nssutil_DupCat(moduleString, newParams); + PORT_Free(newParams); + if (moduleString == NULL) goto loser; + moduleString = nssutil_DupCat(moduleString, + NSSUTIL_DEFAULT_INTERNAL_INIT2); + if (moduleString == NULL) goto loser; + moduleString = nssutil_DupCat(moduleString, + NSSUTIL_DEFAULT_SFTKN_FLAGS); + if (moduleString == NULL) goto loser; + moduleString = nssutil_DupCat(moduleString, + NSSUTIL_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 */ + nssutil_releaseSpecList(moduleList); + moduleList = NULL; + failed = PR_TRUE; + } + if (fd != NULL) { + fclose(fd); + } else if (!failed && rw) { + /* update our internal module */ + nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw); + } + return moduleList; +} + +static SECStatus +nssutil_ReleaseSecmodDBData(const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw) +{ + if (moduleSpecList) { + nssutil_releaseSpecList(moduleSpecList); + } + return SECSuccess; +} + + +/* + * Delete a module from the Data Base + */ +static SECStatus +nssutil_DeleteSecmodDBEntry(const char *appName, + const char *filename, + const char *dbname, + char *args, + PRBool rw) +{ + /* SHDB_FIXME implement */ + os_stat_type stat_existing; + os_open_permissions_type file_mode; + 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 (!rw) { + PORT_SetError(SEC_ERROR_READ_ONLY); + return SECFailure; + } + + dbname2 = PORT_Strdup(dbname); + if (dbname2 == NULL) goto loser; + dbname2[strlen(dbname)-1]++; + + /* get the permissions of the existing file, or use the default */ + if (!os_stat(dbname, &stat_existing)) { + file_mode = stat_existing.st_mode; + } else { + file_mode = os_open_permissions_default; + } + + /* do we really want to use streams here */ + fd = fopen(dbname, "r"); + if (fd == NULL) goto loser; + + fd2 = lfopen(dbname2, lfopen_truncate, file_mode); + + if (fd2 == NULL) goto loser; + + name = NSSUTIL_ArgGetParamValue("name",args); + if (name) { + name_len = PORT_Strlen(name); + } + lib = NSSUTIL_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 = nssutil_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 + */ +static SECStatus +nssutil_AddSecmodDBEntry(const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw) +{ + os_stat_type stat_existing; + os_open_permissions_type file_mode; + FILE *fd = NULL; + char *block = NULL; + PRBool libFound = PR_FALSE; + + if (dbname == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + /* 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) nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); + + /* get the permissions of the existing file, or use the default */ + if (!os_stat(dbname, &stat_existing)) { + file_mode = stat_existing.st_mode; + } else { + file_mode = os_open_permissions_default; + } + + fd = lfopen(dbname, lfopen_append, file_mode); + if (fd == NULL) { + return SECFailure; + } + module = NSSUTIL_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 = nssutil_DupCat(block, module); + break; + } + block = nssutil_DupnCat(block, module, keyEnd-module+1); + if (block == NULL) { goto loser; } + value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count); + if (value) { + block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value)); + PORT_Free(value); + } + if (block == NULL) { goto loser; } + block = nssutil_DupnCat(block, "\n", 1); + module = keyEnd + 1 + count; + module = NSSUTIL_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; +} + + +char ** +NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args) +{ + char *secmod = NULL; + char *appName = NULL; + char *filename = NULL; + NSSDBType dbType = NSS_DB_TYPE_NONE; + PRBool rw; + static char *success="Success"; + char **rvstr = NULL; + + + secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName, + &filename, &rw); + if ((dbType == NSS_DB_TYPE_LEGACY) || + (dbType == NSS_DB_TYPE_MULTIACCESS)) { + /* we can't handle the old database, only softoken can */ + PORT_SetError(SEC_ERROR_LEGACY_DATABASE); + rvstr = NULL; + goto done; + } + + switch (function) { + case SECMOD_MODULE_DB_FUNCTION_FIND: + rvstr = nssutil_ReadSecmodDB(appName,filename, + secmod,(char *)parameters,rw); + break; + case SECMOD_MODULE_DB_FUNCTION_ADD: + rvstr = (nssutil_AddSecmodDBEntry(appName, filename, + secmod, (char *)args, rw) + == SECSuccess) ? &success: NULL; + break; + case SECMOD_MODULE_DB_FUNCTION_DEL: + rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename, + secmod, (char *)args, rw) + == SECSuccess) ? &success: NULL; + break; + case SECMOD_MODULE_DB_FUNCTION_RELEASE: + rvstr = (nssutil_ReleaseSecmodDBData(appName, filename, + secmod, (char **)args, rw) + == SECSuccess) ? &success: NULL; + break; + } +done: + if (secmod) PR_smprintf_free(secmod); + if (appName) PORT_Free(appName); + if (filename) PORT_Free(filename); + return rvstr; +}