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;
66 int krb_method_gssapi;
67 int krb_method_k5pass;
71 int krb_method_k4pass;
76 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
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", krb5_save_realms, krb_auth_realms,
92 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
94 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
95 RAW_ARGS, "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("KrbServiceName", ap_set_string_slot, service_name,
112 TAKE1, "Kerberos service name to be used by apache."),
115 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
116 TAKE1, "Kerberos ticket lifetime."),
120 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
121 TAKE1, "Location of Kerberos V5 keytab file."),
123 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
124 FLAG, "Credentials retrieved will be flagged as forwardable."),
126 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
127 FLAG, "Enable GSSAPI authentication."),
129 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
130 FLAG, "Enable Kerberos V5 password authentication."),
134 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
135 TAKE1, "Location of Kerberos V4 srvtab file."),
137 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
138 FLAG, "Enable Kerberos V4 password authentication."),
146 gss_ctx_id_t context;
147 gss_cred_id_t server_creds;
150 static gss_connection_t *gss_connection = NULL;
154 /***************************************************************************
155 Auth Configuration Initialization
156 ***************************************************************************/
157 static void *kerb_dir_create_config(MK_POOL *p, char *d)
159 kerb_auth_config *rec;
161 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
162 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
164 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
165 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
168 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
174 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
176 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
180 void log_rerror(const char *file, int line, int level, int status,
181 const request_rec *r, const char *fmt, ...)
187 vsnprintf(errstr, sizeof(errstr), fmt, ap);
191 ap_log_rerror(file, line, level, r, "%s", errstr);
193 ap_log_rerror(file, line, level, status, r, "%s", errstr);
198 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
201 int offset = (int) (long) cmd->info;
202 if (!strncasecmp(arg, "unauthorized", 12))
203 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
204 else if (!strncasecmp(arg, "forbidden", 9))
205 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
206 else if (!strncasecmp(arg, "declined", 8))
207 *(int *) ((char *)struct_ptr + offset) = DECLINED;
209 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
215 /***************************************************************************
216 Username/Password Validation for Krb4
217 ***************************************************************************/
218 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
220 kerb_auth_config *conf =
221 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
224 int lifetime = DEFAULT_TKT_LIFE;
226 char *username = NULL;
227 char *instance = NULL;
230 username = (char *)ap_pstrdup(r->pool, user);
235 instance = strchr(username, '.');
243 realm = strchr(username, '@');
251 if (conf->krb_lifetime) {
252 lifetime = atoi(conf->krb_lifetime);
255 if (conf->krb_force_instance) {
256 instance = conf->krb_force_instance;
259 if (conf->krb_save_credentials) {
260 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
261 sprintf(tfname, "/tmp/k5cc_ap_%s", MK_USER);
263 if (!strcmp(instance, "")) {
264 tfname = strcat(tfname, ".");
265 tfname = strcat(tfname, instance);
268 if (!strcmp(realm, "")) {
269 tfname = strcat(tfname, ".");
270 tfname = strcat(tfname, realm);
273 for (c = tfname + strlen("/tmp") + 1; *c; c++) {
278 krb_set_tkt_string(tfname);
281 if (!strcmp(realm, "")) {
282 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
283 ret = krb_get_lrealm(realm, 1);
288 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
289 lifetime, (char *)pass);
304 /***************************************************************************
305 Username/Password Validation for Krb5
306 ***************************************************************************/
309 krb5_verify_user(krb5_context context, krb5_principal principal,
310 krb5_ccache ccache, const char *password, krb5_boolean secure,
314 krb5_context kcontext;
315 krb5_principal server, client;
318 krb5_flags options = 0;
319 krb5_principal me = NULL;
320 krb5_data tgtname = {
326 memset((char *)&my_creds, 0, sizeof(my_creds));
327 my_creds.client = principal;
329 if (krb5_build_principal_ext(kcontext, &server,
330 krb5_princ_realm(kcontext, me)->length,
331 krb5_princ_realm(kcontext, me)->data,
332 tgtname.length, tgtname.data,
333 krb5_princ_realm(kcontext, me)->length,
334 krb5_princ_realm(kcontext, me)->data,
339 my_creds.server = server;
340 if (krb5_timeofday(kcontext, &now))
343 my_creds.times.starttime = 0;
345 my_creds.times.endtime = now + lifetime;
346 my_creds.times.renew_till = now + renewal;
349 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
350 password, ccache, &my_creds, 0);
361 krb5_cache_cleanup(void *data)
363 krb5_context context;
365 krb5_error_code problem;
366 char *cache_name = (char *) data;
368 problem = krb5_init_context(&context);
370 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
371 return HTTP_INTERNAL_SERVER_ERROR;
374 problem = krb5_cc_resolve(context, cache_name, &cache);
376 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
377 "krb5_cc_resolve() failed (%s: %s)",
378 cache_name, krb5_get_err_text(context, problem)); */
379 return HTTP_INTERNAL_SERVER_ERROR;
382 krb5_cc_destroy(context, cache);
383 krb5_free_context(context);
388 create_krb5_ccache(krb5_context kcontext,
390 kerb_auth_config *conf,
391 krb5_principal princ,
395 krb5_error_code problem;
397 krb5_ccache tmp_ccache = NULL;
400 problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
402 problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
405 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
406 "Cannot create file for new krb5 ccache: %s",
407 krb5_get_err_text(kcontext, problem));
408 ret = HTTP_INTERNAL_SERVER_ERROR;
412 ccname = ap_pstrdup(r->pool, krb5_cc_get_name(kcontext, tmp_ccache));
414 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
416 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
417 "Cannot create krb5 ccache %s: krb5_cc_initialize() failed: %s",
418 ccname, krb5_get_err_text(kcontext, problem));
419 ret = HTTP_INTERNAL_SERVER_ERROR;
423 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
424 ap_register_cleanup(r->pool, ccname,
425 krb5_cache_cleanup, ap_null_cleanup);
427 *ccache = tmp_ccache;
434 krb5_cc_destroy(kcontext, tmp_ccache);
440 store_krb5_creds(krb5_context kcontext,
442 kerb_auth_config *conf,
443 krb5_ccache delegated_cred)
446 krb5_error_code problem;
447 krb5_principal princ;
451 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
453 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
454 krb5_get_err_text(kcontext, problem));
455 return HTTP_INTERNAL_SERVER_ERROR;
458 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
460 krb5_free_principal(kcontext, princ);
464 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
465 krb5_free_principal(kcontext, princ);
467 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
468 krb5_get_err_text(kcontext, problem));
469 krb5_cc_destroy(kcontext, ccache);
470 return HTTP_INTERNAL_SERVER_ERROR;
473 krb5_cc_close(kcontext, ccache);
478 int authenticate_user_krb5pwd(request_rec *r,
479 kerb_auth_config *conf,
480 const char *auth_line)
482 const char *sent_pw = NULL;
483 const char *sent_name = NULL;
484 const char *realms = NULL;
485 const char *service_name = NULL;
486 krb5_context kcontext = NULL;
487 krb5_error_code code;
488 krb5_principal client = NULL;
489 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 sent_name = ap_getword (r->pool, &sent_pw, ':');
502 /* do not allow user to override realm setting of server */
503 if (strchr(sent_name, '@')) {
504 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
505 "specifying realm in user name is prohibited");
506 ret = HTTP_UNAUTHORIZED;
511 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
513 code = krb5_mcc_generate_new(kcontext, &ccache);
516 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
517 "Cannot generate new ccache: %s",
518 krb5_get_err_text(kcontext, code));
519 ret = HTTP_INTERNAL_SERVER_ERROR;
523 if (conf->krb_5_keytab)
524 /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
525 kcontext->default_keytab = conf->krb_5_keytab;
527 if (conf->service_name) {
529 service_name = ap_pstrdup(r->pool, conf->service_name);
530 if ((p=strchr(service_name, '/')))
533 service_name = "khttp";
535 realms = conf->krb_auth_realms;
537 if (realms && (code = krb5_set_default_realm(kcontext,
538 ap_getword_white(r->pool, &realms))))
542 krb5_free_principal(kcontext, client);
545 code = krb5_parse_name(kcontext, sent_name, &client);
549 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
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 code = krb5_unparse_name(kcontext, client, &name);
570 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
571 krb5_get_err_text(kcontext, code));
572 ret = HTTP_UNAUTHORIZED;
575 MK_USER = ap_pstrdup (r->pool, name);
576 MK_AUTH_TYPE = "Basic";
579 if (conf->krb_save_credentials)
580 store_krb5_creds(kcontext, r, conf, ccache);
586 krb5_free_principal(kcontext, client);
588 krb5_cc_destroy(kcontext, ccache);
589 krb5_free_context(kcontext);
594 /*********************************************************************
595 * GSSAPI Authentication
596 ********************************************************************/
599 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
601 OM_uint32 maj_stat, min_stat;
602 OM_uint32 msg_ctx = 0;
603 gss_buffer_desc status_string;
607 snprintf(buf, sizeof(buf), "%s", prefix);
610 maj_stat = gss_display_status (&min_stat,
616 if (sizeof(buf) > len + status_string.length + 1) {
617 sprintf(buf+len, ": %s", (char*) status_string.value);
618 len += status_string.length;
620 gss_release_buffer(&min_stat, &status_string);
621 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
623 return (ap_pstrdup(p, buf));
627 cleanup_gss_connection(void *data)
629 OM_uint32 minor_status;
630 gss_connection_t *gss_conn = (gss_connection_t *)data;
634 if (gss_conn->context != GSS_C_NO_CONTEXT)
635 gss_delete_sec_context(&minor_status, &gss_conn->context,
637 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
638 gss_release_cred(&minor_status, &gss_conn->server_creds);
644 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
645 gss_cred_id_t delegated_cred)
647 OM_uint32 maj_stat, min_stat;
648 krb5_principal princ = NULL;
649 krb5_ccache ccache = NULL;
650 krb5_error_code problem;
651 krb5_context context;
652 int ret = HTTP_INTERNAL_SERVER_ERROR;
654 problem = krb5_init_context(&context);
656 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
657 return HTTP_INTERNAL_SERVER_ERROR;
660 problem = krb5_parse_name(context, princ_name, &princ);
662 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
663 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
667 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
669 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
670 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
674 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
675 if (GSS_ERROR(maj_stat)) {
676 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
677 "Cannot store delegated credential (%s)",
678 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
682 krb5_cc_close(context, ccache);
688 krb5_free_principal(context, princ);
690 krb5_cc_destroy(context, ccache);
691 krb5_free_context(context);
696 get_gss_creds(request_rec *r,
697 kerb_auth_config *conf,
698 gss_cred_id_t *server_creds)
700 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
701 OM_uint32 major_status, minor_status, minor_status2;
702 gss_name_t server_name = GSS_C_NO_NAME;
704 if (conf->service_name) {
705 input_token.value = conf->service_name;
706 input_token.length = strlen(conf->service_name) + 1;
709 input_token.value = "khttp";
710 input_token.length = 6;
712 major_status = gss_import_name(&minor_status, &input_token,
713 (conf->service_name) ?
714 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
716 if (GSS_ERROR(major_status)) {
717 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
718 "%s", get_gss_error(r->pool, minor_status,
719 "gss_import_name() failed"));
720 return HTTP_INTERNAL_SERVER_ERROR;
723 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
724 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
725 server_creds, NULL, NULL);
726 gss_release_name(&minor_status2, &server_name);
727 if (GSS_ERROR(major_status)) {
728 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
729 "%s", get_gss_error(r->pool, minor_status,
730 "gss_acquire_cred() failed"));
731 return HTTP_INTERNAL_SERVER_ERROR;
738 authenticate_user_gss(request_rec *r,
739 kerb_auth_config *conf,
740 const char *auth_line)
742 OM_uint32 major_status, minor_status, minor_status2;
743 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
744 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
745 const char *auth_param = NULL;
747 gss_name_t client_name = GSS_C_NO_NAME;
748 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
750 if (gss_connection == NULL) {
751 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
752 if (gss_connection == NULL) {
753 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
754 "ap_pcalloc() failed (not enough memory)");
755 ret = HTTP_INTERNAL_SERVER_ERROR;
758 memset(gss_connection, 0, sizeof(*gss_connection));
759 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
762 if (conf->krb_5_keytab)
763 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
765 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
766 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
771 /* ap_getword() shifts parameter */
772 auth_param = ap_getword_white(r->pool, &auth_line);
773 if (auth_param == NULL) {
774 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
775 "No Authorization parameter in request from client");
776 ret = HTTP_UNAUTHORIZED;
780 input_token.length = ap_base64decode_len(auth_param) + 1;
781 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
782 if (input_token.value == NULL) {
783 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
784 "ap_pcalloc() failed (not enough memory)");
785 ret = HTTP_INTERNAL_SERVER_ERROR;
788 input_token.length = ap_base64decode(input_token.value, auth_param);
790 major_status = gss_accept_sec_context(&minor_status,
791 &gss_connection->context,
792 gss_connection->server_creds,
794 GSS_C_NO_CHANNEL_BINDINGS,
801 if (output_token.length) {
805 len = ap_base64encode_len(output_token.length) + 1;
806 token = ap_pcalloc(r->connection->pool, len + 1);
808 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
809 "ap_pcalloc() failed (not enough memory)");
810 ret = HTTP_INTERNAL_SERVER_ERROR;
811 gss_release_buffer(&minor_status2, &output_token);
814 ap_base64encode(token, output_token.value, output_token.length);
816 ap_table_set(r->err_headers_out, "WWW-Authenticate",
817 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
818 gss_release_buffer(&minor_status2, &output_token);
821 if (GSS_ERROR(major_status)) {
822 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
823 "%s", get_gss_error(r->pool, minor_status,
824 "gss_accept_sec_context() failed"));
825 ret = HTTP_UNAUTHORIZED;
829 if (major_status & GSS_S_CONTINUE_NEEDED) {
830 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
831 * iterations to establish authentication */
832 ret = HTTP_UNAUTHORIZED;
836 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
837 gss_release_name(&minor_status, &client_name);
838 if (GSS_ERROR(major_status)) {
839 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
840 "%s", get_gss_error(r->pool, minor_status,
841 "gss_export_name() failed"));
842 ret = HTTP_INTERNAL_SERVER_ERROR;
846 MK_AUTH_TYPE = "Negotiate";
847 MK_USER = ap_pstrdup(r->pool, output_token.value);
849 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
850 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
852 gss_release_buffer(&minor_status, &output_token);
856 /* If the user comes from a realm specified by configuration don't include
857 its realm name in the username so that the authorization routine could
858 work for both Password-based and Ticket-based authentication. It's
859 administrators responsibility to include only such realm that have
860 unified principal instances, i.e. if the same principal name occures in
861 multiple realms, it must be always assigned to a single user.
863 p = strchr(r->connection->user, '@');
865 const char *realms = conf->gss_krb5_realms;
867 while (realms && *realms) {
868 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
880 gss_release_cred(&minor_status, &delegated_cred);
882 if (output_token.length)
883 gss_release_buffer(&minor_status, &output_token);
885 if (client_name != GSS_C_NO_NAME)
886 gss_release_name(&minor_status, &client_name);
894 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
896 const char *auth_name = NULL;
898 /* get the user realm specified in .htaccess */
899 auth_name = ap_auth_name(r);
901 /* XXX check AuthType */
903 /* XXX should the WWW-Authenticate header be cleared first? */
905 if (conf->krb_method_gssapi)
906 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
907 if (conf->krb_method_k5pass)
908 ap_table_add(r->err_headers_out, "WWW-Authenticate",
909 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
913 if (conf->krb_method_k4pass)
914 ap_table_add(r->err_headers_out, "WWW-Authenticate",
915 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
919 int kerb_authenticate_user(request_rec *r)
921 kerb_auth_config *conf =
922 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
924 const char *auth_type = NULL;
925 const char *auth_line = NULL;
926 const char *type = NULL;
927 int use_krb5 = 0, use_krb4 = 0;
930 /* get the type specified in .htaccess */
931 type = ap_auth_type(r);
933 if (type && strcasecmp(type, "Kerberos") == 0)
934 use_krb5 = use_krb4 = 1;
935 else if(type && strcasecmp(type, "KerberosV5") == 0)
937 else if (type && strcasecmp(type, "KerberosV4") == 0)
942 /* get what the user sent us in the HTTP header */
943 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
945 note_kerb_auth_failure(r, conf);
946 return HTTP_UNAUTHORIZED;
948 auth_type = ap_getword_white(r->pool, &auth_line);
950 ret = HTTP_UNAUTHORIZED;
953 if (use_krb5 && conf->krb_method_gssapi &&
954 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
955 ret = authenticate_user_gss(r, conf, auth_line);
956 } else if (use_krb5 && conf->krb_method_k5pass &&
957 strcasecmp(auth_type, "Basic") == 0) {
958 ret = authenticate_user_krb5pwd(r, conf, auth_line);
963 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
964 strcasecmp(auth_type, "Basic") == 0)
965 ret = authenticate_user_krb4pwd(r, conf, auth_line);
968 if (ret == HTTP_UNAUTHORIZED)
969 note_kerb_auth_failure(r, conf);
975 /***************************************************************************
976 Module Setup/Configuration
977 ***************************************************************************/
979 module MODULE_VAR_EXPORT auth_kerb_module = {
980 STANDARD_MODULE_STUFF,
981 NULL, /* module initializer */
982 kerb_dir_create_config, /* per-directory config creator */
983 NULL, /* per-directory config merger */
984 NULL, /* per-server config creator */
985 NULL, /* per-server config merger */
986 kerb_auth_cmds, /* command table */
987 NULL, /* [ 9] content handlers */
988 NULL, /* [ 2] URI-to-filename translation */
989 kerb_authenticate_user, /* [ 5] check/validate user_id */
990 NULL, /* [ 6] check user_id is valid *here* */
991 NULL, /* [ 4] check access by host address */
992 NULL, /* [ 7] MIME type checker/setter */
993 NULL, /* [ 8] fixups */
994 NULL, /* [10] logger */
995 NULL, /* [ 3] header parser */
996 NULL, /* process initialization */
997 NULL, /* process exit/cleanup */
998 NULL /* [ 1] post read_request handling */
1001 void kerb_register_hooks(apr_pool_t *p)
1003 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1006 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1008 STANDARD20_MODULE_STUFF,
1009 kerb_dir_create_config, /* create per-dir conf structures */
1010 NULL, /* merge per-dir conf structures */
1011 NULL, /* create per-server conf structures */
1012 NULL, /* merge per-server conf structures */
1013 kerb_auth_cmds, /* table of configuration directives */
1014 kerb_register_hooks /* register hooks */