- kerb_auth_config *conf =
- (kerb_auth_config *)ap_get_module_config(r->per_dir_config,
- &kerb_auth_module);
- int ret;
- krb5_context kcontext;
- krb5_principal server, client;
- krb5_ccache ccache = NULL;
- krb5_deltat lifetime = 300; /* 5 minutes */
- krb5_deltat renewal = 0;
- krb5_flags options = 0;
- char errstr[1024];
- krb5_error_code code;
- const char *realms;
-
- if (krb5_init_context(&kcontext)) {
- snprintf(errstr, sizeof(errstr),
- "Cannot initialize Kerberos5 context");
- ap_log_reason (errstr, r->uri, r);
- ret = SERVER_ERROR;
- return 0;
- }
-
- if (conf->krb_forwardable) {
- options |= KDC_OPT_FORWARDABLE;
- }
-
- if (conf->krb_renewable) {
- options |= KDC_OPT_RENEWABLE;
- renewal = 86400; /* 24 hours */
- }
-
- if (conf->krb_lifetime) {
- lifetime = atoi(conf->krb_lifetime);
- }
-
-/* ????
- code = krb5_cc_gen_new(kcontext, &krb5_mcc_ops, &ccache);
- if (code) {
- snprintf(errstr, sizeof(errstr), "krb5_cc_gen_new(): %.100s",
- krb5_get_err_text(kcontext, code));
- ap_log_reason (errstr, r->uri, r);
- ret = SERVER_ERROR;
- goto end;
- }
-*/
-
- realms = conf->krb_auth_realms;
- do {
- code = 0;
- if (realms) {
- code = krb5_set_default_realm(kcontext,
- ap_getword_white(r->pool, &realms));
- if (code)
- continue;
- }
-
- code = krb5_parse_name(kcontext, r->connection->user, &client);
- if (code)
- continue;
-
- code = krb5_verify_user(kcontext, client, ccache, pass,
- 1, "khttp");
- krb5_free_principal(kcontext, client);
- if (code == 0)
- break;
-
- /* ap_getword_white() used above shifts the parameter, so it's not
- needed to touch the realms variable */
- } while (realms && *realms);
-
- memset((char *)pass, 0, strlen(pass));
-
- if (code) {
- snprintf(errstr, sizeof(errstr), "Verifying krb5 password failed: %s",
- krb5_get_err_text(kcontext, code));
- ap_log_reason (errstr, r->uri, r);
- ret = HTTP_UNAUTHORIZED;
- goto end;
- }
-
- if (conf->krb_save_credentials) {
- ret = store_krb5_creds(kcontext, r, conf, ccache);
- if (ret)
- goto end;
- }
-
- ret = 1; /* XXX should be OK ? */
+ /* XXX Heimdal allows to use the MEMORY: type with empty argument ? */
+ ccname = ap_psprintf(r->pool, "MEMORY:%s/krb5cc_apache_XXXXXX", P_tmpdir);
+ fd = mkstemp(ccname + strlen("MEMORY:"));
+ if (fd < 0) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "mkstemp() failed: %s", strerror(errno));
+ ret = HTTP_INTERNAL_SERVER_ERROR;
+ goto end;
+ }
+ close(fd);
+
+ code = krb5_cc_resolve(kcontext, ccname, &ccache);
+ if (code) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "krb5_cc_resolve() failed: %s",
+ krb5_get_err_text(kcontext, code));
+ ret = HTTP_INTERNAL_SERVER_ERROR;
+ unlink(ccname);
+ goto end;
+ }
+
+ if (conf->krb_5_keytab)
+ krb5_kt_resolve(kcontext, conf->krb_5_keytab, &keytab);
+
+ all_principals_unkown = 1;
+ realms = conf->krb_auth_realms;
+ do {
+ if (realms && (code = krb5_set_default_realm(kcontext,
+ ap_getword_white(r->pool, &realms))))
+ continue;
+
+ if (client) {
+ krb5_free_principal(kcontext, client);
+ client = NULL;
+ }
+ code = krb5_parse_name(kcontext, sent_name, &client);
+ if (code)
+ continue;
+
+ code = verify_krb5_user(r, kcontext, client, ccache, sent_pw,
+ conf->krb_service_name,
+ keytab, conf->krb_verify_kdc);
+ if (!conf->krb_authoritative && code) {
+ /* if we're not authoritative, we allow authentication to pass on
+ * to another modules if (and only if) the user is not known to us */
+ if (all_principals_unkown && code != KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN)
+ all_principals_unkown = 0;
+ }
+
+ if (code == 0)
+ break;
+
+ /* ap_getword_white() used above shifts the parameter, so it's not
+ needed to touch the realms variable */
+ } while (realms && *realms);
+
+ memset((char *)sent_pw, 0, strlen(sent_pw));
+
+ if (code) {
+ /* XXX log only in the verify_krb5_user() call */
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Verifying krb5 password failed: %s",
+ krb5_get_err_text(kcontext, code));
+ if (!conf->krb_authoritative && all_principals_unkown == 1 && code == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN)
+ ret = DECLINED;
+ else
+ ret = HTTP_UNAUTHORIZED;
+
+ goto end;
+ }
+
+ code = krb5_unparse_name(kcontext, client, &name);
+ if (code) {
+ log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "krb5_unparse_name() failed: %s",
+ krb5_get_err_text(kcontext, code));
+ ret = HTTP_UNAUTHORIZED;
+ goto end;
+ }
+ MK_USER = ap_pstrdup (r->pool, name);
+ MK_AUTH_TYPE = "Basic";
+ free(name);
+
+ if (conf->krb_save_credentials)
+ store_krb5_creds(kcontext, r, conf, ccache);
+
+ ret = OK;