summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/mod_nss.html12
-rw-r--r--mod_nss.c3
-rw-r--r--mod_nss.h3
-rw-r--r--nss_engine_config.c11
-rw-r--r--nss_engine_init.c122
5 files changed, 124 insertions, 27 deletions
diff --git a/docs/mod_nss.html b/docs/mod_nss.html
index c84f938..ec03a07 100644
--- a/docs/mod_nss.html
+++ b/docs/mod_nss.html
@@ -440,6 +440,18 @@ reads that many bytes, otherwise it reads until the program exits.<br>
NSSRandomSeed startup /dev/urandom 512<br>
NSSRandomSeed startup /usr/bin/makerandom</code><br>
<br>
+<big><big>NSSSkipPermissionCheck</big></big><br>
+<br>
+The NSS database will be checked to ensure that the user configured
+to run Apache as has owner or group read access to the database
+configured in <code>NSSCertificateDatabase</code>. This check
+can be disabled by setting <code>NSSSkipPermissionCheck</code>
+to <code>on</code>. The default is <code>off</code><br>
+<br>
+<span style="font-weight: bold;">Example</span><br>
+<br>
+<code>NSSSkipPermissionCheck on</code><br>
+<br>
<big><big>NSSEngine</big></big><br>
<br>
Enables or disables the SSL protocol. This is usually used within a
diff --git a/mod_nss.c b/mod_nss.c
index b3ea6f0..38098c8 100644
--- a/mod_nss.c
+++ b/mod_nss.c
@@ -54,6 +54,9 @@ static const command_rec nss_config_cmds[] = {
SSL_CMD_SRV(SessionCacheSize, TAKE1,
"SSL Session Cache size "
"(`N' - number of entries)")
+ SSL_CMD_SRV(SkipPermissionCheck, FLAG,
+ "Skip checking the NSS database read permissions"
+ "(`on', `off')")
SSL_CMD_SRV(PassPhraseDialog, TAKE1,
"SSL dialog mechanism for the pass phrase query "
"(`builtin', `file:/path/to/file`")
diff --git a/mod_nss.h b/mod_nss.h
index ac56ddb..4604ff9 100644
--- a/mod_nss.h
+++ b/mod_nss.h
@@ -256,6 +256,8 @@ typedef struct {
const char *pphrase_dialog_path;
const char *pphrase_dialog_helper;
+ BOOL skip_permission_check;
+
apr_proc_t proc;
apr_procattr_t *procattr;
@@ -418,6 +420,7 @@ const char *nss_cmd_NSSSessionCacheSize(cmd_parms *cmd, void *dcfg, const char *
const char *nss_cmd_NSSPassPhraseDialog(cmd_parms *cmd, void *dcfg, const char *arg);
const char *nss_cmd_NSSPassPhraseHelper(cmd_parms *cmd, void *dcfg, const char *arg);
const char *nss_cmd_NSSRandomSeed(cmd_parms *, void *, const char *, const char *, const char *);
+const char *nss_cmd_NSSSkipPermissionCheck(cmd_parms *cmd, void *dcfg, int flag);
const char *nss_cmd_NSSSessionTickets(cmd_parms *cmd, void *dcfg, int flag);
#ifdef ENABLE_SERVER_DHE
const char *nss_cmd_NSSServerDHE(cmd_parms *cmd, void *dcfg, int flag);
diff --git a/nss_engine_config.c b/nss_engine_config.c
index c0c7155..4adff52 100644
--- a/nss_engine_config.c
+++ b/nss_engine_config.c
@@ -54,6 +54,7 @@ SSLModConfigRec *nss_config_global_create(server_rec *s)
mc->aRandSeed = apr_array_make(pool, 4,
sizeof(ssl_randseed_t));
mc->semid = 0;
+ mc->skip_permission_check = PR_FALSE;
apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY,
apr_pool_cleanup_null,
@@ -803,6 +804,16 @@ const char *nss_cmd_NSSRandomSeed(cmd_parms *cmd,
return NULL;
}
+const char *nss_cmd_NSSSkipPermissionCheck(cmd_parms *cmd,
+ void *dcfg, int flag)
+{
+ SSLModConfigRec *mc = myModConfig(cmd->server);
+
+ mc->skip_permission_check = flag ? PR_TRUE: PR_FALSE;
+
+ return NULL;
+}
+
const char *nss_cmd_NSSSessionTickets(cmd_parms *cmd,
void *dcfg, int flag)
{
diff --git a/nss_engine_init.c b/nss_engine_init.c
index 81b2434..2a6ce58 100644
--- a/nss_engine_init.c
+++ b/nss_engine_init.c
@@ -27,6 +27,8 @@
#include "ocsp.h"
#include "keyhi.h"
#include "cert.h"
+#include <sys/types.h>
+#include <pwd.h>
static SECStatus ownBadCertHandler(void *arg, PRFileDesc * socket);
static SECStatus ownHandshakeCallback(PRFileDesc * socket, void *arg);
@@ -49,6 +51,32 @@ static char *version_components[] = {
NULL
};
+/* See if a uid or gid can read a file at a given path. Ignore world
+ * read permissions.
+ *
+ * Return 0 on failure or file doesn't exist
+ * Return 1 on success
+ */
+static int check_path(uid_t uid, gid_t gid, char *filepath, apr_pool_t *p)
+{
+ apr_finfo_t finfo;
+ int rv;
+
+ if ((rv = apr_stat(&finfo, filepath, APR_FINFO_PROT | APR_FINFO_OWNER,
+ p)) == APR_SUCCESS) {
+ if (((uid == finfo.user) &&
+ ((finfo.protection & APR_FPROT_UREAD))) ||
+ ((gid == finfo.group) &&
+ ((finfo.protection & APR_FPROT_GREAD)))
+ )
+ {
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
static char *nss_add_version_component(apr_pool_t *p,
server_rec *s,
char *name)
@@ -130,6 +158,68 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p)
}
}
+ /* Assuming everything is ok so far, check the cert database permissions
+ * for the server user before Apache starts forking. We die now or
+ * get stuck in an endless loop not able to read the NSS database.
+ */
+ if (mc->nInitCount == 1) {
+ if (mc->skip_permission_check == PR_FALSE) {
+ char filepath[1024];
+ struct passwd *pw = NULL;
+
+ pw = getpwnam(mc->user);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server,
+ "Checking permissions for user %s: uid %d gid %d",
+ mc->user, pw->pw_uid, pw->pw_gid);
+
+ if (strncasecmp(mc->pCertificateDatabase, "sql:", 4) == 0) {
+ apr_snprintf(filepath, 1024, "%s/key4.db",
+ mc->pCertificateDatabase+4);
+ if (!(check_path(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 key "
+ "database %s.", mc->user, filepath);
+ nss_die();
+ }
+ apr_snprintf(filepath, 1024, "%s/cert9.db",
+ mc->pCertificateDatabase+4);
+ if (!(check_path(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 cert "
+ "database %s.", mc->user, filepath);
+ nss_die();
+ }
+ } else {
+ apr_snprintf(filepath, 1024, "%s/key3.db",
+ mc->pCertificateDatabase);
+ if (!(check_path(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 key "
+ "database %s.", mc->user, filepath);
+ nss_die();
+ }
+ apr_snprintf(filepath, 1024, "%s/cert8.db",
+ mc->pCertificateDatabase);
+ if (!(check_path(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 cert "
+ "database %s.", mc->user, filepath);
+ nss_die();
+ }
+ apr_snprintf(filepath, 1024, "%s/secmod.db",
+ mc->pCertificateDatabase);
+ if (!(check_path(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 "
+ "database %s.", mc->user, filepath);
+ nss_die();
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server,
+ "Permissions check out ok");
+ }
+ }
+
/* We need to be in the same directory as libnssckbi.so to load the
* root certificates properly.
*/
@@ -155,6 +245,7 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p)
else
return;
}
+
/* Initialize NSS and open the certificate database read-only. */
rv = NSS_Initialize(mc->pCertificateDatabase, mc->pDBPrefix, mc->pDBPrefix, "secmod.db", NSS_INIT_READONLY);
if (chdir(cwd) != 0) {
@@ -168,39 +259,16 @@ static void nss_init_SSLLibrary(server_rec *base_server, apr_pool_t *p)
return;
}
- /* Assuming everything is ok so far, check the cert database password(s). */
if (rv != SECSuccess) {
- apr_finfo_t finfo;
- char keypath[1024];
- int rv;
- uid_t user_id;
- gid_t gid;
-
- user_id = ap_uname2id(mc->user);
- gid = getegid();
-
NSS_Shutdown();
+
ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server,
"NSS_Initialize failed. Certificate database: %s.", mc->pCertificateDatabase != NULL ? mc->pCertificateDatabase : "not set in configuration");
nss_log_nss_error(APLOG_MARK, APLOG_ERR, base_server);
- apr_snprintf(keypath, 1024, "%s/key3.db", mc->pCertificateDatabase);
- if ((rv = apr_stat(&finfo, keypath, APR_FINFO_PROT | APR_FINFO_OWNER,
- p)) == APR_SUCCESS) {
- if (((user_id == finfo.user) &&
- (!(finfo.protection & APR_FPROT_UREAD))) ||
- ((gid == finfo.group) &&
- (!(finfo.protection & APR_FPROT_GREAD))) ||
- (!(finfo.protection & APR_FPROT_WREAD))
- )
- {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server,
- "Server user lacks read access to NSS database.");
- }
- } else {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server,
- "Does the NSS database exist?");
- }
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server,
+ "Does the NSS database exist?");
+
nss_die();
}