Bug Summary

File:root/firefox-clang/security/nss/lib/util/utilmod.c
Warning:line 412, column 13
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name utilmod.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/util/util_nssutil -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/util/util_nssutil -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG -D NSS_FIPS_DISABLED -D NSS_NO_INIT_SUPPORT -D NSS_X86_OR_X64 -D NSS_X64 -D NSS_USE_64 -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -D LINUX2_1 -D LINUX -D linux -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D HAVE_STRERROR -D XP_UNIX -D _REENTRANT -D NSS_DISABLE_DBM -D NSS_DISABLE_LIBPKIX -I /root/firefox-clang/security/nss/lib/util -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/security/nss/lib/util/util_nssutil -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/private/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c /root/firefox-clang/security/nss/lib/util/utilmod.c
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_UNIX1
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_fdopenfdopen _fdopen
39#define os_truncate_open_flags0100 | 02 | 01000 _O_CREAT | _O_RDWR | _O_TRUNC
40#define os_append_open_flags0100 | 02 | 02000 _O_CREAT | _O_RDWR | _O_APPEND
41#define os_open_permissions_typemode_t int
42#define os_open_permissions_default0600 _S_IREAD | _S_IWRITE
43#define os_stat_typestruct stat struct _stat
44
45/*
46 * Convert a UTF8 string to Unicode wide character
47 */
48LPWSTR
49_NSSUTIL_UTF8ToWide(const char *buf)
50{
51 DWORD size;
52 LPWSTR wide;
53
54 if (!buf) {
55 return NULL((void*)0);
56 }
57
58 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL((void*)0), 0);
59 if (size == 0) {
60 return NULL((void*)0);
61 }
62 wide = PORT_AllocPORT_Alloc_Util(sizeof(WCHAR) * size);
63 if (!wide) {
64 return NULL((void*)0);
65 }
66 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size);
67 if (size == 0) {
68 PORT_FreePORT_Free_Util(wide);
69 return NULL((void*)0);
70 }
71 return wide;
72}
73
74static int
75os_openopen(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_FreePORT_Free_Util(filenameWide);
89
90 return fd;
91}
92
93static int
94os_statstat(const char *path, os_stat_typestruct stat *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_FreePORT_Free_Util(pathWide);
108
109 return result;
110}
111
112static FILE *
113os_fopenfopen(const char *filename, const char *mode)
114{
115 FILE *fp;
116
117 if (!filename || !mode) {
118 return NULL((void*)0);
119 }
120
121 wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
122 if (!filenameWide) {
123 return NULL((void*)0);
124 }
125 wchar_t *modeWide = _NSSUTIL_UTF8ToWide(mode);
126 if (!modeWide) {
127 PORT_FreePORT_Free_Util(filenameWide);
128 return NULL((void*)0);
129 }
130 fp = _wfopen(filenameWide, modeWide);
131 PORT_FreePORT_Free_Util(filenameWide);
132 PORT_FreePORT_Free_Util(modeWide);
133
134 return fp;
135}
136
137PRStatus
138_NSSUTIL_Access(const char *path, PRAccessHow how)PR_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_FreePORT_Free_Util(pathWide);
167
168 return result < 0 ? PR_FAILURE : PR_SUCCESS;
169}
170
171static PRStatus
172nssutil_DeletePR_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_FreePORT_Free_Util(nameWide);
186
187 return result ? PR_SUCCESS : PR_FAILURE;
188}
189
190static PRStatus
191nssutil_RenamePR_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_FreePORT_Free_Util(fromWide);
206 return PR_FAILURE;
207 }
208 result = MoveFileW(fromWide, toWide);
209 PORT_FreePORT_Free_Util(fromWide);
210 PORT_FreePORT_Free_Util(toWide);
211
212 return result ? PR_SUCCESS : PR_FAILURE;
213}
214#else
215#define os_fopenfopen fopen
216#define os_openopen open
217#define os_fdopenfdopen fdopen
218#define os_statstat stat
219#define os_truncate_open_flags0100 | 02 | 01000 O_CREAT0100 | O_RDWR02 | O_TRUNC01000
220#define os_append_open_flags0100 | 02 | 02000 O_CREAT0100 | O_RDWR02 | O_APPEND02000
221#define os_open_permissions_typemode_t mode_t
222#define os_open_permissions_default0600 0600
223#define os_stat_typestruct stat struct stat
224#define nssutil_DeletePR_Delete PR_Delete
225#define nssutil_RenamePR_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 */
253static char *
254nssutil_DupnCat(char *baseString, const char *str, int str_len)
255{
256 int baseStringLen = baseString ? PORT_Strlen(baseString)strlen(baseString) : 0;
257 int len = baseStringLen + 1;
258 char *newString;
259
260 len += str_len;
261 newString = (char *)PORT_ReallocPORT_Realloc_Util(baseString, len);
262 if (newString == NULL((void*)0)) {
263 PORT_FreePORT_Free_Util(baseString);
264 return NULL((void*)0);
265 }
266 PORT_Memcpymemcpy(&newString[baseStringLen], str, str_len);
267 newString[len - 1] = 0;
268 return newString;
269}
270
271/* Same as nssutil_DupnCat except it concatenates the full string, not a
272 * partial one */
273static char *
274nssutil_DupCat(char *baseString, const char *str)
275{
276 return nssutil_DupnCat(baseString, str, PORT_Strlen(str)strlen(str));
277}
278
279/* function to free up all the memory associated with a null terminated
280 * array of module specs */
281static SECStatus
282nssutil_releaseSpecList(char **moduleSpecList)
283{
284 if (moduleSpecList) {
285 char **index;
286 for (index = moduleSpecList; *index; index++) {
287 PORT_FreePORT_Free_Util(*index);
288 }
289 PORT_FreePORT_Free_Util(moduleSpecList);
290 }
291 return SECSuccess;
292}
293
294#define SECMOD_STEP10 10
295static SECStatus
296nssutil_growList(char ***pModuleList, int *useCount, int last)
297{
298 char **newModuleList;
299
300 *useCount += SECMOD_STEP10;
301 newModuleList = (char **)PORT_ReallocPORT_Realloc_Util(*pModuleList,
302 *useCount * sizeof(char *));
303 if (newModuleList == NULL((void*)0)) {
304 return SECFailure;
305 }
306 PORT_Memsetmemset(&newModuleList[last], 0, sizeof(char *) * SECMOD_STEP10);
307 *pModuleList = newModuleList;
308 return SECSuccess;
309}
310
311#ifndef NSS_DISABLE_DBM1
312static char *
313_NSSUTIL_GetOldSecmodName(const char *dbname, const char *filename)
314{
315 char *file = NULL((void*)0);
316 char *dirPath = PORT_StrdupPORT_Strdup_Util(dbname);
317 char *sep;
318
319 sep = PORT_Strrchrstrrchr(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_Strrchrstrrchr(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_FreePORT_Free_Util(dirPath);
334 return file;
335}
336#endif // NSS_DISABLE_DBM
337
338static SECStatus nssutil_AddSecmodDBEntry(const char *appName,
339 const char *filename,
340 const char *dbname,
341 const char *module, PRBool rw);
342
343enum lfopen_mode { lfopen_truncate,
344 lfopen_append };
345
346FILE *
347lfopen(const char *name, enum lfopen_mode om, os_open_permissions_typemode_t open_perms)
348{
349 int fd;
350 FILE *file;
351
352 fd = os_openopen(name,
353 (om == lfopen_truncate) ? os_truncate_open_flags0100 | 02 | 01000 : os_append_open_flags0100 | 02 | 02000,
354 open_perms);
355 if (fd < 0) {
356 return NULL((void*)0);
357 }
358 file = os_fdopenfdopen(fd, (om == lfopen_truncate) ? "w+" : "a+");
359 if (!file) {
360 close(fd);
361 }
362 /* file inherits fd */
363 return file;
364}
365
366#define MAX_LINE_LENGTH2048 2048
367
368/*
369 * Read all the existing modules in out of the file.
370 */
371static char **
372nssutil_ReadSecmodDB(const char *appName,
373 const char *filename, const char *dbname,
374 char *params, PRBool rw)
375{
376 FILE *fd = NULL((void*)0);
377 char **moduleList = NULL((void*)0);
378 int moduleCount = 1;
379 int useCount = SECMOD_STEP10;
380 char line[MAX_LINE_LENGTH2048];
381 PRBool internal = PR_FALSE0;
382 PRBool skipParams = PR_FALSE0;
383 char *moduleString = NULL((void*)0);
384 char *paramsValue = NULL((void*)0);
385 PRBool failed = PR_TRUE1;
386
387 moduleList = (char **)PORT_ZAllocPORT_ZAlloc_Util(useCount * sizeof(char *));
388 if (moduleList == NULL((void*)0))
1
Assuming 'moduleList' is not equal to NULL
2
Taking false branch
389 return NULL((void*)0);
390
391 if (dbname == NULL((void*)0)) {
3
Assuming 'dbname' is not equal to NULL
4
Taking false branch
392 goto return_default;
393 }
394
395 /* do we really want to use streams here */
396 fd = os_fopenfopen(dbname, "r");
397 if (fd
4.1
'fd' is not equal to NULL
== NULL((void*)0))
5
Taking false branch
398 goto done;
399
400 /*
401 * the following loop takes line separated config lines and collapses
402 * the lines to a single string, escaping and quoting as necessary.
403 */
404 /* loop state variables */
405 moduleString = NULL((void*)0); /* current concatenated string */
406 internal = PR_FALSE0; /* is this an internal module */
407 skipParams = PR_FALSE0; /* did we find an override parameter block*/
408 paramsValue = NULL((void*)0); /* the current parameter block value */
409 do {
12
Loop condition is true. Execution continues on line 410
410 int len;
411
412 if (fgets(line, sizeof(line), fd) == NULL((void*)0)) {
6
Assuming this stream operation fails
7
Taking true branch
13
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior
413 goto endloop;
8
Control jumps to line 534
414 }
415
416 /* remove the ending newline */
417 len = PORT_Strlen(line)strlen(line);
418 if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
419 len = len - 2;
420 line[len] = 0;
421 } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
422 len--;
423 line[len] = 0;
424 }
425 if (*line == '#') {
426 continue;
427 }
428 if (*line != 0) {
429 /*
430 * The PKCS #11 group standard assumes blocks of strings
431 * separated by new lines, clumped by new lines. Internally
432 * we take strings separated by spaces, so we may need to escape
433 * certain spaces.
434 */
435 char *value = PORT_Strchrstrchr(line, '=');
436
437 /* there is no value, write out the stanza as is */
438 if (value == NULL((void*)0) || value[1] == 0) {
439 if (moduleString) {
440 moduleString = nssutil_DupnCat(moduleString, " ", 1);
441 if (moduleString == NULL((void*)0))
442 goto loser;
443 }
444 moduleString = nssutil_DupCat(moduleString, line);
445 if (moduleString == NULL((void*)0))
446 goto loser;
447 /* value is already quoted, just write it out */
448 } else if (value[1] == '"') {
449 if (moduleString) {
450 moduleString = nssutil_DupnCat(moduleString, " ", 1);
451 if (moduleString == NULL((void*)0))
452 goto loser;
453 }
454 moduleString = nssutil_DupCat(moduleString, line);
455 if (moduleString == NULL((void*)0))
456 goto loser;
457 /* we have an override parameter section, remember that
458 * we found this (see following comment about why this
459 * is necessary). */
460 if (PORT_StrncasecmpPL_strncasecmp(line, "parameters", 10) == 0) {
461 skipParams = PR_TRUE1;
462 }
463 /*
464 * The internal token always overrides it's parameter block
465 * from the passed in parameters, so wait until then end
466 * before we include the parameter block in case we need to
467 * override it. NOTE: if the parameter block is quoted with ("),
468 * this override does not happen. This allows you to override
469 * the application's parameter configuration.
470 *
471 * parameter block state is controlled by the following variables:
472 * skipParams - Bool : set to true of we have an override param
473 * block (all other blocks, either implicit or explicit are
474 * ignored).
475 * paramsValue - char * : pointer to the current param block. In
476 * the absence of overrides, paramsValue is set to the first
477 * parameter block we find. All subsequent blocks are ignored.
478 * When we find an internal token, the application passed
479 * parameters take precident.
480 */
481 } else if (PORT_StrncasecmpPL_strncasecmp(line, "parameters", 10) == 0) {
482 /* already have parameters */
483 if (paramsValue) {
484 continue;
485 }
486 paramsValue = NSSUTIL_Quote(&value[1], '"');
487 if (paramsValue == NULL((void*)0))
488 goto loser;
489 continue;
490 } else {
491 /* may need to quote */
492 char *newLine;
493 if (moduleString) {
494 moduleString = nssutil_DupnCat(moduleString, " ", 1);
495 if (moduleString == NULL((void*)0))
496 goto loser;
497 }
498 moduleString = nssutil_DupnCat(moduleString, line, value - line + 1);
499 if (moduleString == NULL((void*)0))
500 goto loser;
501 newLine = NSSUTIL_Quote(&value[1], '"');
502 if (newLine == NULL((void*)0))
503 goto loser;
504 moduleString = nssutil_DupCat(moduleString, newLine);
505 PORT_FreePORT_Free_Util(newLine);
506 if (moduleString == NULL((void*)0))
507 goto loser;
508 }
509
510 /* check to see if it's internal? */
511 if (PORT_StrncasecmpPL_strncasecmp(line, "NSS=", 4) == 0) {
512 /* This should be case insensitive! reviewers make
513 * me fix it if it's not */
514 if (PORT_Strstrstrstr(line, "internal")) {
515 internal = PR_TRUE1;
516 /* override the parameters */
517 if (paramsValue) {
518 PORT_FreePORT_Free_Util(paramsValue);
519 }
520 paramsValue = NSSUTIL_Quote(params, '"');
521 }
522 }
523 continue;
524 }
525 if ((moduleString == NULL((void*)0)) || (*moduleString == 0)) {
526 continue;
527 }
528
529 endloop:
530 /*
531 * if we are here, we have found a complete stanza. Now write out
532 * any param section we may have found.
533 */
534 if (paramsValue
8.1
'paramsValue' is null
) {
9
Taking false branch
535 /* we had an override */
536 if (!skipParams) {
537 moduleString = nssutil_DupnCat(moduleString, " parameters=", 12);
538 if (moduleString == NULL((void*)0))
539 goto loser;
540 moduleString = nssutil_DupCat(moduleString, paramsValue);
541 if (moduleString == NULL((void*)0))
542 goto loser;
543 }
544 PORT_FreePORT_Free_Util(paramsValue);
545 paramsValue = NULL((void*)0);
546 }
547
548 if ((moduleCount + 1) >= useCount) {
10
Taking false branch
549 SECStatus rv;
550 rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1);
551 if (rv != SECSuccess) {
552 goto loser;
553 }
554 }
555
556 if (internal
10.1
'internal' is 0
) {
11
Taking false branch
557 moduleList[0] = moduleString;
558 } else {
559 moduleList[moduleCount] = moduleString;
560 moduleCount++;
561 }
562 moduleString = NULL((void*)0);
563 internal = PR_FALSE0;
564 skipParams = PR_FALSE0;
565 } while (!feof(fd));
566
567 if (moduleString) {
568 PORT_FreePORT_Free_Util(moduleString);
569 moduleString = NULL((void*)0);
570 }
571done:
572#ifndef NSS_DISABLE_DBM1
573 /* if we couldn't open a pkcs11 database, look for the old one */
574 if (fd == NULL((void*)0)) {
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)PR_Access((olddbname), (PR_ACCESS_EXISTS));
585 if (status == PR_SUCCESS) {
586 PR_smprintf_free(olddbname);
587 PORT_ZFreePORT_ZFree_Util(moduleList, useCount * sizeof(char *));
588 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LEGACY_DATABASE);
589 return NULL((void*)0);
590 }
591
592 bail:
593 if (olddbname) {
594 PR_smprintf_free(olddbname);
595 }
596 }
597#endif // NSS_DISABLE_DBM
598
599return_default:
600
601 if (!moduleList[0]) {
602 char *newParams;
603 moduleString = PORT_StrdupPORT_Strdup_Util(NSSUTIL_DEFAULT_INTERNAL_INIT1"library= name=\"NSS Internal PKCS #11 Module\" parameters=");
604 newParams = NSSUTIL_Quote(params, '"');
605 if (newParams == NULL((void*)0))
606 goto loser;
607 moduleString = nssutil_DupCat(moduleString, newParams);
608 PORT_FreePORT_Free_Util(newParams);
609 if (moduleString == NULL((void*)0))
610 goto loser;
611 moduleString = nssutil_DupCat(moduleString,
612 NSSUTIL_DEFAULT_INTERNAL_INIT2" NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={");
613 if (moduleString == NULL((void*)0))
614 goto loser;
615 moduleString = nssutil_DupCat(moduleString,
616 NSSUTIL_DEFAULT_SFTKN_FLAGS"slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]");
617 if (moduleString == NULL((void*)0))
618 goto loser;
619 moduleString = nssutil_DupCat(moduleString,
620 NSSUTIL_DEFAULT_INTERNAL_INIT3" askpw=any timeout=30})\"");
621 if (moduleString == NULL((void*)0))
622 goto loser;
623 moduleList[0] = moduleString;
624 moduleString = NULL((void*)0);
625 }
626 failed = PR_FALSE0;
627
628loser:
629 /*
630 * cleanup
631 */
632 /* deal with trust cert db here */
633 if (moduleString) {
634 PORT_FreePORT_Free_Util(moduleString);
635 moduleString = NULL((void*)0);
636 }
637 if (paramsValue) {
638 PORT_FreePORT_Free_Util(paramsValue);
639 paramsValue = NULL((void*)0);
640 }
641 if (failed || (moduleList[0] == NULL((void*)0))) {
642 /* This is wrong! FIXME */
643 nssutil_releaseSpecList(moduleList);
644 moduleList = NULL((void*)0);
645 failed = PR_TRUE1;
646 }
647 if (fd != NULL((void*)0)) {
648 fclose(fd);
649 } else if (!failed && rw) {
650 /* update our internal module */
651 nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw);
652 }
653 return moduleList;
654}
655
656static SECStatus
657nssutil_ReleaseSecmodDBData(const char *appName,
658 const char *filename, const char *dbname,
659 char **moduleSpecList, PRBool rw)
660{
661 if (moduleSpecList) {
662 nssutil_releaseSpecList(moduleSpecList);
663 }
664 return SECSuccess;
665}
666
667/*
668 * Delete a module from the Data Base
669 */
670static SECStatus
671nssutil_DeleteSecmodDBEntry(const char *appName,
672 const char *filename,
673 const char *dbname,
674 const char *args,
675 PRBool rw)
676{
677 /* SHDB_FIXME implement */
678 os_stat_typestruct stat stat_existing;
679 os_open_permissions_typemode_t file_mode;
680 FILE *fd = NULL((void*)0);
681 FILE *fd2 = NULL((void*)0);
682 char line[MAX_LINE_LENGTH2048];
683 char *dbname2 = NULL((void*)0);
684 char *block = NULL((void*)0);
685 char *name = NULL((void*)0);
686 char *lib = NULL((void*)0);
687 int name_len = 0, lib_len = 0;
688 PRBool skip = PR_FALSE0;
689 PRBool found = PR_FALSE0;
690
691 if (dbname == NULL((void*)0)) {
692 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
693 return SECFailure;
694 }
695
696 if (!rw) {
697 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_READ_ONLY);
698 return SECFailure;
699 }
700
701 dbname2 = PORT_StrdupPORT_Strdup_Util(dbname);
702 if (dbname2 == NULL((void*)0))
703 goto loser;
704 dbname2[strlen(dbname) - 1]++;
705
706 /* get the permissions of the existing file, or use the default */
707 if (!os_statstat(dbname, &stat_existing)) {
708 file_mode = stat_existing.st_mode;
709 } else {
710 file_mode = os_open_permissions_default0600;
711 }
712
713 /* do we really want to use streams here */
714 fd = os_fopenfopen(dbname, "r");
715 if (fd == NULL((void*)0))
716 goto loser;
717
718 fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
719
720 if (fd2 == NULL((void*)0))
721 goto loser;
722
723 name = NSSUTIL_ArgGetParamValue("name", args);
724 if (name) {
725 name_len = PORT_Strlen(name)strlen(name);
726 }
727 lib = NSSUTIL_ArgGetParamValue("library", args);
728 if (lib) {
729 lib_len = PORT_Strlen(lib)strlen(lib);
730 }
731
732 /*
733 * the following loop takes line separated config files and collapses
734 * the lines to a single string, escaping and quoting as necessary.
735 */
736 /* loop state variables */
737 block = NULL((void*)0);
738 skip = PR_FALSE0;
739 while (fgets(line, sizeof(line), fd) != NULL((void*)0)) {
740 /* If we are processing a block (we haven't hit a blank line yet */
741 if (*line != '\n') {
742 /* skip means we are in the middle of a block we are deleting */
743 if (skip) {
744 continue;
745 }
746 /* if we haven't found the block yet, check to see if this block
747 * matches our requirements */
748 if (!found && ((name && (PORT_StrncasecmpPL_strncasecmp(line, "name=", 5) == 0) &&
749 (PORT_Strncmpstrncmp(line + 5, name, name_len) == 0)) ||
750 (lib && (PORT_StrncasecmpPL_strncasecmp(line, "library=", 8) == 0) &&
751 (PORT_Strncmpstrncmp(line + 8, lib, lib_len) == 0)))) {
752
753 /* yup, we don't need to save any more data, */
754 PORT_FreePORT_Free_Util(block);
755 block = NULL((void*)0);
756 /* we don't need to collect more of this block */
757 skip = PR_TRUE1;
758 /* we don't need to continue searching for the block */
759 found = PR_TRUE1;
760 continue;
761 }
762 /* not our match, continue to collect data in this block */
763 block = nssutil_DupCat(block, line);
764 continue;
765 }
766 /* we've collected a block of data that wasn't the module we were
767 * looking for, write it out */
768 if (block) {
769 fwrite(block, PORT_Strlen(block)strlen(block), 1, fd2);
770 PORT_FreePORT_Free_Util(block);
771 block = NULL((void*)0);
772 }
773 /* If we didn't just delete the this block, keep the blank line */
774 if (!skip) {
775 fputs(line, fd2);
776 }
777 /* we are definately not in a deleted block anymore */
778 skip = PR_FALSE0;
779 }
780 fclose(fd);
781 fclose(fd2);
782 if (found) {
783 /* rename dbname2 to dbname */
784 nssutil_DeletePR_Delete(dbname);
785 nssutil_RenamePR_Rename(dbname2, dbname);
786 } else {
787 nssutil_DeletePR_Delete(dbname2);
788 }
789 PORT_FreePORT_Free_Util(dbname2);
790 PORT_FreePORT_Free_Util(lib);
791 PORT_FreePORT_Free_Util(name);
792 PORT_FreePORT_Free_Util(block);
793 return SECSuccess;
794
795loser:
796 if (fd != NULL((void*)0)) {
797 fclose(fd);
798 }
799 if (fd2 != NULL((void*)0)) {
800 fclose(fd2);
801 }
802 if (dbname2) {
803 nssutil_DeletePR_Delete(dbname2);
804 PORT_FreePORT_Free_Util(dbname2);
805 }
806 PORT_FreePORT_Free_Util(lib);
807 PORT_FreePORT_Free_Util(name);
808 return SECFailure;
809}
810
811/*
812 * Add a module to the Data base
813 */
814static SECStatus
815nssutil_AddSecmodDBEntry(const char *appName,
816 const char *filename, const char *dbname,
817 const char *module, PRBool rw)
818{
819 os_stat_typestruct stat stat_existing;
820 os_open_permissions_typemode_t file_mode;
821 FILE *fd = NULL((void*)0);
822 char *block = NULL((void*)0);
823 PRBool libFound = PR_FALSE0;
824
825 if (dbname == NULL((void*)0)) {
826 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
827 return SECFailure;
828 }
829
830 /* can't write to a read only module */
831 if (!rw) {
832 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_READ_ONLY);
833 return SECFailure;
834 }
835
836 /* remove the previous version if it exists */
837 (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw);
838
839 /* get the permissions of the existing file, or use the default */
840 if (!os_statstat(dbname, &stat_existing)) {
841 file_mode = stat_existing.st_mode;
842 } else {
843 file_mode = os_open_permissions_default0600;
844 }
845
846 fd = lfopen(dbname, lfopen_append, file_mode);
847 if (fd == NULL((void*)0)) {
848 return SECFailure;
849 }
850 module = NSSUTIL_ArgStrip(module);
851 while (*module) {
852 int count;
853 char *keyEnd = PORT_Strchrstrchr(module, '=');
854 char *value;
855
856 if (PORT_Strncmpstrncmp(module, "library=", 8) == 0) {
857 libFound = PR_TRUE1;
858 }
859 if (keyEnd == NULL((void*)0)) {
860 block = nssutil_DupCat(block, module);
861 break;
862 }
863 block = nssutil_DupnCat(block, module, keyEnd - module + 1);
864 if (block == NULL((void*)0)) {
865 goto loser;
866 }
867 value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
868 if (value) {
869 block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
870 PORT_FreePORT_Free_Util(value);
871 }
872 if (block == NULL((void*)0)) {
873 goto loser;
874 }
875 block = nssutil_DupnCat(block, "\n", 1);
876 module = keyEnd + 1 + count;
877 module = NSSUTIL_ArgStrip(module);
878 }
879 if (block) {
880 if (!libFound) {
881 fprintf(fd, "library=\n");
882 }
883 fwrite(block, PORT_Strlen(block)strlen(block), 1, fd);
884 fprintf(fd, "\n");
885 PORT_FreePORT_Free_Util(block);
886 block = NULL((void*)0);
887 }
888 fclose(fd);
889 return SECSuccess;
890
891loser:
892 PORT_FreePORT_Free_Util(block);
893 fclose(fd);
894 return SECFailure;
895}
896
897char **
898NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args)
899{
900 char *secmod = NULL((void*)0);
901 char *appName = NULL((void*)0);
902 char *filename = NULL((void*)0);
903 NSSDBType dbType = NSS_DB_TYPE_NONE;
904 PRBool rw;
905 static char *success = "Success";
906 char **rvstr = NULL((void*)0);
907
908 secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
909 &filename, &rw);
910 if ((dbType == NSS_DB_TYPE_LEGACY) ||
911 (dbType == NSS_DB_TYPE_MULTIACCESS)) {
912 /* we can't handle the old database, only softoken can */
913 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_LEGACY_DATABASE);
914 rvstr = NULL((void*)0);
915 goto done;
916 }
917
918 switch (function) {
919 case SECMOD_MODULE_DB_FUNCTION_FIND0:
920 rvstr = nssutil_ReadSecmodDB(appName, filename,
921 secmod, (char *)parameters, rw);
922 break;
923 case SECMOD_MODULE_DB_FUNCTION_ADD1:
924 rvstr = (nssutil_AddSecmodDBEntry(appName, filename,
925 secmod, (char *)args, rw) == SECSuccess)
926 ? &success
927 : NULL((void*)0);
928 break;
929 case SECMOD_MODULE_DB_FUNCTION_DEL2:
930 rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename,
931 secmod, (char *)args, rw) == SECSuccess)
932 ? &success
933 : NULL((void*)0);
934 break;
935 case SECMOD_MODULE_DB_FUNCTION_RELEASE3:
936 rvstr = (nssutil_ReleaseSecmodDBData(appName, filename,
937 secmod, (char **)args, rw) == SECSuccess)
938 ? &success
939 : NULL((void*)0);
940 break;
941 }
942done:
943 if (secmod)
944 PR_smprintf_free(secmod);
945 if (appName)
946 PORT_FreePORT_Free_Util(appName);
947 if (filename)
948 PORT_FreePORT_Free_Util(filename);
949 return rvstr;
950}