static krb5_error_code kdc_tgs_req(krb5_context context, krb5_kdc_configuration *config, krb5_data *req_buffer, krb5_data *reply, const char *from, struct sockaddr *addr, int datagram_reply, int *claim) { krb5_error_code ret; KDC_REQ req; size_t len; ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len); if (ret) return ret; *claim = 1; ret = _kdc_tgs_rep(context, config, &req, reply, from, addr, datagram_reply); free_TGS_REQ(&req); return ret; }
int krb5_kdc_process_krb5_request(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, size_t len, krb5_data *reply, const char *from, struct sockaddr *addr, int datagram_reply) { KDC_REQ req; krb5_error_code ret; size_t i; gettimeofday(&_kdc_now, NULL); if(decode_AS_REQ(buf, len, &req, &i) == 0){ krb5_data req_buffer; req_buffer.data = buf; req_buffer.length = len; ret = _kdc_as_rep(context, config, &req, &req_buffer, reply, from, addr, datagram_reply); free_AS_REQ(&req); return ret; }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr); free_TGS_REQ(&req); return ret; } return -1; }
int krb5_kdc_process_request(krb5_context context, krb5_kdc_configuration *config, unsigned char *buf, size_t len, krb5_data *reply, krb5_boolean *prependlength, const char *from, struct sockaddr *addr, int datagram_reply) { KDC_REQ req; Ticket ticket; DigestREQ digestreq; krb5_error_code ret; size_t i; gettimeofday(&_kdc_now, NULL); if(decode_AS_REQ(buf, len, &req, &i) == 0){ krb5_data req_buffer; req_buffer.data = buf; req_buffer.length = len; ret = _kdc_as_rep(context, config, &req, &req_buffer, reply, from, addr, datagram_reply); free_AS_REQ(&req); return ret; }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ ret = _kdc_tgs_rep(context, config, &req, reply, from, addr); free_TGS_REQ(&req); return ret; }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ ret = _kdc_do_524(context, config, &ticket, reply, from, addr); free_Ticket(&ticket); return ret; }else if(decode_DigestREQ(buf, len, &digestreq, &i) == 0){ ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); free_DigestREQ(&digestreq); return ret; } else if(_kdc_maybe_version4(buf, len)){ *prependlength = FALSE; /* elbitapmoc sdrawkcab XXX */ _kdc_do_version4(context, config, buf, len, reply, from, (struct sockaddr_in*)addr); return 0; } else if (config->enable_kaserver) { ret = _kdc_do_kaserver(context, config, buf, len, reply, from, (struct sockaddr_in*)addr); return ret; } return -1; }
static krb5_error_code get_cred_kdc(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_principal impersonate_principal, Ticket *second_ticket, krb5_creds *out_creds) { TGS_REQ req; krb5_data enc; krb5_data resp; krb5_kdc_rep rep; KRB_ERROR error; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; size_t len; Ticket second_ticket_data; METHOD_DATA padata; krb5_data_zero(&resp); krb5_data_zero(&enc); padata.val = NULL; padata.len = 0; krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, &second_ticket_data, &len); if(ret) return ret; second_ticket = &second_ticket_data; } if (impersonate_principal) { krb5_crypto crypto; PA_S4U2Self self; krb5_data data; void *buf; size_t size; self.name = impersonate_principal->name; self.realm = impersonate_principal->realm; self.auth = estrdup("Kerberos"); ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); if (ret) { free(self.auth); goto out; } ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); if (ret) { free(self.auth); krb5_data_free(&data); goto out; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, &self.cksum); krb5_crypto_destroy(context, crypto); krb5_data_free(&data); if (ret) { free(self.auth); goto out; } ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); free(self.auth); free_Checksum(&self.cksum); if (ret) goto out; if (len != size) krb5_abortx(context, "internal asn1 error"); ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto out; } ret = init_tgs_req (context, id, addresses, flags, second_ticket, in_creds, krbtgt, nonce, &padata, &subkey, &req); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); /* * Send and receive */ { krb5_sendto_ctx stctx; ret = krb5_sendto_ctx_alloc(context, &stctx); if (ret) return ret; krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); ret = krb5_sendto_context (context, stctx, &enc, krbtgt->server->name.name_string.val[1], &resp); krb5_sendto_ctx_free(context, stctx); } if(ret) goto out; memset(&rep, 0, sizeof(rep)); if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0) { unsigned eflags = 0; ret = krb5_copy_principal(context, in_creds->client, &out_creds->client); if(ret) goto out2; ret = krb5_copy_principal(context, in_creds->server, &out_creds->server); if(ret) goto out2; /* this should go someplace else */ out_creds->times.endtime = in_creds->times.endtime; /* XXX should do better testing */ if (flags.b.constrained_delegation || impersonate_principal) eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = _krb5_extract_ticket(context, &rep, out_creds, &krbtgt->session, NULL, 0, &krbtgt->addresses, nonce, eflags, decrypt_tkt_with_subkey, subkey); out2: krb5_free_kdc_rep(context, &rep); } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_message(context); } else { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_message(context); } out: if (second_ticket == &second_ticket_data) free_Ticket(&second_ticket_data); free_METHOD_DATA(&padata); krb5_data_free(&resp); krb5_data_free(&enc); if(subkey) krb5_free_keyblock(context, subkey); return ret; }
static krb5_error_code init_tgs_req (krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, const METHOD_DATA *padata, krb5_keyblock **subkey, TGS_REQ *t) { krb5_auth_context ac = NULL; krb5_error_code ret = 0; memset(t, 0, sizeof(*t)); t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->padata, 1 + padata->len); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } { int i; for (i = 0; i < padata->len; i++) { ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); if (ret) { krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } } } ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); if (ret) goto fail; ret = set_auth_data (context, &t->req_body, &in_creds->authdata, ac->local_subkey); if (ret) goto fail; ret = make_pa_tgs_req(context, ac, &t->req_body, &t->padata->val[0], krbtgt); if(ret) goto fail; ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); if (ret) goto fail; fail: if (ac) krb5_auth_con_free(context, ac); if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }
static krb5_error_code tkt_referral_send(krb5_context context, krb5_tkt_creds_context ctx, krb5_data *in, krb5_data *out, krb5_realm *realm, unsigned int *flags) { krb5_error_code ret; TGS_REQ req; size_t len; METHOD_DATA padata; padata.val = NULL; padata.len = 0; krb5_generate_random_block(&ctx->nonce, sizeof(ctx->nonce)); ctx->nonce &= 0xffffffff; if (_krb5_have_debug(context, 10)) { char *sname, *tgtname; krb5_unparse_name(context, ctx->tgt.server, &tgtname); krb5_unparse_name(context, ctx->next.server, &sname); _krb5_debugx(context, 10, "sending TGS-REQ for %s using %s", sname, tgtname); } ret = _krb5_init_tgs_req(context, ctx->ccache, ctx->addreseses, ctx->kdc_flags, ctx->impersonate_principal, NULL, &ctx->next, &ctx->tgt, ctx->nonce, &padata, &ctx->subkey, &req); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, out->data, out->length, &req, &len, ret); if (ret) goto out; if(out->length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); *realm = ctx->tgt.server->name.name_string.val[1]; *flags |= KRB5_TKT_STATE_CONTINUE; ctx->error = 0; ctx->state = tkt_referral_recv; return 0; out: ctx->error = ret; ctx->state = NULL; return ret; }
krb5_error_code _krb5_init_tgs_req(krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, krb5_const_principal impersonate_principal, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, METHOD_DATA *padata, krb5_keyblock **subkey, TGS_REQ *t) { krb5_auth_context ac = NULL; krb5_error_code ret = 0; /* inherit the forwardable/proxyable flags from the krbtgt */ flags.b.forwardable = krbtgt->flags.b.forwardable; flags.b.proxiable = krbtgt->flags.b.proxiable; if (ccache->ops->tgt_req) { KERB_TGS_REQ_OUT out; KERB_TGS_REQ_IN in; memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); ret = ccache->ops->tgt_req(context, ccache, &in, &out); if (ret) return ret; free_KERB_TGS_REQ_OUT(&out); return 0; } memset(t, 0, sizeof(*t)); if (impersonate_principal) { krb5_crypto crypto; PA_S4U2Self self; krb5_data data; void *buf; size_t size, len; self.name = impersonate_principal->name; self.realm = impersonate_principal->realm; self.auth = rk_UNCONST("Kerberos"); ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); if (ret) goto fail; ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); if (ret) { krb5_data_free(&data); goto fail; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, &self.cksum); krb5_crypto_destroy(context, crypto); krb5_data_free(&data); if (ret) goto fail; ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); free_Checksum(&self.cksum); if (ret) goto fail; if (len != size) krb5_abortx(context, "internal asn1 error"); ret = krb5_padata_add(context, padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto fail; } t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = _krb5_init_etype(context, KRB5_PDU_TGS_REQUEST, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->padata, 1 + padata->len); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } { size_t i; for (i = 0; i < padata->len; i++) { ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); if (ret) { krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } } } ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); if (ret) goto fail; ret = set_auth_data (context, &t->req_body, &in_creds->authdata, ac->local_subkey); if (ret) goto fail; ret = make_pa_tgs_req(context, ac, &t->req_body, &t->padata->val[0], ccache, krbtgt); if(ret) goto fail; ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); if (ret) goto fail; fail: if (ac) krb5_auth_con_free(context, ac); if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }
static krb5_error_code get_cred_kdc_usage(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, krb5_addresses *addresses, krb5_creds *in_creds, krb5_creds *krbtgt, krb5_creds *out_creds, krb5_key_usage usage) { TGS_REQ req; krb5_data enc; krb5_data resp; krb5_kdc_rep rep; KRB_ERROR error; krb5_error_code ret; unsigned nonce; krb5_keyblock *subkey = NULL; size_t len; Ticket second_ticket; int send_to_kdc_flags = 0; krb5_data_zero(&resp); krb5_data_zero(&enc); krb5_generate_random_block(&nonce, sizeof(nonce)); nonce &= 0xffffffff; if(flags.b.enc_tkt_in_skey){ ret = decode_Ticket(in_creds->second_ticket.data, in_creds->second_ticket.length, &second_ticket, &len); if(ret) return ret; } ret = init_tgs_req (context, id, addresses, flags, flags.b.enc_tkt_in_skey ? &second_ticket : NULL, in_creds, krbtgt, nonce, &subkey, &req, usage); if(flags.b.enc_tkt_in_skey) free_Ticket(&second_ticket); if (ret) goto out; ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); if (ret) goto out; if(enc.length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); /* don't free addresses */ req.req_body.addresses = NULL; free_TGS_REQ(&req); /* * Send and receive */ again: ret = krb5_sendto_kdc_flags (context, &enc, &krbtgt->server->name.name_string.val[1], &resp, send_to_kdc_flags); if(ret) goto out; memset(&rep, 0, sizeof(rep)); if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ ret = krb5_copy_principal(context, in_creds->client, &out_creds->client); if(ret) goto out; ret = krb5_copy_principal(context, in_creds->server, &out_creds->server); if(ret) goto out; /* this should go someplace else */ out_creds->times.endtime = in_creds->times.endtime; ret = _krb5_extract_ticket(context, &rep, out_creds, &krbtgt->session, NULL, KRB5_KU_TGS_REP_ENC_PART_SESSION, &krbtgt->addresses, nonce, TRUE, flags.b.request_anonymous, decrypt_tkt_with_subkey, subkey); krb5_free_kdc_rep(context, &rep); } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !(send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG)) { send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; krb5_data_free(&resp); goto again; } } else if(resp.data && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_string(context); } else { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_clear_error_string(context); } out: krb5_data_free(&resp); krb5_data_free(&enc); if(subkey){ krb5_free_keyblock_contents(context, subkey); free(subkey); } return ret; }
static krb5_error_code init_tgs_req (krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, krb5_keyblock **subkey, TGS_REQ *t, krb5_key_usage usage) { krb5_error_code ret = 0; memset(t, 0, sizeof(*t)); t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } ALLOC_SEQ(t->padata, 1); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_string(context, "malloc: out of memory"); goto fail; } { krb5_auth_context ac; krb5_keyblock *key = NULL; ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; if (krb5_config_get_bool_default(context, NULL, FALSE, "realms", krbtgt->server->realm, "tgs_require_subkey", NULL)) { ret = krb5_generate_subkey (context, &krbtgt->session, &key); if (ret) { krb5_auth_con_free (context, ac); goto fail; } ret = krb5_auth_con_setlocalsubkey(context, ac, key); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } } ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key ? key : &krbtgt->session); if (ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free (context, ac); goto fail; } ret = make_pa_tgs_req(context, ac, &t->req_body, t->padata->val, krbtgt, usage); if(ret) { if (key) krb5_free_keyblock (context, key); krb5_auth_con_free(context, ac); goto fail; } *subkey = key; krb5_auth_con_free(context, ac); } fail: if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }