|
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 #endif |
|
28 #ifdef XP_UNIX |
|
29 #include <unistd.h> |
|
30 #endif |
|
31 |
|
32 #include <sys/types.h> |
|
33 #include <sys/stat.h> |
|
34 #include <fcntl.h> |
|
35 |
|
36 #if defined (_WIN32) |
|
37 #define os_open _open |
|
38 #define os_fdopen _fdopen |
|
39 #define os_stat _stat |
|
40 #define os_truncate_open_flags _O_CREAT|_O_RDWR|_O_TRUNC |
|
41 #define os_append_open_flags _O_CREAT|_O_RDWR|_O_APPEND |
|
42 #define os_open_permissions_type int |
|
43 #define os_open_permissions_default _S_IREAD | _S_IWRITE |
|
44 #define os_stat_type struct _stat |
|
45 #else |
|
46 #define os_open open |
|
47 #define os_fdopen fdopen |
|
48 #define os_stat stat |
|
49 #define os_truncate_open_flags O_CREAT|O_RDWR|O_TRUNC |
|
50 #define os_append_open_flags O_CREAT|O_RDWR|O_APPEND |
|
51 #define os_open_permissions_type mode_t |
|
52 #define os_open_permissions_default 0600 |
|
53 #define os_stat_type struct stat |
|
54 #endif |
|
55 |
|
56 /**************************************************************** |
|
57 * |
|
58 * Secmod database. |
|
59 * |
|
60 * The new secmod database is simply a text file with each of the module |
|
61 * entries in the following form: |
|
62 * |
|
63 * # |
|
64 * # This is a comment The next line is the library to load |
|
65 * library=libmypkcs11.so |
|
66 * name="My PKCS#11 module" |
|
67 * params="my library's param string" |
|
68 * nss="NSS parameters" |
|
69 * other="parameters for other libraries and applications" |
|
70 * |
|
71 * library=libmynextpk11.so |
|
72 * name="My other PKCS#11 module" |
|
73 */ |
|
74 |
|
75 |
|
76 /* |
|
77 * Smart string cat functions. Automatically manage the memory. |
|
78 * The first parameter is the source string. If it's null, we |
|
79 * allocate memory for it. If it's not, we reallocate memory |
|
80 * so the the concanenated string fits. |
|
81 */ |
|
82 static char * |
|
83 nssutil_DupnCat(char *baseString, const char *str, int str_len) |
|
84 { |
|
85 int len = (baseString ? PORT_Strlen(baseString) : 0) + 1; |
|
86 char *newString; |
|
87 |
|
88 len += str_len; |
|
89 newString = (char *) PORT_Realloc(baseString,len); |
|
90 if (newString == NULL) { |
|
91 PORT_Free(baseString); |
|
92 return NULL; |
|
93 } |
|
94 if (baseString == NULL) *newString = 0; |
|
95 return PORT_Strncat(newString,str, str_len); |
|
96 } |
|
97 |
|
98 /* Same as nssutil_DupnCat except it concatenates the full string, not a |
|
99 * partial one */ |
|
100 static char * |
|
101 nssutil_DupCat(char *baseString, const char *str) |
|
102 { |
|
103 return nssutil_DupnCat(baseString, str, PORT_Strlen(str)); |
|
104 } |
|
105 |
|
106 /* function to free up all the memory associated with a null terminated |
|
107 * array of module specs */ |
|
108 static SECStatus |
|
109 nssutil_releaseSpecList(char **moduleSpecList) |
|
110 { |
|
111 if (moduleSpecList) { |
|
112 char **index; |
|
113 for(index = moduleSpecList; *index; index++) { |
|
114 PORT_Free(*index); |
|
115 } |
|
116 PORT_Free(moduleSpecList); |
|
117 } |
|
118 return SECSuccess; |
|
119 } |
|
120 |
|
121 #define SECMOD_STEP 10 |
|
122 static SECStatus |
|
123 nssutil_growList(char ***pModuleList, int *useCount, int last) |
|
124 { |
|
125 char **newModuleList; |
|
126 |
|
127 *useCount += SECMOD_STEP; |
|
128 newModuleList = (char **)PORT_Realloc(*pModuleList, |
|
129 *useCount*sizeof(char *)); |
|
130 if (newModuleList == NULL) { |
|
131 return SECFailure; |
|
132 } |
|
133 PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); |
|
134 *pModuleList = newModuleList; |
|
135 return SECSuccess; |
|
136 } |
|
137 |
|
138 static |
|
139 char *_NSSUTIL_GetOldSecmodName(const char *dbname,const char *filename) |
|
140 { |
|
141 char *file = NULL; |
|
142 char *dirPath = PORT_Strdup(dbname); |
|
143 char *sep; |
|
144 |
|
145 sep = PORT_Strrchr(dirPath,*NSSUTIL_PATH_SEPARATOR); |
|
146 #ifdef _WIN32 |
|
147 if (!sep) { |
|
148 /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all |
|
149 * platforms. */ |
|
150 sep = PORT_Strrchr(dirPath,'\\'); |
|
151 } |
|
152 #endif |
|
153 if (sep) { |
|
154 *sep = 0; |
|
155 file = PR_smprintf("%s"NSSUTIL_PATH_SEPARATOR"%s", dirPath, filename); |
|
156 } else { |
|
157 file = PR_smprintf("%s", filename); |
|
158 } |
|
159 PORT_Free(dirPath); |
|
160 return file; |
|
161 } |
|
162 |
|
163 static SECStatus nssutil_AddSecmodDBEntry(const char *appName, |
|
164 const char *filename, |
|
165 const char *dbname, |
|
166 char *module, PRBool rw); |
|
167 |
|
168 enum lfopen_mode { lfopen_truncate, lfopen_append }; |
|
169 |
|
170 FILE * |
|
171 lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms) |
|
172 { |
|
173 int fd; |
|
174 FILE *file; |
|
175 |
|
176 fd = os_open(name, |
|
177 (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags, |
|
178 open_perms); |
|
179 if (fd < 0) { |
|
180 return NULL; |
|
181 } |
|
182 file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+"); |
|
183 if (!file) { |
|
184 close(fd); |
|
185 } |
|
186 /* file inherits fd */ |
|
187 return file; |
|
188 } |
|
189 |
|
190 #define MAX_LINE_LENGTH 2048 |
|
191 |
|
192 /* |
|
193 * Read all the existing modules in out of the file. |
|
194 */ |
|
195 static char ** |
|
196 nssutil_ReadSecmodDB(const char *appName, |
|
197 const char *filename, const char *dbname, |
|
198 char *params, PRBool rw) |
|
199 { |
|
200 FILE *fd = NULL; |
|
201 char **moduleList = NULL; |
|
202 int moduleCount = 1; |
|
203 int useCount = SECMOD_STEP; |
|
204 char line[MAX_LINE_LENGTH]; |
|
205 PRBool internal = PR_FALSE; |
|
206 PRBool skipParams = PR_FALSE; |
|
207 char *moduleString = NULL; |
|
208 char *paramsValue=NULL; |
|
209 PRBool failed = PR_TRUE; |
|
210 |
|
211 moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **)); |
|
212 if (moduleList == NULL) return NULL; |
|
213 |
|
214 if (dbname == NULL) { |
|
215 goto return_default; |
|
216 } |
|
217 |
|
218 /* do we really want to use streams here */ |
|
219 fd = fopen(dbname, "r"); |
|
220 if (fd == NULL) goto done; |
|
221 |
|
222 /* |
|
223 * the following loop takes line separated config lines and collapses |
|
224 * the lines to a single string, escaping and quoting as necessary. |
|
225 */ |
|
226 /* loop state variables */ |
|
227 moduleString = NULL; /* current concatenated string */ |
|
228 internal = PR_FALSE; /* is this an internal module */ |
|
229 skipParams = PR_FALSE; /* did we find an override parameter block*/ |
|
230 paramsValue = NULL; /* the current parameter block value */ |
|
231 while (fgets(line, sizeof(line), fd) != NULL) { |
|
232 int len = PORT_Strlen(line); |
|
233 |
|
234 /* remove the ending newline */ |
|
235 if (len && line[len-1] == '\n') { |
|
236 len--; |
|
237 line[len] = 0; |
|
238 } |
|
239 if (*line == '#') { |
|
240 continue; |
|
241 } |
|
242 if (*line != 0) { |
|
243 /* |
|
244 * The PKCS #11 group standard assumes blocks of strings |
|
245 * separated by new lines, clumped by new lines. Internally |
|
246 * we take strings separated by spaces, so we may need to escape |
|
247 * certain spaces. |
|
248 */ |
|
249 char *value = PORT_Strchr(line,'='); |
|
250 |
|
251 /* there is no value, write out the stanza as is */ |
|
252 if (value == NULL || value[1] == 0) { |
|
253 if (moduleString) { |
|
254 moduleString = nssutil_DupnCat(moduleString," ", 1); |
|
255 if (moduleString == NULL) goto loser; |
|
256 } |
|
257 moduleString = nssutil_DupCat(moduleString, line); |
|
258 if (moduleString == NULL) goto loser; |
|
259 /* value is already quoted, just write it out */ |
|
260 } else if (value[1] == '"') { |
|
261 if (moduleString) { |
|
262 moduleString = nssutil_DupnCat(moduleString," ", 1); |
|
263 if (moduleString == NULL) goto loser; |
|
264 } |
|
265 moduleString = nssutil_DupCat(moduleString, line); |
|
266 if (moduleString == NULL) goto loser; |
|
267 /* we have an override parameter section, remember that |
|
268 * we found this (see following comment about why this |
|
269 * is necessary). */ |
|
270 if (PORT_Strncasecmp(line, "parameters", 10) == 0) { |
|
271 skipParams = PR_TRUE; |
|
272 } |
|
273 /* |
|
274 * The internal token always overrides it's parameter block |
|
275 * from the passed in parameters, so wait until then end |
|
276 * before we include the parameter block in case we need to |
|
277 * override it. NOTE: if the parameter block is quoted with ("), |
|
278 * this override does not happen. This allows you to override |
|
279 * the application's parameter configuration. |
|
280 * |
|
281 * parameter block state is controlled by the following variables: |
|
282 * skipParams - Bool : set to true of we have an override param |
|
283 * block (all other blocks, either implicit or explicit are |
|
284 * ignored). |
|
285 * paramsValue - char * : pointer to the current param block. In |
|
286 * the absence of overrides, paramsValue is set to the first |
|
287 * parameter block we find. All subsequent blocks are ignored. |
|
288 * When we find an internal token, the application passed |
|
289 * parameters take precident. |
|
290 */ |
|
291 } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) { |
|
292 /* already have parameters */ |
|
293 if (paramsValue) { |
|
294 continue; |
|
295 } |
|
296 paramsValue = NSSUTIL_Quote(&value[1], '"'); |
|
297 if (paramsValue == NULL) goto loser; |
|
298 continue; |
|
299 } else { |
|
300 /* may need to quote */ |
|
301 char *newLine; |
|
302 if (moduleString) { |
|
303 moduleString = nssutil_DupnCat(moduleString," ", 1); |
|
304 if (moduleString == NULL) goto loser; |
|
305 } |
|
306 moduleString = nssutil_DupnCat(moduleString,line,value-line+1); |
|
307 if (moduleString == NULL) goto loser; |
|
308 newLine = NSSUTIL_Quote(&value[1],'"'); |
|
309 if (newLine == NULL) goto loser; |
|
310 moduleString = nssutil_DupCat(moduleString,newLine); |
|
311 PORT_Free(newLine); |
|
312 if (moduleString == NULL) goto loser; |
|
313 } |
|
314 |
|
315 /* check to see if it's internal? */ |
|
316 if (PORT_Strncasecmp(line, "NSS=", 4) == 0) { |
|
317 /* This should be case insensitive! reviewers make |
|
318 * me fix it if it's not */ |
|
319 if (PORT_Strstr(line,"internal")) { |
|
320 internal = PR_TRUE; |
|
321 /* override the parameters */ |
|
322 if (paramsValue) { |
|
323 PORT_Free(paramsValue); |
|
324 } |
|
325 paramsValue = NSSUTIL_Quote(params, '"'); |
|
326 } |
|
327 } |
|
328 continue; |
|
329 } |
|
330 if ((moduleString == NULL) || (*moduleString == 0)) { |
|
331 continue; |
|
332 } |
|
333 |
|
334 /* |
|
335 * if we are here, we have found a complete stanza. Now write out |
|
336 * any param section we may have found. |
|
337 */ |
|
338 if (paramsValue) { |
|
339 /* we had an override */ |
|
340 if (!skipParams) { |
|
341 moduleString = nssutil_DupnCat(moduleString," parameters=", 12); |
|
342 if (moduleString == NULL) goto loser; |
|
343 moduleString = nssutil_DupCat(moduleString, paramsValue); |
|
344 if (moduleString == NULL) goto loser; |
|
345 } |
|
346 PORT_Free(paramsValue); |
|
347 paramsValue = NULL; |
|
348 } |
|
349 |
|
350 if ((moduleCount+1) >= useCount) { |
|
351 SECStatus rv; |
|
352 rv = nssutil_growList(&moduleList, &useCount, moduleCount+1); |
|
353 if (rv != SECSuccess) { |
|
354 goto loser; |
|
355 } |
|
356 } |
|
357 |
|
358 if (internal) { |
|
359 moduleList[0] = moduleString; |
|
360 } else { |
|
361 moduleList[moduleCount] = moduleString; |
|
362 moduleCount++; |
|
363 } |
|
364 moduleString = NULL; |
|
365 internal = PR_FALSE; |
|
366 skipParams = PR_FALSE; |
|
367 } |
|
368 |
|
369 if (moduleString) { |
|
370 PORT_Free(moduleString); |
|
371 moduleString = NULL; |
|
372 } |
|
373 done: |
|
374 /* if we couldn't open a pkcs11 database, look for the old one */ |
|
375 if (fd == NULL) { |
|
376 char *olddbname = _NSSUTIL_GetOldSecmodName(dbname,filename); |
|
377 PRStatus status; |
|
378 |
|
379 /* couldn't get the old name */ |
|
380 if (!olddbname) { |
|
381 goto bail; |
|
382 } |
|
383 |
|
384 /* old one exists */ |
|
385 status = PR_Access(olddbname, PR_ACCESS_EXISTS); |
|
386 if (status == PR_SUCCESS) { |
|
387 PR_smprintf_free(olddbname); |
|
388 PORT_ZFree(moduleList, useCount*sizeof(char **)); |
|
389 PORT_SetError(SEC_ERROR_LEGACY_DATABASE); |
|
390 return NULL; |
|
391 } |
|
392 |
|
393 bail: |
|
394 if (olddbname) { |
|
395 PR_smprintf_free(olddbname); |
|
396 } |
|
397 } |
|
398 |
|
399 return_default: |
|
400 |
|
401 if (!moduleList[0]) { |
|
402 char * newParams; |
|
403 moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1); |
|
404 newParams = NSSUTIL_Quote(params,'"'); |
|
405 if (newParams == NULL) goto loser; |
|
406 moduleString = nssutil_DupCat(moduleString, newParams); |
|
407 PORT_Free(newParams); |
|
408 if (moduleString == NULL) goto loser; |
|
409 moduleString = nssutil_DupCat(moduleString, |
|
410 NSSUTIL_DEFAULT_INTERNAL_INIT2); |
|
411 if (moduleString == NULL) goto loser; |
|
412 moduleString = nssutil_DupCat(moduleString, |
|
413 NSSUTIL_DEFAULT_SFTKN_FLAGS); |
|
414 if (moduleString == NULL) goto loser; |
|
415 moduleString = nssutil_DupCat(moduleString, |
|
416 NSSUTIL_DEFAULT_INTERNAL_INIT3); |
|
417 if (moduleString == NULL) goto loser; |
|
418 moduleList[0] = moduleString; |
|
419 moduleString = NULL; |
|
420 } |
|
421 failed = PR_FALSE; |
|
422 |
|
423 loser: |
|
424 /* |
|
425 * cleanup |
|
426 */ |
|
427 /* deal with trust cert db here */ |
|
428 if (moduleString) { |
|
429 PORT_Free(moduleString); |
|
430 moduleString = NULL; |
|
431 } |
|
432 if (paramsValue) { |
|
433 PORT_Free(paramsValue); |
|
434 paramsValue = NULL; |
|
435 } |
|
436 if (failed || (moduleList[0] == NULL)) { |
|
437 /* This is wrong! FIXME */ |
|
438 nssutil_releaseSpecList(moduleList); |
|
439 moduleList = NULL; |
|
440 failed = PR_TRUE; |
|
441 } |
|
442 if (fd != NULL) { |
|
443 fclose(fd); |
|
444 } else if (!failed && rw) { |
|
445 /* update our internal module */ |
|
446 nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw); |
|
447 } |
|
448 return moduleList; |
|
449 } |
|
450 |
|
451 static SECStatus |
|
452 nssutil_ReleaseSecmodDBData(const char *appName, |
|
453 const char *filename, const char *dbname, |
|
454 char **moduleSpecList, PRBool rw) |
|
455 { |
|
456 if (moduleSpecList) { |
|
457 nssutil_releaseSpecList(moduleSpecList); |
|
458 } |
|
459 return SECSuccess; |
|
460 } |
|
461 |
|
462 |
|
463 /* |
|
464 * Delete a module from the Data Base |
|
465 */ |
|
466 static SECStatus |
|
467 nssutil_DeleteSecmodDBEntry(const char *appName, |
|
468 const char *filename, |
|
469 const char *dbname, |
|
470 char *args, |
|
471 PRBool rw) |
|
472 { |
|
473 /* SHDB_FIXME implement */ |
|
474 os_stat_type stat_existing; |
|
475 os_open_permissions_type file_mode; |
|
476 FILE *fd = NULL; |
|
477 FILE *fd2 = NULL; |
|
478 char line[MAX_LINE_LENGTH]; |
|
479 char *dbname2 = NULL; |
|
480 char *block = NULL; |
|
481 char *name = NULL; |
|
482 char *lib = NULL; |
|
483 int name_len, lib_len; |
|
484 PRBool skip = PR_FALSE; |
|
485 PRBool found = PR_FALSE; |
|
486 |
|
487 if (dbname == NULL) { |
|
488 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
489 return SECFailure; |
|
490 } |
|
491 |
|
492 if (!rw) { |
|
493 PORT_SetError(SEC_ERROR_READ_ONLY); |
|
494 return SECFailure; |
|
495 } |
|
496 |
|
497 dbname2 = PORT_Strdup(dbname); |
|
498 if (dbname2 == NULL) goto loser; |
|
499 dbname2[strlen(dbname)-1]++; |
|
500 |
|
501 /* get the permissions of the existing file, or use the default */ |
|
502 if (!os_stat(dbname, &stat_existing)) { |
|
503 file_mode = stat_existing.st_mode; |
|
504 } else { |
|
505 file_mode = os_open_permissions_default; |
|
506 } |
|
507 |
|
508 /* do we really want to use streams here */ |
|
509 fd = fopen(dbname, "r"); |
|
510 if (fd == NULL) goto loser; |
|
511 |
|
512 fd2 = lfopen(dbname2, lfopen_truncate, file_mode); |
|
513 |
|
514 if (fd2 == NULL) goto loser; |
|
515 |
|
516 name = NSSUTIL_ArgGetParamValue("name",args); |
|
517 if (name) { |
|
518 name_len = PORT_Strlen(name); |
|
519 } |
|
520 lib = NSSUTIL_ArgGetParamValue("library",args); |
|
521 if (lib) { |
|
522 lib_len = PORT_Strlen(lib); |
|
523 } |
|
524 |
|
525 |
|
526 /* |
|
527 * the following loop takes line separated config files and collapses |
|
528 * the lines to a single string, escaping and quoting as necessary. |
|
529 */ |
|
530 /* loop state variables */ |
|
531 block = NULL; |
|
532 skip = PR_FALSE; |
|
533 while (fgets(line, sizeof(line), fd) != NULL) { |
|
534 /* If we are processing a block (we haven't hit a blank line yet */ |
|
535 if (*line != '\n') { |
|
536 /* skip means we are in the middle of a block we are deleting */ |
|
537 if (skip) { |
|
538 continue; |
|
539 } |
|
540 /* if we haven't found the block yet, check to see if this block |
|
541 * matches our requirements */ |
|
542 if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) && |
|
543 (PORT_Strncmp(line+5,name,name_len) == 0)) || |
|
544 (lib && (PORT_Strncasecmp(line,"library=",8) == 0) && |
|
545 (PORT_Strncmp(line+8,lib,lib_len) == 0)))) { |
|
546 |
|
547 /* yup, we don't need to save any more data, */ |
|
548 PORT_Free(block); |
|
549 block=NULL; |
|
550 /* we don't need to collect more of this block */ |
|
551 skip = PR_TRUE; |
|
552 /* we don't need to continue searching for the block */ |
|
553 found =PR_TRUE; |
|
554 continue; |
|
555 } |
|
556 /* not our match, continue to collect data in this block */ |
|
557 block = nssutil_DupCat(block,line); |
|
558 continue; |
|
559 } |
|
560 /* we've collected a block of data that wasn't the module we were |
|
561 * looking for, write it out */ |
|
562 if (block) { |
|
563 fwrite(block, PORT_Strlen(block), 1, fd2); |
|
564 PORT_Free(block); |
|
565 block = NULL; |
|
566 } |
|
567 /* If we didn't just delete the this block, keep the blank line */ |
|
568 if (!skip) { |
|
569 fputs(line,fd2); |
|
570 } |
|
571 /* we are definately not in a deleted block anymore */ |
|
572 skip = PR_FALSE; |
|
573 } |
|
574 fclose(fd); |
|
575 fclose(fd2); |
|
576 if (found) { |
|
577 /* rename dbname2 to dbname */ |
|
578 PR_Delete(dbname); |
|
579 PR_Rename(dbname2,dbname); |
|
580 } else { |
|
581 PR_Delete(dbname2); |
|
582 } |
|
583 PORT_Free(dbname2); |
|
584 PORT_Free(lib); |
|
585 PORT_Free(name); |
|
586 PORT_Free(block); |
|
587 return SECSuccess; |
|
588 |
|
589 loser: |
|
590 if (fd != NULL) { |
|
591 fclose(fd); |
|
592 } |
|
593 if (fd2 != NULL) { |
|
594 fclose(fd2); |
|
595 } |
|
596 if (dbname2) { |
|
597 PR_Delete(dbname2); |
|
598 PORT_Free(dbname2); |
|
599 } |
|
600 PORT_Free(lib); |
|
601 PORT_Free(name); |
|
602 return SECFailure; |
|
603 } |
|
604 |
|
605 /* |
|
606 * Add a module to the Data base |
|
607 */ |
|
608 static SECStatus |
|
609 nssutil_AddSecmodDBEntry(const char *appName, |
|
610 const char *filename, const char *dbname, |
|
611 char *module, PRBool rw) |
|
612 { |
|
613 os_stat_type stat_existing; |
|
614 os_open_permissions_type file_mode; |
|
615 FILE *fd = NULL; |
|
616 char *block = NULL; |
|
617 PRBool libFound = PR_FALSE; |
|
618 |
|
619 if (dbname == NULL) { |
|
620 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
621 return SECFailure; |
|
622 } |
|
623 |
|
624 /* can't write to a read only module */ |
|
625 if (!rw) { |
|
626 PORT_SetError(SEC_ERROR_READ_ONLY); |
|
627 return SECFailure; |
|
628 } |
|
629 |
|
630 /* remove the previous version if it exists */ |
|
631 (void) nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw); |
|
632 |
|
633 /* get the permissions of the existing file, or use the default */ |
|
634 if (!os_stat(dbname, &stat_existing)) { |
|
635 file_mode = stat_existing.st_mode; |
|
636 } else { |
|
637 file_mode = os_open_permissions_default; |
|
638 } |
|
639 |
|
640 fd = lfopen(dbname, lfopen_append, file_mode); |
|
641 if (fd == NULL) { |
|
642 return SECFailure; |
|
643 } |
|
644 module = NSSUTIL_ArgStrip(module); |
|
645 while (*module) { |
|
646 int count; |
|
647 char *keyEnd = PORT_Strchr(module,'='); |
|
648 char *value; |
|
649 |
|
650 if (PORT_Strncmp(module, "library=", 8) == 0) { |
|
651 libFound=PR_TRUE; |
|
652 } |
|
653 if (keyEnd == NULL) { |
|
654 block = nssutil_DupCat(block, module); |
|
655 break; |
|
656 } |
|
657 block = nssutil_DupnCat(block, module, keyEnd-module+1); |
|
658 if (block == NULL) { goto loser; } |
|
659 value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count); |
|
660 if (value) { |
|
661 block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value)); |
|
662 PORT_Free(value); |
|
663 } |
|
664 if (block == NULL) { goto loser; } |
|
665 block = nssutil_DupnCat(block, "\n", 1); |
|
666 module = keyEnd + 1 + count; |
|
667 module = NSSUTIL_ArgStrip(module); |
|
668 } |
|
669 if (block) { |
|
670 if (!libFound) { |
|
671 fprintf(fd,"library=\n"); |
|
672 } |
|
673 fwrite(block, PORT_Strlen(block), 1, fd); |
|
674 fprintf(fd,"\n"); |
|
675 PORT_Free(block); |
|
676 block = NULL; |
|
677 } |
|
678 fclose(fd); |
|
679 return SECSuccess; |
|
680 |
|
681 loser: |
|
682 PORT_Free(block); |
|
683 fclose(fd); |
|
684 return SECFailure; |
|
685 } |
|
686 |
|
687 |
|
688 char ** |
|
689 NSSUTIL_DoModuleDBFunction(unsigned long function,char *parameters, void *args) |
|
690 { |
|
691 char *secmod = NULL; |
|
692 char *appName = NULL; |
|
693 char *filename = NULL; |
|
694 NSSDBType dbType = NSS_DB_TYPE_NONE; |
|
695 PRBool rw; |
|
696 static char *success="Success"; |
|
697 char **rvstr = NULL; |
|
698 |
|
699 |
|
700 secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName, |
|
701 &filename, &rw); |
|
702 if ((dbType == NSS_DB_TYPE_LEGACY) || |
|
703 (dbType == NSS_DB_TYPE_MULTIACCESS)) { |
|
704 /* we can't handle the old database, only softoken can */ |
|
705 PORT_SetError(SEC_ERROR_LEGACY_DATABASE); |
|
706 rvstr = NULL; |
|
707 goto done; |
|
708 } |
|
709 |
|
710 switch (function) { |
|
711 case SECMOD_MODULE_DB_FUNCTION_FIND: |
|
712 rvstr = nssutil_ReadSecmodDB(appName,filename, |
|
713 secmod,(char *)parameters,rw); |
|
714 break; |
|
715 case SECMOD_MODULE_DB_FUNCTION_ADD: |
|
716 rvstr = (nssutil_AddSecmodDBEntry(appName, filename, |
|
717 secmod, (char *)args, rw) |
|
718 == SECSuccess) ? &success: NULL; |
|
719 break; |
|
720 case SECMOD_MODULE_DB_FUNCTION_DEL: |
|
721 rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename, |
|
722 secmod, (char *)args, rw) |
|
723 == SECSuccess) ? &success: NULL; |
|
724 break; |
|
725 case SECMOD_MODULE_DB_FUNCTION_RELEASE: |
|
726 rvstr = (nssutil_ReleaseSecmodDBData(appName, filename, |
|
727 secmod, (char **)args, rw) |
|
728 == SECSuccess) ? &success: NULL; |
|
729 break; |
|
730 } |
|
731 done: |
|
732 if (secmod) PR_smprintf_free(secmod); |
|
733 if (appName) PORT_Free(appName); |
|
734 if (filename) PORT_Free(filename); |
|
735 return rvstr; |
|
736 } |