Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / security / nss / lib / softoken / sftkmod.c
blob408270bdd0965b1c96ce3d4dc97c25d7072e116e
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2007
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
36 /*
37 * The following code handles the storage of PKCS 11 modules used by the
38 * NSS. For the rest of NSS, only one kind of database handle exists:
40 * SFTKDBHandle
42 * There is one SFTKDBHandle for the each key database and one for each cert
43 * database. These databases are opened as associated pairs, one pair per
44 * slot. SFTKDBHandles are reference counted objects.
46 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
47 * represents the underlying physical database. These objects are not
48 * reference counted, an are 'owned' by their respective SFTKDBHandles.
52 #include "sftkdb.h"
53 #include "sftkpars.h"
54 #include "prprf.h"
55 #include "prsystem.h"
56 #include "lgglue.h"
57 #include "secmodt.h"
59 /****************************************************************
61 * Secmod database.
63 * The new secmod database is simply a text file with each of the module
64 * entries. in the following form:
66 * #
67 * # This is a comment The next line is the library to load
68 * library=libmypkcs11.so
69 * name="My PKCS#11 module"
70 * params="my library's param string"
71 * nss="NSS parameters"
72 * other="parameters for other libraries and applications"
74 * library=libmynextpk11.so
75 * name="My other PKCS#11 module"
78 static char *
79 sftkdb_quote(const char *string, char quote)
81 char *newString = 0;
82 int escapes = 0, size = 0;
83 const char *src;
84 char *dest;
86 size=2;
87 for (src=string; *src ; src++) {
88 if ((*src == quote) || (*src == '\\')) escapes++;
89 size++;
92 dest = newString = PORT_ZAlloc(escapes+size+1);
93 if (newString == NULL) {
94 return NULL;
97 *dest++=quote;
98 for (src=string; *src; src++,dest++) {
99 if ((*src == '\\') || (*src == quote)) {
100 *dest++ = '\\';
102 *dest = *src;
104 *dest=quote;
106 return newString;
110 * Smart string cat functions. Automatically manage the memory.
111 * The first parameter is the source string. If it's null, we
112 * allocate memory for it. If it's not, we reallocate memory
113 * so the the concanenated string fits.
115 static char *
116 sftkdb_DupnCat(char *baseString, const char *str, int str_len)
118 int len = (baseString ? PORT_Strlen(baseString) : 0) + 1;
119 char *newString;
121 len += str_len;
122 newString = (char *) PORT_Realloc(baseString,len);
123 if (newString == NULL) {
124 PORT_Free(baseString);
125 return NULL;
127 if (baseString == NULL) *newString = 0;
128 return PORT_Strncat(newString,str, str_len);
131 /* Same as sftkdb_DupnCat except it concatenates the full string, not a
132 * partial one */
133 static char *
134 sftkdb_DupCat(char *baseString, const char *str)
136 return sftkdb_DupnCat(baseString, str, PORT_Strlen(str));
139 /* function to free up all the memory associated with a null terminated
140 * array of module specs */
141 static SECStatus
142 sftkdb_releaseSpecList(char **moduleSpecList)
144 if (moduleSpecList) {
145 char **index;
146 for(index = moduleSpecList; *index; index++) {
147 PORT_Free(*index);
149 PORT_Free(moduleSpecList);
151 return SECSuccess;
154 #define SECMOD_STEP 10
155 static SECStatus
156 sftkdb_growList(char ***pModuleList, int *useCount, int last)
158 char **newModuleList;
160 *useCount += SECMOD_STEP;
161 newModuleList = (char **)PORT_Realloc(*pModuleList,
162 *useCount*sizeof(char *));
163 if (newModuleList == NULL) {
164 return SECFailure;
166 PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP);
167 *pModuleList = newModuleList;
168 return SECSuccess;
171 static
172 char *sftk_getOldSecmodName(const char *dbname,const char *filename)
174 char *file = NULL;
175 char *dirPath = PORT_Strdup(dbname);
176 char *sep;
178 sep = PORT_Strrchr(dirPath,*PATH_SEPARATOR);
179 #ifdef WINDOWS
180 if (!sep) {
181 sep = PORT_Strrchr(dirPath,'/');
183 #endif
184 if (sep) {
185 *(sep)=0;
187 file= PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, filename);
188 PORT_Free(dirPath);
189 return file;
192 #define MAX_LINE_LENGTH 2048
193 #define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters="
194 #define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={"
195 #define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\""
197 #ifdef XP_UNIX
198 #include <unistd.h>
199 #endif
201 * Read all the existing modules in out of the file.
203 char **
204 sftkdb_ReadSecmodDB(SDBType dbType, const char *appName,
205 const char *filename, const char *dbname,
206 char *params, PRBool rw)
208 FILE *fd = NULL;
209 char **moduleList = NULL;
210 int moduleCount = 1;
211 int useCount = SECMOD_STEP;
212 char line[MAX_LINE_LENGTH];
213 PRBool internal = PR_FALSE;
214 PRBool skipParams = PR_FALSE;
215 char *moduleString = NULL;
216 char *paramsValue=NULL;
217 PRBool failed = PR_TRUE;
219 if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
220 return sftkdbCall_ReadSecmodDB(appName, filename, dbname, params, rw);
223 moduleList = (char **) PORT_ZAlloc(useCount*sizeof(char **));
224 if (moduleList == NULL) return NULL;
226 /* do we really want to use streams here */
227 fd = fopen(dbname, "r");
228 if (fd == NULL) goto done;
231 * the following loop takes line separated config lines and colapses
232 * the lines to a single string, escaping and quoting as necessary.
234 /* loop state variables */
235 moduleString = NULL; /* current concatenated string */
236 internal = PR_FALSE; /* is this an internal module */
237 skipParams = PR_FALSE; /* did we find an override parameter block*/
238 paramsValue = NULL; /* the current parameter block value */
239 while (fgets(line, sizeof(line), fd) != NULL) {
240 int len = PORT_Strlen(line);
242 /* remove the ending newline */
243 if (len && line[len-1] == '\n') {
244 len--;
245 line[len] = 0;
247 if (*line == '#') {
248 continue;
250 if (*line != 0) {
252 * The PKCS #11 group standard assumes blocks of strings
253 * separated by new lines, clumped by new lines. Internally
254 * we take strings separated by spaces, so we may need to escape
255 * certain spaces.
257 char *value = PORT_Strchr(line,'=');
259 /* there is no value, write out the stanza as is */
260 if (value == NULL || value[1] == 0) {
261 if (moduleString) {
262 moduleString = sftkdb_DupnCat(moduleString," ", 1);
263 if (moduleString == NULL) goto loser;
265 moduleString = sftkdb_DupCat(moduleString, line);
266 if (moduleString == NULL) goto loser;
267 /* value is already quoted, just write it out */
268 } else if (value[1] == '"') {
269 if (moduleString) {
270 moduleString = sftkdb_DupnCat(moduleString," ", 1);
271 if (moduleString == NULL) goto loser;
273 moduleString = sftkdb_DupCat(moduleString, line);
274 if (moduleString == NULL) goto loser;
275 /* we have an override parameter section, remember that
276 * we found this (see following comment about why this
277 * is necessary). */
278 if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
279 skipParams = PR_TRUE;
282 * The internal token always overrides it's parameter block
283 * from the passed in parameters, so wait until then end
284 * before we include the parameter block in case we need to
285 * override it. NOTE: if the parameter block is quoted with ("),
286 * this override does not happen. This allows you to override
287 * the application's parameter configuration.
289 * parameter block state is controlled by the following variables:
290 * skipParams - Bool : set to true of we have an override param
291 * block (all other blocks, either implicit or explicit are
292 * ignored).
293 * paramsValue - char * : pointer to the current param block. In
294 * the absence of overrides, paramsValue is set to the first
295 * parameter block we find. All subsequent blocks are ignored.
296 * When we find an internal token, the application passed
297 * parameters take precident.
299 } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
300 /* already have parameters */
301 if (paramsValue) {
302 continue;
304 paramsValue = sftkdb_quote(&value[1], '"');
305 if (paramsValue == NULL) goto loser;
306 continue;
307 } else {
308 /* may need to quote */
309 char *newLine;
310 if (moduleString) {
311 moduleString = sftkdb_DupnCat(moduleString," ", 1);
312 if (moduleString == NULL) goto loser;
314 moduleString = sftkdb_DupnCat(moduleString,line,value-line+1);
315 if (moduleString == NULL) goto loser;
316 newLine = sftkdb_quote(&value[1],'"');
317 if (newLine == NULL) goto loser;
318 moduleString = sftkdb_DupCat(moduleString,newLine);
319 PORT_Free(newLine);
320 if (moduleString == NULL) goto loser;
323 /* check to see if it's internal? */
324 if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
325 /* This should be case insensitive! reviewers make
326 * me fix it if it's not */
327 if (PORT_Strstr(line,"internal")) {
328 internal = PR_TRUE;
329 /* override the parameters */
330 if (paramsValue) {
331 PORT_Free(paramsValue);
333 paramsValue = sftkdb_quote(params, '"');
336 continue;
338 if ((moduleString == NULL) || (*moduleString == 0)) {
339 continue;
343 * if we are here, we have found a complete stanza. Now write out
344 * any param section we may have found.
346 if (paramsValue) {
347 /* we had an override */
348 if (!skipParams) {
349 moduleString = sftkdb_DupnCat(moduleString," parameters=", 12);
350 if (moduleString == NULL) goto loser;
351 moduleString = sftkdb_DupCat(moduleString, paramsValue);
352 if (moduleString == NULL) goto loser;
354 PORT_Free(paramsValue);
355 paramsValue = NULL;
358 if ((moduleCount+1) >= useCount) {
359 SECStatus rv;
360 rv = sftkdb_growList(&moduleList, &useCount, moduleCount+1);
361 if (rv != SECSuccess) {
362 goto loser;
366 if (internal) {
367 moduleList[0] = moduleString;
368 } else {
369 moduleList[moduleCount] = moduleString;
370 moduleCount++;
372 moduleString = NULL;
373 internal = PR_FALSE;
374 skipParams = PR_FALSE;
377 if (moduleString) {
378 PORT_Free(moduleString);
379 moduleString = NULL;
381 done:
382 /* if we couldn't open a pkcs11 database, look for the old one */
383 if (fd == NULL) {
384 char *olddbname = sftk_getOldSecmodName(dbname,filename);
385 PRStatus status;
386 char **oldModuleList;
387 int i;
389 /* couldn't get the old name */
390 if (!olddbname) {
391 goto bail;
394 /* old one doesn't exist */
395 status = PR_Access(olddbname, PR_ACCESS_EXISTS);
396 if (status != PR_SUCCESS) {
397 goto bail;
400 oldModuleList = sftkdbCall_ReadSecmodDB(appName, filename,
401 olddbname, params, rw);
402 /* old one had no modules */
403 if (!oldModuleList) {
404 goto bail;
407 /* count the modules */
408 for (i=0; oldModuleList[i]; i++) { }
410 /* grow the moduleList if necessary */
411 if (i >= useCount) {
412 SECStatus rv;
413 rv = sftkdb_growList(&moduleList,&useCount,moduleCount+1);
414 if (rv != SECSuccess) {
415 goto loser;
419 /* write each module out, and copy it */
420 for (i=0; oldModuleList[i]; i++) {
421 if (rw) {
422 sftkdb_AddSecmodDB(dbType,appName,filename,dbname,
423 oldModuleList[i],rw);
425 if (moduleList[i]) {
426 PORT_Free(moduleList[i]);
428 moduleList[i] = PORT_Strdup(oldModuleList[i]);
431 /* done with the old module list */
432 sftkdbCall_ReleaseSecmodDBData(appName, filename, olddbname,
433 oldModuleList, rw);
434 bail:
435 if (olddbname) {
436 PR_smprintf_free(olddbname);
440 if (!moduleList[0]) {
441 char * newParams;
442 moduleString = PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1);
443 newParams = sftkdb_quote(params,'"');
444 if (newParams == NULL) goto loser;
445 moduleString = sftkdb_DupCat(moduleString, newParams);
446 PORT_Free(newParams);
447 if (moduleString == NULL) goto loser;
448 moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT2);
449 if (moduleString == NULL) goto loser;
450 moduleString = sftkdb_DupCat(moduleString, SECMOD_SLOT_FLAGS);
451 if (moduleString == NULL) goto loser;
452 moduleString = sftkdb_DupCat(moduleString, SFTK_DEFAULT_INTERNAL_INIT3);
453 if (moduleString == NULL) goto loser;
454 moduleList[0] = moduleString;
455 moduleString = NULL;
457 failed = PR_FALSE;
459 loser:
461 * cleanup
463 /* deal with trust cert db here */
464 if (moduleString) {
465 PORT_Free(moduleString);
466 moduleString = NULL;
468 if (paramsValue) {
469 PORT_Free(paramsValue);
470 paramsValue = NULL;
472 if (failed || (moduleList[0] == NULL)) {
473 /* This is wrong! FIXME */
474 sftkdb_releaseSpecList(moduleList);
475 moduleList = NULL;
476 failed = PR_TRUE;
478 if (fd != NULL) {
479 fclose(fd);
480 } else if (!failed && rw) {
481 /* update our internal module */
482 sftkdb_AddSecmodDB(dbType,appName,filename,dbname,moduleList[0],rw);
484 return moduleList;
487 SECStatus
488 sftkdb_ReleaseSecmodDBData(SDBType dbType, const char *appName,
489 const char *filename, const char *dbname,
490 char **moduleSpecList, PRBool rw)
492 if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
493 return sftkdbCall_ReleaseSecmodDBData(appName, filename, dbname,
494 moduleSpecList, rw);
496 if (moduleSpecList) {
497 sftkdb_releaseSpecList(moduleSpecList);
499 return SECSuccess;
504 * Delete a module from the Data Base
506 SECStatus
507 sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName,
508 const char *filename, const char *dbname,
509 char *args, PRBool rw)
511 /* SHDB_FIXME implement */
512 FILE *fd = NULL;
513 FILE *fd2 = NULL;
514 char line[MAX_LINE_LENGTH];
515 char *dbname2 = NULL;
516 char *block = NULL;
517 char *name = NULL;
518 char *lib = NULL;
519 int name_len, lib_len;
520 PRBool skip = PR_FALSE;
521 PRBool found = PR_FALSE;
523 if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
524 return sftkdbCall_DeleteSecmodDB(appName, filename, dbname, args, rw);
527 if (!rw) {
528 return SECFailure;
531 dbname2 = strdup(dbname);
532 if (dbname2 == NULL) goto loser;
533 dbname2[strlen(dbname)-1]++;
535 /* do we really want to use streams here */
536 fd = fopen(dbname, "r");
537 if (fd == NULL) goto loser;
538 fd2 = fopen(dbname2, "w+");
539 if (fd2 == NULL) goto loser;
541 name = sftk_argGetParamValue("name",args);
542 if (name) {
543 name_len = PORT_Strlen(name);
545 lib = sftk_argGetParamValue("library",args);
546 if (lib) {
547 lib_len = PORT_Strlen(lib);
552 * the following loop takes line separated config files and colapses
553 * the lines to a single string, escaping and quoting as necessary.
555 /* loop state variables */
556 block = NULL;
557 skip = PR_FALSE;
558 while (fgets(line, sizeof(line), fd) != NULL) {
559 /* If we are processing a block (we haven't hit a blank line yet */
560 if (*line != '\n') {
561 /* skip means we are in the middle of a block we are deleting */
562 if (skip) {
563 continue;
565 /* if we haven't found the block yet, check to see if this block
566 * matches our requirements */
567 if (!found && ((name && (PORT_Strncasecmp(line,"name=",5) == 0) &&
568 (PORT_Strncmp(line+5,name,name_len) == 0)) ||
569 (lib && (PORT_Strncasecmp(line,"library=",8) == 0) &&
570 (PORT_Strncmp(line+8,lib,lib_len) == 0)))) {
572 /* yup, we don't need to save any more data, */
573 PORT_Free(block);
574 block=NULL;
575 /* we don't need to collect more of this block */
576 skip = PR_TRUE;
577 /* we don't need to continue searching for the block */
578 found =PR_TRUE;
579 continue;
581 /* not our match, continue to collect data in this block */
582 block = sftkdb_DupCat(block,line);
583 continue;
585 /* we've collected a block of data that wasn't the module we were
586 * looking for, write it out */
587 if (block) {
588 fwrite(block, PORT_Strlen(block), 1, fd2);
589 PORT_Free(block);
590 block = NULL;
592 /* If we didn't just delete the this block, keep the blank line */
593 if (!skip) {
594 fputs(line,fd2);
596 /* we are definately not in a deleted block anymore */
597 skip = PR_FALSE;
599 fclose(fd);
600 fclose(fd2);
601 /* rename dbname2 to dbname */
602 if (found) {
603 PR_Delete(dbname);
604 PR_Rename(dbname2,dbname);
606 PORT_Free(dbname2);
607 return SECSuccess;
609 loser:
610 if (fd != NULL) {
611 fclose(fd);
613 if (fd2 != NULL) {
614 fclose(fd2);
616 if (dbname2) {
617 PR_Delete(dbname2);
618 PORT_Free(dbname2);
620 return SECFailure;
624 * Add a module to the Data base
626 SECStatus
627 sftkdb_AddSecmodDB(SDBType dbType, const char *appName,
628 const char *filename, const char *dbname,
629 char *module, PRBool rw)
631 FILE *fd = NULL;
632 char *block = NULL;
633 PRBool libFound = PR_FALSE;
635 if ((dbType == SDB_LEGACY) || (dbType == SDB_MULTIACCESS)) {
636 return sftkdbCall_AddSecmodDB(appName, filename, dbname, module, rw);
639 /* can't write to a read only module */
640 if (!rw) {
641 return SECFailure;
644 /* remove the previous version if it exists */
645 (void) sftkdb_DeleteSecmodDB(dbType, appName, filename, dbname, module, rw);
647 /* do we really want to use streams here */
648 fd = fopen(dbname, "a+");
649 if (fd == NULL) {
650 return SECFailure;
652 module = sftk_argStrip(module);
653 while (*module) {
654 int count;
655 char *keyEnd = PORT_Strchr(module,'=');
656 char *value;
658 if (PORT_Strncmp(module, "library=", 8) == 0) {
659 libFound=PR_TRUE;
661 if (keyEnd == NULL) {
662 block = sftkdb_DupCat(block, module);
663 break;
665 value = sftk_argFetchValue(&keyEnd[1], &count);
666 block = sftkdb_DupnCat(block, module, keyEnd-module+1);
667 if (block == NULL) { goto loser; }
668 if (value) {
669 block = sftkdb_DupCat(block, sftk_argStrip(value));
670 PORT_Free(value);
672 if (block == NULL) { goto loser; }
673 block = sftkdb_DupnCat(block, "\n", 1);
674 module = keyEnd + 1 + count;
675 module = sftk_argStrip(module);
677 if (block) {
678 if (!libFound) {
679 fprintf(fd,"library=\n");
681 fwrite(block, PORT_Strlen(block), 1, fd);
682 fprintf(fd,"\n");
683 PORT_Free(block);
684 block = NULL;
686 fclose(fd);
687 return SECSuccess;
689 loser:
690 PORT_Free(block);
691 fclose(fd);
692 return SECFailure;