]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add "pa_config_data" configuration to ccaches
authorNalin Dahyabhai <nalin@dahyabhai.net>
Mon, 17 Sep 2012 22:16:51 +0000 (18:16 -0400)
committerGreg Hudson <ghudson@mit.edu>
Wed, 17 Oct 2012 19:24:52 +0000 (15:24 -0400)
* Read a "pa_config_data" item from an in_ccache, if provided, and add a
  callback which client preauth plugins can use to retrieve a string
  value from it that's keyed by a string.
* Add a callback which client preauth plugins can use to provide string
  key/value pairs to be stored in the ccache.
* Moves the definition of (struct krb5_clpreauth_rock_st) from k5-int.h
  to init_creds_ctx.h to try to reduce the number of files that will
  need to include k5-json.h to understand k5_json_value.

src/include/k5-int.h
src/include/krb5/preauth_plugin.h
src/lib/krb5/krb/get_in_tkt.c
src/lib/krb5/krb/init_creds_ctx.h
src/lib/krb5/krb/preauth2.c
src/lib/krb5/krb/preauth_sam2.c

index 08e8dcd5add3d0412010f5b6dfa1634c17f7f908..75e67831135334cb42e733b63a2544a41a8f700d 100644 (file)
@@ -283,6 +283,7 @@ typedef INT64_TYPE krb5_int64;
 #define KRB5_CONF_PROXY_IMPERSONATOR          "proxy_impersonator"
 #define KRB5_CONF_REFRESH_TIME                "refresh_time"
 #define KRB5_CONF_PA_TYPE                     "pa_type"
+#define KRB5_CONF_PA_CONFIG_DATA              "pa_config_data"
 
 /* Error codes used in KRB_ERROR protocol messages.
    Return values of library routines are based on a different error table
@@ -806,53 +807,6 @@ typedef krb5_error_code
                            krb5_keyblock *as_key, void *gak_data,
                            k5_response_items *ritems);
 
-#define CLIENT_ROCK_MAGIC 0x4352434b
-/*
- * This structure is passed into the clpreauth methods and passed back to
- * clpreauth callbacks so that they can locate the requested information.  It
- * is opaque to the plugin code and can be expanded in the future as new types
- * of requests are defined which may require other things to be passed through.
- * All pointer fields are aliases and should not be freed.
- */
-struct krb5int_fast_request_state;
-struct krb5_clpreauth_rock_st {
-    krb5_magic magic;
-    krb5_enctype *etype;
-    struct krb5int_fast_request_state *fast_state;
-
-    /*
-     * These fields allow gak_fct to be called via the rock.  The
-     * gak_fct and gak_data fields have an extra level of indirection
-     * since they can change in the init_creds context.
-     */
-    krb5_keyblock *as_key;
-    krb5_gic_get_as_key_fct *gak_fct;
-    void **gak_data;
-    krb5_boolean *default_salt;
-    krb5_data *salt;
-    krb5_data *s2kparams;
-    krb5_principal client;
-    krb5_prompter_fct prompter;
-    void *prompter_data;
-
-    /* Discovered offset of server time during preauth */
-    krb5_timestamp pa_offset;
-    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 {
     krb5_timestamp      patimestamp;
     krb5_int32          pausec;
index 2ae077c941f8b6732f4926790d0116b18b15cc96..f2fca372a26dad0d8231384266b26801e2851ce7 100644 (file)
@@ -209,6 +209,22 @@ typedef struct krb5_clpreauth_callbacks_st {
     /* Indicate interest in the AS key through the responder interface. */
     void (*need_as_key)(krb5_context context, krb5_clpreauth_rock rock);
 
+    /*
+     * Get a configuration/state item from an input ccache, which may allow it
+     * to retrace the steps it took last time.  The returned data string is an
+     * alias and should not be freed.
+     */
+    const char *(*get_cc_config)(krb5_context context,
+                                 krb5_clpreauth_rock rock, const char *key);
+
+    /*
+     * Set a configuration/state item which will be recorded to an output
+     * ccache, if the calling application supplied one.  Both key and data
+     * should be valid UTF-8 text.
+     */
+    krb5_error_code (*set_cc_config)(krb5_context context,
+                                     krb5_clpreauth_rock rock,
+                                     const char *key, const char *data);
     /* End of version 2 clpreauth callbacks (added in 1.11). */
 } *krb5_clpreauth_callbacks;
 
index 9929fdb8edd217e4b3ed6cc257e2c05568e6b4ff..c2cd9e883726eb2c534d2b49088be8cac3c52b5e 100644 (file)
@@ -832,6 +832,8 @@ krb5_init_creds_init(krb5_context context,
     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;
+    ctx->preauth_rock.cc_config_in = &ctx->cc_config_in;
+    ctx->preauth_rock.cc_config_out = &ctx->cc_config_out;
 
     /* Initialise request parameters as per krb5_get_init_creds() */
     ctx->request->kdc_options = context->kdc_default_options;
@@ -1137,6 +1139,77 @@ save_selected_preauth_type(krb5_context context, krb5_ccache ccache,
     return code;
 }
 
+static krb5_error_code
+clear_cc_config_out_data(krb5_context context, krb5_init_creds_context ctx)
+{
+    if (ctx->cc_config_out != NULL)
+        k5_json_release(ctx->cc_config_out);
+    ctx->cc_config_out = k5_json_object_create();
+    if (ctx->cc_config_out == NULL)
+        return ENOMEM;
+    return 0;
+}
+
+static krb5_error_code
+read_cc_config_in_data(krb5_context context, krb5_init_creds_context ctx)
+{
+    krb5_data config;
+    char *encoded;
+    krb5_error_code code;
+    int i;
+
+    if (ctx->cc_config_in != NULL)
+        k5_json_release(ctx->cc_config_in);
+    ctx->cc_config_in = NULL;
+
+    if (ctx->opte->opt_private->in_ccache == NULL)
+        return 0;
+
+    memset(&config, 0, sizeof(config));
+    code = krb5_cc_get_config(context, ctx->opte->opt_private->in_ccache,
+                              ctx->request->server,
+                              KRB5_CONF_PA_CONFIG_DATA, &config);
+    if (code)
+        return code;
+
+    i = asprintf(&encoded, "%.*s", (int)config.length, config.data);
+    krb5_free_data_contents(context, &config);
+    if (i < 0)
+        return ENOMEM;
+
+    ctx->cc_config_in = k5_json_decode(encoded);
+    free(encoded);
+    if (ctx->cc_config_in == NULL)
+        return ENOMEM;
+    if (k5_json_get_tid(ctx->cc_config_in) != K5_JSON_TID_OBJECT) {
+        k5_json_release(ctx->cc_config_in);
+        ctx->cc_config_in = NULL;
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+save_cc_config_out_data(krb5_context context, krb5_ccache ccache,
+                        krb5_init_creds_context ctx)
+{
+    krb5_data config;
+    char *encoded;
+    krb5_error_code code;
+
+    if (ctx->cc_config_out == NULL)
+        return 0;
+    encoded = k5_json_encode(ctx->cc_config_out);
+    if (encoded == NULL)
+        return ENOMEM;
+    config = string2data(encoded);
+    code = krb5_cc_set_config(context, ccache, ctx->cred.server,
+                              KRB5_CONF_PA_CONFIG_DATA, &config);
+    free(encoded);
+    return code;
+}
+
 static krb5_error_code
 init_creds_step_request(krb5_context context,
                         krb5_init_creds_context ctx,
@@ -1177,6 +1250,14 @@ init_creds_step_request(krb5_context context,
     read_allowed_preauth_type(context, ctx);
     ctx->selected_preauth_type = KRB5_PADATA_NONE;
 
+    /*
+     * Read cached preauth configuration data for this server principal from
+     * the in_ccache, if the application supplied one, and delete any that was
+     * stored by a previous (clearly failed) module.
+     */
+    read_cc_config_in_data(context, ctx);
+    clear_cc_config_out_data(context, ctx);
+
     if (ctx->err_reply == NULL) {
         /* either our first attempt, or retrying after PREAUTH_NEEDED */
         code = krb5_do_preauth(context,
@@ -1574,6 +1655,9 @@ init_creds_step_reply(krb5_context context,
                 goto cc_cleanup;
         }
         code = save_selected_preauth_type(context, out_ccache, ctx);
+        if (code != 0)
+            goto cc_cleanup;
+        code = save_cc_config_out_data(context, out_ccache, ctx);
     cc_cleanup:
         if (code !=0) {
             const char *msg;
index b4925ef697f1de840b504b514ab9c73563d6e932..e893113a05339e2011066115ec13b209fd858c78 100644 (file)
@@ -3,6 +3,57 @@
 #ifndef KRB5_INIT_CREDS_CONTEXT
 #define KRB5_INIT_CREDS_CONTEXT 1
 
+#include "k5-json.h"
+
+#define CLIENT_ROCK_MAGIC 0x4352434b
+/*
+ * This structure is passed into the clpreauth methods and passed back to
+ * clpreauth callbacks so that they can locate the requested information.  It
+ * is opaque to the plugin code and can be expanded in the future as new types
+ * of requests are defined which may require other things to be passed through.
+ * All pointer fields are aliases and should not be freed.
+ */
+struct krb5_clpreauth_rock_st {
+    krb5_magic magic;
+    krb5_enctype *etype;
+    struct krb5int_fast_request_state *fast_state;
+
+    /*
+     * These fields allow gak_fct to be called via the rock.  The
+     * gak_fct and gak_data fields have an extra level of indirection
+     * since they can change in the init_creds context.
+     */
+    krb5_keyblock *as_key;
+    krb5_gic_get_as_key_fct *gak_fct;
+    void **gak_data;
+    krb5_boolean *default_salt;
+    krb5_data *salt;
+    krb5_data *s2kparams;
+    krb5_principal client;
+    krb5_prompter_fct prompter;
+    void *prompter_data;
+
+    /* Discovered offset of server time during preauth */
+    krb5_timestamp pa_offset;
+    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;
+    /* Preauth configuration data which can help us make some decisions. */
+    k5_json_value *cc_config_in;
+    k5_json_value *cc_config_out;
+};
+
 struct _krb5_init_creds_context {
     krb5_gic_opt_ext *opte;
     char *in_tkt_service;
@@ -49,6 +100,8 @@ struct _krb5_init_creds_context {
     struct krb5_responder_context_st rctx;
     krb5_preauthtype selected_preauth_type;
     krb5_preauthtype allowed_preauth_type;
+    void *cc_config_in;
+    void *cc_config_out;
 };
 
 krb5_error_code
index dc8a31dd6d4226185ce542d70a0ec81fdbf88509..9ce82d5a35e62ea0c307b9fa8f542c240bcb5cd8 100644 (file)
  */
 
 #include "k5-int.h"
+#include "k5-json.h"
 #include "osconf.h"
 #include <krb5/preauth_plugin.h>
 #include "int-proto.h"
 #include "fast.h"
+#include "init_creds_ctx.h"
 
 #if !defined(_WIN32)
 #include <unistd.h>
@@ -436,6 +438,46 @@ need_as_key(krb5_context context, krb5_clpreauth_rock rock)
                      NULL, NULL, *rock->gak_data, rock->rctx.items);
 }
 
+static const char *
+get_cc_config(krb5_context context, krb5_clpreauth_rock rock, const char *key)
+{
+    k5_json_value value;
+
+    if (rock->cc_config_in == NULL || *rock->cc_config_in == NULL)
+        return NULL;
+
+    value = k5_json_object_get(*rock->cc_config_in, key);
+    if (value == NULL)
+        return NULL;
+
+    if (k5_json_get_tid(value) != K5_JSON_TID_STRING)
+        return NULL;
+
+    return k5_json_string_utf8(value);
+}
+
+static krb5_error_code
+set_cc_config(krb5_context context, krb5_clpreauth_rock rock,
+              const char *key, const char *data)
+{
+    k5_json_value value;
+    int i;
+
+    if (rock->cc_config_out == NULL || *rock->cc_config_out == NULL)
+        return ENOENT;
+
+    value = k5_json_string_create(data);
+    if (value == NULL)
+        return ENOMEM;
+
+    i = k5_json_object_set(*rock->cc_config_out, key, value);
+    k5_json_release(value);
+    if (i < 0)
+        return ENOMEM;
+
+    return 0;
+}
+
 static struct krb5_clpreauth_callbacks_st callbacks = {
     2,
     get_etype,
@@ -445,7 +487,9 @@ static struct krb5_clpreauth_callbacks_st callbacks = {
     get_preauth_time,
     responder_ask_question,
     responder_get_answer,
-    need_as_key
+    need_as_key,
+    get_cc_config,
+    set_cc_config
 };
 
 /* Tweak the request body, for now adding any enctypes which the module claims
index 0190137e960c6ce048567d657384a0cc4405adff..a5f63959780d3241292cc46f53d4d472b66f4a00 100644 (file)
@@ -28,6 +28,7 @@
 #include <k5-int.h>
 #include <krb5/preauth_plugin.h>
 #include "int-proto.h"
+#include "init_creds_ctx.h"
 
 static int
 sam2_flags(krb5_context context, krb5_preauthtype pa_type)