get_cred.c revision 127808
155682Smarkm/* 2127808Snectar * Copyright (c) 1997 - 2004 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 36127808SnectarRCSID("$Id: get_cred.c,v 1.91.4.3 2004/01/09 00:47:17 lha 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, 4878527Sassar krb5_creds *creds, 4978527Sassar krb5_key_usage usage) 5055682Smarkm{ 5155682Smarkm u_char *buf; 5255682Smarkm size_t buf_size; 5355682Smarkm size_t len; 5455682Smarkm krb5_data in_data; 5555682Smarkm krb5_error_code ret; 5655682Smarkm 57103423Snectar ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret); 58103423Snectar if (ret) 59103423Snectar goto out; 60103423Snectar if(buf_size != len) 61103423Snectar krb5_abortx(context, "internal error in ASN.1 encoder"); 6255682Smarkm 6355682Smarkm in_data.length = len; 64103423Snectar in_data.data = buf; 6555682Smarkm ret = krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 6655682Smarkm &padata->padata_value, 6772445Sassar KRB5_KU_TGS_REQ_AUTH_CKSUM, 6878527Sassar usage 6978527Sassar /* KRB5_KU_TGS_REQ_AUTH */); 7055682Smarkmout: 7155682Smarkm free (buf); 7255682Smarkm if(ret) 7355682Smarkm return ret; 7472445Sassar padata->padata_type = KRB5_PADATA_TGS_REQ; 7555682Smarkm return 0; 7655682Smarkm} 7755682Smarkm 7855682Smarkm/* 7955682Smarkm * Set the `enc-authorization-data' in `req_body' based on `authdata' 8055682Smarkm */ 8155682Smarkm 8255682Smarkmstatic krb5_error_code 8355682Smarkmset_auth_data (krb5_context context, 8455682Smarkm KDC_REQ_BODY *req_body, 8555682Smarkm krb5_authdata *authdata, 8655682Smarkm krb5_keyblock *key) 8755682Smarkm{ 8855682Smarkm if(authdata->len) { 8955682Smarkm size_t len; 9055682Smarkm unsigned char *buf; 9155682Smarkm krb5_crypto crypto; 9255682Smarkm krb5_error_code ret; 9355682Smarkm 94103423Snectar ASN1_MALLOC_ENCODE(AuthorizationData, buf, len, authdata, &len, ret); 95103423Snectar if (ret) 9655682Smarkm return ret; 9755682Smarkm 9855682Smarkm ALLOC(req_body->enc_authorization_data, 1); 9955682Smarkm if (req_body->enc_authorization_data == NULL) { 10055682Smarkm free (buf); 10178527Sassar krb5_set_error_string(context, "malloc: out of memory"); 10278527Sassar return ENOMEM; 10355682Smarkm } 10455682Smarkm ret = krb5_crypto_init(context, key, 0, &crypto); 10555682Smarkm if (ret) { 10655682Smarkm free (buf); 10755682Smarkm free (req_body->enc_authorization_data); 10855682Smarkm return ret; 10955682Smarkm } 11055682Smarkm krb5_encrypt_EncryptedData(context, 11155682Smarkm crypto, 11255682Smarkm KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 11355682Smarkm /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */ 11455682Smarkm buf, 11555682Smarkm len, 11655682Smarkm 0, 11755682Smarkm req_body->enc_authorization_data); 11855682Smarkm free (buf); 11955682Smarkm krb5_crypto_destroy(context, crypto); 12055682Smarkm } else { 12155682Smarkm req_body->enc_authorization_data = NULL; 12255682Smarkm } 12355682Smarkm return 0; 12455682Smarkm} 12555682Smarkm 12655682Smarkm/* 12755682Smarkm * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 12855682Smarkm * (if not-NULL), `in_creds', `krbtgt', and returning the generated 12955682Smarkm * subkey in `subkey'. 13055682Smarkm */ 13155682Smarkm 13255682Smarkmstatic krb5_error_code 13355682Smarkminit_tgs_req (krb5_context context, 13455682Smarkm krb5_ccache ccache, 13555682Smarkm krb5_addresses *addresses, 13655682Smarkm krb5_kdc_flags flags, 13755682Smarkm Ticket *second_ticket, 13855682Smarkm krb5_creds *in_creds, 13955682Smarkm krb5_creds *krbtgt, 14055682Smarkm unsigned nonce, 14155682Smarkm krb5_keyblock **subkey, 14278527Sassar TGS_REQ *t, 14378527Sassar krb5_key_usage usage) 14455682Smarkm{ 145103423Snectar krb5_error_code ret = 0; 14655682Smarkm 14755682Smarkm memset(t, 0, sizeof(*t)); 14855682Smarkm t->pvno = 5; 14955682Smarkm t->msg_type = krb_tgs_req; 15055682Smarkm if (in_creds->session.keytype) { 151103423Snectar ALLOC_SEQ(&t->req_body.etype, 1); 152103423Snectar if(t->req_body.etype.val == NULL) { 153103423Snectar ret = ENOMEM; 154103423Snectar krb5_set_error_string(context, "malloc: out of memory"); 155103423Snectar goto fail; 156103423Snectar } 157103423Snectar t->req_body.etype.val[0] = in_creds->session.keytype; 15855682Smarkm } else { 15955682Smarkm ret = krb5_init_etype(context, 16055682Smarkm &t->req_body.etype.len, 16155682Smarkm &t->req_body.etype.val, 16255682Smarkm NULL); 16355682Smarkm } 16455682Smarkm if (ret) 16555682Smarkm goto fail; 16655682Smarkm t->req_body.addresses = addresses; 16755682Smarkm t->req_body.kdc_options = flags.b; 16855682Smarkm ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 16955682Smarkm if (ret) 17055682Smarkm goto fail; 17155682Smarkm ALLOC(t->req_body.sname, 1); 17255682Smarkm if (t->req_body.sname == NULL) { 17355682Smarkm ret = ENOMEM; 17478527Sassar krb5_set_error_string(context, "malloc: out of memory"); 17555682Smarkm goto fail; 17655682Smarkm } 17772445Sassar 17872445Sassar /* some versions of some code might require that the client be 17972445Sassar present in TGS-REQs, but this is clearly against the spec */ 18072445Sassar 18155682Smarkm ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 18255682Smarkm if (ret) 18355682Smarkm goto fail; 18455682Smarkm 18555682Smarkm /* req_body.till should be NULL if there is no endtime specified, 18655682Smarkm but old MIT code (like DCE secd) doesn't like that */ 18755682Smarkm ALLOC(t->req_body.till, 1); 18855682Smarkm if(t->req_body.till == NULL){ 18955682Smarkm ret = ENOMEM; 19078527Sassar krb5_set_error_string(context, "malloc: out of memory"); 19155682Smarkm goto fail; 19255682Smarkm } 19355682Smarkm *t->req_body.till = in_creds->times.endtime; 19455682Smarkm 19555682Smarkm t->req_body.nonce = nonce; 19655682Smarkm if(second_ticket){ 19755682Smarkm ALLOC(t->req_body.additional_tickets, 1); 19855682Smarkm if (t->req_body.additional_tickets == NULL) { 19955682Smarkm ret = ENOMEM; 20078527Sassar krb5_set_error_string(context, "malloc: out of memory"); 20155682Smarkm goto fail; 20255682Smarkm } 20355682Smarkm ALLOC_SEQ(t->req_body.additional_tickets, 1); 20455682Smarkm if (t->req_body.additional_tickets->val == NULL) { 20555682Smarkm ret = ENOMEM; 20678527Sassar krb5_set_error_string(context, "malloc: out of memory"); 20755682Smarkm goto fail; 20855682Smarkm } 20955682Smarkm ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 21055682Smarkm if (ret) 21155682Smarkm goto fail; 21255682Smarkm } 21355682Smarkm ALLOC(t->padata, 1); 21455682Smarkm if (t->padata == NULL) { 21555682Smarkm ret = ENOMEM; 21678527Sassar krb5_set_error_string(context, "malloc: out of memory"); 21755682Smarkm goto fail; 21855682Smarkm } 21955682Smarkm ALLOC_SEQ(t->padata, 1); 22055682Smarkm if (t->padata->val == NULL) { 22155682Smarkm ret = ENOMEM; 22278527Sassar krb5_set_error_string(context, "malloc: out of memory"); 22355682Smarkm goto fail; 22455682Smarkm } 22555682Smarkm 22655682Smarkm { 22755682Smarkm krb5_auth_context ac; 228127808Snectar krb5_keyblock *key = NULL; 22955682Smarkm 23055682Smarkm ret = krb5_auth_con_init(context, &ac); 23155682Smarkm if(ret) 23255682Smarkm goto fail; 233127808Snectar 234127808Snectar if (krb5_config_get_bool_default(context, NULL, FALSE, 235127808Snectar "realms", 236127808Snectar krbtgt->server->realm, 237127808Snectar "tgs_require_subkey", 238127808Snectar NULL)) 239127808Snectar { 240127808Snectar ret = krb5_generate_subkey (context, &krbtgt->session, &key); 241127808Snectar if (ret) { 242127808Snectar krb5_auth_con_free (context, ac); 243127808Snectar goto fail; 244127808Snectar } 245127808Snectar 246127808Snectar ret = krb5_auth_con_setlocalsubkey(context, ac, key); 247127808Snectar if (ret) { 248127808Snectar if (key) 249127808Snectar krb5_free_keyblock (context, key); 250127808Snectar krb5_auth_con_free (context, ac); 251127808Snectar goto fail; 252127808Snectar } 25355682Smarkm } 25455682Smarkm 25555682Smarkm ret = set_auth_data (context, &t->req_body, &in_creds->authdata, key); 25655682Smarkm if (ret) { 257127808Snectar if (key) 258127808Snectar krb5_free_keyblock (context, key); 25955682Smarkm krb5_auth_con_free (context, ac); 26055682Smarkm goto fail; 26155682Smarkm } 26255682Smarkm 26355682Smarkm ret = make_pa_tgs_req(context, 26455682Smarkm ac, 26555682Smarkm &t->req_body, 26655682Smarkm t->padata->val, 26778527Sassar krbtgt, 26878527Sassar usage); 26955682Smarkm if(ret) { 270127808Snectar if (key) 271127808Snectar krb5_free_keyblock (context, key); 27255682Smarkm krb5_auth_con_free(context, ac); 27355682Smarkm goto fail; 27455682Smarkm } 27555682Smarkm *subkey = key; 27655682Smarkm 27755682Smarkm krb5_auth_con_free(context, ac); 27855682Smarkm } 27955682Smarkmfail: 280127808Snectar if (ret) { 281127808Snectar t->req_body.addresses = NULL; 28255682Smarkm free_TGS_REQ (t); 283127808Snectar } 28455682Smarkm return ret; 28555682Smarkm} 28655682Smarkm 287127808Snectarkrb5_error_code 288127808Snectar_krb5_get_krbtgt(krb5_context context, 289127808Snectar krb5_ccache id, 290127808Snectar krb5_realm realm, 291127808Snectar krb5_creds **cred) 29255682Smarkm{ 29355682Smarkm krb5_error_code ret; 29455682Smarkm krb5_creds tmp_cred; 29555682Smarkm 29655682Smarkm memset(&tmp_cred, 0, sizeof(tmp_cred)); 29755682Smarkm 298127808Snectar ret = krb5_cc_get_principal(context, id, &tmp_cred.client); 299127808Snectar if (ret) 300127808Snectar return ret; 301127808Snectar 30255682Smarkm ret = krb5_make_principal(context, 30355682Smarkm &tmp_cred.server, 30455682Smarkm realm, 30555682Smarkm KRB5_TGS_NAME, 30655682Smarkm realm, 30755682Smarkm NULL); 308127808Snectar if(ret) { 309127808Snectar krb5_free_principal(context, tmp_cred.client); 31055682Smarkm return ret; 311127808Snectar } 31255682Smarkm ret = krb5_get_credentials(context, 31355682Smarkm KRB5_GC_CACHED, 31455682Smarkm id, 31555682Smarkm &tmp_cred, 31655682Smarkm cred); 317127808Snectar krb5_free_principal(context, tmp_cred.client); 31855682Smarkm krb5_free_principal(context, tmp_cred.server); 31955682Smarkm if(ret) 32055682Smarkm return ret; 32155682Smarkm return 0; 32255682Smarkm} 32355682Smarkm 32455682Smarkm/* DCE compatible decrypt proc */ 32555682Smarkmstatic krb5_error_code 32655682Smarkmdecrypt_tkt_with_subkey (krb5_context context, 32755682Smarkm krb5_keyblock *key, 32855682Smarkm krb5_key_usage usage, 32955682Smarkm krb5_const_pointer subkey, 33055682Smarkm krb5_kdc_rep *dec_rep) 33155682Smarkm{ 33255682Smarkm krb5_error_code ret; 33355682Smarkm krb5_data data; 33455682Smarkm size_t size; 33555682Smarkm krb5_crypto crypto; 33655682Smarkm 33772445Sassar ret = krb5_crypto_init(context, key, 0, &crypto); 33872445Sassar if (ret) 33972445Sassar return ret; 34055682Smarkm ret = krb5_decrypt_EncryptedData (context, 34155682Smarkm crypto, 34255682Smarkm usage, 34355682Smarkm &dec_rep->kdc_rep.enc_part, 34455682Smarkm &data); 34555682Smarkm krb5_crypto_destroy(context, crypto); 34655682Smarkm if(ret && subkey){ 34755682Smarkm /* DCE compat -- try to decrypt with subkey */ 34872445Sassar ret = krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); 34972445Sassar if (ret) 35072445Sassar return ret; 35155682Smarkm ret = krb5_decrypt_EncryptedData (context, 35255682Smarkm crypto, 35355682Smarkm KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 35455682Smarkm &dec_rep->kdc_rep.enc_part, 35555682Smarkm &data); 35655682Smarkm krb5_crypto_destroy(context, crypto); 35755682Smarkm } 35855682Smarkm if (ret) 35955682Smarkm return ret; 36055682Smarkm 36155682Smarkm ret = krb5_decode_EncASRepPart(context, 36255682Smarkm data.data, 36355682Smarkm data.length, 36455682Smarkm &dec_rep->enc_part, 36555682Smarkm &size); 36655682Smarkm if (ret) 36755682Smarkm ret = krb5_decode_EncTGSRepPart(context, 36855682Smarkm data.data, 36955682Smarkm data.length, 37055682Smarkm &dec_rep->enc_part, 37155682Smarkm &size); 37255682Smarkm krb5_data_free (&data); 37355682Smarkm return ret; 37455682Smarkm} 37555682Smarkm 37655682Smarkmstatic krb5_error_code 37778527Sassarget_cred_kdc_usage(krb5_context context, 37878527Sassar krb5_ccache id, 37978527Sassar krb5_kdc_flags flags, 38078527Sassar krb5_addresses *addresses, 38178527Sassar krb5_creds *in_creds, 38278527Sassar krb5_creds *krbtgt, 38378527Sassar krb5_creds *out_creds, 38478527Sassar krb5_key_usage usage) 38555682Smarkm{ 38655682Smarkm TGS_REQ req; 38755682Smarkm krb5_data enc; 38855682Smarkm krb5_data resp; 38955682Smarkm krb5_kdc_rep rep; 39055682Smarkm KRB_ERROR error; 39155682Smarkm krb5_error_code ret; 39255682Smarkm unsigned nonce; 39355682Smarkm krb5_keyblock *subkey = NULL; 39455682Smarkm u_char *buf = NULL; 39555682Smarkm size_t buf_size; 39655682Smarkm size_t len; 39755682Smarkm Ticket second_ticket; 39855682Smarkm 39955682Smarkm krb5_generate_random_block(&nonce, sizeof(nonce)); 40055682Smarkm nonce &= 0xffffffff; 40155682Smarkm 40255682Smarkm if(flags.b.enc_tkt_in_skey){ 40355682Smarkm ret = decode_Ticket(in_creds->second_ticket.data, 40455682Smarkm in_creds->second_ticket.length, 40555682Smarkm &second_ticket, &len); 40655682Smarkm if(ret) 40755682Smarkm return ret; 40855682Smarkm } 40955682Smarkm 41055682Smarkm ret = init_tgs_req (context, 41155682Smarkm id, 41255682Smarkm addresses, 41355682Smarkm flags, 41455682Smarkm flags.b.enc_tkt_in_skey ? &second_ticket : NULL, 41555682Smarkm in_creds, 41655682Smarkm krbtgt, 41755682Smarkm nonce, 41855682Smarkm &subkey, 41978527Sassar &req, 42078527Sassar usage); 42155682Smarkm if(flags.b.enc_tkt_in_skey) 42255682Smarkm free_Ticket(&second_ticket); 42355682Smarkm if (ret) 42455682Smarkm goto out; 42555682Smarkm 426103423Snectar ASN1_MALLOC_ENCODE(TGS_REQ, buf, buf_size, &req, &enc.length, ret); 427103423Snectar if (ret) 42855682Smarkm goto out; 429103423Snectar if(enc.length != buf_size) 430103423Snectar krb5_abortx(context, "internal error in ASN.1 encoder"); 43155682Smarkm 43255682Smarkm /* don't free addresses */ 43355682Smarkm req.req_body.addresses = NULL; 43455682Smarkm free_TGS_REQ(&req); 43555682Smarkm 43655682Smarkm enc.data = buf + buf_size - enc.length; 43755682Smarkm if (ret) 43855682Smarkm goto out; 43955682Smarkm 44055682Smarkm /* 44155682Smarkm * Send and receive 44255682Smarkm */ 44355682Smarkm 44455682Smarkm ret = krb5_sendto_kdc (context, &enc, 44555682Smarkm &krbtgt->server->name.name_string.val[1], &resp); 44655682Smarkm if(ret) 44755682Smarkm goto out; 44855682Smarkm 44955682Smarkm memset(&rep, 0, sizeof(rep)); 45055682Smarkm if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ 45155682Smarkm ret = krb5_copy_principal(context, 45255682Smarkm in_creds->client, 45355682Smarkm &out_creds->client); 45455682Smarkm if(ret) 45555682Smarkm goto out; 45655682Smarkm ret = krb5_copy_principal(context, 45755682Smarkm in_creds->server, 45855682Smarkm &out_creds->server); 45955682Smarkm if(ret) 46055682Smarkm goto out; 46155682Smarkm /* this should go someplace else */ 46255682Smarkm out_creds->times.endtime = in_creds->times.endtime; 46355682Smarkm 46455682Smarkm ret = _krb5_extract_ticket(context, 46555682Smarkm &rep, 46655682Smarkm out_creds, 46755682Smarkm &krbtgt->session, 46855682Smarkm NULL, 46955682Smarkm KRB5_KU_TGS_REP_ENC_PART_SESSION, 47055682Smarkm &krbtgt->addresses, 47155682Smarkm nonce, 47255682Smarkm TRUE, 47372445Sassar flags.b.request_anonymous, 47455682Smarkm decrypt_tkt_with_subkey, 47555682Smarkm subkey); 47655682Smarkm krb5_free_kdc_rep(context, &rep); 47755682Smarkm if (ret) 47855682Smarkm goto out; 47978527Sassar } else if(krb5_rd_error(context, &resp, &error) == 0) { 48078527Sassar ret = krb5_error_from_rd_error(context, &error, in_creds); 48178527Sassar krb5_free_error_contents(context, &error); 48278527Sassar } else if(resp.data && ((char*)resp.data)[0] == 4) { 48355682Smarkm ret = KRB5KRB_AP_ERR_V4_REPLY; 48478527Sassar krb5_clear_error_string(context); 48578527Sassar } else { 48655682Smarkm ret = KRB5KRB_AP_ERR_MSG_TYPE; 48778527Sassar krb5_clear_error_string(context); 48878527Sassar } 48955682Smarkm krb5_data_free(&resp); 490127808Snectar out: 49155682Smarkm if(subkey){ 49255682Smarkm krb5_free_keyblock_contents(context, subkey); 49355682Smarkm free(subkey); 49455682Smarkm } 49555682Smarkm if (buf) 49655682Smarkm free (buf); 49755682Smarkm return ret; 49855682Smarkm 49955682Smarkm} 50055682Smarkm 50178527Sassarstatic krb5_error_code 50278527Sassarget_cred_kdc(krb5_context context, 50378527Sassar krb5_ccache id, 50478527Sassar krb5_kdc_flags flags, 50578527Sassar krb5_addresses *addresses, 50678527Sassar krb5_creds *in_creds, 50778527Sassar krb5_creds *krbtgt, 50878527Sassar krb5_creds *out_creds) 50978527Sassar{ 51078527Sassar krb5_error_code ret; 51178527Sassar 51278527Sassar ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 51378527Sassar krbtgt, out_creds, KRB5_KU_TGS_REQ_AUTH); 51478527Sassar if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 51578527Sassar krb5_clear_error_string (context); 51678527Sassar ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 51778527Sassar krbtgt, out_creds, KRB5_KU_AP_REQ_AUTH); 51878527Sassar } 51978527Sassar return ret; 52078527Sassar} 52178527Sassar 52255682Smarkm/* same as above, just get local addresses first */ 52355682Smarkm 52455682Smarkmstatic krb5_error_code 52555682Smarkmget_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, 52655682Smarkm krb5_creds *in_creds, krb5_creds *krbtgt, 52755682Smarkm krb5_creds *out_creds) 52855682Smarkm{ 52955682Smarkm krb5_error_code ret; 53090926Snectar krb5_addresses addresses, *addrs = &addresses; 53155682Smarkm 53255682Smarkm krb5_get_all_client_addrs(context, &addresses); 53390926Snectar /* XXX this sucks. */ 53490926Snectar if(addresses.len == 0) 53590926Snectar addrs = NULL; 53690926Snectar ret = get_cred_kdc(context, id, flags, addrs, 53755682Smarkm in_creds, krbtgt, out_creds); 53855682Smarkm krb5_free_addresses(context, &addresses); 53955682Smarkm return ret; 54055682Smarkm} 54155682Smarkm 54255682Smarkmkrb5_error_code 54355682Smarkmkrb5_get_kdc_cred(krb5_context context, 54455682Smarkm krb5_ccache id, 54555682Smarkm krb5_kdc_flags flags, 54655682Smarkm krb5_addresses *addresses, 54755682Smarkm Ticket *second_ticket, 54855682Smarkm krb5_creds *in_creds, 54955682Smarkm krb5_creds **out_creds 55055682Smarkm ) 55155682Smarkm{ 55255682Smarkm krb5_error_code ret; 55355682Smarkm krb5_creds *krbtgt; 55478527Sassar 55555682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 55678527Sassar if(*out_creds == NULL) { 55778527Sassar krb5_set_error_string(context, "malloc: out of memory"); 55855682Smarkm return ENOMEM; 55978527Sassar } 560127808Snectar ret = _krb5_get_krbtgt (context, 561127808Snectar id, 562127808Snectar in_creds->server->realm, 563127808Snectar &krbtgt); 56455682Smarkm if(ret) { 56555682Smarkm free(*out_creds); 56655682Smarkm return ret; 56755682Smarkm } 56855682Smarkm ret = get_cred_kdc(context, id, flags, addresses, 56955682Smarkm in_creds, krbtgt, *out_creds); 57055682Smarkm krb5_free_creds (context, krbtgt); 57155682Smarkm if(ret) 57255682Smarkm free(*out_creds); 57355682Smarkm return ret; 57455682Smarkm} 57555682Smarkm 57655682Smarkm 57755682Smarkmstatic krb5_error_code 57855682Smarkmfind_cred(krb5_context context, 57955682Smarkm krb5_ccache id, 58055682Smarkm krb5_principal server, 58155682Smarkm krb5_creds **tgts, 58255682Smarkm krb5_creds *out_creds) 58355682Smarkm{ 58455682Smarkm krb5_error_code ret; 58555682Smarkm krb5_creds mcreds; 58655682Smarkm mcreds.server = server; 58755682Smarkm ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 58855682Smarkm &mcreds, out_creds); 58955682Smarkm if(ret == 0) 59055682Smarkm return 0; 59155682Smarkm while(tgts && *tgts){ 59255682Smarkm if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 59355682Smarkm &mcreds, *tgts)){ 59455682Smarkm ret = krb5_copy_creds_contents(context, *tgts, out_creds); 59555682Smarkm return ret; 59655682Smarkm } 59755682Smarkm tgts++; 59855682Smarkm } 59978527Sassar krb5_clear_error_string(context); 60055682Smarkm return KRB5_CC_NOTFOUND; 60155682Smarkm} 60255682Smarkm 60355682Smarkmstatic krb5_error_code 60455682Smarkmadd_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt) 60555682Smarkm{ 60655682Smarkm int i; 60755682Smarkm krb5_error_code ret; 60855682Smarkm krb5_creds **tmp = *tgts; 60978527Sassar 61055682Smarkm for(i = 0; tmp && tmp[i]; i++); /* XXX */ 61155682Smarkm tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 61278527Sassar if(tmp == NULL) { 61378527Sassar krb5_set_error_string(context, "malloc: out of memory"); 61455682Smarkm return ENOMEM; 61578527Sassar } 61655682Smarkm *tgts = tmp; 61755682Smarkm ret = krb5_copy_creds(context, tkt, &tmp[i]); 61855682Smarkm tmp[i+1] = NULL; 61955682Smarkm return ret; 62055682Smarkm} 62155682Smarkm 62255682Smarkm/* 62355682Smarkmget_cred(server) 62455682Smarkm creds = cc_get_cred(server) 62555682Smarkm if(creds) return creds 62655682Smarkm tgt = cc_get_cred(krbtgt/server_realm@any_realm) 62755682Smarkm if(tgt) 62855682Smarkm return get_cred_tgt(server, tgt) 62955682Smarkm if(client_realm == server_realm) 63055682Smarkm return NULL 63155682Smarkm tgt = get_cred(krbtgt/server_realm@client_realm) 63255682Smarkm while(tgt_inst != server_realm) 63355682Smarkm tgt = get_cred(krbtgt/server_realm@tgt_inst) 63455682Smarkm return get_cred_tgt(server, tgt) 63555682Smarkm */ 63655682Smarkm 63755682Smarkmstatic krb5_error_code 63855682Smarkmget_cred_from_kdc_flags(krb5_context context, 63955682Smarkm krb5_kdc_flags flags, 64055682Smarkm krb5_ccache ccache, 64155682Smarkm krb5_creds *in_creds, 64255682Smarkm krb5_creds **out_creds, 64355682Smarkm krb5_creds ***ret_tgts) 64455682Smarkm{ 64555682Smarkm krb5_error_code ret; 64655682Smarkm krb5_creds *tgt, tmp_creds; 64772445Sassar krb5_const_realm client_realm, server_realm, try_realm; 64855682Smarkm 64955682Smarkm *out_creds = NULL; 65055682Smarkm 65155682Smarkm client_realm = *krb5_princ_realm(context, in_creds->client); 65255682Smarkm server_realm = *krb5_princ_realm(context, in_creds->server); 65355682Smarkm memset(&tmp_creds, 0, sizeof(tmp_creds)); 65455682Smarkm ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 65555682Smarkm if(ret) 65655682Smarkm return ret; 65772445Sassar 658127808Snectar try_realm = krb5_config_get_string(context, NULL, "capaths", 659127808Snectar client_realm, server_realm, NULL); 660127808Snectar 661127808Snectar#if 1 662127808Snectar /* XXX remove in future release */ 663127808Snectar if(try_realm == NULL) 664127808Snectar try_realm = krb5_config_get_string(context, NULL, "libdefaults", 665127808Snectar "capath", server_realm, NULL); 666127808Snectar#endif 667127808Snectar 66872445Sassar if (try_realm == NULL) 66972445Sassar try_realm = client_realm; 67072445Sassar 67155682Smarkm ret = krb5_make_principal(context, 67255682Smarkm &tmp_creds.server, 67372445Sassar try_realm, 67455682Smarkm KRB5_TGS_NAME, 675127808Snectar server_realm, 67655682Smarkm NULL); 67755682Smarkm if(ret){ 67855682Smarkm krb5_free_principal(context, tmp_creds.client); 67955682Smarkm return ret; 68055682Smarkm } 68155682Smarkm { 68255682Smarkm krb5_creds tgts; 68355682Smarkm /* XXX try krb5_cc_retrieve_cred first? */ 68455682Smarkm ret = find_cred(context, ccache, tmp_creds.server, 68555682Smarkm *ret_tgts, &tgts); 68655682Smarkm if(ret == 0){ 68755682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 68878527Sassar if(*out_creds == NULL) { 68978527Sassar krb5_set_error_string(context, "malloc: out of memory"); 69055682Smarkm ret = ENOMEM; 69178527Sassar } else { 692102644Snectar krb5_boolean noaddr; 693102644Snectar 694102644Snectar krb5_appdefault_boolean(context, NULL, tgts.server->realm, 695102644Snectar "no-addresses", FALSE, &noaddr); 696102644Snectar 697102644Snectar if (noaddr) 698102644Snectar ret = get_cred_kdc(context, ccache, flags, NULL, 699102644Snectar in_creds, &tgts, *out_creds); 700102644Snectar else 701102644Snectar ret = get_cred_kdc_la(context, ccache, flags, 702102644Snectar in_creds, &tgts, *out_creds); 70372445Sassar if (ret) { 70455682Smarkm free (*out_creds); 70572445Sassar *out_creds = NULL; 70672445Sassar } 70755682Smarkm } 70855682Smarkm krb5_free_creds_contents(context, &tgts); 70955682Smarkm krb5_free_principal(context, tmp_creds.server); 71055682Smarkm krb5_free_principal(context, tmp_creds.client); 71155682Smarkm return ret; 71255682Smarkm } 71355682Smarkm } 71478527Sassar if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { 71578527Sassar krb5_clear_error_string (context); 71655682Smarkm return KRB5_CC_NOTFOUND; 71778527Sassar } 71855682Smarkm /* XXX this can loop forever */ 71955682Smarkm while(1){ 72055682Smarkm general_string tgt_inst; 72172445Sassar 72255682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 72355682Smarkm &tgt, ret_tgts); 72455682Smarkm if(ret) { 72555682Smarkm krb5_free_principal(context, tmp_creds.server); 72655682Smarkm krb5_free_principal(context, tmp_creds.client); 72755682Smarkm return ret; 72855682Smarkm } 72955682Smarkm ret = add_cred(context, ret_tgts, tgt); 73055682Smarkm if(ret) { 73155682Smarkm krb5_free_principal(context, tmp_creds.server); 73255682Smarkm krb5_free_principal(context, tmp_creds.client); 73355682Smarkm return ret; 73455682Smarkm } 73555682Smarkm tgt_inst = tgt->server->name.name_string.val[1]; 73655682Smarkm if(strcmp(tgt_inst, server_realm) == 0) 73755682Smarkm break; 73855682Smarkm krb5_free_principal(context, tmp_creds.server); 73955682Smarkm ret = krb5_make_principal(context, &tmp_creds.server, 74055682Smarkm tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 74155682Smarkm if(ret) { 74255682Smarkm krb5_free_principal(context, tmp_creds.server); 74355682Smarkm krb5_free_principal(context, tmp_creds.client); 74455682Smarkm return ret; 74555682Smarkm } 74655682Smarkm ret = krb5_free_creds(context, tgt); 74755682Smarkm if(ret) { 74855682Smarkm krb5_free_principal(context, tmp_creds.server); 74955682Smarkm krb5_free_principal(context, tmp_creds.client); 75055682Smarkm return ret; 75155682Smarkm } 75255682Smarkm } 75355682Smarkm 75455682Smarkm krb5_free_principal(context, tmp_creds.server); 75555682Smarkm krb5_free_principal(context, tmp_creds.client); 75655682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 75778527Sassar if(*out_creds == NULL) { 75878527Sassar krb5_set_error_string(context, "malloc: out of memory"); 75955682Smarkm ret = ENOMEM; 76078527Sassar } else { 761102644Snectar krb5_boolean noaddr; 762102644Snectar 763102644Snectar krb5_appdefault_boolean(context, NULL, tgt->server->realm, 764102644Snectar "no-addresses", FALSE, &noaddr); 765102644Snectar if (noaddr) 766102644Snectar ret = get_cred_kdc (context, ccache, flags, NULL, 767102644Snectar in_creds, tgt, *out_creds); 768102644Snectar else 769102644Snectar ret = get_cred_kdc_la(context, ccache, flags, 770102644Snectar in_creds, tgt, *out_creds); 77172445Sassar if (ret) { 77255682Smarkm free (*out_creds); 77372445Sassar *out_creds = NULL; 77472445Sassar } 77555682Smarkm } 77655682Smarkm krb5_free_creds(context, tgt); 77755682Smarkm return ret; 77855682Smarkm} 77955682Smarkm 78055682Smarkmkrb5_error_code 78178527Sassarkrb5_get_cred_from_kdc_opt(krb5_context context, 78278527Sassar krb5_ccache ccache, 78378527Sassar krb5_creds *in_creds, 78478527Sassar krb5_creds **out_creds, 78578527Sassar krb5_creds ***ret_tgts, 78678527Sassar krb5_flags flags) 78778527Sassar{ 78878527Sassar krb5_kdc_flags f; 78978527Sassar f.i = flags; 79078527Sassar return get_cred_from_kdc_flags(context, f, ccache, 79178527Sassar in_creds, out_creds, ret_tgts); 79278527Sassar} 79378527Sassar 79478527Sassarkrb5_error_code 79555682Smarkmkrb5_get_cred_from_kdc(krb5_context context, 79655682Smarkm krb5_ccache ccache, 79755682Smarkm krb5_creds *in_creds, 79855682Smarkm krb5_creds **out_creds, 79955682Smarkm krb5_creds ***ret_tgts) 80055682Smarkm{ 80178527Sassar return krb5_get_cred_from_kdc_opt(context, ccache, 80278527Sassar in_creds, out_creds, ret_tgts, 0); 80355682Smarkm} 80455682Smarkm 80555682Smarkm 80655682Smarkmkrb5_error_code 80755682Smarkmkrb5_get_credentials_with_flags(krb5_context context, 80855682Smarkm krb5_flags options, 80955682Smarkm krb5_kdc_flags flags, 81055682Smarkm krb5_ccache ccache, 81155682Smarkm krb5_creds *in_creds, 81255682Smarkm krb5_creds **out_creds) 81355682Smarkm{ 81455682Smarkm krb5_error_code ret; 81555682Smarkm krb5_creds **tgts; 81672445Sassar krb5_creds *res_creds; 81755682Smarkm int i; 81855682Smarkm 81972445Sassar *out_creds = NULL; 82072445Sassar res_creds = calloc(1, sizeof(*res_creds)); 82178527Sassar if (res_creds == NULL) { 82278527Sassar krb5_set_error_string(context, "malloc: out of memory"); 82355682Smarkm return ENOMEM; 82478527Sassar } 82555682Smarkm 82655682Smarkm ret = krb5_cc_retrieve_cred(context, 82755682Smarkm ccache, 82855682Smarkm in_creds->session.keytype ? 82955682Smarkm KRB5_TC_MATCH_KEYTYPE : 0, 83072445Sassar in_creds, res_creds); 83172445Sassar if(ret == 0) { 83272445Sassar *out_creds = res_creds; 83355682Smarkm return 0; 83472445Sassar } 83572445Sassar free(res_creds); 83655682Smarkm if(ret != KRB5_CC_END) 83755682Smarkm return ret; 83878527Sassar if(options & KRB5_GC_CACHED) { 83978527Sassar krb5_clear_error_string (context); 84055682Smarkm return KRB5_CC_NOTFOUND; 84178527Sassar } 84255682Smarkm if(options & KRB5_GC_USER_USER) 84355682Smarkm flags.b.enc_tkt_in_skey = 1; 84455682Smarkm tgts = NULL; 84555682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, 84655682Smarkm in_creds, out_creds, &tgts); 84772445Sassar for(i = 0; tgts && tgts[i]; i++) { 84855682Smarkm krb5_cc_store_cred(context, ccache, tgts[i]); 84955682Smarkm krb5_free_creds(context, tgts[i]); 85055682Smarkm } 85155682Smarkm free(tgts); 85255682Smarkm if(ret == 0 && flags.b.enc_tkt_in_skey == 0) 85355682Smarkm krb5_cc_store_cred(context, ccache, *out_creds); 85455682Smarkm return ret; 85555682Smarkm} 85655682Smarkm 85755682Smarkmkrb5_error_code 85855682Smarkmkrb5_get_credentials(krb5_context context, 85955682Smarkm krb5_flags options, 86055682Smarkm krb5_ccache ccache, 86155682Smarkm krb5_creds *in_creds, 86255682Smarkm krb5_creds **out_creds) 86355682Smarkm{ 86455682Smarkm krb5_kdc_flags flags; 86555682Smarkm flags.i = 0; 86655682Smarkm return krb5_get_credentials_with_flags(context, options, flags, 86755682Smarkm ccache, in_creds, out_creds); 86855682Smarkm} 869