#define KRB5_CONF_FAST_AVAIL "fast_avail"
#define KRB5_CONF_PROXY_IMPERSONATOR "proxy_impersonator"
#define KRB5_CONF_REFRESH_TIME "refresh_time"
+#define KRB5_CONF_PA_TYPE "pa_type"
/* Error codes used in KRB_ERROR protocol messages.
Return values of library routines are based on a different error table
krb5_int32 pa_offset_usec;
enum { NO_OFFSET = 0, UNAUTH_OFFSET, AUTH_OFFSET } pa_offset_state;
struct krb5_responder_context_st rctx;
+
+ /*
+ * Configuration information read from an in_ccache, actually stored in the
+ * containing context structure, but needed by callbacks which currently
+ * only get a pointer to the rock
+ */
+
+ /* The allowed preauth type (number) that we might use, equal to
+ * KRB5_PADATA_NONE if none was set. */
+ krb5_preauthtype *allowed_preauth_type;
+ krb5_preauthtype *selected_preauth_type;
};
typedef struct _krb5_pa_enc_ts {
ctx->preauth_rock.client = client;
ctx->preauth_rock.prompter = prompter;
ctx->preauth_rock.prompter_data = data;
+ ctx->preauth_rock.allowed_preauth_type = &ctx->allowed_preauth_type;
+ ctx->preauth_rock.selected_preauth_type = &ctx->selected_preauth_type;
/* Initialise request parameters as per krb5_get_init_creds() */
ctx->request->kdc_options = context->kdc_default_options;
return 0;
}
+static void
+read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx)
+{
+ krb5_data config;
+ char *tmp, *p;
+
+ ctx->allowed_preauth_type = KRB5_PADATA_NONE;
+ if (ctx->opte->opt_private->in_ccache == NULL)
+ return;
+ memset(&config, 0, sizeof(config));
+ if (krb5_cc_get_config(context, ctx->opte->opt_private->in_ccache,
+ ctx->request->server,
+ KRB5_CONF_PA_TYPE, &config) != 0)
+ return;
+ tmp = malloc(config.length + 1);
+ if (tmp == NULL) {
+ krb5_free_data_contents(context, &config);
+ return;
+ }
+ memcpy(tmp, config.data, config.length);
+ tmp[config.length] = '\0';
+ ctx->allowed_preauth_type = strtol(tmp, &p, 10);
+ if (p == NULL || *p != '\0')
+ ctx->allowed_preauth_type = KRB5_PADATA_NONE;
+ free(tmp);
+ krb5_free_data_contents(context, &config);
+}
+
+static krb5_error_code
+save_selected_preauth_type(krb5_context context, krb5_ccache ccache,
+ krb5_init_creds_context ctx)
+{
+ krb5_data config_data;
+ char *tmp;
+ krb5_error_code code;
+
+ if (ctx->selected_preauth_type == KRB5_PADATA_NONE)
+ return 0;
+ if (asprintf(&tmp, "%ld", (long)ctx->selected_preauth_type) < 0)
+ return ENOMEM;
+ config_data = string2data(tmp);
+ code = krb5_cc_set_config(context, ccache, ctx->cred.server,
+ KRB5_CONF_PA_TYPE, &config_data);
+ free(tmp);
+ return code;
+}
+
static krb5_error_code
init_creds_step_request(krb5_context context,
krb5_init_creds_context ctx,
if (code)
goto cleanup;
+ /* Read the allowed patype for this server principal from the in_ccache,
+ * if the application supplied one. */
+ read_allowed_preauth_type(context, ctx);
+ ctx->selected_preauth_type = KRB5_PADATA_NONE;
+
if (ctx->err_reply == NULL) {
/* either our first attempt, or retrying after PREAUTH_NEEDED */
code = krb5_do_preauth(context,
ctx->etype = ctx->reply->enc_part.enctype;
+ /*
+ * At this point, allow whichever preauth plugin that can handle the KDC's
+ * reply padata to do so, regardless of that data's padata type. We don't
+ * want to record the type of padata in the reply, so set the pointer for
+ * that data to NULL.
+ */
+ ctx->allowed_preauth_type = KRB5_PADATA_NONE;
+ ctx->preauth_rock.selected_preauth_type = NULL;
+
code = krb5_do_preauth(context,
ctx->request,
ctx->inner_request_body,
config_data.length = strlen(config_data.data);
code = krb5_cc_set_config(context, out_ccache, ctx->cred.server,
KRB5_CONF_FAST_AVAIL, &config_data);
+ if (code != 0)
+ goto cc_cleanup;
}
+ code = save_selected_preauth_type(context, out_ccache, ctx);
cc_cleanup:
if (code !=0) {
const char *msg;
/* skip over those which don't match the flags (INFO vs REAL, mainly) */
if ((module->flags & module_required_flags) == 0)
continue;
+ if ((module->flags & PA_REAL) &&
+ *preauth_rock->allowed_preauth_type != KRB5_PADATA_NONE &&
+ in_padata->pa_type != *preauth_rock->allowed_preauth_type)
+ continue;
/* if it's a REAL module, try to call it only once per library call */
if (module_required_flags & PA_REAL) {
if (module->use_count > 0) {
if (ret != 0)
return ret;
}
+ /* Record which pa_type we answered a call for. */
+ if (preauth_rock->selected_preauth_type != NULL)
+ *preauth_rock->selected_preauth_type = in_padata->pa_type;
break;
}
if (i >= kcontext->preauth_context->n_modules) {
if (module->pa_type != padata[i]->pa_type) {
continue;
}
+ if ((module->flags & PA_REAL) &&
+ *preauth_rock->allowed_preauth_type != KRB5_PADATA_NONE &&
+ padata[i]->pa_type != *preauth_rock->allowed_preauth_type) {
+ /* It's unlikely that we'll get here. */
+ continue;
+ }
if (module->client_tryagain == NULL) {
continue;
}
prep_questions = module->client_prep_questions;
if (module->pa_type != pa->pa_type || prep_questions == NULL)
continue;
+ if ((module->flags & PA_REAL) &&
+ *rock->allowed_preauth_type != KRB5_PADATA_NONE &&
+ pa->pa_type != *rock->allowed_preauth_type)
+ continue;
ret = (*prep_questions)(context, module->moddata,
*module->modreq_p,
(krb5_get_init_creds_opt *)opte,