diff options
-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(); } |