5 #include "apr_strings.h"
8 #include "http_config.h"
11 #include "http_protocol.h"
12 #include "http_request.h"
24 module auth_kerb_module;
26 module AP_MODULE_DECLARE_DATA auth_kerb_module;
29 /***************************************************************************
30 Macros To Ease Compatibility
31 ***************************************************************************/
34 #define MK_TABLE_GET ap_table_get
35 #define MK_TABLE_SET ap_table_set
36 #define MK_TABLE_TYPE table
37 #define MK_PSTRDUP ap_pstrdup
38 #define MK_USER r->connection->user
39 #define MK_AUTH_TYPE r->connection->ap_auth_type
40 #define MK_ARRAY_HEADER array_header
42 #define MK_POOL apr_pool_t
43 #define MK_TABLE_GET apr_table_get
44 #define MK_TABLE_SET apr_table_set
45 #define MK_TABLE_TYPE apr_table_t
46 #define MK_PSTRDUP apr_pstrdup
47 #define MK_USER r->user
48 #define MK_AUTH_TYPE r->ap_auth_type
49 #define MK_ARRAY_HEADER apr_array_header_t
55 /***************************************************************************
56 Auth Configuration Structure
57 ***************************************************************************/
60 char *krb_auth_realms;
62 char *krb_force_instance;
63 int krb_save_credentials;
70 int krb_method_gssapi;
71 int krb_method_k5pass;
75 int krb_method_k4pass;
80 #define command(name, func, var, type, usage) \
82 (void*)XtOffsetOf(kerb_auth_config, var), \
83 OR_AUTHCFG, type, usage }
85 #define command(name, func, var, type, usage) \
86 AP_INIT_ ## type (name, func, \
87 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
91 static const command_rec kerb_auth_cmds[] = {
92 command("AuthKerberos", ap_set_flag_slot, krb_auth_enable,
93 FLAG, "Permit Kerberos auth without AuthType requirement."),
95 command("KrbAuthRealm", ap_set_string_slot, krb_auth_realms,
96 ITERATE, "Realms to attempt authentication against (can be multiple)."),
98 command("KrbAuthRealms", ap_set_string_slot, krb_auth_realms,
99 ITERATE, "Alias for KrbAuthRealm."),
102 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
103 TAKE1, "If auth fails, return status set here."),
106 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
107 TAKE1, "Force authentication against an instance specified here."),
109 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
110 FLAG, "Save and store credentials/tickets retrieved during auth."),
112 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
113 FLAG, "Alias for KrbSaveCredentials."),
115 command("KrbTmpdir", ap_set_string_slot, krb_tmp_dir,
116 TAKE1, "Path to store ticket files and such in."),
118 command("KrbServiceName", ap_set_string_slot, service_name,
119 TAKE1, "Kerberos service name to be used by apache."),
122 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
123 TAKE1, "Kerberos ticket lifetime."),
127 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
128 TAKE1, "Location of Kerberos V5 keytab file."),
130 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
131 FLAG, "Credentials retrieved will be flagged as forwardable."),
133 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
134 FLAG, "Enable GSSAPI authentication."),
136 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
137 FLAG, "Enable Kerberos V5 password authentication."),
141 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
142 TAKE1, "Location of Kerberos V4 srvtab file."),
144 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
145 FLAG, "Enable Kerberos V4 password authentication."),
153 gss_ctx_id_t context;
154 gss_cred_id_t server_creds;
157 static gss_connection_t *gss_connection = NULL;
161 /***************************************************************************
162 Auth Configuration Initialization
163 ***************************************************************************/
164 static void *kerb_dir_create_config(MK_POOL *p, char *d)
166 kerb_auth_config *rec;
168 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
169 ((kerb_auth_config *)rec)->krb_auth_enable = 1;
170 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
172 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
173 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
176 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
181 void log_rerror(const char *file, int line, int level, int status,
182 const request_rec *r, const char *fmt, ...)
188 vsnprintf(errstr, sizeof(errstr), fmt, ap);
192 ap_log_rerror(file, line, level, r, "%s", errstr);
194 ap_log_rerror(file, line, level, status, r, "%s", errstr);
199 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
202 int offset = (int) (long) cmd->info;
203 if (!strncasecmp(arg, "unauthorized", 12))
204 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
205 else if (!strncasecmp(arg, "forbidden", 9))
206 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
207 else if (!strncasecmp(arg, "declined", 8))
208 *(int *) ((char *)struct_ptr + offset) = DECLINED;
210 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
216 /***************************************************************************
217 Username/Password Validation for Krb4
218 ***************************************************************************/
219 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
221 kerb_auth_config *conf =
222 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
225 int lifetime = DEFAULT_TKT_LIFE;
227 char *username = NULL;
228 char *instance = NULL;
231 username = (char *)ap_pstrdup(r->pool, user);
236 instance = strchr(username, '.');
244 realm = strchr(username, '@');
252 if (conf->krb_lifetime) {
253 lifetime = atoi(conf->krb_lifetime);
256 if (conf->krb_force_instance) {
257 instance = conf->krb_force_instance;
260 if (conf->krb_save_credentials) {
261 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
262 sprintf(tfname, "%s/k5cc_ap_%s",
263 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
266 if (!strcmp(instance, "")) {
267 tfname = strcat(tfname, ".");
268 tfname = strcat(tfname, instance);
271 if (!strcmp(realm, "")) {
272 tfname = strcat(tfname, ".");
273 tfname = strcat(tfname, realm);
276 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
277 "/tmp") + 1; *c; c++) {
282 krb_set_tkt_string(tfname);
285 if (!strcmp(realm, "")) {
286 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
287 ret = krb_get_lrealm(realm, 1);
292 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
293 lifetime, (char *)pass);
308 /***************************************************************************
309 Username/Password Validation for Krb5
310 ***************************************************************************/
313 krb5_verify_user(krb5_context context, krb5_principal principal,
314 krb5_ccache ccache, const char *password, krb5_boolean secure,
318 krb5_context kcontext;
319 krb5_principal server, client;
322 krb5_flags options = 0;
323 krb5_principal me = NULL;
324 krb5_data tgtname = {
330 memset((char *)&my_creds, 0, sizeof(my_creds));
331 my_creds.client = principal;
333 if (krb5_build_principal_ext(kcontext, &server,
334 krb5_princ_realm(kcontext, me)->length,
335 krb5_princ_realm(kcontext, me)->data,
336 tgtname.length, tgtname.data,
337 krb5_princ_realm(kcontext, me)->length,
338 krb5_princ_realm(kcontext, me)->data,
343 my_creds.server = server;
344 if (krb5_timeofday(kcontext, &now))
347 my_creds.times.starttime = 0;
349 my_creds.times.endtime = now + lifetime;
350 my_creds.times.renew_till = now + renewal;
353 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
354 password, ccache, &my_creds, 0);
365 krb5_cache_cleanup(void *data)
367 krb5_context context;
369 krb5_error_code problem;
370 char *cache_name = (char *) data;
372 problem = krb5_init_context(&context);
374 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
375 return HTTP_INTERNAL_SERVER_ERROR;
378 problem = krb5_cc_resolve(context, cache_name, &cache);
380 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
381 "krb5_cc_resolve() failed (%s: %s)",
382 cache_name, krb5_get_err_text(context, problem)); */
383 return HTTP_INTERNAL_SERVER_ERROR;
386 krb5_cc_destroy(context, cache);
387 krb5_free_context(context);
392 create_krb5_ccache(krb5_context kcontext,
394 kerb_auth_config *conf,
395 krb5_principal princ,
398 char *c, ccname[MAX_STRING_LEN];
399 krb5_error_code problem;
401 krb5_ccache tmp_ccache = NULL;
403 snprintf(ccname, sizeof(ccname), "FILE:%s/k5cc_ap_%s",
404 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
407 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
408 "/tmp") + 1; *c; c++) {
413 problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
415 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
416 "Cannot create krb5 ccache: krb5_cc_resolve() failed: %s",
417 krb5_get_err_text(kcontext, problem));
418 ret = HTTP_INTERNAL_SERVER_ERROR;
422 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
424 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
425 "Cannot create krb5 ccache: krb5_cc_initialize() failed: %s",
426 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);
472 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
473 krb5_free_principal(kcontext, princ);
475 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
476 krb5_get_err_text(kcontext, problem));
477 krb5_cc_destroy(kcontext, ccache);
478 return HTTP_INTERNAL_SERVER_ERROR;
481 krb5_cc_close(kcontext, ccache);
486 int authenticate_user_krb5pwd(request_rec *r,
487 kerb_auth_config *conf,
488 const char *auth_line)
490 const char *sent_pw = NULL;
491 const char *realms = NULL;
492 krb5_context kcontext;
493 krb5_error_code code;
494 krb5_principal client = NULL;
495 krb5_ccache ccache = NULL;
498 code = krb5_init_context(&kcontext);
500 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
501 "Cannot initialize Kerberos5 context (%d)", code);
502 return HTTP_INTERNAL_SERVER_ERROR;
505 sent_pw = ap_pbase64decode(r->pool, auth_line);
506 MK_USER = ap_getword (r->pool, &sent_pw, ':');
507 MK_AUTH_TYPE = "Basic";
509 /* do not allow user to override realm setting of server */
510 if (strchr(MK_USER, '@')) {
511 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
512 "specifying realm in user name is prohibited");
513 ret = HTTP_UNAUTHORIZED;
518 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
520 code = krb5_mcc_generate_new(kcontext, &ccache);
523 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
524 "Cannot generate new ccache: %s",
525 krb5_get_err_text(kcontext, code));
526 ret = HTTP_INTERNAL_SERVER_ERROR;
530 if (conf->krb_5_keytab)
531 /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
532 kcontext->default_keytab = conf->krb_5_keytab;
534 realms = conf->krb_auth_realms;
536 if (realms && (code = krb5_set_default_realm(kcontext,
537 ap_getword_white(r->pool, &realms))))
540 code = krb5_parse_name(kcontext, MK_USER, &client);
544 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
545 (conf->service_name) ? conf->service_name : "khttp");
546 krb5_free_principal(kcontext, client);
550 /* ap_getword_white() used above shifts the parameter, so it's not
551 needed to touch the realms variable */
552 } while (realms && *realms);
554 memset((char *)sent_pw, 0, strlen(sent_pw));
557 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
558 "Verifying krb5 password failed: %s",
559 krb5_get_err_text(kcontext, code));
560 ret = HTTP_UNAUTHORIZED;
564 if (conf->krb_save_credentials) {
565 ret = store_krb5_creds(kcontext, r, conf, ccache);
566 if (ret) /* Ignore error ?? */
574 krb5_free_principal(kcontext, client);
576 krb5_cc_destroy(kcontext, ccache);
577 krb5_free_context(kcontext);
582 /*********************************************************************
583 * GSSAPI Authentication
584 ********************************************************************/
587 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
589 OM_uint32 maj_stat, min_stat;
590 OM_uint32 msg_ctx = 0;
591 gss_buffer_desc status_string;
595 snprintf(buf, sizeof(buf), "%s", prefix);
598 maj_stat = gss_display_status (&min_stat,
604 if (sizeof(buf) > len + status_string.length + 1) {
605 sprintf(buf+len, ": %s", (char*) status_string.value);
606 len += status_string.length;
608 gss_release_buffer(&min_stat, &status_string);
609 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
611 return (ap_pstrdup(p, buf));
615 cleanup_gss_connection(void *data)
617 OM_uint32 minor_status;
618 gss_connection_t *gss_conn = (gss_connection_t *)data;
622 if (gss_conn->context != GSS_C_NO_CONTEXT)
623 gss_delete_sec_context(&minor_status, &gss_conn->context,
625 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
626 gss_release_cred(&minor_status, &gss_conn->server_creds);
632 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
633 gss_cred_id_t delegated_cred)
635 OM_uint32 maj_stat, min_stat;
636 krb5_principal princ = NULL;
637 krb5_ccache ccache = NULL;
638 krb5_error_code problem;
639 krb5_context context;
640 int ret = HTTP_INTERNAL_SERVER_ERROR;
642 problem = krb5_init_context(&context);
644 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
645 return HTTP_INTERNAL_SERVER_ERROR;
648 problem = krb5_parse_name(context, princ_name, &princ);
650 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
651 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
655 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
657 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
658 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
662 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
663 if (GSS_ERROR(maj_stat)) {
664 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
665 "Cannot store delegated credential (%s)",
666 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
670 krb5_cc_close(context, ccache);
676 krb5_free_principal(context, princ);
678 krb5_cc_destroy(context, ccache);
679 krb5_free_context(context);
684 get_gss_creds(request_rec *r,
685 kerb_auth_config *conf,
686 gss_cred_id_t *server_creds)
688 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
689 OM_uint32 major_status, minor_status, minor_status2;
690 gss_name_t server_name = GSS_C_NO_NAME;
692 if (conf->service_name) {
693 input_token.value = conf->service_name;
694 input_token.length = strlen(conf->service_name) + 1;
697 input_token.value = "khttp";
698 input_token.length = 6;
700 major_status = gss_import_name(&minor_status, &input_token,
701 (conf->service_name) ?
702 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
704 if (GSS_ERROR(major_status)) {
705 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
706 "%s", get_gss_error(r->pool, minor_status,
707 "gss_import_name() failed"));
708 return HTTP_INTERNAL_SERVER_ERROR;
711 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
712 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
713 server_creds, NULL, NULL);
714 gss_release_name(&minor_status2, &server_name);
715 if (GSS_ERROR(major_status)) {
716 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
717 "%s", get_gss_error(r->pool, minor_status,
718 "gss_acquire_cred() failed"));
719 return HTTP_INTERNAL_SERVER_ERROR;
726 authenticate_user_gss(request_rec *r,
727 kerb_auth_config *conf,
728 const char *auth_line)
730 OM_uint32 major_status, minor_status, minor_status2;
731 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
732 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
733 const char *auth_param = NULL;
735 gss_name_t client_name = GSS_C_NO_NAME;
736 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
738 if (gss_connection == NULL) {
739 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
740 if (gss_connection == NULL) {
741 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
742 "ap_pcalloc() failed (not enough memory)");
743 ret = HTTP_INTERNAL_SERVER_ERROR;
746 memset(gss_connection, 0, sizeof(*gss_connection));
747 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
750 if (conf->krb_5_keytab)
751 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
753 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
754 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
759 /* ap_getword() shifts parameter */
760 auth_param = ap_getword_white(r->pool, &auth_line);
761 if (auth_param == NULL) {
762 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
763 "No Authorization parameter in request from client");
764 ret = HTTP_UNAUTHORIZED;
768 input_token.length = ap_base64decode_len(auth_param) + 1;
769 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
770 if (input_token.value == NULL) {
771 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
772 "ap_pcalloc() failed (not enough memory)");
773 ret = HTTP_INTERNAL_SERVER_ERROR;
776 input_token.length = ap_base64decode(input_token.value, auth_param);
778 major_status = gss_accept_sec_context(&minor_status,
779 &gss_connection->context,
780 gss_connection->server_creds,
782 GSS_C_NO_CHANNEL_BINDINGS,
789 if (output_token.length) {
793 len = ap_base64encode_len(output_token.length) + 1;
794 token = ap_pcalloc(r->connection->pool, len + 1);
796 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
797 "ap_pcalloc() failed (not enough memory)");
798 ret = HTTP_INTERNAL_SERVER_ERROR;
799 gss_release_buffer(&minor_status2, &output_token);
802 ap_base64encode(token, output_token.value, output_token.length);
804 ap_table_set(r->err_headers_out, "WWW-Authenticate",
805 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
806 gss_release_buffer(&minor_status2, &output_token);
809 if (GSS_ERROR(major_status)) {
810 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
811 "%s", get_gss_error(r->pool, minor_status,
812 "gss_accept_sec_context() failed"));
813 ret = HTTP_UNAUTHORIZED;
817 if (major_status & GSS_S_CONTINUE_NEEDED) {
818 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
819 * iterations to establish authentication */
820 ret = HTTP_UNAUTHORIZED;
824 major_status = gss_export_name(&minor_status, client_name, &output_token);
825 gss_release_name(&minor_status, &client_name);
826 if (GSS_ERROR(major_status)) {
827 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
828 "%s", get_gss_error(r->pool, minor_status,
829 "gss_export_name() failed"));
830 ret = HTTP_INTERNAL_SERVER_ERROR;
834 MK_AUTH_TYPE = "Negotiate";
835 MK_USER = ap_pstrdup(r->pool, output_token.value);
837 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
838 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
840 gss_release_buffer(&minor_status, &output_token);
844 /* If the user comes from a realm specified by configuration don't include
845 its realm name in the username so that the authorization routine could
846 work for both Password-based and Ticket-based authentication. It's
847 administrators responsibility to include only such realm that have
848 unified principal instances, i.e. if the same principal name occures in
849 multiple realms, it must be always assigned to a single user.
851 p = strchr(r->connection->user, '@');
853 const char *realms = conf->gss_krb5_realms;
855 while (realms && *realms) {
856 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
868 gss_release_cred(&minor_status, &delegated_cred);
870 if (output_token.length)
871 gss_release_buffer(&minor_status, &output_token);
873 if (client_name != GSS_C_NO_NAME)
874 gss_release_name(&minor_status, &client_name);
882 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
884 const char *auth_name = NULL;
886 /* get the user realm specified in .htaccess */
887 auth_name = ap_auth_name(r);
889 /* XXX should the WWW-Authenticate header be cleared first? */
891 if (conf->krb_method_gssapi)
892 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
893 if (conf->krb_method_k5pass)
894 ap_table_add(r->err_headers_out, "WWW-Authenticate",
895 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
899 if (conf->krb_method_k4pass)
900 ap_table_add(r->err_headers_out, "WWW-Authenticate",
901 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
905 int kerb_authenticate_user(request_rec *r)
907 kerb_auth_config *conf =
908 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
910 const char *auth_type = NULL;
911 const char *auth_line = NULL;
912 const char *type = NULL;
915 /* get the type specified in .htaccess */
916 type = ap_auth_type(r);
919 if (type != NULL && strcasecmp(type, "KerberosV5") == 0) {
920 log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
921 "The use of KerberosV5 in AuthType is obsolete, please consider using the AuthKerberos option");
922 conf->krb_auth_enable = 1;
927 if (type != NULL && strcasecmp(type, "KerberosV4") == 0) {
928 log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
929 "The use of KerberosV4 in AuthType is obsolete, please consider using the AuthKerberos option");
930 conf->krb_auth_enable = 1;
934 if (!conf->krb_auth_enable)
937 /* get what the user sent us in the HTTP header */
938 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
940 note_kerb_auth_failure(r, conf);
941 return HTTP_UNAUTHORIZED;
943 auth_type = ap_getword_white(r->pool, &auth_line);
945 ret = HTTP_UNAUTHORIZED;
948 if (conf->krb_method_gssapi &&
949 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
950 ret = authenticate_user_gss(r, conf, auth_line);
951 } else if (conf->krb_method_k5pass &&
952 strcasecmp(auth_type, "Basic") == 0) {
953 ret = authenticate_user_krb5pwd(r, conf, auth_line);
958 if (ret == HTTP_UNAUTHORIZED && conf->krb_method_k4pass &&
959 strcasecmp(auth_type, "Basic") == 0)
960 ret = authenticate_user_krb4pwd(r, conf, auth_line);
963 if (ret == HTTP_UNAUTHORIZED)
964 note_kerb_auth_failure(r, conf);
970 /***************************************************************************
971 Module Setup/Configuration
972 ***************************************************************************/
974 module MODULE_VAR_EXPORT auth_kerb_module = {
975 STANDARD_MODULE_STUFF,
976 NULL, /* module initializer */
977 kerb_dir_create_config, /* per-directory config creator */
978 NULL, /* per-directory config merger */
979 NULL, /* per-server config creator */
980 NULL, /* per-server config merger */
981 kerb_auth_cmds, /* command table */
982 NULL, /* [ 9] content handlers */
983 NULL, /* [ 2] URI-to-filename translation */
984 kerb_authenticate_user, /* [ 5] check/validate user_id */
985 NULL, /* [ 6] check user_id is valid *here* */
986 NULL, /* [ 4] check access by host address */
987 NULL, /* [ 7] MIME type checker/setter */
988 NULL, /* [ 8] fixups */
989 NULL, /* [10] logger */
990 NULL, /* [ 3] header parser */
991 NULL, /* process initialization */
992 NULL, /* process exit/cleanup */
993 NULL /* [ 1] post read_request handling */
996 void kerb_register_hooks(apr_pool_t *p)
998 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1001 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1003 STANDARD20_MODULE_STUFF,
1004 kerb_dir_create_config, /* create per-dir conf structures */
1005 NULL, /* merge per-dir conf structures */
1006 NULL, /* create per-server conf structures */
1007 NULL, /* merge per-server conf structures */
1008 kerb_auth_cmds, /* table of configuration directives */
1009 kerb_register_hooks /* register hooks */