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