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/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..755654d 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));
@@ -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
@@ -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));
}
}
@@ -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 601a97f..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 {
@@ -136,4 +137,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);
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,