From 9d52c3cedd6a1fd21cb83ffe51d112f027315565 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Jan 19 2018 20:17:51 +0000 Subject: Try to auto-detect the NSS database format if not specified If no database prefix, sql or dbm, is specified then look in the database dir to try to figure out the type based on the files (cert9 vs cert8). Prefer the sql/cert9 format over dbm/cert8. --- diff --git a/mod_nss.h b/mod_nss.h index 8643e88..5fed982 100644 --- a/mod_nss.h +++ b/mod_nss.h @@ -58,6 +58,7 @@ #include #include #include +#include /* Apache ships its autoconf-generated config.h which defines these * as empty. We want the mod_nss version in our own config.h so @@ -161,6 +162,12 @@ ap_set_module_config(c->conn_config, &nss_module, val) #endif /* + * NSS database prefixes + */ +#define SQLDB "sql:" +#define LEGACY "dbm:" + +/* * Define the SSL options */ #define SSL_OPT_NONE (0) @@ -246,6 +253,7 @@ typedef struct { apr_pool_t *ptemp; /* pointer to ptemp passed in during init */ const char *pCertificateDatabase; const char *pDBPrefix; + NSSDBType dbtype; /* config for SSL session cache */ int session_cache_size; @@ -506,6 +514,7 @@ void addHashVhostNick(char *vhost_id, char *nickname); int nss_io_buffer_fill(request_rec *r, apr_size_t maxlen); int nss_rand_seed(server_rec *s, apr_pool_t *p, ssl_rsctx_t nCtx, char *prefix); +NSSDBType detect_dbtype(const char *dbdir, apr_pool_t *p); /* Pass Phrase Handling */ SECStatus nss_Init_Tokens(server_rec *s); diff --git a/nss_engine_config.c b/nss_engine_config.c index dff3ed1..e19e4e8 100644 --- a/nss_engine_config.c +++ b/nss_engine_config.c @@ -46,6 +46,7 @@ SSLModConfigRec *nss_config_global_create(server_rec *s) mc->nInitCount = 0; mc->pCertificateDatabase = NULL; mc->pDBPrefix = NULL; + mc->dbtype = NSS_DB_TYPE_NONE; mc->session_cache_size = UNSET; mc->session_cache_timeout = UNSET; mc->ssl3_session_cache_timeout = UNSET; diff --git a/nss_engine_init.c b/nss_engine_init.c index 7ecfca8..0fd44da 100644 --- a/nss_engine_init.c +++ b/nss_engine_init.c @@ -186,8 +186,15 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) } } + if (mc->nInitCount == 1) { + mc->dbtype = detect_dbtype(mc->pCertificateDatabase, p); + } + + /* Strip the known prefixes */ if (strncasecmp(mc->pCertificateDatabase, "sql:", 4) == 0) dbdir = (char *)mc->pCertificateDatabase + 4; + else if (strncasecmp(mc->pCertificateDatabase, "dbm:", 4) == 0) + dbdir = (char *)mc->pCertificateDatabase + 4; else dbdir = (char *)mc->pCertificateDatabase; @@ -197,7 +204,7 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) */ if (mc->nInitCount == 1) { if (mc->skip_permission_check == PR_FALSE) { - char filepath[1024]; + char filepath[APR_PATH_MAX]; struct passwd *pw = NULL; pw = getpwnam(mc->user); @@ -212,9 +219,8 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) nss_die(); } - if (strncasecmp(mc->pCertificateDatabase, "sql:", 4) == 0) { - apr_snprintf(filepath, 1024, "%s/key4.db", - mc->pCertificateDatabase+4); + if (mc->dbtype == NSS_DB_TYPE_SQL) { + apr_snprintf(filepath, APR_PATH_MAX, "%s/key4.db", dbdir); if (!(check_path(mc->user, pw->pw_uid, pw->pw_gid, filepath, p))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, @@ -222,8 +228,7 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) "database %s.", mc->user, filepath); nss_die(); } - apr_snprintf(filepath, 1024, "%s/cert9.db", - mc->pCertificateDatabase+4); + apr_snprintf(filepath, APR_PATH_MAX, "%s/cert9.db", dbdir); if (!(check_path(mc->user, pw->pw_uid, pw->pw_gid, filepath, p))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, @@ -231,9 +236,8 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) "database %s.", mc->user, filepath); nss_die(); } - } else { - apr_snprintf(filepath, 1024, "%s/key3.db", - mc->pCertificateDatabase); + } else { /* legacy/dbm type */ + apr_snprintf(filepath, APR_PATH_MAX, "%s/key3.db", dbdir); if (!(check_path(mc->user, pw->pw_uid, pw->pw_gid, filepath, p))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, @@ -241,8 +245,7 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) "database %s.", mc->user, filepath); nss_die(); } - apr_snprintf(filepath, 1024, "%s/cert8.db", - mc->pCertificateDatabase); + apr_snprintf(filepath, APR_PATH_MAX, "%s/cert8.db", dbdir); if (!(check_path(mc->user, pw->pw_uid, pw->pw_gid, filepath, p))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, @@ -250,8 +253,7 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p) "database %s.", mc->user, filepath); nss_die(); } - apr_snprintf(filepath, 1024, "%s/secmod.db", - mc->pCertificateDatabase); + apr_snprintf(filepath, APR_PATH_MAX, "%s/secmod.db", dbdir); if (!(check_path(mc->user, pw->pw_uid, pw->pw_gid, filepath, p))) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, "Server user %s lacks read access to NSS secmod " diff --git a/nss_util.c b/nss_util.c index 243e637..cbe65de 100644 --- a/nss_util.c +++ b/nss_util.c @@ -260,3 +260,67 @@ SECItem_to_ipaddr(apr_pool_t *p, SECItem *item) return apr_pstrdup(p, buf); } + +static int +file_exists(char *filepath, apr_pool_t *p) +{ + apr_finfo_t finfo; + + if ((apr_stat(&finfo, filepath, APR_FINFO_PROT | APR_FINFO_OWNER, p)) + == APR_SUCCESS) { + return 1; + } else { + return 0; + } +} + +/* Detect whether a given NSS database directory is a sql or dbm + * type. Return the type found. + * + * sql is given priority + * + * NOTE: This uses some private constants from NSS. + * + * Other types (extern, multiaccess) are not handled. + */ +NSSDBType +detect_dbtype(const char *dbdir, apr_pool_t *p) +{ + NSSDBType dbtype = NSS_DB_TYPE_NONE; + char filepath[APR_PATH_MAX]; + + if (PORT_Strncmp(dbdir, SQLDB, 4) == 0) { + dbtype = NSS_DB_TYPE_SQL; + } else if (PORT_Strncmp(dbdir, LEGACY, 4) == 0) { + dbtype = NSS_DB_TYPE_LEGACY; + } else { + char *envtype; + + envtype = PR_GetEnvSecure("NSS_DEFAULT_DB_TYPE"); + if (NULL != envtype) { + if (!(PORT_Strncmp(envtype, SQLDB, 4))) { + dbtype = NSS_DB_TYPE_SQL; + } else if (!(PORT_Strncmp(envtype, LEGACY, 4))) { + dbtype = NSS_DB_TYPE_LEGACY; + } + } + } + + /* If a prefix was set in path or environment we're done */ + if (dbtype != NSS_DB_TYPE_NONE) { + return dbtype; + } + + /* Look in the directory to see what files are available */ + apr_snprintf(filepath, APR_PATH_MAX, "%s/cert9.db", dbdir); + if (file_exists(filepath, p)) { + dbtype = NSS_DB_TYPE_SQL; + } else { + apr_snprintf(filepath, APR_PATH_MAX, "%s/cert8.db", dbdir); + if (file_exists(filepath, p)) { + dbtype = NSS_DB_TYPE_LEGACY; + } + } + + return dbtype; +}