1 /***************************************************************************
2 Included Headers And Module Declaration
3 ***************************************************************************/
8 #include "http_config.h"
11 #include "http_protocol.h"
12 #include "http_request.h"
14 module kerb_auth_module;
17 #include "apr_strings.h"
19 #include "ap_config.h"
21 #include "http_config.h"
22 #include "http_core.h"
24 #include "http_protocol.h"
25 #include "http_request.h"
27 module AP_MODULE_DECLARE_DATA kerb_auth_module;
43 /***************************************************************************
44 Macros To Ease Compatibility
45 ***************************************************************************/
48 #define MK_TABLE_GET ap_table_get
49 #define MK_TABLE_SET ap_table_set
50 #define MK_TABLE_TYPE table
51 #define MK_PSTRDUP ap_pstrdup
52 #define MK_PROXY STD_PROXY
53 #define MK_USER r->connection->user
54 #define MK_AUTH_TYPE r->connection->ap_auth_type
55 #define MK_ARRAY_HEADER array_header
58 #define MK_POOL apr_pool_t
59 #define MK_TABLE_GET apr_table_get
60 #define MK_TABLE_SET apr_table_set
61 #define MK_TABLE_TYPE apr_table_t
62 #define MK_PSTRDUP apr_pstrdup
63 #define MK_PROXY PROXYREQ_PROXY
64 #define MK_USER r->user
65 #define MK_AUTH_TYPE r->ap_auth_type
66 #define MK_ARRAY_HEADER apr_array_header_t
73 /***************************************************************************
74 Auth Configuration Structure
75 ***************************************************************************/
84 int krb_authoritative;
85 char *krb_default_realm;
87 char *krb_force_instance;
95 int krb_save_credentials;
101 gss_ctx_id_t context;
102 gss_cred_id_t server_creds;
105 static gss_connection_t *gss_connection = NULL;
108 cleanup_gss_connection(void *data)
110 OM_uint32 minor_status;
111 gss_connection_t *gss_conn = (gss_connection_t *)data;
115 if (gss_conn->context != GSS_C_NO_CONTEXT)
116 gss_delete_sec_context(&minor_status, &gss_conn->context,
118 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
119 gss_release_cred(&minor_status, &gss_conn->server_creds);
124 /***************************************************************************
125 Auth Configuration Initialization
126 ***************************************************************************/
127 static void *kerb_dir_config(MK_POOL *p, char *d)
130 rec = (void *) ap_pcalloc(p, sizeof(kerb_auth_config));
131 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
132 ((kerb_auth_config *)rec)->krb_authoritative = 0;
133 ((kerb_auth_config *)rec)->krb_auth_type = MK_PSTRDUP(p, "None");
140 /***************************************************************************
141 Auth Configuration Parsers
142 ***************************************************************************/
143 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
146 int offset = (int) (long) cmd->info;
147 if (!strncasecmp(arg, "unauthorized", 12))
148 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
149 else if (!strncasecmp(arg, "forbidden", 9))
150 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
151 else if (!strncasecmp(arg, "declined", 8))
152 *(int *) ((char *)struct_ptr + offset) = DECLINED;
154 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
158 /* these are either char *struct_ptr, char *arg or void *struct_ptr, const char *arg */
159 static const char *kerb_set_type_slot(cmd_parms *cmd, void *struct_ptr,
162 int offset = (int) (long) cmd->info;
164 if (!strncasecmp(arg, "v5", 2))
165 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV5");
169 if (!strncasecmp(arg, "v4", 2))
170 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV4");
173 if (!strncasecmp(arg, "dualv5v4", 8))
174 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV5V4");
176 (!strncasecmp(arg, "dualv4v5", 8))
177 *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV4V5");
178 #if defined(KRB4) && defined(KRB5)
179 #endif /* KRB4 && KRB5 */
181 return "AuthKerberos must be V5, V4, DualV4V5, or DualV5V4.";
188 /***************************************************************************
189 Auth Configuration Commands
190 ***************************************************************************/
192 command_rec kerb_auth_cmds[] = {
196 (void*)XtOffsetOf(kerb_auth_config, krb_auth_type),
199 "Permit Kerberos auth without AuthType requirement."
206 (void*)XtOffsetOf(kerb_auth_config, krb_4_srvtab),
207 RSRC_CONF & ACCESS_CONF,
209 "Location of Kerberos V4 srvtab file."
217 (void*)XtOffsetOf(kerb_auth_config, krb_5_keytab),
218 RSRC_CONF & ACCESS_CONF,
220 "Location of Kerberos V5 keytab file."
227 (void*)XtOffsetOf(kerb_auth_config, krb_authoritative),
230 "Refuse to pass request down to lower modules."
236 (void*)XtOffsetOf(kerb_auth_config, krb_default_realm),
239 "Default realm to authenticate users against."
245 (void*)XtOffsetOf(kerb_auth_config, krb_fail_status),
248 "If auth fails, return status set here."
254 (void*)XtOffsetOf(kerb_auth_config, krb_force_instance),
257 "Force authentication against an instance specified here."
264 (void*)XtOffsetOf(kerb_auth_config, krb_forwardable),
267 "Credentials retrieved will be flagged as forwardable."
274 (void*)XtOffsetOf(kerb_auth_config, krb_lifetime),
277 "Lifetime of tickets retrieved."
284 (void*)XtOffsetOf(kerb_auth_config, krb_renewable),
287 "Credentials retrieved will be renewable for this length."
292 "KrbSaveCredentials",
294 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
297 "Save and store credentials/tickets retrieved during auth."
303 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
306 "Alias for KrbSaveCredentials."
312 (void*)XtOffsetOf(kerb_auth_config, krb_tmp_dir),
313 RSRC_CONF & ACCESS_CONF,
315 "Path to store ticket files and such in."
322 static const command_rec kerb_auth_cmds[] = {
326 (void*)APR_XtOffsetOf(kerb_auth_config, krb_auth_type),
328 "Permit Kerberos auth without AuthType requirement."
335 (void*)APR_XtOffsetOf(kerb_auth_config, krb_4_srvtab),
336 RSRC_CONF & ACCESS_CONF,
337 "Location of Kerberos V4 srvtab file."
345 (void*)APR_XtOffsetOf(kerb_auth_config, krb_5_keytab),
346 RSRC_CONF & ACCESS_CONF,
347 "Location of Kerberos V5 keytab file."
354 (void*)APR_XtOffsetOf(kerb_auth_config, krb_authoritative),
356 "Refuse to pass request down to lower modules."
362 (void*)APR_XtOffsetOf(kerb_auth_config, krb_default_realm),
364 "Default realm to authenticate users against."
370 (void*)APR_XtOffsetOf(kerb_auth_config, krb_fail_status),
372 "If auth fails, return status set here."
378 (void*)APR_XtOffsetOf(kerb_auth_config, krb_force_instance),
380 "Force authentication against an instance specified here."
387 (void*)APR_XtOffsetOf(kerb_auth_config, krb_forwardable),
389 "Credentials retrieved will be flagged as forwardable."
396 (void*)APR_XtOffsetOf(kerb_auth_config, krb_lifetime),
398 "Lifetime of tickets retrieved."
405 (void*)APR_XtOffsetOf(kerb_auth_config, krb_renewable),
407 "Credentials retrieved will be renewable for this length."
412 "KrbSaveCredentials",
414 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
416 "Save and store credentials/tickets retrieved during auth."
422 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
424 "Alias for KrbSaveCredentials."
430 (void*)APR_XtOffsetOf(kerb_auth_config, krb_tmp_dir),
431 RSRC_CONF & ACCESS_CONF,
432 "Path to store ticket files and such in."
443 krb5_verify_user(krb5_context context, krb5_principal principal,
444 krb5_ccache ccache, const char *password, krb5_boolean secure,
450 krb5_data tgtname = {
456 memset((char *)&my_creds, 0, sizeof(my_creds));
457 my_creds.client = principal;
459 if (krb5_build_principal_ext(kcontext, &server,
460 krb5_princ_realm(kcontext, me)->length,
461 krb5_princ_realm(kcontext, me)->data,
462 tgtname.length, tgtname.data,
463 krb5_princ_realm(kcontext, me)->length,
464 krb5_princ_realm(kcontext, me)->data,
469 my_creds.server = server;
470 if (krb5_timeofday(kcontext, &now))
473 my_creds.times.starttime = 0;
475 my_creds.times.endtime = now + lifetime;
476 my_creds.times.renew_till = now + renewal;
479 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
480 pass, ccache, &my_creds, 0);
490 /***************************************************************************
491 Username/Password Validation
492 ***************************************************************************/
495 krb5_cache_cleanup(void *data)
497 krb5_context context;
499 krb5_error_code problem;
500 char *cache_name = (char *) data;
502 problem = krb5_init_context(&context);
504 ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "krb5_init_context() failed");
508 problem = krb5_cc_resolve(context, cache_name, &cache);
510 ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
511 "krb5_cc_resolve() failed (%s: %s)",
512 cache_name, krb5_get_err_text(context, problem));
516 krb5_cc_destroy(context, cache);
517 krb5_free_context(context);
521 store_krb5_creds(krb5_context kcontext,
523 kerb_auth_config *conf,
524 krb5_ccache delegated_cred)
526 char *c, ccname[MAX_STRING_LEN];
527 krb5_error_code problem;
530 krb5_ccache ccache = NULL;
531 krb5_principal me = NULL;
533 sprintf(ccname, "FILE:%s/k5cc_ap_%s",
534 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
537 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
538 "/tmp") + 1; *c; c++) {
543 problem = krb5_cc_set_default_name(kcontext, ccname);
545 snprintf(errstr, sizeof(errstr),
546 "krb5_cc_set_default_name() failed: %s",
547 krb5_get_err_text(kcontext, problem));
548 ap_log_reason (errstr, r->uri, r);
553 /* XXX Dan: Why is this done? Cleanup? But the file would not be
554 * accessible from another processes (CGI) */
555 unlink(ccname+strlen("FILE:"));
558 problem = krb5_cc_resolve(kcontext, ccname, &ccache);
560 snprintf(errstr, sizeof(errstr),
561 "krb5_cc_resolve() failed: %s",
562 krb5_get_err_text(kcontext, problem));
563 ap_log_reason (errstr, r->uri, r);
568 problem = krb5_cc_get_principal(kcontext, delegated_cred, &me);
570 snprintf(errstr, sizeof(errstr),
571 "krb5_cc_get_principal() failed: %s",
572 krb5_get_err_text(kcontext, problem));
573 ap_log_reason (errstr, r->uri, r);
578 problem = krb5_cc_initialize(kcontext, ccache, me);
580 snprintf(errstr, sizeof(errstr),
581 "krb5_cc_initialize() failed: %s",
582 krb5_get_err_text(kcontext, problem));
583 ap_log_reason (errstr, r->uri, r);
588 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
590 snprintf(errstr, sizeof(errstr),
591 "krb5_cc_copy_cache failed: %s",
592 krb5_get_err_text(kcontext, problem));
593 ap_log_reason (errstr, r->uri, r);
597 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
598 ap_register_cleanup(r->pool, ccname,
599 krb5_cache_cleanup, ap_null_cleanup);
601 krb5_cc_close(kcontext, ccache);
607 return ret; /* XXX */
610 int kerb5_password_validate(request_rec *r, const char *user, const char *pass)
613 kerb_auth_config *conf =
614 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
617 krb5_context kcontext;
618 krb5_principal server, client;
619 krb5_ccache ccache = NULL;
620 krb5_deltat lifetime = 300; /* 5 minutes */
621 krb5_deltat renewal = 0;
622 krb5_flags options = 0;
624 krb5_error_code code;
627 if (krb5_init_context(&kcontext)) {
628 snprintf(errstr, sizeof(errstr),
629 "Cannot initialize Kerberos5 context");
630 ap_log_reason (errstr, r->uri, r);
635 if (conf->krb_forwardable) {
636 options |= KDC_OPT_FORWARDABLE;
639 if (conf->krb_renewable) {
640 options |= KDC_OPT_RENEWABLE;
641 renewal = 86400; /* 24 hours */
644 if (conf->krb_lifetime) {
645 lifetime = atoi(conf->krb_lifetime);
648 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
650 snprintf(errstr, sizeof(errstr), "krb5_cc_gen_new(): %.100s",
651 krb5_get_err_text(kcontext, code));
652 ap_log_reason (errstr, r->uri, r);
657 realms = conf->krb_default_realm;
661 code = krb5_set_default_realm(kcontext,
662 ap_getword_white(r->pool, &realms));
667 code = krb5_parse_name(kcontext, r->connection->user, &client);
671 code = krb5_verify_user(kcontext, client, ccache, pass,
673 krb5_free_principal(kcontext, client);
677 /* ap_getword_white() used above shifts the parameter, so it's not
678 needed to touch the realms variable */
679 } while (realms && *realms);
681 memset((char *)pass, 0, strlen(pass));
684 snprintf(errstr, sizeof(errstr), "Verifying krb5 password failed: %s",
685 krb5_get_err_text(kcontext, code));
686 ap_log_reason (errstr, r->uri, r);
687 ret = HTTP_UNAUTHORIZED;
691 if (conf->krb_save_credentials) {
692 ret = store_krb5_creds(kcontext, r, conf, ccache);
697 ret = 1; /* XXX should be OK ? */
701 krb5_cc_destroy(kcontext, ccache);
702 krb5_free_context(kcontext);
704 return (ret != 1) ? 0 : 1; /* XXX */
709 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
711 kerb_auth_config *conf =
712 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
715 int lifetime = DEFAULT_TKT_LIFE;
717 char *username = NULL;
718 char *instance = NULL;
721 username = (char *)ap_pstrdup(r->pool, user);
726 instance = strchr(username, '.');
734 realm = strchr(username, '@');
742 if (conf->krb_lifetime) {
743 lifetime = atoi(conf->krb_lifetime);
746 if (conf->krb_force_instance) {
747 instance = conf->krb_force_instance;
750 if (conf->krb_save_credentials) {
751 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
752 sprintf(tfname, "%s/k5cc_ap_%s",
753 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
756 if (!strcmp(instance, "")) {
757 tfname = strcat(tfname, ".");
758 tfname = strcat(tfname, instance);
761 if (!strcmp(realm, "")) {
762 tfname = strcat(tfname, ".");
763 tfname = strcat(tfname, realm);
766 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
767 "/tmp") + 1; *c; c++) {
772 krb_set_tkt_string(tfname);
775 if (!strcmp(realm, "")) {
776 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
777 ret = krb_get_lrealm(realm, 1);
782 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
783 lifetime, (char *)pass);
798 get_gss_creds(request_rec *r,
799 kerb_auth_config *conf,
800 gss_cred_id_t *server_creds)
803 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
804 OM_uint32 major_status, minor_status;
805 gss_name_t server_name = GSS_C_NO_NAME;
807 if (conf->service_name) {
808 input_token.value = conf->service_name;
809 input_token.length = strlen(conf->service_name) + 1;
812 input_token.value = "khttp";
813 input_token.length = 6;
815 major_status = gss_import_name(&minor_status, &input_token,
816 (conf->service_name) ?
817 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
819 if (GSS_ERROR(major_status)) {
820 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
821 "%s", get_gss_error(r->pool, minor_status,
822 "gss_import_name() failed"));
828 if (conf->krb_5_keytab)
829 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
832 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
833 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
834 server_creds, NULL, NULL);
836 if (conf->krb_5_keytab)
837 unsetenv("KRB5_KTNAME");
839 if (GSS_ERROR(major_status)) {
840 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
841 "%s", get_gss_error(r->pool, minor_status,
842 "gss_acquire_cred() failed"));
856 negotiate_authenticate_user(request_rec *r,
857 kerb_auth_config *conf,
858 const char *auth_line)
860 OM_uint32 major_status, minor_status, minor_status2;
861 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
862 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
863 const char *auth_param = NULL;
864 krb5_context krb_ctx = NULL;
866 gss_name_t client_name = GSS_C_NO_NAME;
867 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
870 if (gss_connection == NULL) {
871 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
872 if (gss_connection == NULL) {
873 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
874 "ap_pcalloc() failed (not enough memory)");
878 memset(gss_connection, 0, sizeof(*gss_connection));
879 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
882 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
883 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
888 /* ap_getword() shifts parameter */
889 auth_param = ap_getword_white(r->pool, &auth_line);
890 if (auth_param == NULL) {
891 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
892 "No Authorization parameter in request from client");
893 ret = HTTP_UNAUTHORIZED;
897 input_token.length = ap_base64decode_len(auth_param);
898 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
899 if (input_token.value == NULL) {
900 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
901 "ap_pcalloc() failed (not enough memory)");
905 input_token.length = ap_base64decode(input_token.value, auth_param);
907 major_status = gss_accept_sec_context(&minor_status,
908 &gss_connection->context,
909 gss_connection->server_creds,
911 GSS_C_NO_CHANNEL_BINDINGS,
918 if (output_token.length) {
922 len = ap_base64encode_len(output_token.length);
923 token = ap_pcalloc(r->connection->pool, len + 1);
925 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
926 "ap_pcalloc() failed (not enough memory)");
928 gss_release_buffer(&minor_status2, &output_token);
931 ap_base64encode(token, output_token.value, output_token.length);
933 ap_table_set(r->err_headers_out, "WWW-Authenticate",
934 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
935 gss_release_buffer(&minor_status2, &output_token);
938 if (GSS_ERROR(major_status)) {
939 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
940 "%s", get_gss_error(r->pool, minor_status,
941 "gss_accept_sec_context() failed"));
942 ret = HTTP_UNAUTHORIZED;
946 if (major_status & GSS_S_CONTINUE_NEEDED) {
947 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
948 * iterations to establish authentication */
949 ret = HTTP_UNAUTHORIZED;
953 major_status = gss_export_name(&minor_status, client_name, &output_token);
954 gss_release_name(&minor_status, &client_name);
955 if (GSS_ERROR(major_status)) {
956 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
957 "%s", get_gss_error(r->pool, minor_status,
958 "gss_export_name() failed"));
963 r->connection->ap_auth_type = "Negotiate";
964 r->connection->user = ap_pstrdup(r->pool, output_token.value);
966 /* If the user comes from a realm specified by configuration don't include
967 its realm name in the username so that the authorization routine could
968 work for both Password-based and Ticket-based authentication. It's
969 administrators responsibility to include only such realm that have
970 unified principal instances, i.e. if the same principal name occures in
971 multiple realms, it must be always assigned to a single user.
973 p = strchr(r->connection->user, '@');
975 const char *realms = conf->gss_krb5_realms;
977 while (realms && *realms) {
978 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
986 gss_release_buffer(&minor_status, &output_token);
989 /* This should be only done if afs token are requested or gss_save creds is
991 /* gss_export_cred() from the GGF GSS Extensions could be used */
992 if (delegated_cred != GSS_C_NO_CREDENTIAL &&
993 (conf->gss_save_creds || (conf->gss_krb5_cells && k_hasafs()))) {
994 krb5_init_context(&krb_ctx);
995 do_afs_log(krb_ctx, r, delegated_cred->ccache, conf->gss_krb5_cells);
996 ret = store_krb5_creds(krb_ctx, r, conf, delegated_cred->ccache);
997 krb5_free_context(krb_ctx);
1006 gss_release_cred(&minor_status, &delegated_cred);
1008 if (output_token.length)
1009 gss_release_buffer(&minor_status, &output_token);
1011 if (client_name != GSS_C_NO_NAME)
1012 gss_release_name(&minor_status, &client_name);
1018 /***************************************************************************
1020 ***************************************************************************/
1021 int kerb_authenticate_user(request_rec *r)
1023 const char *name; /* AuthName specified */
1024 const char *type; /* AuthType specified */
1025 int KerberosV5 = 0; /* Kerberos V5 check enabled */
1026 int KerberosV4 = 0; /* Kerberos V4 check enabled */
1027 int KerberosV4first = 0; /* Kerberos V4 check first */
1028 const char *sent_pw; /* Password sent by browser */
1029 int res; /* Response holder */
1030 int retcode; /* Return code holder */
1031 const char *t; /* Decoded auth_line */
1032 const char *authtype; /* AuthType to send back to browser */
1033 const char *auth_line = MK_TABLE_GET(r->headers_in,
1034 (r->proxyreq == MK_PROXY)
1035 ? "Proxy-Authorization"
1037 kerb_auth_config *conf =
1038 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1041 type = ap_auth_type(r);
1045 if ((strncasecmp(type, "KerberosV5", 10) == 0) ||
1046 (strncasecmp(conf->krb_auth_type, "KerberosV5", 10) == 0)) {
1052 if ((strncasecmp(type, "KerberosV4", 10) == 0) ||
1053 (strncasecmp(conf->krb_auth_type, "KerberosV4", 10) == 0)) {
1058 #if defined(KRB5) && defined(KRB4)
1059 if ((strncasecmp(type, "KerberosDualV5V4", 15) == 0) ||
1060 (strncasecmp(conf->krb_auth_type, "KerberosDualV5V4", 15) == 0)) {
1065 if ((strncasecmp(type, "KerberosDualV4V5", 15) == 0) ||
1066 (strncasecmp(conf->krb_auth_type, "KerberosDualV4V5", 15) == 0)) {
1069 KerberosV4first = 1;
1071 #endif /* KRB5 && KRB4 */
1074 if (!KerberosV4 && !KerberosV5) {
1075 if (conf->krb_authoritative) {
1076 return HTTP_UNAUTHORIZED;
1083 name = ap_auth_name(r);
1085 return HTTP_INTERNAL_SERVER_ERROR;
1089 MK_TABLE_SET(r->err_headers_out, "WWW-Authenticate",
1090 (char *)ap_pstrcat(r->pool,
1091 "Basic realm=\"", name, "\"", NULL));
1092 return HTTP_UNAUTHORIZED;
1095 type = ap_getword_white(r->pool, &auth_line);
1096 t = ap_pbase64decode(r->pool, auth_line);
1097 MK_USER = ap_getword_nulls(r->pool, &t, ':');
1098 MK_AUTH_TYPE = "Kerberos";
1099 sent_pw = ap_getword_white(r->pool, &t);
1104 if (KerberosV5 && !KerberosV4first && retcode != OK) {
1105 MK_AUTH_TYPE = "KerberosV5";
1106 if (kerb5_password_validate(r, MK_USER, sent_pw)) {
1110 retcode = conf->krb_fail_status;
1111 /* XXX should SERVER_ERROR be overriden too? */
1117 if (KerberosV4 && retcode != OK) {
1118 MK_AUTH_TYPE = "KerberosV4";
1119 if (kerb4_password_validate(r, MK_USER, sent_pw)) {
1123 retcode = conf->krb_fail_status;
1128 #if defined(KRB5) && defined(KRB4)
1129 if (KerberosV5 && KerberosV4first && retcode != OK) {
1130 MK_AUTH_TYPE = "KerberosV5";
1131 if (kerb5_password_validate(r, MK_USER, sent_pw)) {
1135 retcode = conf->krb_fail_status;
1138 #endif /* KRB5 && KRB4 */
1140 if (conf->krb_authoritative && retcode == DECLINED) {
1141 return HTTP_UNAUTHORIZED;
1151 /***************************************************************************
1153 ***************************************************************************/
1154 int kerb_check_user_access(request_rec *r)
1158 const MK_ARRAY_HEADER *reqs_arr = ap_requires(r);
1160 kerb_auth_config *conf =
1161 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1164 if (reqs_arr == NULL) {
1167 reqs = (require_line *)reqs_arr->elts;
1169 for (x = 0; x < reqs_arr->nelts; x++) {
1170 t = reqs[x].requirement;
1171 w = ap_getword_white(r->pool, &t);
1172 if (strcmp(w, "realm") == 0) {
1173 while (t[0] != '\0') {
1174 w = ap_getword_conf(r->pool, &t);
1175 if (strcmp(MK_USER, w) == 0) {
1188 /***************************************************************************
1189 Module Setup/Configuration
1190 ***************************************************************************/
1192 module MODULE_VAR_EXPORT kerb_auth_module = {
1193 STANDARD_MODULE_STUFF,
1194 NULL, /* module initializer */
1195 kerb_dir_config, /* per-directory config creator */
1196 NULL, /* per-directory config merger */
1197 NULL, /* per-server config creator */
1198 NULL, /* per-server config merger */
1199 kerb_auth_cmds, /* command table */
1200 NULL, /* [ 9] content handlers */
1201 NULL, /* [ 2] URI-to-filename translation */
1202 kerb_authenticate_user, /* [ 5] check/validate user_id */
1203 kerb_check_user_access, /* [ 6] check user_id is valid *here* */
1204 NULL, /* [ 4] check access by host address */
1205 NULL, /* [ 7] MIME type checker/setter */
1206 NULL, /* [ 8] fixups */
1207 NULL, /* [10] logger */
1208 NULL, /* [ 3] header parser */
1209 NULL, /* process initialization */
1210 NULL, /* process exit/cleanup */
1211 NULL /* [ 1] post read_request handling */
1213 , /* EAPI Additions */
1214 NULL, /* EAPI add module */
1215 NULL, /* EAPI remove module */
1216 NULL, /* EAPI rewrite command */
1217 NULL /* EAPI new connection */
1222 void kerb_register_hooks(apr_pool_t *p)
1224 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1225 ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE);
1228 module AP_MODULE_DECLARE_DATA kerb_auth_module =
1230 STANDARD20_MODULE_STUFF,
1231 kerb_dir_config, /* create per-dir conf structures */
1232 NULL, /* merge per-dir conf structures */
1233 NULL, /* create per-server conf structures */
1234 NULL, /* merge per-server conf structures */
1235 kerb_auth_cmds, /* table of configuration directives */
1236 kerb_register_hooks /* register hooks */