diff options
author | Rob Crittenden <rcritten@redhat.com> | 2016-02-29 22:33:23 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2016-03-01 11:42:27 -0500 |
commit | 105d65bfedfa0e381dcebd197ef67aab799fc8b1 (patch) | |
tree | 87bb5d4c0fb34884a7f47efeb8c86192859bb534 | |
parent | 8e8befca612a8f70b9d47de5393c134aecf81494 (diff) | |
download | mod_nss-105d65bfedfa0e381dcebd197ef67aab799fc8b1.tar.gz mod_nss-105d65bfedfa0e381dcebd197ef67aab799fc8b1.tar.xz mod_nss-105d65bfedfa0e381dcebd197ef67aab799fc8b1.zip |
Check filesystem permissions on NSS database at startup
See if the configured user has read access to the NSS database
during initialization so the server can gracefully shutdown
rather than ending up in a forking loop because the database is
owned by root and is therefore unreadable once Apache starts
forking.
Adds a new configuration option, NSSSkipPermissionCheck <on/off>,
to skip this check in case something goes wrong.
https://fedorahosted.org/mod_nss/ticket/3
-rw-r--r-- | docs/mod_nss.html | 12 | ||||
-rw-r--r-- | mod_nss.c | 3 | ||||
-rw-r--r-- | mod_nss.h | 3 | ||||
-rw-r--r-- | nss_engine_config.c | 11 | ||||
-rw-r--r-- | nss_engine_init.c | 122 |
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 @@ -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`") @@ -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(); } |