5 #include "apr_strings.h"
8 #include "http_config.h"
11 #include "http_protocol.h"
12 #include "http_request.h"
18 #include <gssapi_generic.h>
19 #define GSS_C_NT_USER_NAME gss_nt_user_name
20 #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
21 #define krb5_get_err_text(context,code) error_message(code)
30 module auth_kerb_module;
32 module AP_MODULE_DECLARE_DATA auth_kerb_module;
35 /***************************************************************************
36 Macros To Ease Compatibility
37 ***************************************************************************/
40 #define MK_TABLE_GET ap_table_get
41 #define MK_TABLE_SET ap_table_set
42 #define MK_TABLE_TYPE table
43 #define MK_PSTRDUP ap_pstrdup
44 #define MK_USER r->connection->user
45 #define MK_AUTH_TYPE r->connection->ap_auth_type
46 #define MK_ARRAY_HEADER array_header
48 #define MK_POOL apr_pool_t
49 #define MK_TABLE_GET apr_table_get
50 #define MK_TABLE_SET apr_table_set
51 #define MK_TABLE_TYPE apr_table_t
52 #define MK_PSTRDUP apr_pstrdup
53 #define MK_USER r->user
54 #define MK_AUTH_TYPE r->ap_auth_type
55 #define MK_ARRAY_HEADER apr_array_header_t
59 /***************************************************************************
60 Auth Configuration Structure
61 ***************************************************************************/
63 char *krb_auth_realms;
64 char *krb_force_instance;
65 int krb_save_credentials;
69 int krb_method_gssapi;
70 int krb_method_k5pass;
74 int krb_method_k4pass;
79 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
82 #define command(name, func, var, type, usage) \
84 (void*)XtOffsetOf(kerb_auth_config, var), \
85 OR_AUTHCFG, type, usage }
87 #define command(name, func, var, type, usage) \
88 AP_INIT_ ## type (name, func, \
89 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
93 static const command_rec kerb_auth_cmds[] = {
94 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
95 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
97 command("KrbAuthRealm", krb5_save_realms, krb_auth_realms,
98 RAW_ARGS, "Alias for KrbAuthRealms."),
100 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
101 FLAG, "Save and store credentials/tickets retrieved during auth."),
103 command("KrbServiceName", ap_set_string_slot, service_name,
104 TAKE1, "Kerberos service name to be used by apache."),
107 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
108 TAKE1, "Location of Kerberos V5 keytab file."),
110 command("KrbMethodNegotiate", ap_set_flag_slot, krb_method_gssapi,
111 FLAG, "Enable Negotiate authentication method."),
113 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
114 FLAG, "Enable Kerberos V5 password authentication."),
118 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
119 TAKE1, "Location of Kerberos V4 srvtab file."),
121 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
122 FLAG, "Enable Kerberos V4 password authentication."),
130 gss_ctx_id_t context;
131 gss_cred_id_t server_creds;
134 static gss_connection_t *gss_connection = NULL;
138 /***************************************************************************
139 Auth Configuration Initialization
140 ***************************************************************************/
141 static void *kerb_dir_create_config(MK_POOL *p, char *d)
143 kerb_auth_config *rec;
145 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
147 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
148 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
151 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
157 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
159 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
163 void log_rerror(const char *file, int line, int level, int status,
164 const request_rec *r, const char *fmt, ...)
170 vsnprintf(errstr, sizeof(errstr), fmt, ap);
174 ap_log_rerror(file, line, level, r, "%s", errstr);
176 ap_log_rerror(file, line, level, status, r, "%s", errstr);
181 /***************************************************************************
182 Username/Password Validation for Krb4
183 ***************************************************************************/
185 krb4_cache_cleanup(void *data)
187 char *tkt_file = (char *) data;
189 krb_set_tkt_string(tkt_file);
195 authenticate_user_krb4pwd(request_rec *r,
196 kerb_auth_config *conf,
197 const char *auth_line)
201 const char *sent_name;
203 char *tkt_file_p = NULL;
209 sent_pw = ap_pbase64decode(r->pool, auth_line);
210 sent_name = ap_getword (r->pool, &sent_pw, ':');
212 snprintf(tkt_file, sizeof(tkt_file), "/tmp/apache_tkt_XXXXXX");
213 fd = mkstemp(tkt_file);
215 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
216 "Cannot create krb4 ccache: mkstemp() failed: %s",
218 return HTTP_INTERNAL_SERVER_ERROR;
221 tkt_file_p = ap_pstrdup(r->pool, tkt_file);
222 ap_register_cleanup(r->pool, tkt_file_p,
223 krb4_cache_cleanup, ap_null_cleanup);
225 krb_set_tkt_string(tkt_file);
227 realms = conf->krb_auth_realms;
231 realm = ap_getword_white(r->pool, &realms);
233 ret = krb_verify_user_srvtab((char *)sent_name, "", (char *)realm,
234 (char *)sent_pw, 1, "khttp",
238 } while (realms && *realms);
241 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
242 "Verifying krb4 password failed (%d)", ret);
243 ret = HTTP_UNAUTHORIZED;
247 if ((ret = krb_get_tf_realm(tkt_file, pr.realm)) ||
248 (ret = tf_init(tkt_file, R_TKT_FIL)) ||
249 (ret = tf_get_pname(pr.name)) ||
250 (ret = tf_get_pinst(pr.instance))) {
251 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
252 "Cannot read krb4 principal from tfile (%d)", ret);
253 ret = HTTP_INTERNAL_SERVER_ERROR;
257 MK_USER = ap_pstrdup (r->pool, krb_unparse_name(&pr));
258 MK_AUTH_TYPE = "Basic";
259 ap_table_setn(r->subprocess_env, "KRBTKFILE", tkt_file_p);
263 krb4_cache_cleanup(tkt_file);
272 /***************************************************************************
273 Username/Password Validation for Krb5
274 ***************************************************************************/
277 krb5_verify_user(krb5_context context, krb5_principal principal,
278 krb5_ccache ccache, const char *password, krb5_boolean secure,
282 krb5_principal server = NULL;
284 krb5_verify_init_creds_opt opt;
286 memset(&creds, 0, sizeof(creds));
288 ret = krb5_get_init_creds_password(context, &creds, principal,
289 (char *)password, krb5_prompter_posix,
290 NULL, 0, NULL, NULL);
294 ret = krb5_sname_to_principal(context, NULL, service,
295 KRB5_NT_SRV_HST, &server);
299 krb5_verify_init_creds_opt_init(&opt);
300 krb5_verify_init_creds_opt_set_ap_req_nofail(&opt, secure);
302 ret = krb5_verify_init_creds(context, &creds, server, NULL, NULL, &opt);
307 ret = krb5_cc_initialize(context, ccache, principal);
309 ret = krb5_cc_store_cred(context, ccache, &creds);
313 krb5_free_cred_contents(context, &creds);
315 krb5_free_principal(context, server);
322 krb5_cache_cleanup(void *data)
324 krb5_context context;
326 krb5_error_code problem;
327 char *cache_name = (char *) data;
329 problem = krb5_init_context(&context);
331 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
332 return HTTP_INTERNAL_SERVER_ERROR;
335 problem = krb5_cc_resolve(context, cache_name, &cache);
337 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
338 "krb5_cc_resolve() failed (%s: %s)",
339 cache_name, krb5_get_err_text(context, problem)); */
340 return HTTP_INTERNAL_SERVER_ERROR;
343 krb5_cc_destroy(context, cache);
344 krb5_free_context(context);
349 create_krb5_ccache(krb5_context kcontext,
351 kerb_auth_config *conf,
352 krb5_principal princ,
356 krb5_error_code problem;
358 krb5_ccache tmp_ccache = NULL;
361 problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
363 problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
364 /* krb5_fcc_generate_new() doesn't set KRB5_TC_OPENCLOSE, which makes
365 krb5_cc_initialize() fail */
366 krb5_fcc_set_flags(kcontext, tmp_ccache, KRB5_TC_OPENCLOSE);
369 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
370 "Cannot create file for new krb5 ccache: %s",
371 krb5_get_err_text(kcontext, problem));
372 ret = HTTP_INTERNAL_SERVER_ERROR;
376 ccname = ap_pstrdup(r->pool, krb5_cc_get_name(kcontext, tmp_ccache));
378 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
380 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
381 "Cannot initialize krb5 ccache %s: krb5_cc_initialize() failed: %s",
382 ccname, krb5_get_err_text(kcontext, problem));
383 ret = HTTP_INTERNAL_SERVER_ERROR;
387 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
388 ap_register_cleanup(r->pool, ccname,
389 krb5_cache_cleanup, ap_null_cleanup);
391 *ccache = tmp_ccache;
398 krb5_cc_destroy(kcontext, tmp_ccache);
404 store_krb5_creds(krb5_context kcontext,
406 kerb_auth_config *conf,
407 krb5_ccache delegated_cred)
410 krb5_error_code problem;
411 krb5_principal princ;
415 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
417 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
418 krb5_get_err_text(kcontext, problem));
419 return HTTP_INTERNAL_SERVER_ERROR;
422 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
424 krb5_free_principal(kcontext, princ);
429 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
431 problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
433 krb5_free_principal(kcontext, princ);
435 snprintf(errstr, sizeof(errstr), "Failed to store credentials: %s",
436 krb5_get_err_text(kcontext, problem));
437 krb5_cc_destroy(kcontext, ccache);
438 return HTTP_INTERNAL_SERVER_ERROR;
441 krb5_cc_close(kcontext, ccache);
446 int authenticate_user_krb5pwd(request_rec *r,
447 kerb_auth_config *conf,
448 const char *auth_line)
450 const char *sent_pw = NULL;
451 const char *sent_name = NULL;
452 const char *realms = NULL;
453 const char *service_name = NULL;
454 krb5_context kcontext = NULL;
455 krb5_error_code code;
456 krb5_principal client = NULL;
457 krb5_ccache ccache = NULL;
461 code = krb5_init_context(&kcontext);
463 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
464 "Cannot initialize Kerberos5 context (%d)", code);
465 return HTTP_INTERNAL_SERVER_ERROR;
468 sent_pw = ap_pbase64decode(r->pool, auth_line);
469 sent_name = ap_getword (r->pool, &sent_pw, ':');
470 /* do not allow user to override realm setting of server */
471 if (strchr(sent_name, '@')) {
472 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
473 "specifying realm in user name is prohibited");
474 ret = HTTP_UNAUTHORIZED;
479 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
481 code = krb5_mcc_generate_new(kcontext, &ccache);
484 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
485 "Cannot generate new ccache: %s",
486 krb5_get_err_text(kcontext, code));
487 ret = HTTP_INTERNAL_SERVER_ERROR;
491 if (conf->krb_5_keytab)
492 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
493 /* kcontext->default_keytab = conf->krb_5_keytab; */
495 if (conf->service_name) {
497 service_name = ap_pstrdup(r->pool, conf->service_name);
498 if ((p=strchr(service_name, '/')))
501 service_name = "khttp";
503 realms = conf->krb_auth_realms;
505 if (realms && (code = krb5_set_default_realm(kcontext,
506 ap_getword_white(r->pool, &realms))))
510 krb5_free_principal(kcontext, client);
513 code = krb5_parse_name(kcontext, sent_name, &client);
517 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
522 /* ap_getword_white() used above shifts the parameter, so it's not
523 needed to touch the realms variable */
524 } while (realms && *realms);
526 memset((char *)sent_pw, 0, strlen(sent_pw));
529 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
530 "Verifying krb5 password failed: %s",
531 krb5_get_err_text(kcontext, code));
532 ret = HTTP_UNAUTHORIZED;
536 code = krb5_unparse_name(kcontext, client, &name);
538 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
539 krb5_get_err_text(kcontext, code));
540 ret = HTTP_UNAUTHORIZED;
543 MK_USER = ap_pstrdup (r->pool, name);
544 MK_AUTH_TYPE = "Basic";
547 if (conf->krb_save_credentials)
548 store_krb5_creds(kcontext, r, conf, ccache);
554 krb5_free_principal(kcontext, client);
556 krb5_cc_destroy(kcontext, ccache);
557 krb5_free_context(kcontext);
562 /*********************************************************************
563 * GSSAPI Authentication
564 ********************************************************************/
567 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
569 OM_uint32 maj_stat, min_stat;
570 OM_uint32 msg_ctx = 0;
571 gss_buffer_desc status_string;
575 snprintf(buf, sizeof(buf), "%s", prefix);
578 maj_stat = gss_display_status (&min_stat,
584 if (sizeof(buf) > len + status_string.length + 1) {
585 sprintf(buf+len, ": %s", (char*) status_string.value);
586 len += status_string.length;
588 gss_release_buffer(&min_stat, &status_string);
589 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
591 return (ap_pstrdup(p, buf));
595 cleanup_gss_connection(void *data)
597 OM_uint32 minor_status;
598 gss_connection_t *gss_conn = (gss_connection_t *)data;
602 if (gss_conn->context != GSS_C_NO_CONTEXT)
603 gss_delete_sec_context(&minor_status, &gss_conn->context,
605 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
606 gss_release_cred(&minor_status, &gss_conn->server_creds);
608 gss_connection = NULL;
614 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
615 gss_cred_id_t delegated_cred)
617 OM_uint32 maj_stat, min_stat;
618 krb5_principal princ = NULL;
619 krb5_ccache ccache = NULL;
620 krb5_error_code problem;
621 krb5_context context;
622 int ret = HTTP_INTERNAL_SERVER_ERROR;
624 problem = krb5_init_context(&context);
626 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
627 return HTTP_INTERNAL_SERVER_ERROR;
630 problem = krb5_parse_name(context, princ_name, &princ);
632 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
633 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
637 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
639 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
640 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
644 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
645 if (GSS_ERROR(maj_stat)) {
646 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
647 "Cannot store delegated credential (%s)",
648 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
652 krb5_cc_close(context, ccache);
658 krb5_free_principal(context, princ);
660 krb5_cc_destroy(context, ccache);
661 krb5_free_context(context);
666 get_gss_creds(request_rec *r,
667 kerb_auth_config *conf,
668 gss_cred_id_t *server_creds)
670 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
671 OM_uint32 major_status, minor_status, minor_status2;
672 gss_name_t server_name = GSS_C_NO_NAME;
674 if (conf->service_name) {
675 input_token.value = conf->service_name;
676 input_token.length = strlen(conf->service_name) + 1;
679 input_token.value = "khttp";
680 input_token.length = 6;
682 major_status = gss_import_name(&minor_status, &input_token,
683 (conf->service_name) ?
684 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
686 if (GSS_ERROR(major_status)) {
687 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
688 "%s", get_gss_error(r->pool, minor_status,
689 "gss_import_name() failed"));
690 return HTTP_INTERNAL_SERVER_ERROR;
693 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
694 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
695 server_creds, NULL, NULL);
696 gss_release_name(&minor_status2, &server_name);
697 if (GSS_ERROR(major_status)) {
698 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
699 "%s", get_gss_error(r->pool, minor_status,
700 "gss_acquire_cred() failed"));
701 return HTTP_INTERNAL_SERVER_ERROR;
708 authenticate_user_gss(request_rec *r,
709 kerb_auth_config *conf,
710 const char *auth_line)
712 OM_uint32 major_status, minor_status, minor_status2;
713 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
714 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
715 const char *auth_param = NULL;
717 gss_name_t client_name = GSS_C_NO_NAME;
718 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
719 static int initial_return = HTTP_UNAUTHORIZED;
721 /* needed to work around replay caches */
722 if (!ap_is_initial_req(r))
723 return initial_return;
724 initial_return = HTTP_UNAUTHORIZED;
726 if (gss_connection == NULL) {
727 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
728 if (gss_connection == NULL) {
729 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
730 "ap_pcalloc() failed (not enough memory)");
731 ret = HTTP_INTERNAL_SERVER_ERROR;
734 memset(gss_connection, 0, sizeof(*gss_connection));
735 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
738 if (conf->krb_5_keytab)
739 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
741 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
742 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
747 /* ap_getword() shifts parameter */
748 auth_param = ap_getword_white(r->pool, &auth_line);
749 if (auth_param == NULL) {
750 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
751 "No Authorization parameter in request from client");
752 ret = HTTP_UNAUTHORIZED;
756 input_token.length = ap_base64decode_len(auth_param) + 1;
757 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
758 if (input_token.value == NULL) {
759 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
760 "ap_pcalloc() failed (not enough memory)");
761 ret = HTTP_INTERNAL_SERVER_ERROR;
764 input_token.length = ap_base64decode(input_token.value, auth_param);
766 major_status = gss_accept_sec_context(&minor_status,
767 &gss_connection->context,
768 gss_connection->server_creds,
770 GSS_C_NO_CHANNEL_BINDINGS,
777 if (output_token.length) {
781 len = ap_base64encode_len(output_token.length) + 1;
782 token = ap_pcalloc(r->connection->pool, len + 1);
784 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
785 "ap_pcalloc() failed (not enough memory)");
786 ret = HTTP_INTERNAL_SERVER_ERROR;
787 gss_release_buffer(&minor_status2, &output_token);
790 ap_base64encode(token, output_token.value, output_token.length);
792 ap_table_set(r->err_headers_out, "WWW-Authenticate",
793 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
794 gss_release_buffer(&minor_status2, &output_token);
797 if (GSS_ERROR(major_status)) {
798 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
799 "%s", get_gss_error(r->pool, minor_status,
800 "gss_accept_sec_context() failed"));
801 ret = HTTP_UNAUTHORIZED;
805 if (major_status & GSS_S_CONTINUE_NEEDED) {
806 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
807 * iterations to establish authentication */
808 ret = HTTP_UNAUTHORIZED;
812 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
813 gss_release_name(&minor_status, &client_name);
814 if (GSS_ERROR(major_status)) {
815 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
816 "%s", get_gss_error(r->pool, minor_status,
817 "gss_export_name() failed"));
818 ret = HTTP_INTERNAL_SERVER_ERROR;
822 MK_AUTH_TYPE = "Negotiate";
823 MK_USER = ap_pstrdup(r->pool, output_token.value);
825 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
826 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
828 gss_release_buffer(&minor_status, &output_token);
831 /* If the user comes from a realm specified by configuration don't include
832 its realm name in the username so that the authorization routine could
833 work for both Password-based and Ticket-based authentication. It's
834 administrators responsibility to include only such realm that have
835 unified principal instances, i.e. if the same principal name occures in
836 multiple realms, it must be always assigned to a single user.
838 p = strchr(r->connection->user, '@');
840 const char *realms = conf->gss_krb5_realms;
842 while (realms && *realms) {
843 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
855 gss_release_cred(&minor_status, &delegated_cred);
857 if (output_token.length)
858 gss_release_buffer(&minor_status, &output_token);
860 if (client_name != GSS_C_NO_NAME)
861 gss_release_name(&minor_status, &client_name);
863 cleanup_gss_connection(gss_connection);
865 initial_return = ret;
872 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
873 int use_krb4, int use_krb5)
875 const char *auth_name = NULL;
878 /* get the user realm specified in .htaccess */
879 auth_name = ap_auth_name(r);
881 /* XXX should the WWW-Authenticate header be cleared first? */
883 if (use_krb5 && conf->krb_method_gssapi)
884 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
885 if (use_krb5 && conf->krb_method_k5pass) {
886 ap_table_add(r->err_headers_out, "WWW-Authenticate",
887 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
893 if (use_krb4 && conf->krb_method_k4pass && !set_basic)
894 ap_table_add(r->err_headers_out, "WWW-Authenticate",
895 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
899 int kerb_authenticate_user(request_rec *r)
901 kerb_auth_config *conf =
902 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
904 const char *auth_type = NULL;
905 const char *auth_line = NULL;
906 const char *type = NULL;
907 int use_krb5 = 0, use_krb4 = 0;
910 /* get the type specified in .htaccess */
911 type = ap_auth_type(r);
913 if (type && strcasecmp(type, "Kerberos") == 0)
914 use_krb5 = use_krb4 = 1;
915 else if(type && strcasecmp(type, "KerberosV5") == 0)
917 else if(type && strcasecmp(type, "KerberosV4") == 0)
922 /* get what the user sent us in the HTTP header */
923 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
925 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
926 return HTTP_UNAUTHORIZED;
928 auth_type = ap_getword_white(r->pool, &auth_line);
930 ret = HTTP_UNAUTHORIZED;
933 if (use_krb5 && conf->krb_method_gssapi &&
934 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
935 ret = authenticate_user_gss(r, conf, auth_line);
936 } else if (use_krb5 && conf->krb_method_k5pass &&
937 strcasecmp(auth_type, "Basic") == 0) {
938 ret = authenticate_user_krb5pwd(r, conf, auth_line);
943 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
944 strcasecmp(auth_type, "Basic") == 0)
945 ret = authenticate_user_krb4pwd(r, conf, auth_line);
948 if (ret == HTTP_UNAUTHORIZED)
949 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
955 /***************************************************************************
956 Module Setup/Configuration
957 ***************************************************************************/
959 module MODULE_VAR_EXPORT auth_kerb_module = {
960 STANDARD_MODULE_STUFF,
961 NULL, /* module initializer */
962 kerb_dir_create_config, /* per-directory config creator */
963 NULL, /* per-directory config merger */
964 NULL, /* per-server config creator */
965 NULL, /* per-server config merger */
966 kerb_auth_cmds, /* command table */
967 NULL, /* [ 9] content handlers */
968 NULL, /* [ 2] URI-to-filename translation */
969 kerb_authenticate_user, /* [ 5] check/validate user_id */
970 NULL, /* [ 6] check user_id is valid *here* */
971 NULL, /* [ 4] check access by host address */
972 NULL, /* [ 7] MIME type checker/setter */
973 NULL, /* [ 8] fixups */
974 NULL, /* [10] logger */
975 NULL, /* [ 3] header parser */
976 NULL, /* process initialization */
977 NULL, /* process exit/cleanup */
978 NULL /* [ 1] post read_request handling */
981 void kerb_register_hooks(apr_pool_t *p)
983 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
986 module AP_MODULE_DECLARE_DATA auth_kerb_module =
988 STANDARD20_MODULE_STUFF,
989 kerb_dir_create_config, /* create per-dir conf structures */
990 NULL, /* merge per-dir conf structures */
991 NULL, /* create per-server conf structures */
992 NULL, /* merge per-server conf structures */
993 kerb_auth_cmds, /* table of configuration directives */
994 kerb_register_hooks /* register hooks */