#ident "$Id$"
+#include "config.h"
+
#define MODAUTHKERB_VERSION "5.0-rc2"
#ifndef APXS1
#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_USER r->connection->user
#define MK_AUTH_TYPE r->connection->ap_auth_type
-#define MK_ARRAY_HEADER array_header
#else
#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_USER r->user
#define MK_AUTH_TYPE r->ap_auth_type
-#define MK_ARRAY_HEADER apr_array_header_t
#endif /* APXS1 */
const request_rec *r, const char *fmt, ...)
{
char errstr[1024];
+ char errnostr[1024];
va_list ap;
va_start(ap, fmt);
vsnprintf(errstr, sizeof(errstr), fmt, ap);
va_end(ap);
+ errnostr[0] = '\0';
+ if (errno)
+ snprintf(errnostr, sizeof(errnostr), "%s: (%s)", errstr, strerror(errno));
+ else
+ snprintf(errnostr, sizeof(errnostr), "%s", errstr);
+
#ifdef APXS1
- ap_log_rerror(file, line, level, r, "%s", errstr);
+ ap_log_rerror(file, line, level | APLOG_NOERRNO, r, "%s", errnostr);
#else
- ap_log_rerror(file, line, level, status, r, "%s", errstr);
+ ap_log_rerror(file, line, level | APLOG_NOERRNO, status, r, "%s", errnostr);
#endif
}
ret = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm,
DEFAULT_TKT_LIFE, password);
- if (ret)
- /* log(krb_err_txt[ret]) */
+ if (ret) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot get krb4 ticket: krb_get_pw_in_tkt() failed: %s",
+ krb_get_err_text(ret));
return ret;
+ }
hostname = ap_get_server_name(r);
hp = gethostbyname(hostname);
if (hp == NULL) {
dest_tkt();
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot verify krb4 ticket: gethostbyname() failed: %s",
+ hstrerror(h_errno));
return h_errno;
}
memcpy(&addr, hp->h_addr, sizeof(addr));
ret = krb_mk_req(&ticket, linstance, phost, lrealm, 0);
if (ret) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot verify krb4 ticket: krb_mk_req() failed: %s",
+ krb_get_err_text(ret));
dest_tkt();
return ret;
}
ret = krb_rd_req(&ticket, linstance, phost, addr, &authdata, srvtab);
- if (ret)
+ if (ret) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot verify krb4 ticket: krb_rd_req() failed: %s",
+ krb_get_err_text(ret));
dest_tkt();
+ }
return ret;
}
} while (realms && *realms);
if (ret) {
- log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "Verifying krb4 password failed (%d)", ret);
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Verifying krb4 password failed");
ret = HTTP_UNAUTHORIZED;
goto end;
}
int ret;
krb5_ccache tmp_ccache = NULL;
-#ifdef HEIMDAL
+#ifdef HAVE_KRB5_CC_GEN_NEW
problem = krb5_cc_gen_new(kcontext, &krb5_fcc_ops, &tmp_ccache);
#else
+ /* only older MIT seem to not have the krb5_cc_gen_new() call, so we use
+ * MIT specific call here */
problem = krb5_fcc_generate_new(kcontext, &tmp_ccache);
/* krb5_fcc_generate_new() doesn't set KRB5_TC_OPENCLOSE, which makes
krb5_cc_initialize() fail */
goto end;
}
-#ifdef HEIMDAL
+#ifdef HAVE_KRB5_CC_GEN_NEW
code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
#else
+ /* only older MIT seem to not have the krb5_cc_gen_new() call, so we use
+ * MIT specific call here */
code = krb5_mcc_generate_new(kcontext, &ccache);
#endif
if (code) {
if (conf->krb_5_keytab)
krb5_kt_resolve(kcontext, conf->krb_5_keytab, &keytab);
- /* setenv("KRB5_KTNAME", conf->krb_5_keytab, 1); */
realms = conf->krb_auth_realms;
do {
int ret;
gss_name_t client_name = GSS_C_NO_NAME;
gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
- static int initial_return = HTTP_UNAUTHORIZED;
-
- /* needed to work around replay caches */
- if (!ap_is_initial_req(r))
- return initial_return;
- initial_return = HTTP_UNAUTHORIZED;
if (gss_connection == NULL) {
gss_connection = ap_pcalloc(r->connection->pool, sizeof(*gss_connection));
ap_register_cleanup(r->connection->pool, gss_connection, cleanup_gss_connection, ap_null_cleanup);
}
- if (conf->krb_5_keytab)
- setenv("KRB5_KTNAME", conf->krb_5_keytab, 1);
+ if (conf->krb_5_keytab) {
+ char *ktname;
+ /* we don't use the ap_* calls here, since the string passed to putenv()
+ * will become part of the enviroment and shouldn't be free()ed by apache
+ */
+ ktname = malloc(strlen("KRB5_KTNAME=") + strlen(conf->krb_5_keytab) + 1);
+ if (ktname == NULL) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "malloc() failed: not enough memory");
+ ret = HTTP_INTERNAL_SERVER_ERROR;
+ goto end;
+ }
+ sprintf(ktname, "KRB5_KTNAME=%s", conf->krb_5_keytab);
+ putenv(ktname);
+ }
if (gss_connection->server_creds == GSS_C_NO_CREDENTIAL) {
ret = get_gss_creds(r, conf, &gss_connection->server_creds);
cleanup_gss_connection(gss_connection);
- initial_return = ret;
return ret;
}
#endif /* KRB5 */
+static int
+already_succeeded(request_rec *r)
+{
+ if (ap_is_initial_req(r) || MK_AUTH_TYPE == NULL)
+ return 0;
+ if (strcmp(MK_AUTH_TYPE, "Negotiate") ||
+ (strcmp(MK_AUTH_TYPE, "Basic") && strchr(MK_USER, '@')))
+ return 1;
+ return 0;
+}
static void
note_kerb_auth_failure(request_rec *r, const kerb_auth_config *conf,
/* XXX should the WWW-Authenticate header be cleared first? */
#ifdef KRB5
if (use_krb5 && conf->krb_method_gssapi)
- ap_table_add(r->err_headers_out, "WWW-Authenticate", "Negotiate ");
+ ap_table_add(r->err_headers_out, "WWW-Authenticate", "Negotiate");
if (use_krb5 && conf->krb_method_k5pass) {
ap_table_add(r->err_headers_out, "WWW-Authenticate",
ap_pstrcat(r->pool, "Basic realm=\"", auth_name, "\"", NULL));
const char *type = NULL;
int use_krb5 = 0, use_krb4 = 0;
int ret;
+ static int last_return = HTTP_UNAUTHORIZED;
/* get the type specified in .htaccess */
type = ap_auth_type(r);
}
auth_type = ap_getword_white(r->pool, &auth_line);
+ if (already_succeeded(r))
+ return last_return;
+
ret = HTTP_UNAUTHORIZED;
#ifdef KRB5
if (ret == HTTP_UNAUTHORIZED)
note_kerb_auth_failure(r, conf, use_krb4, use_krb5);
+ last_return = ret;
return ret;
}