From 0c32d165baa8ccde5a9c94e8a596f0b7a3435ee4 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 24 Feb 2017 08:14:47 -0500 Subject: [PATCH 1/2] Pass just the pool to mag_error This way this error reporting function can be used also when a request_rec is not available, like i the configuration phase. Signed-off-by: Simo Sorce Reviewed-by: Robbie Harwood Reviewed-by: Isaac Boukris --- src/environ.c | 4 ++-- src/mod_auth_gssapi.c | 20 ++++++++++---------- src/mod_auth_gssapi.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/environ.c b/src/environ.c index 2bbc7df..e81bac0 100644 --- a/src/environ.c +++ b/src/environ.c @@ -28,7 +28,7 @@ static bool mag_get_name_attr(request_rec *req, ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "gss_get_name_attribute() failed on %.*s%s", (int)attr->name.length, (char *)attr->name.value, - mag_error(req, "", maj, min)); + mag_error(req->pool, "", maj, min)); return false; } @@ -209,7 +209,7 @@ void mag_get_name_attributes(request_rec *req, struct mag_config *cfg, maj = gss_inquire_name(&min, name, NULL, NULL, &attrs); if (GSS_ERROR(maj)) { - error = mag_error(req, "gss_inquire_name() failed", maj, min); + error = mag_error(req->pool, "gss_inquire_name() failed", maj, min); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", error); apr_table_set(mc->env, "GSS_NAME_ATTR_ERROR", error); return; diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index 13bec7a..7d493ad 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -28,7 +28,7 @@ module AP_MODULE_DECLARE_DATA auth_gssapi_module; APLOG_USE_MODULE(auth_gssapi); -static char *mag_status(request_rec *req, int type, uint32_t err) +static char *mag_status(apr_pool_t *pool, int type, uint32_t err) { uint32_t maj_ret, min_ret; gss_buffer_desc text; @@ -47,10 +47,10 @@ static char *mag_status(request_rec *req, int type, uint32_t err) len = text.length; if (msg_ret) { - msg_ret = apr_psprintf(req->pool, "%s, %*s", + msg_ret = apr_psprintf(pool, "%s, %*s", msg_ret, len, (char *)text.value); } else { - msg_ret = apr_psprintf(req->pool, "%*s", len, (char *)text.value); + msg_ret = apr_psprintf(pool, "%*s", len, (char *)text.value); } gss_release_buffer(&min_ret, &text); } while (msg_ctx != 0); @@ -58,14 +58,14 @@ static char *mag_status(request_rec *req, int type, uint32_t err) return msg_ret; } -char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min) +char *mag_error(apr_pool_t *pool, const char *msg, uint32_t maj, uint32_t min) { char *msg_maj; char *msg_min; - msg_maj = mag_status(req, GSS_C_GSS_CODE, maj); - msg_min = mag_status(req, GSS_C_MECH_CODE, min); - return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); + msg_maj = mag_status(pool, GSS_C_GSS_CODE, maj); + msg_min = mag_status(pool, GSS_C_MECH_CODE, min); + return apr_psprintf(pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); } enum mag_err_code { @@ -98,7 +98,7 @@ static void mag_post_error(request_rec *req, struct mag_config *cfg, const char *text = NULL; if (maj) - text = mag_error(req, msg, maj, min); + text = mag_error(req->pool, msg, maj, min); if (cfg->enverrs) mag_publish_error(req, maj, min, text ? text : msg, mag_err_text(err)); @@ -288,7 +288,7 @@ static void mag_store_deleg_creds(request_rec *req, const char *ccname, GSS_C_NULL_OID, 1, 1, &store, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", - mag_error(req, "failed to store delegated creds", + mag_error(req->pool, "failed to store delegated creds", maj, min)); } } @@ -598,7 +598,7 @@ static bool mag_auth_basic(request_rec *req, if (maj != GSS_S_COMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Failed to restore per-thread ccache, %s", - mag_error(req, "gss_krb5_ccache_name() " + mag_error(req->pool, "gss_krb5_ccache_name() " "failed", maj, min)); } } diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h index 601a97f..1d97e4e 100644 --- a/src/mod_auth_gssapi.h +++ b/src/mod_auth_gssapi.h @@ -136,4 +136,4 @@ struct mag_conn { struct mag_conn *mag_new_conn_ctx(apr_pool_t *pool); const char *mag_str_auth_type(int auth_type); -char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min); +char *mag_error(apr_pool_t *pool, const char *msg, uint32_t maj, uint32_t min); From 605ed4debe058f5a5b93b6defc3b59d369444387 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 23 Feb 2017 19:22:17 -0500 Subject: [PATCH 2/2] Add option to select acceptor name This option is useful to select and allow only a specific credential when keys for multiple principals are available in a keytab. Signed-off-by: Simo Sorce Reviewed-by: Robbie Harwood Reviewed-by: Isaac Boukris Closes #131 --- README | 20 ++++++++++++++++++++ src/mod_auth_gssapi.c | 24 ++++++++++++++++++++++-- src/mod_auth_gssapi.h | 1 + tests/httpd.conf | 11 +++++++++++ tests/magtests.py | 19 +++++++++++++++++++ 5 files changed, 73 insertions(+), 2 deletions(-) diff --git a/README b/README index f681e49..1fdfe98 100644 --- a/README +++ b/README @@ -398,3 +398,23 @@ an additional message that provides more context. - **Enable with:** GssapiPublishErrors On - **Default:** GssapiPublishErrors Off + + +### GssapiAcceptorName + +This option is used to force the server to accept only for a specific name. + +This allows, for example to select to use a specific credential when multiple +keys are provided in a keytab. + +Note: By default no name is set and any name in a keytab or mechanism specific +acceptor credential will be allowed. + +Note: Global gssapi options set in krb5.conf like 'ignore_acceptor_hostname' +may affect the ability to restrict names. + +Note: The GSS_C_NT_HOSTBASED_SERVICE format is used for names (see example). + +#### Example + GssapiAcceptorName HTTP@www.example.com + diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index 7d493ad..755654d 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -189,11 +189,11 @@ static bool mag_acquire_creds(request_rec *req, #ifdef HAVE_CRED_STORE gss_const_key_value_set_t store = cfg->cred_store; - maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, + maj = gss_acquire_cred_from(&min, cfg->acceptor_name, GSS_C_INDEFINITE, desired_mechs, cred_usage, store, creds, actual_mechs, NULL); #else - maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, + maj = gss_acquire_cred(&min, cfg->acceptor_name, GSS_C_INDEFINITE, desired_mechs, cred_usage, creds, actual_mechs, NULL); #endif @@ -1706,6 +1706,24 @@ static const char *mag_basic_auth_mechs(cmd_parms *parms, void *mconfig, } #endif +static const char *mag_acceptor_name(cmd_parms *parms, void *mconfig, + const char *w) +{ + struct mag_config *cfg = (struct mag_config *)mconfig; + gss_buffer_desc bufnam = { strlen(w), (void *)w }; + uint32_t maj, min; + + maj = gss_import_name(&min, &bufnam, GSS_C_NT_HOSTBASED_SERVICE, + &cfg->acceptor_name); + if (GSS_ERROR(maj)) { + return apr_psprintf(parms->pool, "[%s] Failed to import name '%s' %s", + parms->cmd->name, w, + mag_error(parms->pool, "", maj, min)); + } + + return NULL; +} + static void *mag_create_server_config(apr_pool_t *p, server_rec *s) { struct mag_server_config *scfg; @@ -1780,6 +1798,8 @@ static const command_rec mag_commands[] = { AP_INIT_FLAG("GssapiPublishErrors", ap_set_flag_slot, (void *)APR_OFFSETOF(struct mag_config, enverrs), OR_AUTHCFG, "Publish GSSAPI Errors in Envionment Variables"), + AP_INIT_RAW_ARGS("GssapiAcceptorName", mag_acceptor_name, NULL, OR_AUTHCFG, + "Name of the acceptor credentials."), { NULL } }; diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h index 1d97e4e..159d6b7 100644 --- a/src/mod_auth_gssapi.h +++ b/src/mod_auth_gssapi.h @@ -92,6 +92,7 @@ struct mag_config { bool negotiate_once; struct mag_name_attributes *name_attributes; bool enverrs; + gss_name_t acceptor_name; }; struct mag_server_config { diff --git a/tests/httpd.conf b/tests/httpd.conf index 8b64000..7879727 100644 --- a/tests/httpd.conf +++ b/tests/httpd.conf @@ -200,6 +200,17 @@ CoreDumpDirectory "${HTTPROOT}" Require valid-user + + AuthType GSSAPI + AuthName "Bad Acceptor Name" + GssapiSSLonly Off + GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache + GssapiCredStore client_keytab:${HTTPROOT}/http.keytab + GssapiCredStore keytab:${HTTPROOT}/http.keytab + GssapiAcceptorName BAD@example.com + Require valid-user + + ProxyRequests On ProxyVia On diff --git a/tests/magtests.py b/tests/magtests.py index f0b642a..bc2b8ea 100755 --- a/tests/magtests.py +++ b/tests/magtests.py @@ -391,6 +391,23 @@ def test_basic_auth_krb5(testdir, testenv, testlog): sys.stderr.write('BASIC Proxy Auth: SUCCESS\n') +def test_bad_acceptor_name(testdir, testenv, testlog): + + bandir = os.path.join(testdir, 'httpd', 'html', 'bad_acceptor_name') + os.mkdir(bandir) + shutil.copy('tests/index.html', bandir) + + with (open(testlog, 'a')) as logfile: + ban = subprocess.Popen(["tests/t_bad_acceptor_name.py"], + stdout=logfile, stderr=logfile, + env=testenv, preexec_fn=os.setsid) + ban.wait() + if ban.returncode != 0: + sys.stderr.write('BAD ACCEPTOR: SUCCESS\n') + else: + sys.stderr.write('BAD ACCEPTOR: FAILED\n') + + if __name__ == '__main__': args = parse_args() @@ -425,6 +442,8 @@ def test_basic_auth_krb5(testdir, testenv, testlog): test_spnego_negotiate_once(testdir, testenv, testlog) + test_bad_acceptor_name(testdir, testenv, testlog) + testenv = {'MAG_USER_NAME': USR_NAME, 'MAG_USER_PASSWORD': USR_PWD, 'MAG_USER_NAME_2': USR_NAME_2,