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 ***************************************************************************/
59 char *krb_auth_realms;
61 char *krb_force_instance;
62 int krb_save_credentials;
69 int krb_method_gssapi;
70 int krb_method_k5pass;
74 int krb_method_k4pass;
79 #define command(name, func, var, type, usage) \
81 (void*)XtOffsetOf(kerb_auth_config, var), \
82 OR_AUTHCFG, type, usage }
84 #define command(name, func, var, type, usage) \
85 AP_INIT_ ## type (name, func, \
86 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
90 static const command_rec kerb_auth_cmds[] = {
91 command("KrbAuthRealm", ap_set_string_slot, krb_auth_realms,
92 ITERATE, "Realms to attempt authentication against (can be multiple)."),
94 command("KrbAuthRealms", ap_set_string_slot, krb_auth_realms,
95 ITERATE, "Alias for KrbAuthRealm."),
98 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
99 TAKE1, "If auth fails, return status set here."),
102 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
103 TAKE1, "Force authentication against an instance specified here."),
105 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
106 FLAG, "Save and store credentials/tickets retrieved during auth."),
108 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
109 FLAG, "Alias for KrbSaveCredentials."),
111 command("KrbTmpdir", ap_set_string_slot, krb_tmp_dir,
112 TAKE1, "Path to store ticket files and such in."),
114 command("KrbServiceName", ap_set_string_slot, service_name,
115 TAKE1, "Kerberos service name to be used by apache."),
118 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
119 TAKE1, "Kerberos ticket lifetime."),
123 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
124 TAKE1, "Location of Kerberos V5 keytab file."),
126 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
127 FLAG, "Credentials retrieved will be flagged as forwardable."),
129 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
130 FLAG, "Enable GSSAPI authentication."),
132 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
133 FLAG, "Enable Kerberos V5 password authentication."),
137 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
138 TAKE1, "Location of Kerberos V4 srvtab file."),
140 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
141 FLAG, "Enable Kerberos V4 password authentication."),
149 gss_ctx_id_t context;
150 gss_cred_id_t server_creds;
153 static gss_connection_t *gss_connection = NULL;
157 /***************************************************************************
158 Auth Configuration Initialization
159 ***************************************************************************/
160 static void *kerb_dir_create_config(MK_POOL *p, char *d)
162 kerb_auth_config *rec;
164 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
165 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
167 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
168 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
171 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
176 void log_rerror(const char *file, int line, int level, int status,
177 const request_rec *r, const char *fmt, ...)
183 vsnprintf(errstr, sizeof(errstr), fmt, ap);
187 ap_log_rerror(file, line, level, r, "%s", errstr);
189 ap_log_rerror(file, line, level, status, r, "%s", errstr);
194 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
197 int offset = (int) (long) cmd->info;
198 if (!strncasecmp(arg, "unauthorized", 12))
199 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
200 else if (!strncasecmp(arg, "forbidden", 9))
201 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
202 else if (!strncasecmp(arg, "declined", 8))
203 *(int *) ((char *)struct_ptr + offset) = DECLINED;
205 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
211 /***************************************************************************
212 Username/Password Validation for Krb4
213 ***************************************************************************/
214 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
216 kerb_auth_config *conf =
217 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
220 int lifetime = DEFAULT_TKT_LIFE;
222 char *username = NULL;
223 char *instance = NULL;
226 username = (char *)ap_pstrdup(r->pool, user);
231 instance = strchr(username, '.');
239 realm = strchr(username, '@');
247 if (conf->krb_lifetime) {
248 lifetime = atoi(conf->krb_lifetime);
251 if (conf->krb_force_instance) {
252 instance = conf->krb_force_instance;
255 if (conf->krb_save_credentials) {
256 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
257 sprintf(tfname, "%s/k5cc_ap_%s",
258 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
261 if (!strcmp(instance, "")) {
262 tfname = strcat(tfname, ".");
263 tfname = strcat(tfname, instance);
266 if (!strcmp(realm, "")) {
267 tfname = strcat(tfname, ".");
268 tfname = strcat(tfname, realm);
271 for (c = tfname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
272 "/tmp") + 1; *c; c++) {
277 krb_set_tkt_string(tfname);
280 if (!strcmp(realm, "")) {
281 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
282 ret = krb_get_lrealm(realm, 1);
287 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
288 lifetime, (char *)pass);
303 /***************************************************************************
304 Username/Password Validation for Krb5
305 ***************************************************************************/
308 krb5_verify_user(krb5_context context, krb5_principal principal,
309 krb5_ccache ccache, const char *password, krb5_boolean secure,
313 krb5_context kcontext;
314 krb5_principal server, client;
317 krb5_flags options = 0;
318 krb5_principal me = NULL;
319 krb5_data tgtname = {
325 memset((char *)&my_creds, 0, sizeof(my_creds));
326 my_creds.client = principal;
328 if (krb5_build_principal_ext(kcontext, &server,
329 krb5_princ_realm(kcontext, me)->length,
330 krb5_princ_realm(kcontext, me)->data,
331 tgtname.length, tgtname.data,
332 krb5_princ_realm(kcontext, me)->length,
333 krb5_princ_realm(kcontext, me)->data,
338 my_creds.server = server;
339 if (krb5_timeofday(kcontext, &now))
342 my_creds.times.starttime = 0;
344 my_creds.times.endtime = now + lifetime;
345 my_creds.times.renew_till = now + renewal;
348 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
349 password, ccache, &my_creds, 0);
360 krb5_cache_cleanup(void *data)
362 krb5_context context;
364 krb5_error_code problem;
365 char *cache_name = (char *) data;
367 problem = krb5_init_context(&context);
369 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
370 return HTTP_INTERNAL_SERVER_ERROR;
373 problem = krb5_cc_resolve(context, cache_name, &cache);
375 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
376 "krb5_cc_resolve() failed (%s: %s)",
377 cache_name, krb5_get_err_text(context, problem)); */
378 return HTTP_INTERNAL_SERVER_ERROR;
381 krb5_cc_destroy(context, cache);
382 krb5_free_context(context);
387 create_krb5_ccache(krb5_context kcontext,
389 kerb_auth_config *conf,
390 krb5_principal princ,
393 char *c, ccname[MAX_STRING_LEN];
394 krb5_error_code problem;
396 krb5_ccache tmp_ccache = NULL;
398 snprintf(ccname, sizeof(ccname), "FILE:%s/k5cc_ap_%s",
399 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
402 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
403 "/tmp") + 1; *c; c++) {
408 problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
410 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
411 "Cannot create krb5 ccache: krb5_cc_resolve() failed: %s",
412 krb5_get_err_text(kcontext, problem));
413 ret = HTTP_INTERNAL_SERVER_ERROR;
417 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
419 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
420 "Cannot create krb5 ccache: krb5_cc_initialize() failed: %s",
421 krb5_get_err_text(kcontext, problem));
422 ret = HTTP_INTERNAL_SERVER_ERROR;
426 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
427 ap_register_cleanup(r->pool, ccname,
428 krb5_cache_cleanup, ap_null_cleanup);
430 *ccache = tmp_ccache;
437 krb5_cc_destroy(kcontext, tmp_ccache);
443 store_krb5_creds(krb5_context kcontext,
445 kerb_auth_config *conf,
446 krb5_ccache delegated_cred)
449 krb5_error_code problem;
450 krb5_principal princ;
454 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
456 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
457 krb5_get_err_text(kcontext, problem));
458 return HTTP_INTERNAL_SERVER_ERROR;
461 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
463 krb5_free_principal(kcontext, princ);
467 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
468 krb5_free_principal(kcontext, princ);
470 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
471 krb5_get_err_text(kcontext, problem));
472 krb5_cc_destroy(kcontext, ccache);
473 return HTTP_INTERNAL_SERVER_ERROR;
476 krb5_cc_close(kcontext, ccache);
481 int authenticate_user_krb5pwd(request_rec *r,
482 kerb_auth_config *conf,
483 const char *auth_line)
485 const char *sent_pw = NULL;
486 const char *realms = NULL;
487 krb5_context kcontext = NULL;
488 krb5_error_code code;
489 krb5_principal client = NULL;
490 krb5_ccache ccache = NULL;
493 code = krb5_init_context(&kcontext);
495 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
496 "Cannot initialize Kerberos5 context (%d)", code);
497 return HTTP_INTERNAL_SERVER_ERROR;
500 sent_pw = ap_pbase64decode(r->pool, auth_line);
501 MK_USER = ap_getword (r->pool, &sent_pw, ':');
502 MK_AUTH_TYPE = "Basic";
504 /* do not allow user to override realm setting of server */
505 if (strchr(MK_USER, '@')) {
506 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
507 "specifying realm in user name is prohibited");
508 ret = HTTP_UNAUTHORIZED;
513 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
515 code = krb5_mcc_generate_new(kcontext, &ccache);
518 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
519 "Cannot generate new ccache: %s",
520 krb5_get_err_text(kcontext, code));
521 ret = HTTP_INTERNAL_SERVER_ERROR;
525 if (conf->krb_5_keytab)
526 /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
527 kcontext->default_keytab = conf->krb_5_keytab;
529 realms = conf->krb_auth_realms;
531 if (realms && (code = krb5_set_default_realm(kcontext,
532 ap_getword_white(r->pool, &realms))))
536 code = krb5_parse_name(kcontext, MK_USER, &client);
538 code = krb5_parse_name(kcontext, "kouril", &client);
543 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
544 (conf->service_name) ? conf->service_name : "khttp");
545 krb5_free_principal(kcontext, client);
549 /* ap_getword_white() used above shifts the parameter, so it's not
550 needed to touch the realms variable */
551 } while (realms && *realms);
553 memset((char *)sent_pw, 0, strlen(sent_pw));
556 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
557 "Verifying krb5 password failed: %s",
558 krb5_get_err_text(kcontext, code));
559 ret = HTTP_UNAUTHORIZED;
563 if (conf->krb_save_credentials) {
564 ret = store_krb5_creds(kcontext, r, conf, ccache);
565 if (ret) /* Ignore error ?? */
573 krb5_free_principal(kcontext, client);
575 krb5_cc_destroy(kcontext, ccache);
576 krb5_free_context(kcontext);
581 /*********************************************************************
582 * GSSAPI Authentication
583 ********************************************************************/
586 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
588 OM_uint32 maj_stat, min_stat;
589 OM_uint32 msg_ctx = 0;
590 gss_buffer_desc status_string;
594 snprintf(buf, sizeof(buf), "%s", prefix);
597 maj_stat = gss_display_status (&min_stat,
603 if (sizeof(buf) > len + status_string.length + 1) {
604 sprintf(buf+len, ": %s", (char*) status_string.value);
605 len += status_string.length;
607 gss_release_buffer(&min_stat, &status_string);
608 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
610 return (ap_pstrdup(p, buf));
614 cleanup_gss_connection(void *data)
616 OM_uint32 minor_status;
617 gss_connection_t *gss_conn = (gss_connection_t *)data;
621 if (gss_conn->context != GSS_C_NO_CONTEXT)
622 gss_delete_sec_context(&minor_status, &gss_conn->context,
624 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
625 gss_release_cred(&minor_status, &gss_conn->server_creds);
631 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
632 gss_cred_id_t delegated_cred)
634 OM_uint32 maj_stat, min_stat;
635 krb5_principal princ = NULL;
636 krb5_ccache ccache = NULL;
637 krb5_error_code problem;
638 krb5_context context;
639 int ret = HTTP_INTERNAL_SERVER_ERROR;
641 problem = krb5_init_context(&context);
643 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
644 return HTTP_INTERNAL_SERVER_ERROR;
647 problem = krb5_parse_name(context, princ_name, &princ);
649 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
650 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
654 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
656 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
657 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
661 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
662 if (GSS_ERROR(maj_stat)) {
663 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
664 "Cannot store delegated credential (%s)",
665 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
669 krb5_cc_close(context, ccache);
675 krb5_free_principal(context, princ);
677 krb5_cc_destroy(context, ccache);
678 krb5_free_context(context);
683 get_gss_creds(request_rec *r,
684 kerb_auth_config *conf,
685 gss_cred_id_t *server_creds)
687 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
688 OM_uint32 major_status, minor_status, minor_status2;
689 gss_name_t server_name = GSS_C_NO_NAME;
691 if (conf->service_name) {
692 input_token.value = conf->service_name;
693 input_token.length = strlen(conf->service_name) + 1;
696 input_token.value = "khttp";
697 input_token.length = 6;
699 major_status = gss_import_name(&minor_status, &input_token,
700 (conf->service_name) ?
701 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
703 if (GSS_ERROR(major_status)) {
704 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
705 "%s", get_gss_error(r->pool, minor_status,
706 "gss_import_name() failed"));
707 return HTTP_INTERNAL_SERVER_ERROR;
710 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
711 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
712 server_creds, NULL, NULL);
713 gss_release_name(&minor_status2, &server_name);
714 if (GSS_ERROR(major_status)) {
715 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
716 "%s", get_gss_error(r->pool, minor_status,
717 "gss_acquire_cred() failed"));
718 return HTTP_INTERNAL_SERVER_ERROR;
725 authenticate_user_gss(request_rec *r,
726 kerb_auth_config *conf,
727 const char *auth_line)
729 OM_uint32 major_status, minor_status, minor_status2;
730 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
731 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
732 const char *auth_param = NULL;
734 gss_name_t client_name = GSS_C_NO_NAME;
735 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
737 if (gss_connection == NULL) {
738 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
739 if (gss_connection == NULL) {
740 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
741 "ap_pcalloc() failed (not enough memory)");
742 ret = HTTP_INTERNAL_SERVER_ERROR;
745 memset(gss_connection, 0, sizeof(*gss_connection));
746 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
749 if (conf->krb_5_keytab)
750 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
752 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
753 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
758 /* ap_getword() shifts parameter */
759 auth_param = ap_getword_white(r->pool, &auth_line);
760 if (auth_param == NULL) {
761 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
762 "No Authorization parameter in request from client");
763 ret = HTTP_UNAUTHORIZED;
767 input_token.length = ap_base64decode_len(auth_param) + 1;
768 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
769 if (input_token.value == NULL) {
770 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
771 "ap_pcalloc() failed (not enough memory)");
772 ret = HTTP_INTERNAL_SERVER_ERROR;
775 input_token.length = ap_base64decode(input_token.value, auth_param);
777 major_status = gss_accept_sec_context(&minor_status,
778 &gss_connection->context,
779 gss_connection->server_creds,
781 GSS_C_NO_CHANNEL_BINDINGS,
788 if (output_token.length) {
792 len = ap_base64encode_len(output_token.length) + 1;
793 token = ap_pcalloc(r->connection->pool, len + 1);
795 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
796 "ap_pcalloc() failed (not enough memory)");
797 ret = HTTP_INTERNAL_SERVER_ERROR;
798 gss_release_buffer(&minor_status2, &output_token);
801 ap_base64encode(token, output_token.value, output_token.length);
803 ap_table_set(r->err_headers_out, "WWW-Authenticate",
804 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
805 gss_release_buffer(&minor_status2, &output_token);
808 if (GSS_ERROR(major_status)) {
809 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
810 "%s", get_gss_error(r->pool, minor_status,
811 "gss_accept_sec_context() failed"));
812 ret = HTTP_UNAUTHORIZED;
816 if (major_status & GSS_S_CONTINUE_NEEDED) {
817 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
818 * iterations to establish authentication */
819 ret = HTTP_UNAUTHORIZED;
823 major_status = gss_export_name(&minor_status, client_name, &output_token);
824 gss_release_name(&minor_status, &client_name);
825 if (GSS_ERROR(major_status)) {
826 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
827 "%s", get_gss_error(r->pool, minor_status,
828 "gss_export_name() failed"));
829 ret = HTTP_INTERNAL_SERVER_ERROR;
833 MK_AUTH_TYPE = "Negotiate";
834 MK_USER = ap_pstrdup(r->pool, output_token.value);
836 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
837 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
839 gss_release_buffer(&minor_status, &output_token);
843 /* If the user comes from a realm specified by configuration don't include
844 its realm name in the username so that the authorization routine could
845 work for both Password-based and Ticket-based authentication. It's
846 administrators responsibility to include only such realm that have
847 unified principal instances, i.e. if the same principal name occures in
848 multiple realms, it must be always assigned to a single user.
850 p = strchr(r->connection->user, '@');
852 const char *realms = conf->gss_krb5_realms;
854 while (realms && *realms) {
855 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
867 gss_release_cred(&minor_status, &delegated_cred);
869 if (output_token.length)
870 gss_release_buffer(&minor_status, &output_token);
872 if (client_name != GSS_C_NO_NAME)
873 gss_release_name(&minor_status, &client_name);
881 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
883 const char *auth_name = NULL;
885 /* get the user realm specified in .htaccess */
886 auth_name = ap_auth_name(r);
888 /* XXX check AuthType */
890 /* XXX should the WWW-Authenticate header be cleared first? */
892 if (conf->krb_method_gssapi)
893 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
894 if (conf->krb_method_k5pass)
895 ap_table_add(r->err_headers_out, "WWW-Authenticate",
896 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
900 if (conf->krb_method_k4pass)
901 ap_table_add(r->err_headers_out, "WWW-Authenticate",
902 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
906 int kerb_authenticate_user(request_rec *r)
908 kerb_auth_config *conf =
909 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
911 const char *auth_type = NULL;
912 const char *auth_line = NULL;
913 const char *type = NULL;
914 int use_krb5 = 0, use_krb4 = 0;
917 /* get the type specified in .htaccess */
918 type = ap_auth_type(r);
920 if (type && strcasecmp(type, "Kerberos") == 0)
921 use_krb5 = use_krb4 = 1;
922 else if(type && strcasecmp(type, "KerberosV5") == 0)
924 else if (type && strcasecmp(type, "KerberosV4") == 0)
929 /* get what the user sent us in the HTTP header */
930 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
932 note_kerb_auth_failure(r, conf);
933 return HTTP_UNAUTHORIZED;
935 auth_type = ap_getword_white(r->pool, &auth_line);
937 ret = HTTP_UNAUTHORIZED;
940 if (use_krb5 && conf->krb_method_gssapi &&
941 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
942 ret = authenticate_user_gss(r, conf, auth_line);
943 } else if (use_krb5 && conf->krb_method_k5pass &&
944 strcasecmp(auth_type, "Basic") == 0) {
945 ret = authenticate_user_krb5pwd(r, conf, auth_line);
950 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
951 strcasecmp(auth_type, "Basic") == 0)
952 ret = authenticate_user_krb4pwd(r, conf, auth_line);
955 if (ret == HTTP_UNAUTHORIZED)
956 note_kerb_auth_failure(r, conf);
962 /***************************************************************************
963 Module Setup/Configuration
964 ***************************************************************************/
966 module MODULE_VAR_EXPORT auth_kerb_module = {
967 STANDARD_MODULE_STUFF,
968 NULL, /* module initializer */
969 kerb_dir_create_config, /* per-directory config creator */
970 NULL, /* per-directory config merger */
971 NULL, /* per-server config creator */
972 NULL, /* per-server config merger */
973 kerb_auth_cmds, /* command table */
974 NULL, /* [ 9] content handlers */
975 NULL, /* [ 2] URI-to-filename translation */
976 kerb_authenticate_user, /* [ 5] check/validate user_id */
977 NULL, /* [ 6] check user_id is valid *here* */
978 NULL, /* [ 4] check access by host address */
979 NULL, /* [ 7] MIME type checker/setter */
980 NULL, /* [ 8] fixups */
981 NULL, /* [10] logger */
982 NULL, /* [ 3] header parser */
983 NULL, /* process initialization */
984 NULL, /* process exit/cleanup */
985 NULL /* [ 1] post read_request handling */
988 void kerb_register_hooks(apr_pool_t *p)
990 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
993 module AP_MODULE_DECLARE_DATA auth_kerb_module =
995 STANDARD20_MODULE_STUFF,
996 kerb_dir_create_config, /* create per-dir conf structures */
997 NULL, /* merge per-dir conf structures */
998 NULL, /* create per-server conf structures */
999 NULL, /* merge per-server conf structures */
1000 kerb_auth_cmds, /* table of configuration directives */
1001 kerb_register_hooks /* register hooks */