1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/util/utilmod.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,736 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * The following code handles the storage of PKCS 11 modules used by the 1.9 + * NSS. For the rest of NSS, only one kind of database handle exists: 1.10 + * 1.11 + * SFTKDBHandle 1.12 + * 1.13 + * There is one SFTKDBHandle for each key database and one for each cert 1.14 + * database. These databases are opened as associated pairs, one pair per 1.15 + * slot. SFTKDBHandles are reference counted objects. 1.16 + * 1.17 + * Each SFTKDBHandle points to a low level database handle (SDB). This handle 1.18 + * represents the underlying physical database. These objects are not 1.19 + * reference counted, and are 'owned' by their respective SFTKDBHandles. 1.20 + */ 1.21 + 1.22 +#include "prprf.h" 1.23 +#include "prsystem.h" 1.24 +#include "secport.h" 1.25 +#include "utilpars.h" 1.26 +#include "secerr.h" 1.27 + 1.28 +#if defined (_WIN32) 1.29 +#include <io.h> 1.30 +#endif 1.31 +#ifdef XP_UNIX 1.32 +#include <unistd.h> 1.33 +#endif 1.34 + 1.35 +#include <sys/types.h> 1.36 +#include <sys/stat.h> 1.37 +#include <fcntl.h> 1.38 + 1.39 +#if defined (_WIN32) 1.40 +#define os_open _open 1.41 +#define os_fdopen _fdopen 1.42 +#define os_stat _stat 1.43 +#define os_truncate_open_flags _O_CREAT|_O_RDWR|_O_TRUNC 1.44 +#define os_append_open_flags _O_CREAT|_O_RDWR|_O_APPEND 1.45 +#define os_open_permissions_type int 1.46 +#define os_open_permissions_default _S_IREAD | _S_IWRITE 1.47 +#define os_stat_type struct _stat 1.48 +#else 1.49 +#define os_open open 1.50 +#define os_fdopen fdopen 1.51 +#define os_stat stat 1.52 +#define os_truncate_open_flags O_CREAT|O_RDWR|O_TRUNC 1.53 +#define os_append_open_flags O_CREAT|O_RDWR|O_APPEND 1.54 +#define os_open_permissions_type mode_t 1.55 +#define os_open_permissions_default 0600 1.56 +#define os_stat_type struct stat 1.57 +#endif 1.58 + 1.59 +/**************************************************************** 1.60 + * 1.61 + * Secmod database. 1.62 + * 1.63 + * The new secmod database is simply a text file with each of the module 1.64 + * entries in the following form: 1.65 + * 1.66 + * # 1.67 + * # This is a comment The next line is the library to load 1.68 + * library=libmypkcs11.so 1.69 + * name="My PKCS#11 module" 1.70 + * params="my library's param string" 1.71 + * nss="NSS parameters" 1.72 + * other="parameters for other libraries and applications" 1.73 + * 1.74 + * library=libmynextpk11.so 1.75 + * name="My other PKCS#11 module" 1.76 + */ 1.77 + 1.78 + 1.79 +/* 1.80 + * Smart string cat functions. Automatically manage the memory. 1.81 + * The first parameter is the source string. If it's null, we 1.82 + * allocate memory for it. If it's not, we reallocate memory 1.83 + * so the the concanenated string fits. 1.84 + */ 1.85 +static char * 1.86 +nssutil_DupnCat(char *baseString, const char *str, int str_len) 1.87 +{ 1.88 + int len = (baseString ? PORT_Strlen(baseString) : 0) + 1; 1.89 + char *newString; 1.90 + 1.91 + len += str_len; 1.92 + newString = (char *) PORT_Realloc(baseString,len); 1.93 + if (newString == NULL) { 1.94 + PORT_Free(baseString); 1.95 + return NULL; 1.96 + } 1.97 + if (baseString == NULL) *newString = 0; 1.98 + return PORT_Strncat(newString,str, str_len); 1.99 +} 1.100 + 1.101 +/* Same as nssutil_DupnCat except it concatenates the full string, not a 1.102 + * partial one */ 1.103 +static char * 1.104 +nssutil_DupCat(char *baseString, const char *str) 1.105 +{ 1.106 + return nssutil_DupnCat(baseString, str, PORT_Strlen(str)); 1.107 +} 1.108 + 1.109 +/* function to free up all the memory associated with a null terminated 1.110 + * array of module specs */ 1.111 +static SECStatus 1.112 +nssutil_releaseSpecList(char **moduleSpecList) 1.113 +{ 1.114 + if (moduleSpecList) { 1.115 + char **index; 1.116 + for(index = moduleSpecList; *index; index++) { 1.117 + PORT_Free(*index); 1.118 + } 1.119 + PORT_Free(moduleSpecList); 1.120 + } 1.121 + return SECSuccess; 1.122 +} 1.123 + 1.124 +#define SECMOD_STEP 10 1.125 +static SECStatus 1.126 +nssutil_growList(char ***pModuleList, int *useCount, int last) 1.127 +{ 1.128 + char **newModuleList; 1.129 + 1.130 + *useCount += SECMOD_STEP; 1.131 + newModuleList = (char **)PORT_Realloc(*pModuleList, 1.132 + *useCount*sizeof(char *)); 1.133 + if (newModuleList == NULL) { 1.134 + return SECFailure; 1.135 + } 1.136 + PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); 1.137 + *pModuleList = newModuleList; 1.138 + return SECSuccess; 1.139 +} 1.140 + 1.141 +static 1.142 +char *_NSSUTIL_GetOldSecmodName(const char *dbname,const char *filename) 1.143 +{ 1.144 + char *file = NULL; 1.145 + char *dirPath = PORT_Strdup(dbname); 1.146 + char *sep; 1.147 + 1.148 + sep = PORT_Strrchr(dirPath,*NSSUTIL_PATH_SEPARATOR); 1.149 +#ifdef _WIN32 1.150 + if (!sep) { 1.151 + /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all 1.152 + * platforms. */ 1.153 + sep = PORT_Strrchr(dirPath,'\\'); 1.154 + } 1.155 +#endif 1.156 + if (sep) { 1.157 + *sep = 0; 1.158 + file = PR_smprintf("%s"NSSUTIL_PATH_SEPARATOR"%s", dirPath, filename); 1.159 + } else { 1.160 + file = PR_smprintf("%s", filename); 1.161 + } 1.162 + PORT_Free(dirPath); 1.163 + return file; 1.164 +} 1.165 + 1.166 +static SECStatus nssutil_AddSecmodDBEntry(const char *appName, 1.167 + const char *filename, 1.168 + const char *dbname, 1.169 + char *module, PRBool rw); 1.170 + 1.171 +enum lfopen_mode { lfopen_truncate, lfopen_append }; 1.172 + 1.173 +FILE * 1.174 +lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) 1.175 +{ 1.176 + int fd; 1.177 + FILE *file; 1.178 + 1.179 + fd = os_open(name, 1.180 + (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, 1.181 + open_perms); 1.182 + if (fd < 0) { 1.183 + return NULL; 1.184 + } 1.185 + file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); 1.186 + if (!file) { 1.187 + close(fd); 1.188 + } 1.189 + /* file inherits fd */ 1.190 + return file; 1.191 +} 1.192 + 1.193 +#define MAX_LINE_LENGTH 2048 1.194 + 1.195 +/* 1.196 + * Read all the existing modules in out of the file. 1.197 + */ 1.198 +static char ** 1.199 +nssutil_ReadSecmodDB(const char *appName, 1.200 + const char *filename, const char *dbname, 1.201 + char *params, PRBool rw) 1.202 +{ 1.203 + FILE *fd = NULL; 1.204 + char **moduleList = NULL; 1.205 + int moduleCount = 1; 1.206 + int useCount = SECMOD_STEP; 1.207 + char line[MAX_LINE_LENGTH]; 1.208 + PRBool internal = PR_FALSE; 1.209 + PRBool skipParams = PR_FALSE; 1.210 + char *moduleString = NULL; 1.211 + char *paramsValue=NULL; 1.212 + PRBool failed = PR_TRUE; 1.213 + 1.214 + moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); 1.215 + if (moduleList == NULL) return NULL; 1.216 + 1.217 + if (dbname == NULL) { 1.218 + goto return_default; 1.219 + } 1.220 + 1.221 + /* do we really want to use streams here */ 1.222 + fd = fopen(dbname, "r"); 1.223 + if (fd == NULL) goto done; 1.224 + 1.225 + /* 1.226 + * the following loop takes line separated config lines and collapses 1.227 + * the lines to a single string, escaping and quoting as necessary. 1.228 + */ 1.229 + /* loop state variables */ 1.230 + moduleString = NULL; /* current concatenated string */ 1.231 + internal = PR_FALSE; /* is this an internal module */ 1.232 + skipParams = PR_FALSE; /* did we find an override parameter block*/ 1.233 + paramsValue = NULL; /* the current parameter block value */ 1.234 + while (fgets(line, sizeof(line), fd) != NULL) { 1.235 + int len = PORT_Strlen(line); 1.236 + 1.237 + /* remove the ending newline */ 1.238 + if (len && line[len-1] == '\n') { 1.239 + len--; 1.240 + line[len] = 0; 1.241 + } 1.242 + if (*line == '#') { 1.243 + continue; 1.244 + } 1.245 + if (*line != 0) { 1.246 + /* 1.247 + * The PKCS #11 group standard assumes blocks of strings 1.248 + * separated by new lines, clumped by new lines. Internally 1.249 + * we take strings separated by spaces, so we may need to escape 1.250 + * certain spaces. 1.251 + */ 1.252 + char *value = PORT_Strchr(line,'='); 1.253 + 1.254 + /* there is no value, write out the stanza as is */ 1.255 + if (value == NULL || value[1] == 0) { 1.256 + if (moduleString) { 1.257 + moduleString = nssutil_DupnCat(moduleString," ", 1); 1.258 + if (moduleString == NULL) goto loser; 1.259 + } 1.260 + moduleString = nssutil_DupCat(moduleString, line); 1.261 + if (moduleString == NULL) goto loser; 1.262 + /* value is already quoted, just write it out */ 1.263 + } else if (value[1] == '"') { 1.264 + if (moduleString) { 1.265 + moduleString = nssutil_DupnCat(moduleString," ", 1); 1.266 + if (moduleString == NULL) goto loser; 1.267 + } 1.268 + moduleString = nssutil_DupCat(moduleString, line); 1.269 + if (moduleString == NULL) goto loser; 1.270 + /* we have an override parameter section, remember that 1.271 + * we found this (see following comment about why this 1.272 + * is necessary). */ 1.273 + if (PORT_Strncasecmp(line, "parameters", 10) == 0) { 1.274 + skipParams = PR_TRUE; 1.275 + } 1.276 + /* 1.277 + * The internal token always overrides it's parameter block 1.278 + * from the passed in parameters, so wait until then end 1.279 + * before we include the parameter block in case we need to 1.280 + * override it. NOTE: if the parameter block is quoted with ("), 1.281 + * this override does not happen. This allows you to override 1.282 + * the application's parameter configuration. 1.283 + * 1.284 + * parameter block state is controlled by the following variables: 1.285 + * skipParams - Bool : set to true of we have an override param 1.286 + * block (all other blocks, either implicit or explicit are 1.287 + * ignored). 1.288 + * paramsValue - char * : pointer to the current param block. In 1.289 + * the absence of overrides, paramsValue is set to the first 1.290 + * parameter block we find. All subsequent blocks are ignored. 1.291 + * When we find an internal token, the application passed 1.292 + * parameters take precident. 1.293 + */ 1.294 + } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { 1.295 + /* already have parameters */ 1.296 + if (paramsValue) { 1.297 + continue; 1.298 + } 1.299 + paramsValue = NSSUTIL_Quote(&value[1], '"'); 1.300 + if (paramsValue == NULL) goto loser; 1.301 + continue; 1.302 + } else { 1.303 + /* may need to quote */ 1.304 + char *newLine; 1.305 + if (moduleString) { 1.306 + moduleString = nssutil_DupnCat(moduleString," ", 1); 1.307 + if (moduleString == NULL) goto loser; 1.308 + } 1.309 + moduleString = nssutil_DupnCat(moduleString,line,value-line+1); 1.310 + if (moduleString == NULL) goto loser; 1.311 + newLine = NSSUTIL_Quote(&value[1],'"'); 1.312 + if (newLine == NULL) goto loser; 1.313 + moduleString = nssutil_DupCat(moduleString,newLine); 1.314 + PORT_Free(newLine); 1.315 + if (moduleString == NULL) goto loser; 1.316 + } 1.317 + 1.318 + /* check to see if it's internal? */ 1.319 + if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { 1.320 + /* This should be case insensitive! reviewers make 1.321 + * me fix it if it's not */ 1.322 + if (PORT_Strstr(line,"internal")) { 1.323 + internal = PR_TRUE; 1.324 + /* override the parameters */ 1.325 + if (paramsValue) { 1.326 + PORT_Free(paramsValue); 1.327 + } 1.328 + paramsValue = NSSUTIL_Quote(params, '"'); 1.329 + } 1.330 + } 1.331 + continue; 1.332 + } 1.333 + if ((moduleString == NULL) || (*moduleString == 0)) { 1.334 + continue; 1.335 + } 1.336 + 1.337 + /* 1.338 + * if we are here, we have found a complete stanza. Now write out 1.339 + * any param section we may have found. 1.340 + */ 1.341 + if (paramsValue) { 1.342 + /* we had an override */ 1.343 + if (!skipParams) { 1.344 + moduleString = nssutil_DupnCat(moduleString," parameters=", 12); 1.345 + if (moduleString == NULL) goto loser; 1.346 + moduleString = nssutil_DupCat(moduleString, paramsValue); 1.347 + if (moduleString == NULL) goto loser; 1.348 + } 1.349 + PORT_Free(paramsValue); 1.350 + paramsValue = NULL; 1.351 + } 1.352 + 1.353 + if ((moduleCount+1) >= useCount) { 1.354 + SECStatus rv; 1.355 + rv = nssutil_growList(&moduleList, &useCount, moduleCount+1); 1.356 + if (rv != SECSuccess) { 1.357 + goto loser; 1.358 + } 1.359 + } 1.360 + 1.361 + if (internal) { 1.362 + moduleList[0] = moduleString; 1.363 + } else { 1.364 + moduleList[moduleCount] = moduleString; 1.365 + moduleCount++; 1.366 + } 1.367 + moduleString = NULL; 1.368 + internal = PR_FALSE; 1.369 + skipParams = PR_FALSE; 1.370 + } 1.371 + 1.372 + if (moduleString) { 1.373 + PORT_Free(moduleString); 1.374 + moduleString = NULL; 1.375 + } 1.376 +done: 1.377 + /* if we couldn't open a pkcs11 database, look for the old one */ 1.378 + if (fd == NULL) { 1.379 + char *olddbname = _NSSUTIL_GetOldSecmodName(dbname,filename); 1.380 + PRStatus status; 1.381 + 1.382 + /* couldn't get the old name */ 1.383 + if (!olddbname) { 1.384 + goto bail; 1.385 + } 1.386 + 1.387 + /* old one exists */ 1.388 + status = PR_Access(olddbname, PR_ACCESS_EXISTS); 1.389 + if (status == PR_SUCCESS) { 1.390 + PR_smprintf_free(olddbname); 1.391 + PORT_ZFree(moduleList, useCount*sizeof(char **)); 1.392 + PORT_SetError(SEC_ERROR_LEGACY_DATABASE); 1.393 + return NULL; 1.394 + } 1.395 + 1.396 +bail: 1.397 + if (olddbname) { 1.398 + PR_smprintf_free(olddbname); 1.399 + } 1.400 + } 1.401 + 1.402 +return_default: 1.403 + 1.404 + if (!moduleList[0]) { 1.405 + char * newParams; 1.406 + moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1); 1.407 + newParams = NSSUTIL_Quote(params,'"'); 1.408 + if (newParams == NULL) goto loser; 1.409 + moduleString = nssutil_DupCat(moduleString, newParams); 1.410 + PORT_Free(newParams); 1.411 + if (moduleString == NULL) goto loser; 1.412 + moduleString = nssutil_DupCat(moduleString, 1.413 + NSSUTIL_DEFAULT_INTERNAL_INIT2); 1.414 + if (moduleString == NULL) goto loser; 1.415 + moduleString = nssutil_DupCat(moduleString, 1.416 + NSSUTIL_DEFAULT_SFTKN_FLAGS); 1.417 + if (moduleString == NULL) goto loser; 1.418 + moduleString = nssutil_DupCat(moduleString, 1.419 + NSSUTIL_DEFAULT_INTERNAL_INIT3); 1.420 + if (moduleString == NULL) goto loser; 1.421 + moduleList[0] = moduleString; 1.422 + moduleString = NULL; 1.423 + } 1.424 + failed = PR_FALSE; 1.425 + 1.426 +loser: 1.427 + /* 1.428 + * cleanup 1.429 + */ 1.430 + /* deal with trust cert db here */ 1.431 + if (moduleString) { 1.432 + PORT_Free(moduleString); 1.433 + moduleString = NULL; 1.434 + } 1.435 + if (paramsValue) { 1.436 + PORT_Free(paramsValue); 1.437 + paramsValue = NULL; 1.438 + } 1.439 + if (failed || (moduleList[0] == NULL)) { 1.440 + /* This is wrong! FIXME */ 1.441 + nssutil_releaseSpecList(moduleList); 1.442 + moduleList = NULL; 1.443 + failed = PR_TRUE; 1.444 + } 1.445 + if (fd != NULL) { 1.446 + fclose(fd); 1.447 + } else if (!failed && rw) { 1.448 + /* update our internal module */ 1.449 + nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw); 1.450 + } 1.451 + return moduleList; 1.452 +} 1.453 + 1.454 +static SECStatus 1.455 +nssutil_ReleaseSecmodDBData(const char *appName, 1.456 + const char *filename, const char *dbname, 1.457 + char **moduleSpecList, PRBool rw) 1.458 +{ 1.459 + if (moduleSpecList) { 1.460 + nssutil_releaseSpecList(moduleSpecList); 1.461 + } 1.462 + return SECSuccess; 1.463 +} 1.464 + 1.465 + 1.466 +/* 1.467 + * Delete a module from the Data Base 1.468 + */ 1.469 +static SECStatus 1.470 +nssutil_DeleteSecmodDBEntry(const char *appName, 1.471 + const char *filename, 1.472 + const char *dbname, 1.473 + char *args, 1.474 + PRBool rw) 1.475 +{ 1.476 + /* SHDB_FIXME implement */ 1.477 + os_stat_type stat_existing; 1.478 + os_open_permissions_type file_mode; 1.479 + FILE *fd = NULL; 1.480 + FILE *fd2 = NULL; 1.481 + char line[MAX_LINE_LENGTH]; 1.482 + char *dbname2 = NULL; 1.483 + char *block = NULL; 1.484 + char *name = NULL; 1.485 + char *lib = NULL; 1.486 + int name_len, lib_len; 1.487 + PRBool skip = PR_FALSE; 1.488 + PRBool found = PR_FALSE; 1.489 + 1.490 + if (dbname == NULL) { 1.491 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.492 + return SECFailure; 1.493 + } 1.494 + 1.495 + if (!rw) { 1.496 + PORT_SetError(SEC_ERROR_READ_ONLY); 1.497 + return SECFailure; 1.498 + } 1.499 + 1.500 + dbname2 = PORT_Strdup(dbname); 1.501 + if (dbname2 == NULL) goto loser; 1.502 + dbname2[strlen(dbname)-1]++; 1.503 + 1.504 + /* get the permissions of the existing file, or use the default */ 1.505 + if (!os_stat(dbname, &stat_existing)) { 1.506 + file_mode = stat_existing.st_mode; 1.507 + } else { 1.508 + file_mode = os_open_permissions_default; 1.509 + } 1.510 + 1.511 + /* do we really want to use streams here */ 1.512 + fd = fopen(dbname, "r"); 1.513 + if (fd == NULL) goto loser; 1.514 + 1.515 + fd2 = lfopen(dbname2, lfopen_truncate, file_mode); 1.516 + 1.517 + if (fd2 == NULL) goto loser; 1.518 + 1.519 + name = NSSUTIL_ArgGetParamValue("name",args); 1.520 + if (name) { 1.521 + name_len = PORT_Strlen(name); 1.522 + } 1.523 + lib = NSSUTIL_ArgGetParamValue("library",args); 1.524 + if (lib) { 1.525 + lib_len = PORT_Strlen(lib); 1.526 + } 1.527 + 1.528 + 1.529 + /* 1.530 + * the following loop takes line separated config files and collapses 1.531 + * the lines to a single string, escaping and quoting as necessary. 1.532 + */ 1.533 + /* loop state variables */ 1.534 + block = NULL; 1.535 + skip = PR_FALSE; 1.536 + while (fgets(line, sizeof(line), fd) != NULL) { 1.537 + /* If we are processing a block (we haven't hit a blank line yet */ 1.538 + if (*line != '\n') { 1.539 + /* skip means we are in the middle of a block we are deleting */ 1.540 + if (skip) { 1.541 + continue; 1.542 + } 1.543 + /* if we haven't found the block yet, check to see if this block 1.544 + * matches our requirements */ 1.545 + if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) && 1.546 + (PORT_Strncmp(line+5,name,name_len) == 0)) || 1.547 + (lib && (PORT_Strncasecmp(line,"library=",8) == 0) && 1.548 + (PORT_Strncmp(line+8,lib,lib_len) == 0)))) { 1.549 + 1.550 + /* yup, we don't need to save any more data, */ 1.551 + PORT_Free(block); 1.552 + block=NULL; 1.553 + /* we don't need to collect more of this block */ 1.554 + skip = PR_TRUE; 1.555 + /* we don't need to continue searching for the block */ 1.556 + found =PR_TRUE; 1.557 + continue; 1.558 + } 1.559 + /* not our match, continue to collect data in this block */ 1.560 + block = nssutil_DupCat(block,line); 1.561 + continue; 1.562 + } 1.563 + /* we've collected a block of data that wasn't the module we were 1.564 + * looking for, write it out */ 1.565 + if (block) { 1.566 + fwrite(block, PORT_Strlen(block), 1, fd2); 1.567 + PORT_Free(block); 1.568 + block = NULL; 1.569 + } 1.570 + /* If we didn't just delete the this block, keep the blank line */ 1.571 + if (!skip) { 1.572 + fputs(line,fd2); 1.573 + } 1.574 + /* we are definately not in a deleted block anymore */ 1.575 + skip = PR_FALSE; 1.576 + } 1.577 + fclose(fd); 1.578 + fclose(fd2); 1.579 + if (found) { 1.580 + /* rename dbname2 to dbname */ 1.581 + PR_Delete(dbname); 1.582 + PR_Rename(dbname2,dbname); 1.583 + } else { 1.584 + PR_Delete(dbname2); 1.585 + } 1.586 + PORT_Free(dbname2); 1.587 + PORT_Free(lib); 1.588 + PORT_Free(name); 1.589 + PORT_Free(block); 1.590 + return SECSuccess; 1.591 + 1.592 +loser: 1.593 + if (fd != NULL) { 1.594 + fclose(fd); 1.595 + } 1.596 + if (fd2 != NULL) { 1.597 + fclose(fd2); 1.598 + } 1.599 + if (dbname2) { 1.600 + PR_Delete(dbname2); 1.601 + PORT_Free(dbname2); 1.602 + } 1.603 + PORT_Free(lib); 1.604 + PORT_Free(name); 1.605 + return SECFailure; 1.606 +} 1.607 + 1.608 +/* 1.609 + * Add a module to the Data base 1.610 + */ 1.611 +static SECStatus 1.612 +nssutil_AddSecmodDBEntry(const char *appName, 1.613 + const char *filename, const char *dbname, 1.614 + char *module, PRBool rw) 1.615 +{ 1.616 + os_stat_type stat_existing; 1.617 + os_open_permissions_type file_mode; 1.618 + FILE *fd = NULL; 1.619 + char *block = NULL; 1.620 + PRBool libFound = PR_FALSE; 1.621 + 1.622 + if (dbname == NULL) { 1.623 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.624 + return SECFailure; 1.625 + } 1.626 + 1.627 + /* can't write to a read only module */ 1.628 + if (!rw) { 1.629 + PORT_SetError(SEC_ERROR_READ_ONLY); 1.630 + return SECFailure; 1.631 + } 1.632 + 1.633 + /* remove the previous version if it exists */ 1.634 + (void) nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); 1.635 + 1.636 + /* get the permissions of the existing file, or use the default */ 1.637 + if (!os_stat(dbname, &stat_existing)) { 1.638 + file_mode = stat_existing.st_mode; 1.639 + } else { 1.640 + file_mode = os_open_permissions_default; 1.641 + } 1.642 + 1.643 + fd = lfopen(dbname, lfopen_append, file_mode); 1.644 + if (fd == NULL) { 1.645 + return SECFailure; 1.646 + } 1.647 + module = NSSUTIL_ArgStrip(module); 1.648 + while (*module) { 1.649 + int count; 1.650 + char *keyEnd = PORT_Strchr(module,'='); 1.651 + char *value; 1.652 + 1.653 + if (PORT_Strncmp(module, "library=", 8) == 0) { 1.654 + libFound=PR_TRUE; 1.655 + } 1.656 + if (keyEnd == NULL) { 1.657 + block = nssutil_DupCat(block, module); 1.658 + break; 1.659 + } 1.660 + block = nssutil_DupnCat(block, module, keyEnd-module+1); 1.661 + if (block == NULL) { goto loser; } 1.662 + value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count); 1.663 + if (value) { 1.664 + block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value)); 1.665 + PORT_Free(value); 1.666 + } 1.667 + if (block == NULL) { goto loser; } 1.668 + block = nssutil_DupnCat(block, "\n", 1); 1.669 + module = keyEnd + 1 + count; 1.670 + module = NSSUTIL_ArgStrip(module); 1.671 + } 1.672 + if (block) { 1.673 + if (!libFound) { 1.674 + fprintf(fd,"library=\n"); 1.675 + } 1.676 + fwrite(block, PORT_Strlen(block), 1, fd); 1.677 + fprintf(fd,"\n"); 1.678 + PORT_Free(block); 1.679 + block = NULL; 1.680 + } 1.681 + fclose(fd); 1.682 + return SECSuccess; 1.683 + 1.684 +loser: 1.685 + PORT_Free(block); 1.686 + fclose(fd); 1.687 + return SECFailure; 1.688 +} 1.689 + 1.690 + 1.691 +char ** 1.692 +NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args) 1.693 +{ 1.694 + char *secmod = NULL; 1.695 + char *appName = NULL; 1.696 + char *filename = NULL; 1.697 + NSSDBType dbType = NSS_DB_TYPE_NONE; 1.698 + PRBool rw; 1.699 + static char *success="Success"; 1.700 + char **rvstr = NULL; 1.701 + 1.702 + 1.703 + secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName, 1.704 + &filename, &rw); 1.705 + if ((dbType == NSS_DB_TYPE_LEGACY) || 1.706 + (dbType == NSS_DB_TYPE_MULTIACCESS)) { 1.707 + /* we can't handle the old database, only softoken can */ 1.708 + PORT_SetError(SEC_ERROR_LEGACY_DATABASE); 1.709 + rvstr = NULL; 1.710 + goto done; 1.711 + } 1.712 + 1.713 + switch (function) { 1.714 + case SECMOD_MODULE_DB_FUNCTION_FIND: 1.715 + rvstr = nssutil_ReadSecmodDB(appName,filename, 1.716 + secmod,(char *)parameters,rw); 1.717 + break; 1.718 + case SECMOD_MODULE_DB_FUNCTION_ADD: 1.719 + rvstr = (nssutil_AddSecmodDBEntry(appName, filename, 1.720 + secmod, (char *)args, rw) 1.721 + == SECSuccess) ? &success: NULL; 1.722 + break; 1.723 + case SECMOD_MODULE_DB_FUNCTION_DEL: 1.724 + rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename, 1.725 + secmod, (char *)args, rw) 1.726 + == SECSuccess) ? &success: NULL; 1.727 + break; 1.728 + case SECMOD_MODULE_DB_FUNCTION_RELEASE: 1.729 + rvstr = (nssutil_ReleaseSecmodDBData(appName, filename, 1.730 + secmod, (char **)args, rw) 1.731 + == SECSuccess) ? &success: NULL; 1.732 + break; 1.733 + } 1.734 +done: 1.735 + if (secmod) PR_smprintf_free(secmod); 1.736 + if (appName) PORT_Free(appName); 1.737 + if (filename) PORT_Free(filename); 1.738 + return rvstr; 1.739 +}