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
53 /***************************************************************************
54 Auth Configuration Structure
55 ***************************************************************************/
57 char *krb_auth_realms;
59 char *krb_force_instance;
60 int krb_save_credentials;
67 int krb_method_gssapi;
68 int krb_method_k5pass;
72 int krb_method_k4pass;
77 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
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("KrbAuthRealm", krb5_save_realms, krb_auth_realms,
93 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
95 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
96 RAW_ARGS, "Alias for KrbAuthRealm."),
99 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
100 TAKE1, "If auth fails, return status set here."),
103 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
104 TAKE1, "Force authentication against an instance specified here."),
106 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
107 FLAG, "Save and store credentials/tickets retrieved during auth."),
109 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
110 FLAG, "Alias for KrbSaveCredentials."),
112 command("KrbTmpdir", ap_set_string_slot, krb_tmp_dir,
113 TAKE1, "Path to store ticket files and such in."),
115 command("KrbServiceName", ap_set_string_slot, service_name,
116 TAKE1, "Kerberos service name to be used by apache."),
119 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
120 TAKE1, "Kerberos ticket lifetime."),
124 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
125 TAKE1, "Location of Kerberos V5 keytab file."),
127 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
128 FLAG, "Credentials retrieved will be flagged as forwardable."),
130 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
131 FLAG, "Enable GSSAPI authentication."),
133 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
134 FLAG, "Enable Kerberos V5 password authentication."),
138 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
139 TAKE1, "Location of Kerberos V4 srvtab file."),
141 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
142 FLAG, "Enable Kerberos V4 password authentication."),
150 gss_ctx_id_t context;
151 gss_cred_id_t server_creds;
154 static gss_connection_t *gss_connection = NULL;
158 /***************************************************************************
159 Auth Configuration Initialization
160 ***************************************************************************/
161 static void *kerb_dir_create_config(MK_POOL *p, char *d)
163 kerb_auth_config *rec;
165 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
166 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
168 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
169 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
172 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
178 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
180 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
184 void log_rerror(const char *file, int line, int level, int status,
185 const request_rec *r, const char *fmt, ...)
191 vsnprintf(errstr, sizeof(errstr), fmt, ap);
195 ap_log_rerror(file, line, level, r, "%s", errstr);
197 ap_log_rerror(file, line, level, status, r, "%s", errstr);
202 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
205 int offset = (int) (long) cmd->info;
206 if (!strncasecmp(arg, "unauthorized", 12))
207 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
208 else if (!strncasecmp(arg, "forbidden", 9))
209 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
210 else if (!strncasecmp(arg, "declined", 8))
211 *(int *) ((char *)struct_ptr + offset) = DECLINED;
213 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
219 /***************************************************************************
220 Username/Password Validation for Krb4
221 ***************************************************************************/
222 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
224 kerb_auth_config *conf =
225 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
228 int lifetime = DEFAULT_TKT_LIFE;
230 char *username = NULL;
231 char *instance = NULL;
234 username = (char *)ap_pstrdup(r->pool, user);
239 instance = strchr(username, '.');
247 realm = strchr(username, '@');
255 if (conf->krb_lifetime) {
256 lifetime = atoi(conf->krb_lifetime);
259 if (conf->krb_force_instance) {
260 instance = conf->krb_force_instance;
263 if (conf->krb_save_credentials) {
264 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
265 sprintf(tfname, "%s/k5cc_ap_%s",
266 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
269 if (!strcmp(instance, "")) {
270 tfname = strcat(tfname, ".");
271 tfname = strcat(tfname, instance);
274 if (!strcmp(realm, "")) {
275 tfname = strcat(tfname, ".");
276 tfname = strcat(tfname, realm);
279 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
280 "/tmp") + 1; *c; c++) {
285 krb_set_tkt_string(tfname);
288 if (!strcmp(realm, "")) {
289 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
290 ret = krb_get_lrealm(realm, 1);
295 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
296 lifetime, (char *)pass);
311 /***************************************************************************
312 Username/Password Validation for Krb5
313 ***************************************************************************/
316 krb5_verify_user(krb5_context context, krb5_principal principal,
317 krb5_ccache ccache, const char *password, krb5_boolean secure,
321 krb5_context kcontext;
322 krb5_principal server, client;
325 krb5_flags options = 0;
326 krb5_principal me = NULL;
327 krb5_data tgtname = {
333 memset((char *)&my_creds, 0, sizeof(my_creds));
334 my_creds.client = principal;
336 if (krb5_build_principal_ext(kcontext, &server,
337 krb5_princ_realm(kcontext, me)->length,
338 krb5_princ_realm(kcontext, me)->data,
339 tgtname.length, tgtname.data,
340 krb5_princ_realm(kcontext, me)->length,
341 krb5_princ_realm(kcontext, me)->data,
346 my_creds.server = server;
347 if (krb5_timeofday(kcontext, &now))
350 my_creds.times.starttime = 0;
352 my_creds.times.endtime = now + lifetime;
353 my_creds.times.renew_till = now + renewal;
356 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
357 password, ccache, &my_creds, 0);
368 krb5_cache_cleanup(void *data)
370 krb5_context context;
372 krb5_error_code problem;
373 char *cache_name = (char *) data;
375 problem = krb5_init_context(&context);
377 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
378 return HTTP_INTERNAL_SERVER_ERROR;
381 problem = krb5_cc_resolve(context, cache_name, &cache);
383 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
384 "krb5_cc_resolve() failed (%s: %s)",
385 cache_name, krb5_get_err_text(context, problem)); */
386 return HTTP_INTERNAL_SERVER_ERROR;
389 krb5_cc_destroy(context, cache);
390 krb5_free_context(context);
395 create_krb5_ccache(krb5_context kcontext,
397 kerb_auth_config *conf,
398 krb5_principal princ,
401 char *c, ccname[MAX_STRING_LEN];
402 krb5_error_code problem;
404 krb5_ccache tmp_ccache = NULL;
406 snprintf(ccname, sizeof(ccname), "FILE:%s/k5cc_ap_%s",
407 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
410 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
411 "/tmp") + 1; *c; c++) {
416 problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
418 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
419 "Cannot create krb5 ccache: krb5_cc_resolve() failed: %s",
420 krb5_get_err_text(kcontext, problem));
421 ret = HTTP_INTERNAL_SERVER_ERROR;
425 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
427 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
428 "Cannot create krb5 ccache: krb5_cc_initialize() failed: %s",
429 krb5_get_err_text(kcontext, problem));
430 ret = HTTP_INTERNAL_SERVER_ERROR;
434 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
435 ap_register_cleanup(r->pool, ccname,
436 krb5_cache_cleanup, ap_null_cleanup);
438 *ccache = tmp_ccache;
445 krb5_cc_destroy(kcontext, tmp_ccache);
451 store_krb5_creds(krb5_context kcontext,
453 kerb_auth_config *conf,
454 krb5_ccache delegated_cred)
457 krb5_error_code problem;
458 krb5_principal princ;
462 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
464 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
465 krb5_get_err_text(kcontext, problem));
466 return HTTP_INTERNAL_SERVER_ERROR;
469 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
471 krb5_free_principal(kcontext, princ);
475 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
476 krb5_free_principal(kcontext, princ);
478 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
479 krb5_get_err_text(kcontext, problem));
480 krb5_cc_destroy(kcontext, ccache);
481 return HTTP_INTERNAL_SERVER_ERROR;
484 krb5_cc_close(kcontext, ccache);
489 int authenticate_user_krb5pwd(request_rec *r,
490 kerb_auth_config *conf,
491 const char *auth_line)
493 const char *sent_pw = NULL;
494 const char *realms = NULL;
495 krb5_context kcontext = NULL;
496 krb5_error_code code;
497 krb5_principal client = NULL;
498 krb5_ccache ccache = NULL;
501 code = krb5_init_context(&kcontext);
503 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
504 "Cannot initialize Kerberos5 context (%d)", code);
505 return HTTP_INTERNAL_SERVER_ERROR;
508 sent_pw = ap_pbase64decode(r->pool, auth_line);
509 MK_USER = ap_getword (r->pool, &sent_pw, ':');
510 MK_AUTH_TYPE = "Basic";
512 /* do not allow user to override realm setting of server */
513 if (strchr(MK_USER, '@')) {
514 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
515 "specifying realm in user name is prohibited");
516 ret = HTTP_UNAUTHORIZED;
521 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
523 code = krb5_mcc_generate_new(kcontext, &ccache);
526 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
527 "Cannot generate new ccache: %s",
528 krb5_get_err_text(kcontext, code));
529 ret = HTTP_INTERNAL_SERVER_ERROR;
533 if (conf->krb_5_keytab)
534 /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
535 kcontext->default_keytab = conf->krb_5_keytab;
537 realms = conf->krb_auth_realms;
539 if (realms && (code = krb5_set_default_realm(kcontext,
540 ap_getword_white(r->pool, &realms))))
543 code = krb5_parse_name(kcontext, MK_USER, &client);
547 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
548 (conf->service_name) ? conf->service_name : "khttp");
549 krb5_free_principal(kcontext, client);
554 /* ap_getword_white() used above shifts the parameter, so it's not
555 needed to touch the realms variable */
556 } while (realms && *realms);
558 memset((char *)sent_pw, 0, strlen(sent_pw));
561 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
562 "Verifying krb5 password failed: %s",
563 krb5_get_err_text(kcontext, code));
564 ret = HTTP_UNAUTHORIZED;
568 if (conf->krb_save_credentials) {
569 ret = store_krb5_creds(kcontext, r, conf, ccache);
570 if (ret) /* Ignore error ?? */
578 krb5_free_principal(kcontext, client);
580 krb5_cc_destroy(kcontext, ccache);
581 krb5_free_context(kcontext);
586 /*********************************************************************
587 * GSSAPI Authentication
588 ********************************************************************/
591 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
593 OM_uint32 maj_stat, min_stat;
594 OM_uint32 msg_ctx = 0;
595 gss_buffer_desc status_string;
599 snprintf(buf, sizeof(buf), "%s", prefix);
602 maj_stat = gss_display_status (&min_stat,
608 if (sizeof(buf) > len + status_string.length + 1) {
609 sprintf(buf+len, ": %s", (char*) status_string.value);
610 len += status_string.length;
612 gss_release_buffer(&min_stat, &status_string);
613 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
615 return (ap_pstrdup(p, buf));
619 cleanup_gss_connection(void *data)
621 OM_uint32 minor_status;
622 gss_connection_t *gss_conn = (gss_connection_t *)data;
626 if (gss_conn->context != GSS_C_NO_CONTEXT)
627 gss_delete_sec_context(&minor_status, &gss_conn->context,
629 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
630 gss_release_cred(&minor_status, &gss_conn->server_creds);
636 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
637 gss_cred_id_t delegated_cred)
639 OM_uint32 maj_stat, min_stat;
640 krb5_principal princ = NULL;
641 krb5_ccache ccache = NULL;
642 krb5_error_code problem;
643 krb5_context context;
644 int ret = HTTP_INTERNAL_SERVER_ERROR;
646 problem = krb5_init_context(&context);
648 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
649 return HTTP_INTERNAL_SERVER_ERROR;
652 problem = krb5_parse_name(context, princ_name, &princ);
654 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
655 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
659 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
661 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
662 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
666 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
667 if (GSS_ERROR(maj_stat)) {
668 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
669 "Cannot store delegated credential (%s)",
670 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
674 krb5_cc_close(context, ccache);
680 krb5_free_principal(context, princ);
682 krb5_cc_destroy(context, ccache);
683 krb5_free_context(context);
688 get_gss_creds(request_rec *r,
689 kerb_auth_config *conf,
690 gss_cred_id_t *server_creds)
692 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
693 OM_uint32 major_status, minor_status, minor_status2;
694 gss_name_t server_name = GSS_C_NO_NAME;
696 if (conf->service_name) {
697 input_token.value = conf->service_name;
698 input_token.length = strlen(conf->service_name) + 1;
701 input_token.value = "khttp";
702 input_token.length = 6;
704 major_status = gss_import_name(&minor_status, &input_token,
705 (conf->service_name) ?
706 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
708 if (GSS_ERROR(major_status)) {
709 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
710 "%s", get_gss_error(r->pool, minor_status,
711 "gss_import_name() failed"));
712 return HTTP_INTERNAL_SERVER_ERROR;
715 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
716 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
717 server_creds, NULL, NULL);
718 gss_release_name(&minor_status2, &server_name);
719 if (GSS_ERROR(major_status)) {
720 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
721 "%s", get_gss_error(r->pool, minor_status,
722 "gss_acquire_cred() failed"));
723 return HTTP_INTERNAL_SERVER_ERROR;
730 authenticate_user_gss(request_rec *r,
731 kerb_auth_config *conf,
732 const char *auth_line)
734 OM_uint32 major_status, minor_status, minor_status2;
735 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
736 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
737 const char *auth_param = NULL;
739 gss_name_t client_name = GSS_C_NO_NAME;
740 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
742 if (gss_connection == NULL) {
743 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
744 if (gss_connection == NULL) {
745 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
746 "ap_pcalloc() failed (not enough memory)");
747 ret = HTTP_INTERNAL_SERVER_ERROR;
750 memset(gss_connection, 0, sizeof(*gss_connection));
751 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
754 if (conf->krb_5_keytab)
755 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
757 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
758 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
763 /* ap_getword() shifts parameter */
764 auth_param = ap_getword_white(r->pool, &auth_line);
765 if (auth_param == NULL) {
766 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
767 "No Authorization parameter in request from client");
768 ret = HTTP_UNAUTHORIZED;
772 input_token.length = ap_base64decode_len(auth_param) + 1;
773 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
774 if (input_token.value == NULL) {
775 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
776 "ap_pcalloc() failed (not enough memory)");
777 ret = HTTP_INTERNAL_SERVER_ERROR;
780 input_token.length = ap_base64decode(input_token.value, auth_param);
782 major_status = gss_accept_sec_context(&minor_status,
783 &gss_connection->context,
784 gss_connection->server_creds,
786 GSS_C_NO_CHANNEL_BINDINGS,
793 if (output_token.length) {
797 len = ap_base64encode_len(output_token.length) + 1;
798 token = ap_pcalloc(r->connection->pool, len + 1);
800 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
801 "ap_pcalloc() failed (not enough memory)");
802 ret = HTTP_INTERNAL_SERVER_ERROR;
803 gss_release_buffer(&minor_status2, &output_token);
806 ap_base64encode(token, output_token.value, output_token.length);
808 ap_table_set(r->err_headers_out, "WWW-Authenticate",
809 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
810 gss_release_buffer(&minor_status2, &output_token);
813 if (GSS_ERROR(major_status)) {
814 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
815 "%s", get_gss_error(r->pool, minor_status,
816 "gss_accept_sec_context() failed"));
817 ret = HTTP_UNAUTHORIZED;
821 if (major_status & GSS_S_CONTINUE_NEEDED) {
822 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
823 * iterations to establish authentication */
824 ret = HTTP_UNAUTHORIZED;
828 major_status = gss_export_name(&minor_status, client_name, &output_token);
829 gss_release_name(&minor_status, &client_name);
830 if (GSS_ERROR(major_status)) {
831 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
832 "%s", get_gss_error(r->pool, minor_status,
833 "gss_export_name() failed"));
834 ret = HTTP_INTERNAL_SERVER_ERROR;
838 MK_AUTH_TYPE = "Negotiate";
839 MK_USER = ap_pstrdup(r->pool, output_token.value);
841 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
842 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
844 gss_release_buffer(&minor_status, &output_token);
848 /* If the user comes from a realm specified by configuration don't include
849 its realm name in the username so that the authorization routine could
850 work for both Password-based and Ticket-based authentication. It's
851 administrators responsibility to include only such realm that have
852 unified principal instances, i.e. if the same principal name occures in
853 multiple realms, it must be always assigned to a single user.
855 p = strchr(r->connection->user, '@');
857 const char *realms = conf->gss_krb5_realms;
859 while (realms && *realms) {
860 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
872 gss_release_cred(&minor_status, &delegated_cred);
874 if (output_token.length)
875 gss_release_buffer(&minor_status, &output_token);
877 if (client_name != GSS_C_NO_NAME)
878 gss_release_name(&minor_status, &client_name);
886 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
888 const char *auth_name = NULL;
890 /* get the user realm specified in .htaccess */
891 auth_name = ap_auth_name(r);
893 /* XXX check AuthType */
895 /* XXX should the WWW-Authenticate header be cleared first? */
897 if (conf->krb_method_gssapi)
898 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
899 if (conf->krb_method_k5pass)
900 ap_table_add(r->err_headers_out, "WWW-Authenticate",
901 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
905 if (conf->krb_method_k4pass)
906 ap_table_add(r->err_headers_out, "WWW-Authenticate",
907 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
911 int kerb_authenticate_user(request_rec *r)
913 kerb_auth_config *conf =
914 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
916 const char *auth_type = NULL;
917 const char *auth_line = NULL;
918 const char *type = NULL;
919 int use_krb5 = 0, use_krb4 = 0;
922 /* get the type specified in .htaccess */
923 type = ap_auth_type(r);
925 if (type && strcasecmp(type, "Kerberos") == 0)
926 use_krb5 = use_krb4 = 1;
927 else if(type && strcasecmp(type, "KerberosV5") == 0)
929 else if (type && strcasecmp(type, "KerberosV4") == 0)
934 /* get what the user sent us in the HTTP header */
935 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
937 note_kerb_auth_failure(r, conf);
938 return HTTP_UNAUTHORIZED;
940 auth_type = ap_getword_white(r->pool, &auth_line);
942 ret = HTTP_UNAUTHORIZED;
945 if (use_krb5 && conf->krb_method_gssapi &&
946 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
947 ret = authenticate_user_gss(r, conf, auth_line);
948 } else if (use_krb5 && conf->krb_method_k5pass &&
949 strcasecmp(auth_type, "Basic") == 0) {
950 ret = authenticate_user_krb5pwd(r, conf, auth_line);
955 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
956 strcasecmp(auth_type, "Basic") == 0)
957 ret = authenticate_user_krb4pwd(r, conf, auth_line);
960 if (ret == HTTP_UNAUTHORIZED)
961 note_kerb_auth_failure(r, conf);
967 /***************************************************************************
968 Module Setup/Configuration
969 ***************************************************************************/
971 module MODULE_VAR_EXPORT auth_kerb_module = {
972 STANDARD_MODULE_STUFF,
973 NULL, /* module initializer */
974 kerb_dir_create_config, /* per-directory config creator */
975 NULL, /* per-directory config merger */
976 NULL, /* per-server config creator */
977 NULL, /* per-server config merger */
978 kerb_auth_cmds, /* command table */
979 NULL, /* [ 9] content handlers */
980 NULL, /* [ 2] URI-to-filename translation */
981 kerb_authenticate_user, /* [ 5] check/validate user_id */
982 NULL, /* [ 6] check user_id is valid *here* */
983 NULL, /* [ 4] check access by host address */
984 NULL, /* [ 7] MIME type checker/setter */
985 NULL, /* [ 8] fixups */
986 NULL, /* [10] logger */
987 NULL, /* [ 3] header parser */
988 NULL, /* process initialization */
989 NULL, /* process exit/cleanup */
990 NULL /* [ 1] post read_request handling */
993 void kerb_register_hooks(apr_pool_t *p)
995 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
998 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1000 STANDARD20_MODULE_STUFF,
1001 kerb_dir_create_config, /* create per-dir conf structures */
1002 NULL, /* merge per-dir conf structures */
1003 NULL, /* create per-server conf structures */
1004 NULL, /* merge per-server conf structures */
1005 kerb_auth_cmds, /* table of configuration directives */
1006 kerb_register_hooks /* register hooks */