#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
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;
/* 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;
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;
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,
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,
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;
#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;
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
*/
#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>
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,
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
#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)