1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/sysinit/nsssysinit.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,403 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include "seccomon.h" 1.8 +#include "prio.h" 1.9 +#include "prprf.h" 1.10 +#include "plhash.h" 1.11 + 1.12 +/* 1.13 + * The following provides a default example for operating systems to set up 1.14 + * and manage applications loading NSS on their OS globally. 1.15 + * 1.16 + * This code hooks in to the system pkcs11.txt, which controls all the loading 1.17 + * of pkcs11 modules common to all applications. 1.18 + */ 1.19 + 1.20 +/* 1.21 + * OS Specific function to get where the NSS user database should reside. 1.22 + */ 1.23 + 1.24 +#ifdef XP_UNIX 1.25 +#include <unistd.h> 1.26 +#include <sys/stat.h> 1.27 +#include <sys/types.h> 1.28 + 1.29 +static int 1.30 +testdir(char *dir) 1.31 +{ 1.32 + struct stat buf; 1.33 + memset(&buf, 0, sizeof(buf)); 1.34 + 1.35 + if (stat(dir,&buf) < 0) { 1.36 + return 0; 1.37 + } 1.38 + 1.39 + return S_ISDIR(buf.st_mode); 1.40 +} 1.41 + 1.42 +#define NSS_USER_PATH1 "/.pki" 1.43 +#define NSS_USER_PATH2 "/nssdb" 1.44 +static char * 1.45 +getUserDB(void) 1.46 +{ 1.47 + char *userdir = getenv("HOME"); 1.48 + char *nssdir = NULL; 1.49 + 1.50 + if (userdir == NULL) { 1.51 + return NULL; 1.52 + } 1.53 + 1.54 + nssdir = PORT_Alloc(strlen(userdir) 1.55 + +sizeof(NSS_USER_PATH1)+sizeof(NSS_USER_PATH2)); 1.56 + if (nssdir == NULL) { 1.57 + return NULL; 1.58 + } 1.59 + PORT_Strcpy(nssdir, userdir); 1.60 + /* verify it exists */ 1.61 + if (!testdir(nssdir)) { 1.62 + PORT_Free(nssdir); 1.63 + return NULL; 1.64 + } 1.65 + PORT_Strcat(nssdir, NSS_USER_PATH1); 1.66 + if (!testdir(nssdir) && mkdir(nssdir, 0760)) { 1.67 + PORT_Free(nssdir); 1.68 + return NULL; 1.69 + } 1.70 + PORT_Strcat(nssdir, NSS_USER_PATH2); 1.71 + if (!testdir(nssdir) && mkdir(nssdir, 0760)) { 1.72 + PORT_Free(nssdir); 1.73 + return NULL; 1.74 + } 1.75 + return nssdir; 1.76 +} 1.77 + 1.78 +#define NSS_DEFAULT_SYSTEM "/etc/pki/nssdb" 1.79 +static char * 1.80 +getSystemDB(void) { 1.81 + return PORT_Strdup(NSS_DEFAULT_SYSTEM); 1.82 +} 1.83 + 1.84 +static PRBool 1.85 +userIsRoot() 1.86 +{ 1.87 + /* this works for linux and all unixes that we know off 1.88 + though it isn't stated as such in POSIX documentation */ 1.89 + return getuid() == 0; 1.90 +} 1.91 + 1.92 +static PRBool 1.93 +userCanModifySystemDB() 1.94 +{ 1.95 + return (access(NSS_DEFAULT_SYSTEM, W_OK) == 0); 1.96 +} 1.97 + 1.98 +#else 1.99 +#ifdef XP_WIN 1.100 +static char * 1.101 +getUserDB(void) 1.102 +{ 1.103 + /* use the registry to find the user's NSS_DIR. if no entry exists, create 1.104 + * one in the users Appdir location */ 1.105 + return NULL; 1.106 +} 1.107 + 1.108 +static char * 1.109 +getSystemDB(void) 1.110 +{ 1.111 + /* use the registry to find the system's NSS_DIR. if no entry exists, create 1.112 + * one based on the windows system data area */ 1.113 + return NULL; 1.114 +} 1.115 + 1.116 +static PRBool 1.117 +userIsRoot() 1.118 +{ 1.119 + /* use the registry to find if the user is the system administrator. */ 1.120 + return PR_FALSE; 1.121 +} 1.122 + 1.123 +static PRBool 1.124 +userCanModifySystemDB() 1.125 +{ 1.126 + /* use the registry to find if the user has administrative privilege 1.127 + * to modify the system's nss database. */ 1.128 + return PR_FALSE; 1.129 +} 1.130 + 1.131 +#else 1.132 +#error "Need to write getUserDB, SystemDB, userIsRoot, and userCanModifySystemDB functions" 1.133 +#endif 1.134 +#endif 1.135 + 1.136 +static PRBool 1.137 +getFIPSEnv(void) 1.138 +{ 1.139 + char *fipsEnv = getenv("NSS_FIPS"); 1.140 + if (!fipsEnv) { 1.141 + return PR_FALSE; 1.142 + } 1.143 + if ((strcasecmp(fipsEnv,"fips") == 0) || 1.144 + (strcasecmp(fipsEnv,"true") == 0) || 1.145 + (strcasecmp(fipsEnv,"on") == 0) || 1.146 + (strcasecmp(fipsEnv,"1") == 0)) { 1.147 + return PR_TRUE; 1.148 + } 1.149 + return PR_FALSE; 1.150 +} 1.151 +#ifdef XP_LINUX 1.152 + 1.153 +static PRBool 1.154 +getFIPSMode(void) 1.155 +{ 1.156 + FILE *f; 1.157 + char d; 1.158 + size_t size; 1.159 + 1.160 + f = fopen("/proc/sys/crypto/fips_enabled", "r"); 1.161 + if (!f) { 1.162 + /* if we don't have a proc flag, fall back to the 1.163 + * environment variable */ 1.164 + return getFIPSEnv(); 1.165 + } 1.166 + 1.167 + size = fread(&d, 1, 1, f); 1.168 + fclose(f); 1.169 + if (size != 1) 1.170 + return PR_FALSE; 1.171 + if (d != '1') 1.172 + return PR_FALSE; 1.173 + return PR_TRUE; 1.174 +} 1.175 + 1.176 +#else 1.177 +static PRBool 1.178 +getFIPSMode(void) 1.179 +{ 1.180 + return getFIPSEnv(); 1.181 +} 1.182 +#endif 1.183 + 1.184 + 1.185 +#define NSS_DEFAULT_FLAGS "flags=readonly" 1.186 + 1.187 +/* configuration flags according to 1.188 + * https://developer.mozilla.org/en/PKCS11_Module_Specs 1.189 + * As stated there the slotParams start with a slot name which is a slotID 1.190 + * Slots 1 through 3 are reserved for the nss internal modules as follows: 1.191 + * 1 for crypto operations slot non-fips, 1.192 + * 2 for the key slot, and 1.193 + * 3 for the crypto operations slot fips 1.194 + */ 1.195 +#define CIPHER_ORDER_FLAGS "cipherOrder=100" 1.196 +#define SLOT_FLAGS \ 1.197 + "[slotFlags=RSA,RC4,RC2,DES,DH,SHA1,MD5,MD2,SSL,TLS,AES,RANDOM" \ 1.198 + " askpw=any timeout=30 ]" 1.199 + 1.200 +static const char *nssDefaultFlags = 1.201 + CIPHER_ORDER_FLAGS " slotParams={0x00000001=" SLOT_FLAGS " } "; 1.202 + 1.203 +static const char *nssDefaultFIPSFlags = 1.204 + CIPHER_ORDER_FLAGS " slotParams={0x00000003=" SLOT_FLAGS " } "; 1.205 + 1.206 +/* 1.207 + * This function builds the list of databases and modules to load, and sets 1.208 + * their configuration. For the sample we have a fixed set. 1.209 + * 1. We load the user's home nss database. 1.210 + * 2. We load the user's custom PKCS #11 modules. 1.211 + * 3. We load the system nss database readonly. 1.212 + * 1.213 + * Any space allocated in get_list must be freed in release_list. 1.214 + * This function can use whatever information is available to the application. 1.215 + * it is running in the process of the application for which it is making 1.216 + * decisions, so it's possible to acquire the application name as part of 1.217 + * the decision making process. 1.218 + * 1.219 + */ 1.220 +static char ** 1.221 +get_list(char *filename, char *stripped_parameters) 1.222 +{ 1.223 + char **module_list = PORT_ZNewArray(char *, 5); 1.224 + char *userdb, *sysdb; 1.225 + int isFIPS = getFIPSMode(); 1.226 + const char *nssflags = isFIPS ? nssDefaultFIPSFlags : nssDefaultFlags; 1.227 + int next = 0; 1.228 + 1.229 + /* can't get any space */ 1.230 + if (module_list == NULL) { 1.231 + return NULL; 1.232 + } 1.233 + 1.234 + sysdb = getSystemDB(); 1.235 + userdb = getUserDB(); 1.236 + 1.237 + /* Don't open root's user DB */ 1.238 + if (userdb != NULL && !userIsRoot()) { 1.239 + /* return a list of databases to open. First the user Database */ 1.240 + module_list[next++] = PR_smprintf( 1.241 + "library= " 1.242 + "module=\"NSS User database\" " 1.243 + "parameters=\"configdir='sql:%s' %s tokenDescription='NSS user database'\" " 1.244 + "NSS=\"trustOrder=75 %sflags=internal%s\"", 1.245 + userdb, stripped_parameters, nssflags, 1.246 + isFIPS ? ",FIPS" : ""); 1.247 + 1.248 + /* now open the user's defined PKCS #11 modules */ 1.249 + /* skip the local user DB entry */ 1.250 + module_list[next++] = PR_smprintf( 1.251 + "library= " 1.252 + "module=\"NSS User database\" " 1.253 + "parameters=\"configdir='sql:%s' %s\" " 1.254 + "NSS=\"flags=internal,moduleDBOnly,defaultModDB,skipFirst\"", 1.255 + userdb, stripped_parameters); 1.256 + } 1.257 + 1.258 + /* now the system database (always read only unless it's root) */ 1.259 + if (sysdb) { 1.260 + const char *readonly = userCanModifySystemDB() ? "" : "flags=readonly"; 1.261 + module_list[next++] = PR_smprintf( 1.262 + "library= " 1.263 + "module=\"NSS system database\" " 1.264 + "parameters=\"configdir='sql:%s' tokenDescription='NSS system database' %s\" " 1.265 + "NSS=\"trustOrder=80 %sflags=internal,critical\"",sysdb, readonly, nssflags); 1.266 + } 1.267 + 1.268 + /* that was the last module */ 1.269 + module_list[next] = 0; 1.270 + 1.271 + PORT_Free(userdb); 1.272 + PORT_Free(sysdb); 1.273 + 1.274 + return module_list; 1.275 +} 1.276 + 1.277 +static char ** 1.278 +release_list(char **arg) 1.279 +{ 1.280 + static char *success = "Success"; 1.281 + int next; 1.282 + 1.283 + for (next = 0; arg[next]; next++) { 1.284 + free(arg[next]); 1.285 + } 1.286 + PORT_Free(arg); 1.287 + return &success; 1.288 +} 1.289 + 1.290 + 1.291 +#include "utilpars.h" 1.292 + 1.293 +#define TARGET_SPEC_COPY(new, start, end) \ 1.294 + if (end > start) { \ 1.295 + int _cnt = end - start; \ 1.296 + PORT_Memcpy(new, start, _cnt); \ 1.297 + new += _cnt; \ 1.298 + } 1.299 + 1.300 +/* 1.301 + * According the strcpy man page: 1.302 + * 1.303 + * The strings may not overlap, and the destination string dest must be 1.304 + * large enough to receive the copy. 1.305 + * 1.306 + * This implementation allows target to overlap with src. 1.307 + * It does not allow the src to overlap the target. 1.308 + * example: overlapstrcpy(string, string+4) is fine 1.309 + * overlapstrcpy(string+4, string) is not. 1.310 + */ 1.311 +static void 1.312 +overlapstrcpy(char *target, char *src) 1.313 +{ 1.314 + while (*src) { 1.315 + *target++ = *src++; 1.316 + } 1.317 + *target = 0; 1.318 +} 1.319 + 1.320 +/* determine what options the user was trying to open this database with */ 1.321 +/* filename is the directory pointed to by configdir= */ 1.322 +/* stripped is the rest of the parameters with configdir= stripped out */ 1.323 +static SECStatus 1.324 +parse_parameters(char *parameters, char **filename, char **stripped) 1.325 +{ 1.326 + char *sourcePrev; 1.327 + char *sourceCurr; 1.328 + char *targetCurr; 1.329 + char *newStripped; 1.330 + *filename = NULL; 1.331 + *stripped = NULL; 1.332 + 1.333 + newStripped = PORT_Alloc(PORT_Strlen(parameters)+2); 1.334 + targetCurr = newStripped; 1.335 + sourcePrev = parameters; 1.336 + sourceCurr = NSSUTIL_ArgStrip(parameters); 1.337 + TARGET_SPEC_COPY(targetCurr, sourcePrev, sourceCurr); 1.338 + 1.339 + while (*sourceCurr) { 1.340 + int next; 1.341 + sourcePrev = sourceCurr; 1.342 + NSSUTIL_HANDLE_STRING_ARG(sourceCurr, *filename, "configdir=", 1.343 + sourcePrev = sourceCurr; ) 1.344 + NSSUTIL_HANDLE_FINAL_ARG(sourceCurr); 1.345 + TARGET_SPEC_COPY(targetCurr, sourcePrev, sourceCurr); 1.346 + } 1.347 + *targetCurr = 0; 1.348 + if (*filename == NULL) { 1.349 + PORT_Free(newStripped); 1.350 + return SECFailure; 1.351 + } 1.352 + /* strip off any directives from the filename */ 1.353 + if (strncmp("sql:", *filename, 4) == 0) { 1.354 + overlapstrcpy(*filename, (*filename)+4); 1.355 + } else if (strncmp("dbm:", *filename, 4) == 0) { 1.356 + overlapstrcpy(*filename, (*filename)+4); 1.357 + } else if (strncmp("extern:", *filename, 7) == 0) { 1.358 + overlapstrcpy(*filename, (*filename)+7); 1.359 + } 1.360 + *stripped = newStripped; 1.361 + return SECSuccess; 1.362 +} 1.363 + 1.364 +/* entry point */ 1.365 +char ** 1.366 +NSS_ReturnModuleSpecData(unsigned long function, char *parameters, void *args) 1.367 +{ 1.368 + char *filename = NULL; 1.369 + char *stripped = NULL; 1.370 + char **retString = NULL; 1.371 + SECStatus rv; 1.372 + 1.373 + rv = parse_parameters(parameters, &filename, &stripped); 1.374 + if (rv != SECSuccess) { 1.375 + /* use defaults */ 1.376 + filename = getSystemDB(); 1.377 + if (!filename) { 1.378 + return NULL; 1.379 + } 1.380 + stripped = PORT_Strdup(NSS_DEFAULT_FLAGS); 1.381 + if (!stripped) { 1.382 + free(filename); 1.383 + return NULL; 1.384 + } 1.385 + } 1.386 + switch (function) { 1.387 + case SECMOD_MODULE_DB_FUNCTION_FIND: 1.388 + retString = get_list(filename, stripped); 1.389 + break; 1.390 + case SECMOD_MODULE_DB_FUNCTION_RELEASE: 1.391 + retString = release_list((char **)args); 1.392 + break; 1.393 + /* can't add or delete from this module DB */ 1.394 + case SECMOD_MODULE_DB_FUNCTION_ADD: 1.395 + case SECMOD_MODULE_DB_FUNCTION_DEL: 1.396 + retString = NULL; 1.397 + break; 1.398 + default: 1.399 + retString = NULL; 1.400 + break; 1.401 + } 1.402 + 1.403 + PORT_Free(filename); 1.404 + PORT_Free(stripped); 1.405 + return retString; 1.406 +}