security/nss/lib/sysinit/nsssysinit.c

changeset 0
6474c204b198
     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 +}

mercurial