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);
650 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
651 gss_cred_id_t delegated_cred)
653 OM_uint32 maj_stat, min_stat;
654 krb5_principal princ = NULL;
655 krb5_ccache ccache = NULL;
656 krb5_error_code problem;
657 krb5_context context;
658 int ret = HTTP_INTERNAL_SERVER_ERROR;
660 problem = krb5_init_context(&context);
662 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
663 return HTTP_INTERNAL_SERVER_ERROR;
666 problem = krb5_parse_name(context, princ_name, &princ);
668 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
669 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
673 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
675 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
676 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
680 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
681 if (GSS_ERROR(maj_stat)) {
682 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
683 "Cannot store delegated credential (%s)",
684 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
688 krb5_cc_close(context, ccache);
694 krb5_free_principal(context, princ);
696 krb5_cc_destroy(context, ccache);
697 krb5_free_context(context);
702 get_gss_creds(request_rec *r,
703 kerb_auth_config *conf,
704 gss_cred_id_t *server_creds)
706 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
707 OM_uint32 major_status, minor_status, minor_status2;
708 gss_name_t server_name = GSS_C_NO_NAME;
710 if (conf->service_name) {
711 input_token.value = conf->service_name;
712 input_token.length = strlen(conf->service_name) + 1;
715 input_token.value = "khttp";
716 input_token.length = 6;
718 major_status = gss_import_name(&minor_status, &input_token,
719 (conf->service_name) ?
720 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
722 if (GSS_ERROR(major_status)) {
723 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
724 "%s", get_gss_error(r->pool, minor_status,
725 "gss_import_name() failed"));
726 return HTTP_INTERNAL_SERVER_ERROR;
729 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
730 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
731 server_creds, NULL, NULL);
732 gss_release_name(&minor_status2, &server_name);
733 if (GSS_ERROR(major_status)) {
734 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
735 "%s", get_gss_error(r->pool, minor_status,
736 "gss_acquire_cred() failed"));
737 return HTTP_INTERNAL_SERVER_ERROR;
744 authenticate_user_gss(request_rec *r,
745 kerb_auth_config *conf,
746 const char *auth_line)
748 OM_uint32 major_status, minor_status, minor_status2;
749 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
750 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
751 const char *auth_param = NULL;
753 gss_name_t client_name = GSS_C_NO_NAME;
754 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
755 static int initial_return = HTTP_UNAUTHORIZED;
757 /* needed to work around replay caches */
758 if (!ap_is_initial_req(r))
759 return initial_return;
760 initial_return = HTTP_UNAUTHORIZED;
762 if (gss_connection == NULL) {
763 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
764 if (gss_connection == NULL) {
765 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
766 "ap_pcalloc() failed (not enough memory)");
767 ret = HTTP_INTERNAL_SERVER_ERROR;
770 memset(gss_connection, 0, sizeof(*gss_connection));
771 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
774 if (conf->krb_5_keytab)
775 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
777 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
778 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
783 /* ap_getword() shifts parameter */
784 auth_param = ap_getword_white(r->pool, &auth_line);
785 if (auth_param == NULL) {
786 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
787 "No Authorization parameter in request from client");
788 ret = HTTP_UNAUTHORIZED;
792 input_token.length = ap_base64decode_len(auth_param) + 1;
793 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
794 if (input_token.value == NULL) {
795 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
796 "ap_pcalloc() failed (not enough memory)");
797 ret = HTTP_INTERNAL_SERVER_ERROR;
800 input_token.length = ap_base64decode(input_token.value, auth_param);
802 major_status = gss_accept_sec_context(&minor_status,
803 &gss_connection->context,
804 gss_connection->server_creds,
806 GSS_C_NO_CHANNEL_BINDINGS,
813 if (output_token.length) {
817 len = ap_base64encode_len(output_token.length) + 1;
818 token = ap_pcalloc(r->connection->pool, len + 1);
820 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
821 "ap_pcalloc() failed (not enough memory)");
822 ret = HTTP_INTERNAL_SERVER_ERROR;
823 gss_release_buffer(&minor_status2, &output_token);
826 ap_base64encode(token, output_token.value, output_token.length);
828 ap_table_set(r->err_headers_out, "WWW-Authenticate",
829 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
830 gss_release_buffer(&minor_status2, &output_token);
833 if (GSS_ERROR(major_status)) {
834 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
835 "%s", get_gss_error(r->pool, minor_status,
836 "gss_accept_sec_context() failed"));
837 ret = HTTP_UNAUTHORIZED;
841 if (major_status & GSS_S_CONTINUE_NEEDED) {
842 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
843 * iterations to establish authentication */
844 ret = HTTP_UNAUTHORIZED;
848 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
849 gss_release_name(&minor_status, &client_name);
850 if (GSS_ERROR(major_status)) {
851 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
852 "%s", get_gss_error(r->pool, minor_status,
853 "gss_export_name() failed"));
854 ret = HTTP_INTERNAL_SERVER_ERROR;
858 MK_AUTH_TYPE = "Negotiate";
859 MK_USER = ap_pstrdup(r->pool, output_token.value);
861 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
862 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
864 gss_release_buffer(&minor_status, &output_token);
868 /* If the user comes from a realm specified by configuration don't include
869 its realm name in the username so that the authorization routine could
870 work for both Password-based and Ticket-based authentication. It's
871 administrators responsibility to include only such realm that have
872 unified principal instances, i.e. if the same principal name occures in
873 multiple realms, it must be always assigned to a single user.
875 p = strchr(r->connection->user, '@');
877 const char *realms = conf->gss_krb5_realms;
879 while (realms && *realms) {
880 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
892 gss_release_cred(&minor_status, &delegated_cred);
894 if (output_token.length)
895 gss_release_buffer(&minor_status, &output_token);
897 if (client_name != GSS_C_NO_NAME)
898 gss_release_name(&minor_status, &client_name);
900 initial_return = ret;
907 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
908 int use_krb4, int use_krb5)
910 const char *auth_name = NULL;
913 /* get the user realm specified in .htaccess */
914 auth_name = ap_auth_name(r);
916 /* XXX should the WWW-Authenticate header be cleared first? */
918 if (use_krb5 && conf->krb_method_gssapi)
919 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
920 if (use_krb5 && conf->krb_method_k5pass) {
921 ap_table_add(r->err_headers_out, "WWW-Authenticate",
922 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
928 if (use_krb4 && conf->krb_method_k4pass && !set_basic)
929 ap_table_add(r->err_headers_out, "WWW-Authenticate",
930 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
934 int kerb_authenticate_user(request_rec *r)
936 kerb_auth_config *conf =
937 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
939 const char *auth_type = NULL;
940 const char *auth_line = NULL;
941 const char *type = NULL;
942 int use_krb5 = 0, use_krb4 = 0;
945 /* get the type specified in .htaccess */
946 type = ap_auth_type(r);
948 if (type && strcasecmp(type, "Kerberos") == 0)
949 use_krb5 = use_krb4 = 1;
950 else if(type && strcasecmp(type, "KerberosV5") == 0)
952 else if(type && strcasecmp(type, "KerberosV4") == 0)
957 /* get what the user sent us in the HTTP header */
958 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
960 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
961 return HTTP_UNAUTHORIZED;
963 auth_type = ap_getword_white(r->pool, &auth_line);
965 ret = HTTP_UNAUTHORIZED;
968 if (use_krb5 && conf->krb_method_gssapi &&
969 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
970 ret = authenticate_user_gss(r, conf, auth_line);
971 } else if (use_krb5 && conf->krb_method_k5pass &&
972 strcasecmp(auth_type, "Basic") == 0) {
973 ret = authenticate_user_krb5pwd(r, conf, auth_line);
978 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
979 strcasecmp(auth_type, "Basic") == 0)
980 ret = authenticate_user_krb4pwd(r, conf, auth_line);
983 if (ret == HTTP_UNAUTHORIZED)
984 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
990 /***************************************************************************
991 Module Setup/Configuration
992 ***************************************************************************/
994 module MODULE_VAR_EXPORT auth_kerb_module = {
995 STANDARD_MODULE_STUFF,
996 NULL, /* module initializer */
997 kerb_dir_create_config, /* per-directory config creator */
998 NULL, /* per-directory config merger */
999 NULL, /* per-server config creator */
1000 NULL, /* per-server config merger */
1001 kerb_auth_cmds, /* command table */
1002 NULL, /* [ 9] content handlers */
1003 NULL, /* [ 2] URI-to-filename translation */
1004 kerb_authenticate_user, /* [ 5] check/validate user_id */
1005 NULL, /* [ 6] check user_id is valid *here* */
1006 NULL, /* [ 4] check access by host address */
1007 NULL, /* [ 7] MIME type checker/setter */
1008 NULL, /* [ 8] fixups */
1009 NULL, /* [10] logger */
1010 NULL, /* [ 3] header parser */
1011 NULL, /* process initialization */
1012 NULL, /* process exit/cleanup */
1013 NULL /* [ 1] post read_request handling */
1016 void kerb_register_hooks(apr_pool_t *p)
1018 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1021 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1023 STANDARD20_MODULE_STUFF,
1024 kerb_dir_create_config, /* create per-dir conf structures */
1025 NULL, /* merge per-dir conf structures */
1026 NULL, /* create per-server conf structures */
1027 NULL, /* merge per-server conf structures */
1028 kerb_auth_cmds, /* table of configuration directives */
1029 kerb_register_hooks /* register hooks */