From 450724b4bc8707da3f44f542aac53f6cf3ef8aef Mon Sep 17 00:00:00 2001 From: jadestorm Date: Thu, 29 May 2003 14:52:38 +0000 Subject: [PATCH] Returned to single mod_auth_kerb.c file. --- ChangeLog | 5 + apache1/module.c | 2 +- apache2/hooks.c | 1 + src/mod_auth_kerb.c | 720 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 727 insertions(+), 1 deletion(-) create mode 100644 src/mod_auth_kerb.c diff --git a/ChangeLog b/ChangeLog index 78727e3..6d3377b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2003-05-29 Daniel Henninger + + * src/mod_auth_kerb.c: + Combined current work back into a single file. + 2002-09-06 Daniel Henninger * apache1/auth_cmds.c: diff --git a/apache1/module.c b/apache1/module.c index 5c848a7..fadaae3 100644 --- a/apache1/module.c +++ b/apache1/module.c @@ -9,7 +9,7 @@ module MODULE_VAR_EXPORT kerb_auth_module = { NULL, /* [ 9] content handlers */ NULL, /* [ 2] URI-to-filename translation */ kerb_authenticate_user, /* [ 5] check/validate user_id */ - NULL, /* [ 6] check user_id is valid *here* */ + kerb_check_user_access, /* [ 6] check user_id is valid *here* */ NULL, /* [ 4] check access by host address */ NULL, /* [ 7] MIME type checker/setter */ NULL, /* [ 8] fixups */ diff --git a/apache2/hooks.c b/apache2/hooks.c index 9e0c9bb..c234640 100644 --- a/apache2/hooks.c +++ b/apache2/hooks.c @@ -1,4 +1,5 @@ void kerb_register_hooks(apr_pool_t *p) { ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE); } diff --git a/src/mod_auth_kerb.c b/src/mod_auth_kerb.c new file mode 100644 index 0000000..cbaa5da --- /dev/null +++ b/src/mod_auth_kerb.c @@ -0,0 +1,720 @@ +/*************************************************************************** + Included Headers And Module Declaration + ***************************************************************************/ +#ifdef APXS1 +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" + +module kerb_auth_module; +#else +#ifdef APXS2 +#include "apr_strings.h" +#include "apr_lib.h" +#include "ap_config.h" +#include "httpd.h" +#include "http_config.h" +#include "http_core.h" +#include "http_log.h" +#include "http_protocol.h" +#include "http_request.h" + +module AP_MODULE_DECLARE_DATA kerb_auth_module; +#endif /* APXS2 */ +#endif /* APXS1 */ + +#ifdef KRB5 +#include +#endif /* KRB5 */ + +#ifdef KRB4 +#include +#endif /* KRB4 */ + + + + +/*************************************************************************** + Macros To Ease Compatibility + ***************************************************************************/ +#ifdef APXS1 +#define MK_POOL pool +#define MK_TABLE_GET ap_table_get +#define MK_TABLE_SET ap_table_set +#define MK_TABLE_TYPE table +#define MK_PSTRDUP ap_pstrdup +#define MK_PROXY STD_PROXY +#define MK_RERROR_LEVEL "" +#define MK_USER r->connection->user +#define MK_AUTH_TYPE r->connection->ap_auth_type +#define MK_ARRAY_HEADER array_header +#else +#ifdef APXS2 +#define MK_POOL apr_pool_t +#define MK_TABLE_GET apr_table_get +#define MK_TABLE_SET apr_table_set +#define MK_TABLE_TYPE apr_table_t +#define MK_PSTRDUP apr_pstrdup +#define MK_PROXY PROXYREQ_PROXY +#define MK_RERROR_LEVEL "0, " +#define MK_USER r->user +#define MK_AUTH_TYPE r->ap_auth_type +#define MK_ARRAY_HEADER apr_array_header_t +#endif /* APXS2 */ +#endif /* APXS1 */ + + + + +/*************************************************************************** + Auth Configuration Structure + ***************************************************************************/ +typedef struct { + char *krb_auth_type; +#ifdef KRB4 + char *krb_4_srvtab; +#endif /* KRB4 */ +#ifdef KRB5 + char *krb_5_keytab; +#endif /* KRB5 */ + int krb_authoritative; + char *krb_default_realm; + int krb_fail_status; + char *krb_force_instance; +#ifdef KRB5 + int krb_forwardable; +#endif /* KRB5 */ + char *krb_lifetime; +#ifdef KRB5 + char *krb_renewable; +#endif /* KRB5 */ + int krb_save_credentials; + char *krb_tmp_dir; +} kerb_auth_config; + + + + +/*************************************************************************** + Auth Configuration Initialization + ***************************************************************************/ +static void *kerb_dir_config(AP_POOL *p, char *d) +{ + static void *rec; + rec = (void *) ap_pcalloc(p, sizeof(kerb_auth_config)); + ((kerb_auth_config *)rec)->krb_fail_status = HTTP_UNAUTHORIZED; + ((kerb_auth_config *)rec)->krb_authoritative = 0; + ((kerb_auth_config *)rec)->krb_auth_type = MK_PSTRDUP(p, "None"); + return rec; +} + + + + +/*************************************************************************** + Auth Configuration Parsers + ***************************************************************************/ +static const char *kerb_set_fail_slot(cmd_parms *cmd, void *struct_ptr, + const char *arg) +{ + int offset = (int) (long) cmd->info; + if (!strncasecmp(arg, "unauthorized", 12)) + *(int *) ((char *)struct_ptr + offset) = HTTP_UNAUTHORIZED; + else if (!strncasecmp(arg, "forbidden", 9)) + *(int *) ((char *)struct_ptr + offset) = HTTP_FORBIDDEN; + else if (!strncasecmp(arg, "declined", 8)) + *(int *) ((char *)struct_ptr + offset) = DECLINED; + else + return "KrbAuthFailStatus must be Forbidden, Unauthorized, or Declined."; + return NULL; +} + +/* these are either char *struct_ptr, char *arg or void *struct_ptr, const char *arg */ +static const char *kerb_set_type_slot(cmd_parms *cmd, void *struct_ptr, + const char *arg) +{ + int offset = (int) (long) cmd->info; + if +#ifdef KRB5 + (!strncasecmp(arg, "v5", 2)) + *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV5"); + else if +#endif /* KRB5 */ +#ifdef KRB4 + (!strncasecmp(arg, "v4", 2)) + *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosV4"); +#endif /* KRB4 */ + else if + (!strncasecmp(arg, "dualv5v4", 8)) + *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV5V4"); + else if + (!strncasecmp(arg, "dualv4v5", 8)) + *(char **) ((char *)struct_ptr + offset) = MK_PSTRDUP(cmd->pool, "KerberosDualV4V5"); +#if defined(KRB4) && defined(KRB5) +#endif /* KRB4 && KRB5 */ + else + return "AuthKerberos must be V5, V4, DualV4V5, or DualV5V4."; + return NULL; +} + + + + +/*************************************************************************** + Auth Configuration Commands + ***************************************************************************/ +#ifdef APXS1 +command_rec kerb_auth_cmds[] = { + { + "AuthKerberos", + kerb_set_type_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_auth_type), + OR_AUTHCFG, + TAKE1, + "Permit Kerberos auth without AuthType requirement." + }, + +#ifdef KRB4 + { + "Krb4Srvtab", + ap_set_file_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_4_srvtab), + RSRC_CONF & ACCESS_CONF, + TAKE1, + "Location of Kerberos V4 srvtab file." + }, +#endif /* KRB4 */ + +#ifdef KRB5 + { + "Krb5Keytab", + ap_set_file_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_5_keytab), + RSRC_CONF & ACCESS_CONF, + TAKE1, + "Location of Kerberos V5 keytab file." + }, +#endif /* KRB5 */ + + { + "KrbAuthoritative", + ap_set_flag_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_authoritative), + OR_AUTHCFG, + FLAG, + "Refuse to pass request down to lower modules." + }, + + { + "KrbDefaultRealm", + ap_set_string_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_default_realm), + OR_AUTHCFG, + TAKE1, + "Default realm to authenticate users against." + }, + + { + "KrbFailStatus", + kerb_set_fail_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_fail_status), + OR_AUTHCFG, + TAKE1, + "If auth fails, return status set here." + }, + + { + "KrbForceInstance", + ap_set_string_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_force_instance), + OR_AUTHCFG, + TAKE1, + "Force authentication against an instance specified here." + }, + +#ifdef KRB5 + { + "KrbForwardable", + ap_set_flag_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_forwardable), + OR_AUTHCFG, + FLAG, + "Credentials retrieved will be flagged as forwardable." + }, +#endif /* KRB5 */ + + { + "KrbLifetime", + ap_set_string_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_lifetime), + OR_AUTHCFG, + TAKE1, + "Lifetime of tickets retrieved." + }, + +#ifdef KRB5 + { + "KrbRenewable", + ap_set_string_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_renewable), + OR_AUTHCFG, + TAKE1, + "Credentials retrieved will be renewable for this length." + }, +#endif /* KRB5 */ + + { + "KrbSaveCredentials", + ap_set_flag_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials), + OR_AUTHCFG, + FLAG, + "Save and store credentials/tickets retrieved during auth." + }, + + { + "KrbSaveTickets", + ap_set_flag_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_save_credentials), + OR_AUTHCFG, + FLAG, + "Alias for KrbSaveCredentials." + }, + + { + "KrbTmpdir", + ap_set_string_slot, + (void*)XtOffsetOf(kerb_auth_config, krb_tmp_dir), + OR_AUTHCFG, + TAKE1, + "Path to store ticket files and such in." + }, + + { NULL } +}; +#else +#ifdef APXS2 +static const command_rec kerb_auth_cmds[] = { + AP_INIT_TAKE1( + "AuthKerberos", + kerb_set_type_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_auth_type), + OR_AUTHCFG, + "Permit Kerberos auth without AuthType requirement." + ), + +#ifdef KRB4 + AP_INIT_TAKE1( + "Krb4Srvtab", + ap_set_file_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_4_srvtab), + RSRC_CONF & ACCESS_CONF, + "Location of Kerberos V4 srvtab file." + ), +#endif /* KRB4 */ + +#ifdef KRB5 + AP_INIT_TAKE1( + "Krb5Keytab", + ap_set_file_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_5_keytab), + RSRC_CONF & ACCESS_CONF, + "Location of Kerberos V5 keytab file." + ), +#endif /* KRB5 */ + + AP_INIT_FLAG( + "KrbAuthoritative", + ap_set_flag_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_authoritative), + OR_AUTHCFG, + "Refuse to pass request down to lower modules." + ), + + AP_INIT_TAKE1( + "KrbDefaultRealm", + ap_set_string_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_default_realm), + OR_AUTHCFG, + "Default realm to authenticate users against." + ), + + AP_INIT_TAKE1( + "KrbFailStatus", + kerb_set_fail_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_fail_status), + OR_AUTHCFG, + "If auth fails, return status set here." + ), + + AP_INIT_TAKE1( + "KrbForceInstance", + ap_set_string_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_force_instance), + OR_AUTHCFG, + "Force authentication against an instance specified here." + ), + +#ifdef KRB5 + AP_INIT_FLAG( + "KrbForwardable", + ap_set_flag_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_forwardable), + OR_AUTHCFG, + "Credentials retrieved will be flagged as forwardable." + ), +#endif /* KRB5 */ + + AP_INIT_TAKE1( + "KrbLifetime", + ap_set_string_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_lifetime), + OR_AUTHCFG, + "Lifetime of tickets retrieved." + ), + +#ifdef KRB5 + AP_INIT_TAKE1( + "KrbRenewable", + ap_set_string_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_renewable), + OR_AUTHCFG, + "Credentials retrieved will be renewable for this length." + ), +#endif /* KRB5 */ + + AP_INIT_FLAG( + "KrbSaveCredentials", + ap_set_flag_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials), + OR_AUTHCFG, + "Save and store credentials/tickets retrieved during auth." + ), + + AP_INIT_FLAG( + "KrbSaveTickets", + ap_set_flag_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_save_credentials), + OR_AUTHCFG, + "Alias for KrbSaveCredentials." + ), + + AP_INIT_TAKE1( + "KrbTmpdir", + ap_set_string_slot, + (void*)APR_XtOffsetOf(kerb_auth_config, krb_tmp_dir), + OR_AUTHCFG, + "Path to store ticket files and such in." + ), + + { NULL } +}; +#endif /* APXS2 */ +#endif /* APXS1 */ + + + + +/*************************************************************************** + Username/Password Validation + ***************************************************************************/ +#ifdef KRB5 +int kerb5_password_validate(const char *user, const char *pass) { + int ret; + krb5_context kcontext; + krb5_principal server, me; + krb5_creds my_creds; + krb5_timestamp now; + krb5_deltat lifetime = 0; + krb5_data tgtname = { + 0, + KRB5_TGS_NAME_SIZE, + KRB5_TGS_NAME + }; + + if (krb5_init_context(&kcontext)) + return 0; + + memset((char *)&my_creds, 0, sizeof(my_creds)); + if(krb5_parse_name(kcontext, user, &me)) + return 0; + my_creds.client = me; + + if (krb5_build_principal_ext(kcontext, &server, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + tgtname.length, tgtname.data, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + 0)) { + return 0; + } + my_creds.server = server; + if (krb5_timeofday(kcontext, &now)) + return 0; + my_creds.times.starttime = 0; + my_creds.times.endtime = now + lifetime; + my_creds.times.renew_till = 0; + + ret = krb5_get_in_tkt_with_password(kcontext, 0, 0, NULL, 0, + pass, NULL, &my_creds, 0); + if (ret) { + return 0; + } + + krb5_free_cred_contents(kcontext, &my_creds); + + return 1; +} +#endif /* KRB5 */ + +#ifdef KRB4 +int kerb4_password_validate(const char *user, const char *pass) { + int ret; + char realm[REALM_SZ]; + + ret = krb_get_lrealm(realm, 1); + if (ret != KSUCCESS) + return !KRB4_OK; + + ret = krb_get_pw_in_tkt((char *)user, "", realm, "krbtgt", realm, + DEFAULT_TKT_LIFE, (char *)pass); + switch (ret) { + case INTK_OK: + case INTK_W_NOTALL: + return KRB4_OK; + break; + + default: + return !KRB4_OK; + break; + } +} +#endif /* KRB4 */ + + + + +/*************************************************************************** + User Authentication + ***************************************************************************/ +int kerb_authenticate_user(request_rec *r) { + const char *name; /* AuthName specified */ + const char *type; /* AuthType specified */ + int KerberosV5 = 0; /* Kerberos V5 check enabled */ + int KerberosV4 = 0; /* Kerberos V4 check enabled */ + int KerberosV4first = 0; /* Kerberos V4 check first */ + const char *sent_pw; /* Password sent by browser */ + int res; /* Response holder */ + int retcode; /* Return code holder */ + const char *t; /* Decoded auth_line */ + const char *authtype; /* AuthType to send back to browser */ + const char *auth_line = MK_TABLE_GET(r->headers_in, + (r->proxyreq == MK_PROXY) + ? "Proxy-Authorization" + : "Authorization"); + kerb_auth_config *conf = + (kerb_auth_config *)ap_get_module_config(r->per_dir_config, + &kerb_auth_module); + + type = ap_auth_type(r); + + if (type != NULL) { +#ifdef KRB5 + if ((strncasecmp(type, "KerberosV5", 10) == 0) || + (strncasecmp(conf->krb_auth_type, "KerberosV5", 10) == 0)) { + KerberosV5 = 1; + } +#endif /* KRB5 */ + +#ifdef KRB4 + if ((strncasecmp(type, "KerberosV4", 10) == 0) || + (strncasecmp(conf->krb_auth_type, "KerberosV4", 10) == 0)) { + KerberosV4 = 1; + } +#endif /* KRB4 */ + +#if defined(KRB5) && defined(KRB4) + if ((strncasecmp(type, "KerberosDualV5V4", 15) == 0) || + (strncasecmp(conf->krb_auth_type, "KerberosDualV5V4", 15) == 0)) { + KerberosV5 = 1; + KerberosV4 = 1; + } + + if ((strncasecmp(type, "KerberosDualV4V5", 15) == 0) || + (strncasecmp(conf->krb_auth_type, "KerberosDualV4V5", 15) == 0)) { + KerberosV5 = 1; + KerberosV4 = 1; + KerberosV4first = 1; + } +#endif /* KRB5 && KRB4 */ + } + + if (!KerberosV4 && !KerberosV5) { + if (conf->krb_authoritative) { + return HTTP_UNAUTHORIZED; + } + else { + return DECLINED; + } + } + + name = ap_auth_name(r); + if (!name) { + ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, + MK_RERROR_LEVEL "need AuthName: %s", r->uri); + return HTTP_INTERNAL_SERVER_ERROR; + } + + if (!auth_line) { + MK_TABLE_SET(r->err_headers_out, "WWW-Authenticate", + ap_pstrcat(r->pool, "Basic realm=\"", name, "\"", NULL)); + return HTTP_UNAUTHORIZED; + } + + type = ap_getword_white(r->pool, &auth_line); + t = ap_pbase64decode(r->pool, auth_line); + MK_USER = ap_getword_nulls(r->pool, &t, ':'); + MK_AUTH_TYPE = "Kerberos"; + sent_pw = ap_getword_white(r->pool, &t); + + retcode = DECLINED; + +#ifdef KRB5 + if (KerberosV5 && !KerberosV4first && retcode != OK) { + MK_AUTH_TYPE = "KerberosV5"; + if (kerb5_password_validate(MK_USER, sent_pw)) { + retcode = OK; + } + else { + retcode = conf->krb_fail_status; + } + } +#endif /* KRB5 */ + +#ifdef KRB4 + if (KerberosV4 && retcode != OK) { + MK_AUTH_TYPE = "KerberosV4"; + if (kerb4_password_validate(MK_USER, sent_pw)) { + retcode = OK; + } + else { + retcode = conf->krb_fail_status; + } + } +#endif /* KRB4 */ + +#if defined(KRB5) && defined(KRB4) + if (KerberosV5 && KerberosV4first && retcode != OK) { + MK_AUTH_TYPE = "KerberosV5" + if (kerb5_password_validate(MK_USER, sent_pw)) { + retcode = OK; + } + else { + retcode = conf->krb_fail_status; + } + } +#endif /* KRB5 && KRB4 */ + + if (conf->krb_authoritative && retcode == DECLINED) { + return HTTP_UNAUTHORIZED; + } + else { + return retcode; + } +} + + + + +/*************************************************************************** + Access Verification + ***************************************************************************/ +int check_user_access(request_rec *r) { + register int x; + const char *t, *w; + const MK_ARRAY_HEADER *reqs_arr = ap_requires(r); + require_line *reqs; + kerb_auth_config *conf = + (kerb_auth_config *)ap_get_module_config(r->per_dir_config, + &kerb_auth_module); + + if (reqs_arr == NULL) { + return OK; + } + reqs = (require_line *)reqs_arr->elts; + + for (x = 0; x < reqs_arr->nelts; x++) { + t = reqs[x].requirement; + w = ap_getword_white(r->pool, &t); + if (strcmp(w, "realm") == 0) { + while (t[0] != '\0') { + w = ap_getword_conf(r->pool, &t); + if (strcmp(MK_USER, w) == 0) { + return OK; + } + } + } + } + + return DECLINED; +} + + + + +/*************************************************************************** + Module Setup/Configuration + ***************************************************************************/ +#ifdef APXS1 +module MODULE_VAR_EXPORT kerb_auth_module = { + STANDARD_MODULE_STUFF, + NULL, /* module initializer */ + kerb_dir_config, /* per-directory config creator */ + NULL, /* per-directory config merger */ + NULL, /* per-server config creator */ + NULL, /* per-server config merger */ + kerb_auth_cmds, /* command table */ + NULL, /* [ 9] content handlers */ + NULL, /* [ 2] URI-to-filename translation */ + kerb_authenticate_user, /* [ 5] check/validate user_id */ + kerb_check_user_access, /* [ 6] check user_id is valid *here* */ + NULL, /* [ 4] check access by host address */ + NULL, /* [ 7] MIME type checker/setter */ + NULL, /* [ 8] fixups */ + NULL, /* [10] logger */ + NULL, /* [ 3] header parser */ + NULL, /* process initialization */ + NULL, /* process exit/cleanup */ + NULL /* [ 1] post read_request handling */ +#ifdef EAPI + , /* EAPI Additions */ + NULL, /* EAPI add module */ + NULL, /* EAPI remove module */ + NULL, /* EAPI rewrite command */ + NULL /* EAPI new connection */ +#endif /* EAPI */ +}; +#else +#ifdef APXS2 +void kerb_register_hooks(apr_pool_t *p) +{ + ap_hook_check_user_id(kerb_authenticate_user, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_access_checker(kerb_check_user_access, NULL, NULL, APR_HOOK_MIDDLE); +} + +module AP_MODULE_DECLARE_DATA kerb_auth_module = +{ + STANDARD20_MODULE_STUFF, + kerb_dir_config, /* create per-dir conf structures */ + NULL, /* merge per-dir conf structures */ + NULL, /* create per-server conf structures */ + NULL, /* merge per-server conf structures */ + kerb_auth_cmds, /* table of configuration directives */ + kerb_register_hooks /* register hooks */ +}; +#endif /* APXS2 */ +#endif /* APXS1 */ -- 2.1.4