4 Copyright (C) 2014 Simo Sorce <simo@redhat.com>
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
25 #include "mod_auth_gssapi.h"
27 #define MOD_AUTH_GSSAPI_VERSION PACKAGE_NAME "/" PACKAGE_VERSION
29 module AP_MODULE_DECLARE_DATA auth_gssapi_module;
31 APLOG_USE_MODULE(auth_gssapi);
33 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
35 static char *mag_status(request_rec *req, int type, uint32_t err)
37 uint32_t maj_ret, min_ret;
46 maj_ret = gss_display_status(&min_ret, err, type,
47 GSS_C_NO_OID, &msg_ctx, &text);
48 if (maj_ret != GSS_S_COMPLETE) {
54 msg_ret = apr_psprintf(req->pool, "%s, %*s",
55 msg_ret, len, (char *)text.value);
57 msg_ret = apr_psprintf(req->pool, "%*s", len, (char *)text.value);
59 gss_release_buffer(&min_ret, &text);
60 } while (msg_ctx != 0);
65 static char *mag_error(request_rec *req, const char *msg,
66 uint32_t maj, uint32_t min)
71 msg_maj = mag_status(req, GSS_C_GSS_CODE, maj);
72 msg_min = mag_status(req, GSS_C_MECH_CODE, min);
73 return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min);
76 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *mag_is_https = NULL;
78 static int mag_post_config(apr_pool_t *cfgpool, apr_pool_t *log,
79 apr_pool_t *temp, server_rec *s)
81 /* FIXME: create mutex to deal with connections and contexts ? */
82 mag_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
83 mag_post_config_session();
84 ap_add_version_component(cfgpool, MOD_AUTH_GSSAPI_VERSION);
89 static int mag_pre_connection(conn_rec *c, void *csd)
93 mc = apr_pcalloc(c->pool, sizeof(struct mag_conn));
94 if (!mc) return DECLINED;
97 ap_set_module_config(c->conn_config, &auth_gssapi_module, (void*)mc);
101 static apr_status_t mag_conn_destroy(void *ptr)
103 struct mag_conn *mc = (struct mag_conn *)ptr;
107 (void)gss_delete_sec_context(&min, &mc->ctx, GSS_C_NO_BUFFER);
108 mc->established = false;
113 static bool mag_conn_is_https(conn_rec *c)
116 if (mag_is_https(c)) return true;
122 static void mag_store_deleg_creds(request_rec *req,
123 char *dir, char *clientname,
124 gss_cred_id_t delegated_cred,
127 gss_key_value_element_desc element;
128 gss_key_value_set_desc store;
132 value = apr_psprintf(req->pool, "FILE:%s/%s", dir, clientname);
134 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
135 "OOM storing delegated credentials");
139 element.key = "ccache";
140 element.value = value;
141 store.elements = &element;
144 maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE,
145 GSS_C_NULL_OID, 1, 1, &store, NULL, NULL);
146 if (GSS_ERROR(maj)) {
147 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
148 mag_error(req, "failed to store delegated creds",
155 static int mag_auth(request_rec *req)
158 const char *auth_type;
159 struct mag_config *cfg;
160 const char *auth_header;
161 char *auth_header_type;
162 char *auth_header_value;
163 int ret = HTTP_UNAUTHORIZED;
164 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
166 gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
167 gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
168 gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
169 gss_name_t client = GSS_C_NO_NAME;
170 gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
171 gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL;
172 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
173 gss_cred_usage_t cred_usage = GSS_C_ACCEPT;
180 gss_OID mech_type = GSS_C_NO_OID;
181 gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
182 struct mag_conn *mc = NULL;
183 bool is_basic = false;
184 gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT;
185 gss_name_t server = GSS_C_NO_NAME;
186 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
187 const char *user_ccache = NULL;
188 const char *orig_ccache = NULL;
191 type = ap_auth_type(req);
192 if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
196 /* ignore auth for subrequests */
197 if (!ap_is_initial_req(req)) {
201 cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);
204 if (!mag_conn_is_https(req->connection)) {
205 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
206 "Not a TLS connection, refusing to authenticate!");
211 if (cfg->gss_conn_ctx) {
212 mc = (struct mag_conn *)ap_get_module_config(
213 req->connection->conn_config,
214 &auth_gssapi_module);
216 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
217 "Failed to retrieve connection context!");
222 /* if available, session always supersedes connection bound data */
223 if (cfg->use_sessions) {
224 mag_check_session(req, cfg, &mc);
228 /* register the context in the memory pool, so it can be freed
229 * when the connection/request is terminated */
230 apr_pool_userdata_set(mc, "mag_conn_ptr",
231 mag_conn_destroy, mc->parent);
233 if (mc->established) {
234 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
235 "Already established context found!");
236 apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name);
237 req->ap_auth_type = apr_pstrdup(req->pool, mc->auth_type);
238 req->user = apr_pstrdup(req->pool, mc->user_name);
247 auth_header = apr_table_get(req->headers_in, "Authorization");
248 if (!auth_header) goto done;
250 auth_header_type = ap_getword_white(req->pool, &auth_header);
251 if (!auth_header_type) goto done;
253 if (strcasecmp(auth_header_type, "Negotiate") == 0) {
254 auth_type = "Negotiate";
256 auth_header_value = ap_getword_white(req->pool, &auth_header);
257 if (!auth_header_value) goto done;
258 input.length = apr_base64_decode_len(auth_header_value) + 1;
259 input.value = apr_pcalloc(req->pool, input.length);
260 if (!input.value) goto done;
261 input.length = apr_base64_decode(input.value, auth_header_value);
262 } else if ((strcasecmp(auth_header_type, "Basic") == 0) &&
263 (cfg->use_basic_auth == true)) {
267 gss_buffer_desc ba_user;
268 gss_buffer_desc ba_pwd;
270 ba_pwd.value = ap_pbase64decode(req->pool, auth_header);
271 if (!ba_pwd.value) goto done;
272 ba_user.value = ap_getword_nulls_nc(req->pool,
273 (char **)&ba_pwd.value, ':');
274 if (!ba_user.value) goto done;
275 if (((char *)ba_user.value)[0] == '\0' ||
276 ((char *)ba_pwd.value)[0] == '\0') {
277 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
278 "Invalid empty user or password for Basic Auth");
281 ba_user.length = strlen(ba_user.value);
282 ba_pwd.length = strlen(ba_pwd.value);
283 maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &client);
284 if (GSS_ERROR(maj)) {
285 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
287 mag_error(req, "gss_import_name() failed",
291 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
292 /* Set a per-thread ccache in case we are using kerberos,
293 * it is not elegant but avoids interference between threads */
294 long long unsigned int rndname;
296 rs = apr_generate_random_bytes((unsigned char *)(&rndname),
297 sizeof(long long unsigned int));
298 if (rs != APR_SUCCESS) {
299 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
300 "Failed to generate random ccache name");
303 user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname);
304 maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache);
305 if (GSS_ERROR(maj)) {
306 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
308 mag_error(req, "gss_krb5_ccache_name() "
309 "failed", maj, min));
313 maj = gss_acquire_cred_with_password(&min, client, &ba_pwd,
317 &user_cred, NULL, NULL);
318 if (GSS_ERROR(maj)) {
319 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
321 mag_error(req, "gss_acquire_cred_with_password() "
322 "failed", maj, min));
325 gss_release_name(&min, &client);
330 req->ap_auth_type = apr_pstrdup(req->pool, auth_type);
332 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
333 if (cfg->use_s4u2proxy) {
334 cred_usage = GSS_C_BOTH;
336 if (cfg->cred_store) {
337 maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
338 GSS_C_NO_OID_SET, cred_usage,
339 cfg->cred_store, &acquired_cred,
341 if (GSS_ERROR(maj)) {
342 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
343 mag_error(req, "gss_acquire_cred_from() failed",
351 if (!acquired_cred) {
352 /* Try to acquire default creds */
353 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
354 GSS_C_NO_OID_SET, cred_usage,
355 &acquired_cred, NULL, NULL);
356 if (GSS_ERROR(maj)) {
357 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
358 "%s", mag_error(req, "gss_acquire_cred_from()"
359 " failed", maj, min));
363 maj = gss_inquire_cred(&min, acquired_cred, &server,
365 if (GSS_ERROR(maj)) {
366 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
367 "%s", mag_error(req, "gss_inquired_cred_() "
368 "failed", maj, min));
371 /* output and input are inverted here, this is intentional */
372 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
373 GSS_C_NO_OID, 0, 300,
374 GSS_C_NO_CHANNEL_BINDINGS, &output,
375 NULL, &input, NULL, NULL);
376 if (GSS_ERROR(maj)) {
377 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
378 "%s", mag_error(req, "gss_init_sec_context() "
379 "failed", maj, min));
384 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
385 &input, GSS_C_NO_CHANNEL_BINDINGS,
386 &client, &mech_type, &output, &flags, &vtime,
388 if (GSS_ERROR(maj)) {
389 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
390 mag_error(req, "gss_accept_sec_context() failed",
395 while (maj == GSS_S_CONTINUE_NEEDED) {
396 gss_release_buffer(&min, &input);
397 /* output and input are inverted here, this is intentional */
398 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
399 GSS_C_NO_OID, 0, 300,
400 GSS_C_NO_CHANNEL_BINDINGS, &output,
401 NULL, &input, NULL, NULL);
402 if (GSS_ERROR(maj)) {
403 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
404 "%s", mag_error(req, "gss_init_sec_context() "
405 "failed", maj, min));
408 gss_release_buffer(&min, &output);
409 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
410 &input, GSS_C_NO_CHANNEL_BINDINGS,
411 &client, &mech_type, &output, &flags,
412 &vtime, &delegated_cred);
413 if (GSS_ERROR(maj)) {
414 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
415 "%s", mag_error(req, "gss_accept_sec_context()"
416 " failed", maj, min));
420 } else if (maj == GSS_S_CONTINUE_NEEDED) {
422 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
423 "Mechanism needs continuation but neither "
424 "GssapiConnectionBound nor "
425 "GssapiUseSessions are available");
426 gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
427 gss_release_buffer(&min, &output);
430 /* auth not complete send token and wait next packet */
434 /* Always set the GSS name in an env var */
435 maj = gss_display_name(&min, client, &name, NULL);
436 if (GSS_ERROR(maj)) {
437 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
438 mag_error(req, "gss_display_name() failed",
442 clientname = apr_pstrndup(req->pool, name.value, name.length);
443 apr_table_set(req->subprocess_env, "GSS_NAME", clientname);
445 #ifdef HAVE_GSS_STORE_CRED_INTO
446 if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
447 char *ccachefile = NULL;
449 mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
450 delegated_cred, &ccachefile);
453 apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
458 if (cfg->map_to_local) {
459 maj = gss_localname(&min, client, mech_type, &lname);
460 if (maj != GSS_S_COMPLETE) {
461 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
462 mag_error(req, "gss_localname() failed", maj, min));
465 req->user = apr_pstrndup(req->pool, lname.value, lname.length);
467 req->user = clientname;
471 mc->user_name = apr_pstrdup(mc->parent, req->user);
472 mc->gss_name = apr_pstrdup(mc->parent, clientname);
473 mc->established = true;
474 if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
475 vtime = MIN_SESS_EXP_TIME;
477 mc->expiration = time(NULL) + vtime;
478 if (cfg->use_sessions) {
479 mag_attempt_session(req, cfg, mc);
481 mc->auth_type = auth_type;
487 if (ret == HTTP_UNAUTHORIZED) {
488 if (output.length != 0) {
489 replen = apr_base64_encode_len(output.length) + 1;
490 reply = apr_pcalloc(req->pool, 10 + replen);
492 memcpy(reply, "Negotiate ", 10);
493 apr_base64_encode(&reply[10], output.value, output.length);
494 apr_table_add(req->err_headers_out,
495 "WWW-Authenticate", reply);
498 apr_table_add(req->err_headers_out,
499 "WWW-Authenticate", "Negotiate");
500 if (cfg->use_basic_auth) {
501 apr_table_add(req->err_headers_out,
503 apr_psprintf(req->pool, "Basic realm=\"%s\"",
508 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
509 if (user_ccache != NULL) {
510 maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
511 if (maj != GSS_S_COMPLETE) {
512 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
513 "Failed to restore per-thread ccache, %s",
514 mag_error(req, "gss_krb5_ccache_name() "
515 "failed", maj, min));
519 gss_delete_sec_context(&min, &user_ctx, &output);
520 gss_release_cred(&min, &user_cred);
521 gss_release_cred(&min, &acquired_cred);
522 gss_release_cred(&min, &delegated_cred);
523 gss_release_buffer(&min, &output);
524 gss_release_name(&min, &client);
525 gss_release_name(&min, &server);
526 gss_release_buffer(&min, &name);
527 gss_release_buffer(&min, &lname);
532 static void *mag_create_dir_config(apr_pool_t *p, char *dir)
534 struct mag_config *cfg;
536 cfg = (struct mag_config *)apr_pcalloc(p, sizeof(struct mag_config));
537 if (!cfg) return NULL;
543 static const char *mag_ssl_only(cmd_parms *parms, void *mconfig, int on)
545 struct mag_config *cfg = (struct mag_config *)mconfig;
546 cfg->ssl_only = on ? true : false;
550 static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on)
552 struct mag_config *cfg = (struct mag_config *)mconfig;
553 cfg->map_to_local = on ? true : false;
557 static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on)
559 struct mag_config *cfg = (struct mag_config *)mconfig;
560 cfg->gss_conn_ctx = on ? true : false;
564 static const char *mag_use_sess(cmd_parms *parms, void *mconfig, int on)
566 struct mag_config *cfg = (struct mag_config *)mconfig;
567 cfg->use_sessions = on ? true : false;
571 static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
573 struct mag_config *cfg = (struct mag_config *)mconfig;
574 cfg->use_s4u2proxy = on ? true : false;
576 if (cfg->deleg_ccache_dir == NULL) {
577 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, "/tmp");
578 if (!cfg->deleg_ccache_dir) {
579 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0,
580 parms->server, "%s", "OOM setting deleg_ccache_dir.");
586 static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
588 struct mag_config *cfg = (struct mag_config *)mconfig;
595 if (strncmp(w, "key:", 4) != 0) {
596 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
597 "Invalid key format, expected prefix 'key:'");
602 l = apr_base64_decode_len(k);
603 val = apr_palloc(parms->temp_pool, l);
605 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
606 "Failed to get memory to decode key");
610 key.length = (int)apr_base64_decode_binary(val, k);
611 key.value = (unsigned char *)val;
613 if (key.length < 32) {
614 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
615 "Invalid key length, expected >=32 got %d", key.length);
619 rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &key);
621 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
622 "Failed to import sealing key!");
627 #define MAX_CRED_OPTIONS 10
629 static const char *mag_cred_store(cmd_parms *parms, void *mconfig,
632 struct mag_config *cfg = (struct mag_config *)mconfig;
633 gss_key_value_element_desc *elements;
642 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
643 "%s [%s]", "Invalid syntax for GssapiCredStore option", w);
647 key = apr_pstrndup(parms->pool, w, (p-w));
648 value = apr_pstrdup(parms->pool, p + 1);
649 if (!key || !value) {
650 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
651 "%s", "OOM handling GssapiCredStore option");
655 if (!cfg->cred_store) {
656 cfg->cred_store = apr_pcalloc(parms->pool,
657 sizeof(gss_key_value_set_desc));
658 if (!cfg->cred_store) {
659 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
660 "%s", "OOM handling GssapiCredStore option");
663 size = sizeof(gss_key_value_element_desc) * MAX_CRED_OPTIONS;
664 cfg->cred_store->elements = apr_palloc(parms->pool, size);
665 if (!cfg->cred_store->elements) {
666 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
667 "%s", "OOM handling GssapiCredStore option");
671 elements = cfg->cred_store->elements;
672 count = cfg->cred_store->count;
674 if (count >= MAX_CRED_OPTIONS) {
675 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
676 "Too many GssapiCredStore options (MAX: %d)",
680 cfg->cred_store->count++;
682 elements[count].key = key;
683 elements[count].value = value;
688 static const char *mag_deleg_ccache_dir(cmd_parms *parms, void *mconfig,
691 struct mag_config *cfg = (struct mag_config *)mconfig;
693 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, value);
694 if (!cfg->deleg_ccache_dir) {
695 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
696 "%s", "OOM handling GssapiDelegCcacheDir option");
702 static const char *mag_use_basic_auth(cmd_parms *parms, void *mconfig, int on)
704 struct mag_config *cfg = (struct mag_config *)mconfig;
706 cfg->use_basic_auth = on ? true : false;
710 static const command_rec mag_commands[] = {
711 AP_INIT_FLAG("GssapiSSLonly", mag_ssl_only, NULL, OR_AUTHCFG,
712 "Work only if connection is SSL Secured"),
713 AP_INIT_FLAG("GssapiLocalName", mag_map_to_local, NULL, OR_AUTHCFG,
714 "Translate principals to local names"),
715 AP_INIT_FLAG("GssapiConnectionBound", mag_conn_ctx, NULL, OR_AUTHCFG,
716 "Authentication is bound to the TCP connection"),
717 AP_INIT_FLAG("GssapiUseSessions", mag_use_sess, NULL, OR_AUTHCFG,
718 "Authentication uses mod_sessions to hold status"),
719 AP_INIT_RAW_ARGS("GssapiSessionKey", mag_sess_key, NULL, OR_AUTHCFG,
720 "Key Used to seal session data."),
721 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
722 AP_INIT_FLAG("GssapiUseS4U2Proxy", mag_use_s4u2p, NULL, OR_AUTHCFG,
723 "Initializes credentials for s4u2proxy usage"),
725 #ifdef HAVE_GSS_STORE_CRED_INTO
726 AP_INIT_ITERATE("GssapiCredStore", mag_cred_store, NULL, OR_AUTHCFG,
728 AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL,
729 OR_AUTHCFG, "Directory to store delegated credentials"),
731 #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
732 AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
733 "Allows use of Basic Auth for authentication"),
739 mag_register_hooks(apr_pool_t *p)
741 ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE);
742 ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE);
743 ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
746 module AP_MODULE_DECLARE_DATA auth_gssapi_module =
748 STANDARD20_MODULE_STUFF,
749 mag_create_dir_config,