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 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,
305 (const char **)&orig_ccache);
306 if (GSS_ERROR(maj)) {
307 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
309 mag_error(req, "gss_krb5_ccache_name() "
310 "failed", maj, min));
314 maj = gss_acquire_cred_with_password(&min, client, &ba_pwd,
318 &user_cred, NULL, NULL);
319 if (GSS_ERROR(maj)) {
320 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
322 mag_error(req, "gss_acquire_cred_with_password() "
323 "failed", maj, min));
326 gss_release_name(&min, &client);
331 req->ap_auth_type = apr_pstrdup(req->pool, auth_type);
333 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
334 if (cfg->use_s4u2proxy) {
335 cred_usage = GSS_C_BOTH;
337 if (cfg->cred_store) {
338 maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
339 GSS_C_NO_OID_SET, cred_usage,
340 cfg->cred_store, &acquired_cred,
342 if (GSS_ERROR(maj)) {
343 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
344 mag_error(req, "gss_acquire_cred_from() failed",
352 if (!acquired_cred) {
353 /* Try to acquire default creds */
354 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
355 GSS_C_NO_OID_SET, cred_usage,
356 &acquired_cred, NULL, NULL);
357 if (GSS_ERROR(maj)) {
358 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
359 "%s", mag_error(req, "gss_acquire_cred_from()"
360 " failed", maj, min));
364 maj = gss_inquire_cred(&min, acquired_cred, &server,
366 if (GSS_ERROR(maj)) {
367 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
368 "%s", mag_error(req, "gss_inquired_cred_() "
369 "failed", maj, min));
372 /* output and input are inverted here, this is intentional */
373 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
374 GSS_C_NO_OID, 0, 300,
375 GSS_C_NO_CHANNEL_BINDINGS, &output,
376 NULL, &input, NULL, NULL);
377 if (GSS_ERROR(maj)) {
378 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
379 "%s", mag_error(req, "gss_init_sec_context() "
380 "failed", maj, min));
385 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
386 &input, GSS_C_NO_CHANNEL_BINDINGS,
387 &client, &mech_type, &output, &flags, &vtime,
389 if (GSS_ERROR(maj)) {
390 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
391 mag_error(req, "gss_accept_sec_context() failed",
396 while (maj == GSS_S_CONTINUE_NEEDED) {
397 gss_release_buffer(&min, &input);
398 /* output and input are inverted here, this is intentional */
399 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
400 GSS_C_NO_OID, 0, 300,
401 GSS_C_NO_CHANNEL_BINDINGS, &output,
402 NULL, &input, NULL, NULL);
403 if (GSS_ERROR(maj)) {
404 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
405 "%s", mag_error(req, "gss_init_sec_context() "
406 "failed", maj, min));
409 gss_release_buffer(&min, &output);
410 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
411 &input, GSS_C_NO_CHANNEL_BINDINGS,
412 &client, &mech_type, &output, &flags,
413 &vtime, &delegated_cred);
414 if (GSS_ERROR(maj)) {
415 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
416 "%s", mag_error(req, "gss_accept_sec_context()"
417 " failed", maj, min));
421 } else if (maj == GSS_S_CONTINUE_NEEDED) {
423 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
424 "Mechanism needs continuation but neither "
425 "GssapiConnectionBound nor "
426 "GssapiUseSessions are available");
427 gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
428 gss_release_buffer(&min, &output);
431 /* auth not complete send token and wait next packet */
435 /* Always set the GSS name in an env var */
436 maj = gss_display_name(&min, client, &name, NULL);
437 if (GSS_ERROR(maj)) {
438 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
439 mag_error(req, "gss_display_name() failed",
443 clientname = apr_pstrndup(req->pool, name.value, name.length);
444 apr_table_set(req->subprocess_env, "GSS_NAME", clientname);
446 #ifdef HAVE_GSS_STORE_CRED_INTO
447 if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
448 char *ccachefile = NULL;
450 mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
451 delegated_cred, &ccachefile);
454 apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
459 if (cfg->map_to_local) {
460 maj = gss_localname(&min, client, mech_type, &lname);
461 if (maj != GSS_S_COMPLETE) {
462 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
463 mag_error(req, "gss_localname() failed", maj, min));
466 req->user = apr_pstrndup(req->pool, lname.value, lname.length);
468 req->user = clientname;
472 mc->user_name = apr_pstrdup(mc->parent, req->user);
473 mc->gss_name = apr_pstrdup(mc->parent, clientname);
474 mc->established = true;
475 if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
476 vtime = MIN_SESS_EXP_TIME;
478 mc->expiration = time(NULL) + vtime;
479 if (cfg->use_sessions) {
480 mag_attempt_session(req, cfg, mc);
482 mc->auth_type = auth_type;
488 if (ret == HTTP_UNAUTHORIZED) {
489 if (output.length != 0) {
490 replen = apr_base64_encode_len(output.length) + 1;
491 reply = apr_pcalloc(req->pool, 10 + replen);
493 memcpy(reply, "Negotiate ", 10);
494 apr_base64_encode(&reply[10], output.value, output.length);
495 apr_table_add(req->err_headers_out,
496 "WWW-Authenticate", reply);
499 apr_table_add(req->err_headers_out,
500 "WWW-Authenticate", "Negotiate");
501 if (cfg->use_basic_auth) {
502 apr_table_add(req->err_headers_out,
504 apr_psprintf(req->pool, "Basic realm=\"%s\"",
509 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
510 if (user_ccache != NULL) {
511 maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
512 if (maj != GSS_S_COMPLETE) {
513 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
514 "Failed to restore per-thread ccache, %s",
515 mag_error(req, "gss_krb5_ccache_name() "
516 "failed", maj, min));
522 gss_delete_sec_context(&min, &user_ctx, &output);
523 gss_release_cred(&min, &user_cred);
524 gss_release_cred(&min, &acquired_cred);
525 gss_release_cred(&min, &delegated_cred);
526 gss_release_buffer(&min, &output);
527 gss_release_name(&min, &client);
528 gss_release_name(&min, &server);
529 gss_release_buffer(&min, &name);
530 gss_release_buffer(&min, &lname);
535 static void *mag_create_dir_config(apr_pool_t *p, char *dir)
537 struct mag_config *cfg;
539 cfg = (struct mag_config *)apr_pcalloc(p, sizeof(struct mag_config));
540 if (!cfg) return NULL;
546 static const char *mag_ssl_only(cmd_parms *parms, void *mconfig, int on)
548 struct mag_config *cfg = (struct mag_config *)mconfig;
549 cfg->ssl_only = on ? true : false;
553 static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on)
555 struct mag_config *cfg = (struct mag_config *)mconfig;
556 cfg->map_to_local = on ? true : false;
560 static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on)
562 struct mag_config *cfg = (struct mag_config *)mconfig;
563 cfg->gss_conn_ctx = on ? true : false;
567 static const char *mag_use_sess(cmd_parms *parms, void *mconfig, int on)
569 struct mag_config *cfg = (struct mag_config *)mconfig;
570 cfg->use_sessions = on ? true : false;
574 static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
576 struct mag_config *cfg = (struct mag_config *)mconfig;
577 cfg->use_s4u2proxy = on ? true : false;
579 if (cfg->deleg_ccache_dir == NULL) {
580 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, "/tmp");
581 if (!cfg->deleg_ccache_dir) {
582 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0,
583 parms->server, "%s", "OOM setting deleg_ccache_dir.");
589 static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
591 struct mag_config *cfg = (struct mag_config *)mconfig;
598 if (strncmp(w, "key:", 4) != 0) {
599 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
600 "Invalid key format, expected prefix 'key:'");
605 l = apr_base64_decode_len(k);
606 val = apr_palloc(parms->temp_pool, l);
608 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
609 "Failed to get memory to decode key");
613 keys.length = (int)apr_base64_decode_binary(val, k);
614 keys.value = (unsigned char *)val;
616 if (keys.length != 32) {
617 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
618 "Invalid key lenght, expected 32 got %d", keys.length);
622 rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &keys);
624 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
625 "Failed to import sealing key!");
630 #define MAX_CRED_OPTIONS 10
632 static const char *mag_cred_store(cmd_parms *parms, void *mconfig,
635 struct mag_config *cfg = (struct mag_config *)mconfig;
636 gss_key_value_element_desc *elements;
645 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
646 "%s [%s]", "Invalid syntax for GssapiCredStore option", w);
650 key = apr_pstrndup(parms->pool, w, (p-w));
651 value = apr_pstrdup(parms->pool, p + 1);
652 if (!key || !value) {
653 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
654 "%s", "OOM handling GssapiCredStore option");
658 if (!cfg->cred_store) {
659 cfg->cred_store = apr_pcalloc(parms->pool,
660 sizeof(gss_key_value_set_desc));
661 if (!cfg->cred_store) {
662 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
663 "%s", "OOM handling GssapiCredStore option");
666 size = sizeof(gss_key_value_element_desc) * MAX_CRED_OPTIONS;
667 cfg->cred_store->elements = apr_palloc(parms->pool, size);
668 if (!cfg->cred_store->elements) {
669 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
670 "%s", "OOM handling GssapiCredStore option");
674 elements = cfg->cred_store->elements;
675 count = cfg->cred_store->count;
677 if (count >= MAX_CRED_OPTIONS) {
678 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
679 "Too many GssapiCredStore options (MAX: %d)",
683 cfg->cred_store->count++;
685 elements[count].key = key;
686 elements[count].value = value;
691 static const char *mag_deleg_ccache_dir(cmd_parms *parms, void *mconfig,
694 struct mag_config *cfg = (struct mag_config *)mconfig;
696 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, value);
697 if (!cfg->deleg_ccache_dir) {
698 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
699 "%s", "OOM handling GssapiDelegCcacheDir option");
705 static const char *mag_use_basic_auth(cmd_parms *parms, void *mconfig, int on)
707 struct mag_config *cfg = (struct mag_config *)mconfig;
709 cfg->use_basic_auth = on ? true : false;
713 static const command_rec mag_commands[] = {
714 AP_INIT_FLAG("GssapiSSLonly", mag_ssl_only, NULL, OR_AUTHCFG,
715 "Work only if connection is SSL Secured"),
716 AP_INIT_FLAG("GssapiLocalName", mag_map_to_local, NULL, OR_AUTHCFG,
717 "Translate principals to local names"),
718 AP_INIT_FLAG("GssapiConnectionBound", mag_conn_ctx, NULL, OR_AUTHCFG,
719 "Authentication is bound to the TCP connection"),
720 AP_INIT_FLAG("GssapiUseSessions", mag_use_sess, NULL, OR_AUTHCFG,
721 "Authentication uses mod_sessions to hold status"),
722 AP_INIT_RAW_ARGS("GssapiSessionKey", mag_sess_key, NULL, OR_AUTHCFG,
723 "Key Used to seal session data."),
724 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
725 AP_INIT_FLAG("GssapiUseS4U2Proxy", mag_use_s4u2p, NULL, OR_AUTHCFG,
726 "Initializes credentials for s4u2proxy usage"),
728 #ifdef HAVE_GSS_STORE_CRED_INTO
729 AP_INIT_ITERATE("GssapiCredStore", mag_cred_store, NULL, OR_AUTHCFG,
731 AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL,
732 OR_AUTHCFG, "Directory to store delegated credentials"),
734 #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
735 AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
736 "Allows use of Basic Auth for authentication"),
742 mag_register_hooks(apr_pool_t *p)
744 ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE);
745 ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE);
746 ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
749 module AP_MODULE_DECLARE_DATA auth_gssapi_module =
751 STANDARD20_MODULE_STUFF,
752 mag_create_dir_config,