From e86b58e01cced6e9da381e023141a7954667349e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 12 Jun 2007 17:49:37 +0000 Subject: [PATCH] Add hooks for processing the reply from the server. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@21058 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/krb5/send_to_kdc.c | 147 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 131 insertions(+), 16 deletions(-) diff --git a/lib/krb5/send_to_kdc.c b/lib/krb5/send_to_kdc.c index 71946acf8..846022c84 100644 --- a/lib/krb5/send_to_kdc.c +++ b/lib/krb5/send_to_kdc.c @@ -413,26 +413,16 @@ krb5_sendto_kdc_flags(krb5_context context, int flags) { krb5_error_code ret; - krb5_krbhst_handle handle; - int type; + krb5_sendto_ctx ctx; - if ((flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) - type = KRB5_KRBHST_ADMIN; - else - type = KRB5_KRBHST_KDC; - - if (send_data->length > context->large_msg_size) - flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; - - ret = krb5_krbhst_init_flags(context, *realm, type, flags, &handle); + ret = krb5_sendto_ctx_alloc(context, &ctx); if (ret) return ret; + krb5_sendto_ctx_add_flags(ctx, flags); + krb5_sendto_ctx_set_func(ctx, _krb5_kdc_retry, NULL); - ret = krb5_sendto(context, send_data, handle, receive); - krb5_krbhst_free(context, handle); - if (ret == KRB5_KDC_UNREACH) - krb5_set_error_string(context, - "unable to reach any KDC in realm %s", *realm); + ret = krb5_sendto_context(context, ctx, send_data, *realm, receive); + krb5_sendto_ctx_free(context, ctx); return ret; } @@ -458,4 +448,129 @@ krb5_set_send_to_kdc_func(krb5_context context, return 0; } +struct krb5_sendto_ctx { + int flags; + int type; + krb5_sendto_ctx_func func; + void *data; +}; +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx) +{ + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + return 0; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_add_flags(krb5_sendto_ctx ctx, int flags) +{ + ctx->flags |= flags; +} + +int KRB5_LIB_FUNCTION +krb5_sendto_ctx_get_flags(krb5_sendto_ctx ctx) +{ + return ctx->flags; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_type(krb5_sendto_ctx ctx, int type) +{ + ctx->type = type; +} + + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_func(krb5_sendto_ctx ctx, + krb5_sendto_ctx_func func, + void *data) +{ + ctx->func = func; + ctx->data = data; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_free(krb5_context context, krb5_sendto_ctx ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + free(ctx); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_context(krb5_context context, + krb5_sendto_ctx ctx, + const krb5_data *send_data, + const krb5_realm realm, + krb5_data *receive) +{ + krb5_error_code ret; + krb5_krbhst_handle handle = NULL; + int type, freectx = 0; + int action; + + krb5_data_zero(receive); + + if (ctx == NULL) { + freectx = 1; + ret = krb5_sendto_ctx_alloc(context, &ctx); + if (ret) + return ret; + } + + type = ctx->type; + if (type == 0) { + if ((ctx->flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) + type = KRB5_KRBHST_ADMIN; + else + type = KRB5_KRBHST_KDC; + } + + if (send_data->length > context->large_msg_size) + ctx->flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; + + /* loop until we get back a appropriate response */ + + do { + action = KRB5_SENDTO_DONE; + + krb5_data_free(receive); + + if (handle == NULL) { + ret = krb5_krbhst_init_flags(context, realm, type, + ctx->flags, &handle); + if (ret) { + if (freectx) + krb5_sendto_ctx_free(context, ctx); + return ret; + } + } + + ret = krb5_sendto(context, send_data, handle, receive); + if (ret) + break; + if (ctx->func) { + ret = (*ctx->func)(context, ctx, ctx->data, receive, &action); + if (ret) + break; + } + if (action != KRB5_SENDTO_CONTINUE) { + krb5_krbhst_free(context, handle); + handle = NULL; + } + } while (action != KRB5_SENDTO_DONE); + if (handle) + krb5_krbhst_free(context, handle); + if (ret == KRB5_KDC_UNREACH) + krb5_set_error_string(context, + "unable to reach any KDC in realm %s", realm); + if (ret) + krb5_data_free(receive); + if (freectx) + krb5_sendto_ctx_free(context, ctx); + return ret; +}