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 char *escape(apr_pool_t *pool, const char *name,
123 char find, const char *replace)
125 char *escaped = NULL;
130 namecopy = apr_pstrdup(pool, name);
131 if (!namecopy) goto done;
133 p = strchr(namecopy, find);
134 if (!p) return namecopy;
139 /* terminate previous segment */
142 escaped = apr_pstrcat(pool, escaped, n, replace, NULL);
144 escaped = apr_pstrcat(pool, n, replace, NULL);
146 if (!escaped) goto done;
147 /* move to next segment */
151 /* append last segment if any */
153 escaped = apr_pstrcat(pool, escaped, n, NULL);
158 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
159 "OOM escaping name");
164 static void mag_store_deleg_creds(request_rec *req,
165 char *dir, char *clientname,
166 gss_cred_id_t delegated_cred,
169 gss_key_value_element_desc element;
170 gss_key_value_set_desc store;
175 /* We need to escape away '/', we can't have path separators in
176 * a ccache file name */
177 /* first double escape the esacping char (~) if any */
178 escaped = escape(req->pool, clientname, '~', "~~");
179 if (!escaped) return;
180 /* then escape away the separator (/) if any */
181 escaped = escape(req->pool, escaped, '/', "~");
182 if (!escaped) return;
184 value = apr_psprintf(req->pool, "FILE:%s/%s", dir, escaped);
186 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, NULL,
187 "OOM storing delegated credentials");
191 element.key = "ccache";
192 element.value = value;
193 store.elements = &element;
196 maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE,
197 GSS_C_NULL_OID, 1, 1, &store, NULL, NULL);
198 if (GSS_ERROR(maj)) {
199 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
200 mag_error(req, "failed to store delegated creds",
207 static int mag_auth(request_rec *req)
210 const char *auth_type;
211 struct mag_config *cfg;
212 const char *auth_header;
213 char *auth_header_type;
214 char *auth_header_value;
215 int ret = HTTP_UNAUTHORIZED;
216 gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
218 gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
219 gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
220 gss_buffer_desc name = GSS_C_EMPTY_BUFFER;
221 gss_name_t client = GSS_C_NO_NAME;
222 gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
223 gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL;
224 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
225 gss_cred_usage_t cred_usage = GSS_C_ACCEPT;
232 gss_OID mech_type = GSS_C_NO_OID;
233 gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
234 struct mag_conn *mc = NULL;
235 bool is_basic = false;
236 gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT;
237 gss_name_t server = GSS_C_NO_NAME;
238 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
239 const char *user_ccache = NULL;
240 const char *orig_ccache = NULL;
243 type = ap_auth_type(req);
244 if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
248 /* ignore auth for subrequests */
249 if (!ap_is_initial_req(req)) {
253 cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);
256 if (!mag_conn_is_https(req->connection)) {
257 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
258 "Not a TLS connection, refusing to authenticate!");
263 if (cfg->gss_conn_ctx) {
264 mc = (struct mag_conn *)ap_get_module_config(
265 req->connection->conn_config,
266 &auth_gssapi_module);
268 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
269 "Failed to retrieve connection context!");
274 /* if available, session always supersedes connection bound data */
275 if (cfg->use_sessions) {
276 mag_check_session(req, cfg, &mc);
280 /* register the context in the memory pool, so it can be freed
281 * when the connection/request is terminated */
282 apr_pool_userdata_set(mc, "mag_conn_ptr",
283 mag_conn_destroy, mc->parent);
285 if (mc->established) {
286 ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
287 "Already established context found!");
288 apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name);
289 req->ap_auth_type = apr_pstrdup(req->pool, mc->auth_type);
290 req->user = apr_pstrdup(req->pool, mc->user_name);
299 auth_header = apr_table_get(req->headers_in, "Authorization");
300 if (!auth_header) goto done;
302 auth_header_type = ap_getword_white(req->pool, &auth_header);
303 if (!auth_header_type) goto done;
305 if (strcasecmp(auth_header_type, "Negotiate") == 0) {
306 auth_type = "Negotiate";
308 auth_header_value = ap_getword_white(req->pool, &auth_header);
309 if (!auth_header_value) goto done;
310 input.length = apr_base64_decode_len(auth_header_value) + 1;
311 input.value = apr_pcalloc(req->pool, input.length);
312 if (!input.value) goto done;
313 input.length = apr_base64_decode(input.value, auth_header_value);
314 } else if ((strcasecmp(auth_header_type, "Basic") == 0) &&
315 (cfg->use_basic_auth == true)) {
319 gss_buffer_desc ba_user;
320 gss_buffer_desc ba_pwd;
322 ba_pwd.value = ap_pbase64decode(req->pool, auth_header);
323 if (!ba_pwd.value) goto done;
324 ba_user.value = ap_getword_nulls_nc(req->pool,
325 (char **)&ba_pwd.value, ':');
326 if (!ba_user.value) goto done;
327 if (((char *)ba_user.value)[0] == '\0' ||
328 ((char *)ba_pwd.value)[0] == '\0') {
329 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
330 "Invalid empty user or password for Basic Auth");
333 ba_user.length = strlen(ba_user.value);
334 ba_pwd.length = strlen(ba_pwd.value);
335 maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &client);
336 if (GSS_ERROR(maj)) {
337 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
339 mag_error(req, "gss_import_name() failed",
343 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
344 /* Set a per-thread ccache in case we are using kerberos,
345 * it is not elegant but avoids interference between threads */
346 long long unsigned int rndname;
348 rs = apr_generate_random_bytes((unsigned char *)(&rndname),
349 sizeof(long long unsigned int));
350 if (rs != APR_SUCCESS) {
351 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
352 "Failed to generate random ccache name");
355 user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname);
356 maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache);
357 if (GSS_ERROR(maj)) {
358 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
360 mag_error(req, "gss_krb5_ccache_name() "
361 "failed", maj, min));
365 maj = gss_acquire_cred_with_password(&min, client, &ba_pwd,
369 &user_cred, NULL, NULL);
370 if (GSS_ERROR(maj)) {
371 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
373 mag_error(req, "gss_acquire_cred_with_password() "
374 "failed", maj, min));
377 gss_release_name(&min, &client);
382 req->ap_auth_type = apr_pstrdup(req->pool, auth_type);
384 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
385 if (cfg->use_s4u2proxy) {
386 cred_usage = GSS_C_BOTH;
388 if (cfg->cred_store) {
389 maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
390 GSS_C_NO_OID_SET, cred_usage,
391 cfg->cred_store, &acquired_cred,
393 if (GSS_ERROR(maj)) {
394 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
395 mag_error(req, "gss_acquire_cred_from() failed",
403 if (!acquired_cred) {
404 /* Try to acquire default creds */
405 maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
406 GSS_C_NO_OID_SET, cred_usage,
407 &acquired_cred, NULL, NULL);
408 if (GSS_ERROR(maj)) {
409 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
410 "%s", mag_error(req, "gss_acquire_cred_from()"
411 " failed", maj, min));
415 maj = gss_inquire_cred(&min, acquired_cred, &server,
417 if (GSS_ERROR(maj)) {
418 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
419 "%s", mag_error(req, "gss_inquired_cred_() "
420 "failed", maj, min));
423 /* output and input are inverted here, this is intentional */
424 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
425 GSS_C_NO_OID, 0, 300,
426 GSS_C_NO_CHANNEL_BINDINGS, &output,
427 NULL, &input, NULL, NULL);
428 if (GSS_ERROR(maj)) {
429 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
430 "%s", mag_error(req, "gss_init_sec_context() "
431 "failed", maj, min));
436 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
437 &input, GSS_C_NO_CHANNEL_BINDINGS,
438 &client, &mech_type, &output, &flags, &vtime,
440 if (GSS_ERROR(maj)) {
441 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
442 mag_error(req, "gss_accept_sec_context() failed",
447 while (maj == GSS_S_CONTINUE_NEEDED) {
448 gss_release_buffer(&min, &input);
449 /* output and input are inverted here, this is intentional */
450 maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
451 GSS_C_NO_OID, 0, 300,
452 GSS_C_NO_CHANNEL_BINDINGS, &output,
453 NULL, &input, NULL, NULL);
454 if (GSS_ERROR(maj)) {
455 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
456 "%s", mag_error(req, "gss_init_sec_context() "
457 "failed", maj, min));
460 gss_release_buffer(&min, &output);
461 maj = gss_accept_sec_context(&min, pctx, acquired_cred,
462 &input, GSS_C_NO_CHANNEL_BINDINGS,
463 &client, &mech_type, &output, &flags,
464 &vtime, &delegated_cred);
465 if (GSS_ERROR(maj)) {
466 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
467 "%s", mag_error(req, "gss_accept_sec_context()"
468 " failed", maj, min));
472 } else if (maj == GSS_S_CONTINUE_NEEDED) {
474 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
475 "Mechanism needs continuation but neither "
476 "GssapiConnectionBound nor "
477 "GssapiUseSessions are available");
478 gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
479 gss_release_buffer(&min, &output);
482 /* auth not complete send token and wait next packet */
486 /* Always set the GSS name in an env var */
487 maj = gss_display_name(&min, client, &name, NULL);
488 if (GSS_ERROR(maj)) {
489 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
490 mag_error(req, "gss_display_name() failed",
494 clientname = apr_pstrndup(req->pool, name.value, name.length);
495 apr_table_set(req->subprocess_env, "GSS_NAME", clientname);
497 #ifdef HAVE_GSS_STORE_CRED_INTO
498 if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
499 char *ccachefile = NULL;
501 mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
502 delegated_cred, &ccachefile);
505 apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
510 if (cfg->map_to_local) {
511 maj = gss_localname(&min, client, mech_type, &lname);
512 if (maj != GSS_S_COMPLETE) {
513 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
514 mag_error(req, "gss_localname() failed", maj, min));
517 req->user = apr_pstrndup(req->pool, lname.value, lname.length);
519 req->user = clientname;
523 mc->user_name = apr_pstrdup(mc->parent, req->user);
524 mc->gss_name = apr_pstrdup(mc->parent, clientname);
525 mc->established = true;
526 if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
527 vtime = MIN_SESS_EXP_TIME;
529 mc->expiration = time(NULL) + vtime;
530 if (cfg->use_sessions) {
531 mag_attempt_session(req, cfg, mc);
533 mc->auth_type = auth_type;
539 if (ret == HTTP_UNAUTHORIZED) {
540 if (output.length != 0) {
541 replen = apr_base64_encode_len(output.length) + 1;
542 reply = apr_pcalloc(req->pool, 10 + replen);
544 memcpy(reply, "Negotiate ", 10);
545 apr_base64_encode(&reply[10], output.value, output.length);
546 apr_table_add(req->err_headers_out,
547 "WWW-Authenticate", reply);
550 apr_table_add(req->err_headers_out,
551 "WWW-Authenticate", "Negotiate");
552 if (cfg->use_basic_auth) {
553 apr_table_add(req->err_headers_out,
555 apr_psprintf(req->pool, "Basic realm=\"%s\"",
560 #ifdef HAVE_GSS_KRB5_CCACHE_NAME
561 if (user_ccache != NULL) {
562 maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
563 if (maj != GSS_S_COMPLETE) {
564 ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
565 "Failed to restore per-thread ccache, %s",
566 mag_error(req, "gss_krb5_ccache_name() "
567 "failed", maj, min));
571 gss_delete_sec_context(&min, &user_ctx, &output);
572 gss_release_cred(&min, &user_cred);
573 gss_release_cred(&min, &acquired_cred);
574 gss_release_cred(&min, &delegated_cred);
575 gss_release_buffer(&min, &output);
576 gss_release_name(&min, &client);
577 gss_release_name(&min, &server);
578 gss_release_buffer(&min, &name);
579 gss_release_buffer(&min, &lname);
584 static void *mag_create_dir_config(apr_pool_t *p, char *dir)
586 struct mag_config *cfg;
588 cfg = (struct mag_config *)apr_pcalloc(p, sizeof(struct mag_config));
589 if (!cfg) return NULL;
595 static const char *mag_ssl_only(cmd_parms *parms, void *mconfig, int on)
597 struct mag_config *cfg = (struct mag_config *)mconfig;
598 cfg->ssl_only = on ? true : false;
602 static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on)
604 struct mag_config *cfg = (struct mag_config *)mconfig;
605 cfg->map_to_local = on ? true : false;
609 static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on)
611 struct mag_config *cfg = (struct mag_config *)mconfig;
612 cfg->gss_conn_ctx = on ? true : false;
616 static const char *mag_use_sess(cmd_parms *parms, void *mconfig, int on)
618 struct mag_config *cfg = (struct mag_config *)mconfig;
619 cfg->use_sessions = on ? true : false;
623 static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
625 struct mag_config *cfg = (struct mag_config *)mconfig;
626 cfg->use_s4u2proxy = on ? true : false;
628 if (cfg->deleg_ccache_dir == NULL) {
629 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, "/tmp");
630 if (!cfg->deleg_ccache_dir) {
631 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0,
632 parms->server, "%s", "OOM setting deleg_ccache_dir.");
638 static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
640 struct mag_config *cfg = (struct mag_config *)mconfig;
647 if (strncmp(w, "key:", 4) != 0) {
648 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
649 "Invalid key format, expected prefix 'key:'");
654 l = apr_base64_decode_len(k);
655 val = apr_palloc(parms->temp_pool, l);
657 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
658 "Failed to get memory to decode key");
662 key.length = (int)apr_base64_decode_binary(val, k);
663 key.value = (unsigned char *)val;
665 if (key.length < 32) {
666 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
667 "Invalid key length, expected >=32 got %d", key.length);
671 rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &key);
673 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
674 "Failed to import sealing key!");
679 #define MAX_CRED_OPTIONS 10
681 static const char *mag_cred_store(cmd_parms *parms, void *mconfig,
684 struct mag_config *cfg = (struct mag_config *)mconfig;
685 gss_key_value_element_desc *elements;
694 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
695 "%s [%s]", "Invalid syntax for GssapiCredStore option", w);
699 key = apr_pstrndup(parms->pool, w, (p-w));
700 value = apr_pstrdup(parms->pool, p + 1);
701 if (!key || !value) {
702 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
703 "%s", "OOM handling GssapiCredStore option");
707 if (!cfg->cred_store) {
708 cfg->cred_store = apr_pcalloc(parms->pool,
709 sizeof(gss_key_value_set_desc));
710 if (!cfg->cred_store) {
711 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
712 "%s", "OOM handling GssapiCredStore option");
715 size = sizeof(gss_key_value_element_desc) * MAX_CRED_OPTIONS;
716 cfg->cred_store->elements = apr_palloc(parms->pool, size);
717 if (!cfg->cred_store->elements) {
718 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
719 "%s", "OOM handling GssapiCredStore option");
723 elements = cfg->cred_store->elements;
724 count = cfg->cred_store->count;
726 if (count >= MAX_CRED_OPTIONS) {
727 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
728 "Too many GssapiCredStore options (MAX: %d)",
732 cfg->cred_store->count++;
734 elements[count].key = key;
735 elements[count].value = value;
740 static const char *mag_deleg_ccache_dir(cmd_parms *parms, void *mconfig,
743 struct mag_config *cfg = (struct mag_config *)mconfig;
745 cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, value);
746 if (!cfg->deleg_ccache_dir) {
747 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server,
748 "%s", "OOM handling GssapiDelegCcacheDir option");
754 static const char *mag_use_basic_auth(cmd_parms *parms, void *mconfig, int on)
756 struct mag_config *cfg = (struct mag_config *)mconfig;
758 cfg->use_basic_auth = on ? true : false;
762 static const command_rec mag_commands[] = {
763 AP_INIT_FLAG("GssapiSSLonly", mag_ssl_only, NULL, OR_AUTHCFG,
764 "Work only if connection is SSL Secured"),
765 AP_INIT_FLAG("GssapiLocalName", mag_map_to_local, NULL, OR_AUTHCFG,
766 "Translate principals to local names"),
767 AP_INIT_FLAG("GssapiConnectionBound", mag_conn_ctx, NULL, OR_AUTHCFG,
768 "Authentication is bound to the TCP connection"),
769 AP_INIT_FLAG("GssapiUseSessions", mag_use_sess, NULL, OR_AUTHCFG,
770 "Authentication uses mod_sessions to hold status"),
771 AP_INIT_RAW_ARGS("GssapiSessionKey", mag_sess_key, NULL, OR_AUTHCFG,
772 "Key Used to seal session data."),
773 #ifdef HAVE_GSS_ACQUIRE_CRED_FROM
774 AP_INIT_FLAG("GssapiUseS4U2Proxy", mag_use_s4u2p, NULL, OR_AUTHCFG,
775 "Initializes credentials for s4u2proxy usage"),
777 #ifdef HAVE_GSS_STORE_CRED_INTO
778 AP_INIT_ITERATE("GssapiCredStore", mag_cred_store, NULL, OR_AUTHCFG,
780 AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL,
781 OR_AUTHCFG, "Directory to store delegated credentials"),
783 #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
784 AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
785 "Allows use of Basic Auth for authentication"),
791 mag_register_hooks(apr_pool_t *p)
793 ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE);
794 ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE);
795 ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
798 module AP_MODULE_DECLARE_DATA auth_gssapi_module =
800 STANDARD20_MODULE_STUFF,
801 mag_create_dir_config,