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
_NSSUTIL_UTF8ToWide(const char * buf)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
os_open(const char * filename,int oflag,int pmode)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
os_stat(const char * path,os_stat_type * buffer)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 *
os_fopen(const char * filename,const char * mode)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
_NSSUTIL_Access(const char * path,PRAccessHow how)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
nssutil_Delete(const char * name)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
nssutil_Rename(const char * from,const char * to)191 nssutil_Rename(const char *from, const char *to)
192 {
193 BOOL result;
194
195 if (!from || !to) {
196 return PR_FAILURE;
197 }
198
199 wchar_t *fromWide = _NSSUTIL_UTF8ToWide(from);
200 if (!fromWide) {
201 return PR_FAILURE;
202 }
203 wchar_t *toWide = _NSSUTIL_UTF8ToWide(to);
204 if (!toWide) {
205 PORT_Free(fromWide);
206 return PR_FAILURE;
207 }
208 result = MoveFileW(fromWide, toWide);
209 PORT_Free(fromWide);
210 PORT_Free(toWide);
211
212 return result ? PR_SUCCESS : PR_FAILURE;
213 }
214 #else
215 #define os_fopen fopen
216 #define os_open open
217 #define os_fdopen fdopen
218 #define os_stat stat
219 #define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC
220 #define os_append_open_flags O_CREAT | O_RDWR | O_APPEND
221 #define os_open_permissions_type mode_t
222 #define os_open_permissions_default 0600
223 #define os_stat_type struct stat
224 #define nssutil_Delete PR_Delete
225 #define nssutil_Rename PR_Rename
226 #endif
227
228 /****************************************************************
229 *
230 * Secmod database.
231 *
232 * The new secmod database is simply a text file with each of the module
233 * entries in the following form:
234 *
235 * #
236 * # This is a comment The next line is the library to load
237 * library=libmypkcs11.so
238 * name="My PKCS#11 module"
239 * params="my library's param string"
240 * nss="NSS parameters"
241 * other="parameters for other libraries and applications"
242 *
243 * library=libmynextpk11.so
244 * name="My other PKCS#11 module"
245 */
246
247 /*
248 * Smart string cat functions. Automatically manage the memory.
249 * The first parameter is the destination string. If it's null, we
250 * allocate memory for it. If it's not, we reallocate memory
251 * so the the concanenated string fits.
252 */
253 static char *
nssutil_DupnCat(char * baseString,const char * str,int str_len)254 nssutil_DupnCat(char *baseString, const char *str, int str_len)
255 {
256 int baseStringLen = baseString ? PORT_Strlen(baseString) : 0;
257 int len = baseStringLen + 1;
258 char *newString;
259
260 len += str_len;
261 newString = (char *)PORT_Realloc(baseString, len);
262 if (newString == NULL) {
263 PORT_Free(baseString);
264 return NULL;
265 }
266 PORT_Memcpy(&newString[baseStringLen], str, str_len);
267 newString[len - 1] = 0;
268 return newString;
269 }
270
271 /* Same as nssutil_DupnCat except it concatenates the full string, not a
272 * partial one */
273 static char *
nssutil_DupCat(char * baseString,const char * str)274 nssutil_DupCat(char *baseString, const char *str)
275 {
276 return nssutil_DupnCat(baseString, str, PORT_Strlen(str));
277 }
278
279 /* function to free up all the memory associated with a null terminated
280 * array of module specs */
281 static SECStatus
nssutil_releaseSpecList(char ** moduleSpecList)282 nssutil_releaseSpecList(char **moduleSpecList)
283 {
284 if (moduleSpecList) {
285 char **index;
286 for (index = moduleSpecList; *index; index++) {
287 PORT_Free(*index);
288 }
289 PORT_Free(moduleSpecList);
290 }
291 return SECSuccess;
292 }
293
294 #define SECMOD_STEP 10
295 static SECStatus
nssutil_growList(char *** pModuleList,int * useCount,int last)296 nssutil_growList(char ***pModuleList, int *useCount, int last)
297 {
298 char **newModuleList;
299
300 *useCount += SECMOD_STEP;
301 newModuleList = (char **)PORT_Realloc(*pModuleList,
302 *useCount * sizeof(char *));
303 if (newModuleList == NULL) {
304 return SECFailure;
305 }
306 PORT_Memset(&newModuleList[last], 0, sizeof(char *) * SECMOD_STEP);
307 *pModuleList = newModuleList;
308 return SECSuccess;
309 }
310
311 static char *
_NSSUTIL_GetOldSecmodName(const char * dbname,const char * filename)312 _NSSUTIL_GetOldSecmodName(const char *dbname, const char *filename)
313 {
314 char *file = NULL;
315 char *dirPath = PORT_Strdup(dbname);
316 char *sep;
317
318 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 if (sep) {
327 *sep = 0;
328 file = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s", dirPath, filename);
329 } else {
330 file = PR_smprintf("%s", filename);
331 }
332 PORT_Free(dirPath);
333 return file;
334 }
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 *
lfopen(const char * name,enum lfopen_mode om,os_open_permissions_type open_perms)345 lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms)
346 {
347 int fd;
348 FILE *file;
349
350 fd = os_open(name,
351 (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags,
352 open_perms);
353 if (fd < 0) {
354 return NULL;
355 }
356 file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+");
357 if (!file) {
358 close(fd);
359 }
360 /* file inherits fd */
361 return file;
362 }
363
364 #define MAX_LINE_LENGTH 2048
365
366 /*
367 * Read all the existing modules in out of the file.
368 */
369 static char **
nssutil_ReadSecmodDB(const char * appName,const char * filename,const char * dbname,char * params,PRBool rw)370 nssutil_ReadSecmodDB(const char *appName,
371 const char *filename, const char *dbname,
372 char *params, PRBool rw)
373 {
374 FILE *fd = NULL;
375 char **moduleList = NULL;
376 int moduleCount = 1;
377 int useCount = SECMOD_STEP;
378 char line[MAX_LINE_LENGTH];
379 PRBool internal = PR_FALSE;
380 PRBool skipParams = PR_FALSE;
381 char *moduleString = NULL;
382 char *paramsValue = NULL;
383 PRBool failed = PR_TRUE;
384
385 moduleList = (char **)PORT_ZAlloc(useCount * sizeof(char *));
386 if (moduleList == NULL)
387 return NULL;
388
389 if (dbname == NULL) {
390 goto return_default;
391 }
392
393 /* do we really want to use streams here */
394 fd = os_fopen(dbname, "r");
395 if (fd == NULL)
396 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 moduleString = NULL; /* current concatenated string */
404 internal = PR_FALSE; /* is this an internal module */
405 skipParams = PR_FALSE; /* did we find an override parameter block*/
406 paramsValue = NULL; /* the current parameter block value */
407 do {
408 int len;
409
410 if (fgets(line, sizeof(line), fd) == NULL) {
411 goto endloop;
412 }
413
414 /* remove the ending newline */
415 len = PORT_Strlen(line);
416 if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
417 len = len - 2;
418 line[len] = 0;
419 } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
420 len--;
421 line[len] = 0;
422 }
423 if (*line == '#') {
424 continue;
425 }
426 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 char *value = PORT_Strchr(line, '=');
434
435 /* there is no value, write out the stanza as is */
436 if (value == NULL || value[1] == 0) {
437 if (moduleString) {
438 moduleString = nssutil_DupnCat(moduleString, " ", 1);
439 if (moduleString == NULL)
440 goto loser;
441 }
442 moduleString = nssutil_DupCat(moduleString, line);
443 if (moduleString == NULL)
444 goto loser;
445 /* value is already quoted, just write it out */
446 } else if (value[1] == '"') {
447 if (moduleString) {
448 moduleString = nssutil_DupnCat(moduleString, " ", 1);
449 if (moduleString == NULL)
450 goto loser;
451 }
452 moduleString = nssutil_DupCat(moduleString, line);
453 if (moduleString == NULL)
454 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 if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
459 skipParams = PR_TRUE;
460 }
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 } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
480 /* already have parameters */
481 if (paramsValue) {
482 continue;
483 }
484 paramsValue = NSSUTIL_Quote(&value[1], '"');
485 if (paramsValue == NULL)
486 goto loser;
487 continue;
488 } else {
489 /* may need to quote */
490 char *newLine;
491 if (moduleString) {
492 moduleString = nssutil_DupnCat(moduleString, " ", 1);
493 if (moduleString == NULL)
494 goto loser;
495 }
496 moduleString = nssutil_DupnCat(moduleString, line, value - line + 1);
497 if (moduleString == NULL)
498 goto loser;
499 newLine = NSSUTIL_Quote(&value[1], '"');
500 if (newLine == NULL)
501 goto loser;
502 moduleString = nssutil_DupCat(moduleString, newLine);
503 PORT_Free(newLine);
504 if (moduleString == NULL)
505 goto loser;
506 }
507
508 /* check to see if it's internal? */
509 if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
510 /* This should be case insensitive! reviewers make
511 * me fix it if it's not */
512 if (PORT_Strstr(line, "internal")) {
513 internal = PR_TRUE;
514 /* override the parameters */
515 if (paramsValue) {
516 PORT_Free(paramsValue);
517 }
518 paramsValue = NSSUTIL_Quote(params, '"');
519 }
520 }
521 continue;
522 }
523 if ((moduleString == NULL) || (*moduleString == 0)) {
524 continue;
525 }
526
527 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 if (paramsValue) {
533 /* we had an override */
534 if (!skipParams) {
535 moduleString = nssutil_DupnCat(moduleString, " parameters=", 12);
536 if (moduleString == NULL)
537 goto loser;
538 moduleString = nssutil_DupCat(moduleString, paramsValue);
539 if (moduleString == NULL)
540 goto loser;
541 }
542 PORT_Free(paramsValue);
543 paramsValue = NULL;
544 }
545
546 if ((moduleCount + 1) >= useCount) {
547 SECStatus rv;
548 rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1);
549 if (rv != SECSuccess) {
550 goto loser;
551 }
552 }
553
554 if (internal) {
555 moduleList[0] = moduleString;
556 } else {
557 moduleList[moduleCount] = moduleString;
558 moduleCount++;
559 }
560 moduleString = NULL;
561 internal = PR_FALSE;
562 skipParams = PR_FALSE;
563 } while (!feof(fd));
564
565 if (moduleString) {
566 PORT_Free(moduleString);
567 moduleString = NULL;
568 }
569 done:
570 /* if we couldn't open a pkcs11 database, look for the old one */
571 if (fd == NULL) {
572 char *olddbname = _NSSUTIL_GetOldSecmodName(dbname, filename);
573 PRStatus status;
574
575 /* couldn't get the old name */
576 if (!olddbname) {
577 goto bail;
578 }
579
580 /* old one exists */
581 status = _NSSUTIL_Access(olddbname, PR_ACCESS_EXISTS);
582 if (status == PR_SUCCESS) {
583 PR_smprintf_free(olddbname);
584 PORT_ZFree(moduleList, useCount * sizeof(char *));
585 PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
586 return NULL;
587 }
588
589 bail:
590 if (olddbname) {
591 PR_smprintf_free(olddbname);
592 }
593 }
594
595 return_default:
596
597 if (!moduleList[0]) {
598 char *newParams;
599 moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1);
600 newParams = NSSUTIL_Quote(params, '"');
601 if (newParams == NULL)
602 goto loser;
603 moduleString = nssutil_DupCat(moduleString, newParams);
604 PORT_Free(newParams);
605 if (moduleString == NULL)
606 goto loser;
607 moduleString = nssutil_DupCat(moduleString,
608 NSSUTIL_DEFAULT_INTERNAL_INIT2);
609 if (moduleString == NULL)
610 goto loser;
611 moduleString = nssutil_DupCat(moduleString,
612 NSSUTIL_DEFAULT_SFTKN_FLAGS);
613 if (moduleString == NULL)
614 goto loser;
615 moduleString = nssutil_DupCat(moduleString,
616 NSSUTIL_DEFAULT_INTERNAL_INIT3);
617 if (moduleString == NULL)
618 goto loser;
619 moduleList[0] = moduleString;
620 moduleString = NULL;
621 }
622 failed = PR_FALSE;
623
624 loser:
625 /*
626 * cleanup
627 */
628 /* deal with trust cert db here */
629 if (moduleString) {
630 PORT_Free(moduleString);
631 moduleString = NULL;
632 }
633 if (paramsValue) {
634 PORT_Free(paramsValue);
635 paramsValue = NULL;
636 }
637 if (failed || (moduleList[0] == NULL)) {
638 /* This is wrong! FIXME */
639 nssutil_releaseSpecList(moduleList);
640 moduleList = NULL;
641 failed = PR_TRUE;
642 }
643 if (fd != NULL) {
644 fclose(fd);
645 } else if (!failed && rw) {
646 /* update our internal module */
647 nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw);
648 }
649 return moduleList;
650 }
651
652 static SECStatus
nssutil_ReleaseSecmodDBData(const char * appName,const char * filename,const char * dbname,char ** moduleSpecList,PRBool rw)653 nssutil_ReleaseSecmodDBData(const char *appName,
654 const char *filename, const char *dbname,
655 char **moduleSpecList, PRBool rw)
656 {
657 if (moduleSpecList) {
658 nssutil_releaseSpecList(moduleSpecList);
659 }
660 return SECSuccess;
661 }
662
663 /*
664 * Delete a module from the Data Base
665 */
666 static SECStatus
nssutil_DeleteSecmodDBEntry(const char * appName,const char * filename,const char * dbname,const char * args,PRBool rw)667 nssutil_DeleteSecmodDBEntry(const char *appName,
668 const char *filename,
669 const char *dbname,
670 const char *args,
671 PRBool rw)
672 {
673 /* SHDB_FIXME implement */
674 os_stat_type stat_existing;
675 os_open_permissions_type file_mode;
676 FILE *fd = NULL;
677 FILE *fd2 = NULL;
678 char line[MAX_LINE_LENGTH];
679 char *dbname2 = NULL;
680 char *block = NULL;
681 char *name = NULL;
682 char *lib = NULL;
683 int name_len = 0, lib_len = 0;
684 PRBool skip = PR_FALSE;
685 PRBool found = PR_FALSE;
686
687 if (dbname == NULL) {
688 PORT_SetError(SEC_ERROR_INVALID_ARGS);
689 return SECFailure;
690 }
691
692 if (!rw) {
693 PORT_SetError(SEC_ERROR_READ_ONLY);
694 return SECFailure;
695 }
696
697 dbname2 = PORT_Strdup(dbname);
698 if (dbname2 == NULL)
699 goto loser;
700 dbname2[strlen(dbname) - 1]++;
701
702 /* get the permissions of the existing file, or use the default */
703 if (!os_stat(dbname, &stat_existing)) {
704 file_mode = stat_existing.st_mode;
705 } else {
706 file_mode = os_open_permissions_default;
707 }
708
709 /* do we really want to use streams here */
710 fd = os_fopen(dbname, "r");
711 if (fd == NULL)
712 goto loser;
713
714 fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
715
716 if (fd2 == NULL)
717 goto loser;
718
719 name = NSSUTIL_ArgGetParamValue("name", args);
720 if (name) {
721 name_len = PORT_Strlen(name);
722 }
723 lib = NSSUTIL_ArgGetParamValue("library", args);
724 if (lib) {
725 lib_len = PORT_Strlen(lib);
726 }
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 block = NULL;
734 skip = PR_FALSE;
735 while (fgets(line, sizeof(line), fd) != NULL) {
736 /* If we are processing a block (we haven't hit a blank line yet */
737 if (*line != '\n') {
738 /* skip means we are in the middle of a block we are deleting */
739 if (skip) {
740 continue;
741 }
742 /* if we haven't found the block yet, check to see if this block
743 * matches our requirements */
744 if (!found && ((name && (PORT_Strncasecmp(line, "name=", 5) == 0) &&
745 (PORT_Strncmp(line + 5, name, name_len) == 0)) ||
746 (lib && (PORT_Strncasecmp(line, "library=", 8) == 0) &&
747 (PORT_Strncmp(line + 8, lib, lib_len) == 0)))) {
748
749 /* yup, we don't need to save any more data, */
750 PORT_Free(block);
751 block = NULL;
752 /* we don't need to collect more of this block */
753 skip = PR_TRUE;
754 /* we don't need to continue searching for the block */
755 found = PR_TRUE;
756 continue;
757 }
758 /* not our match, continue to collect data in this block */
759 block = nssutil_DupCat(block, line);
760 continue;
761 }
762 /* we've collected a block of data that wasn't the module we were
763 * looking for, write it out */
764 if (block) {
765 fwrite(block, PORT_Strlen(block), 1, fd2);
766 PORT_Free(block);
767 block = NULL;
768 }
769 /* If we didn't just delete the this block, keep the blank line */
770 if (!skip) {
771 fputs(line, fd2);
772 }
773 /* we are definately not in a deleted block anymore */
774 skip = PR_FALSE;
775 }
776 fclose(fd);
777 fclose(fd2);
778 if (found) {
779 /* rename dbname2 to dbname */
780 nssutil_Delete(dbname);
781 nssutil_Rename(dbname2, dbname);
782 } else {
783 nssutil_Delete(dbname2);
784 }
785 PORT_Free(dbname2);
786 PORT_Free(lib);
787 PORT_Free(name);
788 PORT_Free(block);
789 return SECSuccess;
790
791 loser:
792 if (fd != NULL) {
793 fclose(fd);
794 }
795 if (fd2 != NULL) {
796 fclose(fd2);
797 }
798 if (dbname2) {
799 nssutil_Delete(dbname2);
800 PORT_Free(dbname2);
801 }
802 PORT_Free(lib);
803 PORT_Free(name);
804 return SECFailure;
805 }
806
807 /*
808 * Add a module to the Data base
809 */
810 static SECStatus
nssutil_AddSecmodDBEntry(const char * appName,const char * filename,const char * dbname,const char * module,PRBool rw)811 nssutil_AddSecmodDBEntry(const char *appName,
812 const char *filename, const char *dbname,
813 const char *module, PRBool rw)
814 {
815 os_stat_type stat_existing;
816 os_open_permissions_type file_mode;
817 FILE *fd = NULL;
818 char *block = NULL;
819 PRBool libFound = PR_FALSE;
820
821 if (dbname == NULL) {
822 PORT_SetError(SEC_ERROR_INVALID_ARGS);
823 return SECFailure;
824 }
825
826 /* can't write to a read only module */
827 if (!rw) {
828 PORT_SetError(SEC_ERROR_READ_ONLY);
829 return SECFailure;
830 }
831
832 /* remove the previous version if it exists */
833 (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw);
834
835 /* get the permissions of the existing file, or use the default */
836 if (!os_stat(dbname, &stat_existing)) {
837 file_mode = stat_existing.st_mode;
838 } else {
839 file_mode = os_open_permissions_default;
840 }
841
842 fd = lfopen(dbname, lfopen_append, file_mode);
843 if (fd == NULL) {
844 return SECFailure;
845 }
846 module = NSSUTIL_ArgStrip(module);
847 while (*module) {
848 int count;
849 char *keyEnd = PORT_Strchr(module, '=');
850 char *value;
851
852 if (PORT_Strncmp(module, "library=", 8) == 0) {
853 libFound = PR_TRUE;
854 }
855 if (keyEnd == NULL) {
856 block = nssutil_DupCat(block, module);
857 break;
858 }
859 block = nssutil_DupnCat(block, module, keyEnd - module + 1);
860 if (block == NULL) {
861 goto loser;
862 }
863 value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
864 if (value) {
865 block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
866 PORT_Free(value);
867 }
868 if (block == NULL) {
869 goto loser;
870 }
871 block = nssutil_DupnCat(block, "\n", 1);
872 module = keyEnd + 1 + count;
873 module = NSSUTIL_ArgStrip(module);
874 }
875 if (block) {
876 if (!libFound) {
877 fprintf(fd, "library=\n");
878 }
879 fwrite(block, PORT_Strlen(block), 1, fd);
880 fprintf(fd, "\n");
881 PORT_Free(block);
882 block = NULL;
883 }
884 fclose(fd);
885 return SECSuccess;
886
887 loser:
888 PORT_Free(block);
889 fclose(fd);
890 return SECFailure;
891 }
892
893 char **
NSSUTIL_DoModuleDBFunction(unsigned long function,char * parameters,void * args)894 NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args)
895 {
896 char *secmod = NULL;
897 char *appName = NULL;
898 char *filename = NULL;
899 NSSDBType dbType = NSS_DB_TYPE_NONE;
900 PRBool rw;
901 static char *success = "Success";
902 char **rvstr = NULL;
903
904 secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
905 &filename, &rw);
906 if ((dbType == NSS_DB_TYPE_LEGACY) ||
907 (dbType == NSS_DB_TYPE_MULTIACCESS)) {
908 /* we can't handle the old database, only softoken can */
909 PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
910 rvstr = NULL;
911 goto done;
912 }
913
914 switch (function) {
915 case SECMOD_MODULE_DB_FUNCTION_FIND:
916 rvstr = nssutil_ReadSecmodDB(appName, filename,
917 secmod, (char *)parameters, rw);
918 break;
919 case SECMOD_MODULE_DB_FUNCTION_ADD:
920 rvstr = (nssutil_AddSecmodDBEntry(appName, filename,
921 secmod, (char *)args, rw) == SECSuccess)
922 ? &success
923 : NULL;
924 break;
925 case SECMOD_MODULE_DB_FUNCTION_DEL:
926 rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename,
927 secmod, (char *)args, rw) == SECSuccess)
928 ? &success
929 : NULL;
930 break;
931 case SECMOD_MODULE_DB_FUNCTION_RELEASE:
932 rvstr = (nssutil_ReleaseSecmodDBData(appName, filename,
933 secmod, (char **)args, rw) == SECSuccess)
934 ? &success
935 : NULL;
936 break;
937 }
938 done:
939 if (secmod)
940 PR_smprintf_free(secmod);
941 if (appName)
942 PORT_Free(appName);
943 if (filename)
944 PORT_Free(filename);
945 return rvstr;
946 }
947