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;
46 /***************************************************************************
47 Macros To Ease Compatibility
48 ***************************************************************************/
51 #define MK_TABLE_GET ap_table_get
52 #define MK_TABLE_SET ap_table_set
53 #define MK_TABLE_TYPE table
54 #define MK_PSTRDUP ap_pstrdup
55 #define MK_PROXY STD_PROXY
56 #define MK_USER r->connection->user
57 #define MK_AUTH_TYPE r->connection->ap_auth_type
58 #define MK_ARRAY_HEADER array_header
61 #define MK_POOL apr_pool_t
62 #define MK_TABLE_GET apr_table_get
63 #define MK_TABLE_SET apr_table_set
64 #define MK_TABLE_TYPE apr_table_t
65 #define MK_PSTRDUP apr_pstrdup
66 #define MK_PROXY PROXYREQ_PROXY
67 #define MK_USER r->user
68 #define MK_AUTH_TYPE r->ap_auth_type
69 #define MK_ARRAY_HEADER apr_array_header_t
76 /***************************************************************************
77 Auth Configuration Structure
78 ***************************************************************************/
87 char *krb_auth_realms;
88 int krb_authoritative;
90 char *krb_force_instance;
96 int krb_method_gssapi;
99 int krb_method_k4pass;
102 int krb_method_k5pass;
105 int krb_save_credentials;
113 /***************************************************************************
114 GSSAPI Support Initialization
115 ***************************************************************************/
118 gss_ctx_id_t context;
119 gss_cred_id_t server_creds;
122 static gss_connection_t *gss_connection = NULL;
125 cleanup_gss_connection(void *data)
127 OM_uint32 minor_status;
128 gss_connection_t *gss_conn = (gss_connection_t *)data;
132 if (gss_conn->context != GSS_C_NO_CONTEXT)
133 gss_delete_sec_context(&minor_status, &gss_conn->context,
135 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
136 gss_release_cred(&minor_status, &gss_conn->server_creds);
143 /***************************************************************************
144 Auth Configuration Initialization
145 ***************************************************************************/
146 static void *kerb_dir_config(MK_POOL *p, char *d)
149 rec = (void *) ap_pcalloc(p, sizeof(kerb_auth_config));
150 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
151 ((kerb_auth_config *)rec)->krb_authoritative = 0;
153 ((kerb_auth_config *)rec)->krb_method_gssapi = 0;
156 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
159 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
161 ((kerb_auth_config *)rec)->krb_method_k4pass = 0;
164 ((kerb_auth_config *)rec)->krb_auth_realms = "";
171 /***************************************************************************
172 Auth Configuration Parsers
173 ***************************************************************************/
174 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
177 int offset = (int) (long) cmd->info;
178 if (!strncasecmp(arg, "unauthorized", 12))
179 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
180 else if (!strncasecmp(arg, "forbidden", 9))
181 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
182 else if (!strncasecmp(arg, "declined", 8))
183 *(int *) ((char *)struct_ptr + offset) = DECLINED;
185 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
192 /***************************************************************************
193 Auth Configuration Commands
194 ***************************************************************************/
196 command_rec kerb_auth_cmds[] = {
200 (void*)XtOffsetOf(kerb_auth_config, krb_auth_enable),
203 "Permit Kerberos auth without AuthType requirement."
210 (void*)XtOffsetOf(kerb_auth_config, krb_4_srvtab),
211 RSRC_CONF & ACCESS_CONF,
213 "Location of Kerberos V4 srvtab file."
221 (void*)XtOffsetOf(kerb_auth_config, krb_5_keytab),
222 RSRC_CONF & ACCESS_CONF,
224 "Location of Kerberos V5 keytab file."
231 (void*)XtOffsetOf(kerb_auth_config, krb_authoritative),
234 "Refuse to pass request down to lower modules."
240 (void*)XtOffsetOf(kerb_auth_config, krb_auth_realms),
243 "Realms to attempt authentication against (can be multiple)."
249 (void*)XtOffsetOf(kerb_auth_config, krb_fail_status),
252 "If auth fails, return status set here."
258 (void*)XtOffsetOf(kerb_auth_config, krb_force_instance),
261 "Force authentication against an instance specified here."
268 (void*)XtOffsetOf(kerb_auth_config, krb_forwardable),
271 "Credentials retrieved will be flagged as forwardable."
278 (void*)XtOffsetOf(kerb_auth_config, krb_lifetime),
281 "Lifetime of tickets retrieved."
288 (void*)XtOffsetOf(kerb_auth_config, krb_method_gssapi),
291 "Enable GSSAPI authentication."
299 (void*)XtOffsetOf(kerb_auth_config, krb_method_k4pass),
302 "Enable Kerberos V4 password authentication."
310 (void*)XtOffsetOf(kerb_auth_config, krb_method_k5pass),
313 "Enable Kerberos V5 password authentication."
319 (void*)XtOffsetOf(kerb_auth_config, krb_renewable),
322 "Credentials retrieved will be renewable for this length."
327 "KrbSaveCredentials",
329 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
332 "Save and store credentials/tickets retrieved during auth."
338 (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials),
341 "Alias for KrbSaveCredentials."
347 (void*)XtOffsetOf(kerb_auth_config, krb_tmp_dir),
348 RSRC_CONF & ACCESS_CONF,
350 "Path to store ticket files and such in."
357 static const command_rec kerb_auth_cmds[] = {
361 (void*)APR_XtOffsetOf(kerb_auth_config, krb_auth_enable),
363 "Permit Kerberos auth without AuthType requirement."
370 (void*)APR_XtOffsetOf(kerb_auth_config, krb_4_srvtab),
371 RSRC_CONF & ACCESS_CONF,
372 "Location of Kerberos V4 srvtab file."
380 (void*)APR_XtOffsetOf(kerb_auth_config, krb_5_keytab),
381 RSRC_CONF & ACCESS_CONF,
382 "Location of Kerberos V5 keytab file."
389 (void*)APR_XtOffsetOf(kerb_auth_config, krb_authoritative),
391 "Refuse to pass request down to lower modules."
397 (void*)APR_XtOffsetOf(kerb_auth_config, krb_auth_realms),
399 "Realm to attempt authentication against (can be multiple)."
405 (void*)APR_XtOffsetOf(kerb_auth_config, krb_fail_status),
407 "If auth fails, return status set here."
413 (void*)APR_XtOffsetOf(kerb_auth_config, krb_force_instance),
415 "Force authentication against an instance specified here."
422 (void*)APR_XtOffsetOf(kerb_auth_config, krb_forwardable),
424 "Credentials retrieved will be flagged as forwardable."
431 (void*)APR_XtOffsetOf(kerb_auth_config, krb_lifetime),
433 "Lifetime of tickets retrieved."
440 (void*)APR_XtOffsetOf(kerb_auth_config, krb_method_gssapi),
442 "Enable GSSAPI authentication."
450 (void*)APR_XtOffsetOf(kerb_auth_config, krb_method_k4pass),
452 "Enable Kerberos V4 password authentication."
460 (void*)APR_XtOffsetOf(kerb_auth_config, krb_method_k5pass),
462 "Enable Kerberos V5 password authentication."
468 (void*)APR_XtOffsetOf(kerb_auth_config, krb_renewable),
470 "Credentials retrieved will be renewable for this length."
475 "KrbSaveCredentials",
477 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
479 "Save and store credentials/tickets retrieved during auth."
485 (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials),
487 "Alias for KrbSaveCredentials."
493 (void*)APR_XtOffsetOf(kerb_auth_config, krb_tmp_dir),
494 RSRC_CONF & ACCESS_CONF,
495 "Path to store ticket files and such in."
506 krb5_verify_user(krb5_context context, krb5_principal principal,
507 krb5_ccache ccache, const char *password, krb5_boolean secure,
511 krb5_context kcontext;
512 krb5_principal server, client;
515 krb5_flags options = 0;
516 krb5_principal me = NULL;
517 krb5_data tgtname = {
523 memset((char *)&my_creds, 0, sizeof(my_creds));
524 my_creds.client = principal;
526 if (krb5_build_principal_ext(kcontext, &server,
527 krb5_princ_realm(kcontext, me)->length,
528 krb5_princ_realm(kcontext, me)->data,
529 tgtname.length, tgtname.data,
530 krb5_princ_realm(kcontext, me)->length,
531 krb5_princ_realm(kcontext, me)->data,
536 my_creds.server = server;
537 if (krb5_timeofday(kcontext, &now))
540 my_creds.times.starttime = 0;
542 my_creds.times.endtime = now + lifetime;
543 my_creds.times.renew_till = now + renewal;
546 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
547 password, ccache, &my_creds, 0);
557 /***************************************************************************
558 Username/Password Validation
559 ***************************************************************************/
562 krb5_cache_cleanup(void *data)
564 krb5_context context;
566 krb5_error_code problem;
567 char *cache_name = (char *) data;
569 problem = krb5_init_context(&context);
571 ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "krb5_init_context() failed");
575 problem = krb5_cc_resolve(context, cache_name, &cache);
577 ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
578 "krb5_cc_resolve() failed (%s: %s)",
579 cache_name, krb5_get_err_text(context, problem));
583 krb5_cc_destroy(context, cache);
584 krb5_free_context(context);
588 store_krb5_creds(krb5_context kcontext,
590 kerb_auth_config *conf,
591 krb5_ccache delegated_cred)
593 char *c, ccname[MAX_STRING_LEN];
594 krb5_error_code problem;
597 krb5_ccache ccache = NULL;
598 krb5_principal me = NULL;
600 sprintf(ccname, "FILE:%s/k5cc_ap_%s",
601 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
604 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
605 "/tmp") + 1; *c; c++) {
610 problem = krb5_cc_set_default_name(kcontext, ccname);
612 snprintf(errstr, sizeof(errstr),
613 "krb5_cc_set_default_name() failed: %s",
614 krb5_get_err_text(kcontext, problem));
615 ap_log_reason (errstr, r->uri, r);
620 /* XXX Dan: Why is this done? Cleanup? But the file would not be
621 * accessible from another processes (CGI) */
622 unlink(ccname+strlen("FILE:"));
625 problem = krb5_cc_resolve(kcontext, ccname, &ccache);
627 snprintf(errstr, sizeof(errstr),
628 "krb5_cc_resolve() failed: %s",
629 krb5_get_err_text(kcontext, problem));
630 ap_log_reason (errstr, r->uri, r);
635 problem = krb5_cc_get_principal(kcontext, delegated_cred, &me);
637 snprintf(errstr, sizeof(errstr),
638 "krb5_cc_get_principal() failed: %s",
639 krb5_get_err_text(kcontext, problem));
640 ap_log_reason (errstr, r->uri, r);
645 problem = krb5_cc_initialize(kcontext, ccache, me);
647 snprintf(errstr, sizeof(errstr),
648 "krb5_cc_initialize() failed: %s",
649 krb5_get_err_text(kcontext, problem));
650 ap_log_reason (errstr, r->uri, r);
655 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
657 snprintf(errstr, sizeof(errstr),
658 "krb5_cc_copy_cache failed: %s",
659 krb5_get_err_text(kcontext, problem));
660 ap_log_reason (errstr, r->uri, r);
664 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
665 ap_register_cleanup(r->pool, ccname,
666 krb5_cache_cleanup, ap_null_cleanup);
668 krb5_cc_close(kcontext, ccache);
674 return ret; /* XXX */
677 int kerb5_password_validate(request_rec *r, const char *user, const char *pass)
680 kerb_auth_config *conf =
681 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
684 krb5_context kcontext;
685 krb5_principal client;
686 krb5_ccache ccache = NULL;
687 krb5_deltat lifetime = 300; /* 5 minutes */
688 krb5_deltat renewal = 0;
689 krb5_flags options = 0;
691 krb5_error_code code;
694 if (krb5_init_context(&kcontext)) {
695 snprintf(errstr, sizeof(errstr),
696 "Cannot initialize Kerberos5 context");
697 ap_log_reason (errstr, r->uri, r);
702 if (conf->krb_forwardable) {
703 options |= KDC_OPT_FORWARDABLE;
706 if (conf->krb_renewable) {
707 options |= KDC_OPT_RENEWABLE;
708 renewal = 86400; /* 24 hours */
711 if (conf->krb_lifetime) {
712 lifetime = atoi(conf->krb_lifetime);
716 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
718 code = krb5_mcc_generate_new(kcontext, &ccache);
721 snprintf(errstr, sizeof(errstr), "Cannot generate new ccache: %.100s",
722 krb5_get_err_text(kcontext, code));
723 ap_log_reason (errstr, r->uri, r);
728 realms = conf->krb_auth_realms;
732 code = krb5_set_default_realm(kcontext,
733 ap_getword_white(r->pool, &realms));
738 code = krb5_parse_name(kcontext, r->connection->user, &client);
742 code = krb5_verify_user(kcontext, client, ccache, pass,
744 krb5_free_principal(kcontext, client);
748 /* ap_getword_white() used above shifts the parameter, so it's not
749 needed to touch the realms variable */
750 } while (realms && *realms);
752 memset((char *)pass, 0, strlen(pass));
755 snprintf(errstr, sizeof(errstr), "Verifying krb5 password failed: %s",
756 krb5_get_err_text(kcontext, code));
757 ap_log_reason (errstr, r->uri, r);
758 ret = HTTP_UNAUTHORIZED;
762 if (conf->krb_save_credentials) {
763 ret = store_krb5_creds(kcontext, r, conf, ccache);
768 ret = 1; /* XXX should be OK ? */
772 krb5_cc_destroy(kcontext, ccache);
773 krb5_free_context(kcontext);
775 return (ret != 1) ? 0 : 1; /* XXX */
780 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
782 kerb_auth_config *conf =
783 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
786 int lifetime = DEFAULT_TKT_LIFE;
788 char *username = NULL;
789 char *instance = NULL;
792 username = (char *)ap_pstrdup(r->pool, user);
797 instance = strchr(username, '.');
805 realm = strchr(username, '@');
813 if (conf->krb_lifetime) {
814 lifetime = atoi(conf->krb_lifetime);
817 if (conf->krb_force_instance) {
818 instance = conf->krb_force_instance;
821 if (conf->krb_save_credentials) {
822 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
823 sprintf(tfname, "%s/k5cc_ap_%s",
824 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
827 if (!strcmp(instance, "")) {
828 tfname = strcat(tfname, ".");
829 tfname = strcat(tfname, instance);
832 if (!strcmp(realm, "")) {
833 tfname = strcat(tfname, ".");
834 tfname = strcat(tfname, realm);
837 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
838 "/tmp") + 1; *c; c++) {
843 krb_set_tkt_string(tfname);
846 if (!strcmp(realm, "")) {
847 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
848 ret = krb_get_lrealm(realm, 1);
853 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
854 lifetime, (char *)pass);
871 /***************************************************************************
873 ***************************************************************************/
876 get_gss_error(pool *p, OM_uint32 error_status, char *prefix)
878 OM_uint32 maj_stat, min_stat;
879 OM_uint32 msg_ctx = 0;
880 gss_buffer_desc status_string;
884 snprintf(buf, sizeof(buf), "%s: ", prefix);
887 maj_stat = gss_display_status (&min_stat,
893 if (sizeof(buf) > len + status_string.length + 1) {
894 sprintf(buf+len, "%s:", (char*) status_string.value);
895 len += status_string.length;
897 gss_release_buffer(&min_stat, &status_string);
898 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
900 return (ap_pstrdup(p, buf));
904 get_gss_creds(request_rec *r,
905 kerb_auth_config *conf,
906 gss_cred_id_t *server_creds)
909 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
910 OM_uint32 major_status, minor_status;
911 gss_name_t server_name = GSS_C_NO_NAME;
913 if (conf->service_name) {
914 input_token.value = conf->service_name;
915 input_token.length = strlen(conf->service_name) + 1;
918 input_token.value = "khttp";
919 input_token.length = 6;
921 major_status = gss_import_name(&minor_status, &input_token,
922 (conf->service_name) ?
923 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
925 if (GSS_ERROR(major_status)) {
926 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
927 "%s", get_gss_error(r->pool, minor_status,
928 "gss_import_name() failed"));
934 if (conf->krb_5_keytab)
935 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
938 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
939 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
940 server_creds, NULL, NULL);
942 if (conf->krb_5_keytab)
943 unsetenv("KRB5_KTNAME");
945 if (GSS_ERROR(major_status)) {
946 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
947 "%s", get_gss_error(r->pool, minor_status,
948 "gss_acquire_cred() failed"));
962 negotiate_authenticate_user(request_rec *r,
963 kerb_auth_config *conf,
964 const char *auth_line)
966 OM_uint32 major_status, minor_status, minor_status2;
967 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
968 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
969 const char *auth_param = NULL;
971 gss_name_t client_name = GSS_C_NO_NAME;
972 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
974 if (gss_connection == NULL) {
975 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
976 if (gss_connection == NULL) {
977 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
978 "ap_pcalloc() failed (not enough memory)");
982 memset(gss_connection, 0, sizeof(*gss_connection));
983 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
986 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
987 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
992 /* ap_getword() shifts parameter */
993 auth_param = ap_getword_white(r->pool, &auth_line);
994 if (auth_param == NULL) {
995 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
996 "No Authorization parameter in request from client");
997 ret = HTTP_UNAUTHORIZED;
1001 input_token.length = ap_base64decode_len(auth_param);
1002 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
1003 if (input_token.value == NULL) {
1004 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1005 "ap_pcalloc() failed (not enough memory)");
1009 input_token.length = ap_base64decode(input_token.value, auth_param);
1011 major_status = gss_accept_sec_context(&minor_status,
1012 &gss_connection->context,
1013 gss_connection->server_creds,
1015 GSS_C_NO_CHANNEL_BINDINGS,
1022 if (output_token.length) {
1026 len = ap_base64encode_len(output_token.length);
1027 token = ap_pcalloc(r->connection->pool, len + 1);
1028 if (token == NULL) {
1029 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1030 "ap_pcalloc() failed (not enough memory)");
1032 gss_release_buffer(&minor_status2, &output_token);
1035 ap_base64encode(token, output_token.value, output_token.length);
1037 ap_table_set(r->err_headers_out, "WWW-Authenticate",
1038 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
1039 gss_release_buffer(&minor_status2, &output_token);
1042 if (GSS_ERROR(major_status)) {
1043 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1044 "%s", get_gss_error(r->pool, minor_status,
1045 "gss_accept_sec_context() failed"));
1046 ret = HTTP_UNAUTHORIZED;
1050 if (major_status & GSS_S_CONTINUE_NEEDED) {
1051 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
1052 * iterations to establish authentication */
1053 ret = HTTP_UNAUTHORIZED;
1057 major_status = gss_export_name(&minor_status, client_name, &output_token);
1058 gss_release_name(&minor_status, &client_name);
1059 if (GSS_ERROR(major_status)) {
1060 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1061 "%s", get_gss_error(r->pool, minor_status,
1062 "gss_export_name() failed"));
1067 r->connection->ap_auth_type = "Negotiate";
1068 r->connection->user = ap_pstrdup(r->pool, output_token.value);
1070 /* If the user comes from a realm specified by configuration don't include
1071 its realm name in the username so that the authorization routine could
1072 work for both Password-based and Ticket-based authentication. It's
1073 administrators responsibility to include only such realm that have
1074 unified principal instances, i.e. if the same principal name occures in
1075 multiple realms, it must be always assigned to a single user.
1077 p = strchr(r->connection->user, '@');
1079 const char *realms = conf->gss_krb5_realms;
1081 while (realms && *realms) {
1082 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
1090 gss_release_buffer(&minor_status, &output_token);
1093 /* This should be only done if afs token are requested or gss_save creds is
1095 /* gss_export_cred() from the GGF GSS Extensions could be used */
1096 if (delegated_cred != GSS_C_NO_CREDENTIAL &&
1097 (conf->gss_save_creds || (conf->gss_krb5_cells && k_hasafs()))) {
1098 krb5_init_context(&krb_ctx);
1099 do_afs_log(krb_ctx, r, delegated_cred->ccache, conf->gss_krb5_cells);
1100 ret = store_krb5_creds(krb_ctx, r, conf, delegated_cred->ccache);
1101 krb5_free_context(krb_ctx);
1110 gss_release_cred(&minor_status, &delegated_cred);
1112 if (output_token.length)
1113 gss_release_buffer(&minor_status, &output_token);
1115 if (client_name != GSS_C_NO_NAME)
1116 gss_release_name(&minor_status, &client_name);
1125 /***************************************************************************
1127 ***************************************************************************/
1128 int kerb_authenticate_user(request_rec *r)
1130 const char *name; /* AuthName specified */
1131 const char *type; /* AuthType specified */
1132 const char *sent_pw; /* Password sent by browser */
1133 int res; /* Response holder */
1134 int retcode; /* Return code holder */
1135 const char *t; /* Decoded auth_line */
1136 const char *authtype; /* AuthType to send back to browser */
1137 const char *auth_line = MK_TABLE_GET(r->headers_in,
1138 (r->proxyreq == MK_PROXY)
1139 ? "Proxy-Authorization"
1141 kerb_auth_config *conf =
1142 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1145 type = ap_auth_type(r);
1147 if (!conf->krb_auth_enable &&
1148 (type == NULL || (strncasecmp(type, "Kerberos", 8) != 0))) {
1149 if (conf->krb_authoritative) {
1150 return HTTP_UNAUTHORIZED;
1157 name = ap_auth_name(r);
1159 return HTTP_INTERNAL_SERVER_ERROR;
1163 MK_TABLE_SET(r->err_headers_out, "WWW-Authenticate",
1164 (char *)ap_pstrcat(r->pool,
1165 "Basic realm=\"", name, "\"", NULL));
1166 return HTTP_UNAUTHORIZED;
1169 type = ap_getword_white(r->pool, &auth_line);
1170 t = ap_pbase64decode(r->pool, auth_line);
1171 MK_USER = ap_getword_nulls(r->pool, &t, ':');
1172 MK_AUTH_TYPE = "Kerberos";
1173 sent_pw = ap_getword_white(r->pool, &t);
1178 if (conf->krb_method_gssapi && retcode != OK) {
1179 MK_AUTH_TYPE = "Negotiate";
1180 if (negotiate_authenticate_user(r, conf, auth_line))
1183 retcode = conf->krb_fail_status;
1188 if (conf->krb_method_k5pass && retcode != OK) {
1189 MK_AUTH_TYPE = "KerberosV5";
1190 if (kerb5_password_validate(r, MK_USER, sent_pw)) {
1194 retcode = conf->krb_fail_status;
1195 /* XXX should SERVER_ERROR be overriden too? */
1201 if (conf->krb_method_k4pass && retcode != OK) {
1202 MK_AUTH_TYPE = "KerberosV4";
1203 if (kerb4_password_validate(r, MK_USER, sent_pw)) {
1207 retcode = conf->krb_fail_status;
1212 if (conf->krb_authoritative && retcode == DECLINED) {
1213 return HTTP_UNAUTHORIZED;
1223 /***************************************************************************
1225 ***************************************************************************/
1226 int kerb_check_user_access(request_rec *r)
1230 const MK_ARRAY_HEADER *reqs_arr = ap_requires(r);
1232 kerb_auth_config *conf =
1233 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1236 if (reqs_arr == NULL) {
1239 reqs = (require_line *)reqs_arr->elts;
1241 for (x = 0; x < reqs_arr->nelts; x++) {
1242 t = reqs[x].requirement;
1243 w = ap_getword_white(r->pool, &t);
1244 if (strcmp(w, "realm") == 0) {
1245 while (t[0] != '\0') {
1246 w = ap_getword_conf(r->pool, &t);
1247 if (strcmp(MK_USER, w) == 0) {
1260 /***************************************************************************
1261 Module Setup/Configuration
1262 ***************************************************************************/
1264 module MODULE_VAR_EXPORT kerb_auth_module = {
1265 STANDARD_MODULE_STUFF,
1266 NULL, /* module initializer */
1267 kerb_dir_config, /* per-directory config creator */
1268 NULL, /* per-directory config merger */
1269 NULL, /* per-server config creator */
1270 NULL, /* per-server config merger */
1271 kerb_auth_cmds, /* command table */
1272 NULL, /* [ 9] content handlers */
1273 NULL, /* [ 2] URI-to-filename translation */
1274 kerb_authenticate_user, /* [ 5] check/validate user_id */
1275 kerb_check_user_access, /* [ 6] check user_id is valid *here* */
1276 NULL, /* [ 4] check access by host address */
1277 NULL, /* [ 7] MIME type checker/setter */
1278 NULL, /* [ 8] fixups */
1279 NULL, /* [10] logger */
1280 NULL, /* [ 3] header parser */
1281 NULL, /* process initialization */
1282 NULL, /* process exit/cleanup */
1283 NULL /* [ 1] post read_request handling */
1285 , /* EAPI Additions */
1286 NULL, /* EAPI add module */
1287 NULL, /* EAPI remove module */
1288 NULL, /* EAPI rewrite command */
1289 NULL /* EAPI new connection */
1294 void kerb_register_hooks(apr_pool_t *p)
1296 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1297 ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE);
1300 module AP_MODULE_DECLARE_DATA kerb_auth_module =
1302 STANDARD20_MODULE_STUFF,
1303 kerb_dir_config, /* create per-dir conf structures */
1304 NULL, /* merge per-dir conf structures */
1305 NULL, /* create per-server conf structures */
1306 NULL, /* merge per-server conf structures */
1307 kerb_auth_cmds, /* table of configuration directives */
1308 kerb_register_hooks /* register hooks */