andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * The following code handles the storage of PKCS 11 modules used by the andre@0: * NSS. For the rest of NSS, only one kind of database handle exists: andre@0: * andre@0: * SFTKDBHandle andre@0: * andre@0: * There is one SFTKDBHandle for each key database and one for each cert andre@0: * database. These databases are opened as associated pairs, one pair per andre@0: * slot. SFTKDBHandles are reference counted objects. andre@0: * andre@0: * Each SFTKDBHandle points to a low level database handle (SDB). This handle andre@0: * represents the underlying physical database. These objects are not andre@0: * reference counted, and are 'owned' by their respective SFTKDBHandles. andre@0: */ andre@0: andre@0: #include "prprf.h" andre@0: #include "prsystem.h" andre@0: #include "secport.h" andre@0: #include "utilpars.h" andre@0: #include "secerr.h" andre@0: andre@0: #if defined (_WIN32) andre@0: #include andre@0: #endif andre@0: #ifdef XP_UNIX andre@0: #include andre@0: #endif andre@0: andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: #if defined (_WIN32) andre@0: #define os_open _open andre@0: #define os_fdopen _fdopen andre@0: #define os_stat _stat andre@0: #define os_truncate_open_flags _O_CREAT|_O_RDWR|_O_TRUNC andre@0: #define os_append_open_flags _O_CREAT|_O_RDWR|_O_APPEND andre@0: #define os_open_permissions_type int andre@0: #define os_open_permissions_default _S_IREAD | _S_IWRITE andre@0: #define os_stat_type struct _stat andre@0: #else andre@0: #define os_open open andre@0: #define os_fdopen fdopen andre@0: #define os_stat stat andre@0: #define os_truncate_open_flags O_CREAT|O_RDWR|O_TRUNC andre@0: #define os_append_open_flags O_CREAT|O_RDWR|O_APPEND andre@0: #define os_open_permissions_type mode_t andre@0: #define os_open_permissions_default 0600 andre@0: #define os_stat_type struct stat andre@0: #endif andre@0: andre@0: /**************************************************************** andre@0: * andre@0: * Secmod database. andre@0: * andre@0: * The new secmod database is simply a text file with each of the module andre@0: * entries in the following form: andre@0: * andre@0: * # andre@0: * # This is a comment The next line is the library to load andre@0: * library=libmypkcs11.so andre@0: * name="My PKCS#11 module" andre@0: * params="my library's param string" andre@0: * nss="NSS parameters" andre@0: * other="parameters for other libraries and applications" andre@0: * andre@0: * library=libmynextpk11.so andre@0: * name="My other PKCS#11 module" andre@0: */ andre@0: andre@0: andre@0: /* andre@0: * Smart string cat functions. Automatically manage the memory. andre@0: * The first parameter is the source string. If it's null, we andre@0: * allocate memory for it. If it's not, we reallocate memory andre@0: * so the the concanenated string fits. andre@0: */ andre@0: static char * andre@0: nssutil_DupnCat(char *baseString, const char *str, int str_len) andre@0: { andre@0: int len = (baseString ? PORT_Strlen(baseString) : 0) + 1; andre@0: char *newString; andre@0: andre@0: len += str_len; andre@0: newString = (char *) PORT_Realloc(baseString,len); andre@0: if (newString == NULL) { andre@0: PORT_Free(baseString); andre@0: return NULL; andre@0: } andre@0: if (baseString == NULL) *newString = 0; andre@0: return PORT_Strncat(newString,str, str_len); andre@0: } andre@0: andre@0: /* Same as nssutil_DupnCat except it concatenates the full string, not a andre@0: * partial one */ andre@0: static char * andre@0: nssutil_DupCat(char *baseString, const char *str) andre@0: { andre@0: return nssutil_DupnCat(baseString, str, PORT_Strlen(str)); andre@0: } andre@0: andre@0: /* function to free up all the memory associated with a null terminated andre@0: * array of module specs */ andre@0: static SECStatus andre@0: nssutil_releaseSpecList(char **moduleSpecList) andre@0: { andre@0: if (moduleSpecList) { andre@0: char **index; andre@0: for(index = moduleSpecList; *index; index++) { andre@0: PORT_Free(*index); andre@0: } andre@0: PORT_Free(moduleSpecList); andre@0: } andre@0: return SECSuccess; andre@0: } andre@0: andre@0: #define SECMOD_STEP 10 andre@0: static SECStatus andre@0: nssutil_growList(char ***pModuleList, int *useCount, int last) andre@0: { andre@0: char **newModuleList; andre@0: andre@0: *useCount += SECMOD_STEP; andre@0: newModuleList = (char **)PORT_Realloc(*pModuleList, andre@0: *useCount*sizeof(char *)); andre@0: if (newModuleList == NULL) { andre@0: return SECFailure; andre@0: } andre@0: PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); andre@0: *pModuleList = newModuleList; andre@0: return SECSuccess; andre@0: } andre@0: andre@0: static andre@0: char *_NSSUTIL_GetOldSecmodName(const char *dbname,const char *filename) andre@0: { andre@0: char *file = NULL; andre@0: char *dirPath = PORT_Strdup(dbname); andre@0: char *sep; andre@0: andre@0: sep = PORT_Strrchr(dirPath,*NSSUTIL_PATH_SEPARATOR); andre@0: #ifdef _WIN32 andre@0: if (!sep) { andre@0: /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all andre@0: * platforms. */ andre@0: sep = PORT_Strrchr(dirPath,'\\'); andre@0: } andre@0: #endif andre@0: if (sep) { andre@0: *sep = 0; andre@0: file = PR_smprintf("%s"NSSUTIL_PATH_SEPARATOR"%s", dirPath, filename); andre@0: } else { andre@0: file = PR_smprintf("%s", filename); andre@0: } andre@0: PORT_Free(dirPath); andre@0: return file; andre@0: } andre@0: andre@0: static SECStatus nssutil_AddSecmodDBEntry(const char *appName, andre@0: const char *filename, andre@0: const char *dbname, andre@0: char *module, PRBool rw); andre@0: andre@0: enum lfopen_mode { lfopen_truncate, lfopen_append }; andre@0: andre@0: FILE * andre@0: lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) andre@0: { andre@0: int fd; andre@0: FILE *file; andre@0: andre@0: fd = os_open(name, andre@0: (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, andre@0: open_perms); andre@0: if (fd < 0) { andre@0: return NULL; andre@0: } andre@0: file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); andre@0: if (!file) { andre@0: close(fd); andre@0: } andre@0: /* file inherits fd */ andre@0: return file; andre@0: } andre@0: andre@0: #define MAX_LINE_LENGTH 2048 andre@0: andre@0: /* andre@0: * Read all the existing modules in out of the file. andre@0: */ andre@0: static char ** andre@0: nssutil_ReadSecmodDB(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char *params, PRBool rw) andre@0: { andre@0: FILE *fd = NULL; andre@0: char **moduleList = NULL; andre@0: int moduleCount = 1; andre@0: int useCount = SECMOD_STEP; andre@0: char line[MAX_LINE_LENGTH]; andre@0: PRBool internal = PR_FALSE; andre@0: PRBool skipParams = PR_FALSE; andre@0: char *moduleString = NULL; andre@0: char *paramsValue=NULL; andre@0: PRBool failed = PR_TRUE; andre@0: andre@0: moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); andre@0: if (moduleList == NULL) return NULL; andre@0: andre@0: if (dbname == NULL) { andre@0: goto return_default; andre@0: } andre@0: andre@0: /* do we really want to use streams here */ andre@0: fd = fopen(dbname, "r"); andre@0: if (fd == NULL) goto done; andre@0: andre@0: /* andre@0: * the following loop takes line separated config lines and collapses andre@0: * the lines to a single string, escaping and quoting as necessary. andre@0: */ andre@0: /* loop state variables */ andre@0: moduleString = NULL; /* current concatenated string */ andre@0: internal = PR_FALSE; /* is this an internal module */ andre@0: skipParams = PR_FALSE; /* did we find an override parameter block*/ andre@0: paramsValue = NULL; /* the current parameter block value */ andre@0: while (fgets(line, sizeof(line), fd) != NULL) { andre@0: int len = PORT_Strlen(line); andre@0: andre@0: /* remove the ending newline */ andre@0: if (len && line[len-1] == '\n') { andre@0: len--; andre@0: line[len] = 0; andre@0: } andre@0: if (*line == '#') { andre@0: continue; andre@0: } andre@0: if (*line != 0) { andre@0: /* andre@0: * The PKCS #11 group standard assumes blocks of strings andre@0: * separated by new lines, clumped by new lines. Internally andre@0: * we take strings separated by spaces, so we may need to escape andre@0: * certain spaces. andre@0: */ andre@0: char *value = PORT_Strchr(line,'='); andre@0: andre@0: /* there is no value, write out the stanza as is */ andre@0: if (value == NULL || value[1] == 0) { andre@0: if (moduleString) { andre@0: moduleString = nssutil_DupnCat(moduleString," ", 1); andre@0: if (moduleString == NULL) goto loser; andre@0: } andre@0: moduleString = nssutil_DupCat(moduleString, line); andre@0: if (moduleString == NULL) goto loser; andre@0: /* value is already quoted, just write it out */ andre@0: } else if (value[1] == '"') { andre@0: if (moduleString) { andre@0: moduleString = nssutil_DupnCat(moduleString," ", 1); andre@0: if (moduleString == NULL) goto loser; andre@0: } andre@0: moduleString = nssutil_DupCat(moduleString, line); andre@0: if (moduleString == NULL) goto loser; andre@0: /* we have an override parameter section, remember that andre@0: * we found this (see following comment about why this andre@0: * is necessary). */ andre@0: if (PORT_Strncasecmp(line, "parameters", 10) == 0) { andre@0: skipParams = PR_TRUE; andre@0: } andre@0: /* andre@0: * The internal token always overrides it's parameter block andre@0: * from the passed in parameters, so wait until then end andre@0: * before we include the parameter block in case we need to andre@0: * override it. NOTE: if the parameter block is quoted with ("), andre@0: * this override does not happen. This allows you to override andre@0: * the application's parameter configuration. andre@0: * andre@0: * parameter block state is controlled by the following variables: andre@0: * skipParams - Bool : set to true of we have an override param andre@0: * block (all other blocks, either implicit or explicit are andre@0: * ignored). andre@0: * paramsValue - char * : pointer to the current param block. In andre@0: * the absence of overrides, paramsValue is set to the first andre@0: * parameter block we find. All subsequent blocks are ignored. andre@0: * When we find an internal token, the application passed andre@0: * parameters take precident. andre@0: */ andre@0: } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { andre@0: /* already have parameters */ andre@0: if (paramsValue) { andre@0: continue; andre@0: } andre@0: paramsValue = NSSUTIL_Quote(&value[1], '"'); andre@0: if (paramsValue == NULL) goto loser; andre@0: continue; andre@0: } else { andre@0: /* may need to quote */ andre@0: char *newLine; andre@0: if (moduleString) { andre@0: moduleString = nssutil_DupnCat(moduleString," ", 1); andre@0: if (moduleString == NULL) goto loser; andre@0: } andre@0: moduleString = nssutil_DupnCat(moduleString,line,value-line+1); andre@0: if (moduleString == NULL) goto loser; andre@0: newLine = NSSUTIL_Quote(&value[1],'"'); andre@0: if (newLine == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString,newLine); andre@0: PORT_Free(newLine); andre@0: if (moduleString == NULL) goto loser; andre@0: } andre@0: andre@0: /* check to see if it's internal? */ andre@0: if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { andre@0: /* This should be case insensitive! reviewers make andre@0: * me fix it if it's not */ andre@0: if (PORT_Strstr(line,"internal")) { andre@0: internal = PR_TRUE; andre@0: /* override the parameters */ andre@0: if (paramsValue) { andre@0: PORT_Free(paramsValue); andre@0: } andre@0: paramsValue = NSSUTIL_Quote(params, '"'); andre@0: } andre@0: } andre@0: continue; andre@0: } andre@0: if ((moduleString == NULL) || (*moduleString == 0)) { andre@0: continue; andre@0: } andre@0: andre@0: /* andre@0: * if we are here, we have found a complete stanza. Now write out andre@0: * any param section we may have found. andre@0: */ andre@0: if (paramsValue) { andre@0: /* we had an override */ andre@0: if (!skipParams) { andre@0: moduleString = nssutil_DupnCat(moduleString," parameters=", 12); andre@0: if (moduleString == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString, paramsValue); andre@0: if (moduleString == NULL) goto loser; andre@0: } andre@0: PORT_Free(paramsValue); andre@0: paramsValue = NULL; andre@0: } andre@0: andre@0: if ((moduleCount+1) >= useCount) { andre@0: SECStatus rv; andre@0: rv = nssutil_growList(&moduleList, &useCount, moduleCount+1); andre@0: if (rv != SECSuccess) { andre@0: goto loser; andre@0: } andre@0: } andre@0: andre@0: if (internal) { andre@0: moduleList[0] = moduleString; andre@0: } else { andre@0: moduleList[moduleCount] = moduleString; andre@0: moduleCount++; andre@0: } andre@0: moduleString = NULL; andre@0: internal = PR_FALSE; andre@0: skipParams = PR_FALSE; andre@0: } andre@0: andre@0: if (moduleString) { andre@0: PORT_Free(moduleString); andre@0: moduleString = NULL; andre@0: } andre@0: done: andre@0: /* if we couldn't open a pkcs11 database, look for the old one */ andre@0: if (fd == NULL) { andre@0: char *olddbname = _NSSUTIL_GetOldSecmodName(dbname,filename); andre@0: PRStatus status; andre@0: andre@0: /* couldn't get the old name */ andre@0: if (!olddbname) { andre@0: goto bail; andre@0: } andre@0: andre@0: /* old one exists */ andre@0: status = PR_Access(olddbname, PR_ACCESS_EXISTS); andre@0: if (status == PR_SUCCESS) { andre@0: PR_smprintf_free(olddbname); andre@0: PORT_ZFree(moduleList, useCount*sizeof(char **)); andre@0: PORT_SetError(SEC_ERROR_LEGACY_DATABASE); andre@0: return NULL; andre@0: } andre@0: andre@0: bail: andre@0: if (olddbname) { andre@0: PR_smprintf_free(olddbname); andre@0: } andre@0: } andre@0: andre@0: return_default: andre@0: andre@0: if (!moduleList[0]) { andre@0: char * newParams; andre@0: moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1); andre@0: newParams = NSSUTIL_Quote(params,'"'); andre@0: if (newParams == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString, newParams); andre@0: PORT_Free(newParams); andre@0: if (moduleString == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString, andre@0: NSSUTIL_DEFAULT_INTERNAL_INIT2); andre@0: if (moduleString == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString, andre@0: NSSUTIL_DEFAULT_SFTKN_FLAGS); andre@0: if (moduleString == NULL) goto loser; andre@0: moduleString = nssutil_DupCat(moduleString, andre@0: NSSUTIL_DEFAULT_INTERNAL_INIT3); andre@0: if (moduleString == NULL) goto loser; andre@0: moduleList[0] = moduleString; andre@0: moduleString = NULL; andre@0: } andre@0: failed = PR_FALSE; andre@0: andre@0: loser: andre@0: /* andre@0: * cleanup andre@0: */ andre@0: /* deal with trust cert db here */ andre@0: if (moduleString) { andre@0: PORT_Free(moduleString); andre@0: moduleString = NULL; andre@0: } andre@0: if (paramsValue) { andre@0: PORT_Free(paramsValue); andre@0: paramsValue = NULL; andre@0: } andre@0: if (failed || (moduleList[0] == NULL)) { andre@0: /* This is wrong! FIXME */ andre@0: nssutil_releaseSpecList(moduleList); andre@0: moduleList = NULL; andre@0: failed = PR_TRUE; andre@0: } andre@0: if (fd != NULL) { andre@0: fclose(fd); andre@0: } else if (!failed && rw) { andre@0: /* update our internal module */ andre@0: nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw); andre@0: } andre@0: return moduleList; andre@0: } andre@0: andre@0: static SECStatus andre@0: nssutil_ReleaseSecmodDBData(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char **moduleSpecList, PRBool rw) andre@0: { andre@0: if (moduleSpecList) { andre@0: nssutil_releaseSpecList(moduleSpecList); andre@0: } andre@0: return SECSuccess; andre@0: } andre@0: andre@0: andre@0: /* andre@0: * Delete a module from the Data Base andre@0: */ andre@0: static SECStatus andre@0: nssutil_DeleteSecmodDBEntry(const char *appName, andre@0: const char *filename, andre@0: const char *dbname, andre@0: char *args, andre@0: PRBool rw) andre@0: { andre@0: /* SHDB_FIXME implement */ andre@0: os_stat_type stat_existing; andre@0: os_open_permissions_type file_mode; andre@0: FILE *fd = NULL; andre@0: FILE *fd2 = NULL; andre@0: char line[MAX_LINE_LENGTH]; andre@0: char *dbname2 = NULL; andre@0: char *block = NULL; andre@0: char *name = NULL; andre@0: char *lib = NULL; andre@0: int name_len, lib_len; andre@0: PRBool skip = PR_FALSE; andre@0: PRBool found = PR_FALSE; andre@0: andre@0: if (dbname == NULL) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: andre@0: if (!rw) { andre@0: PORT_SetError(SEC_ERROR_READ_ONLY); andre@0: return SECFailure; andre@0: } andre@0: andre@0: dbname2 = PORT_Strdup(dbname); andre@0: if (dbname2 == NULL) goto loser; andre@0: dbname2[strlen(dbname)-1]++; andre@0: andre@0: /* get the permissions of the existing file, or use the default */ andre@0: if (!os_stat(dbname, &stat_existing)) { andre@0: file_mode = stat_existing.st_mode; andre@0: } else { andre@0: file_mode = os_open_permissions_default; andre@0: } andre@0: andre@0: /* do we really want to use streams here */ andre@0: fd = fopen(dbname, "r"); andre@0: if (fd == NULL) goto loser; andre@0: andre@0: fd2 = lfopen(dbname2, lfopen_truncate, file_mode); andre@0: andre@0: if (fd2 == NULL) goto loser; andre@0: andre@0: name = NSSUTIL_ArgGetParamValue("name",args); andre@0: if (name) { andre@0: name_len = PORT_Strlen(name); andre@0: } andre@0: lib = NSSUTIL_ArgGetParamValue("library",args); andre@0: if (lib) { andre@0: lib_len = PORT_Strlen(lib); andre@0: } andre@0: andre@0: andre@0: /* andre@0: * the following loop takes line separated config files and collapses andre@0: * the lines to a single string, escaping and quoting as necessary. andre@0: */ andre@0: /* loop state variables */ andre@0: block = NULL; andre@0: skip = PR_FALSE; andre@0: while (fgets(line, sizeof(line), fd) != NULL) { andre@0: /* If we are processing a block (we haven't hit a blank line yet */ andre@0: if (*line != '\n') { andre@0: /* skip means we are in the middle of a block we are deleting */ andre@0: if (skip) { andre@0: continue; andre@0: } andre@0: /* if we haven't found the block yet, check to see if this block andre@0: * matches our requirements */ andre@0: if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) && andre@0: (PORT_Strncmp(line+5,name,name_len) == 0)) || andre@0: (lib && (PORT_Strncasecmp(line,"library=",8) == 0) && andre@0: (PORT_Strncmp(line+8,lib,lib_len) == 0)))) { andre@0: andre@0: /* yup, we don't need to save any more data, */ andre@0: PORT_Free(block); andre@0: block=NULL; andre@0: /* we don't need to collect more of this block */ andre@0: skip = PR_TRUE; andre@0: /* we don't need to continue searching for the block */ andre@0: found =PR_TRUE; andre@0: continue; andre@0: } andre@0: /* not our match, continue to collect data in this block */ andre@0: block = nssutil_DupCat(block,line); andre@0: continue; andre@0: } andre@0: /* we've collected a block of data that wasn't the module we were andre@0: * looking for, write it out */ andre@0: if (block) { andre@0: fwrite(block, PORT_Strlen(block), 1, fd2); andre@0: PORT_Free(block); andre@0: block = NULL; andre@0: } andre@0: /* If we didn't just delete the this block, keep the blank line */ andre@0: if (!skip) { andre@0: fputs(line,fd2); andre@0: } andre@0: /* we are definately not in a deleted block anymore */ andre@0: skip = PR_FALSE; andre@0: } andre@0: fclose(fd); andre@0: fclose(fd2); andre@0: if (found) { andre@0: /* rename dbname2 to dbname */ andre@0: PR_Delete(dbname); andre@0: PR_Rename(dbname2,dbname); andre@0: } else { andre@0: PR_Delete(dbname2); andre@0: } andre@0: PORT_Free(dbname2); andre@0: PORT_Free(lib); andre@0: PORT_Free(name); andre@0: PORT_Free(block); andre@0: return SECSuccess; andre@0: andre@0: loser: andre@0: if (fd != NULL) { andre@0: fclose(fd); andre@0: } andre@0: if (fd2 != NULL) { andre@0: fclose(fd2); andre@0: } andre@0: if (dbname2) { andre@0: PR_Delete(dbname2); andre@0: PORT_Free(dbname2); andre@0: } andre@0: PORT_Free(lib); andre@0: PORT_Free(name); andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* andre@0: * Add a module to the Data base andre@0: */ andre@0: static SECStatus andre@0: nssutil_AddSecmodDBEntry(const char *appName, andre@0: const char *filename, const char *dbname, andre@0: char *module, PRBool rw) andre@0: { andre@0: os_stat_type stat_existing; andre@0: os_open_permissions_type file_mode; andre@0: FILE *fd = NULL; andre@0: char *block = NULL; andre@0: PRBool libFound = PR_FALSE; andre@0: andre@0: if (dbname == NULL) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* can't write to a read only module */ andre@0: if (!rw) { andre@0: PORT_SetError(SEC_ERROR_READ_ONLY); andre@0: return SECFailure; andre@0: } andre@0: andre@0: /* remove the previous version if it exists */ andre@0: (void) nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); andre@0: andre@0: /* get the permissions of the existing file, or use the default */ andre@0: if (!os_stat(dbname, &stat_existing)) { andre@0: file_mode = stat_existing.st_mode; andre@0: } else { andre@0: file_mode = os_open_permissions_default; andre@0: } andre@0: andre@0: fd = lfopen(dbname, lfopen_append, file_mode); andre@0: if (fd == NULL) { andre@0: return SECFailure; andre@0: } andre@0: module = NSSUTIL_ArgStrip(module); andre@0: while (*module) { andre@0: int count; andre@0: char *keyEnd = PORT_Strchr(module,'='); andre@0: char *value; andre@0: andre@0: if (PORT_Strncmp(module, "library=", 8) == 0) { andre@0: libFound=PR_TRUE; andre@0: } andre@0: if (keyEnd == NULL) { andre@0: block = nssutil_DupCat(block, module); andre@0: break; andre@0: } andre@0: block = nssutil_DupnCat(block, module, keyEnd-module+1); andre@0: if (block == NULL) { goto loser; } andre@0: value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count); andre@0: if (value) { andre@0: block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value)); andre@0: PORT_Free(value); andre@0: } andre@0: if (block == NULL) { goto loser; } andre@0: block = nssutil_DupnCat(block, "\n", 1); andre@0: module = keyEnd + 1 + count; andre@0: module = NSSUTIL_ArgStrip(module); andre@0: } andre@0: if (block) { andre@0: if (!libFound) { andre@0: fprintf(fd,"library=\n"); andre@0: } andre@0: fwrite(block, PORT_Strlen(block), 1, fd); andre@0: fprintf(fd,"\n"); andre@0: PORT_Free(block); andre@0: block = NULL; andre@0: } andre@0: fclose(fd); andre@0: return SECSuccess; andre@0: andre@0: loser: andre@0: PORT_Free(block); andre@0: fclose(fd); andre@0: return SECFailure; andre@0: } andre@0: andre@0: andre@0: char ** andre@0: NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args) andre@0: { andre@0: char *secmod = NULL; andre@0: char *appName = NULL; andre@0: char *filename = NULL; andre@0: NSSDBType dbType = NSS_DB_TYPE_NONE; andre@0: PRBool rw; andre@0: static char *success="Success"; andre@0: char **rvstr = NULL; andre@0: andre@0: andre@0: secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName, andre@0: &filename, &rw); andre@0: if ((dbType == NSS_DB_TYPE_LEGACY) || andre@0: (dbType == NSS_DB_TYPE_MULTIACCESS)) { andre@0: /* we can't handle the old database, only softoken can */ andre@0: PORT_SetError(SEC_ERROR_LEGACY_DATABASE); andre@0: rvstr = NULL; andre@0: goto done; andre@0: } andre@0: andre@0: switch (function) { andre@0: case SECMOD_MODULE_DB_FUNCTION_FIND: andre@0: rvstr = nssutil_ReadSecmodDB(appName,filename, andre@0: secmod,(char *)parameters,rw); andre@0: break; andre@0: case SECMOD_MODULE_DB_FUNCTION_ADD: andre@0: rvstr = (nssutil_AddSecmodDBEntry(appName, filename, andre@0: secmod, (char *)args, rw) andre@0: == SECSuccess) ? &success: NULL; andre@0: break; andre@0: case SECMOD_MODULE_DB_FUNCTION_DEL: andre@0: rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename, andre@0: secmod, (char *)args, rw) andre@0: == SECSuccess) ? &success: NULL; andre@0: break; andre@0: case SECMOD_MODULE_DB_FUNCTION_RELEASE: andre@0: rvstr = (nssutil_ReleaseSecmodDBData(appName, filename, andre@0: secmod, (char **)args, rw) andre@0: == SECSuccess) ? &success: NULL; andre@0: break; andre@0: } andre@0: done: andre@0: if (secmod) PR_smprintf_free(secmod); andre@0: if (appName) PORT_Free(appName); andre@0: if (filename) PORT_Free(filename); andre@0: return rvstr; andre@0: }