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;
65 char *krb_force_instance;
66 int krb_save_credentials;
72 int krb_method_gssapi;
73 int krb_method_k5pass;
77 int krb_method_k4pass;
82 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
85 #define command(name, func, var, type, usage) \
87 (void*)XtOffsetOf(kerb_auth_config, var), \
88 OR_AUTHCFG, type, usage }
90 #define command(name, func, var, type, usage) \
91 AP_INIT_ ## type (name, func, \
92 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
96 static const command_rec kerb_auth_cmds[] = {
97 command("KrbAuthRealm", krb5_save_realms, krb_auth_realms,
98 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
100 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
101 RAW_ARGS, "Alias for KrbAuthRealm."),
104 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
105 TAKE1, "If auth fails, return status set here."),
108 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
109 TAKE1, "Force authentication against an instance specified here."),
111 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
112 FLAG, "Save and store credentials/tickets retrieved during auth."),
114 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
115 FLAG, "Alias for KrbSaveCredentials."),
117 command("KrbServiceName", ap_set_string_slot, service_name,
118 TAKE1, "Kerberos service name to be used by apache."),
121 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
122 TAKE1, "Kerberos ticket lifetime."),
126 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
127 TAKE1, "Location of Kerberos V5 keytab file."),
129 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
130 FLAG, "Credentials retrieved will be flagged as forwardable."),
132 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
133 FLAG, "Enable GSSAPI authentication."),
135 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
136 FLAG, "Enable Kerberos V5 password authentication."),
140 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
141 TAKE1, "Location of Kerberos V4 srvtab file."),
143 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
144 FLAG, "Enable Kerberos V4 password authentication."),
152 gss_ctx_id_t context;
153 gss_cred_id_t server_creds;
156 static gss_connection_t *gss_connection = NULL;
160 /***************************************************************************
161 Auth Configuration Initialization
162 ***************************************************************************/
163 static void *kerb_dir_create_config(MK_POOL *p, char *d)
165 kerb_auth_config *rec;
167 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
168 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
170 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
171 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
174 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
180 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
182 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
186 void log_rerror(const char *file, int line, int level, int status,
187 const request_rec *r, const char *fmt, ...)
193 vsnprintf(errstr, sizeof(errstr), fmt, ap);
197 ap_log_rerror(file, line, level, r, "%s", errstr);
199 ap_log_rerror(file, line, level, status, r, "%s", errstr);
204 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
207 int offset = (int) (long) cmd->info;
208 if (!strncasecmp(arg, "unauthorized", 12))
209 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
210 else if (!strncasecmp(arg, "forbidden", 9))
211 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
212 else if (!strncasecmp(arg, "declined", 8))
213 *(int *) ((char *)struct_ptr + offset) = DECLINED;
215 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
221 /***************************************************************************
222 Username/Password Validation for Krb4
223 ***************************************************************************/
224 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
226 kerb_auth_config *conf =
227 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
230 int lifetime = DEFAULT_TKT_LIFE;
232 char *username = NULL;
233 char *instance = NULL;
236 username = (char *)ap_pstrdup(r->pool, user);
241 instance = strchr(username, '.');
249 realm = strchr(username, '@');
257 if (conf->krb_lifetime) {
258 lifetime = atoi(conf->krb_lifetime);
261 if (conf->krb_force_instance) {
262 instance = conf->krb_force_instance;
265 if (conf->krb_save_credentials) {
266 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
267 sprintf(tfname, "/tmp/k5cc_ap_%s", MK_USER);
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("/tmp") + 1; *c; c++) {
284 krb_set_tkt_string(tfname);
287 if (!strcmp(realm, "")) {
288 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
289 ret = krb_get_lrealm(realm, 1);
294 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
295 lifetime, (char *)pass);
310 /***************************************************************************
311 Username/Password Validation for Krb5
312 ***************************************************************************/
315 krb5_verify_user(krb5_context context, krb5_principal principal,
316 krb5_ccache ccache, const char *password, krb5_boolean secure,
320 krb5_principal server = NULL;
322 krb5_verify_init_creds_opt opt;
324 memset(&creds, 0, sizeof(creds));
326 ret = krb5_get_init_creds_password(context, &creds, principal,
327 (char *)password, krb5_prompter_posix,
328 NULL, 0, NULL, NULL);
332 ret = krb5_sname_to_principal(context, NULL, service,
333 KRB5_NT_SRV_HST, &server);
337 krb5_verify_init_creds_opt_init(&opt);
338 krb5_verify_init_creds_opt_set_ap_req_nofail(&opt, secure);
340 ret = krb5_verify_init_creds(context, &creds, server, NULL, NULL, &opt);
345 ret = krb5_cc_initialize(context, ccache, principal);
347 ret = krb5_cc_store_cred(context, ccache, &creds);
351 krb5_free_cred_contents(context, &creds);
353 krb5_free_principal(context, server);
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,
394 krb5_error_code problem;
396 krb5_ccache tmp_ccache = NULL;
399 problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
401 problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
402 /* krb5_fcc_generate_new() doesn't set KRB5_TC_OPENCLOSE, which makes
403 krb5_cc_initialize() fail */
404 krb5_fcc_set_flags(kcontext, tmp_ccache, KRB5_TC_OPENCLOSE);
407 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
408 "Cannot create file for new krb5 ccache: %s",
409 krb5_get_err_text(kcontext, problem));
410 ret = HTTP_INTERNAL_SERVER_ERROR;
414 ccname = ap_pstrdup(r->pool, krb5_cc_get_name(kcontext, tmp_ccache));
416 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
418 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
419 "Cannot initialize krb5 ccache %s: krb5_cc_initialize() failed: %s",
420 ccname, krb5_get_err_text(kcontext, problem));
421 ret = HTTP_INTERNAL_SERVER_ERROR;
425 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
426 ap_register_cleanup(r->pool, ccname,
427 krb5_cache_cleanup, ap_null_cleanup);
429 *ccache = tmp_ccache;
436 krb5_cc_destroy(kcontext, tmp_ccache);
442 store_krb5_creds(krb5_context kcontext,
444 kerb_auth_config *conf,
445 krb5_ccache delegated_cred)
448 krb5_error_code problem;
449 krb5_principal princ;
453 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
455 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
456 krb5_get_err_text(kcontext, problem));
457 return HTTP_INTERNAL_SERVER_ERROR;
460 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
462 krb5_free_principal(kcontext, princ);
467 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
469 problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
471 krb5_free_principal(kcontext, princ);
473 snprintf(errstr, sizeof(errstr), "Failed to store credentials: %s",
474 krb5_get_err_text(kcontext, problem));
475 krb5_cc_destroy(kcontext, ccache);
476 return HTTP_INTERNAL_SERVER_ERROR;
479 krb5_cc_close(kcontext, ccache);
484 int authenticate_user_krb5pwd(request_rec *r,
485 kerb_auth_config *conf,
486 const char *auth_line)
488 const char *sent_pw = NULL;
489 const char *sent_name = NULL;
490 const char *realms = NULL;
491 const char *service_name = NULL;
492 krb5_context kcontext = NULL;
493 krb5_error_code code;
494 krb5_principal client = NULL;
495 krb5_ccache ccache = NULL;
499 code = krb5_init_context(&kcontext);
501 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
502 "Cannot initialize Kerberos5 context (%d)", code);
503 return HTTP_INTERNAL_SERVER_ERROR;
506 sent_pw = ap_pbase64decode(r->pool, auth_line);
507 sent_name = ap_getword (r->pool, &sent_pw, ':');
508 /* do not allow user to override realm setting of server */
509 if (strchr(sent_name, '@')) {
510 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
511 "specifying realm in user name is prohibited");
512 ret = HTTP_UNAUTHORIZED;
517 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
519 code = krb5_mcc_generate_new(kcontext, &ccache);
522 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
523 "Cannot generate new ccache: %s",
524 krb5_get_err_text(kcontext, code));
525 ret = HTTP_INTERNAL_SERVER_ERROR;
529 if (conf->krb_5_keytab)
530 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
531 /* kcontext->default_keytab = conf->krb_5_keytab; */
533 if (conf->service_name) {
535 service_name = ap_pstrdup(r->pool, conf->service_name);
536 if ((p=strchr(service_name, '/')))
539 service_name = "khttp";
541 realms = conf->krb_auth_realms;
543 if (realms && (code = krb5_set_default_realm(kcontext,
544 ap_getword_white(r->pool, &realms))))
548 krb5_free_principal(kcontext, client);
551 code = krb5_parse_name(kcontext, sent_name, &client);
555 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
560 /* ap_getword_white() used above shifts the parameter, so it's not
561 needed to touch the realms variable */
562 } while (realms && *realms);
564 memset((char *)sent_pw, 0, strlen(sent_pw));
567 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
568 "Verifying krb5 password failed: %s",
569 krb5_get_err_text(kcontext, code));
570 ret = HTTP_UNAUTHORIZED;
574 code = krb5_unparse_name(kcontext, client, &name);
576 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
577 krb5_get_err_text(kcontext, code));
578 ret = HTTP_UNAUTHORIZED;
581 MK_USER = ap_pstrdup (r->pool, name);
582 MK_AUTH_TYPE = "Basic";
585 if (conf->krb_save_credentials)
586 store_krb5_creds(kcontext, r, conf, ccache);
592 krb5_free_principal(kcontext, client);
594 krb5_cc_destroy(kcontext, ccache);
595 krb5_free_context(kcontext);
600 /*********************************************************************
601 * GSSAPI Authentication
602 ********************************************************************/
605 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
607 OM_uint32 maj_stat, min_stat;
608 OM_uint32 msg_ctx = 0;
609 gss_buffer_desc status_string;
613 snprintf(buf, sizeof(buf), "%s", prefix);
616 maj_stat = gss_display_status (&min_stat,
622 if (sizeof(buf) > len + status_string.length + 1) {
623 sprintf(buf+len, ": %s", (char*) status_string.value);
624 len += status_string.length;
626 gss_release_buffer(&min_stat, &status_string);
627 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
629 return (ap_pstrdup(p, buf));
633 cleanup_gss_connection(void *data)
635 OM_uint32 minor_status;
636 gss_connection_t *gss_conn = (gss_connection_t *)data;
640 if (gss_conn->context != GSS_C_NO_CONTEXT)
641 gss_delete_sec_context(&minor_status, &gss_conn->context,
643 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
644 gss_release_cred(&minor_status, &gss_conn->server_creds);
646 gss_connection = NULL;
652 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
653 gss_cred_id_t delegated_cred)
655 OM_uint32 maj_stat, min_stat;
656 krb5_principal princ = NULL;
657 krb5_ccache ccache = NULL;
658 krb5_error_code problem;
659 krb5_context context;
660 int ret = HTTP_INTERNAL_SERVER_ERROR;
662 problem = krb5_init_context(&context);
664 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
665 return HTTP_INTERNAL_SERVER_ERROR;
668 problem = krb5_parse_name(context, princ_name, &princ);
670 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
671 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
675 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
677 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
678 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
682 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
683 if (GSS_ERROR(maj_stat)) {
684 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
685 "Cannot store delegated credential (%s)",
686 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
690 krb5_cc_close(context, ccache);
696 krb5_free_principal(context, princ);
698 krb5_cc_destroy(context, ccache);
699 krb5_free_context(context);
704 get_gss_creds(request_rec *r,
705 kerb_auth_config *conf,
706 gss_cred_id_t *server_creds)
708 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
709 OM_uint32 major_status, minor_status, minor_status2;
710 gss_name_t server_name = GSS_C_NO_NAME;
712 if (conf->service_name) {
713 input_token.value = conf->service_name;
714 input_token.length = strlen(conf->service_name) + 1;
717 input_token.value = "khttp";
718 input_token.length = 6;
720 major_status = gss_import_name(&minor_status, &input_token,
721 (conf->service_name) ?
722 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
724 if (GSS_ERROR(major_status)) {
725 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
726 "%s", get_gss_error(r->pool, minor_status,
727 "gss_import_name() failed"));
728 return HTTP_INTERNAL_SERVER_ERROR;
731 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
732 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
733 server_creds, NULL, NULL);
734 gss_release_name(&minor_status2, &server_name);
735 if (GSS_ERROR(major_status)) {
736 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
737 "%s", get_gss_error(r->pool, minor_status,
738 "gss_acquire_cred() failed"));
739 return HTTP_INTERNAL_SERVER_ERROR;
746 authenticate_user_gss(request_rec *r,
747 kerb_auth_config *conf,
748 const char *auth_line)
750 OM_uint32 major_status, minor_status, minor_status2;
751 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
752 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
753 const char *auth_param = NULL;
755 gss_name_t client_name = GSS_C_NO_NAME;
756 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
757 static int initial_return = HTTP_UNAUTHORIZED;
759 /* needed to work around replay caches */
760 if (!ap_is_initial_req(r))
761 return initial_return;
762 initial_return = HTTP_UNAUTHORIZED;
764 if (gss_connection == NULL) {
765 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
766 if (gss_connection == NULL) {
767 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
768 "ap_pcalloc() failed (not enough memory)");
769 ret = HTTP_INTERNAL_SERVER_ERROR;
772 memset(gss_connection, 0, sizeof(*gss_connection));
773 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
776 if (conf->krb_5_keytab)
777 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
779 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
780 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
785 /* ap_getword() shifts parameter */
786 auth_param = ap_getword_white(r->pool, &auth_line);
787 if (auth_param == NULL) {
788 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
789 "No Authorization parameter in request from client");
790 ret = HTTP_UNAUTHORIZED;
794 input_token.length = ap_base64decode_len(auth_param) + 1;
795 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
796 if (input_token.value == NULL) {
797 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
798 "ap_pcalloc() failed (not enough memory)");
799 ret = HTTP_INTERNAL_SERVER_ERROR;
802 input_token.length = ap_base64decode(input_token.value, auth_param);
804 major_status = gss_accept_sec_context(&minor_status,
805 &gss_connection->context,
806 gss_connection->server_creds,
808 GSS_C_NO_CHANNEL_BINDINGS,
815 if (output_token.length) {
819 len = ap_base64encode_len(output_token.length) + 1;
820 token = ap_pcalloc(r->connection->pool, len + 1);
822 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
823 "ap_pcalloc() failed (not enough memory)");
824 ret = HTTP_INTERNAL_SERVER_ERROR;
825 gss_release_buffer(&minor_status2, &output_token);
828 ap_base64encode(token, output_token.value, output_token.length);
830 ap_table_set(r->err_headers_out, "WWW-Authenticate",
831 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
832 gss_release_buffer(&minor_status2, &output_token);
835 if (GSS_ERROR(major_status)) {
836 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
837 "%s", get_gss_error(r->pool, minor_status,
838 "gss_accept_sec_context() failed"));
839 ret = HTTP_UNAUTHORIZED;
843 if (major_status & GSS_S_CONTINUE_NEEDED) {
844 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
845 * iterations to establish authentication */
846 ret = HTTP_UNAUTHORIZED;
850 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
851 gss_release_name(&minor_status, &client_name);
852 if (GSS_ERROR(major_status)) {
853 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
854 "%s", get_gss_error(r->pool, minor_status,
855 "gss_export_name() failed"));
856 ret = HTTP_INTERNAL_SERVER_ERROR;
860 MK_AUTH_TYPE = "Negotiate";
861 MK_USER = ap_pstrdup(r->pool, output_token.value);
863 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
864 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
866 gss_release_buffer(&minor_status, &output_token);
869 /* If the user comes from a realm specified by configuration don't include
870 its realm name in the username so that the authorization routine could
871 work for both Password-based and Ticket-based authentication. It's
872 administrators responsibility to include only such realm that have
873 unified principal instances, i.e. if the same principal name occures in
874 multiple realms, it must be always assigned to a single user.
876 p = strchr(r->connection->user, '@');
878 const char *realms = conf->gss_krb5_realms;
880 while (realms && *realms) {
881 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
893 gss_release_cred(&minor_status, &delegated_cred);
895 if (output_token.length)
896 gss_release_buffer(&minor_status, &output_token);
898 if (client_name != GSS_C_NO_NAME)
899 gss_release_name(&minor_status, &client_name);
901 cleanup_gss_connection(gss_connection);
903 initial_return = ret;
910 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
911 int use_krb4, int use_krb5)
913 const char *auth_name = NULL;
916 /* get the user realm specified in .htaccess */
917 auth_name = ap_auth_name(r);
919 /* XXX should the WWW-Authenticate header be cleared first? */
921 if (use_krb5 && conf->krb_method_gssapi)
922 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
923 if (use_krb5 && conf->krb_method_k5pass) {
924 ap_table_add(r->err_headers_out, "WWW-Authenticate",
925 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
931 if (use_krb4 && conf->krb_method_k4pass && !set_basic)
932 ap_table_add(r->err_headers_out, "WWW-Authenticate",
933 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
937 int kerb_authenticate_user(request_rec *r)
939 kerb_auth_config *conf =
940 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
942 const char *auth_type = NULL;
943 const char *auth_line = NULL;
944 const char *type = NULL;
945 int use_krb5 = 0, use_krb4 = 0;
948 /* get the type specified in .htaccess */
949 type = ap_auth_type(r);
951 if (type && strcasecmp(type, "Kerberos") == 0)
952 use_krb5 = use_krb4 = 1;
953 else if(type && strcasecmp(type, "KerberosV5") == 0)
955 else if(type && strcasecmp(type, "KerberosV4") == 0)
960 /* get what the user sent us in the HTTP header */
961 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
963 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
964 return HTTP_UNAUTHORIZED;
966 auth_type = ap_getword_white(r->pool, &auth_line);
968 ret = HTTP_UNAUTHORIZED;
971 if (use_krb5 && conf->krb_method_gssapi &&
972 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
973 ret = authenticate_user_gss(r, conf, auth_line);
974 } else if (use_krb5 && conf->krb_method_k5pass &&
975 strcasecmp(auth_type, "Basic") == 0) {
976 ret = authenticate_user_krb5pwd(r, conf, auth_line);
981 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
982 strcasecmp(auth_type, "Basic") == 0)
983 ret = authenticate_user_krb4pwd(r, conf, auth_line);
986 if (ret == HTTP_UNAUTHORIZED)
987 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
993 /***************************************************************************
994 Module Setup/Configuration
995 ***************************************************************************/
997 module MODULE_VAR_EXPORT auth_kerb_module = {
998 STANDARD_MODULE_STUFF,
999 NULL, /* module initializer */
1000 kerb_dir_create_config, /* per-directory config creator */
1001 NULL, /* per-directory config merger */
1002 NULL, /* per-server config creator */
1003 NULL, /* per-server config merger */
1004 kerb_auth_cmds, /* command table */
1005 NULL, /* [ 9] content handlers */
1006 NULL, /* [ 2] URI-to-filename translation */
1007 kerb_authenticate_user, /* [ 5] check/validate user_id */
1008 NULL, /* [ 6] check user_id is valid *here* */
1009 NULL, /* [ 4] check access by host address */
1010 NULL, /* [ 7] MIME type checker/setter */
1011 NULL, /* [ 8] fixups */
1012 NULL, /* [10] logger */
1013 NULL, /* [ 3] header parser */
1014 NULL, /* process initialization */
1015 NULL, /* process exit/cleanup */
1016 NULL /* [ 1] post read_request handling */
1019 void kerb_register_hooks(apr_pool_t *p)
1021 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1024 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1026 STANDARD20_MODULE_STUFF,
1027 kerb_dir_create_config, /* create per-dir conf structures */
1028 NULL, /* merge per-dir conf structures */
1029 NULL, /* create per-server conf structures */
1030 NULL, /* merge per-server conf structures */
1031 kerb_auth_cmds, /* table of configuration directives */
1032 kerb_register_hooks /* register hooks */