Skip to content

Commit

Permalink
Add "pa_config_data" configuration to ccaches
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
nalind authored and greghudson committed Oct 17, 2012
1 parent 9364a03 commit f6a42c2
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 48 deletions.
48 changes: 1 addition & 47 deletions src/include/k5-int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions src/include/krb5/preauth_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
84 changes: 84 additions & 0 deletions src/lib/krb5/krb/get_in_tkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
53 changes: 53 additions & 0 deletions src/lib/krb5/krb/init_creds_ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
46 changes: 45 additions & 1 deletion src/lib/krb5/krb/preauth2.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@
*/

#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>
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/lib/krb5/krb/preauth_sam2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit f6a42c2

Please sign in to comment.