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;
67 int krb_method_gssapi;
68 int krb_method_k5pass;
72 int krb_method_k4pass;
77 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg);
80 #define command(name, func, var, type, usage) \
82 (void*)XtOffsetOf(kerb_auth_config, var), \
83 OR_AUTHCFG, type, usage }
85 #define command(name, func, var, type, usage) \
86 AP_INIT_ ## type (name, func, \
87 (void*)APR_XtOffsetOf(kerb_auth_config, var), \
91 static const command_rec kerb_auth_cmds[] = {
92 command("KrbAuthRealm", krb5_save_realms, krb_auth_realms,
93 RAW_ARGS, "Realms to attempt authentication against (can be multiple)."),
95 command("KrbAuthRealms", krb5_save_realms, krb_auth_realms,
96 RAW_ARGS, "Alias for KrbAuthRealm."),
99 command("KrbFailStatus", kerb_set_fail_slot, krb_fail_status,
100 TAKE1, "If auth fails, return status set here."),
103 command("KrbForceInstance", ap_set_string_slot, krb_force_instance,
104 TAKE1, "Force authentication against an instance specified here."),
106 command("KrbSaveCredentials", ap_set_flag_slot, krb_save_credentials,
107 FLAG, "Save and store credentials/tickets retrieved during auth."),
109 command("KrbSaveTickets", ap_set_flag_slot, krb_save_credentials,
110 FLAG, "Alias for KrbSaveCredentials."),
112 command("KrbTmpdir", ap_set_string_slot, krb_tmp_dir,
113 TAKE1, "Path to store ticket files and such in."),
115 command("KrbServiceName", ap_set_string_slot, service_name,
116 TAKE1, "Kerberos service name to be used by apache."),
119 command("KrbLifetime", ap_set_string_slot, krb_lifetime,
120 TAKE1, "Kerberos ticket lifetime."),
124 command("Krb5Keytab", ap_set_file_slot, krb_5_keytab,
125 TAKE1, "Location of Kerberos V5 keytab file."),
127 command("KrbForwardable", ap_set_flag_slot, krb_forwardable,
128 FLAG, "Credentials retrieved will be flagged as forwardable."),
130 command("KrbMethodGSSAPI", ap_set_flag_slot, krb_method_gssapi,
131 FLAG, "Enable GSSAPI authentication."),
133 command("KrbMethodK5Pass", ap_set_flag_slot, krb_method_k5pass,
134 FLAG, "Enable Kerberos V5 password authentication."),
138 command("Krb4Srvtab", ap_set_file_slot, krb_4_srvtab,
139 TAKE1, "Location of Kerberos V4 srvtab file."),
141 command("KrbMethodK4Pass", ap_set_flag_slot, krb_method_k4pass,
142 FLAG, "Enable Kerberos V4 password authentication."),
150 gss_ctx_id_t context;
151 gss_cred_id_t server_creds;
154 static gss_connection_t *gss_connection = NULL;
158 /***************************************************************************
159 Auth Configuration Initialization
160 ***************************************************************************/
161 static void *kerb_dir_create_config(MK_POOL *p, char *d)
163 kerb_auth_config *rec;
165 rec = (kerb_auth_config *) ap_pcalloc(p, sizeof(kerb_auth_config));
166 ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED;
168 ((kerb_auth_config *)rec)->krb_method_k5pass = 1;
169 ((kerb_auth_config *)rec)->krb_method_gssapi = 1;
172 ((kerb_auth_config *)rec)->krb_method_k4pass = 1;
178 krb5_save_realms(cmd_parms *cmd, kerb_auth_config *sec, char *arg)
180 sec->krb_auth_realms= ap_pstrdup(cmd->pool, arg);
184 void log_rerror(const char *file, int line, int level, int status,
185 const request_rec *r, const char *fmt, ...)
191 vsnprintf(errstr, sizeof(errstr), fmt, ap);
195 ap_log_rerror(file, line, level, r, "%s", errstr);
197 ap_log_rerror(file, line, level, status, r, "%s", errstr);
202 static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr,
205 int offset = (int) (long) cmd->info;
206 if (!strncasecmp(arg, "unauthorized", 12))
207 *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED;
208 else if (!strncasecmp(arg, "forbidden", 9))
209 *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN;
210 else if (!strncasecmp(arg, "declined", 8))
211 *(int *) ((char *)struct_ptr + offset) = DECLINED;
213 return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined.";
219 /***************************************************************************
220 Username/Password Validation for Krb4
221 ***************************************************************************/
222 int kerb4_password_validate(request_rec *r, const char *user, const char *pass)
224 kerb_auth_config *conf =
225 (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
228 int lifetime = DEFAULT_TKT_LIFE;
230 char *username = NULL;
231 char *instance = NULL;
234 username = (char *)ap_pstrdup(r->pool, user);
239 instance = strchr(username, '.');
247 realm = strchr(username, '@');
255 if (conf->krb_lifetime) {
256 lifetime = atoi(conf->krb_lifetime);
259 if (conf->krb_force_instance) {
260 instance = conf->krb_force_instance;
263 if (conf->krb_save_credentials) {
264 tfname = (char *)malloc(sizeof(char) * MAX_STRING_LEN);
265 sprintf(tfname, "%s/k5cc_ap_%s",
266 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
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(conf->krb_tmp_dir ? conf->krb_tmp_dir :
280 "/tmp") + 1; *c; c++) {
285 krb_set_tkt_string(tfname);
288 if (!strcmp(realm, "")) {
289 realm = (char *)malloc(sizeof(char) * (REALM_SZ + 1));
290 ret = krb_get_lrealm(realm, 1);
295 ret = krb_get_pw_in_tkt((char *)user, instance, realm, "krbtgt", realm,
296 lifetime, (char *)pass);
311 /***************************************************************************
312 Username/Password Validation for Krb5
313 ***************************************************************************/
316 krb5_verify_user(krb5_context context, krb5_principal principal,
317 krb5_ccache ccache, const char *password, krb5_boolean secure,
321 krb5_context kcontext;
322 krb5_principal server, client;
325 krb5_flags options = 0;
326 krb5_principal me = NULL;
327 krb5_data tgtname = {
333 memset((char *)&my_creds, 0, sizeof(my_creds));
334 my_creds.client = principal;
336 if (krb5_build_principal_ext(kcontext, &server,
337 krb5_princ_realm(kcontext, me)->length,
338 krb5_princ_realm(kcontext, me)->data,
339 tgtname.length, tgtname.data,
340 krb5_princ_realm(kcontext, me)->length,
341 krb5_princ_realm(kcontext, me)->data,
346 my_creds.server = server;
347 if (krb5_timeofday(kcontext, &now))
350 my_creds.times.starttime = 0;
352 my_creds.times.endtime = now + lifetime;
353 my_creds.times.renew_till = now + renewal;
356 ret = krb5_get_in_tkt_with_password(kcontext, options, 0, NULL, 0,
357 password, ccache, &my_creds, 0);
368 krb5_cache_cleanup(void *data)
370 krb5_context context;
372 krb5_error_code problem;
373 char *cache_name = (char *) data;
375 problem = krb5_init_context(&context);
377 /* ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "krb5_init_context() failed"); */
378 return HTTP_INTERNAL_SERVER_ERROR;
381 problem = krb5_cc_resolve(context, cache_name, &cache);
383 /* log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
384 "krb5_cc_resolve() failed (%s: %s)",
385 cache_name, krb5_get_err_text(context, problem)); */
386 return HTTP_INTERNAL_SERVER_ERROR;
389 krb5_cc_destroy(context, cache);
390 krb5_free_context(context);
395 create_krb5_ccache(krb5_context kcontext,
397 kerb_auth_config *conf,
398 krb5_principal princ,
401 char *c, ccname[MAX_STRING_LEN];
402 krb5_error_code problem;
404 krb5_ccache tmp_ccache = NULL;
406 snprintf(ccname, sizeof(ccname), "FILE:%s/k5cc_ap_%s",
407 conf->krb_tmp_dir ? conf->krb_tmp_dir : "/tmp",
410 for (c = ccname + strlen(conf->krb_tmp_dir ? conf->krb_tmp_dir :
411 "/tmp") + 1; *c; c++) {
416 problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
418 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
419 "Cannot create krb5 ccache: krb5_cc_resolve() failed: %s",
420 krb5_get_err_text(kcontext, problem));
421 ret = HTTP_INTERNAL_SERVER_ERROR;
425 problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
427 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
428 "Cannot create krb5 ccache: krb5_cc_initialize() failed: %s",
429 krb5_get_err_text(kcontext, problem));
430 ret = HTTP_INTERNAL_SERVER_ERROR;
434 ap_table_setn(r->subprocess_env, "KRB5CCNAME", ccname);
435 ap_register_cleanup(r->pool, ccname,
436 krb5_cache_cleanup, ap_null_cleanup);
438 *ccache = tmp_ccache;
445 krb5_cc_destroy(kcontext, tmp_ccache);
451 store_krb5_creds(krb5_context kcontext,
453 kerb_auth_config *conf,
454 krb5_ccache delegated_cred)
457 krb5_error_code problem;
458 krb5_principal princ;
462 problem = krb5_cc_get_principal(kcontext, delegated_cred, &princ);
464 snprintf(errstr, sizeof(errstr), "krb5_cc_get_principal() failed: %s",
465 krb5_get_err_text(kcontext, problem));
466 return HTTP_INTERNAL_SERVER_ERROR;
469 ret = create_krb5_ccache(kcontext, r, conf, princ, &ccache);
471 krb5_free_principal(kcontext, princ);
475 problem = krb5_cc_copy_cache(kcontext, delegated_cred, ccache);
476 krb5_free_principal(kcontext, princ);
478 snprintf(errstr, sizeof(errstr), "krb5_cc_copy_cache() failed: %s",
479 krb5_get_err_text(kcontext, problem));
480 krb5_cc_destroy(kcontext, ccache);
481 return HTTP_INTERNAL_SERVER_ERROR;
484 krb5_cc_close(kcontext, ccache);
489 int authenticate_user_krb5pwd(request_rec *r,
490 kerb_auth_config *conf,
491 const char *auth_line)
493 const char *sent_pw = NULL;
494 const char *sent_name = NULL;
495 const char *realms = NULL;
496 const char *service_name = NULL;
497 krb5_context kcontext = NULL;
498 krb5_error_code code;
499 krb5_principal client = NULL;
500 krb5_ccache ccache = NULL;
504 code = krb5_init_context(&kcontext);
506 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
507 "Cannot initialize Kerberos5 context (%d)", code);
508 return HTTP_INTERNAL_SERVER_ERROR;
511 sent_pw = ap_pbase64decode(r->pool, auth_line);
512 sent_name = ap_getword (r->pool, &sent_pw, ':');
513 /* do not allow user to override realm setting of server */
514 if (strchr(sent_name, '@')) {
515 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
516 "specifying realm in user name is prohibited");
517 ret = HTTP_UNAUTHORIZED;
522 code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
524 code = krb5_mcc_generate_new(kcontext, &ccache);
527 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
528 "Cannot generate new ccache: %s",
529 krb5_get_err_text(kcontext, code));
530 ret = HTTP_INTERNAL_SERVER_ERROR;
534 if (conf->krb_5_keytab)
535 /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
536 kcontext->default_keytab = conf->krb_5_keytab;
538 if (conf->service_name) {
540 service_name = ap_pstrdup(r->pool, conf->service_name);
541 if ((p=strchr(service_name, '/')))
544 service_name = "khttp";
546 realms = conf->krb_auth_realms;
548 if (realms && (code = krb5_set_default_realm(kcontext,
549 ap_getword_white(r->pool, &realms))))
553 krb5_free_principal(kcontext, client);
556 code = krb5_parse_name(kcontext, sent_name, &client);
560 code = krb5_verify_user(kcontext, client, ccache, sent_pw, 1,
565 /* ap_getword_white() used above shifts the parameter, so it's not
566 needed to touch the realms variable */
567 } while (realms && *realms);
569 memset((char *)sent_pw, 0, strlen(sent_pw));
572 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
573 "Verifying krb5 password failed: %s",
574 krb5_get_err_text(kcontext, code));
575 ret = HTTP_UNAUTHORIZED;
579 code = krb5_unparse_name(kcontext, client, &name);
581 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
582 krb5_get_err_text(kcontext, code));
583 ret = HTTP_UNAUTHORIZED;
586 MK_USER = ap_pstrdup (r->pool, name);
587 MK_AUTH_TYPE = "Basic";
590 if (conf->krb_save_credentials)
591 store_krb5_creds(kcontext, r, conf, ccache);
597 krb5_free_principal(kcontext, client);
599 krb5_cc_destroy(kcontext, ccache);
600 krb5_free_context(kcontext);
605 /*********************************************************************
606 * GSSAPI Authentication
607 ********************************************************************/
610 get_gss_error(MK_POOL *p, OM_uint32 error_status, char *prefix)
612 OM_uint32 maj_stat, min_stat;
613 OM_uint32 msg_ctx = 0;
614 gss_buffer_desc status_string;
618 snprintf(buf, sizeof(buf), "%s", prefix);
621 maj_stat = gss_display_status (&min_stat,
627 if (sizeof(buf) > len + status_string.length + 1) {
628 sprintf(buf+len, ": %s", (char*) status_string.value);
629 len += status_string.length;
631 gss_release_buffer(&min_stat, &status_string);
632 } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
634 return (ap_pstrdup(p, buf));
638 cleanup_gss_connection(void *data)
640 OM_uint32 minor_status;
641 gss_connection_t *gss_conn = (gss_connection_t *)data;
645 if (gss_conn->context != GSS_C_NO_CONTEXT)
646 gss_delete_sec_context(&minor_status, &gss_conn->context,
648 if (gss_conn->server_creds != GSS_C_NO_CREDENTIAL)
649 gss_release_cred(&minor_status, &gss_conn->server_creds);
655 store_gss_creds(request_rec *r, kerb_auth_config *conf, char *princ_name,
656 gss_cred_id_t delegated_cred)
658 OM_uint32 maj_stat, min_stat;
659 krb5_principal princ = NULL;
660 krb5_ccache ccache = NULL;
661 krb5_error_code problem;
662 krb5_context context;
663 int ret = HTTP_INTERNAL_SERVER_ERROR;
665 problem = krb5_init_context(&context);
667 log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Cannot initialize krb5 context");
668 return HTTP_INTERNAL_SERVER_ERROR;
671 problem = krb5_parse_name(context, princ_name, &princ);
673 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
674 "Cannot parse delegated username (%s)", krb5_get_err_text(context, problem));
678 problem = create_krb5_ccache(context, r, conf, princ, &ccache);
680 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
681 "Cannot create krb5 ccache (%s)", krb5_get_err_text(context, problem));
685 maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
686 if (GSS_ERROR(maj_stat)) {
687 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
688 "Cannot store delegated credential (%s)",
689 get_gss_error(r->pool, min_stat, "gss_krb5_copy_ccache"));
693 krb5_cc_close(context, ccache);
699 krb5_free_principal(context, princ);
701 krb5_cc_destroy(context, ccache);
702 krb5_free_context(context);
707 get_gss_creds(request_rec *r,
708 kerb_auth_config *conf,
709 gss_cred_id_t *server_creds)
711 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
712 OM_uint32 major_status, minor_status, minor_status2;
713 gss_name_t server_name = GSS_C_NO_NAME;
715 if (conf->service_name) {
716 input_token.value = conf->service_name;
717 input_token.length = strlen(conf->service_name) + 1;
720 input_token.value = "khttp";
721 input_token.length = 6;
723 major_status = gss_import_name(&minor_status, &input_token,
724 (conf->service_name) ?
725 GSS_C_NT_USER_NAME : GSS_C_NT_HOSTBASED_SERVICE,
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_import_name() failed"));
731 return HTTP_INTERNAL_SERVER_ERROR;
734 major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
735 GSS_C_NO_OID_SET, GSS_C_ACCEPT,
736 server_creds, NULL, NULL);
737 gss_release_name(&minor_status2, &server_name);
738 if (GSS_ERROR(major_status)) {
739 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
740 "%s", get_gss_error(r->pool, minor_status,
741 "gss_acquire_cred() failed"));
742 return HTTP_INTERNAL_SERVER_ERROR;
749 authenticate_user_gss(request_rec *r,
750 kerb_auth_config *conf,
751 const char *auth_line)
753 OM_uint32 major_status, minor_status, minor_status2;
754 gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
755 gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
756 const char *auth_param = NULL;
758 gss_name_t client_name = GSS_C_NO_NAME;
759 gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
761 if (gss_connection == NULL) {
762 gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
763 if (gss_connection == NULL) {
764 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
765 "ap_pcalloc() failed (not enough memory)");
766 ret = HTTP_INTERNAL_SERVER_ERROR;
769 memset(gss_connection, 0, sizeof(*gss_connection));
770 ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
773 if (conf->krb_5_keytab)
774 setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
776 if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
777 ret = get_gss_creds(r, conf, &gss_connection->server_creds);
782 /* ap_getword() shifts parameter */
783 auth_param = ap_getword_white(r->pool, &auth_line);
784 if (auth_param == NULL) {
785 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
786 "No Authorization parameter in request from client");
787 ret = HTTP_UNAUTHORIZED;
791 input_token.length = ap_base64decode_len(auth_param) + 1;
792 input_token.value = ap_pcalloc(r->connection->pool, input_token.length);
793 if (input_token.value == NULL) {
794 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
795 "ap_pcalloc() failed (not enough memory)");
796 ret = HTTP_INTERNAL_SERVER_ERROR;
799 input_token.length = ap_base64decode(input_token.value, auth_param);
801 major_status = gss_accept_sec_context(&minor_status,
802 &gss_connection->context,
803 gss_connection->server_creds,
805 GSS_C_NO_CHANNEL_BINDINGS,
812 if (output_token.length) {
816 len = ap_base64encode_len(output_token.length) + 1;
817 token = ap_pcalloc(r->connection->pool, len + 1);
819 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
820 "ap_pcalloc() failed (not enough memory)");
821 ret = HTTP_INTERNAL_SERVER_ERROR;
822 gss_release_buffer(&minor_status2, &output_token);
825 ap_base64encode(token, output_token.value, output_token.length);
827 ap_table_set(r->err_headers_out, "WWW-Authenticate",
828 ap_pstrcat(r->pool, "GSS-Negotiate ", token, NULL));
829 gss_release_buffer(&minor_status2, &output_token);
832 if (GSS_ERROR(major_status)) {
833 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
834 "%s", get_gss_error(r->pool, minor_status,
835 "gss_accept_sec_context() failed"));
836 ret = HTTP_UNAUTHORIZED;
840 if (major_status & GSS_S_CONTINUE_NEEDED) {
841 /* Some GSSAPI mechanism (eg GSI from Globus) may require multiple
842 * iterations to establish authentication */
843 ret = HTTP_UNAUTHORIZED;
847 major_status = gss_display_name(&minor_status, client_name, &output_token, NULL);
848 gss_release_name(&minor_status, &client_name);
849 if (GSS_ERROR(major_status)) {
850 log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
851 "%s", get_gss_error(r->pool, minor_status,
852 "gss_export_name() failed"));
853 ret = HTTP_INTERNAL_SERVER_ERROR;
857 MK_AUTH_TYPE = "Negotiate";
858 MK_USER = ap_pstrdup(r->pool, output_token.value);
860 if (conf->krb_save_credentials && delegated_cred != GSS_C_NO_CREDENTIAL)
861 store_gss_creds(r, conf, (char *)output_token.value, delegated_cred);
863 gss_release_buffer(&minor_status, &output_token);
867 /* If the user comes from a realm specified by configuration don't include
868 its realm name in the username so that the authorization routine could
869 work for both Password-based and Ticket-based authentication. It's
870 administrators responsibility to include only such realm that have
871 unified principal instances, i.e. if the same principal name occures in
872 multiple realms, it must be always assigned to a single user.
874 p = strchr(r->connection->user, '@');
876 const char *realms = conf->gss_krb5_realms;
878 while (realms && *realms) {
879 if (strcmp(p+1, ap_getword_white(r->pool, &realms)) == 0) {
891 gss_release_cred(&minor_status, &delegated_cred);
893 if (output_token.length)
894 gss_release_buffer(&minor_status, &output_token);
896 if (client_name != GSS_C_NO_NAME)
897 gss_release_name(&minor_status, &client_name);
905 note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf)
907 const char *auth_name = NULL;
909 /* get the user realm specified in .htaccess */
910 auth_name = ap_auth_name(r);
912 /* XXX check AuthType */
914 /* XXX should the WWW-Authenticate header be cleared first? */
916 if (conf->krb_method_gssapi)
917 ap_table_add(r->err_headers_out, "WWW-Authenticate", "GSS-Negotiate ");
918 if (conf->krb_method_k5pass)
919 ap_table_add(r->err_headers_out, "WWW-Authenticate",
920 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
924 if (conf->krb_method_k4pass)
925 ap_table_add(r->err_headers_out, "WWW-Authenticate",
926 ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
930 int kerb_authenticate_user(request_rec *r)
932 kerb_auth_config *conf =
933 (kerb_auth_config *) ap_get_module_config(r->per_dir_config,
935 const char *auth_type = NULL;
936 const char *auth_line = NULL;
937 const char *type = NULL;
938 int use_krb5 = 0, use_krb4 = 0;
941 /* get the type specified in .htaccess */
942 type = ap_auth_type(r);
944 if (type && strcasecmp(type, "Kerberos") == 0)
945 use_krb5 = use_krb4 = 1;
946 else if(type && strcasecmp(type, "KerberosV5") == 0)
948 else if (type && strcasecmp(type, "KerberosV4") == 0)
953 /* get what the user sent us in the HTTP header */
954 auth_line = MK_TABLE_GET(r->headers_in, "Authorization");
956 note_kerb_auth_failure(r, conf);
957 return HTTP_UNAUTHORIZED;
959 auth_type = ap_getword_white(r->pool, &auth_line);
961 ret = HTTP_UNAUTHORIZED;
964 if (use_krb5 && conf->krb_method_gssapi &&
965 strcasecmp(auth_type, "GSS-Negotiate") == 0) {
966 ret = authenticate_user_gss(r, conf, auth_line);
967 } else if (use_krb5 && conf->krb_method_k5pass &&
968 strcasecmp(auth_type, "Basic") == 0) {
969 ret = authenticate_user_krb5pwd(r, conf, auth_line);
974 if (ret == HTTP_UNAUTHORIZED && use_krb4 && conf->krb_method_k4pass &&
975 strcasecmp(auth_type, "Basic") == 0)
976 ret = authenticate_user_krb4pwd(r, conf, auth_line);
979 if (ret == HTTP_UNAUTHORIZED)
980 note_kerb_auth_failure(r, conf);
986 /***************************************************************************
987 Module Setup/Configuration
988 ***************************************************************************/
990 module MODULE_VAR_EXPORT auth_kerb_module = {
991 STANDARD_MODULE_STUFF,
992 NULL, /* module initializer */
993 kerb_dir_create_config, /* per-directory config creator */
994 NULL, /* per-directory config merger */
995 NULL, /* per-server config creator */
996 NULL, /* per-server config merger */
997 kerb_auth_cmds, /* command table */
998 NULL, /* [ 9] content handlers */
999 NULL, /* [ 2] URI-to-filename translation */
1000 kerb_authenticate_user, /* [ 5] check/validate user_id */
1001 NULL, /* [ 6] check user_id is valid *here* */
1002 NULL, /* [ 4] check access by host address */
1003 NULL, /* [ 7] MIME type checker/setter */
1004 NULL, /* [ 8] fixups */
1005 NULL, /* [10] logger */
1006 NULL, /* [ 3] header parser */
1007 NULL, /* process initialization */
1008 NULL, /* process exit/cleanup */
1009 NULL /* [ 1] post read_request handling */
1012 void kerb_register_hooks(apr_pool_t *p)
1014 ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE);
1017 module AP_MODULE_DECLARE_DATA auth_kerb_module =
1019 STANDARD20_MODULE_STUFF,
1020 kerb_dir_create_config, /* create per-dir conf structures */
1021 NULL, /* merge per-dir conf structures */
1022 NULL, /* create per-server conf structures */
1023 NULL, /* merge per-server conf structures */
1024 kerb_auth_cmds, /* table of configuration directives */
1025 kerb_register_hooks /* register hooks */