krb5 commit: Add "pa_type" configuration to ccaches

Greg Hudson ghudson at MIT.EDU
Tue Oct 16 19:23:09 EDT 2012


https://github.com/krb5/krb5/commit/4e89b0b186ec90a6a06dd761d61ab45d82db599a
commit 4e89b0b186ec90a6a06dd761d61ab45d82db599a
Author: Nalin Dahyabhai <nalin at dahyabhai.net>
Date:   Mon Jul 23 18:18:58 2012 -0400

    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)

 src/include/k5-int.h              |   12 +++++++
 src/lib/krb5/krb/get_in_tkt.c     |   66 +++++++++++++++++++++++++++++++++++++
 src/lib/krb5/krb/init_creds_ctx.h |    2 +
 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 169d6d3..d5299c5 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 225f34f..9929fdb 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 eb7b608..b4925ef 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 1ee53a6..dc8a31d 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,


More information about the cvs-krb5 mailing list