Coverage Report

Created: 2018-09-25 14:53

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