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 create_krb5_ccache(krb5_context kcontext,
590 kerb_auth_config *conf,
591 krb5_principal princ,
594 char *c, ccname[MAX_STRING_LEN];
595 krb5_error_code problem;
598 krb5_ccache tmp_ccache = NULL;
600 snprintf(ccname, sizeof(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++) {
611 /* not sure what's the purpose of this call here */
612 problem = krb5_cc_set_default_name(kcontext, ccname);
614 snprintf(errstr, sizeof(errstr),
615 "krb5_cc_set_default_name() failed: %s",
616 krb5_get_err_text(kcontext, problem));
617 ap_log_reason (errstr, r->uri, r);
625 /* XXX Dan: Why is this done? Cleanup? But the file would not be
626 * accessible from another processes (CGI) */
627 unlink(ccname+strlen("FILE:"));
630 problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
632 snprintf(errstr, sizeof(errstr),
633 "krb5_cc_resolve() failed: %s",
634 krb5_get_err_text(kcontext, problem));
635 ap_log_reason (errstr, r->uri, r);
640 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
642 snprintf(errstr, sizeof(errstr),
643 "krb5_cc_initialize() failed: %s",
644 krb5_get_err_text(kcontext, problem));
645 ap_log_reason (errstr, r->uri, r);
650 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
651 ap_register_cleanup(r->pool, ccname,
652 krb5_cache_cleanup, ap_null_cleanup);
654 *ccache = tmp_ccache;
661 krb5_cc_destroy(kcontext, tmp_ccache);
663 return ret; /* XXX */
667 store_krb5_creds(krb5_context kcontext,
669 kerb_auth_config *conf,
670 krb5_ccache delegated_cred)
673 krb5_error_code problem;
674 krb5_principal princ;
678 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
680 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
681 krb5_get_err_text(kcontext, problem));
685 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
687 krb5_free_principal(kcontext, princ);
691 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
692 krb5_free_principal(kcontext, princ);
694 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
695 krb5_get_err_text(kcontext, problem));
696 krb5_cc_destroy(kcontext, ccache);
700 krb5_cc_close(kcontext, ccache);
704 int kerb5_password_validate(request_rec *r, const char *user, const char *pass)
707 kerb_auth_config *conf =
708 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
711 krb5_context kcontext;
712 krb5_principal client;
713 krb5_ccache ccache = NULL;
714 krb5_deltat lifetime = 300; /* 5 minutes */
715 krb5_deltat renewal = 0;
716 krb5_flags options = 0;
718 krb5_error_code code;
721 if (krb5_init_context(&kcontext)) {
722 snprintf(errstr, sizeof(errstr),
723 "Cannot initialize Kerberos5 context");
724 ap_log_reason (errstr, r->uri, r);
729 if (conf->krb_forwardable) {
730 options |= KDC_OPT_FORWARDABLE;
733 if (conf->krb_renewable) {
734 options |= KDC_OPT_RENEWABLE;
735 renewal = 86400; /* 24 hours */
738 if (conf->krb_lifetime) {
739 lifetime = atoi(conf->krb_lifetime);
743 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
745 code = krb5_mcc_generate_new(kcontext, &ccache);
748 snprintf(errstr, sizeof(errstr), "Cannot generate new ccache: %.100s",
749 krb5_get_err_text(kcontext, code));
750 ap_log_reason (errstr, r->uri, r);
755 realms = conf->krb_auth_realms;
759 code = krb5_set_default_realm(kcontext,
760 ap_getword_white(r->pool, &realms));
765 code = krb5_parse_name(kcontext, r->connection->user, &client);
769 code = krb5_verify_user(kcontext, client, ccache, pass,
771 krb5_free_principal(kcontext, client);
775 /* ap_getword_white() used above shifts the parameter, so it's not
776 needed to touch the realms variable */
777 } while (realms && *realms);
779 memset((char *)pass, 0, strlen(pass));
782 snprintf(errstr, sizeof(errstr), "Verifying krb5 password failed: %s",
783 krb5_get_err_text(kcontext, code));
784 ap_log_reason (errstr, r->uri, r);
785 ret = HTTP_UNAUTHORIZED;
789 if (conf->krb_save_credentials) {
790 ret = store_krb5_creds(kcontext, r, conf, ccache);
795 ret = 1; /* XXX should be OK ? */
799 krb5_cc_destroy(kcontext, ccache);
800 krb5_free_context(kcontext);
802 return (ret != 1) ? 0 : 1; /* XXX */
807 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
809 kerb_auth_config *conf =
810 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
813 int lifetime = DEFAULT_TKT_LIFE;
815 char *username = NULL;
816 char *instance = NULL;
819 username = (char *)ap_pstrdup(r->pool, user);
824 instance = strchr(username, '.');
832 realm = strchr(username, '@');
840 if (conf->krb_lifetime) {
841 lifetime = atoi(conf->krb_lifetime);
844 if (conf->krb_force_instance) {
845 instance = conf->krb_force_instance;
848 if (conf->krb_save_credentials) {
849 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
850 sprintf(tfname, "%s/k5cc_ap_%s",
851 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
854 if (!strcmp(instance, "")) {
855 tfname = strcat(tfname, ".");
856 tfname = strcat(tfname, instance);
859 if (!strcmp(realm, "")) {
860 tfname = strcat(tfname, ".");
861 tfname = strcat(tfname, realm);
864 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
865 "/tmp") + 1; *c; c++) {
870 krb_set_tkt_string(tfname);
873 if (!strcmp(realm, "")) {
874 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
875 ret = krb_get_lrealm(realm, 1);
880 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
881 lifetime, (char *)pass);
898 /***************************************************************************
900 ***************************************************************************/
903 get_gss_error(pool *p, OM_uint32 error_status, char *prefix)
905 OM_uint32 maj_stat, min_stat;
906 OM_uint32 msg_ctx = 0;
907 gss_buffer_desc status_string;
911 snprintf(buf, sizeof(buf), "%s: ", prefix);
914 maj_stat = gss_display_status (&min_stat,
920 if (sizeof(buf) > len + status_string.length + 1) {
921 sprintf(buf+len, "%s:", (char*) status_string.value);
922 len += status_string.length;
924 gss_release_buffer(&min_stat, &status_string);
925 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
927 return (ap_pstrdup(p, buf));
931 get_gss_creds(request_rec *r,
932 kerb_auth_config *conf,
933 gss_cred_id_t *server_creds)
936 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
937 OM_uint32 major_status, minor_status;
938 gss_name_t server_name = GSS_C_NO_NAME;
940 if (conf->service_name) {
941 input_token.value = conf->service_name;
942 input_token.length = strlen(conf->service_name) + 1;
945 input_token.value = "khttp";
946 input_token.length = 6;
948 major_status = gss_import_name(&minor_status, &input_token,
949 (conf->service_name) ?
950 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
952 if (GSS_ERROR(major_status)) {
953 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
954 "%s", get_gss_error(r->pool, minor_status,
955 "gss_import_name() failed"));
961 if (conf->krb_5_keytab)
962 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
965 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
966 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
967 server_creds, NULL, NULL);
969 if (conf->krb_5_keytab)
970 unsetenv("KRB5_KTNAME");
972 if (GSS_ERROR(major_status)) {
973 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
974 "%s", get_gss_error(r->pool, minor_status,
975 "gss_acquire_cred() failed"));
989 negotiate_authenticate_user(request_rec *r,
990 kerb_auth_config *conf,
991 const char *auth_line)
993 OM_uint32 major_status, minor_status, minor_status2;
994 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
995 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
996 const char *auth_param = NULL;
998 gss_name_t client_name = GSS_C_NO_NAME;
999 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
1001 if (gss_connection == NULL) {
1002 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
1003 if (gss_connection == NULL) {
1004 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1005 "ap_pcalloc() failed (not enough memory)");
1009 memset(gss_connection, 0, sizeof(*gss_connection));
1010 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
1013 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
1014 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
1019 /* ap_getword() shifts parameter */
1020 auth_param = ap_getword_white(r->pool, &auth_line);
1021 if (auth_param == NULL) {
1022 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1023 "No Authorization parameter in request from client");
1024 ret = HTTP_UNAUTHORIZED;
1028 input_token.length = ap_base64decode_len(auth_param);
1029 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
1030 if (input_token.value == NULL) {
1031 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1032 "ap_pcalloc() failed (not enough memory)");
1036 input_token.length = ap_base64decode(input_token.value, auth_param);
1038 major_status = gss_accept_sec_context(&minor_status,
1039 &gss_connection->context,
1040 gss_connection->server_creds,
1042 GSS_C_NO_CHANNEL_BINDINGS,
1049 if (output_token.length) {
1053 len = ap_base64encode_len(output_token.length);
1054 token = ap_pcalloc(r->connection->pool, len + 1);
1055 if (token == NULL) {
1056 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1057 "ap_pcalloc() failed (not enough memory)");
1059 gss_release_buffer(&minor_status2, &output_token);
1062 ap_base64encode(token, output_token.value, output_token.length);
1064 ap_table_set(r->err_headers_out, "WWW-Authenticate",
1065 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
1066 gss_release_buffer(&minor_status2, &output_token);
1069 if (GSS_ERROR(major_status)) {
1070 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1071 "%s", get_gss_error(r->pool, minor_status,
1072 "gss_accept_sec_context() failed"));
1073 ret = HTTP_UNAUTHORIZED;
1077 if (major_status & GSS_S_CONTINUE_NEEDED) {
1078 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
1079 * iterations to establish authentication */
1080 ret = HTTP_UNAUTHORIZED;
1084 major_status = gss_export_name(&minor_status, client_name, &output_token);
1085 gss_release_name(&minor_status, &client_name);
1086 if (GSS_ERROR(major_status)) {
1087 ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
1088 "%s", get_gss_error(r->pool, minor_status,
1089 "gss_export_name() failed"));
1094 r->connection->ap_auth_type = "Negotiate";
1095 r->connection->user = ap_pstrdup(r->pool, output_token.value);
1097 /* If the user comes from a realm specified by configuration don't include
1098 its realm name in the username so that the authorization routine could
1099 work for both Password-based and Ticket-based authentication. It's
1100 administrators responsibility to include only such realm that have
1101 unified principal instances, i.e. if the same principal name occures in
1102 multiple realms, it must be always assigned to a single user.
1104 p = strchr(r->connection->user, '@');
1106 const char *realms = conf->gss_krb5_realms;
1108 while (realms && *realms) {
1109 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
1117 gss_release_buffer(&minor_status, &output_token);
1120 /* This should be only done if afs token are requested or gss_save creds is
1122 /* gss_export_cred() from the GGF GSS Extensions could be used */
1123 if (delegated_cred != GSS_C_NO_CREDENTIAL &&
1124 (conf->gss_save_creds || (conf->gss_krb5_cells && k_hasafs()))) {
1125 krb5_init_context(&krb_ctx);
1126 do_afs_log(krb_ctx, r, delegated_cred->ccache, conf->gss_krb5_cells);
1127 ret = store_krb5_creds(krb_ctx, r, conf, delegated_cred->ccache);
1128 krb5_free_context(krb_ctx);
1137 gss_release_cred(&minor_status, &delegated_cred);
1139 if (output_token.length)
1140 gss_release_buffer(&minor_status, &output_token);
1142 if (client_name != GSS_C_NO_NAME)
1143 gss_release_name(&minor_status, &client_name);
1152 /***************************************************************************
1154 ***************************************************************************/
1155 int kerb_authenticate_user(request_rec *r)
1157 const char *name; /* AuthName specified */
1158 const char *type; /* AuthType specified */
1159 const char *sent_pw; /* Password sent by browser */
1160 int res; /* Response holder */
1161 int retcode; /* Return code holder */
1162 const char *t; /* Decoded auth_line */
1163 const char *authtype; /* AuthType to send back to browser */
1164 const char *auth_line = MK_TABLE_GET(r->headers_in,
1165 (r->proxyreq == MK_PROXY)
1166 ? "Proxy-Authorization"
1168 kerb_auth_config *conf =
1169 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1172 type = ap_auth_type(r);
1174 if (!conf->krb_auth_enable &&
1175 (type == NULL || (strncasecmp(type, "Kerberos", 8) != 0))) {
1176 if (conf->krb_authoritative) {
1177 return HTTP_UNAUTHORIZED;
1184 name = ap_auth_name(r);
1186 return HTTP_INTERNAL_SERVER_ERROR;
1190 MK_TABLE_SET(r->err_headers_out, "WWW-Authenticate",
1191 (char *)ap_pstrcat(r->pool,
1192 "Basic realm=\"", name, "\"", NULL));
1193 return HTTP_UNAUTHORIZED;
1196 type = ap_getword_white(r->pool, &auth_line);
1197 t = ap_pbase64decode(r->pool, auth_line);
1198 MK_USER = ap_getword_nulls(r->pool, &t, ':');
1199 MK_AUTH_TYPE = "Kerberos";
1200 sent_pw = ap_getword_white(r->pool, &t);
1205 if (conf->krb_method_gssapi && retcode != OK) {
1206 MK_AUTH_TYPE = "Negotiate";
1207 if (negotiate_authenticate_user(r, conf, auth_line))
1210 retcode = conf->krb_fail_status;
1215 if (conf->krb_method_k5pass && retcode != OK) {
1216 MK_AUTH_TYPE = "KerberosV5";
1217 if (kerb5_password_validate(r, MK_USER, sent_pw)) {
1221 retcode = conf->krb_fail_status;
1222 /* XXX should SERVER_ERROR be overriden too? */
1228 if (conf->krb_method_k4pass && retcode != OK) {
1229 MK_AUTH_TYPE = "KerberosV4";
1230 if (kerb4_password_validate(r, MK_USER, sent_pw)) {
1234 retcode = conf->krb_fail_status;
1239 if (conf->krb_authoritative && retcode == DECLINED) {
1240 return HTTP_UNAUTHORIZED;
1250 /***************************************************************************
1252 ***************************************************************************/
1253 int kerb_check_user_access(request_rec *r)
1257 const MK_ARRAY_HEADER *reqs_arr = ap_requires(r);
1259 kerb_auth_config *conf =
1260 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
1263 if (reqs_arr == NULL) {
1266 reqs = (require_line *)reqs_arr->elts;
1268 for (x = 0; x < reqs_arr->nelts; x++) {
1269 t = reqs[x].requirement;
1270 w = ap_getword_white(r->pool, &t);
1271 if (strcmp(w, "realm") == 0) {
1272 while (t[0] != '\0') {
1273 w = ap_getword_conf(r->pool, &t);
1274 if (strcmp(MK_USER, w) == 0) {
1287 /***************************************************************************
1288 Module Setup/Configuration
1289 ***************************************************************************/
1291 module MODULE_VAR_EXPORT kerb_auth_module = {
1292 STANDARD_MODULE_STUFF,
1293 NULL, /* module initializer */
1294 kerb_dir_config, /* per-directory config creator */
1295 NULL, /* per-directory config merger */
1296 NULL, /* per-server config creator */
1297 NULL, /* per-server config merger */
1298 kerb_auth_cmds, /* command table */
1299 NULL, /* [ 9] content handlers */
1300 NULL, /* [ 2] URI-to-filename translation */
1301 kerb_authenticate_user, /* [ 5] check/validate user_id */
1302 kerb_check_user_access, /* [ 6] check user_id is valid *here* */
1303 NULL, /* [ 4] check access by host address */
1304 NULL, /* [ 7] MIME type checker/setter */
1305 NULL, /* [ 8] fixups */
1306 NULL, /* [10] logger */
1307 NULL, /* [ 3] header parser */
1308 NULL, /* process initialization */
1309 NULL, /* process exit/cleanup */
1310 NULL /* [ 1] post read_request handling */
1312 , /* EAPI Additions */
1313 NULL, /* EAPI add module */
1314 NULL, /* EAPI remove module */
1315 NULL, /* EAPI rewrite command */
1316 NULL /* EAPI new connection */
1321 void kerb_register_hooks(apr_pool_t *p)
1323 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1324 ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE);
1327 module AP_MODULE_DECLARE_DATA kerb_auth_module =
1329 STANDARD20_MODULE_STUFF,
1330 kerb_dir_config, /* create per-dir conf structures */
1331 NULL, /* merge per-dir conf structures */
1332 NULL, /* create per-server conf structures */
1333 NULL, /* merge per-server conf structures */
1334 kerb_auth_cmds, /* table of configuration directives */
1335 kerb_register_hooks /* register hooks */