utilmod.c (27609B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 /* 5 * The following code handles the storage of PKCS 11 modules used by the 6 * NSS. For the rest of NSS, only one kind of database handle exists: 7 * 8 * SFTKDBHandle 9 * 10 * There is one SFTKDBHandle for each key database and one for each cert 11 * database. These databases are opened as associated pairs, one pair per 12 * slot. SFTKDBHandles are reference counted objects. 13 * 14 * Each SFTKDBHandle points to a low level database handle (SDB). This handle 15 * represents the underlying physical database. These objects are not 16 * reference counted, and are 'owned' by their respective SFTKDBHandles. 17 */ 18 19 #include "prprf.h" 20 #include "prsystem.h" 21 #include "secport.h" 22 #include "utilpars.h" 23 #include "secerr.h" 24 25 #if defined(_WIN32) 26 #include <io.h> 27 #include <windows.h> 28 #endif 29 #ifdef XP_UNIX 30 #include <unistd.h> 31 #endif 32 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 37 #if defined(_WIN32) 38 #define os_fdopen _fdopen 39 #define os_truncate_open_flags _O_CREAT | _O_RDWR | _O_TRUNC 40 #define os_append_open_flags _O_CREAT | _O_RDWR | _O_APPEND 41 #define os_open_permissions_type int 42 #define os_open_permissions_default _S_IREAD | _S_IWRITE 43 #define os_stat_type struct _stat 44 45 /* 46 * Convert a UTF8 string to Unicode wide character 47 */ 48 LPWSTR 49 _NSSUTIL_UTF8ToWide(const char *buf) 50 { 51 DWORD size; 52 LPWSTR wide; 53 54 if (!buf) { 55 return NULL; 56 } 57 58 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0); 59 if (size == 0) { 60 return NULL; 61 } 62 wide = PORT_Alloc(sizeof(WCHAR) * size); 63 if (!wide) { 64 return NULL; 65 } 66 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size); 67 if (size == 0) { 68 PORT_Free(wide); 69 return NULL; 70 } 71 return wide; 72 } 73 74 static int 75 os_open(const char *filename, int oflag, int pmode) 76 { 77 int fd; 78 79 if (!filename) { 80 return -1; 81 } 82 83 wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename); 84 if (!filenameWide) { 85 return -1; 86 } 87 fd = _wopen(filenameWide, oflag, pmode); 88 PORT_Free(filenameWide); 89 90 return fd; 91 } 92 93 static int 94 os_stat(const char *path, os_stat_type *buffer) 95 { 96 int result; 97 98 if (!path) { 99 return -1; 100 } 101 102 wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path); 103 if (!pathWide) { 104 return -1; 105 } 106 result = _wstat(pathWide, buffer); 107 PORT_Free(pathWide); 108 109 return result; 110 } 111 112 static FILE * 113 os_fopen(const char *filename, const char *mode) 114 { 115 FILE *fp; 116 117 if (!filename || !mode) { 118 return NULL; 119 } 120 121 wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename); 122 if (!filenameWide) { 123 return NULL; 124 } 125 wchar_t *modeWide = _NSSUTIL_UTF8ToWide(mode); 126 if (!modeWide) { 127 PORT_Free(filenameWide); 128 return NULL; 129 } 130 fp = _wfopen(filenameWide, modeWide); 131 PORT_Free(filenameWide); 132 PORT_Free(modeWide); 133 134 return fp; 135 } 136 137 PRStatus 138 _NSSUTIL_Access(const char *path, PRAccessHow how) 139 { 140 int result; 141 142 if (!path) { 143 return PR_FAILURE; 144 } 145 146 int mode; 147 switch (how) { 148 case PR_ACCESS_WRITE_OK: 149 mode = 2; 150 break; 151 case PR_ACCESS_READ_OK: 152 mode = 4; 153 break; 154 case PR_ACCESS_EXISTS: 155 mode = 0; 156 break; 157 default: 158 return PR_FAILURE; 159 } 160 161 wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path); 162 if (!pathWide) { 163 return PR_FAILURE; 164 } 165 result = _waccess(pathWide, mode); 166 PORT_Free(pathWide); 167 168 return result < 0 ? PR_FAILURE : PR_SUCCESS; 169 } 170 171 static PRStatus 172 nssutil_Delete(const char *name) 173 { 174 BOOL result; 175 176 if (!name) { 177 return PR_FAILURE; 178 } 179 180 wchar_t *nameWide = _NSSUTIL_UTF8ToWide(name); 181 if (!nameWide) { 182 return PR_FAILURE; 183 } 184 result = DeleteFileW(nameWide); 185 PORT_Free(nameWide); 186 187 return result ? PR_SUCCESS : PR_FAILURE; 188 } 189 190 static PRStatus 191 nssutil_Rename(const char *from, const char *to) 192 { 193 BOOL result; 194 195 if (!from || !to) { 196 return PR_FAILURE; 197 } 198 199 wchar_t *fromWide = _NSSUTIL_UTF8ToWide(from); 200 if (!fromWide) { 201 return PR_FAILURE; 202 } 203 wchar_t *toWide = _NSSUTIL_UTF8ToWide(to); 204 if (!toWide) { 205 PORT_Free(fromWide); 206 return PR_FAILURE; 207 } 208 result = MoveFileW(fromWide, toWide); 209 PORT_Free(fromWide); 210 PORT_Free(toWide); 211 212 return result ? PR_SUCCESS : PR_FAILURE; 213 } 214 #else 215 #define os_fopen fopen 216 #define os_open open 217 #define os_fdopen fdopen 218 #define os_stat stat 219 #define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC 220 #define os_append_open_flags O_CREAT | O_RDWR | O_APPEND 221 #define os_open_permissions_type mode_t 222 #define os_open_permissions_default 0600 223 #define os_stat_type struct stat 224 #define nssutil_Delete PR_Delete 225 #define nssutil_Rename PR_Rename 226 #endif 227 228 /**************************************************************** 229 * 230 * Secmod database. 231 * 232 * The new secmod database is simply a text file with each of the module 233 * entries in the following form: 234 * 235 * # 236 * # This is a comment The next line is the library to load 237 * library=libmypkcs11.so 238 * name="My PKCS#11 module" 239 * params="my library's param string" 240 * nss="NSS parameters" 241 * other="parameters for other libraries and applications" 242 * 243 * library=libmynextpk11.so 244 * name="My other PKCS#11 module" 245 */ 246 247 /* 248 * Smart string cat functions. Automatically manage the memory. 249 * The first parameter is the destination string. If it's null, we 250 * allocate memory for it. If it's not, we reallocate memory 251 * so the the concanenated string fits. 252 */ 253 static char * 254 nssutil_DupnCat(char *baseString, const char *str, int str_len) 255 { 256 int baseStringLen = baseString ? PORT_Strlen(baseString) : 0; 257 int len = baseStringLen + 1; 258 char *newString; 259 260 len += str_len; 261 newString = (char *)PORT_Realloc(baseString, len); 262 if (newString == NULL) { 263 PORT_Free(baseString); 264 return NULL; 265 } 266 PORT_Memcpy(&newString[baseStringLen], str, str_len); 267 newString[len - 1] = 0; 268 return newString; 269 } 270 271 /* Same as nssutil_DupnCat except it concatenates the full string, not a 272 * partial one */ 273 static char * 274 nssutil_DupCat(char *baseString, const char *str) 275 { 276 return nssutil_DupnCat(baseString, str, PORT_Strlen(str)); 277 } 278 279 /* function to free up all the memory associated with a null terminated 280 * array of module specs */ 281 static SECStatus 282 nssutil_releaseSpecList(char **moduleSpecList) 283 { 284 if (moduleSpecList) { 285 char **index; 286 for (index = moduleSpecList; *index; index++) { 287 PORT_Free(*index); 288 } 289 PORT_Free(moduleSpecList); 290 } 291 return SECSuccess; 292 } 293 294 #define SECMOD_STEP 10 295 static SECStatus 296 nssutil_growList(char ***pModuleList, int *useCount, int last) 297 { 298 char **newModuleList; 299 300 *useCount += SECMOD_STEP; 301 newModuleList = (char **)PORT_Realloc(*pModuleList, 302 *useCount * sizeof(char *)); 303 if (newModuleList == NULL) { 304 return SECFailure; 305 } 306 PORT_Memset(&newModuleList[last], 0, sizeof(char *) * SECMOD_STEP); 307 *pModuleList = newModuleList; 308 return SECSuccess; 309 } 310 311 #ifndef NSS_DISABLE_DBM 312 static char * 313 _NSSUTIL_GetOldSecmodName(const char *dbname, const char *filename) 314 { 315 char *file = NULL; 316 char *dirPath = PORT_Strdup(dbname); 317 char *sep; 318 319 sep = PORT_Strrchr(dirPath, *NSSUTIL_PATH_SEPARATOR); 320 #ifdef _WIN32 321 if (!sep) { 322 /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all 323 * platforms. */ 324 sep = PORT_Strrchr(dirPath, '\\'); 325 } 326 #endif 327 if (sep) { 328 *sep = 0; 329 file = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s", dirPath, filename); 330 } else { 331 file = PR_smprintf("%s", filename); 332 } 333 PORT_Free(dirPath); 334 return file; 335 } 336 #endif // NSS_DISABLE_DBM 337 338 static SECStatus nssutil_AddSecmodDBEntry(const char *appName, 339 const char *filename, 340 const char *dbname, 341 const char *module, PRBool rw); 342 343 enum lfopen_mode { lfopen_truncate, 344 lfopen_append }; 345 346 FILE * 347 lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) 348 { 349 int fd; 350 FILE *file; 351 352 fd = os_open(name, 353 (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, 354 open_perms); 355 if (fd < 0) { 356 return NULL; 357 } 358 file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); 359 if (!file) { 360 close(fd); 361 } 362 /* file inherits fd */ 363 return file; 364 } 365 366 #define MAX_LINE_LENGTH 2048 367 368 /* 369 * Read all the existing modules in out of the file. 370 */ 371 static char ** 372 nssutil_ReadSecmodDB(const char *appName, 373 const char *filename, const char *dbname, 374 char *params, PRBool rw) 375 { 376 FILE *fd = NULL; 377 char **moduleList = NULL; 378 int moduleCount = 1; 379 int useCount = SECMOD_STEP; 380 char line[MAX_LINE_LENGTH]; 381 PRBool internal = PR_FALSE; 382 PRBool skipParams = PR_FALSE; 383 char *moduleString = NULL; 384 char *paramsValue = NULL; 385 PRBool failed = PR_TRUE; 386 387 moduleList = (char **)PORT_ZAlloc(useCount * sizeof(char *)); 388 if (moduleList == NULL) 389 return NULL; 390 391 if (dbname == NULL) { 392 goto return_default; 393 } 394 395 /* do we really want to use streams here */ 396 fd = os_fopen(dbname, "r"); 397 if (fd == NULL) 398 goto done; 399 400 /* 401 * the following loop takes line separated config lines and collapses 402 * the lines to a single string, escaping and quoting as necessary. 403 */ 404 /* loop state variables */ 405 moduleString = NULL; /* current concatenated string */ 406 internal = PR_FALSE; /* is this an internal module */ 407 skipParams = PR_FALSE; /* did we find an override parameter block*/ 408 paramsValue = NULL; /* the current parameter block value */ 409 do { 410 int len; 411 412 if (fgets(line, sizeof(line), fd) == NULL) { 413 goto endloop; 414 } 415 416 /* remove the ending newline */ 417 len = PORT_Strlen(line); 418 if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') { 419 len = len - 2; 420 line[len] = 0; 421 } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) { 422 len--; 423 line[len] = 0; 424 } 425 if (*line == '#') { 426 continue; 427 } 428 if (*line != 0) { 429 /* 430 * The PKCS #11 group standard assumes blocks of strings 431 * separated by new lines, clumped by new lines. Internally 432 * we take strings separated by spaces, so we may need to escape 433 * certain spaces. 434 */ 435 char *value = PORT_Strchr(line, '='); 436 437 /* there is no value, write out the stanza as is */ 438 if (value == NULL || value[1] == 0) { 439 if (moduleString) { 440 moduleString = nssutil_DupnCat(moduleString, " ", 1); 441 if (moduleString == NULL) 442 goto loser; 443 } 444 moduleString = nssutil_DupCat(moduleString, line); 445 if (moduleString == NULL) 446 goto loser; 447 /* value is already quoted, just write it out */ 448 } else if (value[1] == '"') { 449 if (moduleString) { 450 moduleString = nssutil_DupnCat(moduleString, " ", 1); 451 if (moduleString == NULL) 452 goto loser; 453 } 454 moduleString = nssutil_DupCat(moduleString, line); 455 if (moduleString == NULL) 456 goto loser; 457 /* we have an override parameter section, remember that 458 * we found this (see following comment about why this 459 * is necessary). */ 460 if (PORT_Strncasecmp(line, "parameters", 10) == 0) { 461 skipParams = PR_TRUE; 462 } 463 /* 464 * The internal token always overrides it's parameter block 465 * from the passed in parameters, so wait until then end 466 * before we include the parameter block in case we need to 467 * override it. NOTE: if the parameter block is quoted with ("), 468 * this override does not happen. This allows you to override 469 * the application's parameter configuration. 470 * 471 * parameter block state is controlled by the following variables: 472 * skipParams - Bool : set to true of we have an override param 473 * block (all other blocks, either implicit or explicit are 474 * ignored). 475 * paramsValue - char * : pointer to the current param block. In 476 * the absence of overrides, paramsValue is set to the first 477 * parameter block we find. All subsequent blocks are ignored. 478 * When we find an internal token, the application passed 479 * parameters take precident. 480 */ 481 } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { 482 /* already have parameters */ 483 if (paramsValue) { 484 continue; 485 } 486 paramsValue = NSSUTIL_Quote(&value[1], '"'); 487 if (paramsValue == NULL) 488 goto loser; 489 continue; 490 } else { 491 /* may need to quote */ 492 char *newLine; 493 if (moduleString) { 494 moduleString = nssutil_DupnCat(moduleString, " ", 1); 495 if (moduleString == NULL) 496 goto loser; 497 } 498 moduleString = nssutil_DupnCat(moduleString, line, value - line + 1); 499 if (moduleString == NULL) 500 goto loser; 501 newLine = NSSUTIL_Quote(&value[1], '"'); 502 if (newLine == NULL) 503 goto loser; 504 moduleString = nssutil_DupCat(moduleString, newLine); 505 PORT_Free(newLine); 506 if (moduleString == NULL) 507 goto loser; 508 } 509 510 /* check to see if it's internal? */ 511 if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { 512 /* This should be case insensitive! reviewers make 513 * me fix it if it's not */ 514 if (PORT_Strstr(line, "internal")) { 515 internal = PR_TRUE; 516 /* override the parameters */ 517 if (paramsValue) { 518 PORT_Free(paramsValue); 519 } 520 paramsValue = NSSUTIL_Quote(params, '"'); 521 } 522 } 523 continue; 524 } 525 if ((moduleString == NULL) || (*moduleString == 0)) { 526 continue; 527 } 528 529 endloop: 530 /* 531 * if we are here, we have found a complete stanza. Now write out 532 * any param section we may have found. 533 */ 534 if (paramsValue) { 535 /* we had an override */ 536 if (!skipParams) { 537 moduleString = nssutil_DupnCat(moduleString, " parameters=", 12); 538 if (moduleString == NULL) 539 goto loser; 540 moduleString = nssutil_DupCat(moduleString, paramsValue); 541 if (moduleString == NULL) 542 goto loser; 543 } 544 PORT_Free(paramsValue); 545 paramsValue = NULL; 546 } 547 548 if ((moduleCount + 1) >= useCount) { 549 SECStatus rv; 550 rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1); 551 if (rv != SECSuccess) { 552 goto loser; 553 } 554 } 555 556 if (internal && (moduleList[0] == NULL)) { 557 moduleList[0] = moduleString; 558 } else { 559 moduleList[moduleCount] = moduleString; 560 moduleCount++; 561 } 562 moduleString = NULL; 563 internal = PR_FALSE; 564 skipParams = PR_FALSE; 565 } while (!feof(fd)); 566 567 if (moduleString) { 568 PORT_Free(moduleString); 569 moduleString = NULL; 570 } 571 done: 572 #ifndef NSS_DISABLE_DBM 573 /* if we couldn't open a pkcs11 database, look for the old one */ 574 if (fd == NULL) { 575 char *olddbname = _NSSUTIL_GetOldSecmodName(dbname, filename); 576 PRStatus status; 577 578 /* couldn't get the old name */ 579 if (!olddbname) { 580 goto bail; 581 } 582 583 /* old one exists */ 584 status = _NSSUTIL_Access(olddbname, PR_ACCESS_EXISTS); 585 if (status == PR_SUCCESS) { 586 PR_smprintf_free(olddbname); 587 PORT_ZFree(moduleList, useCount * sizeof(char *)); 588 PORT_SetError(SEC_ERROR_LEGACY_DATABASE); 589 return NULL; 590 } 591 592 bail: 593 if (olddbname) { 594 PR_smprintf_free(olddbname); 595 } 596 } 597 #endif // NSS_DISABLE_DBM 598 599 return_default: 600 601 if (!moduleList[0]) { 602 char *newParams; 603 moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1); 604 newParams = NSSUTIL_Quote(params, '"'); 605 if (newParams == NULL) 606 goto loser; 607 moduleString = nssutil_DupCat(moduleString, newParams); 608 PORT_Free(newParams); 609 if (moduleString == NULL) 610 goto loser; 611 moduleString = nssutil_DupCat(moduleString, 612 NSSUTIL_DEFAULT_INTERNAL_INIT2); 613 if (moduleString == NULL) 614 goto loser; 615 moduleString = nssutil_DupCat(moduleString, 616 NSSUTIL_DEFAULT_SFTKN_FLAGS); 617 if (moduleString == NULL) 618 goto loser; 619 moduleString = nssutil_DupCat(moduleString, 620 NSSUTIL_DEFAULT_INTERNAL_INIT3); 621 if (moduleString == NULL) 622 goto loser; 623 moduleList[0] = moduleString; 624 moduleString = NULL; 625 } 626 failed = PR_FALSE; 627 628 loser: 629 /* 630 * cleanup 631 */ 632 /* deal with trust cert db here */ 633 if (moduleString) { 634 PORT_Free(moduleString); 635 moduleString = NULL; 636 } 637 if (paramsValue) { 638 PORT_Free(paramsValue); 639 paramsValue = NULL; 640 } 641 if (failed || (moduleList[0] == NULL)) { 642 /* This is wrong! FIXME */ 643 nssutil_releaseSpecList(moduleList); 644 moduleList = NULL; 645 failed = PR_TRUE; 646 } 647 if (fd != NULL) { 648 fclose(fd); 649 } else if (!failed && rw) { 650 /* update our internal module */ 651 nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw); 652 } 653 return moduleList; 654 } 655 656 static SECStatus 657 nssutil_ReleaseSecmodDBData(const char *appName, 658 const char *filename, const char *dbname, 659 char **moduleSpecList, PRBool rw) 660 { 661 if (moduleSpecList) { 662 nssutil_releaseSpecList(moduleSpecList); 663 } 664 return SECSuccess; 665 } 666 667 /* 668 * Delete a module from the Data Base 669 */ 670 static SECStatus 671 nssutil_DeleteSecmodDBEntry(const char *appName, 672 const char *filename, 673 const char *dbname, 674 const char *args, 675 PRBool rw) 676 { 677 /* SHDB_FIXME implement */ 678 os_stat_type stat_existing; 679 os_open_permissions_type file_mode; 680 FILE *fd = NULL; 681 FILE *fd2 = NULL; 682 char line[MAX_LINE_LENGTH]; 683 char *dbname2 = NULL; 684 char *block = NULL; 685 char *name = NULL; 686 char *lib = NULL; 687 int name_len = 0, lib_len = 0; 688 PRBool skip = PR_FALSE; 689 PRBool found = PR_FALSE; 690 691 if (dbname == NULL) { 692 PORT_SetError(SEC_ERROR_INVALID_ARGS); 693 return SECFailure; 694 } 695 696 if (!rw) { 697 PORT_SetError(SEC_ERROR_READ_ONLY); 698 return SECFailure; 699 } 700 701 dbname2 = PORT_Strdup(dbname); 702 if (dbname2 == NULL) 703 goto loser; 704 dbname2[strlen(dbname) - 1]++; 705 706 /* get the permissions of the existing file, or use the default */ 707 if (!os_stat(dbname, &stat_existing)) { 708 file_mode = stat_existing.st_mode; 709 } else { 710 file_mode = os_open_permissions_default; 711 } 712 713 /* do we really want to use streams here */ 714 fd = os_fopen(dbname, "r"); 715 if (fd == NULL) 716 goto loser; 717 718 fd2 = lfopen(dbname2, lfopen_truncate, file_mode); 719 720 if (fd2 == NULL) 721 goto loser; 722 723 name = NSSUTIL_ArgGetParamValue("name", args); 724 if (name) { 725 name_len = PORT_Strlen(name); 726 } 727 lib = NSSUTIL_ArgGetParamValue("library", args); 728 if (lib) { 729 lib_len = PORT_Strlen(lib); 730 } 731 732 /* 733 * the following loop takes line separated config files and collapses 734 * the lines to a single string, escaping and quoting as necessary. 735 */ 736 /* loop state variables */ 737 block = NULL; 738 skip = PR_FALSE; 739 while (fgets(line, sizeof(line), fd) != NULL) { 740 /* If we are processing a block (we haven't hit a blank line yet */ 741 if (*line != '\n') { 742 /* skip means we are in the middle of a block we are deleting */ 743 if (skip) { 744 continue; 745 } 746 /* if we haven't found the block yet, check to see if this block 747 * matches our requirements */ 748 if (!found && ((name && (PORT_Strncasecmp(line, "name=", 5) == 0) && 749 (PORT_Strncmp(line + 5, name, name_len) == 0)) || 750 (lib && (PORT_Strncasecmp(line, "library=", 8) == 0) && 751 (PORT_Strncmp(line + 8, lib, lib_len) == 0)))) { 752 753 /* yup, we don't need to save any more data, */ 754 PORT_Free(block); 755 block = NULL; 756 /* we don't need to collect more of this block */ 757 skip = PR_TRUE; 758 /* we don't need to continue searching for the block */ 759 found = PR_TRUE; 760 continue; 761 } 762 /* not our match, continue to collect data in this block */ 763 block = nssutil_DupCat(block, line); 764 continue; 765 } 766 /* we've collected a block of data that wasn't the module we were 767 * looking for, write it out */ 768 if (block) { 769 fwrite(block, PORT_Strlen(block), 1, fd2); 770 PORT_Free(block); 771 block = NULL; 772 } 773 /* If we didn't just delete the this block, keep the blank line */ 774 if (!skip) { 775 fputs(line, fd2); 776 } 777 /* we are definately not in a deleted block anymore */ 778 skip = PR_FALSE; 779 } 780 fclose(fd); 781 fclose(fd2); 782 if (found) { 783 /* rename dbname2 to dbname */ 784 nssutil_Delete(dbname); 785 nssutil_Rename(dbname2, dbname); 786 } else { 787 nssutil_Delete(dbname2); 788 } 789 PORT_Free(dbname2); 790 PORT_Free(lib); 791 PORT_Free(name); 792 PORT_Free(block); 793 return SECSuccess; 794 795 loser: 796 if (fd != NULL) { 797 fclose(fd); 798 } 799 if (fd2 != NULL) { 800 fclose(fd2); 801 } 802 if (dbname2) { 803 nssutil_Delete(dbname2); 804 PORT_Free(dbname2); 805 } 806 PORT_Free(lib); 807 PORT_Free(name); 808 return SECFailure; 809 } 810 811 /* 812 * Add a module to the Data base 813 */ 814 static SECStatus 815 nssutil_AddSecmodDBEntry(const char *appName, 816 const char *filename, const char *dbname, 817 const char *module, PRBool rw) 818 { 819 os_stat_type stat_existing; 820 os_open_permissions_type file_mode; 821 FILE *fd = NULL; 822 char *block = NULL; 823 PRBool libFound = PR_FALSE; 824 825 if (dbname == NULL) { 826 PORT_SetError(SEC_ERROR_INVALID_ARGS); 827 return SECFailure; 828 } 829 830 /* can't write to a read only module */ 831 if (!rw) { 832 PORT_SetError(SEC_ERROR_READ_ONLY); 833 return SECFailure; 834 } 835 836 /* remove the previous version if it exists */ 837 (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); 838 839 /* get the permissions of the existing file, or use the default */ 840 if (!os_stat(dbname, &stat_existing)) { 841 file_mode = stat_existing.st_mode; 842 } else { 843 file_mode = os_open_permissions_default; 844 } 845 846 fd = lfopen(dbname, lfopen_append, file_mode); 847 if (fd == NULL) { 848 return SECFailure; 849 } 850 module = NSSUTIL_ArgStrip(module); 851 while (*module) { 852 int count; 853 char *keyEnd = PORT_Strchr(module, '='); 854 char *value; 855 856 if (PORT_Strncmp(module, "library=", 8) == 0) { 857 libFound = PR_TRUE; 858 } 859 if (keyEnd == NULL) { 860 block = nssutil_DupCat(block, module); 861 break; 862 } 863 block = nssutil_DupnCat(block, module, keyEnd - module + 1); 864 if (block == NULL) { 865 goto loser; 866 } 867 value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count); 868 if (value) { 869 block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value)); 870 PORT_Free(value); 871 } 872 if (block == NULL) { 873 goto loser; 874 } 875 block = nssutil_DupnCat(block, "\n", 1); 876 module = keyEnd + 1 + count; 877 module = NSSUTIL_ArgStrip(module); 878 } 879 if (block) { 880 if (!libFound) { 881 fprintf(fd, "library=\n"); 882 } 883 fwrite(block, PORT_Strlen(block), 1, fd); 884 fprintf(fd, "\n"); 885 PORT_Free(block); 886 block = NULL; 887 } 888 fclose(fd); 889 return SECSuccess; 890 891 loser: 892 PORT_Free(block); 893 fclose(fd); 894 return SECFailure; 895 } 896 897 char ** 898 NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args) 899 { 900 char *secmod = NULL; 901 char *appName = NULL; 902 char *filename = NULL; 903 NSSDBType dbType = NSS_DB_TYPE_NONE; 904 PRBool rw; 905 static char *success = "Success"; 906 char **rvstr = NULL; 907 908 secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName, 909 &filename, &rw); 910 if ((dbType == NSS_DB_TYPE_LEGACY) || 911 (dbType == NSS_DB_TYPE_MULTIACCESS)) { 912 /* we can't handle the old database, only softoken can */ 913 PORT_SetError(SEC_ERROR_LEGACY_DATABASE); 914 rvstr = NULL; 915 goto done; 916 } 917 918 switch (function) { 919 case SECMOD_MODULE_DB_FUNCTION_FIND: 920 rvstr = nssutil_ReadSecmodDB(appName, filename, 921 secmod, (char *)parameters, rw); 922 break; 923 case SECMOD_MODULE_DB_FUNCTION_ADD: 924 rvstr = (nssutil_AddSecmodDBEntry(appName, filename, 925 secmod, (char *)args, rw) == SECSuccess) 926 ? &success 927 : NULL; 928 break; 929 case SECMOD_MODULE_DB_FUNCTION_DEL: 930 rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename, 931 secmod, (char *)args, rw) == SECSuccess) 932 ? &success 933 : NULL; 934 break; 935 case SECMOD_MODULE_DB_FUNCTION_RELEASE: 936 rvstr = (nssutil_ReleaseSecmodDBData(appName, filename, 937 secmod, (char **)args, rw) == SECSuccess) 938 ? &success 939 : NULL; 940 break; 941 } 942 done: 943 if (secmod) 944 PR_smprintf_free(secmod); 945 if (appName) 946 PORT_Free(appName); 947 if (filename) 948 PORT_Free(filename); 949 return rvstr; 950 }