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 ***************************************************************************/
184 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
186 kerb_auth_config *conf =
187 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
190 int lifetime = DEFAULT_TKT_LIFE;
192 char *username = NULL;
193 char *instance = NULL;
196 username = (char *)ap_pstrdup(r->pool, user);
201 instance = strchr(username, '.');
209 realm = strchr(username, '@');
217 if (conf->krb_lifetime) {
218 lifetime = atoi(conf->krb_lifetime);
221 if (conf->krb_force_instance) {
222 instance = conf->krb_force_instance;
225 if (conf->krb_save_credentials) {
226 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
227 sprintf(tfname, "/tmp/k5cc_ap_%s", MK_USER);
229 if (!strcmp(instance, "")) {
230 tfname = strcat(tfname, ".");
231 tfname = strcat(tfname, instance);
234 if (!strcmp(realm, "")) {
235 tfname = strcat(tfname, ".");
236 tfname = strcat(tfname, realm);
239 for (c = tfname + strlen("/tmp") + 1; *c; c++) {
244 krb_set_tkt_string(tfname);
247 if (!strcmp(realm, "")) {
248 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
249 ret = krb_get_lrealm(realm, 1);
254 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
255 lifetime, (char *)pass);
270 /***************************************************************************
271 Username/Password Validation for Krb5
272 ***************************************************************************/
275 krb5_verify_user(krb5_context context, krb5_principal principal,
276 krb5_ccache ccache, const char *password, krb5_boolean secure,
280 krb5_principal server = NULL;
282 krb5_verify_init_creds_opt opt;
284 memset(&creds, 0, sizeof(creds));
286 ret = krb5_get_init_creds_password(context, &creds, principal,
287 (char *)password, krb5_prompter_posix,
288 NULL, 0, NULL, NULL);
292 ret = krb5_sname_to_principal(context, NULL, service,
293 KRB5_NT_SRV_HST, &server);
297 krb5_verify_init_creds_opt_init(&opt);
298 krb5_verify_init_creds_opt_set_ap_req_nofail(&opt, secure);
300 ret = krb5_verify_init_creds(context, &creds, server, NULL, NULL, &opt);
305 ret = krb5_cc_initialize(context, ccache, principal);
307 ret = krb5_cc_store_cred(context, ccache, &creds);
311 krb5_free_cred_contents(context, &creds);
313 krb5_free_principal(context, server);
320 krb5_cache_cleanup(void *data)
322 krb5_context context;
324 krb5_error_code problem;
325 char *cache_name = (char *) data;
327 problem = krb5_init_context(&context);
329 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
330 return HTTP_INTERNAL_SERVER_ERROR;
333 problem = krb5_cc_resolve(context, cache_name, &cache);
335 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
336 "krb5_cc_resolve() failed (%s: %s)",
337 cache_name, krb5_get_err_text(context, problem)); */
338 return HTTP_INTERNAL_SERVER_ERROR;
341 krb5_cc_destroy(context, cache);
342 krb5_free_context(context);
347 create_krb5_ccache(krb5_context kcontext,
349 kerb_auth_config *conf,
350 krb5_principal princ,
354 krb5_error_code problem;
356 krb5_ccache tmp_ccache = NULL;
359 problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
361 problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
362 /* krb5_fcc_generate_new() doesn't set KRB5_TC_OPENCLOSE, which makes
363 krb5_cc_initialize() fail */
364 krb5_fcc_set_flags(kcontext, tmp_ccache, KRB5_TC_OPENCLOSE);
367 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
368 "Cannot create file for new krb5 ccache: %s",
369 krb5_get_err_text(kcontext, problem));
370 ret = HTTP_INTERNAL_SERVER_ERROR;
374 ccname = ap_pstrdup(r->pool, krb5_cc_get_name(kcontext, tmp_ccache));
376 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
378 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
379 "Cannot initialize krb5 ccache %s: krb5_cc_initialize() failed: %s",
380 ccname, krb5_get_err_text(kcontext, problem));
381 ret = HTTP_INTERNAL_SERVER_ERROR;
385 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
386 ap_register_cleanup(r->pool, ccname,
387 krb5_cache_cleanup, ap_null_cleanup);
389 *ccache = tmp_ccache;
396 krb5_cc_destroy(kcontext, tmp_ccache);
402 store_krb5_creds(krb5_context kcontext,
404 kerb_auth_config *conf,
405 krb5_ccache delegated_cred)
408 krb5_error_code problem;
409 krb5_principal princ;
413 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
415 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
416 krb5_get_err_text(kcontext, problem));
417 return HTTP_INTERNAL_SERVER_ERROR;
420 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
422 krb5_free_principal(kcontext, princ);
427 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
429 problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
431 krb5_free_principal(kcontext, princ);
433 snprintf(errstr, sizeof(errstr), "Failed to store credentials: %s",
434 krb5_get_err_text(kcontext, problem));
435 krb5_cc_destroy(kcontext, ccache);
436 return HTTP_INTERNAL_SERVER_ERROR;
439 krb5_cc_close(kcontext, ccache);
444 int authenticate_user_krb5pwd(request_rec *r,
445 kerb_auth_config *conf,
446 const char *auth_line)
448 const char *sent_pw = NULL;
449 const char *sent_name = NULL;
450 const char *realms = NULL;
451 const char *service_name = NULL;
452 krb5_context kcontext = NULL;
453 krb5_error_code code;
454 krb5_principal client = NULL;
455 krb5_ccache ccache = NULL;
459 code = krb5_init_context(&kcontext);
461 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
462 "Cannot initialize Kerberos5 context (%d)", code);
463 return HTTP_INTERNAL_SERVER_ERROR;
466 sent_pw = ap_pbase64decode(r->pool, auth_line);
467 sent_name = ap_getword (r->pool, &sent_pw, ':');
468 /* do not allow user to override realm setting of server */
469 if (strchr(sent_name, '@')) {
470 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
471 "specifying realm in user name is prohibited");
472 ret = HTTP_UNAUTHORIZED;
477 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
479 code = krb5_mcc_generate_new(kcontext, &ccache);
482 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
483 "Cannot generate new ccache: %s",
484 krb5_get_err_text(kcontext, code));
485 ret = HTTP_INTERNAL_SERVER_ERROR;
489 if (conf->krb_5_keytab)
490 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
491 /* kcontext->default_keytab = conf->krb_5_keytab; */
493 if (conf->service_name) {
495 service_name = ap_pstrdup(r->pool, conf->service_name);
496 if ((p=strchr(service_name, '/')))
499 service_name = "khttp";
501 realms = conf->krb_auth_realms;
503 if (realms && (code = krb5_set_default_realm(kcontext,
504 ap_getword_white(r->pool, &realms))))
508 krb5_free_principal(kcontext, client);
511 code = krb5_parse_name(kcontext, sent_name, &client);
515 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
520 /* ap_getword_white() used above shifts the parameter, so it's not
521 needed to touch the realms variable */
522 } while (realms && *realms);
524 memset((char *)sent_pw, 0, strlen(sent_pw));
527 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
528 "Verifying krb5 password failed: %s",
529 krb5_get_err_text(kcontext, code));
530 ret = HTTP_UNAUTHORIZED;
534 code = krb5_unparse_name(kcontext, client, &name);
536 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
537 krb5_get_err_text(kcontext, code));
538 ret = HTTP_UNAUTHORIZED;
541 MK_USER = ap_pstrdup (r->pool, name);
542 MK_AUTH_TYPE = "Basic";
545 if (conf->krb_save_credentials)
546 store_krb5_creds(kcontext, r, conf, ccache);
552 krb5_free_principal(kcontext, client);
554 krb5_cc_destroy(kcontext, ccache);
555 krb5_free_context(kcontext);
560 /*********************************************************************
561 * GSSAPI Authentication
562 ********************************************************************/
565 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
567 OM_uint32 maj_stat, min_stat;
568 OM_uint32 msg_ctx = 0;
569 gss_buffer_desc status_string;
573 snprintf(buf, sizeof(buf), "%s", prefix);
576 maj_stat = gss_display_status (&min_stat,
582 if (sizeof(buf) > len + status_string.length + 1) {
583 sprintf(buf+len, ": %s", (char*) status_string.value);
584 len += status_string.length;
586 gss_release_buffer(&min_stat, &status_string);
587 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
589 return (ap_pstrdup(p, buf));
593 cleanup_gss_connection(void *data)
595 OM_uint32 minor_status;
596 gss_connection_t *gss_conn = (gss_connection_t *)data;
600 if (gss_conn->context != GSS_C_NO_CONTEXT)
601 gss_delete_sec_context(&minor_status, &gss_conn->context,
603 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
604 gss_release_cred(&minor_status, &gss_conn->server_creds);
606 gss_connection = NULL;
612 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
613 gss_cred_id_t delegated_cred)
615 OM_uint32 maj_stat, min_stat;
616 krb5_principal princ = NULL;
617 krb5_ccache ccache = NULL;
618 krb5_error_code problem;
619 krb5_context context;
620 int ret = HTTP_INTERNAL_SERVER_ERROR;
622 problem = krb5_init_context(&context);
624 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
625 return HTTP_INTERNAL_SERVER_ERROR;
628 problem = krb5_parse_name(context, princ_name, &princ);
630 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
631 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
635 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
637 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
638 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
642 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
643 if (GSS_ERROR(maj_stat)) {
644 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
645 "Cannot store delegated credential (%s)",
646 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
650 krb5_cc_close(context, ccache);
656 krb5_free_principal(context, princ);
658 krb5_cc_destroy(context, ccache);
659 krb5_free_context(context);
664 get_gss_creds(request_rec *r,
665 kerb_auth_config *conf,
666 gss_cred_id_t *server_creds)
668 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
669 OM_uint32 major_status, minor_status, minor_status2;
670 gss_name_t server_name = GSS_C_NO_NAME;
672 if (conf->service_name) {
673 input_token.value = conf->service_name;
674 input_token.length = strlen(conf->service_name) + 1;
677 input_token.value = "khttp";
678 input_token.length = 6;
680 major_status = gss_import_name(&minor_status, &input_token,
681 (conf->service_name) ?
682 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
684 if (GSS_ERROR(major_status)) {
685 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
686 "%s", get_gss_error(r->pool, minor_status,
687 "gss_import_name() failed"));
688 return HTTP_INTERNAL_SERVER_ERROR;
691 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
692 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
693 server_creds, NULL, NULL);
694 gss_release_name(&minor_status2, &server_name);
695 if (GSS_ERROR(major_status)) {
696 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
697 "%s", get_gss_error(r->pool, minor_status,
698 "gss_acquire_cred() failed"));
699 return HTTP_INTERNAL_SERVER_ERROR;
706 authenticate_user_gss(request_rec *r,
707 kerb_auth_config *conf,
708 const char *auth_line)
710 OM_uint32 major_status, minor_status, minor_status2;
711 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
712 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
713 const char *auth_param = NULL;
715 gss_name_t client_name = GSS_C_NO_NAME;
716 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
717 static int initial_return = HTTP_UNAUTHORIZED;
719 /* needed to work around replay caches */
720 if (!ap_is_initial_req(r))
721 return initial_return;
722 initial_return = HTTP_UNAUTHORIZED;
724 if (gss_connection == NULL) {
725 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
726 if (gss_connection == NULL) {
727 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
728 "ap_pcalloc() failed (not enough memory)");
729 ret = HTTP_INTERNAL_SERVER_ERROR;
732 memset(gss_connection, 0, sizeof(*gss_connection));
733 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
736 if (conf->krb_5_keytab)
737 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
739 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
740 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
745 /* ap_getword() shifts parameter */
746 auth_param = ap_getword_white(r->pool, &auth_line);
747 if (auth_param == NULL) {
748 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
749 "No Authorization parameter in request from client");
750 ret = HTTP_UNAUTHORIZED;
754 input_token.length = ap_base64decode_len(auth_param) + 1;
755 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
756 if (input_token.value == NULL) {
757 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
758 "ap_pcalloc() failed (not enough memory)");
759 ret = HTTP_INTERNAL_SERVER_ERROR;
762 input_token.length = ap_base64decode(input_token.value, auth_param);
764 major_status = gss_accept_sec_context(&minor_status,
765 &gss_connection->context,
766 gss_connection->server_creds,
768 GSS_C_NO_CHANNEL_BINDINGS,
775 if (output_token.length) {
779 len = ap_base64encode_len(output_token.length) + 1;
780 token = ap_pcalloc(r->connection->pool, len + 1);
782 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
783 "ap_pcalloc() failed (not enough memory)");
784 ret = HTTP_INTERNAL_SERVER_ERROR;
785 gss_release_buffer(&minor_status2, &output_token);
788 ap_base64encode(token, output_token.value, output_token.length);
790 ap_table_set(r->err_headers_out, "WWW-Authenticate",
791 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
792 gss_release_buffer(&minor_status2, &output_token);
795 if (GSS_ERROR(major_status)) {
796 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
797 "%s", get_gss_error(r->pool, minor_status,
798 "gss_accept_sec_context() failed"));
799 ret = HTTP_UNAUTHORIZED;
803 if (major_status & GSS_S_CONTINUE_NEEDED) {
804 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
805 * iterations to establish authentication */
806 ret = HTTP_UNAUTHORIZED;
810 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
811 gss_release_name(&minor_status, &client_name);
812 if (GSS_ERROR(major_status)) {
813 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
814 "%s", get_gss_error(r->pool, minor_status,
815 "gss_export_name() failed"));
816 ret = HTTP_INTERNAL_SERVER_ERROR;
820 MK_AUTH_TYPE = "Negotiate";
821 MK_USER = ap_pstrdup(r->pool, output_token.value);
823 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
824 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
826 gss_release_buffer(&minor_status, &output_token);
829 /* If the user comes from a realm specified by configuration don't include
830 its realm name in the username so that the authorization routine could
831 work for both Password-based and Ticket-based authentication. It's
832 administrators responsibility to include only such realm that have
833 unified principal instances, i.e. if the same principal name occures in
834 multiple realms, it must be always assigned to a single user.
836 p = strchr(r->connection->user, '@');
838 const char *realms = conf->gss_krb5_realms;
840 while (realms && *realms) {
841 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
853 gss_release_cred(&minor_status, &delegated_cred);
855 if (output_token.length)
856 gss_release_buffer(&minor_status, &output_token);
858 if (client_name != GSS_C_NO_NAME)
859 gss_release_name(&minor_status, &client_name);
861 cleanup_gss_connection(gss_connection);
863 initial_return = ret;
870 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
871 int use_krb4, int use_krb5)
873 const char *auth_name = NULL;
876 /* get the user realm specified in .htaccess */
877 auth_name = ap_auth_name(r);
879 /* XXX should the WWW-Authenticate header be cleared first? */
881 if (use_krb5 && conf->krb_method_gssapi)
882 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
883 if (use_krb5 && conf->krb_method_k5pass) {
884 ap_table_add(r->err_headers_out, "WWW-Authenticate",
885 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
891 if (use_krb4 && conf->krb_method_k4pass && !set_basic)
892 ap_table_add(r->err_headers_out, "WWW-Authenticate",
893 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
897 int kerb_authenticate_user(request_rec *r)
899 kerb_auth_config *conf =
900 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
902 const char *auth_type = NULL;
903 const char *auth_line = NULL;
904 const char *type = NULL;
905 int use_krb5 = 0, use_krb4 = 0;
908 /* get the type specified in .htaccess */
909 type = ap_auth_type(r);
911 if (type && strcasecmp(type, "Kerberos") == 0)
912 use_krb5 = use_krb4 = 1;
913 else if(type && strcasecmp(type, "KerberosV5") == 0)
915 else if(type && strcasecmp(type, "KerberosV4") == 0)
920 /* get what the user sent us in the HTTP header */
921 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
923 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
924 return HTTP_UNAUTHORIZED;
926 auth_type = ap_getword_white(r->pool, &auth_line);
928 ret = HTTP_UNAUTHORIZED;
931 if (use_krb5 && conf->krb_method_gssapi &&
932 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
933 ret = authenticate_user_gss(r, conf, auth_line);
934 } else if (use_krb5 && conf->krb_method_k5pass &&
935 strcasecmp(auth_type, "Basic") == 0) {
936 ret = authenticate_user_krb5pwd(r, conf, auth_line);
941 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
942 strcasecmp(auth_type, "Basic") == 0)
943 ret = authenticate_user_krb4pwd(r, conf, auth_line);
946 if (ret == HTTP_UNAUTHORIZED)
947 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
953 /***************************************************************************
954 Module Setup/Configuration
955 ***************************************************************************/
957 module MODULE_VAR_EXPORT auth_kerb_module = {
958 STANDARD_MODULE_STUFF,
959 NULL, /* module initializer */
960 kerb_dir_create_config, /* per-directory config creator */
961 NULL, /* per-directory config merger */
962 NULL, /* per-server config creator */
963 NULL, /* per-server config merger */
964 kerb_auth_cmds, /* command table */
965 NULL, /* [ 9] content handlers */
966 NULL, /* [ 2] URI-to-filename translation */
967 kerb_authenticate_user, /* [ 5] check/validate user_id */
968 NULL, /* [ 6] check user_id is valid *here* */
969 NULL, /* [ 4] check access by host address */
970 NULL, /* [ 7] MIME type checker/setter */
971 NULL, /* [ 8] fixups */
972 NULL, /* [10] logger */
973 NULL, /* [ 3] header parser */
974 NULL, /* process initialization */
975 NULL, /* process exit/cleanup */
976 NULL /* [ 1] post read_request handling */
979 void kerb_register_hooks(apr_pool_t *p)
981 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
984 module AP_MODULE_DECLARE_DATA auth_kerb_module =
986 STANDARD20_MODULE_STUFF,
987 kerb_dir_create_config, /* create per-dir conf structures */
988 NULL, /* merge per-dir conf structures */
989 NULL, /* create per-server conf structures */
990 NULL, /* merge per-server conf structures */
991 kerb_auth_cmds, /* table of configuration directives */
992 kerb_register_hooks /* register hooks */