155682Smarkm/* 2178825Sdfr * Copyright (c) 1997 - 2007 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 36178825SdfrRCSID("$Id: get_cred.c 21668 2007-07-22 11:28:05Z lha $"); 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; 65178825Sdfr ret = _krb5_mk_req_internal(context, &ac, 0, &in_data, creds, 66178825Sdfr &padata->padata_value, 67178825Sdfr KRB5_KU_TGS_REQ_AUTH_CKSUM, 68178825Sdfr usage 69178825Sdfr /* KRB5_KU_TGS_REQ_AUTH */); 70178825Sdfr out: 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) { 89178825Sdfr size_t len, buf_size; 9055682Smarkm unsigned char *buf; 9155682Smarkm krb5_crypto crypto; 9255682Smarkm krb5_error_code ret; 9355682Smarkm 94178825Sdfr ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, 95178825Sdfr &len, ret); 96103423Snectar if (ret) 9755682Smarkm return ret; 98178825Sdfr if (buf_size != len) 99178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 10055682Smarkm 10155682Smarkm ALLOC(req_body->enc_authorization_data, 1); 10255682Smarkm if (req_body->enc_authorization_data == NULL) { 10355682Smarkm free (buf); 10478527Sassar krb5_set_error_string(context, "malloc: out of memory"); 10578527Sassar return ENOMEM; 10655682Smarkm } 10755682Smarkm ret = krb5_crypto_init(context, key, 0, &crypto); 10855682Smarkm if (ret) { 10955682Smarkm free (buf); 11055682Smarkm free (req_body->enc_authorization_data); 111178825Sdfr req_body->enc_authorization_data = NULL; 11255682Smarkm return ret; 11355682Smarkm } 11455682Smarkm krb5_encrypt_EncryptedData(context, 11555682Smarkm crypto, 11655682Smarkm KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, 11755682Smarkm /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */ 11855682Smarkm buf, 11955682Smarkm len, 12055682Smarkm 0, 12155682Smarkm req_body->enc_authorization_data); 12255682Smarkm free (buf); 12355682Smarkm krb5_crypto_destroy(context, crypto); 12455682Smarkm } else { 12555682Smarkm req_body->enc_authorization_data = NULL; 12655682Smarkm } 12755682Smarkm return 0; 12855682Smarkm} 12955682Smarkm 13055682Smarkm/* 13155682Smarkm * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' 13255682Smarkm * (if not-NULL), `in_creds', `krbtgt', and returning the generated 13355682Smarkm * subkey in `subkey'. 13455682Smarkm */ 13555682Smarkm 13655682Smarkmstatic krb5_error_code 13755682Smarkminit_tgs_req (krb5_context context, 13855682Smarkm krb5_ccache ccache, 13955682Smarkm krb5_addresses *addresses, 14055682Smarkm krb5_kdc_flags flags, 14155682Smarkm Ticket *second_ticket, 14255682Smarkm krb5_creds *in_creds, 14355682Smarkm krb5_creds *krbtgt, 14455682Smarkm unsigned nonce, 145178825Sdfr const METHOD_DATA *padata, 14655682Smarkm krb5_keyblock **subkey, 14778527Sassar TGS_REQ *t, 14878527Sassar krb5_key_usage usage) 14955682Smarkm{ 150103423Snectar krb5_error_code ret = 0; 15155682Smarkm 15255682Smarkm memset(t, 0, sizeof(*t)); 15355682Smarkm t->pvno = 5; 15455682Smarkm t->msg_type = krb_tgs_req; 15555682Smarkm if (in_creds->session.keytype) { 156103423Snectar ALLOC_SEQ(&t->req_body.etype, 1); 157103423Snectar if(t->req_body.etype.val == NULL) { 158103423Snectar ret = ENOMEM; 159103423Snectar krb5_set_error_string(context, "malloc: out of memory"); 160103423Snectar goto fail; 161103423Snectar } 162103423Snectar t->req_body.etype.val[0] = in_creds->session.keytype; 16355682Smarkm } else { 16455682Smarkm ret = krb5_init_etype(context, 16555682Smarkm &t->req_body.etype.len, 16655682Smarkm &t->req_body.etype.val, 16755682Smarkm NULL); 16855682Smarkm } 16955682Smarkm if (ret) 17055682Smarkm goto fail; 17155682Smarkm t->req_body.addresses = addresses; 17255682Smarkm t->req_body.kdc_options = flags.b; 17355682Smarkm ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); 17455682Smarkm if (ret) 17555682Smarkm goto fail; 17655682Smarkm ALLOC(t->req_body.sname, 1); 17755682Smarkm if (t->req_body.sname == NULL) { 17855682Smarkm ret = ENOMEM; 17978527Sassar krb5_set_error_string(context, "malloc: out of memory"); 18055682Smarkm goto fail; 18155682Smarkm } 18272445Sassar 18372445Sassar /* some versions of some code might require that the client be 18472445Sassar present in TGS-REQs, but this is clearly against the spec */ 18572445Sassar 18655682Smarkm ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); 18755682Smarkm if (ret) 18855682Smarkm goto fail; 18955682Smarkm 19055682Smarkm /* req_body.till should be NULL if there is no endtime specified, 19155682Smarkm but old MIT code (like DCE secd) doesn't like that */ 19255682Smarkm ALLOC(t->req_body.till, 1); 19355682Smarkm if(t->req_body.till == NULL){ 19455682Smarkm ret = ENOMEM; 19578527Sassar krb5_set_error_string(context, "malloc: out of memory"); 19655682Smarkm goto fail; 19755682Smarkm } 19855682Smarkm *t->req_body.till = in_creds->times.endtime; 19955682Smarkm 20055682Smarkm t->req_body.nonce = nonce; 20155682Smarkm if(second_ticket){ 20255682Smarkm ALLOC(t->req_body.additional_tickets, 1); 20355682Smarkm if (t->req_body.additional_tickets == NULL) { 20455682Smarkm ret = ENOMEM; 20578527Sassar krb5_set_error_string(context, "malloc: out of memory"); 20655682Smarkm goto fail; 20755682Smarkm } 20855682Smarkm ALLOC_SEQ(t->req_body.additional_tickets, 1); 20955682Smarkm if (t->req_body.additional_tickets->val == NULL) { 21055682Smarkm ret = ENOMEM; 21178527Sassar krb5_set_error_string(context, "malloc: out of memory"); 21255682Smarkm goto fail; 21355682Smarkm } 21455682Smarkm ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); 21555682Smarkm if (ret) 21655682Smarkm goto fail; 21755682Smarkm } 21855682Smarkm ALLOC(t->padata, 1); 21955682Smarkm if (t->padata == NULL) { 22055682Smarkm ret = ENOMEM; 22178527Sassar krb5_set_error_string(context, "malloc: out of memory"); 22255682Smarkm goto fail; 22355682Smarkm } 224178825Sdfr ALLOC_SEQ(t->padata, 1 + padata->len); 22555682Smarkm if (t->padata->val == NULL) { 22655682Smarkm ret = ENOMEM; 22778527Sassar krb5_set_error_string(context, "malloc: out of memory"); 22855682Smarkm goto fail; 22955682Smarkm } 230178825Sdfr { 231178825Sdfr int i; 232178825Sdfr for (i = 0; i < padata->len; i++) { 233178825Sdfr ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); 234178825Sdfr if (ret) { 235178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 236178825Sdfr goto fail; 237178825Sdfr } 238178825Sdfr } 239178825Sdfr } 24055682Smarkm 24155682Smarkm { 24255682Smarkm krb5_auth_context ac; 243127808Snectar krb5_keyblock *key = NULL; 24455682Smarkm 24555682Smarkm ret = krb5_auth_con_init(context, &ac); 24655682Smarkm if(ret) 24755682Smarkm goto fail; 248127808Snectar 249127808Snectar if (krb5_config_get_bool_default(context, NULL, FALSE, 250127808Snectar "realms", 251127808Snectar krbtgt->server->realm, 252127808Snectar "tgs_require_subkey", 253127808Snectar NULL)) 254127808Snectar { 255127808Snectar ret = krb5_generate_subkey (context, &krbtgt->session, &key); 256127808Snectar if (ret) { 257127808Snectar krb5_auth_con_free (context, ac); 258127808Snectar goto fail; 259127808Snectar } 260127808Snectar 261127808Snectar ret = krb5_auth_con_setlocalsubkey(context, ac, key); 262127808Snectar if (ret) { 263127808Snectar if (key) 264127808Snectar krb5_free_keyblock (context, key); 265127808Snectar krb5_auth_con_free (context, ac); 266127808Snectar goto fail; 267127808Snectar } 26855682Smarkm } 26955682Smarkm 270178825Sdfr ret = set_auth_data (context, &t->req_body, &in_creds->authdata, 271178825Sdfr key ? key : &krbtgt->session); 27255682Smarkm if (ret) { 273127808Snectar if (key) 274127808Snectar krb5_free_keyblock (context, key); 27555682Smarkm krb5_auth_con_free (context, ac); 27655682Smarkm goto fail; 27755682Smarkm } 27855682Smarkm 27955682Smarkm ret = make_pa_tgs_req(context, 28055682Smarkm ac, 28155682Smarkm &t->req_body, 282178825Sdfr &t->padata->val[0], 28378527Sassar krbtgt, 28478527Sassar usage); 28555682Smarkm if(ret) { 286127808Snectar if (key) 287127808Snectar krb5_free_keyblock (context, key); 28855682Smarkm krb5_auth_con_free(context, ac); 28955682Smarkm goto fail; 29055682Smarkm } 29155682Smarkm *subkey = key; 29255682Smarkm 29355682Smarkm krb5_auth_con_free(context, ac); 29455682Smarkm } 29555682Smarkmfail: 296127808Snectar if (ret) { 297127808Snectar t->req_body.addresses = NULL; 29855682Smarkm free_TGS_REQ (t); 299127808Snectar } 30055682Smarkm return ret; 30155682Smarkm} 30255682Smarkm 303127808Snectarkrb5_error_code 304127808Snectar_krb5_get_krbtgt(krb5_context context, 305127808Snectar krb5_ccache id, 306127808Snectar krb5_realm realm, 307127808Snectar krb5_creds **cred) 30855682Smarkm{ 30955682Smarkm krb5_error_code ret; 31055682Smarkm krb5_creds tmp_cred; 31155682Smarkm 31255682Smarkm memset(&tmp_cred, 0, sizeof(tmp_cred)); 31355682Smarkm 314127808Snectar ret = krb5_cc_get_principal(context, id, &tmp_cred.client); 315127808Snectar if (ret) 316127808Snectar return ret; 317127808Snectar 31855682Smarkm ret = krb5_make_principal(context, 31955682Smarkm &tmp_cred.server, 32055682Smarkm realm, 32155682Smarkm KRB5_TGS_NAME, 32255682Smarkm realm, 32355682Smarkm NULL); 324127808Snectar if(ret) { 325127808Snectar krb5_free_principal(context, tmp_cred.client); 32655682Smarkm return ret; 327127808Snectar } 32855682Smarkm ret = krb5_get_credentials(context, 32955682Smarkm KRB5_GC_CACHED, 33055682Smarkm id, 33155682Smarkm &tmp_cred, 33255682Smarkm cred); 333127808Snectar krb5_free_principal(context, tmp_cred.client); 33455682Smarkm krb5_free_principal(context, tmp_cred.server); 33555682Smarkm if(ret) 33655682Smarkm return ret; 33755682Smarkm return 0; 33855682Smarkm} 33955682Smarkm 34055682Smarkm/* DCE compatible decrypt proc */ 34155682Smarkmstatic krb5_error_code 34255682Smarkmdecrypt_tkt_with_subkey (krb5_context context, 34355682Smarkm krb5_keyblock *key, 34455682Smarkm krb5_key_usage usage, 34555682Smarkm krb5_const_pointer subkey, 34655682Smarkm krb5_kdc_rep *dec_rep) 34755682Smarkm{ 34855682Smarkm krb5_error_code ret; 34955682Smarkm krb5_data data; 35055682Smarkm size_t size; 35155682Smarkm krb5_crypto crypto; 35255682Smarkm 35372445Sassar ret = krb5_crypto_init(context, key, 0, &crypto); 35472445Sassar if (ret) 35572445Sassar return ret; 35655682Smarkm ret = krb5_decrypt_EncryptedData (context, 35755682Smarkm crypto, 35855682Smarkm usage, 35955682Smarkm &dec_rep->kdc_rep.enc_part, 36055682Smarkm &data); 36155682Smarkm krb5_crypto_destroy(context, crypto); 36255682Smarkm if(ret && subkey){ 36355682Smarkm /* DCE compat -- try to decrypt with subkey */ 364178825Sdfr ret = krb5_crypto_init(context, subkey, 0, &crypto); 36572445Sassar if (ret) 36672445Sassar return ret; 36755682Smarkm ret = krb5_decrypt_EncryptedData (context, 36855682Smarkm crypto, 36955682Smarkm KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, 37055682Smarkm &dec_rep->kdc_rep.enc_part, 37155682Smarkm &data); 37255682Smarkm krb5_crypto_destroy(context, crypto); 37355682Smarkm } 37455682Smarkm if (ret) 37555682Smarkm return ret; 37655682Smarkm 37755682Smarkm ret = krb5_decode_EncASRepPart(context, 37855682Smarkm data.data, 37955682Smarkm data.length, 38055682Smarkm &dec_rep->enc_part, 38155682Smarkm &size); 38255682Smarkm if (ret) 38355682Smarkm ret = krb5_decode_EncTGSRepPart(context, 38455682Smarkm data.data, 38555682Smarkm data.length, 38655682Smarkm &dec_rep->enc_part, 38755682Smarkm &size); 38855682Smarkm krb5_data_free (&data); 38955682Smarkm return ret; 39055682Smarkm} 39155682Smarkm 39255682Smarkmstatic krb5_error_code 39378527Sassarget_cred_kdc_usage(krb5_context context, 39478527Sassar krb5_ccache id, 39578527Sassar krb5_kdc_flags flags, 39678527Sassar krb5_addresses *addresses, 397178825Sdfr krb5_creds *in_creds, 39878527Sassar krb5_creds *krbtgt, 399178825Sdfr krb5_principal impersonate_principal, 400178825Sdfr Ticket *second_ticket, 40178527Sassar krb5_creds *out_creds, 40278527Sassar krb5_key_usage usage) 40355682Smarkm{ 40455682Smarkm TGS_REQ req; 40555682Smarkm krb5_data enc; 40655682Smarkm krb5_data resp; 40755682Smarkm krb5_kdc_rep rep; 40855682Smarkm KRB_ERROR error; 40955682Smarkm krb5_error_code ret; 41055682Smarkm unsigned nonce; 41155682Smarkm krb5_keyblock *subkey = NULL; 41255682Smarkm size_t len; 413178825Sdfr Ticket second_ticket_data; 414178825Sdfr METHOD_DATA padata; 41555682Smarkm 416178825Sdfr krb5_data_zero(&resp); 417178825Sdfr krb5_data_zero(&enc); 418178825Sdfr padata.val = NULL; 419178825Sdfr padata.len = 0; 420178825Sdfr 42155682Smarkm krb5_generate_random_block(&nonce, sizeof(nonce)); 42255682Smarkm nonce &= 0xffffffff; 42355682Smarkm 424178825Sdfr if(flags.b.enc_tkt_in_skey && second_ticket == NULL){ 42555682Smarkm ret = decode_Ticket(in_creds->second_ticket.data, 42655682Smarkm in_creds->second_ticket.length, 427178825Sdfr &second_ticket_data, &len); 42855682Smarkm if(ret) 42955682Smarkm return ret; 430178825Sdfr second_ticket = &second_ticket_data; 43155682Smarkm } 43255682Smarkm 433178825Sdfr 434178825Sdfr if (impersonate_principal) { 435178825Sdfr krb5_crypto crypto; 436178825Sdfr PA_S4U2Self self; 437178825Sdfr krb5_data data; 438178825Sdfr void *buf; 439178825Sdfr size_t size; 440178825Sdfr 441178825Sdfr self.name = impersonate_principal->name; 442178825Sdfr self.realm = impersonate_principal->realm; 443178825Sdfr self.auth = estrdup("Kerberos"); 444178825Sdfr 445178825Sdfr ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); 446178825Sdfr if (ret) { 447178825Sdfr free(self.auth); 448178825Sdfr goto out; 449178825Sdfr } 450178825Sdfr 451178825Sdfr ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); 452178825Sdfr if (ret) { 453178825Sdfr free(self.auth); 454178825Sdfr krb5_data_free(&data); 455178825Sdfr goto out; 456178825Sdfr } 457178825Sdfr 458178825Sdfr ret = krb5_create_checksum(context, 459178825Sdfr crypto, 460178825Sdfr KRB5_KU_OTHER_CKSUM, 461178825Sdfr 0, 462178825Sdfr data.data, 463178825Sdfr data.length, 464178825Sdfr &self.cksum); 465178825Sdfr krb5_crypto_destroy(context, crypto); 466178825Sdfr krb5_data_free(&data); 467178825Sdfr if (ret) { 468178825Sdfr free(self.auth); 469178825Sdfr goto out; 470178825Sdfr } 471178825Sdfr 472178825Sdfr ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); 473178825Sdfr free(self.auth); 474178825Sdfr free_Checksum(&self.cksum); 475178825Sdfr if (ret) 476178825Sdfr goto out; 477178825Sdfr if (len != size) 478178825Sdfr krb5_abortx(context, "internal asn1 error"); 479178825Sdfr 480178825Sdfr ret = krb5_padata_add(context, &padata, KRB5_PADATA_S4U2SELF, buf, len); 481178825Sdfr if (ret) 482178825Sdfr goto out; 483178825Sdfr } 484178825Sdfr 48555682Smarkm ret = init_tgs_req (context, 48655682Smarkm id, 48755682Smarkm addresses, 48855682Smarkm flags, 489178825Sdfr second_ticket, 49055682Smarkm in_creds, 49155682Smarkm krbtgt, 49255682Smarkm nonce, 493178825Sdfr &padata, 49455682Smarkm &subkey, 49578527Sassar &req, 49678527Sassar usage); 49755682Smarkm if (ret) 49855682Smarkm goto out; 49955682Smarkm 500178825Sdfr ASN1_MALLOC_ENCODE(TGS_REQ, enc.data, enc.length, &req, &len, ret); 501103423Snectar if (ret) 50255682Smarkm goto out; 503178825Sdfr if(enc.length != len) 504103423Snectar krb5_abortx(context, "internal error in ASN.1 encoder"); 50555682Smarkm 50655682Smarkm /* don't free addresses */ 50755682Smarkm req.req_body.addresses = NULL; 50855682Smarkm free_TGS_REQ(&req); 50955682Smarkm 51055682Smarkm /* 51155682Smarkm * Send and receive 51255682Smarkm */ 513178825Sdfr { 514178825Sdfr krb5_sendto_ctx stctx; 515178825Sdfr ret = krb5_sendto_ctx_alloc(context, &stctx); 516178825Sdfr if (ret) 517178825Sdfr return ret; 518178825Sdfr krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); 51955682Smarkm 520178825Sdfr ret = krb5_sendto_context (context, stctx, &enc, 521178825Sdfr krbtgt->server->name.name_string.val[1], 522178825Sdfr &resp); 523178825Sdfr krb5_sendto_ctx_free(context, stctx); 524178825Sdfr } 52555682Smarkm if(ret) 52655682Smarkm goto out; 52755682Smarkm 52855682Smarkm memset(&rep, 0, sizeof(rep)); 52955682Smarkm if(decode_TGS_REP(resp.data, resp.length, &rep.kdc_rep, &len) == 0){ 53055682Smarkm ret = krb5_copy_principal(context, 53155682Smarkm in_creds->client, 53255682Smarkm &out_creds->client); 53355682Smarkm if(ret) 53455682Smarkm goto out; 53555682Smarkm ret = krb5_copy_principal(context, 53655682Smarkm in_creds->server, 53755682Smarkm &out_creds->server); 53855682Smarkm if(ret) 53955682Smarkm goto out; 54055682Smarkm /* this should go someplace else */ 54155682Smarkm out_creds->times.endtime = in_creds->times.endtime; 54255682Smarkm 54355682Smarkm ret = _krb5_extract_ticket(context, 54455682Smarkm &rep, 54555682Smarkm out_creds, 54655682Smarkm &krbtgt->session, 54755682Smarkm NULL, 54855682Smarkm KRB5_KU_TGS_REP_ENC_PART_SESSION, 54955682Smarkm &krbtgt->addresses, 55055682Smarkm nonce, 551178825Sdfr EXTRACT_TICKET_ALLOW_CNAME_MISMATCH| 552178825Sdfr EXTRACT_TICKET_ALLOW_SERVER_MISMATCH, 55355682Smarkm decrypt_tkt_with_subkey, 55455682Smarkm subkey); 55555682Smarkm krb5_free_kdc_rep(context, &rep); 55678527Sassar } else if(krb5_rd_error(context, &resp, &error) == 0) { 55778527Sassar ret = krb5_error_from_rd_error(context, &error, in_creds); 55878527Sassar krb5_free_error_contents(context, &error); 55978527Sassar } else if(resp.data && ((char*)resp.data)[0] == 4) { 56055682Smarkm ret = KRB5KRB_AP_ERR_V4_REPLY; 56178527Sassar krb5_clear_error_string(context); 56278527Sassar } else { 56355682Smarkm ret = KRB5KRB_AP_ERR_MSG_TYPE; 56478527Sassar krb5_clear_error_string(context); 56578527Sassar } 566178825Sdfr 567178825Sdfrout: 568178825Sdfr if (second_ticket == &second_ticket_data) 569178825Sdfr free_Ticket(&second_ticket_data); 570178825Sdfr free_METHOD_DATA(&padata); 57155682Smarkm krb5_data_free(&resp); 572178825Sdfr krb5_data_free(&enc); 57355682Smarkm if(subkey){ 57455682Smarkm krb5_free_keyblock_contents(context, subkey); 57555682Smarkm free(subkey); 57655682Smarkm } 57755682Smarkm return ret; 57855682Smarkm 57955682Smarkm} 58055682Smarkm 58178527Sassarstatic krb5_error_code 58278527Sassarget_cred_kdc(krb5_context context, 58378527Sassar krb5_ccache id, 58478527Sassar krb5_kdc_flags flags, 58578527Sassar krb5_addresses *addresses, 58678527Sassar krb5_creds *in_creds, 58778527Sassar krb5_creds *krbtgt, 588178825Sdfr krb5_principal impersonate_principal, 589178825Sdfr Ticket *second_ticket, 59078527Sassar krb5_creds *out_creds) 59178527Sassar{ 59278527Sassar krb5_error_code ret; 59378527Sassar 59478527Sassar ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 595178825Sdfr krbtgt, impersonate_principal, second_ticket, 596178825Sdfr out_creds, KRB5_KU_TGS_REQ_AUTH); 59778527Sassar if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) { 59878527Sassar krb5_clear_error_string (context); 59978527Sassar ret = get_cred_kdc_usage(context, id, flags, addresses, in_creds, 600178825Sdfr krbtgt, impersonate_principal, second_ticket, 601178825Sdfr out_creds, KRB5_KU_AP_REQ_AUTH); 60278527Sassar } 60378527Sassar return ret; 60478527Sassar} 60578527Sassar 60655682Smarkm/* same as above, just get local addresses first */ 60755682Smarkm 60855682Smarkmstatic krb5_error_code 60955682Smarkmget_cred_kdc_la(krb5_context context, krb5_ccache id, krb5_kdc_flags flags, 61055682Smarkm krb5_creds *in_creds, krb5_creds *krbtgt, 611178825Sdfr krb5_principal impersonate_principal, Ticket *second_ticket, 61255682Smarkm krb5_creds *out_creds) 61355682Smarkm{ 61455682Smarkm krb5_error_code ret; 61590926Snectar krb5_addresses addresses, *addrs = &addresses; 61655682Smarkm 61755682Smarkm krb5_get_all_client_addrs(context, &addresses); 61890926Snectar /* XXX this sucks. */ 61990926Snectar if(addresses.len == 0) 62090926Snectar addrs = NULL; 62190926Snectar ret = get_cred_kdc(context, id, flags, addrs, 622178825Sdfr in_creds, krbtgt, impersonate_principal, second_ticket, 623178825Sdfr out_creds); 62455682Smarkm krb5_free_addresses(context, &addresses); 62555682Smarkm return ret; 62655682Smarkm} 62755682Smarkm 628178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 62955682Smarkmkrb5_get_kdc_cred(krb5_context context, 63055682Smarkm krb5_ccache id, 63155682Smarkm krb5_kdc_flags flags, 63255682Smarkm krb5_addresses *addresses, 63355682Smarkm Ticket *second_ticket, 63455682Smarkm krb5_creds *in_creds, 63555682Smarkm krb5_creds **out_creds 63655682Smarkm ) 63755682Smarkm{ 63855682Smarkm krb5_error_code ret; 63955682Smarkm krb5_creds *krbtgt; 64078527Sassar 64155682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 64278527Sassar if(*out_creds == NULL) { 64378527Sassar krb5_set_error_string(context, "malloc: out of memory"); 64455682Smarkm return ENOMEM; 64578527Sassar } 646127808Snectar ret = _krb5_get_krbtgt (context, 647127808Snectar id, 648127808Snectar in_creds->server->realm, 649127808Snectar &krbtgt); 65055682Smarkm if(ret) { 65155682Smarkm free(*out_creds); 65255682Smarkm return ret; 65355682Smarkm } 65455682Smarkm ret = get_cred_kdc(context, id, flags, addresses, 655178825Sdfr in_creds, krbtgt, NULL, NULL, *out_creds); 65655682Smarkm krb5_free_creds (context, krbtgt); 65755682Smarkm if(ret) 65855682Smarkm free(*out_creds); 65955682Smarkm return ret; 66055682Smarkm} 66155682Smarkm 662178825Sdfrstatic void 663178825Sdfrnot_found(krb5_context context, krb5_const_principal p) 664178825Sdfr{ 665178825Sdfr krb5_error_code ret; 666178825Sdfr char *str; 66755682Smarkm 668178825Sdfr ret = krb5_unparse_name(context, p, &str); 669178825Sdfr if(ret) { 670178825Sdfr krb5_clear_error_string(context); 671178825Sdfr return; 672178825Sdfr } 673178825Sdfr krb5_set_error_string(context, "Matching credential (%s) not found", str); 674178825Sdfr free(str); 675178825Sdfr} 676178825Sdfr 67755682Smarkmstatic krb5_error_code 67855682Smarkmfind_cred(krb5_context context, 67955682Smarkm krb5_ccache id, 68055682Smarkm krb5_principal server, 68155682Smarkm krb5_creds **tgts, 68255682Smarkm krb5_creds *out_creds) 68355682Smarkm{ 68455682Smarkm krb5_error_code ret; 68555682Smarkm krb5_creds mcreds; 686178825Sdfr 687178825Sdfr krb5_cc_clear_mcred(&mcreds); 68855682Smarkm mcreds.server = server; 68955682Smarkm ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM, 69055682Smarkm &mcreds, out_creds); 69155682Smarkm if(ret == 0) 69255682Smarkm return 0; 69355682Smarkm while(tgts && *tgts){ 69455682Smarkm if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM, 69555682Smarkm &mcreds, *tgts)){ 69655682Smarkm ret = krb5_copy_creds_contents(context, *tgts, out_creds); 69755682Smarkm return ret; 69855682Smarkm } 69955682Smarkm tgts++; 70055682Smarkm } 701178825Sdfr not_found(context, server); 70255682Smarkm return KRB5_CC_NOTFOUND; 70355682Smarkm} 70455682Smarkm 70555682Smarkmstatic krb5_error_code 70655682Smarkmadd_cred(krb5_context context, krb5_creds ***tgts, krb5_creds *tkt) 70755682Smarkm{ 70855682Smarkm int i; 70955682Smarkm krb5_error_code ret; 71055682Smarkm krb5_creds **tmp = *tgts; 71178527Sassar 71255682Smarkm for(i = 0; tmp && tmp[i]; i++); /* XXX */ 71355682Smarkm tmp = realloc(tmp, (i+2)*sizeof(*tmp)); 71478527Sassar if(tmp == NULL) { 71578527Sassar krb5_set_error_string(context, "malloc: out of memory"); 71655682Smarkm return ENOMEM; 71778527Sassar } 71855682Smarkm *tgts = tmp; 71955682Smarkm ret = krb5_copy_creds(context, tkt, &tmp[i]); 72055682Smarkm tmp[i+1] = NULL; 72155682Smarkm return ret; 72255682Smarkm} 72355682Smarkm 72455682Smarkm/* 72555682Smarkmget_cred(server) 72655682Smarkm creds = cc_get_cred(server) 72755682Smarkm if(creds) return creds 72855682Smarkm tgt = cc_get_cred(krbtgt/server_realm@any_realm) 72955682Smarkm if(tgt) 73055682Smarkm return get_cred_tgt(server, tgt) 73155682Smarkm if(client_realm == server_realm) 73255682Smarkm return NULL 73355682Smarkm tgt = get_cred(krbtgt/server_realm@client_realm) 73455682Smarkm while(tgt_inst != server_realm) 73555682Smarkm tgt = get_cred(krbtgt/server_realm@tgt_inst) 73655682Smarkm return get_cred_tgt(server, tgt) 73755682Smarkm */ 73855682Smarkm 73955682Smarkmstatic krb5_error_code 74055682Smarkmget_cred_from_kdc_flags(krb5_context context, 74155682Smarkm krb5_kdc_flags flags, 74255682Smarkm krb5_ccache ccache, 74355682Smarkm krb5_creds *in_creds, 744178825Sdfr krb5_principal impersonate_principal, 745178825Sdfr Ticket *second_ticket, 74655682Smarkm krb5_creds **out_creds, 74755682Smarkm krb5_creds ***ret_tgts) 74855682Smarkm{ 74955682Smarkm krb5_error_code ret; 75055682Smarkm krb5_creds *tgt, tmp_creds; 75172445Sassar krb5_const_realm client_realm, server_realm, try_realm; 75255682Smarkm 75355682Smarkm *out_creds = NULL; 75455682Smarkm 755178825Sdfr client_realm = krb5_principal_get_realm(context, in_creds->client); 756178825Sdfr server_realm = krb5_principal_get_realm(context, in_creds->server); 75755682Smarkm memset(&tmp_creds, 0, sizeof(tmp_creds)); 75855682Smarkm ret = krb5_copy_principal(context, in_creds->client, &tmp_creds.client); 75955682Smarkm if(ret) 76055682Smarkm return ret; 76172445Sassar 762127808Snectar try_realm = krb5_config_get_string(context, NULL, "capaths", 763127808Snectar client_realm, server_realm, NULL); 764127808Snectar 765127808Snectar#if 1 766127808Snectar /* XXX remove in future release */ 767127808Snectar if(try_realm == NULL) 768127808Snectar try_realm = krb5_config_get_string(context, NULL, "libdefaults", 769127808Snectar "capath", server_realm, NULL); 770127808Snectar#endif 771127808Snectar 77272445Sassar if (try_realm == NULL) 77372445Sassar try_realm = client_realm; 77472445Sassar 77555682Smarkm ret = krb5_make_principal(context, 77655682Smarkm &tmp_creds.server, 77772445Sassar try_realm, 77855682Smarkm KRB5_TGS_NAME, 779127808Snectar server_realm, 78055682Smarkm NULL); 78155682Smarkm if(ret){ 78255682Smarkm krb5_free_principal(context, tmp_creds.client); 78355682Smarkm return ret; 78455682Smarkm } 78555682Smarkm { 78655682Smarkm krb5_creds tgts; 78755682Smarkm /* XXX try krb5_cc_retrieve_cred first? */ 78855682Smarkm ret = find_cred(context, ccache, tmp_creds.server, 78955682Smarkm *ret_tgts, &tgts); 79055682Smarkm if(ret == 0){ 79155682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 79278527Sassar if(*out_creds == NULL) { 79378527Sassar krb5_set_error_string(context, "malloc: out of memory"); 79455682Smarkm ret = ENOMEM; 79578527Sassar } else { 796102644Snectar krb5_boolean noaddr; 797102644Snectar 798102644Snectar krb5_appdefault_boolean(context, NULL, tgts.server->realm, 799102644Snectar "no-addresses", FALSE, &noaddr); 800102644Snectar 801102644Snectar if (noaddr) 802102644Snectar ret = get_cred_kdc(context, ccache, flags, NULL, 803178825Sdfr in_creds, &tgts, 804178825Sdfr impersonate_principal, 805178825Sdfr second_ticket, 806178825Sdfr *out_creds); 807102644Snectar else 808102644Snectar ret = get_cred_kdc_la(context, ccache, flags, 809178825Sdfr in_creds, &tgts, 810178825Sdfr impersonate_principal, 811178825Sdfr second_ticket, 812178825Sdfr *out_creds); 81372445Sassar if (ret) { 81455682Smarkm free (*out_creds); 81572445Sassar *out_creds = NULL; 81672445Sassar } 81755682Smarkm } 818178825Sdfr krb5_free_cred_contents(context, &tgts); 81955682Smarkm krb5_free_principal(context, tmp_creds.server); 82055682Smarkm krb5_free_principal(context, tmp_creds.client); 82155682Smarkm return ret; 82255682Smarkm } 82355682Smarkm } 82478527Sassar if(krb5_realm_compare(context, in_creds->client, in_creds->server)) { 825178825Sdfr not_found(context, in_creds->server); 82655682Smarkm return KRB5_CC_NOTFOUND; 82778527Sassar } 82855682Smarkm /* XXX this can loop forever */ 82955682Smarkm while(1){ 830178825Sdfr heim_general_string tgt_inst; 83172445Sassar 83255682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, &tmp_creds, 833178825Sdfr NULL, NULL, &tgt, ret_tgts); 83455682Smarkm if(ret) { 83555682Smarkm krb5_free_principal(context, tmp_creds.server); 83655682Smarkm krb5_free_principal(context, tmp_creds.client); 83755682Smarkm return ret; 83855682Smarkm } 83955682Smarkm ret = add_cred(context, ret_tgts, tgt); 84055682Smarkm if(ret) { 84155682Smarkm krb5_free_principal(context, tmp_creds.server); 84255682Smarkm krb5_free_principal(context, tmp_creds.client); 84355682Smarkm return ret; 84455682Smarkm } 84555682Smarkm tgt_inst = tgt->server->name.name_string.val[1]; 84655682Smarkm if(strcmp(tgt_inst, server_realm) == 0) 84755682Smarkm break; 84855682Smarkm krb5_free_principal(context, tmp_creds.server); 84955682Smarkm ret = krb5_make_principal(context, &tmp_creds.server, 85055682Smarkm tgt_inst, KRB5_TGS_NAME, server_realm, NULL); 85155682Smarkm if(ret) { 85255682Smarkm krb5_free_principal(context, tmp_creds.server); 85355682Smarkm krb5_free_principal(context, tmp_creds.client); 85455682Smarkm return ret; 85555682Smarkm } 85655682Smarkm ret = krb5_free_creds(context, tgt); 85755682Smarkm if(ret) { 85855682Smarkm krb5_free_principal(context, tmp_creds.server); 85955682Smarkm krb5_free_principal(context, tmp_creds.client); 86055682Smarkm return ret; 86155682Smarkm } 86255682Smarkm } 86355682Smarkm 86455682Smarkm krb5_free_principal(context, tmp_creds.server); 86555682Smarkm krb5_free_principal(context, tmp_creds.client); 86655682Smarkm *out_creds = calloc(1, sizeof(**out_creds)); 86778527Sassar if(*out_creds == NULL) { 86878527Sassar krb5_set_error_string(context, "malloc: out of memory"); 86955682Smarkm ret = ENOMEM; 87078527Sassar } else { 871102644Snectar krb5_boolean noaddr; 872102644Snectar 873102644Snectar krb5_appdefault_boolean(context, NULL, tgt->server->realm, 874178825Sdfr "no-addresses", KRB5_ADDRESSLESS_DEFAULT, 875178825Sdfr &noaddr); 876102644Snectar if (noaddr) 877102644Snectar ret = get_cred_kdc (context, ccache, flags, NULL, 878178825Sdfr in_creds, tgt, NULL, NULL, 879178825Sdfr *out_creds); 880102644Snectar else 881102644Snectar ret = get_cred_kdc_la(context, ccache, flags, 882178825Sdfr in_creds, tgt, NULL, NULL, 883178825Sdfr *out_creds); 88472445Sassar if (ret) { 88555682Smarkm free (*out_creds); 88672445Sassar *out_creds = NULL; 88772445Sassar } 88855682Smarkm } 88955682Smarkm krb5_free_creds(context, tgt); 89055682Smarkm return ret; 89155682Smarkm} 89255682Smarkm 893178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 89478527Sassarkrb5_get_cred_from_kdc_opt(krb5_context context, 89578527Sassar krb5_ccache ccache, 89678527Sassar krb5_creds *in_creds, 89778527Sassar krb5_creds **out_creds, 89878527Sassar krb5_creds ***ret_tgts, 89978527Sassar krb5_flags flags) 90078527Sassar{ 90178527Sassar krb5_kdc_flags f; 90278527Sassar f.i = flags; 90378527Sassar return get_cred_from_kdc_flags(context, f, ccache, 904178825Sdfr in_creds, NULL, NULL, 905178825Sdfr out_creds, ret_tgts); 90678527Sassar} 90778527Sassar 908178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 90955682Smarkmkrb5_get_cred_from_kdc(krb5_context context, 91055682Smarkm krb5_ccache ccache, 91155682Smarkm krb5_creds *in_creds, 91255682Smarkm krb5_creds **out_creds, 91355682Smarkm krb5_creds ***ret_tgts) 91455682Smarkm{ 91578527Sassar return krb5_get_cred_from_kdc_opt(context, ccache, 91678527Sassar in_creds, out_creds, ret_tgts, 0); 91755682Smarkm} 91855682Smarkm 91955682Smarkm 920178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 92155682Smarkmkrb5_get_credentials_with_flags(krb5_context context, 92255682Smarkm krb5_flags options, 92355682Smarkm krb5_kdc_flags flags, 92455682Smarkm krb5_ccache ccache, 92555682Smarkm krb5_creds *in_creds, 92655682Smarkm krb5_creds **out_creds) 92755682Smarkm{ 92855682Smarkm krb5_error_code ret; 92955682Smarkm krb5_creds **tgts; 93072445Sassar krb5_creds *res_creds; 93155682Smarkm int i; 93255682Smarkm 93372445Sassar *out_creds = NULL; 93472445Sassar res_creds = calloc(1, sizeof(*res_creds)); 93578527Sassar if (res_creds == NULL) { 93678527Sassar krb5_set_error_string(context, "malloc: out of memory"); 93755682Smarkm return ENOMEM; 93878527Sassar } 93955682Smarkm 940178825Sdfr if (in_creds->session.keytype) 941178825Sdfr options |= KRB5_TC_MATCH_KEYTYPE; 942178825Sdfr 943178825Sdfr /* 944178825Sdfr * If we got a credential, check if credential is expired before 945178825Sdfr * returning it. 946178825Sdfr */ 94755682Smarkm ret = krb5_cc_retrieve_cred(context, 948178825Sdfr ccache, 949178825Sdfr in_creds->session.keytype ? 950178825Sdfr KRB5_TC_MATCH_KEYTYPE : 0, 951178825Sdfr in_creds, res_creds); 952178825Sdfr /* 953178825Sdfr * If we got a credential, check if credential is expired before 954178825Sdfr * returning it, but only if KRB5_GC_EXPIRED_OK is not set. 955178825Sdfr */ 956178825Sdfr if (ret == 0) { 957178825Sdfr krb5_timestamp timeret; 958178825Sdfr 959178825Sdfr /* If expired ok, don't bother checking */ 960178825Sdfr if(options & KRB5_GC_EXPIRED_OK) { 961178825Sdfr *out_creds = res_creds; 962178825Sdfr return 0; 963178825Sdfr } 964178825Sdfr 965178825Sdfr krb5_timeofday(context, &timeret); 966178825Sdfr if(res_creds->times.endtime > timeret) { 967178825Sdfr *out_creds = res_creds; 968178825Sdfr return 0; 969178825Sdfr } 970178825Sdfr if(options & KRB5_GC_CACHED) 971178825Sdfr krb5_cc_remove_cred(context, ccache, 0, res_creds); 972178825Sdfr 973178825Sdfr } else if(ret != KRB5_CC_END) { 974178825Sdfr free(res_creds); 975178825Sdfr return ret; 97672445Sassar } 97772445Sassar free(res_creds); 97878527Sassar if(options & KRB5_GC_CACHED) { 979178825Sdfr not_found(context, in_creds->server); 980178825Sdfr return KRB5_CC_NOTFOUND; 98178527Sassar } 98255682Smarkm if(options & KRB5_GC_USER_USER) 98355682Smarkm flags.b.enc_tkt_in_skey = 1; 984178825Sdfr if (flags.b.enc_tkt_in_skey) 985178825Sdfr options |= KRB5_GC_NO_STORE; 986178825Sdfr 98755682Smarkm tgts = NULL; 98855682Smarkm ret = get_cred_from_kdc_flags(context, flags, ccache, 989178825Sdfr in_creds, NULL, NULL, out_creds, &tgts); 99072445Sassar for(i = 0; tgts && tgts[i]; i++) { 99155682Smarkm krb5_cc_store_cred(context, ccache, tgts[i]); 99255682Smarkm krb5_free_creds(context, tgts[i]); 99355682Smarkm } 99455682Smarkm free(tgts); 995178825Sdfr if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 99655682Smarkm krb5_cc_store_cred(context, ccache, *out_creds); 99755682Smarkm return ret; 99855682Smarkm} 99955682Smarkm 1000178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 100155682Smarkmkrb5_get_credentials(krb5_context context, 100255682Smarkm krb5_flags options, 100355682Smarkm krb5_ccache ccache, 100455682Smarkm krb5_creds *in_creds, 100555682Smarkm krb5_creds **out_creds) 100655682Smarkm{ 100755682Smarkm krb5_kdc_flags flags; 100855682Smarkm flags.i = 0; 100955682Smarkm return krb5_get_credentials_with_flags(context, options, flags, 101055682Smarkm ccache, in_creds, out_creds); 101155682Smarkm} 1012178825Sdfr 1013178825Sdfrstruct krb5_get_creds_opt_data { 1014178825Sdfr krb5_principal self; 1015178825Sdfr krb5_flags options; 1016178825Sdfr krb5_enctype enctype; 1017178825Sdfr Ticket *ticket; 1018178825Sdfr}; 1019178825Sdfr 1020178825Sdfr 1021178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1022178825Sdfrkrb5_get_creds_opt_alloc(krb5_context context, krb5_get_creds_opt *opt) 1023178825Sdfr{ 1024178825Sdfr *opt = calloc(1, sizeof(**opt)); 1025178825Sdfr if (*opt == NULL) { 1026178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1027178825Sdfr return ENOMEM; 1028178825Sdfr } 1029178825Sdfr return 0; 1030178825Sdfr} 1031178825Sdfr 1032178825Sdfrvoid KRB5_LIB_FUNCTION 1033178825Sdfrkrb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) 1034178825Sdfr{ 1035178825Sdfr if (opt->self) 1036178825Sdfr krb5_free_principal(context, opt->self); 1037178825Sdfr memset(opt, 0, sizeof(*opt)); 1038178825Sdfr free(opt); 1039178825Sdfr} 1040178825Sdfr 1041178825Sdfrvoid KRB5_LIB_FUNCTION 1042178825Sdfrkrb5_get_creds_opt_set_options(krb5_context context, 1043178825Sdfr krb5_get_creds_opt opt, 1044178825Sdfr krb5_flags options) 1045178825Sdfr{ 1046178825Sdfr opt->options = options; 1047178825Sdfr} 1048178825Sdfr 1049178825Sdfrvoid KRB5_LIB_FUNCTION 1050178825Sdfrkrb5_get_creds_opt_add_options(krb5_context context, 1051178825Sdfr krb5_get_creds_opt opt, 1052178825Sdfr krb5_flags options) 1053178825Sdfr{ 1054178825Sdfr opt->options |= options; 1055178825Sdfr} 1056178825Sdfr 1057178825Sdfrvoid KRB5_LIB_FUNCTION 1058178825Sdfrkrb5_get_creds_opt_set_enctype(krb5_context context, 1059178825Sdfr krb5_get_creds_opt opt, 1060178825Sdfr krb5_enctype enctype) 1061178825Sdfr{ 1062178825Sdfr opt->enctype = enctype; 1063178825Sdfr} 1064178825Sdfr 1065178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1066178825Sdfrkrb5_get_creds_opt_set_impersonate(krb5_context context, 1067178825Sdfr krb5_get_creds_opt opt, 1068178825Sdfr krb5_const_principal self) 1069178825Sdfr{ 1070178825Sdfr if (opt->self) 1071178825Sdfr krb5_free_principal(context, opt->self); 1072178825Sdfr return krb5_copy_principal(context, self, &opt->self); 1073178825Sdfr} 1074178825Sdfr 1075178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1076178825Sdfrkrb5_get_creds_opt_set_ticket(krb5_context context, 1077178825Sdfr krb5_get_creds_opt opt, 1078178825Sdfr const Ticket *ticket) 1079178825Sdfr{ 1080178825Sdfr if (opt->ticket) { 1081178825Sdfr free_Ticket(opt->ticket); 1082178825Sdfr free(opt->ticket); 1083178825Sdfr opt->ticket = NULL; 1084178825Sdfr } 1085178825Sdfr if (ticket) { 1086178825Sdfr krb5_error_code ret; 1087178825Sdfr 1088178825Sdfr opt->ticket = malloc(sizeof(*ticket)); 1089178825Sdfr if (opt->ticket == NULL) { 1090178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1091178825Sdfr return ENOMEM; 1092178825Sdfr } 1093178825Sdfr ret = copy_Ticket(ticket, opt->ticket); 1094178825Sdfr if (ret) { 1095178825Sdfr free(opt->ticket); 1096178825Sdfr opt->ticket = NULL; 1097178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1098178825Sdfr return ret; 1099178825Sdfr } 1100178825Sdfr } 1101178825Sdfr return 0; 1102178825Sdfr} 1103178825Sdfr 1104178825Sdfr 1105178825Sdfr 1106178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1107178825Sdfrkrb5_get_creds(krb5_context context, 1108178825Sdfr krb5_get_creds_opt opt, 1109178825Sdfr krb5_ccache ccache, 1110178825Sdfr krb5_const_principal inprinc, 1111178825Sdfr krb5_creds **out_creds) 1112178825Sdfr{ 1113178825Sdfr krb5_kdc_flags flags; 1114178825Sdfr krb5_flags options; 1115178825Sdfr krb5_creds in_creds; 1116178825Sdfr krb5_error_code ret; 1117178825Sdfr krb5_creds **tgts; 1118178825Sdfr krb5_creds *res_creds; 1119178825Sdfr int i; 1120178825Sdfr 1121178825Sdfr memset(&in_creds, 0, sizeof(in_creds)); 1122178825Sdfr in_creds.server = rk_UNCONST(inprinc); 1123178825Sdfr 1124178825Sdfr ret = krb5_cc_get_principal(context, ccache, &in_creds.client); 1125178825Sdfr if (ret) 1126178825Sdfr return ret; 1127178825Sdfr 1128178825Sdfr options = opt->options; 1129178825Sdfr flags.i = 0; 1130178825Sdfr 1131178825Sdfr *out_creds = NULL; 1132178825Sdfr res_creds = calloc(1, sizeof(*res_creds)); 1133178825Sdfr if (res_creds == NULL) { 1134178825Sdfr krb5_free_principal(context, in_creds.client); 1135178825Sdfr krb5_set_error_string(context, "malloc: out of memory"); 1136178825Sdfr return ENOMEM; 1137178825Sdfr } 1138178825Sdfr 1139178825Sdfr if (opt->enctype) { 1140178825Sdfr in_creds.session.keytype = opt->enctype; 1141178825Sdfr options |= KRB5_TC_MATCH_KEYTYPE; 1142178825Sdfr } 1143178825Sdfr 1144178825Sdfr /* 1145178825Sdfr * If we got a credential, check if credential is expired before 1146178825Sdfr * returning it. 1147178825Sdfr */ 1148178825Sdfr ret = krb5_cc_retrieve_cred(context, 1149178825Sdfr ccache, 1150178825Sdfr opt->enctype ? KRB5_TC_MATCH_KEYTYPE : 0, 1151178825Sdfr &in_creds, res_creds); 1152178825Sdfr /* 1153178825Sdfr * If we got a credential, check if credential is expired before 1154178825Sdfr * returning it, but only if KRB5_GC_EXPIRED_OK is not set. 1155178825Sdfr */ 1156178825Sdfr if (ret == 0) { 1157178825Sdfr krb5_timestamp timeret; 1158178825Sdfr 1159178825Sdfr /* If expired ok, don't bother checking */ 1160178825Sdfr if(options & KRB5_GC_EXPIRED_OK) { 1161178825Sdfr *out_creds = res_creds; 1162178825Sdfr krb5_free_principal(context, in_creds.client); 1163178825Sdfr return 0; 1164178825Sdfr } 1165178825Sdfr 1166178825Sdfr krb5_timeofday(context, &timeret); 1167178825Sdfr if(res_creds->times.endtime > timeret) { 1168178825Sdfr *out_creds = res_creds; 1169178825Sdfr krb5_free_principal(context, in_creds.client); 1170178825Sdfr return 0; 1171178825Sdfr } 1172178825Sdfr if(options & KRB5_GC_CACHED) 1173178825Sdfr krb5_cc_remove_cred(context, ccache, 0, res_creds); 1174178825Sdfr 1175178825Sdfr } else if(ret != KRB5_CC_END) { 1176178825Sdfr free(res_creds); 1177178825Sdfr krb5_free_principal(context, in_creds.client); 1178178825Sdfr return ret; 1179178825Sdfr } 1180178825Sdfr free(res_creds); 1181178825Sdfr if(options & KRB5_GC_CACHED) { 1182178825Sdfr not_found(context, in_creds.server); 1183178825Sdfr krb5_free_principal(context, in_creds.client); 1184178825Sdfr return KRB5_CC_NOTFOUND; 1185178825Sdfr } 1186178825Sdfr if(options & KRB5_GC_USER_USER) { 1187178825Sdfr flags.b.enc_tkt_in_skey = 1; 1188178825Sdfr options |= KRB5_GC_NO_STORE; 1189178825Sdfr } 1190178825Sdfr if (options & KRB5_GC_FORWARDABLE) 1191178825Sdfr flags.b.forwardable = 1; 1192178825Sdfr if (options & KRB5_GC_NO_TRANSIT_CHECK) 1193178825Sdfr flags.b.disable_transited_check = 1; 1194178825Sdfr if (options & KRB5_GC_CONSTRAINED_DELEGATION) { 1195178825Sdfr flags.b.request_anonymous = 1; /* XXX ARGH confusion */ 1196178825Sdfr flags.b.constrained_delegation = 1; 1197178825Sdfr } 1198178825Sdfr 1199178825Sdfr tgts = NULL; 1200178825Sdfr ret = get_cred_from_kdc_flags(context, flags, ccache, 1201178825Sdfr &in_creds, opt->self, opt->ticket, 1202178825Sdfr out_creds, &tgts); 1203178825Sdfr krb5_free_principal(context, in_creds.client); 1204178825Sdfr for(i = 0; tgts && tgts[i]; i++) { 1205178825Sdfr krb5_cc_store_cred(context, ccache, tgts[i]); 1206178825Sdfr krb5_free_creds(context, tgts[i]); 1207178825Sdfr } 1208178825Sdfr free(tgts); 1209178825Sdfr if(ret == 0 && (options & KRB5_GC_NO_STORE) == 0) 1210178825Sdfr krb5_cc_store_cred(context, ccache, *out_creds); 1211178825Sdfr return ret; 1212178825Sdfr} 1213178825Sdfr 1214178825Sdfr/* 1215178825Sdfr * 1216178825Sdfr */ 1217178825Sdfr 1218178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 1219178825Sdfrkrb5_get_renewed_creds(krb5_context context, 1220178825Sdfr krb5_creds *creds, 1221178825Sdfr krb5_const_principal client, 1222178825Sdfr krb5_ccache ccache, 1223178825Sdfr const char *in_tkt_service) 1224178825Sdfr{ 1225178825Sdfr krb5_error_code ret; 1226178825Sdfr krb5_kdc_flags flags; 1227178825Sdfr krb5_creds in, *template, *out = NULL; 1228178825Sdfr 1229178825Sdfr memset(&in, 0, sizeof(in)); 1230178825Sdfr memset(creds, 0, sizeof(*creds)); 1231178825Sdfr 1232178825Sdfr ret = krb5_copy_principal(context, client, &in.client); 1233178825Sdfr if (ret) 1234178825Sdfr return ret; 1235178825Sdfr 1236178825Sdfr if (in_tkt_service) { 1237178825Sdfr ret = krb5_parse_name(context, in_tkt_service, &in.server); 1238178825Sdfr if (ret) { 1239178825Sdfr krb5_free_principal(context, in.client); 1240178825Sdfr return ret; 1241178825Sdfr } 1242178825Sdfr } else { 1243178825Sdfr const char *realm = krb5_principal_get_realm(context, client); 1244178825Sdfr 1245178825Sdfr ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, 1246178825Sdfr realm, NULL); 1247178825Sdfr if (ret) { 1248178825Sdfr krb5_free_principal(context, in.client); 1249178825Sdfr return ret; 1250178825Sdfr } 1251178825Sdfr } 1252178825Sdfr 1253178825Sdfr flags.i = 0; 1254178825Sdfr flags.b.renewable = flags.b.renew = 1; 1255178825Sdfr 1256178825Sdfr /* 1257178825Sdfr * Get template from old credential cache for the same entry, if 1258178825Sdfr * this failes, no worries. 1259178825Sdfr */ 1260178825Sdfr ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); 1261178825Sdfr if (ret == 0) { 1262178825Sdfr flags.b.forwardable = template->flags.b.forwardable; 1263178825Sdfr flags.b.proxiable = template->flags.b.proxiable; 1264178825Sdfr krb5_free_creds (context, template); 1265178825Sdfr } 1266178825Sdfr 1267178825Sdfr ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &out); 1268178825Sdfr krb5_free_principal(context, in.client); 1269178825Sdfr krb5_free_principal(context, in.server); 1270178825Sdfr if (ret) 1271178825Sdfr return ret; 1272178825Sdfr 1273178825Sdfr ret = krb5_copy_creds_contents(context, out, creds); 1274178825Sdfr krb5_free_creds(context, out); 1275178825Sdfr 1276178825Sdfr return ret; 1277178825Sdfr} 1278