From 6f143d99b3668e6020a1525f839acac54934dbb5 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Fri, 12 Oct 2012 10:33:36 -0400 Subject: [PATCH] Add responder support to get_as_key() This follows the design laid out on the project page: http://k5wiki.kerberos.org/wiki/Projects/Password_response_item --- src/include/k5-int.h | 3 ++- src/include/krb5/krb5.hin | 10 ++++++++++ src/include/krb5/preauth_plugin.h | 3 +++ src/lib/krb5/krb/get_in_tkt.c | 2 +- src/lib/krb5/krb/gic_keytab.c | 7 ++++++- src/lib/krb5/krb/gic_pwd.c | 29 +++++++++++++++++++++++++++-- src/lib/krb5/krb/init_creds_ctx.h | 3 ++- src/lib/krb5/krb/preauth2.c | 20 ++++++++++++++++++-- src/lib/krb5/krb/preauth_sam2.c | 2 +- 9 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/include/k5-int.h b/src/include/k5-int.h index b96d9675d8..57a6277a83 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -802,7 +802,8 @@ typedef krb5_error_code (*krb5_gic_get_as_key_fct)(krb5_context, krb5_principal, krb5_enctype, krb5_prompter_fct, void *prompter_data, krb5_data *salt, krb5_data *s2kparams, - krb5_keyblock *as_key, void *gak_data); + krb5_keyblock *as_key, void *gak_data, + k5_response_items *ritems); #define CLIENT_ROCK_MAGIC 0x4352434b /* diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 933d2b450a..db71f962d4 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -6357,6 +6357,16 @@ krb5_prompter_posix(krb5_context context, void *data, const char *name, const char *banner, int num_prompts, krb5_prompt prompts[]); +/** + * Long-term password responder question + * + * This question is asked when the long-term password is needed. It has no + * challenge and the response is simply the password string. + * + * @version First introduced in 1.11 + */ +#define KRB5_RESPONDER_QUESTION_PASSWORD "password" + typedef struct krb5_responder_context_st *krb5_responder_context; /** diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h index a9a2ab9d2c..2ae077c941 100644 --- a/src/include/krb5/preauth_plugin.h +++ b/src/include/krb5/preauth_plugin.h @@ -206,6 +206,9 @@ typedef struct krb5_clpreauth_callbacks_st { krb5_clpreauth_rock rock, const char *question); + /* Indicate interest in the AS key through the responder interface. */ + void (*need_as_key)(krb5_context context, krb5_clpreauth_rock rock); + /* End of version 2 clpreauth callbacks (added in 1.11). */ } *krb5_clpreauth_callbacks; diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index d52147ac26..01eba6b040 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -1458,7 +1458,7 @@ init_creds_step_reply(krb5_context context, ctx->reply->enc_part.enctype, ctx->prompter, ctx->prompter_data, &ctx->salt, &ctx->s2kparams, - &ctx->as_key, ctx->gak_data); + &ctx->as_key, ctx->gak_data, NULL); if (code != 0) goto cleanup; TRACE_INIT_CREDS_AS_KEY_GAK(context, &ctx->as_key); diff --git a/src/lib/krb5/krb/gic_keytab.c b/src/lib/krb5/krb/gic_keytab.c index 38051dbfdb..0fd1034a38 100644 --- a/src/lib/krb5/krb/gic_keytab.c +++ b/src/lib/krb5/krb/gic_keytab.c @@ -38,13 +38,18 @@ get_as_key_keytab(krb5_context context, krb5_data *salt, krb5_data *params, krb5_keyblock *as_key, - void *gak_data) + void *gak_data, + k5_response_items *ritems) { krb5_keytab keytab = (krb5_keytab) gak_data; krb5_error_code ret; krb5_keytab_entry kt_ent; krb5_keyblock *kt_key; + /* We don't need the password from the responder to create the AS key. */ + if (as_key == NULL) + return 0; + /* if there's already a key of the correct etype, we're done. if the etype is wrong, free the existing key, and make a new one. */ diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c index f5c0b30278..8ffa342be6 100644 --- a/src/lib/krb5/krb/gic_pwd.c +++ b/src/lib/krb5/krb/gic_pwd.c @@ -2,6 +2,7 @@ #include "k5-int.h" #include "com_err.h" #include "init_creds_ctx.h" +#include "int-proto.h" krb5_error_code krb5_get_as_key_password(krb5_context context, @@ -12,7 +13,8 @@ krb5_get_as_key_password(krb5_context context, krb5_data *salt, krb5_data *params, krb5_keyblock *as_key, - void *gak_data) + void *gak_data, + k5_response_items *ritems) { krb5_data *password; krb5_error_code ret; @@ -21,8 +23,21 @@ krb5_get_as_key_password(krb5_context context, char promptstr[1024]; krb5_prompt prompt; krb5_prompt_type prompt_type; + const char *rpass; password = (krb5_data *) gak_data; + assert(password->length > 0); + + /* If we need to get the AS key via the responder, ask for it. */ + if (as_key == NULL) { + /* However, if we already have a password, don't ask. */ + if (password->data[0] != '\0') + return 0; + + return k5_response_items_ask_question(ritems, + KRB5_RESPONDER_QUESTION_PASSWORD, + NULL ); + } /* If there's already a key of the correct etype, we're done. If the etype is wrong, free the existing key, and make @@ -39,7 +54,17 @@ krb5_get_as_key_password(krb5_context context, } } - if (password->length == 0 || password->data[0] == '\0') { + if (password->data[0] == '\0') { + /* Check the responder for the password. */ + rpass = k5_response_items_get_answer(ritems, + KRB5_RESPONDER_QUESTION_PASSWORD); + if (rpass != NULL) { + strlcpy(password->data, rpass, password->length); + password->length = strlen(password->data); + } + } + + if (password->data[0] == '\0') { if (prompter == NULL) return(EIO); diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index ae69ed0828..eb7b608c44 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -58,6 +58,7 @@ krb5_get_as_key_password(krb5_context context, krb5_data *salt, krb5_data *params, krb5_keyblock *as_key, - void *gak_data); + void *gak_data, + k5_response_items *ritems); #endif /* !KRB5_INIT_CREDS_CONTEXT */ diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index cf46845e2e..1ee53a6b72 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -372,7 +372,8 @@ get_as_key(krb5_context context, krb5_clpreauth_rock rock, salt = (*rock->default_salt) ? NULL : rock->salt; ret = (*rock->gak_fct)(context, rock->client, *rock->etype, rock->prompter, rock->prompter_data, salt, - rock->s2kparams, rock->as_key, *rock->gak_data); + rock->s2kparams, rock->as_key, *rock->gak_data, + rock->rctx.items); if (ret) return ret; } @@ -410,6 +411,9 @@ static krb5_error_code responder_ask_question(krb5_context context, krb5_clpreauth_rock rock, const char *question, const char *challenge) { + /* Force plugins to use need_as_key(). */ + if (strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) + return EINVAL; return k5_response_items_ask_question(rock->rctx.items, question, challenge); } @@ -418,9 +422,20 @@ static const char * responder_get_answer(krb5_context context, krb5_clpreauth_rock rock, const char *question) { + /* Don't let plugins get the raw password. */ + if (question && strcmp(KRB5_RESPONDER_QUESTION_PASSWORD, question) == 0) + return NULL; return k5_response_items_get_answer(rock->rctx.items, question); } +static void +need_as_key(krb5_context context, krb5_clpreauth_rock rock) +{ + /* Calling gac_fct() with NULL as_key indicates desire for the AS key. */ + (*rock->gak_fct)(context, rock->client, *rock->etype, NULL, NULL, NULL, + NULL, NULL, *rock->gak_data, rock->rctx.items); +} + static struct krb5_clpreauth_callbacks_st callbacks = { 2, get_etype, @@ -429,7 +444,8 @@ static struct krb5_clpreauth_callbacks_st callbacks = { set_as_key, get_preauth_time, responder_ask_question, - responder_get_answer + responder_get_answer, + need_as_key }; /* Tweak the request body, for now adding any enctypes which the module claims diff --git a/src/lib/krb5/krb/preauth_sam2.c b/src/lib/krb5/krb/preauth_sam2.c index 4c63ff42c2..0190137e96 100644 --- a/src/lib/krb5/krb/preauth_sam2.c +++ b/src/lib/krb5/krb/preauth_sam2.c @@ -155,7 +155,7 @@ sam2_process(krb5_context context, krb5_clpreauth_moddata moddata, retval = (*rock->gak_fct)(context, request->client, sc2b->sam_etype, prompter, prompter_data, rock->salt, rock->s2kparams, rock->as_key, - *rock->gak_data); + *rock->gak_data, rock->rctx.items); if (retval) { krb5_free_sam_challenge_2(context, sc2); krb5_free_sam_challenge_2_body(context, sc2b); -- 2.47.2