tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }