get_cred.c revision 55682
155682Smarkm/* 255682Smarkm * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include <krb5_locl.h> 3555682Smarkm 3655682SmarkmRCSID("$Id: get_cred.c,v 1.75 1999/12/02 17:05:09 joda Exp $"); 3755682Smarkm 3855682Smarkm/* 3955682Smarkm * Take the `body' and encode it into `padata' using the credentials 4055682Smarkm * in `creds'. 4155682Smarkm */ 4255682Smarkm 4355682Smarkmstatic krb5_error_code 4455682Smarkmmake_pa_tgs_req(krb5_context context, 4555682Smarkm krb5_auth_context ac, 4655682Smarkm KDC_REQ_BODY *body, 4755682Smarkm PA_DATA *padata, 4855682Smarkm krb5_creds *creds) 4955682Smarkm{ 5055682Smarkm u_char *buf; 5155682Smarkm size_t buf_size; 5255682Smarkm size_t len; 5355682Smarkm krb5_data in_data; 5455682Smarkm krb5_error_code ret; 5555682Smarkm 5655682Smarkm buf_size = 1024; 5755682Smarkm buf = malloc (buf_size); 5855682Smarkm if (buf == NULL) 5955682Smarkm return ENOMEM; 6055682Smarkm 6155682Smarkm do { 6255682Smarkm ret = encode_KDC_REQ_BODY(buf + buf_size - 1, buf_size, 6355682Smarkm body, &len); 6455682Smarkm if (ret){ 6555682Smarkm if (ret == ASN1_OVERFLOW) { 6655682Smarkm u_char *tmp; 6755682Smarkm 6855682Smarkm buf_size *= 2; 6955682Smarkm tmp = realloc (buf, buf_size); 7055682Smarkm if (tmp == NULL) { 7155682Smarkm ret = ENOMEM; 7255682Smarkm goto out; 7355682Smarkm } 7455682Smarkm buf = tmp; 7555682Smarkm } else { 7655682Smarkm goto out; 7755682Smarkm } 7855682Smarkm } 7955682Smarkm } while (ret == ASN1_OVERFLOW); 8055682Smarkm 8155682Smarkm in_data.length = len; 8255682Smarkm in_data.data = buf + buf_size - len; 8355682Smarkm ret = krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 8455682Smarkm &padata->padata_value, 8555682Smarkm KRB5_KU_TGS_REQ_AUTH_CKSUM); 8655682Smarkmout: 8755682Smarkm free (buf); 8855682Smarkm if(ret) 8955682Smarkm return ret; 9055682Smarkm padata->padata_type = pa_tgs_req; 9155682Smarkm return 0; 9255682Smarkm} 9355682Smarkm 9455682Smarkm/* 9555682Smarkm * Set the `enc-authorization-data' in `req_body' based on `authdata' 9655682Smarkm */ 9755682Smarkm 9855682Smarkmstatic krb5_error_code 9955682Smarkmset_auth_data (krb5_context context, 10055682Smarkm KDC_REQ_BODY *req_body, 10155682Smarkm krb5_authdata *authdata, 10255682Smarkm krb5_keyblock *key) 10355682Smarkm{ 10455682Smarkm if(authdata->len) { 10555682Smarkm size_t len; 10655682Smarkm unsigned char *buf; 10755682Smarkm krb5_crypto crypto; 10855682Smarkm krb5_error_code ret; 10955682Smarkm 11055682Smarkm len = length_AuthorizationData(authdata); 11155682Smarkm buf = malloc(len); 11255682Smarkm if (buf == NULL) 11355682Smarkm return ENOMEM; 11455682Smarkm ret = encode_AuthorizationData(buf + len - 1, 11555682Smarkm len, authdata, &len); 11655682Smarkm if (ret) { 11755682Smarkm free (buf); 11855682Smarkm return ret; 11955682Smarkm } 12055682Smarkm 12155682Smarkm ALLOC(req_body->enc_authorization_data, 1); 12255682Smarkm if (req_body->enc_authorization_data == NULL) { 12355682Smarkm free (buf); 12455682Smarkm return ret; 12555682Smarkm } 12655682Smarkm ret = krb5_crypto_init(context, key, 0, &crypto); 12755682Smarkm if (ret) { 12855682Smarkm free (buf); 12955682Smarkm free (req_body->enc_authorization_data); 13055682Smarkm return ret; 13155682Smarkm } 13255682Smarkm krb5_encrypt_EncryptedData(context, 13355682Smarkm crypto, 13455682Smarkm KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 13555682Smarkm /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */ 13655682Smarkm buf, 13755682Smarkm len, 13855682Smarkm 0, 13955682Smarkm req_body->enc_authorization_data); 14055682Smarkm free (buf); 14155682Smarkm krb5_crypto_destroy(context, crypto); 14255682Smarkm } else { 14355682Smarkm req_body->enc_authorization_data = NULL; 14455682Smarkm } 14555682Smarkm return 0; 14655682Smarkm} 14755682Smarkm 14855682Smarkm/* 14955682Smarkm * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 15055682Smarkm * (if not-NULL), `in_creds', `krbtgt', and returning the generated 15155682Smarkm * subkey in `subkey'. 15255682Smarkm */ 15355682Smarkm 15455682Smarkmstatic krb5_error_code 15555682Smarkminit_tgs_req (krb5_context context, 15655682Smarkm krb5_ccache ccache, 15755682Smarkm krb5_addresses *addresses, 15855682Smarkm krb5_kdc_flags flags, 15955682Smarkm Ticket *second_ticket, 16055682Smarkm krb5_creds *in_creds, 16155682Smarkm krb5_creds *krbtgt, 16255682Smarkm unsigned nonce, 16355682Smarkm krb5_keyblock **subkey, 16455682Smarkm TGS_REQ *t) 16555682Smarkm{ 16655682Smarkm krb5_error_code ret; 16755682Smarkm 16855682Smarkm memset(t, 0, sizeof(*t)); 16955682Smarkm t->pvno = 5; 17055682Smarkm t->msg_type = krb_tgs_req; 17155682Smarkm if (in_creds->session.keytype) { 17255682Smarkm ret = krb5_keytype_to_enctypes_default (context, 17355682Smarkm in_creds->session.keytype, 17455682Smarkm &t->req_body.etype.len, 17555682Smarkm &t->req_body.etype.val); 17655682Smarkm } else { 17755682Smarkm ret = krb5_init_etype(context, 17855682Smarkm &t->req_body.etype.len, 17955682Smarkm &t->req_body.etype.val, 18055682Smarkm NULL); 18155682Smarkm } 18255682Smarkm if (ret) 18355682Smarkm goto fail; 18455682Smarkm t->req_body.addresses = addresses; 18555682Smarkm t->req_body.kdc_options = flags.b; 18655682Smarkm ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 18755682Smarkm if (ret) 18855682Smarkm goto fail; 18955682Smarkm ALLOC(t->req_body.sname, 1); 19055682Smarkm if (t->req_body.sname == NULL) { 19155682Smarkm ret = ENOMEM; 19255682Smarkm goto fail; 19355682Smarkm } 19455682Smarkm ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 19555682Smarkm if (ret) 19655682Smarkm goto fail; 19755682Smarkm 19855682Smarkm /* req_body.till should be NULL if there is no endtime specified, 19955682Smarkm but old MIT code (like DCE secd) doesn't like that */ 20055682Smarkm ALLOC(t->req_body.till, 1); 20155682Smarkm if(t->req_body.till == NULL){ 20255682Smarkm ret = ENOMEM; 20355682Smarkm goto fail; 20455682Smarkm } 20555682Smarkm *t->req_body.till = in_creds->times.endtime; 20655682Smarkm 20755682Smarkm t->req_body.nonce = nonce; 20855682Smarkm if(second_ticket){ 20955682Smarkm ALLOC(t->req_body.additional_tickets, 1); 21055682Smarkm if (t->req_body.additional_tickets == NULL) { 21155682Smarkm ret = ENOMEM; 21255682Smarkm goto fail; 21355682Smarkm } 21455682Smarkm ALLOC_SEQ(t->req_body.additional_tickets, 1); 21555682Smarkm if (t->req_body.additional_tickets->val == NULL) { 21655682Smarkm ret = ENOMEM; 21755682Smarkm goto fail; 21855682Smarkm } 21955682Smarkm ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 22055682Smarkm if (ret) 22155682Smarkm goto fail; 22255682Smarkm } 22355682Smarkm ALLOC(t->padata, 1); 22455682Smarkm if (t->padata == NULL) { 22555682Smarkm ret = ENOMEM; 22655682Smarkm goto fail; 22755682Smarkm } 22855682Smarkm ALLOC_SEQ(t->padata, 1); 22955682Smarkm if (t->padata->val == NULL) { 23055682Smarkm ret = ENOMEM; 23155682Smarkm goto fail; 23255682Smarkm } 23355682Smarkm 23455682Smarkm { 23555682Smarkm krb5_auth_context ac; 23655682Smarkm krb5_keyblock *key; 23755682Smarkm 23855682Smarkm ret = krb5_auth_con_init(context, &ac); 23955682Smarkm if(ret) 24055682Smarkm goto fail; 24155682Smarkm ret = krb5_generate_subkey (context, &krbtgt->session, &key); 24255682Smarkm if (ret) { 24355682Smarkm krb5_auth_con_free (context, ac); 24455682Smarkm goto fail; 24555682Smarkm } 24655682Smarkm ret = krb5_auth_con_setlocalsubkey(context, ac, key); 24755682Smarkm if (ret) { 24855682Smarkm krb5_free_keyblock (context, key); 24955682Smarkm krb5_auth_con_free (context, ac); 25055682Smarkm goto fail; 25155682Smarkm } 25255682Smarkm 25355682Smarkm ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key); 25455682Smarkm if (ret) { 25555682Smarkm krb5_free_keyblock (context, key); 25655682Smarkm krb5_auth_con_free (context, ac); 25755682Smarkm goto fail; 25855682Smarkm } 25955682Smarkm 26055682Smarkm ret = make_pa_tgs_req(context, 26155682Smarkm ac, 26255682Smarkm &t->req_body, 26355682Smarkm t->padata->val, 26455682Smarkm krbtgt); 26555682Smarkm if(ret) { 26655682Smarkm krb5_free_keyblock (context, key); 26755682Smarkm krb5_auth_con_free(context, ac); 26855682Smarkm goto fail; 26955682Smarkm } 27055682Smarkm *subkey = key; 27155682Smarkm 27255682Smarkm krb5_auth_con_free(context, ac); 27355682Smarkm } 27455682Smarkmfail: 27555682Smarkm if (ret) 27655682Smarkm free_TGS_REQ (t); 27755682Smarkm return ret; 27855682Smarkm} 27955682Smarkm 28055682Smarkmstatic krb5_error_code 28155682Smarkmget_krbtgt(krb5_context context, 28255682Smarkm krb5_ccache id, 28355682Smarkm krb5_realm realm, 28455682Smarkm krb5_creds **cred) 28555682Smarkm{ 28655682Smarkm krb5_error_code ret; 28755682Smarkm krb5_creds tmp_cred; 28855682Smarkm 28955682Smarkm memset(&tmp_cred, 0, sizeof(tmp_cred)); 29055682Smarkm 29155682Smarkm ret = krb5_make_principal(context, 29255682Smarkm &tmp_cred.server, 29355682Smarkm realm, 29455682Smarkm KRB5_TGS_NAME, 29555682Smarkm realm, 29655682Smarkm NULL); 29755682Smarkm if(ret) 29855682Smarkm return ret; 29955682Smarkm ret = krb5_get_credentials(context, 30055682Smarkm KRB5_GC_CACHED, 30155682Smarkm id, 30255682Smarkm &tmp_cred, 30355682Smarkm cred); 30455682Smarkm krb5_free_principal(context, tmp_cred.server); 30555682Smarkm if(ret) 30655682Smarkm return ret; 30755682Smarkm return 0; 30855682Smarkm} 30955682Smarkm 31055682Smarkm/* DCE compatible decrypt proc */ 31155682Smarkmstatic krb5_error_code 31255682Smarkmdecrypt_tkt_with_subkey (krb5_context context, 31355682Smarkm krb5_keyblock *key, 31455682Smarkm krb5_key_usage usage, 31555682Smarkm krb5_const_pointer subkey, 31655682Smarkm krb5_kdc_rep *dec_rep) 31755682Smarkm{ 31855682Smarkm krb5_error_code ret; 31955682Smarkm krb5_data data; 32055682Smarkm size_t size; 32155682Smarkm krb5_crypto crypto; 32255682Smarkm 32355682Smarkm krb5_crypto_init(context, key, 0, &crypto); 32455682Smarkm ret = krb5_decrypt_EncryptedData (context, 32555682Smarkm crypto, 32655682Smarkm usage, 32755682Smarkm &dec_rep->kdc_rep.enc_part, 32855682Smarkm &data); 32955682Smarkm krb5_crypto_destroy(context, crypto); 33055682Smarkm if(ret && subkey){ 33155682Smarkm /* DCE compat -- try to decrypt with subkey */ 33255682Smarkm krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); 33355682Smarkm ret = krb5_decrypt_EncryptedData (context, 33455682Smarkm crypto, 33555682Smarkm KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 33655682Smarkm &dec_rep->kdc_rep.enc_part, 33755682Smarkm &data); 33855682Smarkm krb5_crypto_destroy(context, crypto); 33955682Smarkm } 34055682Smarkm if (ret) 34155682Smarkm return ret; 34255682Smarkm 34355682Smarkm ret = krb5_decode_EncASRepPart(context, 34455682Smarkm data.data, 34555682Smarkm data.length, 34655682Smarkm &dec_rep->enc_part, 34755682Smarkm &size); 34855682Smarkm if (ret) 34955682Smarkm ret = krb5_decode_EncTGSRepPart(context, 35055682Smarkm data.data, 35155682Smarkm data.length, 35255682Smarkm &dec_rep->enc_part, 35355682Smarkm &size); 35455682Smarkm krb5_data_free (&data); 35555682Smarkm return ret; 35655682Smarkm} 35755682Smarkm 35855682Smarkmstatic krb5_error_code 35955682Smarkmget_cred_kdc(krb5_context context, 36055682Smarkm krb5_ccache id, 36155682Smarkm krb5_kdc_flags flags, 36255682Smarkm krb5_addresses *addresses, 36355682Smarkm krb5_creds *in_creds, 36455682Smarkm krb5_creds *krbtgt, 36555682Smarkm krb5_creds *out_creds) 36655682Smarkm{ 36755682Smarkm TGS_REQ req; 36855682Smarkm krb5_data enc; 36955682Smarkm krb5_data resp; 37055682Smarkm krb5_kdc_rep rep; 37155682Smarkm KRB_ERROR error; 37255682Smarkm krb5_error_code ret; 37355682Smarkm unsigned nonce; 37455682Smarkm krb5_keyblock *subkey = NULL; 37555682Smarkm u_char *buf = NULL; 37655682Smarkm size_t buf_size; 37755682Smarkm size_t len; 37855682Smarkm Ticket second_ticket; 37955682Smarkm 38055682Smarkm krb5_generate_random_block(&nonce, sizeof(nonce)); 38155682Smarkm nonce &= 0xffffffff; 38255682Smarkm 38355682Smarkm if(flags.b.enc_tkt_in_skey){ 38455682Smarkm ret = decode_Ticket(in_creds->second_ticket.data, 38555682Smarkm in_creds->second_ticket.length, 38655682Smarkm &second_ticket, &len); 38755682Smarkm if(ret) 38855682Smarkm return ret; 38955682Smarkm } 39055682Smarkm 39155682Smarkm ret = init_tgs_req (context, 39255682Smarkm id, 39355682Smarkm addresses, 39455682Smarkm flags, 39555682Smarkm flags.b.enc_tkt_in_skey ? &second_ticket : NULL, 39655682Smarkm in_creds, 39755682Smarkm krbtgt, 39855682Smarkm nonce, 39955682Smarkm &subkey, 40055682Smarkm &req); 40155682Smarkm if(flags.b.enc_tkt_in_skey) 40255682Smarkm free_Ticket(&second_ticket); 40355682Smarkm if (ret) 40455682Smarkm goto out; 40555682Smarkm 40655682Smarkm buf_size = 1024; 40755682Smarkm buf = malloc (buf_size); 40855682Smarkm if (buf == NULL) { 40955682Smarkm ret = ENOMEM; 41055682Smarkm goto out; 41155682Smarkm } 41255682Smarkm 41355682Smarkm do { 41455682Smarkm ret = encode_TGS_REQ (buf + buf_size - 1, buf_size, 41555682Smarkm &req, &enc.length); 41655682Smarkm if (ret) { 41755682Smarkm if (ret == ASN1_OVERFLOW) { 41855682Smarkm u_char *tmp; 41955682Smarkm 42055682Smarkm buf_size *= 2; 42155682Smarkm tmp = realloc (buf, buf_size); 42255682Smarkm if (tmp == NULL) { 42355682Smarkm ret = ENOMEM; 42455682Smarkm goto out; 42555682Smarkm } 42655682Smarkm buf = tmp; 42755682Smarkm } else { 42855682Smarkm goto out; 42955682Smarkm } 43055682Smarkm } 43155682Smarkm } while (ret == ASN1_OVERFLOW); 43255682Smarkm 43355682Smarkm /* don't free addresses */ 43455682Smarkm req.req_body.addresses = NULL; 43555682Smarkm free_TGS_REQ(&req); 43655682Smarkm 43755682Smarkm enc.data = buf + buf_size - enc.length; 43855682Smarkm if (ret) 43955682Smarkm goto out; 44055682Smarkm 44155682Smarkm /* 44255682Smarkm * Send and receive 44355682Smarkm */ 44455682Smarkm 44555682Smarkm ret = krb5_sendto_kdc (context, &enc, 44655682Smarkm &krbtgt->server->name.name_string.val[1], &resp); 44755682Smarkm if(ret) 44855682Smarkm goto out; 44955682Smarkm 45055682Smarkm memset(&rep, 0, sizeof(rep)); 45155682Smarkm if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ 45255682Smarkm ret = krb5_copy_principal(context, 45355682Smarkm in_creds->client, 45455682Smarkm &out_creds->client); 45555682Smarkm if(ret) 45655682Smarkm goto out; 45755682Smarkm ret = krb5_copy_principal(context, 45855682Smarkm in_creds->server, 45955682Smarkm &out_creds->server); 46055682Smarkm if(ret) 46155682Smarkm goto out; 46255682Smarkm /* this should go someplace else */ 46355682Smarkm out_creds->times.endtime = in_creds->times.endtime; 46455682Smarkm 46555682Smarkm ret = _krb5_extract_ticket(context, 46655682Smarkm &rep, 46755682Smarkm out_creds, 46855682Smarkm &krbtgt->session, 46955682Smarkm NULL, 47055682Smarkm KRB5_KU_TGS_REP_ENC_PART_SESSION, 47155682Smarkm &krbtgt->addresses, 47255682Smarkm nonce, 47355682Smarkm TRUE, 47455682Smarkm decrypt_tkt_with_subkey, 47555682Smarkm subkey); 47655682Smarkm krb5_free_kdc_rep(context, &rep); 47755682Smarkm if (ret) 47855682Smarkm goto out; 47955682Smarkm }else if(krb5_rd_error(context, &resp, &error) == 0){ 48055682Smarkm ret = error.error_code; 48155682Smarkm free_KRB_ERROR(&error); 48255682Smarkm }else if(resp.data && ((char*)resp.data)[0] == 4) 48355682Smarkm ret = KRB5KRB_AP_ERR_V4_REPLY; 48455682Smarkm else 48555682Smarkm ret = KRB5KRB_AP_ERR_MSG_TYPE; 48655682Smarkm krb5_data_free(&resp); 48755682Smarkmout: 48855682Smarkm if(subkey){ 48955682Smarkm krb5_free_keyblock_contents(context, subkey); 49055682Smarkm free(subkey); 49155682Smarkm } 49255682Smarkm if (buf) 49355682Smarkm free (buf); 49455682Smarkm return ret; 49555682Smarkm 49655682Smarkm} 49755682Smarkm 49855682Smarkm/* same as above, just get local addresses first */ 49955682Smarkm 50055682Smarkmstatic krb5_error_code 50155682Smarkmget_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, 50255682Smarkm krb5_creds *in_creds, krb5_creds *krbtgt, 50355682Smarkm krb5_creds *out_creds) 50455682Smarkm{ 50555682Smarkm krb5_error_code ret; 50655682Smarkm krb5_addresses addresses; 50755682Smarkm 50855682Smarkm krb5_get_all_client_addrs(context, &addresses); 50955682Smarkm ret = get_cred_kdc(context, id, flags, &addresses, 51055682Smarkm in_creds, krbtgt, out_creds); 51155682Smarkm krb5_free_addresses(context, &addresses); 51255682Smarkm return ret; 51355682Smarkm} 51455682Smarkm 51555682Smarkmkrb5_error_code 51655682Smarkmkrb5_get_kdc_cred(krb5_context context, 51755682Smarkm krb5_ccache id, 51855682Smarkm krb5_kdc_flags flags, 51955682Smarkm krb5_addresses *addresses, 52055682Smarkm Ticket *second_ticket, 52155682Smarkm krb5_creds *in_creds, 52255682Smarkm krb5_creds **out_creds 52355682Smarkm ) 52455682Smarkm{ 52555682Smarkm krb5_error_code ret; 52655682Smarkm krb5_creds *krbtgt; 52755682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 52855682Smarkm if(*out_creds == NULL) 52955682Smarkm return ENOMEM; 53055682Smarkm ret = get_krbtgt (context, 53155682Smarkm id, 53255682Smarkm in_creds->server->realm, 53355682Smarkm &krbtgt); 53455682Smarkm if(ret) { 53555682Smarkm free(*out_creds); 53655682Smarkm return ret; 53755682Smarkm } 53855682Smarkm ret = get_cred_kdc(context, id, flags, addresses, 53955682Smarkm in_creds, krbtgt, *out_creds); 54055682Smarkm krb5_free_creds (context, krbtgt); 54155682Smarkm if(ret) 54255682Smarkm free(*out_creds); 54355682Smarkm return ret; 54455682Smarkm} 54555682Smarkm 54655682Smarkm 54755682Smarkmstatic krb5_error_code 54855682Smarkmfind_cred(krb5_context context, 54955682Smarkm krb5_ccache id, 55055682Smarkm krb5_principal server, 55155682Smarkm krb5_creds **tgts, 55255682Smarkm krb5_creds *out_creds) 55355682Smarkm{ 55455682Smarkm krb5_error_code ret; 55555682Smarkm krb5_creds mcreds; 55655682Smarkm mcreds.server = server; 55755682Smarkm ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 55855682Smarkm &mcreds, out_creds); 55955682Smarkm if(ret == 0) 56055682Smarkm return 0; 56155682Smarkm while(tgts && *tgts){ 56255682Smarkm if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 56355682Smarkm &mcreds, *tgts)){ 56455682Smarkm ret = krb5_copy_creds_contents(context, *tgts, out_creds); 56555682Smarkm return ret; 56655682Smarkm } 56755682Smarkm tgts++; 56855682Smarkm } 56955682Smarkm return KRB5_CC_NOTFOUND; 57055682Smarkm} 57155682Smarkm 57255682Smarkmstatic krb5_error_code 57355682Smarkmadd_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt) 57455682Smarkm{ 57555682Smarkm int i; 57655682Smarkm krb5_error_code ret; 57755682Smarkm krb5_creds **tmp = *tgts; 57855682Smarkm for(i = 0; tmp && tmp[i]; i++); /* XXX */ 57955682Smarkm tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 58055682Smarkm if(tmp == NULL) 58155682Smarkm return ENOMEM; 58255682Smarkm *tgts = tmp; 58355682Smarkm ret = krb5_copy_creds(context, tkt, &tmp[i]); 58455682Smarkm tmp[i+1] = NULL; 58555682Smarkm return ret; 58655682Smarkm} 58755682Smarkm 58855682Smarkm/* 58955682Smarkmget_cred(server) 59055682Smarkm creds = cc_get_cred(server) 59155682Smarkm if(creds) return creds 59255682Smarkm tgt = cc_get_cred(krbtgt/server_realm@any_realm) 59355682Smarkm if(tgt) 59455682Smarkm return get_cred_tgt(server, tgt) 59555682Smarkm if(client_realm == server_realm) 59655682Smarkm return NULL 59755682Smarkm tgt = get_cred(krbtgt/server_realm@client_realm) 59855682Smarkm while(tgt_inst != server_realm) 59955682Smarkm tgt = get_cred(krbtgt/server_realm@tgt_inst) 60055682Smarkm return get_cred_tgt(server, tgt) 60155682Smarkm */ 60255682Smarkm 60355682Smarkmstatic krb5_error_code 60455682Smarkmget_cred_from_kdc_flags(krb5_context context, 60555682Smarkm krb5_kdc_flags flags, 60655682Smarkm krb5_ccache ccache, 60755682Smarkm krb5_creds *in_creds, 60855682Smarkm krb5_creds **out_creds, 60955682Smarkm krb5_creds ***ret_tgts) 61055682Smarkm{ 61155682Smarkm krb5_error_code ret; 61255682Smarkm krb5_creds *tgt, tmp_creds; 61355682Smarkm krb5_realm client_realm, server_realm; 61455682Smarkm 61555682Smarkm *out_creds = NULL; 61655682Smarkm 61755682Smarkm client_realm = *krb5_princ_realm(context, in_creds->client); 61855682Smarkm server_realm = *krb5_princ_realm(context, in_creds->server); 61955682Smarkm memset(&tmp_creds, 0, sizeof(tmp_creds)); 62055682Smarkm ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 62155682Smarkm if(ret) 62255682Smarkm return ret; 62355682Smarkm ret = krb5_make_principal(context, 62455682Smarkm &tmp_creds.server, 62555682Smarkm client_realm, 62655682Smarkm KRB5_TGS_NAME, 62755682Smarkm server_realm, 62855682Smarkm NULL); 62955682Smarkm if(ret){ 63055682Smarkm krb5_free_principal(context, tmp_creds.client); 63155682Smarkm return ret; 63255682Smarkm } 63355682Smarkm { 63455682Smarkm krb5_creds tgts; 63555682Smarkm /* XXX try krb5_cc_retrieve_cred first? */ 63655682Smarkm ret = find_cred(context, ccache, tmp_creds.server, 63755682Smarkm *ret_tgts, &tgts); 63855682Smarkm if(ret == 0){ 63955682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 64055682Smarkm if(*out_creds == NULL) 64155682Smarkm ret = ENOMEM; 64255682Smarkm else { 64355682Smarkm ret = get_cred_kdc_la(context, ccache, flags, 64455682Smarkm in_creds, &tgts, *out_creds); 64555682Smarkm if (ret) 64655682Smarkm free (*out_creds); 64755682Smarkm } 64855682Smarkm krb5_free_creds_contents(context, &tgts); 64955682Smarkm krb5_free_principal(context, tmp_creds.server); 65055682Smarkm krb5_free_principal(context, tmp_creds.client); 65155682Smarkm return ret; 65255682Smarkm } 65355682Smarkm } 65455682Smarkm if(krb5_realm_compare(context, in_creds->client, in_creds->server)) 65555682Smarkm return KRB5_CC_NOTFOUND; 65655682Smarkm /* XXX this can loop forever */ 65755682Smarkm while(1){ 65855682Smarkm general_string tgt_inst; 65955682Smarkm krb5_kdc_flags f; 66055682Smarkm f.i = 0; 66155682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 66255682Smarkm &tgt, ret_tgts); 66355682Smarkm if(ret) { 66455682Smarkm krb5_free_principal(context, tmp_creds.server); 66555682Smarkm krb5_free_principal(context, tmp_creds.client); 66655682Smarkm return ret; 66755682Smarkm } 66855682Smarkm ret = add_cred(context, ret_tgts, tgt); 66955682Smarkm if(ret) { 67055682Smarkm krb5_free_principal(context, tmp_creds.server); 67155682Smarkm krb5_free_principal(context, tmp_creds.client); 67255682Smarkm return ret; 67355682Smarkm } 67455682Smarkm tgt_inst = tgt->server->name.name_string.val[1]; 67555682Smarkm if(strcmp(tgt_inst, server_realm) == 0) 67655682Smarkm break; 67755682Smarkm krb5_free_principal(context, tmp_creds.server); 67855682Smarkm ret = krb5_make_principal(context, &tmp_creds.server, 67955682Smarkm tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 68055682Smarkm if(ret) { 68155682Smarkm krb5_free_principal(context, tmp_creds.server); 68255682Smarkm krb5_free_principal(context, tmp_creds.client); 68355682Smarkm return ret; 68455682Smarkm } 68555682Smarkm ret = krb5_free_creds(context, tgt); 68655682Smarkm if(ret) { 68755682Smarkm krb5_free_principal(context, tmp_creds.server); 68855682Smarkm krb5_free_principal(context, tmp_creds.client); 68955682Smarkm return ret; 69055682Smarkm } 69155682Smarkm } 69255682Smarkm 69355682Smarkm krb5_free_principal(context, tmp_creds.server); 69455682Smarkm krb5_free_principal(context, tmp_creds.client); 69555682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 69655682Smarkm if(*out_creds == NULL) 69755682Smarkm ret = ENOMEM; 69855682Smarkm else { 69955682Smarkm ret = get_cred_kdc_la(context, ccache, flags, 70055682Smarkm in_creds, tgt, *out_creds); 70155682Smarkm if (ret) 70255682Smarkm free (*out_creds); 70355682Smarkm } 70455682Smarkm krb5_free_creds(context, tgt); 70555682Smarkm return ret; 70655682Smarkm} 70755682Smarkm 70855682Smarkmkrb5_error_code 70955682Smarkmkrb5_get_cred_from_kdc(krb5_context context, 71055682Smarkm krb5_ccache ccache, 71155682Smarkm krb5_creds *in_creds, 71255682Smarkm krb5_creds **out_creds, 71355682Smarkm krb5_creds ***ret_tgts) 71455682Smarkm{ 71555682Smarkm krb5_kdc_flags f; 71655682Smarkm f.i = 0; 71755682Smarkm return get_cred_from_kdc_flags(context, f, ccache, 71855682Smarkm in_creds, out_creds, ret_tgts); 71955682Smarkm} 72055682Smarkm 72155682Smarkm 72255682Smarkmkrb5_error_code 72355682Smarkmkrb5_get_credentials_with_flags(krb5_context context, 72455682Smarkm krb5_flags options, 72555682Smarkm krb5_kdc_flags flags, 72655682Smarkm krb5_ccache ccache, 72755682Smarkm krb5_creds *in_creds, 72855682Smarkm krb5_creds **out_creds) 72955682Smarkm{ 73055682Smarkm krb5_error_code ret; 73155682Smarkm krb5_creds **tgts; 73255682Smarkm int i; 73355682Smarkm 73455682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 73555682Smarkm if (*out_creds == NULL) 73655682Smarkm return ENOMEM; 73755682Smarkm 73855682Smarkm ret = krb5_cc_retrieve_cred(context, 73955682Smarkm ccache, 74055682Smarkm in_creds->session.keytype ? 74155682Smarkm KRB5_TC_MATCH_KEYTYPE : 0, 74255682Smarkm in_creds, *out_creds); 74355682Smarkm if(ret == 0) 74455682Smarkm return 0; 74555682Smarkm free(*out_creds); 74655682Smarkm if(ret != KRB5_CC_END) 74755682Smarkm return ret; 74855682Smarkm if(options & KRB5_GC_CACHED) 74955682Smarkm return KRB5_CC_NOTFOUND; 75055682Smarkm if(options & KRB5_GC_USER_USER) 75155682Smarkm flags.b.enc_tkt_in_skey = 1; 75255682Smarkm tgts = NULL; 75355682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, 75455682Smarkm in_creds, out_creds, &tgts); 75555682Smarkm for(i = 0; tgts && tgts[i]; i++){ 75655682Smarkm krb5_cc_store_cred(context, ccache, tgts[i]); 75755682Smarkm krb5_free_creds(context, tgts[i]); 75855682Smarkm } 75955682Smarkm free(tgts); 76055682Smarkm if(ret == 0 && flags.b.enc_tkt_in_skey == 0) 76155682Smarkm krb5_cc_store_cred(context, ccache, *out_creds); 76255682Smarkm return ret; 76355682Smarkm} 76455682Smarkm 76555682Smarkmkrb5_error_code 76655682Smarkmkrb5_get_credentials(krb5_context context, 76755682Smarkm krb5_flags options, 76855682Smarkm krb5_ccache ccache, 76955682Smarkm krb5_creds *in_creds, 77055682Smarkm krb5_creds **out_creds) 77155682Smarkm{ 77255682Smarkm krb5_kdc_flags flags; 77355682Smarkm flags.i = 0; 77455682Smarkm return krb5_get_credentials_with_flags(context, options, flags, 77555682Smarkm ccache, in_creds, out_creds); 77655682Smarkm} 777