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
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.
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 ***** */
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:
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.
59 /****************************************************************
63 * The new secmod database is simply a text file with each of the module
64 * entries. in the following form:
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"
79 sftkdb_quote(const char *string
, char quote
)
82 int escapes
= 0, size
= 0;
87 for (src
=string
; *src
; src
++) {
88 if ((*src
== quote
) || (*src
== '\\')) escapes
++;
92 dest
= newString
= PORT_ZAlloc(escapes
+size
+1);
93 if (newString
== NULL
) {
98 for (src
=string
; *src
; src
++,dest
++) {
99 if ((*src
== '\\') || (*src
== quote
)) {
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.
116 sftkdb_DupnCat(char *baseString
, const char *str
, int str_len
)
118 int len
= (baseString
? PORT_Strlen(baseString
) : 0) + 1;
122 newString
= (char *) PORT_Realloc(baseString
,len
);
123 if (newString
== NULL
) {
124 PORT_Free(baseString
);
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
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 */
142 sftkdb_releaseSpecList(char **moduleSpecList
)
144 if (moduleSpecList
) {
146 for(index
= moduleSpecList
; *index
; index
++) {
149 PORT_Free(moduleSpecList
);
154 #define SECMOD_STEP 10
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
) {
166 PORT_Memset(&newModuleList
[last
],0, sizeof(char *)*SECMOD_STEP
);
167 *pModuleList
= newModuleList
;
172 char *sftk_getOldSecmodName(const char *dbname
,const char *filename
)
175 char *dirPath
= PORT_Strdup(dbname
);
178 sep
= PORT_Strrchr(dirPath
,*PATH_SEPARATOR
);
181 sep
= PORT_Strrchr(dirPath
,'/');
187 file
= PR_smprintf("%s"PATH_SEPARATOR
"%s", dirPath
, filename
);
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})\""
201 * Read all the existing modules in out of the file.
204 sftkdb_ReadSecmodDB(SDBType dbType
, const char *appName
,
205 const char *filename
, const char *dbname
,
206 char *params
, PRBool rw
)
209 char **moduleList
= NULL
;
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') {
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
257 char *value
= PORT_Strchr(line
,'=');
259 /* there is no value, write out the stanza as is */
260 if (value
== NULL
|| value
[1] == 0) {
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] == '"') {
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
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
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 */
304 paramsValue
= sftkdb_quote(&value
[1], '"');
305 if (paramsValue
== NULL
) goto loser
;
308 /* may need to quote */
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
);
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")) {
329 /* override the parameters */
331 PORT_Free(paramsValue
);
333 paramsValue
= sftkdb_quote(params
, '"');
338 if ((moduleString
== NULL
) || (*moduleString
== 0)) {
343 * if we are here, we have found a complete stanza. Now write out
344 * any param section we may have found.
347 /* we had an override */
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
);
358 if ((moduleCount
+1) >= useCount
) {
360 rv
= sftkdb_growList(&moduleList
, &useCount
, moduleCount
+1);
361 if (rv
!= SECSuccess
) {
367 moduleList
[0] = moduleString
;
369 moduleList
[moduleCount
] = moduleString
;
374 skipParams
= PR_FALSE
;
378 PORT_Free(moduleString
);
382 /* if we couldn't open a pkcs11 database, look for the old one */
384 char *olddbname
= sftk_getOldSecmodName(dbname
,filename
);
386 char **oldModuleList
;
389 /* couldn't get the old name */
394 /* old one doesn't exist */
395 status
= PR_Access(olddbname
, PR_ACCESS_EXISTS
);
396 if (status
!= PR_SUCCESS
) {
400 oldModuleList
= sftkdbCall_ReadSecmodDB(appName
, filename
,
401 olddbname
, params
, rw
);
402 /* old one had no modules */
403 if (!oldModuleList
) {
407 /* count the modules */
408 for (i
=0; oldModuleList
[i
]; i
++) { }
410 /* grow the moduleList if necessary */
413 rv
= sftkdb_growList(&moduleList
,&useCount
,moduleCount
+1);
414 if (rv
!= SECSuccess
) {
419 /* write each module out, and copy it */
420 for (i
=0; oldModuleList
[i
]; i
++) {
422 sftkdb_AddSecmodDB(dbType
,appName
,filename
,dbname
,
423 oldModuleList
[i
],rw
);
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
,
436 PR_smprintf_free(olddbname
);
440 if (!moduleList
[0]) {
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
;
463 /* deal with trust cert db here */
465 PORT_Free(moduleString
);
469 PORT_Free(paramsValue
);
472 if (failed
|| (moduleList
[0] == NULL
)) {
473 /* This is wrong! FIXME */
474 sftkdb_releaseSpecList(moduleList
);
480 } else if (!failed
&& rw
) {
481 /* update our internal module */
482 sftkdb_AddSecmodDB(dbType
,appName
,filename
,dbname
,moduleList
[0],rw
);
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
,
496 if (moduleSpecList
) {
497 sftkdb_releaseSpecList(moduleSpecList
);
504 * Delete a module from the Data Base
507 sftkdb_DeleteSecmodDB(SDBType dbType
, const char *appName
,
508 const char *filename
, const char *dbname
,
509 char *args
, PRBool rw
)
511 /* SHDB_FIXME implement */
514 char line
[MAX_LINE_LENGTH
];
515 char *dbname2
= 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
);
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
);
543 name_len
= PORT_Strlen(name
);
545 lib
= sftk_argGetParamValue("library",args
);
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 */
558 while (fgets(line
, sizeof(line
), fd
) != NULL
) {
559 /* If we are processing a block (we haven't hit a blank line yet */
561 /* skip means we are in the middle of a block we are deleting */
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, */
575 /* we don't need to collect more of this block */
577 /* we don't need to continue searching for the block */
581 /* not our match, continue to collect data in this block */
582 block
= sftkdb_DupCat(block
,line
);
585 /* we've collected a block of data that wasn't the module we were
586 * looking for, write it out */
588 fwrite(block
, PORT_Strlen(block
), 1, fd2
);
592 /* If we didn't just delete the this block, keep the blank line */
596 /* we are definately not in a deleted block anymore */
601 /* rename dbname2 to dbname */
604 PR_Rename(dbname2
,dbname
);
624 * Add a module to the Data base
627 sftkdb_AddSecmodDB(SDBType dbType
, const char *appName
,
628 const char *filename
, const char *dbname
,
629 char *module
, PRBool rw
)
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 */
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+");
652 module
= sftk_argStrip(module
);
655 char *keyEnd
= PORT_Strchr(module
,'=');
658 if (PORT_Strncmp(module
, "library=", 8) == 0) {
661 if (keyEnd
== NULL
) {
662 block
= sftkdb_DupCat(block
, module
);
665 value
= sftk_argFetchValue(&keyEnd
[1], &count
);
666 block
= sftkdb_DupnCat(block
, module
, keyEnd
-module
+1);
667 if (block
== NULL
) { goto loser
; }
669 block
= sftkdb_DupCat(block
, sftk_argStrip(value
));
672 if (block
== NULL
) { goto loser
; }
673 block
= sftkdb_DupnCat(block
, "\n", 1);
674 module
= keyEnd
+ 1 + count
;
675 module
= sftk_argStrip(module
);
679 fprintf(fd
,"library=\n");
681 fwrite(block
, PORT_Strlen(block
), 1, fd
);