Coverage Report

Created: 2025-07-11 07:04

/src/nss/lib/util/utilmod.c
Line
Count
Source (jump to first uncovered line)
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
0
#define os_fopen fopen
216
0
#define os_open open
217
0
#define os_fdopen fdopen
218
0
#define os_stat stat
219
0
#define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC
220
0
#define os_append_open_flags O_CREAT | O_RDWR | O_APPEND
221
0
#define os_open_permissions_type mode_t
222
0
#define os_open_permissions_default 0600
223
0
#define os_stat_type struct stat
224
0
#define nssutil_Delete PR_Delete
225
0
#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
0
{
256
0
    int baseStringLen = baseString ? PORT_Strlen(baseString) : 0;
257
0
    int len = baseStringLen + 1;
258
0
    char *newString;
259
260
0
    len += str_len;
261
0
    newString = (char *)PORT_Realloc(baseString, len);
262
0
    if (newString == NULL) {
263
0
        PORT_Free(baseString);
264
0
        return NULL;
265
0
    }
266
0
    PORT_Memcpy(&newString[baseStringLen], str, str_len);
267
0
    newString[len - 1] = 0;
268
0
    return newString;
269
0
}
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
0
{
276
0
    return nssutil_DupnCat(baseString, str, PORT_Strlen(str));
277
0
}
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
0
{
284
0
    if (moduleSpecList) {
285
0
        char **index;
286
0
        for (index = moduleSpecList; *index; index++) {
287
0
            PORT_Free(*index);
288
0
        }
289
0
        PORT_Free(moduleSpecList);
290
0
    }
291
0
    return SECSuccess;
292
0
}
293
294
0
#define SECMOD_STEP 10
295
static SECStatus
296
nssutil_growList(char ***pModuleList, int *useCount, int last)
297
0
{
298
0
    char **newModuleList;
299
300
0
    *useCount += SECMOD_STEP;
301
0
    newModuleList = (char **)PORT_Realloc(*pModuleList,
302
0
                                          *useCount * sizeof(char *));
303
0
    if (newModuleList == NULL) {
304
0
        return SECFailure;
305
0
    }
306
0
    PORT_Memset(&newModuleList[last], 0, sizeof(char *) * SECMOD_STEP);
307
0
    *pModuleList = newModuleList;
308
0
    return SECSuccess;
309
0
}
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
0
{
349
0
    int fd;
350
0
    FILE *file;
351
352
0
    fd = os_open(name,
353
0
                 (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags,
354
0
                 open_perms);
355
0
    if (fd < 0) {
356
0
        return NULL;
357
0
    }
358
0
    file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+");
359
0
    if (!file) {
360
0
        close(fd);
361
0
    }
362
    /* file inherits fd */
363
0
    return file;
364
0
}
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
0
{
376
0
    FILE *fd = NULL;
377
0
    char **moduleList = NULL;
378
0
    int moduleCount = 1;
379
0
    int useCount = SECMOD_STEP;
380
0
    char line[MAX_LINE_LENGTH];
381
0
    PRBool internal = PR_FALSE;
382
0
    PRBool skipParams = PR_FALSE;
383
0
    char *moduleString = NULL;
384
0
    char *paramsValue = NULL;
385
0
    PRBool failed = PR_TRUE;
386
387
0
    moduleList = (char **)PORT_ZAlloc(useCount * sizeof(char *));
388
0
    if (moduleList == NULL)
389
0
        return NULL;
390
391
0
    if (dbname == NULL) {
392
0
        goto return_default;
393
0
    }
394
395
    /* do we really want to use streams here */
396
0
    fd = os_fopen(dbname, "r");
397
0
    if (fd == NULL)
398
0
        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
0
    moduleString = NULL;   /* current concatenated string */
406
0
    internal = PR_FALSE;   /* is this an internal module */
407
0
    skipParams = PR_FALSE; /* did we find an override parameter block*/
408
0
    paramsValue = NULL;    /* the current parameter block value */
409
0
    do {
410
0
        int len;
411
412
0
        if (fgets(line, sizeof(line), fd) == NULL) {
413
0
            goto endloop;
414
0
        }
415
416
        /* remove the ending newline */
417
0
        len = PORT_Strlen(line);
418
0
        if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
419
0
            len = len - 2;
420
0
            line[len] = 0;
421
0
        } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
422
0
            len--;
423
0
            line[len] = 0;
424
0
        }
425
0
        if (*line == '#') {
426
0
            continue;
427
0
        }
428
0
        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
0
            char *value = PORT_Strchr(line, '=');
436
437
            /* there is no value, write out the stanza as is */
438
0
            if (value == NULL || value[1] == 0) {
439
0
                if (moduleString) {
440
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
441
0
                    if (moduleString == NULL)
442
0
                        goto loser;
443
0
                }
444
0
                moduleString = nssutil_DupCat(moduleString, line);
445
0
                if (moduleString == NULL)
446
0
                    goto loser;
447
                /* value is already quoted, just write it out */
448
0
            } else if (value[1] == '"') {
449
0
                if (moduleString) {
450
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
451
0
                    if (moduleString == NULL)
452
0
                        goto loser;
453
0
                }
454
0
                moduleString = nssutil_DupCat(moduleString, line);
455
0
                if (moduleString == NULL)
456
0
                    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
0
                if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
461
0
                    skipParams = PR_TRUE;
462
0
                }
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
0
            } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
482
                /* already have parameters */
483
0
                if (paramsValue) {
484
0
                    continue;
485
0
                }
486
0
                paramsValue = NSSUTIL_Quote(&value[1], '"');
487
0
                if (paramsValue == NULL)
488
0
                    goto loser;
489
0
                continue;
490
0
            } else {
491
                /* may need to quote */
492
0
                char *newLine;
493
0
                if (moduleString) {
494
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
495
0
                    if (moduleString == NULL)
496
0
                        goto loser;
497
0
                }
498
0
                moduleString = nssutil_DupnCat(moduleString, line, value - line + 1);
499
0
                if (moduleString == NULL)
500
0
                    goto loser;
501
0
                newLine = NSSUTIL_Quote(&value[1], '"');
502
0
                if (newLine == NULL)
503
0
                    goto loser;
504
0
                moduleString = nssutil_DupCat(moduleString, newLine);
505
0
                PORT_Free(newLine);
506
0
                if (moduleString == NULL)
507
0
                    goto loser;
508
0
            }
509
510
            /* check to see if it's internal? */
511
0
            if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
512
                /* This should be case insensitive! reviewers make
513
                 * me fix it if it's not */
514
0
                if (PORT_Strstr(line, "internal")) {
515
0
                    internal = PR_TRUE;
516
                    /* override the parameters */
517
0
                    if (paramsValue) {
518
0
                        PORT_Free(paramsValue);
519
0
                    }
520
0
                    paramsValue = NSSUTIL_Quote(params, '"');
521
0
                }
522
0
            }
523
0
            continue;
524
0
        }
525
0
        if ((moduleString == NULL) || (*moduleString == 0)) {
526
0
            continue;
527
0
        }
528
529
0
    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
0
        if (paramsValue) {
535
            /* we had an override */
536
0
            if (!skipParams) {
537
0
                moduleString = nssutil_DupnCat(moduleString, " parameters=", 12);
538
0
                if (moduleString == NULL)
539
0
                    goto loser;
540
0
                moduleString = nssutil_DupCat(moduleString, paramsValue);
541
0
                if (moduleString == NULL)
542
0
                    goto loser;
543
0
            }
544
0
            PORT_Free(paramsValue);
545
0
            paramsValue = NULL;
546
0
        }
547
548
0
        if ((moduleCount + 1) >= useCount) {
549
0
            SECStatus rv;
550
0
            rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1);
551
0
            if (rv != SECSuccess) {
552
0
                goto loser;
553
0
            }
554
0
        }
555
556
0
        if (internal) {
557
0
            moduleList[0] = moduleString;
558
0
        } else {
559
0
            moduleList[moduleCount] = moduleString;
560
0
            moduleCount++;
561
0
        }
562
0
        moduleString = NULL;
563
0
        internal = PR_FALSE;
564
0
        skipParams = PR_FALSE;
565
0
    } while (!feof(fd));
566
567
0
    if (moduleString) {
568
0
        PORT_Free(moduleString);
569
0
        moduleString = NULL;
570
0
    }
571
0
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
0
return_default:
600
601
0
    if (!moduleList[0]) {
602
0
        char *newParams;
603
0
        moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1);
604
0
        newParams = NSSUTIL_Quote(params, '"');
605
0
        if (newParams == NULL)
606
0
            goto loser;
607
0
        moduleString = nssutil_DupCat(moduleString, newParams);
608
0
        PORT_Free(newParams);
609
0
        if (moduleString == NULL)
610
0
            goto loser;
611
0
        moduleString = nssutil_DupCat(moduleString,
612
0
                                      NSSUTIL_DEFAULT_INTERNAL_INIT2);
613
0
        if (moduleString == NULL)
614
0
            goto loser;
615
0
        moduleString = nssutil_DupCat(moduleString,
616
0
                                      NSSUTIL_DEFAULT_SFTKN_FLAGS);
617
0
        if (moduleString == NULL)
618
0
            goto loser;
619
0
        moduleString = nssutil_DupCat(moduleString,
620
0
                                      NSSUTIL_DEFAULT_INTERNAL_INIT3);
621
0
        if (moduleString == NULL)
622
0
            goto loser;
623
0
        moduleList[0] = moduleString;
624
0
        moduleString = NULL;
625
0
    }
626
0
    failed = PR_FALSE;
627
628
0
loser:
629
    /*
630
     * cleanup
631
     */
632
    /* deal with trust cert db here */
633
0
    if (moduleString) {
634
0
        PORT_Free(moduleString);
635
0
        moduleString = NULL;
636
0
    }
637
0
    if (paramsValue) {
638
0
        PORT_Free(paramsValue);
639
0
        paramsValue = NULL;
640
0
    }
641
0
    if (failed || (moduleList[0] == NULL)) {
642
        /* This is wrong! FIXME */
643
0
        nssutil_releaseSpecList(moduleList);
644
0
        moduleList = NULL;
645
0
        failed = PR_TRUE;
646
0
    }
647
0
    if (fd != NULL) {
648
0
        fclose(fd);
649
0
    } else if (!failed && rw) {
650
        /* update our internal module */
651
0
        nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw);
652
0
    }
653
0
    return moduleList;
654
0
}
655
656
static SECStatus
657
nssutil_ReleaseSecmodDBData(const char *appName,
658
                            const char *filename, const char *dbname,
659
                            char **moduleSpecList, PRBool rw)
660
0
{
661
0
    if (moduleSpecList) {
662
0
        nssutil_releaseSpecList(moduleSpecList);
663
0
    }
664
0
    return SECSuccess;
665
0
}
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
0
{
677
    /* SHDB_FIXME implement */
678
0
    os_stat_type stat_existing;
679
0
    os_open_permissions_type file_mode;
680
0
    FILE *fd = NULL;
681
0
    FILE *fd2 = NULL;
682
0
    char line[MAX_LINE_LENGTH];
683
0
    char *dbname2 = NULL;
684
0
    char *block = NULL;
685
0
    char *name = NULL;
686
0
    char *lib = NULL;
687
0
    int name_len = 0, lib_len = 0;
688
0
    PRBool skip = PR_FALSE;
689
0
    PRBool found = PR_FALSE;
690
691
0
    if (dbname == NULL) {
692
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
693
0
        return SECFailure;
694
0
    }
695
696
0
    if (!rw) {
697
0
        PORT_SetError(SEC_ERROR_READ_ONLY);
698
0
        return SECFailure;
699
0
    }
700
701
0
    dbname2 = PORT_Strdup(dbname);
702
0
    if (dbname2 == NULL)
703
0
        goto loser;
704
0
    dbname2[strlen(dbname) - 1]++;
705
706
    /* get the permissions of the existing file, or use the default */
707
0
    if (!os_stat(dbname, &stat_existing)) {
708
0
        file_mode = stat_existing.st_mode;
709
0
    } else {
710
0
        file_mode = os_open_permissions_default;
711
0
    }
712
713
    /* do we really want to use streams here */
714
0
    fd = os_fopen(dbname, "r");
715
0
    if (fd == NULL)
716
0
        goto loser;
717
718
0
    fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
719
720
0
    if (fd2 == NULL)
721
0
        goto loser;
722
723
0
    name = NSSUTIL_ArgGetParamValue("name", args);
724
0
    if (name) {
725
0
        name_len = PORT_Strlen(name);
726
0
    }
727
0
    lib = NSSUTIL_ArgGetParamValue("library", args);
728
0
    if (lib) {
729
0
        lib_len = PORT_Strlen(lib);
730
0
    }
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
0
    block = NULL;
738
0
    skip = PR_FALSE;
739
0
    while (fgets(line, sizeof(line), fd) != NULL) {
740
        /* If we are processing a block (we haven't hit a blank line yet */
741
0
        if (*line != '\n') {
742
            /* skip means we are in the middle of a block we are deleting */
743
0
            if (skip) {
744
0
                continue;
745
0
            }
746
            /* if we haven't found the block yet, check to see if this block
747
             * matches our requirements */
748
0
            if (!found && ((name && (PORT_Strncasecmp(line, "name=", 5) == 0) &&
749
0
                            (PORT_Strncmp(line + 5, name, name_len) == 0)) ||
750
0
                           (lib && (PORT_Strncasecmp(line, "library=", 8) == 0) &&
751
0
                            (PORT_Strncmp(line + 8, lib, lib_len) == 0)))) {
752
753
                /* yup, we don't need to save any more data, */
754
0
                PORT_Free(block);
755
0
                block = NULL;
756
                /* we don't need to collect more of this block */
757
0
                skip = PR_TRUE;
758
                /* we don't need to continue searching for the block */
759
0
                found = PR_TRUE;
760
0
                continue;
761
0
            }
762
            /* not our match, continue to collect data in this block */
763
0
            block = nssutil_DupCat(block, line);
764
0
            continue;
765
0
        }
766
        /* we've collected a block of data that wasn't the module we were
767
         * looking for, write it out */
768
0
        if (block) {
769
0
            fwrite(block, PORT_Strlen(block), 1, fd2);
770
0
            PORT_Free(block);
771
0
            block = NULL;
772
0
        }
773
        /* If we didn't just delete the this block, keep the blank line */
774
0
        if (!skip) {
775
0
            fputs(line, fd2);
776
0
        }
777
        /* we are definately not in a deleted block anymore */
778
0
        skip = PR_FALSE;
779
0
    }
780
0
    fclose(fd);
781
0
    fclose(fd2);
782
0
    if (found) {
783
        /* rename dbname2 to dbname */
784
0
        nssutil_Delete(dbname);
785
0
        nssutil_Rename(dbname2, dbname);
786
0
    } else {
787
0
        nssutil_Delete(dbname2);
788
0
    }
789
0
    PORT_Free(dbname2);
790
0
    PORT_Free(lib);
791
0
    PORT_Free(name);
792
0
    PORT_Free(block);
793
0
    return SECSuccess;
794
795
0
loser:
796
0
    if (fd != NULL) {
797
0
        fclose(fd);
798
0
    }
799
0
    if (fd2 != NULL) {
800
0
        fclose(fd2);
801
0
    }
802
0
    if (dbname2) {
803
0
        nssutil_Delete(dbname2);
804
0
        PORT_Free(dbname2);
805
0
    }
806
0
    PORT_Free(lib);
807
0
    PORT_Free(name);
808
0
    return SECFailure;
809
0
}
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
0
{
819
0
    os_stat_type stat_existing;
820
0
    os_open_permissions_type file_mode;
821
0
    FILE *fd = NULL;
822
0
    char *block = NULL;
823
0
    PRBool libFound = PR_FALSE;
824
825
0
    if (dbname == NULL) {
826
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
827
0
        return SECFailure;
828
0
    }
829
830
    /* can't write to a read only module */
831
0
    if (!rw) {
832
0
        PORT_SetError(SEC_ERROR_READ_ONLY);
833
0
        return SECFailure;
834
0
    }
835
836
    /* remove the previous version if it exists */
837
0
    (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw);
838
839
    /* get the permissions of the existing file, or use the default */
840
0
    if (!os_stat(dbname, &stat_existing)) {
841
0
        file_mode = stat_existing.st_mode;
842
0
    } else {
843
0
        file_mode = os_open_permissions_default;
844
0
    }
845
846
0
    fd = lfopen(dbname, lfopen_append, file_mode);
847
0
    if (fd == NULL) {
848
0
        return SECFailure;
849
0
    }
850
0
    module = NSSUTIL_ArgStrip(module);
851
0
    while (*module) {
852
0
        int count;
853
0
        char *keyEnd = PORT_Strchr(module, '=');
854
0
        char *value;
855
856
0
        if (PORT_Strncmp(module, "library=", 8) == 0) {
857
0
            libFound = PR_TRUE;
858
0
        }
859
0
        if (keyEnd == NULL) {
860
0
            block = nssutil_DupCat(block, module);
861
0
            break;
862
0
        }
863
0
        block = nssutil_DupnCat(block, module, keyEnd - module + 1);
864
0
        if (block == NULL) {
865
0
            goto loser;
866
0
        }
867
0
        value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
868
0
        if (value) {
869
0
            block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
870
0
            PORT_Free(value);
871
0
        }
872
0
        if (block == NULL) {
873
0
            goto loser;
874
0
        }
875
0
        block = nssutil_DupnCat(block, "\n", 1);
876
0
        module = keyEnd + 1 + count;
877
0
        module = NSSUTIL_ArgStrip(module);
878
0
    }
879
0
    if (block) {
880
0
        if (!libFound) {
881
0
            fprintf(fd, "library=\n");
882
0
        }
883
0
        fwrite(block, PORT_Strlen(block), 1, fd);
884
0
        fprintf(fd, "\n");
885
0
        PORT_Free(block);
886
0
        block = NULL;
887
0
    }
888
0
    fclose(fd);
889
0
    return SECSuccess;
890
891
0
loser:
892
0
    PORT_Free(block);
893
0
    fclose(fd);
894
0
    return SECFailure;
895
0
}
896
897
char **
898
NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args)
899
0
{
900
0
    char *secmod = NULL;
901
0
    char *appName = NULL;
902
0
    char *filename = NULL;
903
0
    NSSDBType dbType = NSS_DB_TYPE_NONE;
904
0
    PRBool rw;
905
0
    static char *success = "Success";
906
0
    char **rvstr = NULL;
907
908
0
    secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
909
0
                                    &filename, &rw);
910
0
    if ((dbType == NSS_DB_TYPE_LEGACY) ||
911
0
        (dbType == NSS_DB_TYPE_MULTIACCESS)) {
912
        /* we can't handle the old database, only softoken can */
913
0
        PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
914
0
        rvstr = NULL;
915
0
        goto done;
916
0
    }
917
918
0
    switch (function) {
919
0
        case SECMOD_MODULE_DB_FUNCTION_FIND:
920
0
            rvstr = nssutil_ReadSecmodDB(appName, filename,
921
0
                                         secmod, (char *)parameters, rw);
922
0
            break;
923
0
        case SECMOD_MODULE_DB_FUNCTION_ADD:
924
0
            rvstr = (nssutil_AddSecmodDBEntry(appName, filename,
925
0
                                              secmod, (char *)args, rw) == SECSuccess)
926
0
                        ? &success
927
0
                        : NULL;
928
0
            break;
929
0
        case SECMOD_MODULE_DB_FUNCTION_DEL:
930
0
            rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename,
931
0
                                                 secmod, (char *)args, rw) == SECSuccess)
932
0
                        ? &success
933
0
                        : NULL;
934
0
            break;
935
0
        case SECMOD_MODULE_DB_FUNCTION_RELEASE:
936
0
            rvstr = (nssutil_ReleaseSecmodDBData(appName, filename,
937
0
                                                 secmod, (char **)args, rw) == SECSuccess)
938
0
                        ? &success
939
0
                        : NULL;
940
0
            break;
941
0
    }
942
0
done:
943
0
    if (secmod)
944
0
        PR_smprintf_free(secmod);
945
0
    if (appName)
946
0
        PORT_Free(appName);
947
0
    if (filename)
948
0
        PORT_Free(filename);
949
0
    return rvstr;
950
0
}