void KRB5_LIB_FUNCTION krb5_free_error_contents (krb5_context context, krb5_error *error) { free_KRB_ERROR(error); memset(error, 0, sizeof(*error)); }
void KRB5_LIB_FUNCTION _krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt) { if (opt->opt_private == NULL || opt->opt_private->error == NULL) return; free_KRB_ERROR(opt->opt_private->error); free(opt->opt_private->error); opt->opt_private->error = NULL; }
krb5_error_code KRB5_LIB_FUNCTION krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep) { free_KDC_REP(&rep->kdc_rep); free_EncTGSRepPart(&rep->enc_part); free_KRB_ERROR(&rep->error); memset(rep, 0, sizeof(*rep)); return 0; }
static void free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) { if (ctx->etypes) free(ctx->etypes); if (ctx->pre_auth_types) free (ctx->pre_auth_types); if (ctx->in_tkt_service) free(ctx->in_tkt_service); if (ctx->keytab_data) free(ctx->keytab_data); krb5_data_free(&ctx->req_buffer); krb5_free_cred_contents(context, &ctx->cred); free_METHOD_DATA(&ctx->md); free_AS_REP(&ctx->as_rep); free_EncKDCRepPart(&ctx->enc_part); free_KRB_ERROR(&ctx->error); free_AS_REQ(&ctx->as_req); memset(ctx, 0, sizeof(*ctx)); }
static krb5_error_code process_reply (krb5_context context, krb5_auth_context auth_context, int is_stream, int sock, int *result_code, krb5_data *result_code_string, krb5_data *result_string, const char *host) { krb5_error_code ret; u_char reply[1024 * 3]; ssize_t len; u_int16_t pkt_len, pkt_ver; krb5_data ap_rep_data; int save_errno; len = 0; if (is_stream) { while (len < sizeof(reply)) { unsigned long size; ret = recvfrom (sock, reply + len, sizeof(reply) - len, 0, NULL, NULL); if (ret < 0) { save_errno = errno; krb5_set_error_string(context, "recvfrom %s: %s", host, strerror(save_errno)); return save_errno; } else if (ret == 0) { krb5_set_error_string(context, "recvfrom timeout %s", host); return 1; } len += ret; if (len < 4) continue; _krb5_get_int(reply, &size, 4); if (size + 4 < len) continue; memmove(reply, reply + 4, size); len = size; break; } if (len == sizeof(reply)) { krb5_set_error_string(context, "message too large from %s", host); return ENOMEM; } } else { ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL); if (ret < 0) { save_errno = errno; krb5_set_error_string(context, "recvfrom %s: %s", host, strerror(save_errno)); return save_errno; } len = ret; } if (len < 6) { str2data (result_string, "server %s sent to too short message " "(%ld bytes)", host, (long)len); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } pkt_len = (reply[0] << 8) | (reply[1]); pkt_ver = (reply[2] << 8) | (reply[3]); if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) { KRB_ERROR error; size_t size; u_char *p; memset(&error, 0, sizeof(error)); ret = decode_KRB_ERROR(reply, len, &error, &size); if (ret) return ret; if (error.e_data->length < 2) { str2data(result_string, "server %s sent too short " "e_data to print anything usable", host); free_KRB_ERROR(&error); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } p = error.e_data->data; *result_code = (p[0] << 8) | p[1]; if (error.e_data->length == 2) str2data(result_string, "server only sent error code"); else krb5_data_copy (result_string, p + 2, error.e_data->length - 2); free_KRB_ERROR(&error); return 0; } if (pkt_len != len) { str2data (result_string, "client: wrong len in reply"); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) { str2data (result_string, "client: wrong version number (%d)", pkt_ver); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } ap_rep_data.data = reply + 6; ap_rep_data.length = (reply[4] << 8) | (reply[5]); if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) { str2data (result_string, "client: wrong AP len in reply"); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } if (ap_rep_data.length) { krb5_ap_rep_enc_part *ap_rep; krb5_data priv_data; u_char *p; priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length; priv_data.length = len - ap_rep_data.length - 6; ret = krb5_rd_rep (context, auth_context, &ap_rep_data, &ap_rep); if (ret) return ret; krb5_free_ap_rep_enc_part (context, ap_rep); ret = krb5_rd_priv (context, auth_context, &priv_data, result_code_string, NULL); if (ret) { krb5_data_free (result_code_string); return ret; } if (result_code_string->length < 2) { *result_code = KRB5_KPASSWD_MALFORMED; str2data (result_string, "client: bad length in result"); return 0; } p = result_code_string->data; *result_code = (p[0] << 8) | p[1]; krb5_data_copy (result_string, (unsigned char*)result_code_string->data + 2, result_code_string->length - 2); return 0; } else { KRB_ERROR error; size_t size; u_char *p; ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size); if (ret) { return ret; } if (error.e_data->length < 2) { krb5_warnx (context, "too short e_data to print anything usable"); return 1; /* XXX */ } p = error.e_data->data; *result_code = (p[0] << 8) | p[1]; krb5_data_copy (result_string, p + 2, error.e_data->length - 2); return 0; } }
static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf) { KRB_ERROR error; size_t used; switch (test_context->test) { case TORTURE_KRB5_TEST_PLAIN: if (test_context->packet_count == 0) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) && (test_context->packet_count == 1)) { torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else { torture_assert_int_equal(test_context->tctx, decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, test_context->as_rep.pvno, 5, "Got wrong as_rep->pvno"); torture_assert_int_equal(test_context->tctx, test_context->as_rep.ticket.tkt_vno, 5, "Got wrong as_rep->ticket.tkt_vno"); torture_assert(test_context->tctx, test_context->as_rep.ticket.enc_part.kvno, "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno"); if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) { torture_assert_int_not_equal(test_context->tctx, *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000, 0, "Did not get a RODC number in the KVNO"); } else { torture_assert_int_equal(test_context->tctx, *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000, 0, "Unexpecedly got a RODC number in the KVNO"); } free_AS_REP(&test_context->as_rep); } torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets"); free_AS_REQ(&test_context->as_req); break; /* * Confirm correct error codes when we ask for the PAC. This behaviour is rather odd... */ case TORTURE_KRB5_TEST_PAC_REQUEST: if (test_context->packet_count == 0) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else if (test_context->packet_count == 1) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0) && (test_context->packet_count == 2)) { torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else { torture_assert_int_equal(test_context->tctx, decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, test_context->as_rep.pvno, 5, "Got wrong as_rep->pvno"); free_AS_REP(&test_context->as_rep); } torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets"); free_AS_REQ(&test_context->as_req); break; /* * Confirm correct error codes when we deliberatly send the wrong password */ case TORTURE_KRB5_TEST_BREAK_PW: if (test_context->packet_count == 0) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else if (test_context->packet_count == 1) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_FAILED - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets"); free_AS_REQ(&test_context->as_req); break; /* * Confirm correct error codes when we deliberatly skew the client clock */ case TORTURE_KRB5_TEST_CLOCK_SKEW: if (test_context->packet_count == 0) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } else if (test_context->packet_count == 1) { torture_assert_int_equal(test_context->tctx, decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0, "decode_AS_REP failed"); torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch"); torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno"); torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_AP_ERR_SKEW - KRB5KDC_ERR_NONE, "Got wrong error.error_code"); free_KRB_ERROR(&error); } torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets"); free_AS_REQ(&test_context->as_req); break; } return true; }
static krb5_error_code process_reply(krb5_context context, krb5_auth_context auth_context, krb5_data *data, int *result_code, krb5_data *result_code_string, krb5_data *result_string) { krb5_error_code ret; ssize_t len; uint16_t pkt_len, pkt_ver; krb5_data ap_rep_data; uint8_t *reply; krb5_auth_con_clear(context, auth_context, KRB5_AUTH_CONTEXT_CLEAR_LOCAL_ADDR|KRB5_AUTH_CONTEXT_CLEAR_REMOTE_ADDR); len = data->length; reply = data->data;; if (len < 6) { krb5_data_format(result_string, "server sent to too short message " "(%ld bytes)", (long)len); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } pkt_len = (reply[0] << 8) | (reply[1]); pkt_ver = (reply[2] << 8) | (reply[3]); if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) { KRB_ERROR error; size_t size; u_char *p; memset(&error, 0, sizeof(error)); ret = decode_KRB_ERROR(reply, len, &error, &size); if (ret) return ret; if (error.e_data->length < 2) { krb5_data_format(result_string, "server sent too short " "e_data to print anything usable"); free_KRB_ERROR(&error); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } p = error.e_data->data; *result_code = (p[0] << 8) | p[1]; if (error.e_data->length == 2) krb5_data_format(result_string, "server only sent error code"); else krb5_data_copy (result_string, p + 2, error.e_data->length - 2); free_KRB_ERROR(&error); return 0; } if (pkt_len != len) { krb5_data_format(result_string, "client: wrong len in reply"); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) { krb5_data_format(result_string, "client: wrong version number (%d)", pkt_ver); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } ap_rep_data.data = reply + 6; ap_rep_data.length = (reply[4] << 8) | (reply[5]); if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) { krb5_data_format(result_string, "client: wrong AP len in reply"); *result_code = KRB5_KPASSWD_MALFORMED; return 0; } if (ap_rep_data.length) { krb5_ap_rep_enc_part *ap_rep; krb5_data priv_data; u_char *p; priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length; priv_data.length = len - ap_rep_data.length - 6; ret = krb5_rd_rep (context, auth_context, &ap_rep_data, &ap_rep); if (ret) return ret; krb5_free_ap_rep_enc_part (context, ap_rep); ret = krb5_rd_priv (context, auth_context, &priv_data, result_code_string, NULL); if (ret) { krb5_data_free (result_code_string); return ret; } if (result_code_string->length < 2) { *result_code = KRB5_KPASSWD_MALFORMED; krb5_data_format(result_string, "client: bad length in result"); return 0; } p = result_code_string->data; *result_code = (p[0] << 8) | p[1]; krb5_data_copy (result_string, (unsigned char*)result_code_string->data + 2, result_code_string->length - 2); return 0; } else { KRB_ERROR error; size_t size; u_char *p; ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size); if (ret) { return ret; } if (error.e_data->length < 2) { krb5_warnx (context, "too short e_data to print anything usable"); return 1; /* XXX */ } p = error.e_data->data; *result_code = (p[0] << 8) | p[1]; krb5_data_copy (result_string, p + 2, error.e_data->length - 2); return 0; } }
krb5_error_code KRB5_LIB_FUNCTION krb5_init_creds_step(krb5_context context, krb5_init_creds_context ctx, krb5_data *in, krb5_data *out, krb5_krbhst_info *hostinfo, unsigned int *flags) { krb5_error_code ret; size_t len; size_t size; krb5_data_zero(out); if (ctx->as_req.req_body.cname == NULL) { ret = init_as_req(context, ctx->flags, &ctx->cred, ctx->addrs, ctx->etypes, &ctx->as_req); if (ret) { free_init_creds_ctx(context, ctx); return ret; } } #define MAX_PA_COUNTER 10 if (ctx->pa_counter > MAX_PA_COUNTER) { krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, N_("Looping %d times while getting " "initial credentials", ""), ctx->pa_counter); return KRB5_GET_IN_TKT_LOOP; } ctx->pa_counter++; /* Lets process the input packet */ if (in && in->length) { krb5_kdc_rep rep; memset(&rep, 0, sizeof(rep)); ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { krb5_keyblock *key = NULL; unsigned eflags = EXTRACT_TICKET_AS_REQ; if (ctx->flags.canonicalize) { eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; eflags |= EXTRACT_TICKET_MATCH_REALM; } if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = process_pa_data_to_key(context, ctx, &ctx->cred, &ctx->as_req, &rep.kdc_rep, hostinfo, &key); if (ret) { free_AS_REP(&rep.kdc_rep); goto out; } ret = _krb5_extract_ticket(context, &rep, &ctx->cred, key, NULL, KRB5_KU_AS_REP_ENC_PART, NULL, ctx->nonce, eflags, NULL, NULL); krb5_free_keyblock(context, key); *flags = 0; if (ret == 0) ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); free_AS_REP(&rep.kdc_rep); free_EncASRepPart(&rep.enc_part); return ret; } else { /* let's try to parse it as a KRB-ERROR */ free_KRB_ERROR(&ctx->error); ret = krb5_rd_error(context, in, &ctx->error); if(ret && in->length && ((char*)in->data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; if (ret) goto out; ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); /* * If no preauth was set and KDC requires it, give it one * more try. */ if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { free_METHOD_DATA(&ctx->md); memset(&ctx->md, 0, sizeof(ctx->md)); if (ctx->error.e_data) { ret = decode_METHOD_DATA(ctx->error.e_data->data, ctx->error.e_data->length, &ctx->md, NULL); if (ret) krb5_set_error_message(context, ret, N_("Failed to decode METHOD-DATA", "")); } else { krb5_set_error_message(context, ret, N_("Preauth required but no preauth " "options send by KDC", "")); } } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { /* * Try adapt to timeskrew when we are using pre-auth, and * if there was a time skew, try again. */ krb5_set_real_time(context, ctx->error.stime, -1); if (context->kdc_sec_offset) ret = 0; } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { /* client referal to a new realm */ if (ctx->error.crealm == NULL) { krb5_set_error_message(context, ret, N_("Got a client referral, not but no realm", "")); goto out; } ret = krb5_principal_set_realm(context, ctx->cred.client, *ctx->error.crealm); } if (ret) goto out; } } if (ctx->as_req.padata) { free_METHOD_DATA(ctx->as_req.padata); free(ctx->as_req.padata); ctx->as_req.padata = NULL; } /* Set a new nonce. */ ctx->as_req.req_body.nonce = ctx->nonce; /* fill_in_md_data */ ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, &ctx->md, &ctx->as_req.padata, ctx->prompter, ctx->prompter_data); if (ret) goto out; krb5_data_free(&ctx->req_buffer); ASN1_MALLOC_ENCODE(AS_REQ, ctx->req_buffer.data, ctx->req_buffer.length, &ctx->as_req, &len, ret); if (ret) goto out; if(len != ctx->req_buffer.length) krb5_abortx(context, "internal error in ASN.1 encoder"); out->data = ctx->req_buffer.data; out->length = ctx->req_buffer.length; *flags = 1; return 0; out: return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_get_in_cred(krb5_context context, krb5_flags options, const krb5_addresses *addrs, const krb5_enctype *etypes, const krb5_preauthtype *ptypes, const krb5_preauthdata *preauth, krb5_key_proc key_proc, krb5_const_pointer keyseed, krb5_decrypt_proc decrypt_proc, krb5_const_pointer decryptarg, krb5_creds *creds, krb5_kdc_rep *ret_as_reply) { krb5_error_code ret; AS_REQ a; krb5_kdc_rep rep; krb5_data req, resp; size_t len; krb5_salt salt; krb5_keyblock *key; size_t size; KDCOptions opts; PA_DATA *pa; krb5_enctype etype; krb5_preauthdata *my_preauth = NULL; unsigned nonce; int done; opts = int2KDCOptions(options); krb5_generate_random_block (&nonce, sizeof(nonce)); nonce &= 0xffffffff; do { done = 1; ret = init_as_req (context, opts, creds, addrs, etypes, ptypes, preauth, key_proc, keyseed, nonce, &a); if (my_preauth) { free_ETYPE_INFO(&my_preauth->val[0].info); free (my_preauth->val); my_preauth = NULL; } if (ret) return ret; ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret); free_AS_REQ(&a); if (ret) return ret; if(len != req.length) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp); krb5_data_free(&req); if (ret) return ret; memset (&rep, 0, sizeof(rep)); ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); if(ret) { /* let's try to parse it as a KRB-ERROR */ KRB_ERROR error; int ret2; ret2 = krb5_rd_error(context, &resp, &error); if(ret2 && resp.data && ((char*)resp.data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_data_free(&resp); if (ret2 == 0) { ret = krb5_error_from_rd_error(context, &error, creds); /* if no preauth was set and KDC requires it, give it one more try */ if (!ptypes && !preauth && ret == KRB5KDC_ERR_PREAUTH_REQUIRED #if 0 || ret == KRB5KDC_ERR_BADOPTION #endif && set_ptypes(context, &error, &ptypes, &my_preauth)) { done = 0; preauth = my_preauth; krb5_free_error_contents(context, &error); krb5_clear_error_string(context); continue; } if(ret_as_reply) ret_as_reply->error = error; else free_KRB_ERROR (&error); return ret; } return ret; } krb5_data_free(&resp); } while(!done); pa = NULL; etype = rep.kdc_rep.enc_part.etype; if(rep.kdc_rep.padata){ int i = 0; pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, KRB5_PADATA_PW_SALT, &i); if(pa == NULL) { i = 0; pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, KRB5_PADATA_AFS3_SALT, &i); } } if(pa) { salt.salttype = pa->padata_type; salt.saltvalue = pa->padata_value; ret = (*key_proc)(context, etype, salt, keyseed, &key); } else { /* make a v5 salted pa-data */ ret = krb5_get_pw_salt (context, creds->client, &salt); if (ret) goto out; ret = (*key_proc)(context, etype, salt, keyseed, &key); krb5_free_salt(context, salt); } if (ret) goto out; { unsigned flags = 0; if (opts.request_anonymous) flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; ret = _krb5_extract_ticket(context, &rep, creds, key, keyseed, KRB5_KU_AS_REP_ENC_PART, NULL, nonce, flags, decrypt_proc, decryptarg); } memset (key->keyvalue.data, 0, key->keyvalue.length); krb5_free_keyblock_contents (context, key); free (key); out: if (ret == 0 && ret_as_reply) *ret_as_reply = rep; else krb5_free_kdc_rep (context, &rep); return ret; }