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,
321 krb5_principal server = NULL;
323 krb5_verify_init_creds_opt opt;
325 memset(&creds, 0, sizeof(creds));
327 ret = krb5_get_init_creds_password(context, &creds, principal, password,
328 krb5_prompter_posix, 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);
348 krb5_cc_close(context, ccache);
352 krb5_free_creds_contents(context, &creds);
354 krb5_free_principal(context, service);
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);
465 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
467 problem = krb5_cc_copy_creds(kcontext, delegated_cred, ccache);
469 krb5_free_principal(kcontext, princ);
471 snprintf(errstr, sizeof(errstr), "Failed to store credentials: %s",
472 krb5_get_err_text(kcontext, problem));
473 krb5_cc_destroy(kcontext, ccache);
474 return HTTP_INTERNAL_SERVER_ERROR;
477 krb5_cc_close(kcontext, ccache);
482 int authenticate_user_krb5pwd(request_rec *r,
483 kerb_auth_config *conf,
484 const char *auth_line)
486 const char *sent_pw = NULL;
487 const char *sent_name = NULL;
488 const char *realms = NULL;
489 const char *service_name = NULL;
490 krb5_context kcontext = NULL;
491 krb5_error_code code;
492 krb5_principal client = NULL;
493 krb5_ccache ccache = NULL;
497 code = krb5_init_context(&kcontext);
499 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
500 "Cannot initialize Kerberos5 context (%d)", code);
501 return HTTP_INTERNAL_SERVER_ERROR;
504 sent_pw = ap_pbase64decode(r->pool, auth_line);
505 sent_name = ap_getword (r->pool, &sent_pw, ':');
506 /* do not allow user to override realm setting of server */
507 if (strchr(sent_name, '@')) {
508 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
509 "specifying realm in user name is prohibited");
510 ret = HTTP_UNAUTHORIZED;
515 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
517 code = krb5_mcc_generate_new(kcontext, &ccache);
520 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
521 "Cannot generate new ccache: %s",
522 krb5_get_err_text(kcontext, code));
523 ret = HTTP_INTERNAL_SERVER_ERROR;
527 if (conf->krb_5_keytab)
528 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
529 /* kcontext->default_keytab = conf->krb_5_keytab; */
531 if (conf->service_name) {
533 service_name = ap_pstrdup(r->pool, conf->service_name);
534 if ((p=strchr(service_name, '/')))
537 service_name = "khttp";
539 realms = conf->krb_auth_realms;
541 if (realms && (code = krb5_set_default_realm(kcontext,
542 ap_getword_white(r->pool, &realms))))
546 krb5_free_principal(kcontext, client);
549 code = krb5_parse_name(kcontext, sent_name, &client);
553 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
558 /* ap_getword_white() used above shifts the parameter, so it's not
559 needed to touch the realms variable */
560 } while (realms && *realms);
562 memset((char *)sent_pw, 0, strlen(sent_pw));
565 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
566 "Verifying krb5 password failed: %s",
567 krb5_get_err_text(kcontext, code));
568 ret = HTTP_UNAUTHORIZED;
572 code = krb5_unparse_name(kcontext, client, &name);
574 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
575 krb5_get_err_text(kcontext, code));
576 ret = HTTP_UNAUTHORIZED;
579 MK_USER = ap_pstrdup (r->pool, name);
580 MK_AUTH_TYPE = "Basic";
583 if (conf->krb_save_credentials)
584 store_krb5_creds(kcontext, r, conf, ccache);
590 krb5_free_principal(kcontext, client);
592 krb5_cc_destroy(kcontext, ccache);
593 krb5_free_context(kcontext);
598 /*********************************************************************
599 * GSSAPI Authentication
600 ********************************************************************/
603 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
605 OM_uint32 maj_stat, min_stat;
606 OM_uint32 msg_ctx = 0;
607 gss_buffer_desc status_string;
611 snprintf(buf, sizeof(buf), "%s", prefix);
614 maj_stat = gss_display_status (&min_stat,
620 if (sizeof(buf) > len + status_string.length + 1) {
621 sprintf(buf+len, ": %s", (char*) status_string.value);
622 len += status_string.length;
624 gss_release_buffer(&min_stat, &status_string);
625 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
627 return (ap_pstrdup(p, buf));
631 cleanup_gss_connection(void *data)
633 OM_uint32 minor_status;
634 gss_connection_t *gss_conn = (gss_connection_t *)data;
638 if (gss_conn->context != GSS_C_NO_CONTEXT)
639 gss_delete_sec_context(&minor_status, &gss_conn->context,
641 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
642 gss_release_cred(&minor_status, &gss_conn->server_creds);
648 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
649 gss_cred_id_t delegated_cred)
651 OM_uint32 maj_stat, min_stat;
652 krb5_principal princ = NULL;
653 krb5_ccache ccache = NULL;
654 krb5_error_code problem;
655 krb5_context context;
656 int ret = HTTP_INTERNAL_SERVER_ERROR;
658 problem = krb5_init_context(&context);
660 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
661 return HTTP_INTERNAL_SERVER_ERROR;
664 problem = krb5_parse_name(context, princ_name, &princ);
666 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
667 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
671 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
673 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
674 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
678 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
679 if (GSS_ERROR(maj_stat)) {
680 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
681 "Cannot store delegated credential (%s)",
682 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
686 krb5_cc_close(context, ccache);
692 krb5_free_principal(context, princ);
694 krb5_cc_destroy(context, ccache);
695 krb5_free_context(context);
700 get_gss_creds(request_rec *r,
701 kerb_auth_config *conf,
702 gss_cred_id_t *server_creds)
704 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
705 OM_uint32 major_status, minor_status, minor_status2;
706 gss_name_t server_name = GSS_C_NO_NAME;
708 if (conf->service_name) {
709 input_token.value = conf->service_name;
710 input_token.length = strlen(conf->service_name) + 1;
713 input_token.value = "khttp";
714 input_token.length = 6;
716 major_status = gss_import_name(&minor_status, &input_token,
717 (conf->service_name) ?
718 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
720 if (GSS_ERROR(major_status)) {
721 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
722 "%s", get_gss_error(r->pool, minor_status,
723 "gss_import_name() failed"));
724 return HTTP_INTERNAL_SERVER_ERROR;
727 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
728 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
729 server_creds, NULL, NULL);
730 gss_release_name(&minor_status2, &server_name);
731 if (GSS_ERROR(major_status)) {
732 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
733 "%s", get_gss_error(r->pool, minor_status,
734 "gss_acquire_cred() failed"));
735 return HTTP_INTERNAL_SERVER_ERROR;
742 authenticate_user_gss(request_rec *r,
743 kerb_auth_config *conf,
744 const char *auth_line)
746 OM_uint32 major_status, minor_status, minor_status2;
747 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
748 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
749 const char *auth_param = NULL;
751 gss_name_t client_name = GSS_C_NO_NAME;
752 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
753 static int initial_return = HTTP_UNAUTHORIZED;
755 /* needed to work around replay caches */
756 if (!ap_is_initial_req(r))
757 return initial_return;
758 initial_return = HTTP_UNAUTHORIZED;
760 if (gss_connection == NULL) {
761 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
762 if (gss_connection == NULL) {
763 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
764 "ap_pcalloc() failed (not enough memory)");
765 ret = HTTP_INTERNAL_SERVER_ERROR;
768 memset(gss_connection, 0, sizeof(*gss_connection));
769 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
772 if (conf->krb_5_keytab)
773 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
775 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
776 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
781 /* ap_getword() shifts parameter */
782 auth_param = ap_getword_white(r->pool, &auth_line);
783 if (auth_param == NULL) {
784 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
785 "No Authorization parameter in request from client");
786 ret = HTTP_UNAUTHORIZED;
790 input_token.length = ap_base64decode_len(auth_param) + 1;
791 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
792 if (input_token.value == NULL) {
793 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
794 "ap_pcalloc() failed (not enough memory)");
795 ret = HTTP_INTERNAL_SERVER_ERROR;
798 input_token.length = ap_base64decode(input_token.value, auth_param);
800 major_status = gss_accept_sec_context(&minor_status,
801 &gss_connection->context,
802 gss_connection->server_creds,
804 GSS_C_NO_CHANNEL_BINDINGS,
811 if (output_token.length) {
815 len = ap_base64encode_len(output_token.length) + 1;
816 token = ap_pcalloc(r->connection->pool, len + 1);
818 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
819 "ap_pcalloc() failed (not enough memory)");
820 ret = HTTP_INTERNAL_SERVER_ERROR;
821 gss_release_buffer(&minor_status2, &output_token);
824 ap_base64encode(token, output_token.value, output_token.length);
826 ap_table_set(r->err_headers_out, "WWW-Authenticate",
827 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
828 gss_release_buffer(&minor_status2, &output_token);
831 if (GSS_ERROR(major_status)) {
832 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
833 "%s", get_gss_error(r->pool, minor_status,
834 "gss_accept_sec_context() failed"));
835 ret = HTTP_UNAUTHORIZED;
839 if (major_status & GSS_S_CONTINUE_NEEDED) {
840 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
841 * iterations to establish authentication */
842 ret = HTTP_UNAUTHORIZED;
846 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
847 gss_release_name(&minor_status, &client_name);
848 if (GSS_ERROR(major_status)) {
849 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
850 "%s", get_gss_error(r->pool, minor_status,
851 "gss_export_name() failed"));
852 ret = HTTP_INTERNAL_SERVER_ERROR;
856 MK_AUTH_TYPE = "Negotiate";
857 MK_USER = ap_pstrdup(r->pool, output_token.value);
859 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
860 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
862 gss_release_buffer(&minor_status, &output_token);
866 /* If the user comes from a realm specified by configuration don't include
867 its realm name in the username so that the authorization routine could
868 work for both Password-based and Ticket-based authentication. It's
869 administrators responsibility to include only such realm that have
870 unified principal instances, i.e. if the same principal name occures in
871 multiple realms, it must be always assigned to a single user.
873 p = strchr(r->connection->user, '@');
875 const char *realms = conf->gss_krb5_realms;
877 while (realms && *realms) {
878 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
890 gss_release_cred(&minor_status, &delegated_cred);
892 if (output_token.length)
893 gss_release_buffer(&minor_status, &output_token);
895 if (client_name != GSS_C_NO_NAME)
896 gss_release_name(&minor_status, &client_name);
898 initial_return = ret;
905 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
906 int use_krb4, int use_krb5)
908 const char *auth_name = NULL;
911 /* get the user realm specified in .htaccess */
912 auth_name = ap_auth_name(r);
914 /* XXX should the WWW-Authenticate header be cleared first? */
916 if (use_krb5 && conf->krb_method_gssapi)
917 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
918 if (use_krb5 && conf->krb_method_k5pass) {
919 ap_table_add(r->err_headers_out, "WWW-Authenticate",
920 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
926 if (use_krb4 && conf->krb_method_k4pass && !set_basic)
927 ap_table_add(r->err_headers_out, "WWW-Authenticate",
928 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
932 int kerb_authenticate_user(request_rec *r)
934 kerb_auth_config *conf =
935 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
937 const char *auth_type = NULL;
938 const char *auth_line = NULL;
939 const char *type = NULL;
940 int use_krb5 = 0, use_krb4 = 0;
943 /* get the type specified in .htaccess */
944 type = ap_auth_type(r);
946 if (type && strcasecmp(type, "Kerberos") == 0)
947 use_krb5 = use_krb4 = 1;
948 else if(type && strcasecmp(type, "KerberosV5") == 0)
950 else if(type && strcasecmp(type, "KerberosV4") == 0)
955 /* get what the user sent us in the HTTP header */
956 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
958 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
959 return HTTP_UNAUTHORIZED;
961 auth_type = ap_getword_white(r->pool, &auth_line);
963 ret = HTTP_UNAUTHORIZED;
966 if (use_krb5 && conf->krb_method_gssapi &&
967 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
968 ret = authenticate_user_gss(r, conf, auth_line);
969 } else if (use_krb5 && conf->krb_method_k5pass &&
970 strcasecmp(auth_type, "Basic") == 0) {
971 ret = authenticate_user_krb5pwd(r, conf, auth_line);
976 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
977 strcasecmp(auth_type, "Basic") == 0)
978 ret = authenticate_user_krb4pwd(r, conf, auth_line);
981 if (ret == HTTP_UNAUTHORIZED)
982 note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
988 /***************************************************************************
989 Module Setup/Configuration
990 ***************************************************************************/
992 module MODULE_VAR_EXPORT auth_kerb_module = {
993 STANDARD_MODULE_STUFF,
994 NULL, /* module initializer */
995 kerb_dir_create_config, /* per-directory config creator */
996 NULL, /* per-directory config merger */
997 NULL, /* per-server config creator */
998 NULL, /* per-server config merger */
999 kerb_auth_cmds, /* command table */
1000 NULL, /* [ 9] content handlers */
1001 NULL, /* [ 2] URI-to-filename translation */
1002 kerb_authenticate_user, /* [ 5] check/validate user_id */
1003 NULL, /* [ 6] check user_id is valid *here* */
1004 NULL, /* [ 4] check access by host address */
1005 NULL, /* [ 7] MIME type checker/setter */
1006 NULL, /* [ 8] fixups */
1007 NULL, /* [10] logger */
1008 NULL, /* [ 3] header parser */
1009 NULL, /* process initialization */
1010 NULL, /* process exit/cleanup */
1011 NULL /* [ 1] post read_request handling */
1014 void kerb_register_hooks(apr_pool_t *p)
1016 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1019 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1021 STANDARD20_MODULE_STUFF,
1022 kerb_dir_create_config, /* create per-dir conf structures */
1023 NULL, /* merge per-dir conf structures */
1024 NULL, /* create per-server conf structures */
1025 NULL, /* merge per-server conf structures */
1026 kerb_auth_cmds, /* table of configuration directives */
1027 kerb_register_hooks /* register hooks */