diff options
author | Nalin Dahyabhai <nalin@dahyabhai.net> | 2012-07-23 18:18:58 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2012-10-16 19:22:37 -0400 |
commit | 4e89b0b186ec90a6a06dd761d61ab45d82db599a (patch) | |
tree | ca59cffc6c705d7687753ea6e29416c011475dc3 | |
parent | ebb41dbb797d7a922aaca9b3c09a3e05c45b5a72 (diff) | |
download | krb5-4e89b0b186ec90a6a06dd761d61ab45d82db599a.tar.gz krb5-4e89b0b186ec90a6a06dd761d61ab45d82db599a.tar.xz krb5-4e89b0b186ec90a6a06dd761d61ab45d82db599a.zip |
Add "pa_type" configuration to ccaches
* When producing preauth data, keep track of the type of padata in the
KDC's list of acceptable types which prompted the module to produce
padata.
* After obtaining credentials, store that value as a "pa_type"
configuration item in the out_ccache.
* Read that allowed preauth type from an in_ccache, if possible.
* If we have an allowed preauth type, only call "real" modules that
handle that value when filling in responder items and producing a
client request.
ticket: 7414 (new)
-rw-r--r-- | src/include/k5-int.h | 12 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 66 | ||||
-rw-r--r-- | src/lib/krb5/krb/init_creds_ctx.h | 2 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth2.c | 17 |
4 files changed, 97 insertions, 0 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 169d6d3958..d5299c597e 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -282,6 +282,7 @@ typedef INT64_TYPE krb5_int64; #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 @@ -839,6 +840,17 @@ struct krb5_clpreauth_rock_st { 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 { diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index 225f34f528..9929fdb8ed 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -830,6 +830,8 @@ krb5_init_creds_init(krb5_context context, 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; @@ -1088,6 +1090,53 @@ init_creds_validate_reply(krb5_context context, 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, @@ -1123,6 +1172,11 @@ init_creds_step_request(krb5_context context, 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, @@ -1396,6 +1450,15 @@ init_creds_step_reply(krb5_context 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, @@ -1507,7 +1570,10 @@ init_creds_step_reply(krb5_context context, 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; diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index eb7b608c44..b4925ef697 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -47,6 +47,8 @@ struct _krb5_init_creds_context { krb5_boolean sent_nontrivial_preauth; krb5_boolean preauth_required; struct krb5_responder_context_st rctx; + krb5_preauthtype selected_preauth_type; + krb5_preauthtype allowed_preauth_type; }; krb5_error_code diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index 1ee53a6b72..dc8a31dd6d 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -536,6 +536,10 @@ run_preauth_plugins(krb5_context kcontext, /* 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) { @@ -570,6 +574,9 @@ run_preauth_plugins(krb5_context kcontext, 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) { @@ -821,6 +828,12 @@ krb5_do_preauth_tryagain(krb5_context kcontext, 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; } @@ -873,6 +886,10 @@ fill_response_items(krb5_context context, krb5_kdc_req *request, 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, |