Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/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
8
{
256
8
    int baseStringLen = baseString ? PORT_Strlen(baseString) : 0;
257
8
    int len = baseStringLen + 1;
258
8
    char *newString;
259
260
8
    len += str_len;
261
8
    newString = (char *)PORT_Realloc(baseString, len);
262
8
    if (newString == NULL) {
263
0
        PORT_Free(baseString);
264
0
        return NULL;
265
0
    }
266
8
    PORT_Memcpy(&newString[baseStringLen], str, str_len);
267
8
    newString[len - 1] = 0;
268
8
    return newString;
269
8
}
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
8
{
276
8
    return nssutil_DupnCat(baseString, str, PORT_Strlen(str));
277
8
}
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
2
{
284
2
    if (moduleSpecList) {
285
2
        char **index;
286
4
        for (index = moduleSpecList; *index; index++) {
287
2
            PORT_Free(*index);
288
2
        }
289
2
        PORT_Free(moduleSpecList);
290
2
    }
291
2
    return SECSuccess;
292
2
}
293
294
2
#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
static char *
312
_NSSUTIL_GetOldSecmodName(const char *dbname, const char *filename)
313
0
{
314
0
    char *file = NULL;
315
0
    char *dirPath = PORT_Strdup(dbname);
316
0
    char *sep;
317
318
0
    sep = PORT_Strrchr(dirPath, *NSSUTIL_PATH_SEPARATOR);
319
#ifdef _WIN32
320
    if (!sep) {
321
        /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all
322
         * platforms. */
323
        sep = PORT_Strrchr(dirPath, '\\');
324
    }
325
#endif
326
0
    if (sep) {
327
0
        *sep = 0;
328
0
        file = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s", dirPath, filename);
329
0
    } else {
330
0
        file = PR_smprintf("%s", filename);
331
0
    }
332
0
    PORT_Free(dirPath);
333
0
    return file;
334
0
}
335
336
static SECStatus nssutil_AddSecmodDBEntry(const char *appName,
337
                                          const char *filename,
338
                                          const char *dbname,
339
                                          const char *module, PRBool rw);
340
341
enum lfopen_mode { lfopen_truncate,
342
                   lfopen_append };
343
344
FILE *
345
lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms)
346
0
{
347
0
    int fd;
348
0
    FILE *file;
349
350
0
    fd = os_open(name,
351
0
                 (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags,
352
0
                 open_perms);
353
0
    if (fd < 0) {
354
0
        return NULL;
355
0
    }
356
0
    file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+");
357
0
    if (!file) {
358
0
        close(fd);
359
0
    }
360
    /* file inherits fd */
361
0
    return file;
362
0
}
363
364
#define MAX_LINE_LENGTH 2048
365
366
/*
367
 * Read all the existing modules in out of the file.
368
 */
369
static char **
370
nssutil_ReadSecmodDB(const char *appName,
371
                     const char *filename, const char *dbname,
372
                     char *params, PRBool rw)
373
2
{
374
2
    FILE *fd = NULL;
375
2
    char **moduleList = NULL;
376
2
    int moduleCount = 1;
377
2
    int useCount = SECMOD_STEP;
378
2
    char line[MAX_LINE_LENGTH];
379
2
    PRBool internal = PR_FALSE;
380
2
    PRBool skipParams = PR_FALSE;
381
2
    char *moduleString = NULL;
382
2
    char *paramsValue = NULL;
383
2
    PRBool failed = PR_TRUE;
384
385
2
    moduleList = (char **)PORT_ZAlloc(useCount * sizeof(char *));
386
2
    if (moduleList == NULL)
387
0
        return NULL;
388
389
2
    if (dbname == NULL) {
390
2
        goto return_default;
391
2
    }
392
393
    /* do we really want to use streams here */
394
0
    fd = os_fopen(dbname, "r");
395
0
    if (fd == NULL)
396
0
        goto done;
397
398
    /*
399
     * the following loop takes line separated config lines and collapses
400
     * the lines to a single string, escaping and quoting as necessary.
401
     */
402
    /* loop state variables */
403
0
    moduleString = NULL;   /* current concatenated string */
404
0
    internal = PR_FALSE;   /* is this an internal module */
405
0
    skipParams = PR_FALSE; /* did we find an override parameter block*/
406
0
    paramsValue = NULL;    /* the current parameter block value */
407
0
    do {
408
0
        int len;
409
410
0
        if (fgets(line, sizeof(line), fd) == NULL) {
411
0
            goto endloop;
412
0
        }
413
414
        /* remove the ending newline */
415
0
        len = PORT_Strlen(line);
416
0
        if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
417
0
            len = len - 2;
418
0
            line[len] = 0;
419
0
        } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
420
0
            len--;
421
0
            line[len] = 0;
422
0
        }
423
0
        if (*line == '#') {
424
0
            continue;
425
0
        }
426
0
        if (*line != 0) {
427
            /*
428
             * The PKCS #11 group standard assumes blocks of strings
429
             * separated by new lines, clumped by new lines. Internally
430
             * we take strings separated by spaces, so we may need to escape
431
             * certain spaces.
432
             */
433
0
            char *value = PORT_Strchr(line, '=');
434
435
            /* there is no value, write out the stanza as is */
436
0
            if (value == NULL || value[1] == 0) {
437
0
                if (moduleString) {
438
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
439
0
                    if (moduleString == NULL)
440
0
                        goto loser;
441
0
                }
442
0
                moduleString = nssutil_DupCat(moduleString, line);
443
0
                if (moduleString == NULL)
444
0
                    goto loser;
445
                /* value is already quoted, just write it out */
446
0
            } else if (value[1] == '"') {
447
0
                if (moduleString) {
448
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
449
0
                    if (moduleString == NULL)
450
0
                        goto loser;
451
0
                }
452
0
                moduleString = nssutil_DupCat(moduleString, line);
453
0
                if (moduleString == NULL)
454
0
                    goto loser;
455
                /* we have an override parameter section, remember that
456
                 * we found this (see following comment about why this
457
                 * is necessary). */
458
0
                if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
459
0
                    skipParams = PR_TRUE;
460
0
                }
461
                /*
462
                 * The internal token always overrides it's parameter block
463
                 * from the passed in parameters, so wait until then end
464
                 * before we include the parameter block in case we need to
465
                 * override it. NOTE: if the parameter block is quoted with ("),
466
                 * this override does not happen. This allows you to override
467
                 * the application's parameter configuration.
468
                 *
469
                 * parameter block state is controlled by the following variables:
470
                 *  skipParams - Bool : set to true of we have an override param
471
                 *    block (all other blocks, either implicit or explicit are
472
                 *    ignored).
473
                 *  paramsValue - char * : pointer to the current param block. In
474
                 *    the absence of overrides, paramsValue is set to the first
475
                 *    parameter block we find. All subsequent blocks are ignored.
476
                 *    When we find an internal token, the application passed
477
                 *    parameters take precident.
478
                 */
479
0
            } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
480
                /* already have parameters */
481
0
                if (paramsValue) {
482
0
                    continue;
483
0
                }
484
0
                paramsValue = NSSUTIL_Quote(&value[1], '"');
485
0
                if (paramsValue == NULL)
486
0
                    goto loser;
487
0
                continue;
488
0
            } else {
489
                /* may need to quote */
490
0
                char *newLine;
491
0
                if (moduleString) {
492
0
                    moduleString = nssutil_DupnCat(moduleString, " ", 1);
493
0
                    if (moduleString == NULL)
494
0
                        goto loser;
495
0
                }
496
0
                moduleString = nssutil_DupnCat(moduleString, line, value - line + 1);
497
0
                if (moduleString == NULL)
498
0
                    goto loser;
499
0
                newLine = NSSUTIL_Quote(&value[1], '"');
500
0
                if (newLine == NULL)
501
0
                    goto loser;
502
0
                moduleString = nssutil_DupCat(moduleString, newLine);
503
0
                PORT_Free(newLine);
504
0
                if (moduleString == NULL)
505
0
                    goto loser;
506
0
            }
507
508
            /* check to see if it's internal? */
509
0
            if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
510
                /* This should be case insensitive! reviewers make
511
                 * me fix it if it's not */
512
0
                if (PORT_Strstr(line, "internal")) {
513
0
                    internal = PR_TRUE;
514
                    /* override the parameters */
515
0
                    if (paramsValue) {
516
0
                        PORT_Free(paramsValue);
517
0
                    }
518
0
                    paramsValue = NSSUTIL_Quote(params, '"');
519
0
                }
520
0
            }
521
0
            continue;
522
0
        }
523
0
        if ((moduleString == NULL) || (*moduleString == 0)) {
524
0
            continue;
525
0
        }
526
527
0
    endloop:
528
        /*
529
         * if we are here, we have found a complete stanza. Now write out
530
         * any param section we may have found.
531
         */
532
0
        if (paramsValue) {
533
            /* we had an override */
534
0
            if (!skipParams) {
535
0
                moduleString = nssutil_DupnCat(moduleString, " parameters=", 12);
536
0
                if (moduleString == NULL)
537
0
                    goto loser;
538
0
                moduleString = nssutil_DupCat(moduleString, paramsValue);
539
0
                if (moduleString == NULL)
540
0
                    goto loser;
541
0
            }
542
0
            PORT_Free(paramsValue);
543
0
            paramsValue = NULL;
544
0
        }
545
546
0
        if ((moduleCount + 1) >= useCount) {
547
0
            SECStatus rv;
548
0
            rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1);
549
0
            if (rv != SECSuccess) {
550
0
                goto loser;
551
0
            }
552
0
        }
553
554
0
        if (internal) {
555
0
            moduleList[0] = moduleString;
556
0
        } else {
557
0
            moduleList[moduleCount] = moduleString;
558
0
            moduleCount++;
559
0
        }
560
0
        moduleString = NULL;
561
0
        internal = PR_FALSE;
562
0
        skipParams = PR_FALSE;
563
0
    } while (!feof(fd));
564
565
0
    if (moduleString) {
566
0
        PORT_Free(moduleString);
567
0
        moduleString = NULL;
568
0
    }
569
0
done:
570
    /* if we couldn't open a pkcs11 database, look for the old one */
571
0
    if (fd == NULL) {
572
0
        char *olddbname = _NSSUTIL_GetOldSecmodName(dbname, filename);
573
0
        PRStatus status;
574
575
        /* couldn't get the old name */
576
0
        if (!olddbname) {
577
0
            goto bail;
578
0
        }
579
580
        /* old one exists */
581
0
        status = _NSSUTIL_Access(olddbname, PR_ACCESS_EXISTS);
582
0
        if (status == PR_SUCCESS) {
583
0
            PR_smprintf_free(olddbname);
584
0
            PORT_ZFree(moduleList, useCount * sizeof(char *));
585
0
            PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
586
0
            return NULL;
587
0
        }
588
589
0
    bail:
590
0
        if (olddbname) {
591
0
            PR_smprintf_free(olddbname);
592
0
        }
593
0
    }
594
595
2
return_default:
596
597
2
    if (!moduleList[0]) {
598
2
        char *newParams;
599
2
        moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1);
600
2
        newParams = NSSUTIL_Quote(params, '"');
601
2
        if (newParams == NULL)
602
0
            goto loser;
603
2
        moduleString = nssutil_DupCat(moduleString, newParams);
604
2
        PORT_Free(newParams);
605
2
        if (moduleString == NULL)
606
0
            goto loser;
607
2
        moduleString = nssutil_DupCat(moduleString,
608
2
                                      NSSUTIL_DEFAULT_INTERNAL_INIT2);
609
2
        if (moduleString == NULL)
610
0
            goto loser;
611
2
        moduleString = nssutil_DupCat(moduleString,
612
2
                                      NSSUTIL_DEFAULT_SFTKN_FLAGS);
613
2
        if (moduleString == NULL)
614
0
            goto loser;
615
2
        moduleString = nssutil_DupCat(moduleString,
616
2
                                      NSSUTIL_DEFAULT_INTERNAL_INIT3);
617
2
        if (moduleString == NULL)
618
0
            goto loser;
619
2
        moduleList[0] = moduleString;
620
2
        moduleString = NULL;
621
2
    }
622
2
    failed = PR_FALSE;
623
624
2
loser:
625
    /*
626
     * cleanup
627
     */
628
    /* deal with trust cert db here */
629
2
    if (moduleString) {
630
0
        PORT_Free(moduleString);
631
0
        moduleString = NULL;
632
0
    }
633
2
    if (paramsValue) {
634
0
        PORT_Free(paramsValue);
635
0
        paramsValue = NULL;
636
0
    }
637
2
    if (failed || (moduleList[0] == NULL)) {
638
        /* This is wrong! FIXME */
639
0
        nssutil_releaseSpecList(moduleList);
640
0
        moduleList = NULL;
641
0
        failed = PR_TRUE;
642
0
    }
643
2
    if (fd != NULL) {
644
0
        fclose(fd);
645
2
    } else if (!failed && rw) {
646
        /* update our internal module */
647
0
        nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw);
648
0
    }
649
2
    return moduleList;
650
2
}
651
652
static SECStatus
653
nssutil_ReleaseSecmodDBData(const char *appName,
654
                            const char *filename, const char *dbname,
655
                            char **moduleSpecList, PRBool rw)
656
2
{
657
2
    if (moduleSpecList) {
658
2
        nssutil_releaseSpecList(moduleSpecList);
659
2
    }
660
2
    return SECSuccess;
661
2
}
662
663
/*
664
 * Delete a module from the Data Base
665
 */
666
static SECStatus
667
nssutil_DeleteSecmodDBEntry(const char *appName,
668
                            const char *filename,
669
                            const char *dbname,
670
                            const char *args,
671
                            PRBool rw)
672
0
{
673
    /* SHDB_FIXME implement */
674
0
    os_stat_type stat_existing;
675
0
    os_open_permissions_type file_mode;
676
0
    FILE *fd = NULL;
677
0
    FILE *fd2 = NULL;
678
0
    char line[MAX_LINE_LENGTH];
679
0
    char *dbname2 = NULL;
680
0
    char *block = NULL;
681
0
    char *name = NULL;
682
0
    char *lib = NULL;
683
0
    int name_len = 0, lib_len = 0;
684
0
    PRBool skip = PR_FALSE;
685
0
    PRBool found = PR_FALSE;
686
687
0
    if (dbname == NULL) {
688
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
689
0
        return SECFailure;
690
0
    }
691
692
0
    if (!rw) {
693
0
        PORT_SetError(SEC_ERROR_READ_ONLY);
694
0
        return SECFailure;
695
0
    }
696
697
0
    dbname2 = PORT_Strdup(dbname);
698
0
    if (dbname2 == NULL)
699
0
        goto loser;
700
0
    dbname2[strlen(dbname) - 1]++;
701
702
    /* get the permissions of the existing file, or use the default */
703
0
    if (!os_stat(dbname, &stat_existing)) {
704
0
        file_mode = stat_existing.st_mode;
705
0
    } else {
706
0
        file_mode = os_open_permissions_default;
707
0
    }
708
709
    /* do we really want to use streams here */
710
0
    fd = os_fopen(dbname, "r");
711
0
    if (fd == NULL)
712
0
        goto loser;
713
714
0
    fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
715
716
0
    if (fd2 == NULL)
717
0
        goto loser;
718
719
0
    name = NSSUTIL_ArgGetParamValue("name", args);
720
0
    if (name) {
721
0
        name_len = PORT_Strlen(name);
722
0
    }
723
0
    lib = NSSUTIL_ArgGetParamValue("library", args);
724
0
    if (lib) {
725
0
        lib_len = PORT_Strlen(lib);
726
0
    }
727
728
    /*
729
     * the following loop takes line separated config files and collapses
730
     * the lines to a single string, escaping and quoting as necessary.
731
     */
732
    /* loop state variables */
733
0
    block = NULL;
734
0
    skip = PR_FALSE;
735
0
    while (fgets(line, sizeof(line), fd) != NULL) {
736
        /* If we are processing a block (we haven't hit a blank line yet */
737
0
        if (*line != '\n') {
738
            /* skip means we are in the middle of a block we are deleting */
739
0
            if (skip) {
740
0
                continue;
741
0
            }
742
            /* if we haven't found the block yet, check to see if this block
743
             * matches our requirements */
744
0
            if (!found && ((name && (PORT_Strncasecmp(line, "name=", 5) == 0) &&
745
0
                            (PORT_Strncmp(line + 5, name, name_len) == 0)) ||
746
0
                           (lib && (PORT_Strncasecmp(line, "library=", 8) == 0) &&
747
0
                            (PORT_Strncmp(line + 8, lib, lib_len) == 0)))) {
748
749
                /* yup, we don't need to save any more data, */
750
0
                PORT_Free(block);
751
0
                block = NULL;
752
                /* we don't need to collect more of this block */
753
0
                skip = PR_TRUE;
754
                /* we don't need to continue searching for the block */
755
0
                found = PR_TRUE;
756
0
                continue;
757
0
            }
758
            /* not our match, continue to collect data in this block */
759
0
            block = nssutil_DupCat(block, line);
760
0
            continue;
761
0
        }
762
        /* we've collected a block of data that wasn't the module we were
763
         * looking for, write it out */
764
0
        if (block) {
765
0
            fwrite(block, PORT_Strlen(block), 1, fd2);
766
0
            PORT_Free(block);
767
0
            block = NULL;
768
0
        }
769
        /* If we didn't just delete the this block, keep the blank line */
770
0
        if (!skip) {
771
0
            fputs(line, fd2);
772
0
        }
773
        /* we are definately not in a deleted block anymore */
774
0
        skip = PR_FALSE;
775
0
    }
776
0
    fclose(fd);
777
0
    fclose(fd2);
778
0
    if (found) {
779
        /* rename dbname2 to dbname */
780
0
        nssutil_Delete(dbname);
781
0
        nssutil_Rename(dbname2, dbname);
782
0
    } else {
783
0
        nssutil_Delete(dbname2);
784
0
    }
785
0
    PORT_Free(dbname2);
786
0
    PORT_Free(lib);
787
0
    PORT_Free(name);
788
0
    PORT_Free(block);
789
0
    return SECSuccess;
790
791
0
loser:
792
0
    if (fd != NULL) {
793
0
        fclose(fd);
794
0
    }
795
0
    if (fd2 != NULL) {
796
0
        fclose(fd2);
797
0
    }
798
0
    if (dbname2) {
799
0
        nssutil_Delete(dbname2);
800
0
        PORT_Free(dbname2);
801
0
    }
802
0
    PORT_Free(lib);
803
0
    PORT_Free(name);
804
0
    return SECFailure;
805
0
}
806
807
/*
808
 * Add a module to the Data base
809
 */
810
static SECStatus
811
nssutil_AddSecmodDBEntry(const char *appName,
812
                         const char *filename, const char *dbname,
813
                         const char *module, PRBool rw)
814
0
{
815
0
    os_stat_type stat_existing;
816
0
    os_open_permissions_type file_mode;
817
0
    FILE *fd = NULL;
818
0
    char *block = NULL;
819
0
    PRBool libFound = PR_FALSE;
820
821
0
    if (dbname == NULL) {
822
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
823
0
        return SECFailure;
824
0
    }
825
826
    /* can't write to a read only module */
827
0
    if (!rw) {
828
0
        PORT_SetError(SEC_ERROR_READ_ONLY);
829
0
        return SECFailure;
830
0
    }
831
832
    /* remove the previous version if it exists */
833
0
    (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw);
834
835
    /* get the permissions of the existing file, or use the default */
836
0
    if (!os_stat(dbname, &stat_existing)) {
837
0
        file_mode = stat_existing.st_mode;
838
0
    } else {
839
0
        file_mode = os_open_permissions_default;
840
0
    }
841
842
0
    fd = lfopen(dbname, lfopen_append, file_mode);
843
0
    if (fd == NULL) {
844
0
        return SECFailure;
845
0
    }
846
0
    module = NSSUTIL_ArgStrip(module);
847
0
    while (*module) {
848
0
        int count;
849
0
        char *keyEnd = PORT_Strchr(module, '=');
850
0
        char *value;
851
852
0
        if (PORT_Strncmp(module, "library=", 8) == 0) {
853
0
            libFound = PR_TRUE;
854
0
        }
855
0
        if (keyEnd == NULL) {
856
0
            block = nssutil_DupCat(block, module);
857
0
            break;
858
0
        }
859
0
        block = nssutil_DupnCat(block, module, keyEnd - module + 1);
860
0
        if (block == NULL) {
861
0
            goto loser;
862
0
        }
863
0
        value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
864
0
        if (value) {
865
0
            block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
866
0
            PORT_Free(value);
867
0
        }
868
0
        if (block == NULL) {
869
0
            goto loser;
870
0
        }
871
0
        block = nssutil_DupnCat(block, "\n", 1);
872
0
        module = keyEnd + 1 + count;
873
0
        module = NSSUTIL_ArgStrip(module);
874
0
    }
875
0
    if (block) {
876
0
        if (!libFound) {
877
0
            fprintf(fd, "library=\n");
878
0
        }
879
0
        fwrite(block, PORT_Strlen(block), 1, fd);
880
0
        fprintf(fd, "\n");
881
0
        PORT_Free(block);
882
0
        block = NULL;
883
0
    }
884
0
    fclose(fd);
885
0
    return SECSuccess;
886
887
0
loser:
888
0
    PORT_Free(block);
889
0
    fclose(fd);
890
0
    return SECFailure;
891
0
}
892
893
char **
894
NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args)
895
4
{
896
4
    char *secmod = NULL;
897
4
    char *appName = NULL;
898
4
    char *filename = NULL;
899
4
    NSSDBType dbType = NSS_DB_TYPE_NONE;
900
4
    PRBool rw;
901
4
    static char *success = "Success";
902
4
    char **rvstr = NULL;
903
904
4
    secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
905
4
                                    &filename, &rw);
906
4
    if ((dbType == NSS_DB_TYPE_LEGACY) ||
907
4
        (dbType == NSS_DB_TYPE_MULTIACCESS)) {
908
        /* we can't handle the old database, only softoken can */
909
0
        PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
910
0
        rvstr = NULL;
911
0
        goto done;
912
0
    }
913
914
4
    switch (function) {
915
2
        case SECMOD_MODULE_DB_FUNCTION_FIND:
916
2
            rvstr = nssutil_ReadSecmodDB(appName, filename,
917
2
                                         secmod, (char *)parameters, rw);
918
2
            break;
919
0
        case SECMOD_MODULE_DB_FUNCTION_ADD:
920
0
            rvstr = (nssutil_AddSecmodDBEntry(appName, filename,
921
0
                                              secmod, (char *)args, rw) == SECSuccess)
922
0
                        ? &success
923
0
                        : NULL;
924
0
            break;
925
0
        case SECMOD_MODULE_DB_FUNCTION_DEL:
926
0
            rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename,
927
0
                                                 secmod, (char *)args, rw) == SECSuccess)
928
0
                        ? &success
929
0
                        : NULL;
930
0
            break;
931
2
        case SECMOD_MODULE_DB_FUNCTION_RELEASE:
932
2
            rvstr = (nssutil_ReleaseSecmodDBData(appName, filename,
933
2
                                                 secmod, (char **)args, rw) == SECSuccess)
934
2
                        ? &success
935
2
                        : NULL;
936
2
            break;
937
4
    }
938
4
done:
939
4
    if (secmod)
940
0
        PR_smprintf_free(secmod);
941
4
    if (appName)
942
0
        PORT_Free(appName);
943
4
    if (filename)
944
0
        PORT_Free(filename);
945
4
    return rvstr;
946
4
}