get_for_creds.c revision 127808
1139749Simp/* 2122526Ssimokawa * Copyright (c) 1997 - 2002 Kungliga Tekniska H�gskolan 3122526Ssimokawa * (Royal Institute of Technology, Stockholm, Sweden). 4103285Sikob * All rights reserved. 5103285Sikob * 6103285Sikob * Redistribution and use in source and binary forms, with or without 7103285Sikob * modification, are permitted provided that the following conditions 8103285Sikob * are met: 9103285Sikob * 10103285Sikob * 1. Redistributions of source code must retain the above copyright 11103285Sikob * notice, this list of conditions and the following disclaimer. 12103285Sikob * 13103285Sikob * 2. Redistributions in binary form must reproduce the above copyright 14103285Sikob * notice, this list of conditions and the following disclaimer in the 15103285Sikob * documentation and/or other materials provided with the distribution. 16103285Sikob * 17103285Sikob * 3. Neither the name of the Institute nor the names of its contributors 18103285Sikob * may be used to endorse or promote products derived from this software 19103285Sikob * without specific prior written permission. 20103285Sikob * 21103285Sikob * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24103285Sikob * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31103285Sikob * SUCH DAMAGE. 32103285Sikob */ 33103285Sikob 34103285Sikob#include <krb5_locl.h> 35103285Sikob 36103285SikobRCSID("$Id: get_for_creds.c,v 1.34.4.1 2004/01/09 00:51:55 lha Exp $"); 37103285Sikob 38103285Sikobstatic krb5_error_code 39103285Sikobadd_addrs(krb5_context context, 40103285Sikob krb5_addresses *addr, 41103285Sikob struct addrinfo *ai) 42127468Ssimokawa{ 43103285Sikob krb5_error_code ret; 44103285Sikob unsigned n, i; 45103285Sikob void *tmp; 46127468Ssimokawa struct addrinfo *a; 47117126Sscottl 48117126Sscottl n = 0; 49117732Ssimokawa for (a = ai; a != NULL; a = a->ai_next) 50103285Sikob ++n; 51127468Ssimokawa 52112136Ssimokawa tmp = realloc(addr->val, (addr->len + n) * sizeof(*addr->val)); 53112136Ssimokawa if (tmp == NULL) { 54103285Sikob krb5_set_error_string(context, "malloc: out of memory"); 55127468Ssimokawa ret = ENOMEM; 56127468Ssimokawa goto fail; 57127468Ssimokawa } 58127468Ssimokawa addr->val = tmp; 59127468Ssimokawa for (i = addr->len; i < (addr->len + n); ++i) { 60127468Ssimokawa addr->val[i].addr_type = 0; 61127468Ssimokawa krb5_data_zero(&addr->val[i].address); 62127468Ssimokawa } 63127468Ssimokawa i = addr->len; 64127468Ssimokawa for (a = ai; a != NULL; a = a->ai_next) { 65127468Ssimokawa krb5_address ad; 66127468Ssimokawa 67127468Ssimokawa ret = krb5_sockaddr2address (context, a->ai_addr, &ad); 68127468Ssimokawa if (ret == 0) { 69127468Ssimokawa if (krb5_address_search(context, &ad, addr)) 70103285Sikob krb5_free_address(context, &ad); 71103285Sikob else 72103285Sikob addr->val[i++] = ad; 73103285Sikob } 74103285Sikob else if (ret == KRB5_PROG_ATYPE_NOSUPP) 75103285Sikob krb5_clear_error_string (context); 76103285Sikob else 77103285Sikob goto fail; 78103285Sikob addr->len = i; 79103285Sikob } 80113584Ssimokawa return 0; 81103285Sikobfail: 82120660Ssimokawa krb5_free_addresses (context, addr); 83127468Ssimokawa return ret; 84103285Sikob} 85103285Sikob 86103285Sikob/* 87103285Sikob * Forward credentials for `client' to host `hostname`, 88111615Ssimokawa * making them forwardable if `forwardable', and returning the 89121185Ssimokawa * blob of data to sent in `out_data'. 90121185Ssimokawa * If hostname == NULL, pick it from `server' 91121185Ssimokawa */ 92121185Ssimokawa 93121185Ssimokawakrb5_error_code 94167622Ssimokawakrb5_fwd_tgt_creds (krb5_context context, 95113584Ssimokawa krb5_auth_context auth_context, 96113584Ssimokawa const char *hostname, 97113584Ssimokawa krb5_principal client, 98103285Sikob krb5_principal server, 99113584Ssimokawa krb5_ccache ccache, 100111615Ssimokawa int forwardable, 101111615Ssimokawa krb5_data *out_data) 102111615Ssimokawa{ 103111615Ssimokawa krb5_flags flags = 0; 104130532Sdfr krb5_creds creds; 105111615Ssimokawa krb5_error_code ret; 106111615Ssimokawa krb5_const_realm client_realm; 107120660Ssimokawa 108111615Ssimokawa flags |= KDC_OPT_FORWARDED; 109111615Ssimokawa 110111615Ssimokawa if (forwardable) 111103285Sikob flags |= KDC_OPT_FORWARDABLE; 112120660Ssimokawa 113120660Ssimokawa if (hostname == NULL && 114120660Ssimokawa krb5_principal_get_type(context, server) == KRB5_NT_SRV_HST) { 115120660Ssimokawa const char *inst = krb5_principal_get_comp_string(context, server, 0); 116103285Sikob const char *host = krb5_principal_get_comp_string(context, server, 1); 117103285Sikob 118120660Ssimokawa if (inst != NULL && 119103285Sikob strcmp(inst, "host") == 0 && 120103285Sikob host != NULL && 121120660Ssimokawa krb5_principal_get_comp_string(context, server, 2) == NULL) 122103285Sikob hostname = host; 123103285Sikob } 124111203Ssimokawa 125103285Sikob client_realm = krb5_principal_get_realm(context, client); 126124251Ssimokawa 127111199Ssimokawa memset (&creds, 0, sizeof(creds)); 128122387Ssimokawa creds.client = client; 129122387Ssimokawa 130122387Ssimokawa ret = krb5_build_principal(context, 131127468Ssimokawa &creds.server, 132127468Ssimokawa strlen(client_realm), 133103285Sikob client_realm, 134103285Sikob KRB5_TGS_NAME, 135103285Sikob client_realm, 136103285Sikob NULL); 137103285Sikob if (ret) 138103285Sikob return ret; 139103285Sikob 140103285Sikob ret = krb5_get_forwarded_creds (context, 141103285Sikob auth_context, 142121792Ssimokawa ccache, 143130677Ssimokawa flags, 144122387Ssimokawa hostname, 145122387Ssimokawa &creds, 146122387Ssimokawa out_data); 147122387Ssimokawa return ret; 148127468Ssimokawa} 149127468Ssimokawa 150127468Ssimokawa/* 151127468Ssimokawa * 152103285Sikob */ 153122387Ssimokawa 154122387Ssimokawakrb5_error_code 155122387Ssimokawakrb5_get_forwarded_creds (krb5_context context, 156122387Ssimokawa krb5_auth_context auth_context, 157122387Ssimokawa krb5_ccache ccache, 158127468Ssimokawa krb5_flags flags, 159127468Ssimokawa const char *hostname, 160122387Ssimokawa krb5_creds *in_creds, 161103285Sikob krb5_data *out_data) 162103285Sikob{ 163113584Ssimokawa krb5_error_code ret; 164113584Ssimokawa krb5_creds *out_creds; 165167622Ssimokawa krb5_addresses addrs, *paddrs; 166113584Ssimokawa KRB_CRED cred; 167167622Ssimokawa KrbCredInfo *krb_cred_info; 168113584Ssimokawa EncKrbCredPart enc_krb_cred_part; 169103285Sikob size_t len; 170103285Sikob unsigned char *buf; 171103285Sikob size_t buf_size; 172113584Ssimokawa krb5_kdc_flags kdc_flags; 173129585Sdfr krb5_crypto crypto; 174129585Sdfr struct addrinfo *ai; 175120660Ssimokawa int save_errno; 176103285Sikob krb5_keyblock *key; 177113584Ssimokawa krb5_creds *ticket; 178103285Sikob char *realm; 179103285Sikob 180113584Ssimokawa if (in_creds->client && in_creds->client->realm) 181103285Sikob realm = in_creds->client->realm; 182103285Sikob else 183113584Ssimokawa realm = in_creds->server->realm; 184103285Sikob 185103285Sikob addrs.len = 0; 186103285Sikob addrs.val = NULL; 187114732Ssimokawa paddrs = &addrs; 188110336Ssimokawa 189103285Sikob /* 190110336Ssimokawa * If tickets are address-less, forward address-less tickets. 191103285Sikob */ 192103285Sikob 193103285Sikob ret = _krb5_get_krbtgt (context, 194103285Sikob ccache, 195103285Sikob realm, 196129585Sdfr &ticket); 197114732Ssimokawa if(ret == 0) { 198129585Sdfr if (ticket->addresses.len == 0) 199129585Sdfr paddrs = NULL; 200129585Sdfr krb5_free_creds (context, ticket); 201121185Ssimokawa } 202121185Ssimokawa 203121185Ssimokawa if (paddrs != NULL) { 204121185Ssimokawa 205127468Ssimokawa ret = getaddrinfo (hostname, NULL, NULL, &ai); 206127468Ssimokawa if (ret) { 207127468Ssimokawa save_errno = errno; 208129585Sdfr krb5_set_error_string(context, "resolving %s: %s", 209103285Sikob hostname, gai_strerror(ret)); 210103285Sikob return krb5_eai_to_heim_errno(ret, save_errno); 211113584Ssimokawa } 212113584Ssimokawa 213111615Ssimokawa ret = add_addrs (context, &addrs, ai); 214113584Ssimokawa freeaddrinfo (ai); 215103285Sikob if (ret) 216113584Ssimokawa return ret; 217127468Ssimokawa } 218103285Sikob 219103285Sikob kdc_flags.i = flags; 220103285Sikob 221103285Sikob ret = krb5_get_kdc_cred (context, 222103285Sikob ccache, 223103285Sikob kdc_flags, 224103285Sikob paddrs, 225103285Sikob NULL, 226121185Ssimokawa in_creds, 227103285Sikob &out_creds); 228103285Sikob krb5_free_addresses (context, &addrs); 229129585Sdfr if (ret) { 230111615Ssimokawa return ret; 231111615Ssimokawa } 232111615Ssimokawa 233111615Ssimokawa memset (&cred, 0, sizeof(cred)); 234113584Ssimokawa cred.pvno = 5; 235113584Ssimokawa cred.msg_type = krb_cred; 236103285Sikob ALLOC_SEQ(&cred.tickets, 1); 237103285Sikob if (cred.tickets.val == NULL) { 238103285Sikob ret = ENOMEM; 239103285Sikob krb5_set_error_string(context, "malloc: out of memory"); 240103285Sikob goto out2; 241111615Ssimokawa } 242103285Sikob ret = decode_Ticket(out_creds->ticket.data, 243103285Sikob out_creds->ticket.length, 244103285Sikob cred.tickets.val, &len); 245122387Ssimokawa if (ret) 246124145Ssimokawa goto out3; 247124145Ssimokawa 248103285Sikob memset (&enc_krb_cred_part, 0, sizeof(enc_krb_cred_part)); 249122387Ssimokawa ALLOC_SEQ(&enc_krb_cred_part.ticket_info, 1); 250124169Ssimokawa if (enc_krb_cred_part.ticket_info.val == NULL) { 251124169Ssimokawa ret = ENOMEM; 252124169Ssimokawa krb5_set_error_string(context, "malloc: out of memory"); 253121185Ssimokawa goto out4; 254124169Ssimokawa } 255121185Ssimokawa 256124169Ssimokawa if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { 257127468Ssimokawa int32_t sec, usec; 258124169Ssimokawa 259124169Ssimokawa krb5_us_timeofday (context, &sec, &usec); 260124169Ssimokawa 261124169Ssimokawa ALLOC(enc_krb_cred_part.timestamp, 1); 262124169Ssimokawa if (enc_krb_cred_part.timestamp == NULL) { 263124169Ssimokawa ret = ENOMEM; 264124169Ssimokawa krb5_set_error_string(context, "malloc: out of memory"); 265124169Ssimokawa goto out4; 266121185Ssimokawa } 267121185Ssimokawa *enc_krb_cred_part.timestamp = sec; 268124169Ssimokawa ALLOC(enc_krb_cred_part.usec, 1); 269124169Ssimokawa if (enc_krb_cred_part.usec == NULL) { 270124169Ssimokawa ret = ENOMEM; 271124169Ssimokawa krb5_set_error_string(context, "malloc: out of memory"); 272124169Ssimokawa goto out4; 273103285Sikob } 274108281Ssimokawa *enc_krb_cred_part.usec = usec; 275103285Sikob } else { 276103285Sikob enc_krb_cred_part.timestamp = NULL; 277103285Sikob enc_krb_cred_part.usec = NULL; 278103285Sikob } 279111615Ssimokawa 280111615Ssimokawa if (auth_context->local_address && auth_context->local_port) { 281103285Sikob krb5_boolean noaddr; 282103285Sikob krb5_const_realm realm; 283103285Sikob 284103285Sikob realm = krb5_principal_get_realm(context, out_creds->server); 285103285Sikob krb5_appdefault_boolean(context, NULL, realm, "no-addresses", FALSE, 286103285Sikob &noaddr); 287103285Sikob if (!noaddr) { 288103285Sikob ret = krb5_make_addrport (context, 289103285Sikob &enc_krb_cred_part.s_address, 290103285Sikob auth_context->local_address, 291103285Sikob auth_context->local_port); 292103285Sikob if (ret) 293103285Sikob goto out4; 294103285Sikob } 295103285Sikob } 296103285Sikob 297103285Sikob if (auth_context->remote_address) { 298103285Sikob if (auth_context->remote_port) { 299103285Sikob krb5_boolean noaddr; 300103285Sikob krb5_const_realm realm; 301103285Sikob 302103285Sikob realm = krb5_principal_get_realm(context, out_creds->server); 303103285Sikob krb5_appdefault_boolean(context, NULL, realm, "no-addresses", 304103285Sikob FALSE, &noaddr); 305103285Sikob if (!noaddr) { 306103285Sikob ret = krb5_make_addrport (context, 307103285Sikob &enc_krb_cred_part.r_address, 308103285Sikob auth_context->remote_address, 309103285Sikob auth_context->remote_port); 310103285Sikob if (ret) 311103285Sikob goto out4; 312103285Sikob } 313103285Sikob } else { 314103285Sikob ALLOC(enc_krb_cred_part.r_address, 1); 315103285Sikob if (enc_krb_cred_part.r_address == NULL) { 316103285Sikob ret = ENOMEM; 317103285Sikob krb5_set_error_string(context, "malloc: out of memory"); 318103285Sikob goto out4; 319103285Sikob } 320103285Sikob 321103285Sikob ret = krb5_copy_address (context, auth_context->remote_address, 322103285Sikob enc_krb_cred_part.r_address); 323103285Sikob if (ret) 324103285Sikob goto out4; 325103285Sikob } 326103285Sikob } 327103285Sikob 328103285Sikob /* fill ticket_info.val[0] */ 329103285Sikob 330103285Sikob enc_krb_cred_part.ticket_info.len = 1; 331103285Sikob 332103285Sikob krb_cred_info = enc_krb_cred_part.ticket_info.val; 333103285Sikob 334103285Sikob copy_EncryptionKey (&out_creds->session, &krb_cred_info->key); 335103285Sikob ALLOC(krb_cred_info->prealm, 1); 336103285Sikob copy_Realm (&out_creds->client->realm, krb_cred_info->prealm); 337103285Sikob ALLOC(krb_cred_info->pname, 1); 338103285Sikob copy_PrincipalName(&out_creds->client->name, krb_cred_info->pname); 339103285Sikob ALLOC(krb_cred_info->flags, 1); 340103285Sikob *krb_cred_info->flags = out_creds->flags.b; 341103285Sikob ALLOC(krb_cred_info->authtime, 1); 342103285Sikob *krb_cred_info->authtime = out_creds->times.authtime; 343103285Sikob ALLOC(krb_cred_info->starttime, 1); 344103285Sikob *krb_cred_info->starttime = out_creds->times.starttime; 345103285Sikob ALLOC(krb_cred_info->endtime, 1); 346103285Sikob *krb_cred_info->endtime = out_creds->times.endtime; 347103285Sikob ALLOC(krb_cred_info->renew_till, 1); 348103285Sikob *krb_cred_info->renew_till = out_creds->times.renew_till; 349103285Sikob ALLOC(krb_cred_info->srealm, 1); 350103285Sikob copy_Realm (&out_creds->server->realm, krb_cred_info->srealm); 351103285Sikob ALLOC(krb_cred_info->sname, 1); 352103285Sikob copy_PrincipalName (&out_creds->server->name, krb_cred_info->sname); 353103285Sikob ALLOC(krb_cred_info->caddr, 1); 354120660Ssimokawa copy_HostAddresses (&out_creds->addresses, krb_cred_info->caddr); 355111615Ssimokawa 356132432Ssimokawa krb5_free_creds (context, out_creds); 357111615Ssimokawa 358111615Ssimokawa /* encode EncKrbCredPart */ 359132432Ssimokawa 360132432Ssimokawa ASN1_MALLOC_ENCODE(EncKrbCredPart, buf, buf_size, 361103285Sikob &enc_krb_cred_part, &len, ret); 362103285Sikob free_EncKrbCredPart (&enc_krb_cred_part); 363103285Sikob if (ret) { 364103285Sikob free_KRB_CRED(&cred); 365103285Sikob return ret; 366103285Sikob } 367103285Sikob if(buf_size != len) 368103285Sikob krb5_abortx(context, "internal error in ASN.1 encoder"); 369103285Sikob 370103285Sikob if (auth_context->local_subkey) 371103285Sikob key = auth_context->local_subkey; 372103285Sikob else if (auth_context->remote_subkey) 373103285Sikob key = auth_context->remote_subkey; 374103285Sikob else 375103285Sikob key = auth_context->keyblock; 376103285Sikob 377103285Sikob ret = krb5_crypto_init(context, key, 0, &crypto); 378103285Sikob if (ret) { 379103285Sikob free(buf); 380108503Ssimokawa free_KRB_CRED(&cred); 381108503Ssimokawa return ret; 382103285Sikob } 383103285Sikob ret = krb5_encrypt_EncryptedData (context, 384103285Sikob crypto, 385103285Sikob KRB5_KU_KRB_CRED, 386103285Sikob buf, 387103285Sikob len, 388103285Sikob 0, 389103285Sikob &cred.enc_part); 390103285Sikob free(buf); 391103285Sikob krb5_crypto_destroy(context, crypto); 392103285Sikob if (ret) { 393103285Sikob free_KRB_CRED(&cred); 394103285Sikob return ret; 395103285Sikob } 396110184Ssimokawa 397110184Ssimokawa ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &cred, &len, ret); 398110184Ssimokawa free_KRB_CRED (&cred); 399110184Ssimokawa if (ret) 400110184Ssimokawa return ret; 401110184Ssimokawa if(buf_size != len) 402110184Ssimokawa krb5_abortx(context, "internal error in ASN.1 encoder"); 403110184Ssimokawa out_data->length = len; 404110184Ssimokawa out_data->data = buf; 405110184Ssimokawa return 0; 406110184Ssimokawa out4: 407110184Ssimokawa free_EncKrbCredPart(&enc_krb_cred_part); 408110184Ssimokawa out3: 409110184Ssimokawa free_KRB_CRED(&cred); 410110184Ssimokawa out2: 411110184Ssimokawa krb5_free_creds (context, out_creds); 412110184Ssimokawa return ret; 413110184Ssimokawa} 414110184Ssimokawa