5 #include "apr_strings.h"
8 #include "http_config.h"
11 #include "http_protocol.h"
12 #include "http_request.h"
18 #include <gssapi_generic.h>
19 #define GSS_C_NT_USER_NAME gss_nt_user_name
20 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
21 #define krb5_get_err_text(context,code) error_message(code)
30 module auth_kerb_module;
32 module AP_MODULE_DECLARE_DATA auth_kerb_module;
35 /***************************************************************************
36 Macros To Ease Compatibility
37 ***************************************************************************/
40 #define MK_TABLE_GET ap_table_get
41 #define MK_TABLE_SET ap_table_set
42 #define MK_TABLE_TYPE table
43 #define MK_PSTRDUP ap_pstrdup
44 #define MK_USER r->connection->user
45 #define MK_AUTH_TYPE r->connection->ap_auth_type
46 #define MK_ARRAY_HEADER array_header
48 #define MK_POOL apr_pool_t
49 #define MK_TABLE_GET apr_table_get
50 #define MK_TABLE_SET apr_table_set
51 #define MK_TABLE_TYPE apr_table_t
52 #define MK_PSTRDUP apr_pstrdup
53 #define MK_USER r->user
54 #define MK_AUTH_TYPE r->ap_auth_type
55 #define MK_ARRAY_HEADER apr_array_header_t
59 /***************************************************************************
60 Auth Configuration Structure
61 ***************************************************************************/
63 char *krb_auth_realms;
65 char *krb_force_instance;
66 int krb_save_credentials;
72 int krb_method_gssapi;
73 int krb_method_k5pass;
77 int krb_method_k4pass;
82 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
85 #define command(name, func, var, type, usage) \
87 (void*)XtOffsetOf(kerb_auth_config, var), \
88 OR_AUTHCFG, type, usage }
90 #define command(name, func, var, type, usage) \
91 AP_INIT_ ## type (name, func, \
92 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
96 static const command_rec kerb_auth_cmds[] = {
97 command("KrbAuthRealm", krb5_save_realms, krb_auth_realms,
98 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
100 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
101 RAW_ARGS, "Alias for KrbAuthRealm."),
104 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
105 TAKE1, "If auth fails, return status set here."),
108 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
109 TAKE1, "Force authentication against an instance specified here."),
111 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
112 FLAG, "Save and store credentials/tickets retrieved during auth."),
114 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
115 FLAG, "Alias for KrbSaveCredentials."),
117 command("KrbServiceName", ap_set_string_slot, service_name,
118 TAKE1, "Kerberos service name to be used by apache."),
121 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
122 TAKE1, "Kerberos ticket lifetime."),
126 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
127 TAKE1, "Location of Kerberos V5 keytab file."),
129 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
130 FLAG, "Credentials retrieved will be flagged as forwardable."),
132 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
133 FLAG, "Enable GSSAPI authentication."),
135 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
136 FLAG, "Enable Kerberos V5 password authentication."),
140 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
141 TAKE1, "Location of Kerberos V4 srvtab file."),
143 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
144 FLAG, "Enable Kerberos V4 password authentication."),
152 gss_ctx_id_t context;
153 gss_cred_id_t server_creds;
156 static gss_connection_t *gss_connection = NULL;
160 /***************************************************************************
161 Auth Configuration Initialization
162 ***************************************************************************/
163 static void *kerb_dir_create_config(MK_POOL *p, char *d)
165 kerb_auth_config *rec;
167 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
168 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
170 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
171 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
174 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
180 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
182 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
186 void log_rerror(const char *file, int line, int level, int status,
187 const request_rec *r, const char *fmt, ...)
193 vsnprintf(errstr, sizeof(errstr), fmt, ap);
197 ap_log_rerror(file, line, level, r, "%s", errstr);
199 ap_log_rerror(file, line, level, status, r, "%s", errstr);
204 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
207 int offset = (int) (long) cmd->info;
208 if (!strncasecmp(arg, "unauthorized", 12))
209 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
210 else if (!strncasecmp(arg, "forbidden", 9))
211 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
212 else if (!strncasecmp(arg, "declined", 8))
213 *(int *) ((char *)struct_ptr + offset) = DECLINED;
215 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
221 /***************************************************************************
222 Username/Password Validation for Krb4
223 ***************************************************************************/
224 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
226 kerb_auth_config *conf =
227 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
230 int lifetime = DEFAULT_TKT_LIFE;
232 char *username = NULL;
233 char *instance = NULL;
236 username = (char *)ap_pstrdup(r->pool, user);
241 instance = strchr(username, '.');
249 realm = strchr(username, '@');
257 if (conf->krb_lifetime) {
258 lifetime = atoi(conf->krb_lifetime);
261 if (conf->krb_force_instance) {
262 instance = conf->krb_force_instance;
265 if (conf->krb_save_credentials) {
266 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
267 sprintf(tfname, "/tmp/k5cc_ap_%s", MK_USER);
269 if (!strcmp(instance, "")) {
270 tfname = strcat(tfname, ".");
271 tfname = strcat(tfname, instance);
274 if (!strcmp(realm, "")) {
275 tfname = strcat(tfname, ".");
276 tfname = strcat(tfname, realm);
279 for (c = tfname + strlen("/tmp") + 1; *c; c++) {
284 krb_set_tkt_string(tfname);
287 if (!strcmp(realm, "")) {
288 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
289 ret = krb_get_lrealm(realm, 1);
294 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
295 lifetime, (char *)pass);
310 /***************************************************************************
311 Username/Password Validation for Krb5
312 ***************************************************************************/
315 krb5_verify_user(krb5_context context, krb5_principal principal,
316 krb5_ccache ccache, const char *password, krb5_boolean secure,
320 krb5_context kcontext;
321 krb5_principal server, client;
324 krb5_flags options = 0;
325 krb5_principal me = NULL;
326 krb5_data tgtname = {
334 memset((char *)&my_creds, 0, sizeof(my_creds));
335 my_creds.client = principal;
337 if (krb5_build_principal_ext(kcontext, &server,
338 krb5_princ_realm(kcontext, me)->length,
339 krb5_princ_realm(kcontext, me)->data,
340 tgtname.length, tgtname.data,
341 krb5_princ_realm(kcontext, me)->length,
342 krb5_princ_realm(kcontext, me)->data,
347 my_creds.server = server;
348 if (krb5_timeofday(kcontext, &now))
351 my_creds.times.starttime = 0;
353 my_creds.times.endtime = now + lifetime;
354 my_creds.times.renew_till = now + renewal;
357 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
358 password, ccache, &my_creds, 0);
369 krb5_cache_cleanup(void *data)
371 krb5_context context;
373 krb5_error_code problem;
374 char *cache_name = (char *) data;
376 problem = krb5_init_context(&context);
378 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
379 return HTTP_INTERNAL_SERVER_ERROR;
382 problem = krb5_cc_resolve(context, cache_name, &cache);
384 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
385 "krb5_cc_resolve() failed (%s: %s)",
386 cache_name, krb5_get_err_text(context, problem)); */
387 return HTTP_INTERNAL_SERVER_ERROR;
390 krb5_cc_destroy(context, cache);
391 krb5_free_context(context);
396 create_krb5_ccache(krb5_context kcontext,
398 kerb_auth_config *conf,
399 krb5_principal princ,
403 krb5_error_code problem;
405 krb5_ccache tmp_ccache = NULL;
408 problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
410 problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
413 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
414 "Cannot create file for new krb5 ccache: %s",
415 krb5_get_err_text(kcontext, problem));
416 ret = HTTP_INTERNAL_SERVER_ERROR;
420 ccname = ap_pstrdup(r->pool, krb5_cc_get_name(kcontext, tmp_ccache));
422 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
424 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
425 "Cannot create krb5 ccache %s: krb5_cc_initialize() failed: %s",
426 ccname, krb5_get_err_text(kcontext, problem));
427 ret = HTTP_INTERNAL_SERVER_ERROR;
431 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
432 ap_register_cleanup(r->pool, ccname,
433 krb5_cache_cleanup, ap_null_cleanup);
435 *ccache = tmp_ccache;
442 krb5_cc_destroy(kcontext, tmp_ccache);
448 store_krb5_creds(krb5_context kcontext,
450 kerb_auth_config *conf,
451 krb5_ccache delegated_cred)
454 krb5_error_code problem;
455 krb5_principal princ;
459 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
461 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
462 krb5_get_err_text(kcontext, problem));
463 return HTTP_INTERNAL_SERVER_ERROR;
466 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
468 krb5_free_principal(kcontext, princ);
473 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
475 problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
477 krb5_free_principal(kcontext, princ);
479 snprintf(errstr, sizeof(errstr), "Failed to store credentials: %s",
480 krb5_get_err_text(kcontext, problem));
481 krb5_cc_destroy(kcontext, ccache);
482 return HTTP_INTERNAL_SERVER_ERROR;
485 krb5_cc_close(kcontext, ccache);
490 int authenticate_user_krb5pwd(request_rec *r,
491 kerb_auth_config *conf,
492 const char *auth_line)
494 const char *sent_pw = NULL;
495 const char *sent_name = NULL;
496 const char *realms = NULL;
497 const char *service_name = NULL;
498 krb5_context kcontext = NULL;
499 krb5_error_code code;
500 krb5_principal client = NULL;
501 krb5_ccache ccache = NULL;
505 code = krb5_init_context(&kcontext);
507 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
508 "Cannot initialize Kerberos5 context (%d)", code);
509 return HTTP_INTERNAL_SERVER_ERROR;
512 sent_pw = ap_pbase64decode(r->pool, auth_line);
513 sent_name = ap_getword (r->pool, &sent_pw, ':');
514 /* do not allow user to override realm setting of server */
515 if (strchr(sent_name, '@')) {
516 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
517 "specifying realm in user name is prohibited");
518 ret = HTTP_UNAUTHORIZED;
523 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
525 code = krb5_mcc_generate_new(kcontext, &ccache);
528 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
529 "Cannot generate new ccache: %s",
530 krb5_get_err_text(kcontext, code));
531 ret = HTTP_INTERNAL_SERVER_ERROR;
535 if (conf->krb_5_keytab)
536 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
537 /* kcontext->default_keytab = conf->krb_5_keytab; */
539 if (conf->service_name) {
541 service_name = ap_pstrdup(r->pool, conf->service_name);
542 if ((p=strchr(service_name, '/')))
545 service_name = "khttp";
547 realms = conf->krb_auth_realms;
549 if (realms && (code = krb5_set_default_realm(kcontext,
550 ap_getword_white(r->pool, &realms))))
554 krb5_free_principal(kcontext, client);
557 code = krb5_parse_name(kcontext, sent_name, &client);
561 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
566 /* ap_getword_white() used above shifts the parameter, so it's not
567 needed to touch the realms variable */
568 } while (realms && *realms);
570 memset((char *)sent_pw, 0, strlen(sent_pw));
573 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
574 "Verifying krb5 password failed: %s",
575 krb5_get_err_text(kcontext, code));
576 ret = HTTP_UNAUTHORIZED;
580 code = krb5_unparse_name(kcontext, client, &name);
582 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
583 krb5_get_err_text(kcontext, code));
584 ret = HTTP_UNAUTHORIZED;
587 MK_USER = ap_pstrdup (r->pool, name);
588 MK_AUTH_TYPE = "Basic";
591 if (conf->krb_save_credentials)
592 store_krb5_creds(kcontext, r, conf, ccache);
598 krb5_free_principal(kcontext, client);
600 krb5_cc_destroy(kcontext, ccache);
601 krb5_free_context(kcontext);
606 /*********************************************************************
607 * GSSAPI Authentication
608 ********************************************************************/
611 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
613 OM_uint32 maj_stat, min_stat;
614 OM_uint32 msg_ctx = 0;
615 gss_buffer_desc status_string;
619 snprintf(buf, sizeof(buf), "%s", prefix);
622 maj_stat = gss_display_status (&min_stat,
628 if (sizeof(buf) > len + status_string.length + 1) {
629 sprintf(buf+len, ": %s", (char*) status_string.value);
630 len += status_string.length;
632 gss_release_buffer(&min_stat, &status_string);
633 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
635 return (ap_pstrdup(p, buf));
639 cleanup_gss_connection(void *data)
641 OM_uint32 minor_status;
642 gss_connection_t *gss_conn = (gss_connection_t *)data;
646 if (gss_conn->context != GSS_C_NO_CONTEXT)
647 gss_delete_sec_context(&minor_status, &gss_conn->context,
649 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
650 gss_release_cred(&minor_status, &gss_conn->server_creds);
656 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
657 gss_cred_id_t delegated_cred)
659 OM_uint32 maj_stat, min_stat;
660 krb5_principal princ = NULL;
661 krb5_ccache ccache = NULL;
662 krb5_error_code problem;
663 krb5_context context;
664 int ret = HTTP_INTERNAL_SERVER_ERROR;
666 problem = krb5_init_context(&context);
668 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
669 return HTTP_INTERNAL_SERVER_ERROR;
672 problem = krb5_parse_name(context, princ_name, &princ);
674 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
675 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
679 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
681 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
682 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
686 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
687 if (GSS_ERROR(maj_stat)) {
688 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
689 "Cannot store delegated credential (%s)",
690 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
694 krb5_cc_close(context, ccache);
700 krb5_free_principal(context, princ);
702 krb5_cc_destroy(context, ccache);
703 krb5_free_context(context);
708 get_gss_creds(request_rec *r,
709 kerb_auth_config *conf,
710 gss_cred_id_t *server_creds)
712 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
713 OM_uint32 major_status, minor_status, minor_status2;
714 gss_name_t server_name = GSS_C_NO_NAME;
716 if (conf->service_name) {
717 input_token.value = conf->service_name;
718 input_token.length = strlen(conf->service_name) + 1;
721 input_token.value = "khttp";
722 input_token.length = 6;
724 major_status = gss_import_name(&minor_status, &input_token,
725 (conf->service_name) ?
726 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
728 if (GSS_ERROR(major_status)) {
729 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
730 "%s", get_gss_error(r->pool, minor_status,
731 "gss_import_name() failed"));
732 return HTTP_INTERNAL_SERVER_ERROR;
735 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
736 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
737 server_creds, NULL, NULL);
738 gss_release_name(&minor_status2, &server_name);
739 if (GSS_ERROR(major_status)) {
740 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
741 "%s", get_gss_error(r->pool, minor_status,
742 "gss_acquire_cred() failed"));
743 return HTTP_INTERNAL_SERVER_ERROR;
750 authenticate_user_gss(request_rec *r,
751 kerb_auth_config *conf,
752 const char *auth_line)
754 OM_uint32 major_status, minor_status, minor_status2;
755 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
756 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
757 const char *auth_param = NULL;
759 gss_name_t client_name = GSS_C_NO_NAME;
760 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
761 static int initial_return = HTTP_UNAUTHORIZED;
763 /* needed to work around replay caches */
764 if (!ap_is_initial_req(r))
765 return initial_return;
766 initial_return = HTTP_UNAUTHORIZED;
768 if (gss_connection == NULL) {
769 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
770 if (gss_connection == NULL) {
771 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
772 "ap_pcalloc() failed (not enough memory)");
773 ret = HTTP_INTERNAL_SERVER_ERROR;
776 memset(gss_connection, 0, sizeof(*gss_connection));
777 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
780 if (conf->krb_5_keytab)
781 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
783 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
784 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
789 /* ap_getword() shifts parameter */
790 auth_param = ap_getword_white(r->pool, &auth_line);
791 if (auth_param == NULL) {
792 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
793 "No Authorization parameter in request from client");
794 ret = HTTP_UNAUTHORIZED;
798 input_token.length = ap_base64decode_len(auth_param) + 1;
799 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
800 if (input_token.value == NULL) {
801 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
802 "ap_pcalloc() failed (not enough memory)");
803 ret = HTTP_INTERNAL_SERVER_ERROR;
806 input_token.length = ap_base64decode(input_token.value, auth_param);
808 major_status = gss_accept_sec_context(&minor_status,
809 &gss_connection->context,
810 gss_connection->server_creds,
812 GSS_C_NO_CHANNEL_BINDINGS,
819 if (output_token.length) {
823 len = ap_base64encode_len(output_token.length) + 1;
824 token = ap_pcalloc(r->connection->pool, len + 1);
826 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
827 "ap_pcalloc() failed (not enough memory)");
828 ret = HTTP_INTERNAL_SERVER_ERROR;
829 gss_release_buffer(&minor_status2, &output_token);
832 ap_base64encode(token, output_token.value, output_token.length);
834 ap_table_set(r->err_headers_out, "WWW-Authenticate",
835 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
836 gss_release_buffer(&minor_status2, &output_token);
839 if (GSS_ERROR(major_status)) {
840 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
841 "%s", get_gss_error(r->pool, minor_status,
842 "gss_accept_sec_context() failed"));
843 ret = HTTP_UNAUTHORIZED;
847 if (major_status & GSS_S_CONTINUE_NEEDED) {
848 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
849 * iterations to establish authentication */
850 ret = HTTP_UNAUTHORIZED;
854 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
855 gss_release_name(&minor_status, &client_name);
856 if (GSS_ERROR(major_status)) {
857 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
858 "%s", get_gss_error(r->pool, minor_status,
859 "gss_export_name() failed"));
860 ret = HTTP_INTERNAL_SERVER_ERROR;
864 MK_AUTH_TYPE = "Negotiate";
865 MK_USER = ap_pstrdup(r->pool, output_token.value);
867 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
868 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
870 gss_release_buffer(&minor_status, &output_token);
874 /* If the user comes from a realm specified by configuration don't include
875 its realm name in the username so that the authorization routine could
876 work for both Password-based and Ticket-based authentication. It's
877 administrators responsibility to include only such realm that have
878 unified principal instances, i.e. if the same principal name occures in
879 multiple realms, it must be always assigned to a single user.
881 p = strchr(r->connection->user, '@');
883 const char *realms = conf->gss_krb5_realms;
885 while (realms && *realms) {
886 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
898 gss_release_cred(&minor_status, &delegated_cred);
900 if (output_token.length)
901 gss_release_buffer(&minor_status, &output_token);
903 if (client_name != GSS_C_NO_NAME)
904 gss_release_name(&minor_status, &client_name);
906 initial_return = ret;
913 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
915 const char *auth_name = NULL;
917 /* get the user realm specified in .htaccess */
918 auth_name = ap_auth_name(r);
920 /* XXX check AuthType */
922 /* XXX should the WWW-Authenticate header be cleared first? */
924 if (conf->krb_method_gssapi)
925 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
926 if (conf->krb_method_k5pass)
927 ap_table_add(r->err_headers_out, "WWW-Authenticate",
928 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
932 if (conf->krb_method_k4pass)
933 ap_table_add(r->err_headers_out, "WWW-Authenticate",
934 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
938 int kerb_authenticate_user(request_rec *r)
940 kerb_auth_config *conf =
941 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
943 const char *auth_type = NULL;
944 const char *auth_line = NULL;
945 const char *type = NULL;
946 int use_krb5 = 0, use_krb4 = 0;
949 /* get the type specified in .htaccess */
950 type = ap_auth_type(r);
952 if (type && strcasecmp(type, "Kerberos") == 0)
953 use_krb5 = use_krb4 = 1;
954 else if(type && strcasecmp(type, "KerberosV5") == 0)
956 else if (type && strcasecmp(type, "KerberosV4") == 0)
961 /* get what the user sent us in the HTTP header */
962 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
964 note_kerb_auth_failure(r, conf);
965 return HTTP_UNAUTHORIZED;
967 auth_type = ap_getword_white(r->pool, &auth_line);
969 ret = HTTP_UNAUTHORIZED;
972 if (use_krb5 && conf->krb_method_gssapi &&
973 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
974 ret = authenticate_user_gss(r, conf, auth_line);
975 } else if (use_krb5 && conf->krb_method_k5pass &&
976 strcasecmp(auth_type, "Basic") == 0) {
977 ret = authenticate_user_krb5pwd(r, conf, auth_line);
982 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
983 strcasecmp(auth_type, "Basic") == 0)
984 ret = authenticate_user_krb4pwd(r, conf, auth_line);
987 if (ret == HTTP_UNAUTHORIZED)
988 note_kerb_auth_failure(r, conf);
994 /***************************************************************************
995 Module Setup/Configuration
996 ***************************************************************************/
998 module MODULE_VAR_EXPORT auth_kerb_module = {
999 STANDARD_MODULE_STUFF,
1000 NULL, /* module initializer */
1001 kerb_dir_create_config, /* per-directory config creator */
1002 NULL, /* per-directory config merger */
1003 NULL, /* per-server config creator */
1004 NULL, /* per-server config merger */
1005 kerb_auth_cmds, /* command table */
1006 NULL, /* [ 9] content handlers */
1007 NULL, /* [ 2] URI-to-filename translation */
1008 kerb_authenticate_user, /* [ 5] check/validate user_id */
1009 NULL, /* [ 6] check user_id is valid *here* */
1010 NULL, /* [ 4] check access by host address */
1011 NULL, /* [ 7] MIME type checker/setter */
1012 NULL, /* [ 8] fixups */
1013 NULL, /* [10] logger */
1014 NULL, /* [ 3] header parser */
1015 NULL, /* process initialization */
1016 NULL, /* process exit/cleanup */
1017 NULL /* [ 1] post read_request handling */
1020 void kerb_register_hooks(apr_pool_t *p)
1022 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1025 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1027 STANDARD20_MODULE_STUFF,
1028 kerb_dir_create_config, /* create per-dir conf structures */
1029 NULL, /* merge per-dir conf structures */
1030 NULL, /* create per-server conf structures */
1031 NULL, /* merge per-server conf structures */
1032 kerb_auth_cmds, /* table of configuration directives */
1033 kerb_register_hooks /* register hooks */