17c478bd9Sstevel@tonic-gate /* 2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate 77c478bd9Sstevel@tonic-gate /* 87c478bd9Sstevel@tonic-gate * lib/krb5/krb/get_in_tkt.c 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology. 117c478bd9Sstevel@tonic-gate * All Rights Reserved. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 147c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 157c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 167c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 177c478bd9Sstevel@tonic-gate * 187c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 197c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 207c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 217c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 227c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 237c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 247c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 257c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 267c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 277c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 287c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 297c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 307c478bd9Sstevel@tonic-gate * or implied warranty. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * krb5_get_in_tkt() 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate 38*159d09a2SMark Phalan #include "k5-int.h" 39*159d09a2SMark Phalan #include "int-proto.h" 40*159d09a2SMark Phalan #include "os-proto.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate All-purpose initial ticket routine, usually called via 447c478bd9Sstevel@tonic-gate krb5_get_in_tkt_with_password or krb5_get_in_tkt_with_skey. 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate Attempts to get an initial ticket for creds->client to use server 477c478bd9Sstevel@tonic-gate creds->server, (realm is taken from creds->client), with options 487c478bd9Sstevel@tonic-gate options, and using creds->times.starttime, creds->times.endtime, 497c478bd9Sstevel@tonic-gate creds->times.renew_till as from, till, and rtime. 507c478bd9Sstevel@tonic-gate creds->times.renew_till is ignored unless the RENEWABLE option is requested. 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate key_proc is called to fill in the key to be used for decryption. 537c478bd9Sstevel@tonic-gate keyseed is passed on to key_proc. 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate decrypt_proc is called to perform the decryption of the response (the 567c478bd9Sstevel@tonic-gate encrypted part is in dec_rep->enc_part; the decrypted part should be 577c478bd9Sstevel@tonic-gate allocated and filled into dec_rep->enc_part2 587c478bd9Sstevel@tonic-gate arg is passed on to decrypt_proc. 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate If addrs is non-NULL, it is used for the addresses requested. If it is 617c478bd9Sstevel@tonic-gate null, the system standard addresses are used. 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate A succesful call will place the ticket in the credentials cache ccache 647c478bd9Sstevel@tonic-gate and fill in creds with the ticket information used/returned.. 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate returns system errors, encryption errors 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate */ 697c478bd9Sstevel@tonic-gate 70*159d09a2SMark Phalan /* Solaris Kerberos */ 713441f6a1Ssemery #define max(a, b) ((a) > (b) ? (a) : (b)) 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* some typedef's for the function args to make things look a bit cleaner */ 747c478bd9Sstevel@tonic-gate 75505d05c7Sgtb typedef krb5_error_code (*git_key_proc) (krb5_context, 767c478bd9Sstevel@tonic-gate const krb5_enctype, 777c478bd9Sstevel@tonic-gate krb5_data *, 787c478bd9Sstevel@tonic-gate krb5_const_pointer, 79505d05c7Sgtb krb5_keyblock **); 807c478bd9Sstevel@tonic-gate 81505d05c7Sgtb typedef krb5_error_code (*git_decrypt_proc) (krb5_context, 827c478bd9Sstevel@tonic-gate const krb5_keyblock *, 837c478bd9Sstevel@tonic-gate krb5_const_pointer, 84505d05c7Sgtb krb5_kdc_rep * ); 857c478bd9Sstevel@tonic-gate 86505d05c7Sgtb static krb5_error_code make_preauth_list (krb5_context, 877c478bd9Sstevel@tonic-gate krb5_preauthtype *, 88505d05c7Sgtb int, krb5_pa_data ***); 89*159d09a2SMark Phalan static krb5_error_code sort_krb5_padata_sequence(krb5_context context, 90*159d09a2SMark Phalan krb5_data *realm, 91*159d09a2SMark Phalan krb5_pa_data **padata); 92505d05c7Sgtb 93505d05c7Sgtb /* 94505d05c7Sgtb * This function performs 32 bit bounded addition so we can generate 95505d05c7Sgtb * lifetimes without overflowing krb5_int32 96505d05c7Sgtb */ 97505d05c7Sgtb static krb5_int32 krb5int_addint32 (krb5_int32 x, krb5_int32 y) 98505d05c7Sgtb { 99505d05c7Sgtb if ((x > 0) && (y > (KRB5_INT32_MAX - x))) { 100505d05c7Sgtb /* sum will be be greater than KRB5_INT32_MAX */ 101505d05c7Sgtb return KRB5_INT32_MAX; 102505d05c7Sgtb } else if ((x < 0) && (y < (KRB5_INT32_MIN - x))) { 103505d05c7Sgtb /* sum will be less than KRB5_INT32_MIN */ 104505d05c7Sgtb return KRB5_INT32_MIN; 105505d05c7Sgtb } 106505d05c7Sgtb 107505d05c7Sgtb return x + y; 108505d05c7Sgtb } 109505d05c7Sgtb 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * This function sends a request to the KDC, and gets back a response; 1127c478bd9Sstevel@tonic-gate * the response is parsed into ret_err_reply or ret_as_reply if the 1137c478bd9Sstevel@tonic-gate * reponse is a KRB_ERROR or a KRB_AS_REP packet. If it is some other 1147c478bd9Sstevel@tonic-gate * unexpected response, an error is returned. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate static krb5_error_code 117505d05c7Sgtb send_as_request(krb5_context context, 118505d05c7Sgtb krb5_kdc_req *request, 119505d05c7Sgtb krb5_error ** ret_err_reply, 120505d05c7Sgtb krb5_kdc_rep ** ret_as_reply, 121505d05c7Sgtb int *use_master) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate krb5_kdc_rep *as_reply = 0; 1247c478bd9Sstevel@tonic-gate krb5_error_code retval; 1257c478bd9Sstevel@tonic-gate krb5_data *packet = 0; 1267c478bd9Sstevel@tonic-gate krb5_data reply; 1277c478bd9Sstevel@tonic-gate char k4_version; /* same type as *(krb5_data::data) */ 1287c478bd9Sstevel@tonic-gate int tcp_only = 0; 129*159d09a2SMark Phalan krb5_timestamp time_now; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate reply.data = 0; 1327c478bd9Sstevel@tonic-gate 133*159d09a2SMark Phalan /* set the nonce if the caller expects us to do it */ 134*159d09a2SMark Phalan if (request->nonce == 0) { 135*159d09a2SMark Phalan if ((retval = krb5_timeofday(context, &time_now))) 1367c478bd9Sstevel@tonic-gate goto cleanup; 137*159d09a2SMark Phalan request->nonce = (krb5_int32) time_now; 138*159d09a2SMark Phalan } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* encode & send to KDC */ 1417c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_as_req(request, &packet)) != 0) 1427c478bd9Sstevel@tonic-gate goto cleanup; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate k4_version = packet->data[0]; 1457c478bd9Sstevel@tonic-gate send_again: 1467c478bd9Sstevel@tonic-gate retval = krb5_sendto_kdc(context, packet, 1477c478bd9Sstevel@tonic-gate krb5_princ_realm(context, request->client), 1487c478bd9Sstevel@tonic-gate &reply, use_master, tcp_only); 1497c478bd9Sstevel@tonic-gate if (retval) 1507c478bd9Sstevel@tonic-gate goto cleanup; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* now decode the reply...could be error or as_rep */ 1537c478bd9Sstevel@tonic-gate if (krb5_is_krb_error(&reply)) { 1547c478bd9Sstevel@tonic-gate krb5_error *err_reply; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_error(&reply, &err_reply))) 1577c478bd9Sstevel@tonic-gate /* some other error code--??? */ 1587c478bd9Sstevel@tonic-gate goto cleanup; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate if (ret_err_reply) { 1617c478bd9Sstevel@tonic-gate if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG 1627c478bd9Sstevel@tonic-gate && tcp_only == 0) { 1637c478bd9Sstevel@tonic-gate tcp_only = 1; 1647c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1657c478bd9Sstevel@tonic-gate free(reply.data); 1667c478bd9Sstevel@tonic-gate reply.data = 0; 1677c478bd9Sstevel@tonic-gate goto send_again; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate *ret_err_reply = err_reply; 1707c478bd9Sstevel@tonic-gate } else 1717c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1727c478bd9Sstevel@tonic-gate goto cleanup; 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* 1767c478bd9Sstevel@tonic-gate * Check to make sure it isn't a V4 reply. 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate if (!krb5_is_as_rep(&reply)) { 1797c478bd9Sstevel@tonic-gate /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */ 1807c478bd9Sstevel@tonic-gate #define V4_KRB_PROT_VERSION 4 1817c478bd9Sstevel@tonic-gate #define V4_AUTH_MSG_ERR_REPLY (5<<1) 1827c478bd9Sstevel@tonic-gate /* check here for V4 reply */ 1837c478bd9Sstevel@tonic-gate unsigned int t_switch; 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* From v4 g_in_tkt.c: This used to be 1867c478bd9Sstevel@tonic-gate switch (pkt_msg_type(rpkt) & ~1) { 1877c478bd9Sstevel@tonic-gate but SCO 3.2v4 cc compiled that incorrectly. */ 1887c478bd9Sstevel@tonic-gate t_switch = reply.data[1]; 1897c478bd9Sstevel@tonic-gate t_switch &= ~1; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (t_switch == V4_AUTH_MSG_ERR_REPLY 1927c478bd9Sstevel@tonic-gate && (reply.data[0] == V4_KRB_PROT_VERSION 1937c478bd9Sstevel@tonic-gate || reply.data[0] == k4_version)) { 1947c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_V4_REPLY; 1957c478bd9Sstevel@tonic-gate } else { 1967c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_MSG_TYPE; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate goto cleanup; 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* It must be a KRB_AS_REP message, or an bad returned packet */ 2027c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_as_rep(&reply, &as_reply))) 2037c478bd9Sstevel@tonic-gate /* some other error code ??? */ 2047c478bd9Sstevel@tonic-gate goto cleanup; 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate if (as_reply->msg_type != KRB5_AS_REP) { 2077c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_MSG_TYPE; 2087c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, as_reply); 2097c478bd9Sstevel@tonic-gate goto cleanup; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate if (ret_as_reply) 2137c478bd9Sstevel@tonic-gate *ret_as_reply = as_reply; 2147c478bd9Sstevel@tonic-gate else 2157c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, as_reply); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate cleanup: 2187c478bd9Sstevel@tonic-gate if (packet) 2197c478bd9Sstevel@tonic-gate krb5_free_data(context, packet); 2207c478bd9Sstevel@tonic-gate if (reply.data) 2217c478bd9Sstevel@tonic-gate free(reply.data); 2227c478bd9Sstevel@tonic-gate return retval; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate static krb5_error_code 226505d05c7Sgtb decrypt_as_reply(krb5_context context, 227505d05c7Sgtb krb5_kdc_req *request, 228505d05c7Sgtb krb5_kdc_rep *as_reply, 229505d05c7Sgtb git_key_proc key_proc, 230505d05c7Sgtb krb5_const_pointer keyseed, 231505d05c7Sgtb krb5_keyblock * key, 232505d05c7Sgtb git_decrypt_proc decrypt_proc, 233505d05c7Sgtb krb5_const_pointer decryptarg) 2347c478bd9Sstevel@tonic-gate { 2357c478bd9Sstevel@tonic-gate krb5_error_code retval; 2367c478bd9Sstevel@tonic-gate krb5_keyblock * decrypt_key = 0; 2377c478bd9Sstevel@tonic-gate krb5_data salt; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (as_reply->enc_part2) 2407c478bd9Sstevel@tonic-gate return 0; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (key) 2437c478bd9Sstevel@tonic-gate decrypt_key = key; 244*159d09a2SMark Phalan /* Solaris Kerberos */ 2457c478bd9Sstevel@tonic-gate else if (request != NULL) { 2467c478bd9Sstevel@tonic-gate if ((retval = krb5_principal2salt(context, request->client, &salt))) 2477c478bd9Sstevel@tonic-gate return(retval); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate retval = (*key_proc)(context, as_reply->enc_part.enctype, 2507c478bd9Sstevel@tonic-gate &salt, keyseed, &decrypt_key); 2517c478bd9Sstevel@tonic-gate krb5_xfree(salt.data); 2527c478bd9Sstevel@tonic-gate if (retval) 2537c478bd9Sstevel@tonic-gate goto cleanup; 2547c478bd9Sstevel@tonic-gate } else { 2557c478bd9Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, " 2567c478bd9Sstevel@tonic-gate "error key == NULL and request == NULL"); 2577c478bd9Sstevel@tonic-gate return (EINVAL); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 260*159d09a2SMark Phalan /* 261*159d09a2SMark Phalan * Solaris kerberos: Overwriting the decrypt_key->enctype because the 2627c478bd9Sstevel@tonic-gate * decrypt key's enctype may not be an exact match with the enctype that the 2637c478bd9Sstevel@tonic-gate * KDC used to encrypt this part of the AS reply. This assumes the 2647c478bd9Sstevel@tonic-gate * as_reply->enc_part.enctype has been validated which is done by checking 2657c478bd9Sstevel@tonic-gate * to see if the enctype that the KDC sent back in the as_reply is one of 2667c478bd9Sstevel@tonic-gate * the enctypes originally requested. Note, if request is NULL then the 2677c478bd9Sstevel@tonic-gate * as_reply->enc_part.enctype could not be validated. 2687c478bd9Sstevel@tonic-gate */ 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (request != NULL) { 2717c478bd9Sstevel@tonic-gate if (is_in_keytype(request->ktype, request->nktypes, 2727c478bd9Sstevel@tonic-gate as_reply->enc_part.enctype)) { 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate decrypt_key->enctype = as_reply->enc_part.enctype; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate } else { 2777c478bd9Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, " 2787c478bd9Sstevel@tonic-gate "error is_in_keytype() returned false"); 2797c478bd9Sstevel@tonic-gate retval = KRB5_BAD_ENCTYPE; 2807c478bd9Sstevel@tonic-gate goto cleanup; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply))){ 2857c478bd9Sstevel@tonic-gate KRB5_LOG(KRB5_ERR, "decrypt_as_reply() error (*decrypt_proc)() retval " 2867c478bd9Sstevel@tonic-gate "= %d", retval); 2877c478bd9Sstevel@tonic-gate goto cleanup; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate cleanup: 2917c478bd9Sstevel@tonic-gate if (!key && decrypt_key) 2927c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, decrypt_key); 2937c478bd9Sstevel@tonic-gate return (retval); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate static krb5_error_code 297505d05c7Sgtb verify_as_reply(krb5_context context, 298505d05c7Sgtb krb5_timestamp time_now, 299505d05c7Sgtb krb5_kdc_req *request, 300505d05c7Sgtb krb5_kdc_rep *as_reply) 3017c478bd9Sstevel@tonic-gate { 3027c478bd9Sstevel@tonic-gate krb5_error_code retval; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* check the contents for sanity: */ 3057c478bd9Sstevel@tonic-gate if (!as_reply->enc_part2->times.starttime) 3067c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.starttime = 3077c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.authtime; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if (!krb5_principal_compare(context, as_reply->client, request->client) 3107c478bd9Sstevel@tonic-gate || !krb5_principal_compare(context, as_reply->enc_part2->server, request->server) 3117c478bd9Sstevel@tonic-gate || !krb5_principal_compare(context, as_reply->ticket->server, request->server) 3127c478bd9Sstevel@tonic-gate || (request->nonce != as_reply->enc_part2->nonce) 3137c478bd9Sstevel@tonic-gate /* XXX check for extraneous flags */ 3147c478bd9Sstevel@tonic-gate /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */ 3157c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_POSTDATED) && 3167c478bd9Sstevel@tonic-gate (request->from != 0) && 3177c478bd9Sstevel@tonic-gate (request->from != as_reply->enc_part2->times.starttime)) 3187c478bd9Sstevel@tonic-gate || ((request->till != 0) && 3197c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.endtime > request->till)) 3207c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_RENEWABLE) && 3213441f6a1Ssemery /* 3223441f6a1Ssemery * Solaris Kerberos: Here we error only if renewable_ok was not set. 3233441f6a1Ssemery */ 3243441f6a1Ssemery !(request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3253441f6a1Ssemery (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3267c478bd9Sstevel@tonic-gate (request->rtime != 0) && 3277c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.renew_till > request->rtime)) 3287c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3297c478bd9Sstevel@tonic-gate !(request->kdc_options & KDC_OPT_RENEWABLE) && 3307c478bd9Sstevel@tonic-gate (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3317c478bd9Sstevel@tonic-gate (request->till != 0) && 3327c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.renew_till > request->till)) 3333441f6a1Ssemery /* 3343441f6a1Ssemery * Solaris Kerberos: renew_till should never be greater than till or 3353441f6a1Ssemery * rtime. 3363441f6a1Ssemery */ 3373441f6a1Ssemery || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3383441f6a1Ssemery (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3393441f6a1Ssemery (request->till != 0) && 3403441f6a1Ssemery (request->rtime != 0) && 3413441f6a1Ssemery (as_reply->enc_part2->times.renew_till > max(request->till, 3423441f6a1Ssemery request->rtime))) 3437c478bd9Sstevel@tonic-gate ) 3447c478bd9Sstevel@tonic-gate return KRB5_KDCREP_MODIFIED; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { 3477c478bd9Sstevel@tonic-gate retval = krb5_set_real_time(context, 3487c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.authtime, 0); 3497c478bd9Sstevel@tonic-gate if (retval) 3507c478bd9Sstevel@tonic-gate return retval; 3517c478bd9Sstevel@tonic-gate } else { 3527c478bd9Sstevel@tonic-gate if ((request->from == 0) && 3537c478bd9Sstevel@tonic-gate (labs(as_reply->enc_part2->times.starttime - time_now) 3547c478bd9Sstevel@tonic-gate > context->clockskew)) 3557c478bd9Sstevel@tonic-gate return (KRB5_KDCREP_SKEW); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate return 0; 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3617c478bd9Sstevel@tonic-gate static krb5_error_code 362505d05c7Sgtb stash_as_reply(krb5_context context, 363505d05c7Sgtb krb5_timestamp time_now, 364505d05c7Sgtb krb5_kdc_req *request, 365505d05c7Sgtb krb5_kdc_rep *as_reply, 366505d05c7Sgtb krb5_creds * creds, 367505d05c7Sgtb krb5_ccache ccache) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate krb5_error_code retval; 3707c478bd9Sstevel@tonic-gate krb5_data * packet; 3717c478bd9Sstevel@tonic-gate krb5_principal client; 3727c478bd9Sstevel@tonic-gate krb5_principal server; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate client = NULL; 3757c478bd9Sstevel@tonic-gate server = NULL; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate if (!creds->client) 378505d05c7Sgtb if ((retval = krb5_copy_principal(context, as_reply->client, &client))) 3797c478bd9Sstevel@tonic-gate goto cleanup; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (!creds->server) 382505d05c7Sgtb if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server, 383505d05c7Sgtb &server))) 3847c478bd9Sstevel@tonic-gate goto cleanup; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* fill in the credentials */ 3877c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_keyblock_contents(context, 3887c478bd9Sstevel@tonic-gate as_reply->enc_part2->session, 3897c478bd9Sstevel@tonic-gate &creds->keyblock))) 3907c478bd9Sstevel@tonic-gate goto cleanup; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate creds->times = as_reply->enc_part2->times; 3937c478bd9Sstevel@tonic-gate creds->is_skey = FALSE; /* this is an AS_REQ, so cannot 3947c478bd9Sstevel@tonic-gate be encrypted in skey */ 3957c478bd9Sstevel@tonic-gate creds->ticket_flags = as_reply->enc_part2->flags; 3967c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs, 3977c478bd9Sstevel@tonic-gate &creds->addresses))) 3987c478bd9Sstevel@tonic-gate goto cleanup; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate creds->second_ticket.length = 0; 4017c478bd9Sstevel@tonic-gate creds->second_ticket.data = 0; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_ticket(as_reply->ticket, &packet))) 4047c478bd9Sstevel@tonic-gate goto cleanup; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate creds->ticket = *packet; 4077c478bd9Sstevel@tonic-gate krb5_xfree(packet); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* store it in the ccache! */ 410*159d09a2SMark Phalan if (ccache) /* Solaris Kerberos */ 4117c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_store_cred(context, ccache, creds)) !=0) 4127c478bd9Sstevel@tonic-gate goto cleanup; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate if (!creds->client) 4157c478bd9Sstevel@tonic-gate creds->client = client; 4167c478bd9Sstevel@tonic-gate if (!creds->server) 4177c478bd9Sstevel@tonic-gate creds->server = server; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate cleanup: 4207c478bd9Sstevel@tonic-gate if (retval) { 4217c478bd9Sstevel@tonic-gate if (client) 4227c478bd9Sstevel@tonic-gate krb5_free_principal(context, client); 4237c478bd9Sstevel@tonic-gate if (server) 4247c478bd9Sstevel@tonic-gate krb5_free_principal(context, server); 4257c478bd9Sstevel@tonic-gate if (creds->keyblock.contents) { 4267c478bd9Sstevel@tonic-gate memset((char *)creds->keyblock.contents, 0, 4277c478bd9Sstevel@tonic-gate creds->keyblock.length); 4287c478bd9Sstevel@tonic-gate krb5_xfree(creds->keyblock.contents); 4297c478bd9Sstevel@tonic-gate creds->keyblock.contents = 0; 4307c478bd9Sstevel@tonic-gate creds->keyblock.length = 0; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate if (creds->ticket.data) { 4337c478bd9Sstevel@tonic-gate krb5_xfree(creds->ticket.data); 4347c478bd9Sstevel@tonic-gate creds->ticket.data = 0; 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate if (creds->addresses) { 4377c478bd9Sstevel@tonic-gate krb5_free_addresses(context, creds->addresses); 4387c478bd9Sstevel@tonic-gate creds->addresses = 0; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate return (retval); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4457c478bd9Sstevel@tonic-gate static krb5_error_code 446505d05c7Sgtb make_preauth_list(krb5_context context, 447505d05c7Sgtb krb5_preauthtype * ptypes, 448505d05c7Sgtb int nptypes, 449505d05c7Sgtb krb5_pa_data *** ret_list) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate krb5_preauthtype * ptypep; 4527c478bd9Sstevel@tonic-gate krb5_pa_data ** preauthp; 4537c478bd9Sstevel@tonic-gate int i; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (nptypes < 0) { 4567c478bd9Sstevel@tonic-gate for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++) 4577c478bd9Sstevel@tonic-gate ; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* allocate space for a NULL to terminate the list */ 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if ((preauthp = 4637c478bd9Sstevel@tonic-gate (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL) 4647c478bd9Sstevel@tonic-gate return(ENOMEM); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate for (i=0; i<nptypes; i++) { 4677c478bd9Sstevel@tonic-gate if ((preauthp[i] = 4687c478bd9Sstevel@tonic-gate (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) { 4697c478bd9Sstevel@tonic-gate for (; i>=0; i++) 4707c478bd9Sstevel@tonic-gate free(preauthp[i]); 4717c478bd9Sstevel@tonic-gate free(preauthp); 4727c478bd9Sstevel@tonic-gate return (ENOMEM); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate preauthp[i]->magic = KV5M_PA_DATA; 4757c478bd9Sstevel@tonic-gate preauthp[i]->pa_type = ptypes[i]; 4767c478bd9Sstevel@tonic-gate preauthp[i]->length = 0; 4777c478bd9Sstevel@tonic-gate preauthp[i]->contents = 0; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* fill in the terminating NULL */ 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate preauthp[nptypes] = NULL; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate *ret_list = preauthp; 4857c478bd9Sstevel@tonic-gate return 0; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate #define MAX_IN_TKT_LOOPS 16 489505d05c7Sgtb static const krb5_enctype get_in_tkt_enctypes[] = { 490505d05c7Sgtb ENCTYPE_DES3_CBC_SHA1, 491505d05c7Sgtb ENCTYPE_ARCFOUR_HMAC, 492505d05c7Sgtb ENCTYPE_DES_CBC_MD5, 493505d05c7Sgtb ENCTYPE_DES_CBC_MD4, 494505d05c7Sgtb ENCTYPE_DES_CBC_CRC, 495505d05c7Sgtb 0 496505d05c7Sgtb }; 497*159d09a2SMark Phalan 498*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV 499*159d09a2SMark Phalan krb5_get_in_tkt(krb5_context context, 500*159d09a2SMark Phalan const krb5_flags options, 501*159d09a2SMark Phalan krb5_address * const * addrs, 502*159d09a2SMark Phalan krb5_enctype * ktypes, 503*159d09a2SMark Phalan krb5_preauthtype * ptypes, 504*159d09a2SMark Phalan git_key_proc key_proc, 505*159d09a2SMark Phalan krb5_const_pointer keyseed, 506*159d09a2SMark Phalan git_decrypt_proc decrypt_proc, 507*159d09a2SMark Phalan krb5_const_pointer decryptarg, 508*159d09a2SMark Phalan krb5_creds * creds, 509*159d09a2SMark Phalan krb5_ccache ccache, 510*159d09a2SMark Phalan krb5_kdc_rep ** ret_as_reply) 511*159d09a2SMark Phalan { 512*159d09a2SMark Phalan krb5_error_code retval; 513*159d09a2SMark Phalan krb5_timestamp time_now; 514*159d09a2SMark Phalan krb5_keyblock * decrypt_key = 0; 515*159d09a2SMark Phalan krb5_kdc_req request; 516*159d09a2SMark Phalan krb5_pa_data **padata = 0; 517*159d09a2SMark Phalan krb5_error * err_reply; 518*159d09a2SMark Phalan krb5_kdc_rep * as_reply = 0; 519*159d09a2SMark Phalan krb5_pa_data ** preauth_to_use = 0; 520*159d09a2SMark Phalan int loopcount = 0; 521*159d09a2SMark Phalan krb5_int32 do_more = 0; 522*159d09a2SMark Phalan int use_master = 0; 523*159d09a2SMark Phalan 524*159d09a2SMark Phalan if (! krb5_realm_compare(context, creds->client, creds->server)) 525*159d09a2SMark Phalan return KRB5_IN_TKT_REALM_MISMATCH; 526*159d09a2SMark Phalan 527*159d09a2SMark Phalan if (ret_as_reply) 528*159d09a2SMark Phalan *ret_as_reply = 0; 529*159d09a2SMark Phalan 530*159d09a2SMark Phalan /* 531*159d09a2SMark Phalan * Set up the basic request structure 532*159d09a2SMark Phalan */ 533*159d09a2SMark Phalan request.magic = KV5M_KDC_REQ; 534*159d09a2SMark Phalan request.msg_type = KRB5_AS_REQ; 535*159d09a2SMark Phalan request.addresses = 0; 536*159d09a2SMark Phalan request.ktype = 0; 537*159d09a2SMark Phalan request.padata = 0; 538*159d09a2SMark Phalan if (addrs) 539*159d09a2SMark Phalan request.addresses = (krb5_address **) addrs; 540*159d09a2SMark Phalan else 541*159d09a2SMark Phalan if ((retval = krb5_os_localaddr(context, &request.addresses))) 542*159d09a2SMark Phalan goto cleanup; 543*159d09a2SMark Phalan request.kdc_options = options; 544*159d09a2SMark Phalan request.client = creds->client; 545*159d09a2SMark Phalan request.server = creds->server; 546*159d09a2SMark Phalan request.nonce = 0; 547*159d09a2SMark Phalan request.from = creds->times.starttime; 548*159d09a2SMark Phalan request.till = creds->times.endtime; 549*159d09a2SMark Phalan request.rtime = creds->times.renew_till; 550*159d09a2SMark Phalan 551*159d09a2SMark Phalan request.ktype = malloc (sizeof(get_in_tkt_enctypes)); 552*159d09a2SMark Phalan if (request.ktype == NULL) { 553*159d09a2SMark Phalan retval = ENOMEM; 554*159d09a2SMark Phalan goto cleanup; 555*159d09a2SMark Phalan } 556*159d09a2SMark Phalan memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes)); 557*159d09a2SMark Phalan for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++); 558*159d09a2SMark Phalan if (ktypes) { 559*159d09a2SMark Phalan int i, req, next = 0; 560*159d09a2SMark Phalan for (req = 0; ktypes[req]; req++) { 561*159d09a2SMark Phalan if (ktypes[req] == request.ktype[next]) { 562*159d09a2SMark Phalan next++; 563*159d09a2SMark Phalan continue; 564*159d09a2SMark Phalan } 565*159d09a2SMark Phalan for (i = next + 1; i < request.nktypes; i++) 566*159d09a2SMark Phalan if (ktypes[req] == request.ktype[i]) { 567*159d09a2SMark Phalan /* Found the enctype we want, but not in the 568*159d09a2SMark Phalan position we want. Move it, but keep the old 569*159d09a2SMark Phalan one from the desired slot around in case it's 570*159d09a2SMark Phalan later in our requested-ktypes list. */ 571*159d09a2SMark Phalan krb5_enctype t; 572*159d09a2SMark Phalan t = request.ktype[next]; 573*159d09a2SMark Phalan request.ktype[next] = request.ktype[i]; 574*159d09a2SMark Phalan request.ktype[i] = t; 575*159d09a2SMark Phalan next++; 576*159d09a2SMark Phalan break; 577*159d09a2SMark Phalan } 578*159d09a2SMark Phalan /* If we didn't find it, don't do anything special, just 579*159d09a2SMark Phalan drop it. */ 580*159d09a2SMark Phalan } 581*159d09a2SMark Phalan request.ktype[next] = 0; 582*159d09a2SMark Phalan request.nktypes = next; 583*159d09a2SMark Phalan } 584*159d09a2SMark Phalan request.authorization_data.ciphertext.length = 0; 585*159d09a2SMark Phalan request.authorization_data.ciphertext.data = 0; 586*159d09a2SMark Phalan request.unenc_authdata = 0; 587*159d09a2SMark Phalan request.second_ticket = 0; 588*159d09a2SMark Phalan 589*159d09a2SMark Phalan /* 590*159d09a2SMark Phalan * If a list of preauth types are passed in, convert it to a 591*159d09a2SMark Phalan * preauth_to_use list. 592*159d09a2SMark Phalan */ 593*159d09a2SMark Phalan if (ptypes) { 594*159d09a2SMark Phalan retval = make_preauth_list(context, ptypes, -1, &preauth_to_use); 595*159d09a2SMark Phalan if (retval) 596*159d09a2SMark Phalan goto cleanup; 597*159d09a2SMark Phalan } 598*159d09a2SMark Phalan 599*159d09a2SMark Phalan while (1) { 600*159d09a2SMark Phalan if (loopcount++ > MAX_IN_TKT_LOOPS) { 601*159d09a2SMark Phalan retval = KRB5_GET_IN_TKT_LOOP; 602*159d09a2SMark Phalan goto cleanup; 603*159d09a2SMark Phalan } 604*159d09a2SMark Phalan 605*159d09a2SMark Phalan if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc, 606*159d09a2SMark Phalan keyseed, creds, &request)) != 0) 607*159d09a2SMark Phalan goto cleanup; 608*159d09a2SMark Phalan if (preauth_to_use) 609*159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 610*159d09a2SMark Phalan preauth_to_use = 0; 611*159d09a2SMark Phalan 612*159d09a2SMark Phalan err_reply = 0; 613*159d09a2SMark Phalan as_reply = 0; 614*159d09a2SMark Phalan 615*159d09a2SMark Phalan if ((retval = krb5_timeofday(context, &time_now))) 616*159d09a2SMark Phalan goto cleanup; 617*159d09a2SMark Phalan 618*159d09a2SMark Phalan /* 619*159d09a2SMark Phalan * XXX we know they are the same size... and we should do 620*159d09a2SMark Phalan * something better than just the current time 621*159d09a2SMark Phalan */ 622*159d09a2SMark Phalan request.nonce = (krb5_int32) time_now; 623*159d09a2SMark Phalan 624*159d09a2SMark Phalan if ((retval = send_as_request(context, &request, &err_reply, 625*159d09a2SMark Phalan &as_reply, &use_master))) 626*159d09a2SMark Phalan goto cleanup; 627*159d09a2SMark Phalan 628*159d09a2SMark Phalan if (err_reply) { 629*159d09a2SMark Phalan if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED && 630*159d09a2SMark Phalan err_reply->e_data.length > 0) { 631*159d09a2SMark Phalan retval = decode_krb5_padata_sequence(&err_reply->e_data, 632*159d09a2SMark Phalan &preauth_to_use); 633*159d09a2SMark Phalan krb5_free_error(context, err_reply); 634*159d09a2SMark Phalan if (retval) 635*159d09a2SMark Phalan goto cleanup; 636*159d09a2SMark Phalan retval = sort_krb5_padata_sequence(context, 637*159d09a2SMark Phalan &request.server->realm, 638*159d09a2SMark Phalan padata); 639*159d09a2SMark Phalan if (retval) 640*159d09a2SMark Phalan goto cleanup; 641*159d09a2SMark Phalan continue; 642*159d09a2SMark Phalan } else { 643*159d09a2SMark Phalan retval = (krb5_error_code) err_reply->error 644*159d09a2SMark Phalan + ERROR_TABLE_BASE_krb5; 645*159d09a2SMark Phalan krb5_free_error(context, err_reply); 646*159d09a2SMark Phalan goto cleanup; 647*159d09a2SMark Phalan } 648*159d09a2SMark Phalan } else if (!as_reply) { 649*159d09a2SMark Phalan retval = KRB5KRB_AP_ERR_MSG_TYPE; 650*159d09a2SMark Phalan goto cleanup; 651*159d09a2SMark Phalan } 652*159d09a2SMark Phalan if ((retval = krb5_process_padata(context, &request, as_reply, 653*159d09a2SMark Phalan key_proc, keyseed, decrypt_proc, 654*159d09a2SMark Phalan &decrypt_key, creds, 655*159d09a2SMark Phalan &do_more)) != 0) 656*159d09a2SMark Phalan goto cleanup; 657*159d09a2SMark Phalan 658*159d09a2SMark Phalan if (!do_more) 659*159d09a2SMark Phalan break; 660*159d09a2SMark Phalan } 661*159d09a2SMark Phalan 662*159d09a2SMark Phalan if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc, 663*159d09a2SMark Phalan keyseed, decrypt_key, decrypt_proc, 664*159d09a2SMark Phalan decryptarg))) 665*159d09a2SMark Phalan goto cleanup; 666*159d09a2SMark Phalan 667*159d09a2SMark Phalan if ((retval = verify_as_reply(context, time_now, &request, as_reply))) 668*159d09a2SMark Phalan goto cleanup; 669*159d09a2SMark Phalan 670*159d09a2SMark Phalan if ((retval = stash_as_reply(context, time_now, &request, as_reply, 671*159d09a2SMark Phalan creds, ccache))) 672*159d09a2SMark Phalan goto cleanup; 673*159d09a2SMark Phalan 674*159d09a2SMark Phalan cleanup: 675*159d09a2SMark Phalan if (request.ktype) 676*159d09a2SMark Phalan free(request.ktype); 677*159d09a2SMark Phalan if (!addrs && request.addresses) 678*159d09a2SMark Phalan krb5_free_addresses(context, request.addresses); 679*159d09a2SMark Phalan if (request.padata) 680*159d09a2SMark Phalan krb5_free_pa_data(context, request.padata); 681*159d09a2SMark Phalan if (padata) 682*159d09a2SMark Phalan krb5_free_pa_data(context, padata); 683*159d09a2SMark Phalan if (preauth_to_use) 684*159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 685*159d09a2SMark Phalan if (decrypt_key) 686*159d09a2SMark Phalan krb5_free_keyblock(context, decrypt_key); 687*159d09a2SMark Phalan if (as_reply) { 688*159d09a2SMark Phalan if (ret_as_reply) 689*159d09a2SMark Phalan *ret_as_reply = as_reply; 690*159d09a2SMark Phalan else 691*159d09a2SMark Phalan krb5_free_kdc_rep(context, as_reply); 692*159d09a2SMark Phalan } 693*159d09a2SMark Phalan return (retval); 694*159d09a2SMark Phalan } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate /* begin libdefaults parsing code. This should almost certainly move 6977c478bd9Sstevel@tonic-gate somewhere else, but I don't know where the correct somewhere else 6987c478bd9Sstevel@tonic-gate is yet. */ 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* XXX Duplicating this is annoying; try to work on a better way.*/ 701505d05c7Sgtb static const char *const conf_yes[] = { 7027c478bd9Sstevel@tonic-gate "y", "yes", "true", "t", "1", "on", 7037c478bd9Sstevel@tonic-gate 0, 7047c478bd9Sstevel@tonic-gate }; 7057c478bd9Sstevel@tonic-gate 706505d05c7Sgtb static const char *const conf_no[] = { 7077c478bd9Sstevel@tonic-gate "n", "no", "false", "nil", "0", "off", 7087c478bd9Sstevel@tonic-gate 0, 7097c478bd9Sstevel@tonic-gate }; 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate int 712505d05c7Sgtb _krb5_conf_boolean(const char *s) 7137c478bd9Sstevel@tonic-gate { 714505d05c7Sgtb const char *const *p; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate for(p=conf_yes; *p; p++) { 7177c478bd9Sstevel@tonic-gate if (!strcasecmp(*p,s)) 7187c478bd9Sstevel@tonic-gate return 1; 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate for(p=conf_no; *p; p++) { 7227c478bd9Sstevel@tonic-gate if (!strcasecmp(*p,s)) 7237c478bd9Sstevel@tonic-gate return 0; 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* Default to "no" */ 7277c478bd9Sstevel@tonic-gate return 0; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate static krb5_error_code 731505d05c7Sgtb krb5_libdefault_string(krb5_context context, const krb5_data *realm, 732505d05c7Sgtb const char *option, char **ret_value) 7337c478bd9Sstevel@tonic-gate { 7347c478bd9Sstevel@tonic-gate profile_t profile; 7357c478bd9Sstevel@tonic-gate const char *names[5]; 7367c478bd9Sstevel@tonic-gate char **nameval = NULL; 7377c478bd9Sstevel@tonic-gate krb5_error_code retval; 7387c478bd9Sstevel@tonic-gate char realmstr[1024]; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate if (realm->length > sizeof(realmstr)-1) 7417c478bd9Sstevel@tonic-gate return(EINVAL); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate strncpy(realmstr, realm->data, realm->length); 7447c478bd9Sstevel@tonic-gate realmstr[realm->length] = '\0'; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate if (!context || (context->magic != KV5M_CONTEXT)) 7477c478bd9Sstevel@tonic-gate return KV5M_CONTEXT; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate profile = context->profile; 7507c478bd9Sstevel@tonic-gate 751*159d09a2SMark Phalan /* Solaris Kerberos */ 7527c478bd9Sstevel@tonic-gate names[0] = "realms"; 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * Try number one: 7567c478bd9Sstevel@tonic-gate * 7577c478bd9Sstevel@tonic-gate * [realms] 7587c478bd9Sstevel@tonic-gate * REALM = { 7597c478bd9Sstevel@tonic-gate * option = <boolean> 7607c478bd9Sstevel@tonic-gate * } 7617c478bd9Sstevel@tonic-gate */ 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate names[1] = realmstr; 7647c478bd9Sstevel@tonic-gate names[2] = option; 7657c478bd9Sstevel@tonic-gate names[3] = 0; 7667c478bd9Sstevel@tonic-gate retval = profile_get_values(profile, names, &nameval); 7677c478bd9Sstevel@tonic-gate if (retval == 0 && nameval && nameval[0]) 7687c478bd9Sstevel@tonic-gate goto goodbye; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * Try number two: 7727c478bd9Sstevel@tonic-gate * 7737c478bd9Sstevel@tonic-gate * [libdefaults] 7747c478bd9Sstevel@tonic-gate * option = <boolean> 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate names[0] = "libdefaults"; 7787c478bd9Sstevel@tonic-gate names[1] = option; 7797c478bd9Sstevel@tonic-gate names[2] = 0; 7807c478bd9Sstevel@tonic-gate retval = profile_get_values(profile, names, &nameval); 7817c478bd9Sstevel@tonic-gate if (retval == 0 && nameval && nameval[0]) 7827c478bd9Sstevel@tonic-gate goto goodbye; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate goodbye: 7857c478bd9Sstevel@tonic-gate if (!nameval) 7867c478bd9Sstevel@tonic-gate return(ENOENT); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (!nameval[0]) { 7897c478bd9Sstevel@tonic-gate retval = ENOENT; 7907c478bd9Sstevel@tonic-gate } else { 7917c478bd9Sstevel@tonic-gate *ret_value = malloc(strlen(nameval[0]) + 1); 7927c478bd9Sstevel@tonic-gate if (!*ret_value) 7937c478bd9Sstevel@tonic-gate retval = ENOMEM; 7947c478bd9Sstevel@tonic-gate else 7957c478bd9Sstevel@tonic-gate strcpy(*ret_value, nameval[0]); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate profile_free_list(nameval); 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate return retval; 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* not static so verify_init_creds() can call it */ 8047c478bd9Sstevel@tonic-gate /* as well as the DNS code */ 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate krb5_error_code 807505d05c7Sgtb krb5_libdefault_boolean(krb5_context context, const krb5_data *realm, 808505d05c7Sgtb const char *option, int *ret_value) 8097c478bd9Sstevel@tonic-gate { 8107c478bd9Sstevel@tonic-gate char *string = NULL; 8117c478bd9Sstevel@tonic-gate krb5_error_code retval; 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate retval = krb5_libdefault_string(context, realm, option, &string); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate if (retval) 8167c478bd9Sstevel@tonic-gate return(retval); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate *ret_value = _krb5_conf_boolean(string); 8197c478bd9Sstevel@tonic-gate free(string); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate return(0); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate 824*159d09a2SMark Phalan /* Sort a pa_data sequence so that types named in the "preferred_preauth_types" 825*159d09a2SMark Phalan * libdefaults entry are listed before any others. */ 826*159d09a2SMark Phalan static krb5_error_code 827*159d09a2SMark Phalan sort_krb5_padata_sequence(krb5_context context, krb5_data *realm, 828*159d09a2SMark Phalan krb5_pa_data **padata) 829*159d09a2SMark Phalan { 830*159d09a2SMark Phalan int i, j, base; 831*159d09a2SMark Phalan krb5_error_code ret; 832*159d09a2SMark Phalan const char *p; 833*159d09a2SMark Phalan long l; 834*159d09a2SMark Phalan char *q, *preauth_types = NULL; 835*159d09a2SMark Phalan krb5_pa_data *tmp; 836*159d09a2SMark Phalan int need_free_string = 1; 837*159d09a2SMark Phalan 838*159d09a2SMark Phalan if ((padata == NULL) || (padata[0] == NULL)) { 839*159d09a2SMark Phalan return 0; 840*159d09a2SMark Phalan } 841*159d09a2SMark Phalan 842*159d09a2SMark Phalan ret = krb5_libdefault_string(context, realm, "preferred_preauth_types", 843*159d09a2SMark Phalan &preauth_types); 844*159d09a2SMark Phalan if ((ret != 0) || (preauth_types == NULL)) { 845*159d09a2SMark Phalan /* Try to use PKINIT first. */ 846*159d09a2SMark Phalan preauth_types = "17, 16, 15, 14"; 847*159d09a2SMark Phalan need_free_string = 0; 848*159d09a2SMark Phalan } 849*159d09a2SMark Phalan 850*159d09a2SMark Phalan #ifdef DEBUG 851*159d09a2SMark Phalan fprintf (stderr, "preauth data types before sorting:"); 852*159d09a2SMark Phalan for (i = 0; padata[i]; i++) { 853*159d09a2SMark Phalan fprintf (stderr, " %d", padata[i]->pa_type); 854*159d09a2SMark Phalan } 855*159d09a2SMark Phalan fprintf (stderr, "\n"); 856*159d09a2SMark Phalan #endif 857*159d09a2SMark Phalan 858*159d09a2SMark Phalan base = 0; 859*159d09a2SMark Phalan for (p = preauth_types; *p != '\0';) { 860*159d09a2SMark Phalan /* skip whitespace to find an entry */ 861*159d09a2SMark Phalan p += strspn(p, ", "); 862*159d09a2SMark Phalan if (*p != '\0') { 863*159d09a2SMark Phalan /* see if we can extract a number */ 864*159d09a2SMark Phalan l = strtol(p, &q, 10); 865*159d09a2SMark Phalan if ((q != NULL) && (q > p)) { 866*159d09a2SMark Phalan /* got a valid number; search for a matchin entry */ 867*159d09a2SMark Phalan for (i = base; padata[i] != NULL; i++) { 868*159d09a2SMark Phalan /* bubble the matching entry to the front of the list */ 869*159d09a2SMark Phalan if (padata[i]->pa_type == l) { 870*159d09a2SMark Phalan tmp = padata[i]; 871*159d09a2SMark Phalan for (j = i; j > base; j--) 872*159d09a2SMark Phalan padata[j] = padata[j - 1]; 873*159d09a2SMark Phalan padata[base] = tmp; 874*159d09a2SMark Phalan base++; 875*159d09a2SMark Phalan break; 876*159d09a2SMark Phalan } 877*159d09a2SMark Phalan } 878*159d09a2SMark Phalan p = q; 879*159d09a2SMark Phalan } else { 880*159d09a2SMark Phalan break; 881*159d09a2SMark Phalan } 882*159d09a2SMark Phalan } 883*159d09a2SMark Phalan } 884*159d09a2SMark Phalan if (need_free_string) 885*159d09a2SMark Phalan free(preauth_types); 886*159d09a2SMark Phalan 887*159d09a2SMark Phalan #ifdef DEBUG 888*159d09a2SMark Phalan fprintf (stderr, "preauth data types after sorting:"); 889*159d09a2SMark Phalan for (i = 0; padata[i]; i++) 890*159d09a2SMark Phalan fprintf (stderr, " %d", padata[i]->pa_type); 891*159d09a2SMark Phalan fprintf (stderr, "\n"); 892*159d09a2SMark Phalan #endif 893*159d09a2SMark Phalan 894*159d09a2SMark Phalan return 0; 895*159d09a2SMark Phalan } 896*159d09a2SMark Phalan 897505d05c7Sgtb krb5_error_code KRB5_CALLCONV 898505d05c7Sgtb krb5_get_init_creds(krb5_context context, 899505d05c7Sgtb krb5_creds *creds, 900505d05c7Sgtb krb5_principal client, 901505d05c7Sgtb krb5_prompter_fct prompter, 902505d05c7Sgtb void *prompter_data, 903505d05c7Sgtb krb5_deltat start_time, 904505d05c7Sgtb char *in_tkt_service, 905*159d09a2SMark Phalan krb5_gic_opt_ext *options, 906505d05c7Sgtb krb5_gic_get_as_key_fct gak_fct, 907505d05c7Sgtb void *gak_data, 908505d05c7Sgtb int *use_master, 909505d05c7Sgtb krb5_kdc_rep **as_reply) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate krb5_error_code ret; 9127c478bd9Sstevel@tonic-gate krb5_kdc_req request; 913*159d09a2SMark Phalan krb5_data *encoded_request_body, *encoded_previous_request; 914*159d09a2SMark Phalan krb5_pa_data **preauth_to_use, **kdc_padata; 9157c478bd9Sstevel@tonic-gate int tempint; 916505d05c7Sgtb char *tempstr = NULL; 917505d05c7Sgtb krb5_deltat tkt_life; 9187c478bd9Sstevel@tonic-gate krb5_deltat renew_life; 9197c478bd9Sstevel@tonic-gate int loopcount; 9207c478bd9Sstevel@tonic-gate krb5_data salt; 9217c478bd9Sstevel@tonic-gate krb5_data s2kparams; 9227c478bd9Sstevel@tonic-gate krb5_keyblock as_key; 9237c478bd9Sstevel@tonic-gate krb5_error *err_reply; 9247c478bd9Sstevel@tonic-gate krb5_kdc_rep *local_as_reply; 9257c478bd9Sstevel@tonic-gate krb5_timestamp time_now; 9267c478bd9Sstevel@tonic-gate krb5_enctype etype = 0; 927*159d09a2SMark Phalan krb5_preauth_client_rock get_data_rock; 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* initialize everything which will be freed at cleanup */ 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate s2kparams.data = NULL; 9327c478bd9Sstevel@tonic-gate s2kparams.length = 0; 9337c478bd9Sstevel@tonic-gate request.server = NULL; 9347c478bd9Sstevel@tonic-gate request.ktype = NULL; 9357c478bd9Sstevel@tonic-gate request.addresses = NULL; 9367c478bd9Sstevel@tonic-gate request.padata = NULL; 937*159d09a2SMark Phalan encoded_request_body = NULL; 938*159d09a2SMark Phalan encoded_previous_request = NULL; 939*159d09a2SMark Phalan preauth_to_use = NULL; 940*159d09a2SMark Phalan kdc_padata = NULL; 941*159d09a2SMark Phalan as_key.length = 0; 9427c478bd9Sstevel@tonic-gate salt.length = 0; 9437c478bd9Sstevel@tonic-gate salt.data = NULL; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate (void) memset(&as_key, 0, sizeof(as_key)); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate local_as_reply = 0; 9487c478bd9Sstevel@tonic-gate 949*159d09a2SMark Phalan err_reply = NULL; 950*159d09a2SMark Phalan 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * Set up the basic request structure 9537c478bd9Sstevel@tonic-gate */ 9547c478bd9Sstevel@tonic-gate request.magic = KV5M_KDC_REQ; 9557c478bd9Sstevel@tonic-gate request.msg_type = KRB5_AS_REQ; 9567c478bd9Sstevel@tonic-gate 957*159d09a2SMark Phalan /* request.nonce is filled in when we send a request to the kdc */ 958*159d09a2SMark Phalan request.nonce = 0; 959*159d09a2SMark Phalan 9607c478bd9Sstevel@tonic-gate /* request.padata is filled in later */ 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate request.kdc_options = context->kdc_default_options; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* forwardable */ 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)) 9677c478bd9Sstevel@tonic-gate tempint = options->forwardable; 9687c478bd9Sstevel@tonic-gate else if ((ret = krb5_libdefault_boolean(context, &client->realm, 9697c478bd9Sstevel@tonic-gate "forwardable", &tempint)) == 0) 9707c478bd9Sstevel@tonic-gate /*EMPTY*/ 9717c478bd9Sstevel@tonic-gate ; 9727c478bd9Sstevel@tonic-gate else 9737c478bd9Sstevel@tonic-gate tempint = 0; 9747c478bd9Sstevel@tonic-gate if (tempint) 9757c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_FORWARDABLE; 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* proxiable */ 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)) 9807c478bd9Sstevel@tonic-gate tempint = options->proxiable; 9817c478bd9Sstevel@tonic-gate else if ((ret = krb5_libdefault_boolean(context, &client->realm, 9827c478bd9Sstevel@tonic-gate "proxiable", &tempint)) == 0) 9837c478bd9Sstevel@tonic-gate /*EMPTY*/ 9847c478bd9Sstevel@tonic-gate ; 9857c478bd9Sstevel@tonic-gate else 9867c478bd9Sstevel@tonic-gate tempint = 0; 9877c478bd9Sstevel@tonic-gate if (tempint) 9887c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_PROXIABLE; 9897c478bd9Sstevel@tonic-gate 990505d05c7Sgtb /* allow_postdate */ 991505d05c7Sgtb 992505d05c7Sgtb if (start_time > 0) 993505d05c7Sgtb request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED); 994505d05c7Sgtb 995505d05c7Sgtb /* ticket lifetime */ 996505d05c7Sgtb 997505d05c7Sgtb if ((ret = krb5_timeofday(context, &request.from))) 998505d05c7Sgtb goto cleanup; 999505d05c7Sgtb request.from = krb5int_addint32(request.from, start_time); 1000505d05c7Sgtb 1001505d05c7Sgtb if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)) { 1002505d05c7Sgtb tkt_life = options->tkt_life; 1003505d05c7Sgtb } else if ((ret = krb5_libdefault_string(context, &client->realm, 1004505d05c7Sgtb "ticket_lifetime", &tempstr)) 1005505d05c7Sgtb == 0) { 1006*159d09a2SMark Phalan ret = krb5_string_to_deltat(tempstr, &tkt_life); 1007505d05c7Sgtb free(tempstr); 1008*159d09a2SMark Phalan if (ret) { 1009505d05c7Sgtb goto cleanup; 1010505d05c7Sgtb } 1011505d05c7Sgtb } else { 1012505d05c7Sgtb /* this used to be hardcoded in kinit.c */ 1013505d05c7Sgtb tkt_life = 24*60*60; 1014505d05c7Sgtb } 1015505d05c7Sgtb request.till = krb5int_addint32(request.from, tkt_life); 1016505d05c7Sgtb 1017505d05c7Sgtb /* renewable lifetime */ 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) { 10207c478bd9Sstevel@tonic-gate renew_life = options->renew_life; 10217c478bd9Sstevel@tonic-gate } else if ((ret = krb5_libdefault_string(context, &client->realm, 10227c478bd9Sstevel@tonic-gate "renew_lifetime", &tempstr)) 10237c478bd9Sstevel@tonic-gate == 0) { 1024*159d09a2SMark Phalan ret = krb5_string_to_deltat(tempstr, &renew_life); 10257c478bd9Sstevel@tonic-gate free(tempstr); 1026*159d09a2SMark Phalan if (ret) { 10277c478bd9Sstevel@tonic-gate goto cleanup; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate } else { 10307c478bd9Sstevel@tonic-gate renew_life = 0; 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate if (renew_life > 0) 10337c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_RENEWABLE; 10347c478bd9Sstevel@tonic-gate 1035505d05c7Sgtb if (renew_life > 0) { 1036505d05c7Sgtb request.rtime = krb5int_addint32(request.from, renew_life); 1037505d05c7Sgtb if (request.rtime < request.till) { 1038505d05c7Sgtb /* don't ask for a smaller renewable time than the lifetime */ 1039505d05c7Sgtb request.rtime = request.till; 1040505d05c7Sgtb } 1041505d05c7Sgtb /* we are already asking for renewable tickets so strip this option */ 1042505d05c7Sgtb request.kdc_options &= ~(KDC_OPT_RENEWABLE_OK); 1043505d05c7Sgtb } else { 1044505d05c7Sgtb request.rtime = 0; 1045505d05c7Sgtb } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* client */ 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate request.client = client; 10507c478bd9Sstevel@tonic-gate 1051505d05c7Sgtb /* service */ 1052505d05c7Sgtb 10537c478bd9Sstevel@tonic-gate if (in_tkt_service) { 10547c478bd9Sstevel@tonic-gate /* this is ugly, because so are the data structures involved. I'm 10557c478bd9Sstevel@tonic-gate in the library, so I'm going to manipulate the data structures 10567c478bd9Sstevel@tonic-gate directly, otherwise, it will be worse. */ 10577c478bd9Sstevel@tonic-gate 1058505d05c7Sgtb if ((ret = krb5_parse_name(context, in_tkt_service, &request.server))) 10597c478bd9Sstevel@tonic-gate goto cleanup; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* stuff the client realm into the server principal. 10627c478bd9Sstevel@tonic-gate realloc if necessary */ 10637c478bd9Sstevel@tonic-gate if (request.server->realm.length < request.client->realm.length) 10647c478bd9Sstevel@tonic-gate if ((request.server->realm.data = 10657c478bd9Sstevel@tonic-gate (char *) realloc(request.server->realm.data, 10667c478bd9Sstevel@tonic-gate request.client->realm.length)) == NULL) { 10677c478bd9Sstevel@tonic-gate ret = ENOMEM; 10687c478bd9Sstevel@tonic-gate goto cleanup; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate request.server->realm.length = request.client->realm.length; 10727c478bd9Sstevel@tonic-gate memcpy(request.server->realm.data, request.client->realm.data, 10737c478bd9Sstevel@tonic-gate request.client->realm.length); 10747c478bd9Sstevel@tonic-gate } else { 1075505d05c7Sgtb if ((ret = krb5_build_principal_ext(context, &request.server, 10767c478bd9Sstevel@tonic-gate request.client->realm.length, 10777c478bd9Sstevel@tonic-gate request.client->realm.data, 10787c478bd9Sstevel@tonic-gate KRB5_TGS_NAME_SIZE, 10797c478bd9Sstevel@tonic-gate KRB5_TGS_NAME, 10807c478bd9Sstevel@tonic-gate request.client->realm.length, 10817c478bd9Sstevel@tonic-gate request.client->realm.data, 1082505d05c7Sgtb 0))) 10837c478bd9Sstevel@tonic-gate goto cleanup; 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 1086*159d09a2SMark Phalan krb5_preauth_request_context_init(context); 1087*159d09a2SMark Phalan 1088*159d09a2SMark Phalan /* nonce is filled in by send_as_request if we don't take care of it */ 10897c478bd9Sstevel@tonic-gate 10907c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) { 10917c478bd9Sstevel@tonic-gate request.ktype = options->etype_list; 10927c478bd9Sstevel@tonic-gate request.nktypes = options->etype_list_length; 10937c478bd9Sstevel@tonic-gate } else if ((ret = krb5_get_default_in_tkt_ktypes(context, 10947c478bd9Sstevel@tonic-gate &request.ktype)) == 0) { 10957c478bd9Sstevel@tonic-gate for (request.nktypes = 0; 10967c478bd9Sstevel@tonic-gate request.ktype[request.nktypes]; 10977c478bd9Sstevel@tonic-gate request.nktypes++) 10987c478bd9Sstevel@tonic-gate ; 10997c478bd9Sstevel@tonic-gate } else { 11007c478bd9Sstevel@tonic-gate /* there isn't any useful default here. ret is set from above */ 11017c478bd9Sstevel@tonic-gate goto cleanup; 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) { 11057c478bd9Sstevel@tonic-gate request.addresses = options->address_list; 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate /* it would be nice if this parsed out an address list, but 11087c478bd9Sstevel@tonic-gate that would be work. */ 11097c478bd9Sstevel@tonic-gate else if (((ret = krb5_libdefault_boolean(context, &client->realm, 11107c478bd9Sstevel@tonic-gate "no_addresses", &tempint)) == 0) 1111505d05c7Sgtb || (tempint == 1)) { 11127c478bd9Sstevel@tonic-gate /*EMPTY*/ 11137c478bd9Sstevel@tonic-gate ; 11147c478bd9Sstevel@tonic-gate } else if (((ret = krb5_libdefault_boolean(context, &client->realm, 11157c478bd9Sstevel@tonic-gate "noaddresses", &tempint)) == 0) 1116505d05c7Sgtb || (tempint == 1)) { 11177c478bd9Sstevel@tonic-gate /*EMPTY*/ 11187c478bd9Sstevel@tonic-gate ; 11197c478bd9Sstevel@tonic-gate } else { 11207c478bd9Sstevel@tonic-gate if ((ret = krb5_os_localaddr(context, &request.addresses))) 11217c478bd9Sstevel@tonic-gate goto cleanup; 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate request.authorization_data.ciphertext.length = 0; 11257c478bd9Sstevel@tonic-gate request.authorization_data.ciphertext.data = 0; 11267c478bd9Sstevel@tonic-gate request.unenc_authdata = 0; 11277c478bd9Sstevel@tonic-gate request.second_ticket = 0; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* set up the other state. */ 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) { 1132505d05c7Sgtb if ((ret = make_preauth_list(context, options->preauth_list, 11337c478bd9Sstevel@tonic-gate options->preauth_list_length, 1134*159d09a2SMark Phalan &preauth_to_use))) 11357c478bd9Sstevel@tonic-gate goto cleanup; 11367c478bd9Sstevel@tonic-gate } 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate /* the salt is allocated from somewhere, unless it is from the caller, 11397c478bd9Sstevel@tonic-gate then it is a reference */ 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) { 11427c478bd9Sstevel@tonic-gate salt = *options->salt; 11437c478bd9Sstevel@tonic-gate } else { 1144*159d09a2SMark Phalan salt.length = SALT_TYPE_AFS_LENGTH; 11457c478bd9Sstevel@tonic-gate salt.data = NULL; 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate 1149*159d09a2SMark Phalan /* set the request nonce */ 1150*159d09a2SMark Phalan if ((ret = krb5_timeofday(context, &time_now))) 1151*159d09a2SMark Phalan goto cleanup; 1152*159d09a2SMark Phalan /* 1153*159d09a2SMark Phalan * XXX we know they are the same size... and we should do 1154*159d09a2SMark Phalan * something better than just the current time 1155*159d09a2SMark Phalan */ 1156*159d09a2SMark Phalan request.nonce = (krb5_int32) time_now; 1157*159d09a2SMark Phalan 1158*159d09a2SMark Phalan /* give the preauth plugins a chance to prep the request body */ 1159*159d09a2SMark Phalan krb5_preauth_prepare_request(context, options, &request); 1160*159d09a2SMark Phalan ret = encode_krb5_kdc_req_body(&request, &encoded_request_body); 1161*159d09a2SMark Phalan if (ret) 1162*159d09a2SMark Phalan goto cleanup; 1163*159d09a2SMark Phalan 1164*159d09a2SMark Phalan get_data_rock.magic = CLIENT_ROCK_MAGIC; 1165*159d09a2SMark Phalan get_data_rock.as_reply = NULL; 1166*159d09a2SMark Phalan 1167*159d09a2SMark Phalan /* now, loop processing preauth data and talking to the kdc */ 11687c478bd9Sstevel@tonic-gate for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) { 11697c478bd9Sstevel@tonic-gate if (request.padata) { 11707c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, request.padata); 11717c478bd9Sstevel@tonic-gate request.padata = NULL; 11727c478bd9Sstevel@tonic-gate } 1173*159d09a2SMark Phalan if (!err_reply) { 1174*159d09a2SMark Phalan /* either our first attempt, or retrying after PREAUTH_NEEDED */ 1175*159d09a2SMark Phalan if ((ret = krb5_do_preauth(context, 1176*159d09a2SMark Phalan &request, 1177*159d09a2SMark Phalan encoded_request_body, 1178*159d09a2SMark Phalan encoded_previous_request, 1179*159d09a2SMark Phalan preauth_to_use, &request.padata, 1180*159d09a2SMark Phalan &salt, &s2kparams, &etype, &as_key, 1181*159d09a2SMark Phalan prompter, prompter_data, 1182*159d09a2SMark Phalan gak_fct, gak_data, 1183*159d09a2SMark Phalan &get_data_rock, options))) 11847c478bd9Sstevel@tonic-gate goto cleanup; 1185*159d09a2SMark Phalan } else { 1186*159d09a2SMark Phalan if (preauth_to_use != NULL) { 1187*159d09a2SMark Phalan /* 1188*159d09a2SMark Phalan * Retry after an error other than PREAUTH_NEEDED, 1189*159d09a2SMark Phalan * using e-data to figure out what to change. 1190*159d09a2SMark Phalan */ 1191*159d09a2SMark Phalan ret = krb5_do_preauth_tryagain(context, 1192*159d09a2SMark Phalan &request, 1193*159d09a2SMark Phalan encoded_request_body, 1194*159d09a2SMark Phalan encoded_previous_request, 1195*159d09a2SMark Phalan preauth_to_use, &request.padata, 1196*159d09a2SMark Phalan err_reply, 1197*159d09a2SMark Phalan &salt, &s2kparams, &etype, 1198*159d09a2SMark Phalan &as_key, 1199*159d09a2SMark Phalan prompter, prompter_data, 1200*159d09a2SMark Phalan gak_fct, gak_data, 1201*159d09a2SMark Phalan &get_data_rock, options); 1202*159d09a2SMark Phalan } else { 1203*159d09a2SMark Phalan /* No preauth supplied, so can't query the plug-ins. */ 1204*159d09a2SMark Phalan ret = KRB5KRB_ERR_GENERIC; 12057c478bd9Sstevel@tonic-gate } 1206*159d09a2SMark Phalan if (ret) { 1207*159d09a2SMark Phalan /* couldn't come up with anything better */ 1208*159d09a2SMark Phalan ret = err_reply->error + ERROR_TABLE_BASE_krb5; 1209*159d09a2SMark Phalan } 1210*159d09a2SMark Phalan krb5_free_error(context, err_reply); 1211*159d09a2SMark Phalan err_reply = NULL; 1212*159d09a2SMark Phalan if (ret) 1213*159d09a2SMark Phalan goto cleanup; 1214*159d09a2SMark Phalan } 1215*159d09a2SMark Phalan 1216*159d09a2SMark Phalan if (encoded_previous_request != NULL) { 1217*159d09a2SMark Phalan krb5_free_data(context, encoded_previous_request); 1218*159d09a2SMark Phalan encoded_previous_request = NULL; 1219*159d09a2SMark Phalan } 1220*159d09a2SMark Phalan ret = encode_krb5_as_req(&request, &encoded_previous_request); 1221*159d09a2SMark Phalan if (ret) 1222*159d09a2SMark Phalan goto cleanup; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate err_reply = 0; 12257c478bd9Sstevel@tonic-gate local_as_reply = 0; 1226*159d09a2SMark Phalan if ((ret = send_as_request(context, &request, &err_reply, 12277c478bd9Sstevel@tonic-gate &local_as_reply, use_master))) 12287c478bd9Sstevel@tonic-gate goto cleanup; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate if (err_reply) { 12317c478bd9Sstevel@tonic-gate if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED && 12327c478bd9Sstevel@tonic-gate err_reply->e_data.length > 0) { 1233*159d09a2SMark Phalan /* reset the list of preauth types to try */ 1234*159d09a2SMark Phalan if (preauth_to_use) { 1235*159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 1236*159d09a2SMark Phalan preauth_to_use = NULL; 1237*159d09a2SMark Phalan } 12387c478bd9Sstevel@tonic-gate ret = decode_krb5_padata_sequence(&err_reply->e_data, 1239*159d09a2SMark Phalan &preauth_to_use); 12407c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1241*159d09a2SMark Phalan err_reply = NULL; 12427c478bd9Sstevel@tonic-gate if (ret) 12437c478bd9Sstevel@tonic-gate goto cleanup; 1244*159d09a2SMark Phalan ret = sort_krb5_padata_sequence(context, 1245*159d09a2SMark Phalan &request.server->realm, 1246*159d09a2SMark Phalan preauth_to_use); 1247*159d09a2SMark Phalan if (ret) 1248*159d09a2SMark Phalan goto cleanup; 1249*159d09a2SMark Phalan /* continue to next iteration */ 12507c478bd9Sstevel@tonic-gate } else { 1251*159d09a2SMark Phalan if (err_reply->e_data.length > 0) { 1252*159d09a2SMark Phalan /* continue to next iteration */ 1253*159d09a2SMark Phalan } else { 1254*159d09a2SMark Phalan /* error + no hints = give up */ 1255505d05c7Sgtb ret = (krb5_error_code) err_reply->error 1256505d05c7Sgtb + ERROR_TABLE_BASE_krb5; 12577c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 12587c478bd9Sstevel@tonic-gate goto cleanup; 12597c478bd9Sstevel@tonic-gate } 1260*159d09a2SMark Phalan } 12617c478bd9Sstevel@tonic-gate } else if (local_as_reply) { 12627c478bd9Sstevel@tonic-gate break; 12637c478bd9Sstevel@tonic-gate } else { 12647c478bd9Sstevel@tonic-gate ret = KRB5KRB_AP_ERR_MSG_TYPE; 12657c478bd9Sstevel@tonic-gate goto cleanup; 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate if (loopcount == MAX_IN_TKT_LOOPS) { 12707c478bd9Sstevel@tonic-gate ret = KRB5_GET_IN_TKT_LOOP; 12717c478bd9Sstevel@tonic-gate goto cleanup; 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate /* process any preauth data in the as_reply */ 1275*159d09a2SMark Phalan krb5_clear_preauth_context_use_counts(context); 1276*159d09a2SMark Phalan if ((ret = sort_krb5_padata_sequence(context, &request.server->realm, 1277*159d09a2SMark Phalan local_as_reply->padata))) 12787c478bd9Sstevel@tonic-gate goto cleanup; 1279*159d09a2SMark Phalan get_data_rock.as_reply = local_as_reply; 1280*159d09a2SMark Phalan if ((ret = krb5_do_preauth(context, 1281*159d09a2SMark Phalan &request, 1282*159d09a2SMark Phalan encoded_request_body, encoded_previous_request, 1283*159d09a2SMark Phalan local_as_reply->padata, &kdc_padata, 1284*159d09a2SMark Phalan &salt, &s2kparams, &etype, &as_key, prompter, 1285*159d09a2SMark Phalan prompter_data, gak_fct, gak_data, 1286*159d09a2SMark Phalan &get_data_rock, options))) 1287*159d09a2SMark Phalan goto cleanup; 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY, 12907c478bd9Sstevel@tonic-gate the AS_REP comes back encrypted in the user's longterm key 12917c478bd9Sstevel@tonic-gate instead of in the SAD. If there was a SAM preauth, there 12927c478bd9Sstevel@tonic-gate will be an as_key here which will be the SAD. If that fails, 12937c478bd9Sstevel@tonic-gate use the gak_fct to get the password, and try again. */ 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate /* XXX because etypes are handled poorly (particularly wrt SAM, 12967c478bd9Sstevel@tonic-gate where the etype is fixed by the kdc), we may want to try 12977c478bd9Sstevel@tonic-gate decrypt_as_reply twice. If there's an as_key available, try 12987c478bd9Sstevel@tonic-gate it. If decrypting the as_rep fails, or if there isn't an 12997c478bd9Sstevel@tonic-gate as_key at all yet, then use the gak_fct to get one, and try 13007c478bd9Sstevel@tonic-gate again. */ 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate if (as_key.length) 1303*159d09a2SMark Phalan ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, 1304*159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc, 1305*159d09a2SMark Phalan NULL); 13067c478bd9Sstevel@tonic-gate else 13077c478bd9Sstevel@tonic-gate ret = -1; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (ret) { 13107c478bd9Sstevel@tonic-gate /* if we haven't get gotten a key, get it now */ 13117c478bd9Sstevel@tonic-gate 1312505d05c7Sgtb if ((ret = ((*gak_fct)(context, request.client, 13137c478bd9Sstevel@tonic-gate local_as_reply->enc_part.enctype, 13147c478bd9Sstevel@tonic-gate prompter, prompter_data, &salt, &s2kparams, 1315505d05c7Sgtb &as_key, gak_data)))) 13167c478bd9Sstevel@tonic-gate goto cleanup; 13177c478bd9Sstevel@tonic-gate 1318*159d09a2SMark Phalan if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, 1319*159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc, 1320*159d09a2SMark Phalan NULL))) 13217c478bd9Sstevel@tonic-gate goto cleanup; 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 1324505d05c7Sgtb if ((ret = verify_as_reply(context, time_now, &request, local_as_reply))) 13257c478bd9Sstevel@tonic-gate goto cleanup; 13267c478bd9Sstevel@tonic-gate 1327*159d09a2SMark Phalan /* XXX this should be inside stash_as_reply, but as long as 1328*159d09a2SMark Phalan get_in_tkt is still around using that arg as an in/out, I can't 1329*159d09a2SMark Phalan do that */ 1330*159d09a2SMark Phalan /* Solaris Kerberos */ 13317c478bd9Sstevel@tonic-gate (void) memset(creds, 0, sizeof(*creds)); 13327c478bd9Sstevel@tonic-gate 1333*159d09a2SMark Phalan /* Solaris Kerberos */ 1334505d05c7Sgtb if ((ret = stash_as_reply(context, time_now, &request, local_as_reply, 1335505d05c7Sgtb creds, (krb5_ccache)NULL))) 13367c478bd9Sstevel@tonic-gate goto cleanup; 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate /* success */ 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate ret = 0; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate cleanup: 1343*159d09a2SMark Phalan krb5_preauth_request_context_fini(context); 1344*159d09a2SMark Phalan if (encoded_previous_request != NULL) { 1345*159d09a2SMark Phalan krb5_free_data(context, encoded_previous_request); 1346*159d09a2SMark Phalan encoded_previous_request = NULL; 1347*159d09a2SMark Phalan } 1348*159d09a2SMark Phalan if (encoded_request_body != NULL) { 1349*159d09a2SMark Phalan krb5_free_data(context, encoded_request_body); 1350*159d09a2SMark Phalan encoded_request_body = NULL; 1351*159d09a2SMark Phalan } 13527c478bd9Sstevel@tonic-gate if (request.server) 13537c478bd9Sstevel@tonic-gate krb5_free_principal(context, request.server); 13547c478bd9Sstevel@tonic-gate if (request.ktype && 13557c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)))) 13567c478bd9Sstevel@tonic-gate free(request.ktype); 13577c478bd9Sstevel@tonic-gate if (request.addresses && 13587c478bd9Sstevel@tonic-gate (!(options && 13597c478bd9Sstevel@tonic-gate (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)))) 13607c478bd9Sstevel@tonic-gate krb5_free_addresses(context, request.addresses); 1361*159d09a2SMark Phalan if (preauth_to_use) 1362*159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 1363*159d09a2SMark Phalan if (kdc_padata) 1364*159d09a2SMark Phalan krb5_free_pa_data(context, kdc_padata); 13657c478bd9Sstevel@tonic-gate if (request.padata) 13667c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, request.padata); 13677c478bd9Sstevel@tonic-gate if (as_key.length) 13687c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &as_key); 13697c478bd9Sstevel@tonic-gate if (salt.data && 13707c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)))) 13717c478bd9Sstevel@tonic-gate krb5_xfree(salt.data); 1372505d05c7Sgtb krb5_free_data_contents(context, &s2kparams); 13737c478bd9Sstevel@tonic-gate if (as_reply) 13747c478bd9Sstevel@tonic-gate *as_reply = local_as_reply; 13757c478bd9Sstevel@tonic-gate else if (local_as_reply) 13767c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, local_as_reply); 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate return(ret); 13797c478bd9Sstevel@tonic-gate } 1380