17c478bd9Sstevel@tonic-gate /* 2*12b65585SGordon Ross * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 3*12b65585SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 4*12b65585SGordon Ross */ 57c478bd9Sstevel@tonic-gate /* 67c478bd9Sstevel@tonic-gate * lib/krb5/krb/get_in_tkt.c 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * Copyright 1990,1991, 2003 by the Massachusetts Institute of Technology. 97c478bd9Sstevel@tonic-gate * All Rights Reserved. 107c478bd9Sstevel@tonic-gate * 117c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 127c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 137c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 147c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 157c478bd9Sstevel@tonic-gate * 167c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 177c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 187c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 197c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 207c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 217c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 227c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 237c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 247c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 257c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 267c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 277c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 287c478bd9Sstevel@tonic-gate * or implied warranty. 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * krb5_get_in_tkt() 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <string.h> 355e01956fSGlenn Barry #include <ctype.h> 36159d09a2SMark Phalan #include "k5-int.h" 37159d09a2SMark Phalan #include "int-proto.h" 38159d09a2SMark Phalan #include "os-proto.h" 395e01956fSGlenn Barry #include <locale.h> 405e01956fSGlenn Barry #include <syslog.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 70159d09a2SMark 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 ***); 89159d09a2SMark Phalan static krb5_error_code sort_krb5_padata_sequence(krb5_context context, 90159d09a2SMark Phalan krb5_data *realm, 91159d09a2SMark 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 1175e01956fSGlenn Barry send_as_request2(krb5_context context, 118505d05c7Sgtb krb5_kdc_req *request, 119505d05c7Sgtb krb5_error ** ret_err_reply, 120505d05c7Sgtb krb5_kdc_rep ** ret_as_reply, 1215e01956fSGlenn Barry int *use_master, 1225e01956fSGlenn Barry char **hostname_used) 1235e01956fSGlenn Barry 1247c478bd9Sstevel@tonic-gate { 1257c478bd9Sstevel@tonic-gate krb5_kdc_rep *as_reply = 0; 1267c478bd9Sstevel@tonic-gate krb5_error_code retval; 1277c478bd9Sstevel@tonic-gate krb5_data *packet = 0; 1287c478bd9Sstevel@tonic-gate krb5_data reply; 1297c478bd9Sstevel@tonic-gate char k4_version; /* same type as *(krb5_data::data) */ 1307c478bd9Sstevel@tonic-gate int tcp_only = 0; 131159d09a2SMark Phalan krb5_timestamp time_now; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate reply.data = 0; 1347c478bd9Sstevel@tonic-gate 135*12b65585SGordon Ross /* Solaris Kerberos (illumos) */ 136*12b65585SGordon Ross if (krb5_getenv("MS_INTEROP")) { 137*12b65585SGordon Ross /* Don't bother with UDP. */ 138*12b65585SGordon Ross tcp_only = 1; 139*12b65585SGordon Ross } 140*12b65585SGordon Ross 141159d09a2SMark Phalan /* set the nonce if the caller expects us to do it */ 142159d09a2SMark Phalan if (request->nonce == 0) { 143159d09a2SMark Phalan if ((retval = krb5_timeofday(context, &time_now))) 1447c478bd9Sstevel@tonic-gate goto cleanup; 145159d09a2SMark Phalan request->nonce = (krb5_int32) time_now; 146159d09a2SMark Phalan } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* encode & send to KDC */ 1497c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_as_req(request, &packet)) != 0) 1507c478bd9Sstevel@tonic-gate goto cleanup; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate k4_version = packet->data[0]; 1537c478bd9Sstevel@tonic-gate send_again: 1545e01956fSGlenn Barry retval = krb5_sendto_kdc2(context, packet, 1557c478bd9Sstevel@tonic-gate krb5_princ_realm(context, request->client), 1565e01956fSGlenn Barry &reply, use_master, tcp_only, hostname_used); 1577c478bd9Sstevel@tonic-gate if (retval) 1587c478bd9Sstevel@tonic-gate goto cleanup; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* now decode the reply...could be error or as_rep */ 1617c478bd9Sstevel@tonic-gate if (krb5_is_krb_error(&reply)) { 1627c478bd9Sstevel@tonic-gate krb5_error *err_reply; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_error(&reply, &err_reply))) 1657c478bd9Sstevel@tonic-gate /* some other error code--??? */ 1667c478bd9Sstevel@tonic-gate goto cleanup; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (ret_err_reply) { 1697c478bd9Sstevel@tonic-gate if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG 1707c478bd9Sstevel@tonic-gate && tcp_only == 0) { 1717c478bd9Sstevel@tonic-gate tcp_only = 1; 1727c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1737c478bd9Sstevel@tonic-gate free(reply.data); 1747c478bd9Sstevel@tonic-gate reply.data = 0; 1757c478bd9Sstevel@tonic-gate goto send_again; 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate *ret_err_reply = err_reply; 1785e01956fSGlenn Barry } else { 1797c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1805e01956fSGlenn Barry err_reply = NULL; 1815e01956fSGlenn Barry } 1827c478bd9Sstevel@tonic-gate goto cleanup; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Check to make sure it isn't a V4 reply. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate if (!krb5_is_as_rep(&reply)) { 1897c478bd9Sstevel@tonic-gate /* these are in <kerberosIV/prot.h> as well but it isn't worth including. */ 1907c478bd9Sstevel@tonic-gate #define V4_KRB_PROT_VERSION 4 1917c478bd9Sstevel@tonic-gate #define V4_AUTH_MSG_ERR_REPLY (5<<1) 1927c478bd9Sstevel@tonic-gate /* check here for V4 reply */ 1937c478bd9Sstevel@tonic-gate unsigned int t_switch; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* From v4 g_in_tkt.c: This used to be 1967c478bd9Sstevel@tonic-gate switch (pkt_msg_type(rpkt) & ~1) { 1977c478bd9Sstevel@tonic-gate but SCO 3.2v4 cc compiled that incorrectly. */ 1987c478bd9Sstevel@tonic-gate t_switch = reply.data[1]; 1997c478bd9Sstevel@tonic-gate t_switch &= ~1; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (t_switch == V4_AUTH_MSG_ERR_REPLY 2027c478bd9Sstevel@tonic-gate && (reply.data[0] == V4_KRB_PROT_VERSION 2037c478bd9Sstevel@tonic-gate || reply.data[0] == k4_version)) { 2047c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_V4_REPLY; 2057c478bd9Sstevel@tonic-gate } else { 2067c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_MSG_TYPE; 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate goto cleanup; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* It must be a KRB_AS_REP message, or an bad returned packet */ 2127c478bd9Sstevel@tonic-gate if ((retval = decode_krb5_as_rep(&reply, &as_reply))) 2137c478bd9Sstevel@tonic-gate /* some other error code ??? */ 2147c478bd9Sstevel@tonic-gate goto cleanup; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate if (as_reply->msg_type != KRB5_AS_REP) { 2177c478bd9Sstevel@tonic-gate retval = KRB5KRB_AP_ERR_MSG_TYPE; 2187c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, as_reply); 2197c478bd9Sstevel@tonic-gate goto cleanup; 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (ret_as_reply) 2237c478bd9Sstevel@tonic-gate *ret_as_reply = as_reply; 2247c478bd9Sstevel@tonic-gate else 2257c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, as_reply); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate cleanup: 2287c478bd9Sstevel@tonic-gate if (packet) 2297c478bd9Sstevel@tonic-gate krb5_free_data(context, packet); 2307c478bd9Sstevel@tonic-gate if (reply.data) 2317c478bd9Sstevel@tonic-gate free(reply.data); 2327c478bd9Sstevel@tonic-gate return retval; 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate static krb5_error_code 2365e01956fSGlenn Barry send_as_request(krb5_context context, 2375e01956fSGlenn Barry krb5_kdc_req *request, 2385e01956fSGlenn Barry krb5_error ** ret_err_reply, 2395e01956fSGlenn Barry krb5_kdc_rep ** ret_as_reply, 2405e01956fSGlenn Barry int *use_master) 2415e01956fSGlenn Barry { 2425e01956fSGlenn Barry return send_as_request2(context, 2435e01956fSGlenn Barry request, 2445e01956fSGlenn Barry ret_err_reply, 2455e01956fSGlenn Barry ret_as_reply, 2465e01956fSGlenn Barry use_master, 2475e01956fSGlenn Barry NULL); 2485e01956fSGlenn Barry } 2495e01956fSGlenn Barry 2505e01956fSGlenn Barry static krb5_error_code 251505d05c7Sgtb decrypt_as_reply(krb5_context context, 252505d05c7Sgtb krb5_kdc_req *request, 253505d05c7Sgtb krb5_kdc_rep *as_reply, 254505d05c7Sgtb git_key_proc key_proc, 255505d05c7Sgtb krb5_const_pointer keyseed, 256505d05c7Sgtb krb5_keyblock * key, 257505d05c7Sgtb git_decrypt_proc decrypt_proc, 258505d05c7Sgtb krb5_const_pointer decryptarg) 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate krb5_error_code retval; 2617c478bd9Sstevel@tonic-gate krb5_keyblock * decrypt_key = 0; 2627c478bd9Sstevel@tonic-gate krb5_data salt; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate if (as_reply->enc_part2) 2657c478bd9Sstevel@tonic-gate return 0; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (key) 2687c478bd9Sstevel@tonic-gate decrypt_key = key; 269159d09a2SMark Phalan /* Solaris Kerberos */ 2707c478bd9Sstevel@tonic-gate else if (request != NULL) { 2717c478bd9Sstevel@tonic-gate if ((retval = krb5_principal2salt(context, request->client, &salt))) 2727c478bd9Sstevel@tonic-gate return(retval); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate retval = (*key_proc)(context, as_reply->enc_part.enctype, 2757c478bd9Sstevel@tonic-gate &salt, keyseed, &decrypt_key); 2767c478bd9Sstevel@tonic-gate krb5_xfree(salt.data); 2777c478bd9Sstevel@tonic-gate if (retval) 2787c478bd9Sstevel@tonic-gate goto cleanup; 2797c478bd9Sstevel@tonic-gate } else { 2807c478bd9Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, " 2817c478bd9Sstevel@tonic-gate "error key == NULL and request == NULL"); 2827c478bd9Sstevel@tonic-gate return (EINVAL); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 285159d09a2SMark Phalan /* 286159d09a2SMark Phalan * Solaris kerberos: Overwriting the decrypt_key->enctype because the 2877c478bd9Sstevel@tonic-gate * decrypt key's enctype may not be an exact match with the enctype that the 2887c478bd9Sstevel@tonic-gate * KDC used to encrypt this part of the AS reply. This assumes the 2897c478bd9Sstevel@tonic-gate * as_reply->enc_part.enctype has been validated which is done by checking 2907c478bd9Sstevel@tonic-gate * to see if the enctype that the KDC sent back in the as_reply is one of 2917c478bd9Sstevel@tonic-gate * the enctypes originally requested. Note, if request is NULL then the 2927c478bd9Sstevel@tonic-gate * as_reply->enc_part.enctype could not be validated. 2937c478bd9Sstevel@tonic-gate */ 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (request != NULL) { 2967c478bd9Sstevel@tonic-gate if (is_in_keytype(request->ktype, request->nktypes, 2977c478bd9Sstevel@tonic-gate as_reply->enc_part.enctype)) { 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate decrypt_key->enctype = as_reply->enc_part.enctype; 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate } else { 3027c478bd9Sstevel@tonic-gate KRB5_LOG0(KRB5_ERR, "decrypt_as_reply() end, " 3037c478bd9Sstevel@tonic-gate "error is_in_keytype() returned false"); 3047c478bd9Sstevel@tonic-gate retval = KRB5_BAD_ENCTYPE; 3057c478bd9Sstevel@tonic-gate goto cleanup; 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate if ((retval = (*decrypt_proc)(context, decrypt_key, decryptarg, as_reply))){ 3107c478bd9Sstevel@tonic-gate KRB5_LOG(KRB5_ERR, "decrypt_as_reply() error (*decrypt_proc)() retval " 3117c478bd9Sstevel@tonic-gate "= %d", retval); 3127c478bd9Sstevel@tonic-gate goto cleanup; 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate cleanup: 3167c478bd9Sstevel@tonic-gate if (!key && decrypt_key) 3177c478bd9Sstevel@tonic-gate krb5_free_keyblock(context, decrypt_key); 3187c478bd9Sstevel@tonic-gate return (retval); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate static krb5_error_code 322505d05c7Sgtb verify_as_reply(krb5_context context, 323505d05c7Sgtb krb5_timestamp time_now, 324505d05c7Sgtb krb5_kdc_req *request, 325505d05c7Sgtb krb5_kdc_rep *as_reply) 3267c478bd9Sstevel@tonic-gate { 3277c478bd9Sstevel@tonic-gate krb5_error_code retval; 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* check the contents for sanity: */ 3307c478bd9Sstevel@tonic-gate if (!as_reply->enc_part2->times.starttime) 3317c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.starttime = 3327c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.authtime; 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (!krb5_principal_compare(context, as_reply->client, request->client) 3357c478bd9Sstevel@tonic-gate || !krb5_principal_compare(context, as_reply->enc_part2->server, request->server) 3367c478bd9Sstevel@tonic-gate || !krb5_principal_compare(context, as_reply->ticket->server, request->server) 3377c478bd9Sstevel@tonic-gate || (request->nonce != as_reply->enc_part2->nonce) 3387c478bd9Sstevel@tonic-gate /* XXX check for extraneous flags */ 3397c478bd9Sstevel@tonic-gate /* XXX || (!krb5_addresses_compare(context, addrs, as_reply->enc_part2->caddrs)) */ 3407c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_POSTDATED) && 3417c478bd9Sstevel@tonic-gate (request->from != 0) && 3427c478bd9Sstevel@tonic-gate (request->from != as_reply->enc_part2->times.starttime)) 3437c478bd9Sstevel@tonic-gate || ((request->till != 0) && 3447c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.endtime > request->till)) 3457c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_RENEWABLE) && 3463441f6a1Ssemery /* 3473441f6a1Ssemery * Solaris Kerberos: Here we error only if renewable_ok was not set. 3483441f6a1Ssemery */ 3493441f6a1Ssemery !(request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3503441f6a1Ssemery (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3517c478bd9Sstevel@tonic-gate (request->rtime != 0) && 3527c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.renew_till > request->rtime)) 3537c478bd9Sstevel@tonic-gate || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3547c478bd9Sstevel@tonic-gate !(request->kdc_options & KDC_OPT_RENEWABLE) && 3557c478bd9Sstevel@tonic-gate (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3567c478bd9Sstevel@tonic-gate (request->till != 0) && 3577c478bd9Sstevel@tonic-gate (as_reply->enc_part2->times.renew_till > request->till)) 3583441f6a1Ssemery /* 3593441f6a1Ssemery * Solaris Kerberos: renew_till should never be greater than till or 3603441f6a1Ssemery * rtime. 3613441f6a1Ssemery */ 3623441f6a1Ssemery || ((request->kdc_options & KDC_OPT_RENEWABLE_OK) && 3633441f6a1Ssemery (as_reply->enc_part2->flags & KDC_OPT_RENEWABLE) && 3643441f6a1Ssemery (request->till != 0) && 3653441f6a1Ssemery (request->rtime != 0) && 3663441f6a1Ssemery (as_reply->enc_part2->times.renew_till > max(request->till, 3673441f6a1Ssemery request->rtime))) 3687c478bd9Sstevel@tonic-gate ) 3697c478bd9Sstevel@tonic-gate return KRB5_KDCREP_MODIFIED; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME) { 3727c478bd9Sstevel@tonic-gate retval = krb5_set_real_time(context, 3737c478bd9Sstevel@tonic-gate as_reply->enc_part2->times.authtime, 0); 3747c478bd9Sstevel@tonic-gate if (retval) 3757c478bd9Sstevel@tonic-gate return retval; 3767c478bd9Sstevel@tonic-gate } else { 3777c478bd9Sstevel@tonic-gate if ((request->from == 0) && 3787c478bd9Sstevel@tonic-gate (labs(as_reply->enc_part2->times.starttime - time_now) 3797c478bd9Sstevel@tonic-gate > context->clockskew)) 3807c478bd9Sstevel@tonic-gate return (KRB5_KDCREP_SKEW); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate return 0; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3867c478bd9Sstevel@tonic-gate static krb5_error_code 387505d05c7Sgtb stash_as_reply(krb5_context context, 388505d05c7Sgtb krb5_timestamp time_now, 389505d05c7Sgtb krb5_kdc_req *request, 390505d05c7Sgtb krb5_kdc_rep *as_reply, 391505d05c7Sgtb krb5_creds * creds, 392505d05c7Sgtb krb5_ccache ccache) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate krb5_error_code retval; 3957c478bd9Sstevel@tonic-gate krb5_data * packet; 3967c478bd9Sstevel@tonic-gate krb5_principal client; 3977c478bd9Sstevel@tonic-gate krb5_principal server; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate client = NULL; 4007c478bd9Sstevel@tonic-gate server = NULL; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate if (!creds->client) 403505d05c7Sgtb if ((retval = krb5_copy_principal(context, as_reply->client, &client))) 4047c478bd9Sstevel@tonic-gate goto cleanup; 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate if (!creds->server) 407505d05c7Sgtb if ((retval = krb5_copy_principal(context, as_reply->enc_part2->server, 408505d05c7Sgtb &server))) 4097c478bd9Sstevel@tonic-gate goto cleanup; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* fill in the credentials */ 4127c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_keyblock_contents(context, 4137c478bd9Sstevel@tonic-gate as_reply->enc_part2->session, 4147c478bd9Sstevel@tonic-gate &creds->keyblock))) 4157c478bd9Sstevel@tonic-gate goto cleanup; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate creds->times = as_reply->enc_part2->times; 4187c478bd9Sstevel@tonic-gate creds->is_skey = FALSE; /* this is an AS_REQ, so cannot 4197c478bd9Sstevel@tonic-gate be encrypted in skey */ 4207c478bd9Sstevel@tonic-gate creds->ticket_flags = as_reply->enc_part2->flags; 4217c478bd9Sstevel@tonic-gate if ((retval = krb5_copy_addresses(context, as_reply->enc_part2->caddrs, 4227c478bd9Sstevel@tonic-gate &creds->addresses))) 4237c478bd9Sstevel@tonic-gate goto cleanup; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate creds->second_ticket.length = 0; 4267c478bd9Sstevel@tonic-gate creds->second_ticket.data = 0; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate if ((retval = encode_krb5_ticket(as_reply->ticket, &packet))) 4297c478bd9Sstevel@tonic-gate goto cleanup; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate creds->ticket = *packet; 4327c478bd9Sstevel@tonic-gate krb5_xfree(packet); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* store it in the ccache! */ 435159d09a2SMark Phalan if (ccache) /* Solaris Kerberos */ 4367c478bd9Sstevel@tonic-gate if ((retval = krb5_cc_store_cred(context, ccache, creds)) !=0) 4377c478bd9Sstevel@tonic-gate goto cleanup; 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if (!creds->client) 4407c478bd9Sstevel@tonic-gate creds->client = client; 4417c478bd9Sstevel@tonic-gate if (!creds->server) 4427c478bd9Sstevel@tonic-gate creds->server = server; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate cleanup: 4457c478bd9Sstevel@tonic-gate if (retval) { 4467c478bd9Sstevel@tonic-gate if (client) 4477c478bd9Sstevel@tonic-gate krb5_free_principal(context, client); 4487c478bd9Sstevel@tonic-gate if (server) 4497c478bd9Sstevel@tonic-gate krb5_free_principal(context, server); 4507c478bd9Sstevel@tonic-gate if (creds->keyblock.contents) { 4517c478bd9Sstevel@tonic-gate memset((char *)creds->keyblock.contents, 0, 4527c478bd9Sstevel@tonic-gate creds->keyblock.length); 4537c478bd9Sstevel@tonic-gate krb5_xfree(creds->keyblock.contents); 4547c478bd9Sstevel@tonic-gate creds->keyblock.contents = 0; 4557c478bd9Sstevel@tonic-gate creds->keyblock.length = 0; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate if (creds->ticket.data) { 4587c478bd9Sstevel@tonic-gate krb5_xfree(creds->ticket.data); 4597c478bd9Sstevel@tonic-gate creds->ticket.data = 0; 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate if (creds->addresses) { 4627c478bd9Sstevel@tonic-gate krb5_free_addresses(context, creds->addresses); 4637c478bd9Sstevel@tonic-gate creds->addresses = 0; 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate return (retval); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4707c478bd9Sstevel@tonic-gate static krb5_error_code 471505d05c7Sgtb make_preauth_list(krb5_context context, 472505d05c7Sgtb krb5_preauthtype * ptypes, 473505d05c7Sgtb int nptypes, 474505d05c7Sgtb krb5_pa_data *** ret_list) 4757c478bd9Sstevel@tonic-gate { 4767c478bd9Sstevel@tonic-gate krb5_preauthtype * ptypep; 4777c478bd9Sstevel@tonic-gate krb5_pa_data ** preauthp; 4787c478bd9Sstevel@tonic-gate int i; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (nptypes < 0) { 4817c478bd9Sstevel@tonic-gate for (nptypes=0, ptypep = ptypes; *ptypep; ptypep++, nptypes++) 4827c478bd9Sstevel@tonic-gate ; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* allocate space for a NULL to terminate the list */ 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate if ((preauthp = 4887c478bd9Sstevel@tonic-gate (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL) 4897c478bd9Sstevel@tonic-gate return(ENOMEM); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate for (i=0; i<nptypes; i++) { 4927c478bd9Sstevel@tonic-gate if ((preauthp[i] = 4937c478bd9Sstevel@tonic-gate (krb5_pa_data *) malloc(sizeof(krb5_pa_data))) == NULL) { 4947c478bd9Sstevel@tonic-gate for (; i>=0; i++) 4957c478bd9Sstevel@tonic-gate free(preauthp[i]); 4967c478bd9Sstevel@tonic-gate free(preauthp); 4977c478bd9Sstevel@tonic-gate return (ENOMEM); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate preauthp[i]->magic = KV5M_PA_DATA; 5007c478bd9Sstevel@tonic-gate preauthp[i]->pa_type = ptypes[i]; 5017c478bd9Sstevel@tonic-gate preauthp[i]->length = 0; 5027c478bd9Sstevel@tonic-gate preauthp[i]->contents = 0; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* fill in the terminating NULL */ 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate preauthp[nptypes] = NULL; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate *ret_list = preauthp; 5107c478bd9Sstevel@tonic-gate return 0; 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate #define MAX_IN_TKT_LOOPS 16 514505d05c7Sgtb static const krb5_enctype get_in_tkt_enctypes[] = { 515505d05c7Sgtb ENCTYPE_DES3_CBC_SHA1, 516505d05c7Sgtb ENCTYPE_ARCFOUR_HMAC, 517505d05c7Sgtb ENCTYPE_DES_CBC_MD5, 518505d05c7Sgtb ENCTYPE_DES_CBC_MD4, 519505d05c7Sgtb ENCTYPE_DES_CBC_CRC, 520505d05c7Sgtb 0 521505d05c7Sgtb }; 522159d09a2SMark Phalan 523159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV 524159d09a2SMark Phalan krb5_get_in_tkt(krb5_context context, 525159d09a2SMark Phalan const krb5_flags options, 526159d09a2SMark Phalan krb5_address * const * addrs, 527159d09a2SMark Phalan krb5_enctype * ktypes, 528159d09a2SMark Phalan krb5_preauthtype * ptypes, 529159d09a2SMark Phalan git_key_proc key_proc, 530159d09a2SMark Phalan krb5_const_pointer keyseed, 531159d09a2SMark Phalan git_decrypt_proc decrypt_proc, 532159d09a2SMark Phalan krb5_const_pointer decryptarg, 533159d09a2SMark Phalan krb5_creds * creds, 534159d09a2SMark Phalan krb5_ccache ccache, 535159d09a2SMark Phalan krb5_kdc_rep ** ret_as_reply) 536159d09a2SMark Phalan { 537159d09a2SMark Phalan krb5_error_code retval; 538159d09a2SMark Phalan krb5_timestamp time_now; 539159d09a2SMark Phalan krb5_keyblock * decrypt_key = 0; 540159d09a2SMark Phalan krb5_kdc_req request; 541159d09a2SMark Phalan krb5_pa_data **padata = 0; 542159d09a2SMark Phalan krb5_error * err_reply; 543159d09a2SMark Phalan krb5_kdc_rep * as_reply = 0; 544159d09a2SMark Phalan krb5_pa_data ** preauth_to_use = 0; 545159d09a2SMark Phalan int loopcount = 0; 546159d09a2SMark Phalan krb5_int32 do_more = 0; 547159d09a2SMark Phalan int use_master = 0; 5485e01956fSGlenn Barry char *hostname_used = NULL; 549159d09a2SMark Phalan 5505e01956fSGlenn Barry if (! krb5_realm_compare(context, creds->client, creds->server)) { 5515e01956fSGlenn Barry /* Solaris Kerberos */ 5525e01956fSGlenn Barry char *s_name = NULL; 5535e01956fSGlenn Barry char *c_name = NULL; 5545e01956fSGlenn Barry krb5_error_code serr, cerr; 5555e01956fSGlenn Barry serr = krb5_unparse_name(context, creds->server, &s_name); 5565e01956fSGlenn Barry cerr = krb5_unparse_name(context, creds->client, &c_name); 5575e01956fSGlenn Barry krb5_set_error_message(context, KRB5_IN_TKT_REALM_MISMATCH, 5585e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 5595e01956fSGlenn Barry "Client/server realm mismatch in initial ticket request: '%s' requesting ticket '%s'"), 5605e01956fSGlenn Barry cerr ? "unknown" : c_name, 5615e01956fSGlenn Barry serr ? "unknown" : s_name); 5625e01956fSGlenn Barry if (s_name) 5635e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name); 5645e01956fSGlenn Barry if (c_name) 5655e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name); 566159d09a2SMark Phalan return KRB5_IN_TKT_REALM_MISMATCH; 5675e01956fSGlenn Barry } 568159d09a2SMark Phalan 569159d09a2SMark Phalan if (ret_as_reply) 570159d09a2SMark Phalan *ret_as_reply = 0; 571159d09a2SMark Phalan 572159d09a2SMark Phalan /* 573159d09a2SMark Phalan * Set up the basic request structure 574159d09a2SMark Phalan */ 575159d09a2SMark Phalan request.magic = KV5M_KDC_REQ; 576159d09a2SMark Phalan request.msg_type = KRB5_AS_REQ; 577159d09a2SMark Phalan request.addresses = 0; 578159d09a2SMark Phalan request.ktype = 0; 579159d09a2SMark Phalan request.padata = 0; 580159d09a2SMark Phalan if (addrs) 581159d09a2SMark Phalan request.addresses = (krb5_address **) addrs; 582159d09a2SMark Phalan else 583159d09a2SMark Phalan if ((retval = krb5_os_localaddr(context, &request.addresses))) 584159d09a2SMark Phalan goto cleanup; 585159d09a2SMark Phalan request.kdc_options = options; 586159d09a2SMark Phalan request.client = creds->client; 587159d09a2SMark Phalan request.server = creds->server; 588159d09a2SMark Phalan request.nonce = 0; 589159d09a2SMark Phalan request.from = creds->times.starttime; 590159d09a2SMark Phalan request.till = creds->times.endtime; 591159d09a2SMark Phalan request.rtime = creds->times.renew_till; 592159d09a2SMark Phalan 593159d09a2SMark Phalan request.ktype = malloc (sizeof(get_in_tkt_enctypes)); 594159d09a2SMark Phalan if (request.ktype == NULL) { 595159d09a2SMark Phalan retval = ENOMEM; 596159d09a2SMark Phalan goto cleanup; 597159d09a2SMark Phalan } 598159d09a2SMark Phalan memcpy(request.ktype, get_in_tkt_enctypes, sizeof(get_in_tkt_enctypes)); 599159d09a2SMark Phalan for (request.nktypes = 0;request.ktype[request.nktypes];request.nktypes++); 600159d09a2SMark Phalan if (ktypes) { 601159d09a2SMark Phalan int i, req, next = 0; 602159d09a2SMark Phalan for (req = 0; ktypes[req]; req++) { 603159d09a2SMark Phalan if (ktypes[req] == request.ktype[next]) { 604159d09a2SMark Phalan next++; 605159d09a2SMark Phalan continue; 606159d09a2SMark Phalan } 607159d09a2SMark Phalan for (i = next + 1; i < request.nktypes; i++) 608159d09a2SMark Phalan if (ktypes[req] == request.ktype[i]) { 609159d09a2SMark Phalan /* Found the enctype we want, but not in the 610159d09a2SMark Phalan position we want. Move it, but keep the old 611159d09a2SMark Phalan one from the desired slot around in case it's 612159d09a2SMark Phalan later in our requested-ktypes list. */ 613159d09a2SMark Phalan krb5_enctype t; 614159d09a2SMark Phalan t = request.ktype[next]; 615159d09a2SMark Phalan request.ktype[next] = request.ktype[i]; 616159d09a2SMark Phalan request.ktype[i] = t; 617159d09a2SMark Phalan next++; 618159d09a2SMark Phalan break; 619159d09a2SMark Phalan } 620159d09a2SMark Phalan /* If we didn't find it, don't do anything special, just 621159d09a2SMark Phalan drop it. */ 622159d09a2SMark Phalan } 623159d09a2SMark Phalan request.ktype[next] = 0; 624159d09a2SMark Phalan request.nktypes = next; 625159d09a2SMark Phalan } 626159d09a2SMark Phalan request.authorization_data.ciphertext.length = 0; 627159d09a2SMark Phalan request.authorization_data.ciphertext.data = 0; 628159d09a2SMark Phalan request.unenc_authdata = 0; 629159d09a2SMark Phalan request.second_ticket = 0; 630159d09a2SMark Phalan 631159d09a2SMark Phalan /* 632159d09a2SMark Phalan * If a list of preauth types are passed in, convert it to a 633159d09a2SMark Phalan * preauth_to_use list. 634159d09a2SMark Phalan */ 635159d09a2SMark Phalan if (ptypes) { 636159d09a2SMark Phalan retval = make_preauth_list(context, ptypes, -1, &preauth_to_use); 637159d09a2SMark Phalan if (retval) 638159d09a2SMark Phalan goto cleanup; 639159d09a2SMark Phalan } 640159d09a2SMark Phalan 641159d09a2SMark Phalan while (1) { 642159d09a2SMark Phalan if (loopcount++ > MAX_IN_TKT_LOOPS) { 643159d09a2SMark Phalan retval = KRB5_GET_IN_TKT_LOOP; 6445e01956fSGlenn Barry /* Solaris Kerberos */ 6455e01956fSGlenn Barry { 6465e01956fSGlenn Barry char *s_name = NULL; 6475e01956fSGlenn Barry char *c_name = NULL; 6485e01956fSGlenn Barry krb5_error_code serr, cerr; 6495e01956fSGlenn Barry serr = krb5_unparse_name(context, creds->server, &s_name); 6505e01956fSGlenn Barry cerr = krb5_unparse_name(context, creds->client, &c_name); 6515e01956fSGlenn Barry krb5_set_error_message(context, retval, 6525e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 6535e01956fSGlenn Barry "Looping detected getting ticket: '%s' requesting ticket '%s'. Max loops is %d. Make sure a KDC is available"), 6545e01956fSGlenn Barry cerr ? "unknown" : c_name, 6555e01956fSGlenn Barry serr ? "unknown" : s_name, 6565e01956fSGlenn Barry MAX_IN_TKT_LOOPS); 6575e01956fSGlenn Barry if (s_name) 6585e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name); 6595e01956fSGlenn Barry if (c_name) 6605e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name); 6615e01956fSGlenn Barry } 662159d09a2SMark Phalan goto cleanup; 663159d09a2SMark Phalan } 664159d09a2SMark Phalan 665159d09a2SMark Phalan if ((retval = krb5_obtain_padata(context, preauth_to_use, key_proc, 666159d09a2SMark Phalan keyseed, creds, &request)) != 0) 667159d09a2SMark Phalan goto cleanup; 668159d09a2SMark Phalan if (preauth_to_use) 669159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 670159d09a2SMark Phalan preauth_to_use = 0; 671159d09a2SMark Phalan 672159d09a2SMark Phalan err_reply = 0; 673159d09a2SMark Phalan as_reply = 0; 674159d09a2SMark Phalan 675159d09a2SMark Phalan if ((retval = krb5_timeofday(context, &time_now))) 676159d09a2SMark Phalan goto cleanup; 677159d09a2SMark Phalan 678159d09a2SMark Phalan /* 679159d09a2SMark Phalan * XXX we know they are the same size... and we should do 680159d09a2SMark Phalan * something better than just the current time 681159d09a2SMark Phalan */ 682159d09a2SMark Phalan request.nonce = (krb5_int32) time_now; 683159d09a2SMark Phalan 6845e01956fSGlenn Barry if ((retval = send_as_request2(context, &request, &err_reply, 6855e01956fSGlenn Barry &as_reply, &use_master, 6865e01956fSGlenn Barry &hostname_used))) 687159d09a2SMark Phalan goto cleanup; 688159d09a2SMark Phalan 689159d09a2SMark Phalan if (err_reply) { 690159d09a2SMark Phalan if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED && 691159d09a2SMark Phalan err_reply->e_data.length > 0) { 692159d09a2SMark Phalan retval = decode_krb5_padata_sequence(&err_reply->e_data, 693159d09a2SMark Phalan &preauth_to_use); 694159d09a2SMark Phalan krb5_free_error(context, err_reply); 6955e01956fSGlenn Barry err_reply = NULL; 696159d09a2SMark Phalan if (retval) 697159d09a2SMark Phalan goto cleanup; 698159d09a2SMark Phalan retval = sort_krb5_padata_sequence(context, 699159d09a2SMark Phalan &request.server->realm, 700159d09a2SMark Phalan padata); 701159d09a2SMark Phalan if (retval) 702159d09a2SMark Phalan goto cleanup; 703159d09a2SMark Phalan continue; 704159d09a2SMark Phalan } else { 705159d09a2SMark Phalan retval = (krb5_error_code) err_reply->error 706159d09a2SMark Phalan + ERROR_TABLE_BASE_krb5; 707159d09a2SMark Phalan krb5_free_error(context, err_reply); 7085e01956fSGlenn Barry err_reply = NULL; 709159d09a2SMark Phalan goto cleanup; 710159d09a2SMark Phalan } 711159d09a2SMark Phalan } else if (!as_reply) { 712159d09a2SMark Phalan retval = KRB5KRB_AP_ERR_MSG_TYPE; 713159d09a2SMark Phalan goto cleanup; 714159d09a2SMark Phalan } 715159d09a2SMark Phalan if ((retval = krb5_process_padata(context, &request, as_reply, 716159d09a2SMark Phalan key_proc, keyseed, decrypt_proc, 717159d09a2SMark Phalan &decrypt_key, creds, 718159d09a2SMark Phalan &do_more)) != 0) 719159d09a2SMark Phalan goto cleanup; 720159d09a2SMark Phalan 721159d09a2SMark Phalan if (!do_more) 722159d09a2SMark Phalan break; 723159d09a2SMark Phalan } 724159d09a2SMark Phalan 725159d09a2SMark Phalan if ((retval = decrypt_as_reply(context, &request, as_reply, key_proc, 726159d09a2SMark Phalan keyseed, decrypt_key, decrypt_proc, 727159d09a2SMark Phalan decryptarg))) 728159d09a2SMark Phalan goto cleanup; 729159d09a2SMark Phalan 730159d09a2SMark Phalan if ((retval = verify_as_reply(context, time_now, &request, as_reply))) 731159d09a2SMark Phalan goto cleanup; 732159d09a2SMark Phalan 733159d09a2SMark Phalan if ((retval = stash_as_reply(context, time_now, &request, as_reply, 734159d09a2SMark Phalan creds, ccache))) 735159d09a2SMark Phalan goto cleanup; 736159d09a2SMark Phalan 737159d09a2SMark Phalan cleanup: 738159d09a2SMark Phalan if (request.ktype) 739159d09a2SMark Phalan free(request.ktype); 740159d09a2SMark Phalan if (!addrs && request.addresses) 741159d09a2SMark Phalan krb5_free_addresses(context, request.addresses); 742159d09a2SMark Phalan if (request.padata) 743159d09a2SMark Phalan krb5_free_pa_data(context, request.padata); 744159d09a2SMark Phalan if (padata) 745159d09a2SMark Phalan krb5_free_pa_data(context, padata); 746159d09a2SMark Phalan if (preauth_to_use) 747159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 748159d09a2SMark Phalan if (decrypt_key) 749159d09a2SMark Phalan krb5_free_keyblock(context, decrypt_key); 750159d09a2SMark Phalan if (as_reply) { 751159d09a2SMark Phalan if (ret_as_reply) 752159d09a2SMark Phalan *ret_as_reply = as_reply; 753159d09a2SMark Phalan else 754159d09a2SMark Phalan krb5_free_kdc_rep(context, as_reply); 755159d09a2SMark Phalan } 7565e01956fSGlenn Barry if (hostname_used) 7575e01956fSGlenn Barry free(hostname_used); 7585e01956fSGlenn Barry 759159d09a2SMark Phalan return (retval); 760159d09a2SMark Phalan } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate /* begin libdefaults parsing code. This should almost certainly move 7637c478bd9Sstevel@tonic-gate somewhere else, but I don't know where the correct somewhere else 7647c478bd9Sstevel@tonic-gate is yet. */ 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate /* XXX Duplicating this is annoying; try to work on a better way.*/ 767505d05c7Sgtb static const char *const conf_yes[] = { 7687c478bd9Sstevel@tonic-gate "y", "yes", "true", "t", "1", "on", 7697c478bd9Sstevel@tonic-gate 0, 7707c478bd9Sstevel@tonic-gate }; 7717c478bd9Sstevel@tonic-gate 772505d05c7Sgtb static const char *const conf_no[] = { 7737c478bd9Sstevel@tonic-gate "n", "no", "false", "nil", "0", "off", 7747c478bd9Sstevel@tonic-gate 0, 7757c478bd9Sstevel@tonic-gate }; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate int 778505d05c7Sgtb _krb5_conf_boolean(const char *s) 7797c478bd9Sstevel@tonic-gate { 780505d05c7Sgtb const char *const *p; 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate for(p=conf_yes; *p; p++) { 7837c478bd9Sstevel@tonic-gate if (!strcasecmp(*p,s)) 7847c478bd9Sstevel@tonic-gate return 1; 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate for(p=conf_no; *p; p++) { 7887c478bd9Sstevel@tonic-gate if (!strcasecmp(*p,s)) 7897c478bd9Sstevel@tonic-gate return 0; 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* Default to "no" */ 7937c478bd9Sstevel@tonic-gate return 0; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate static krb5_error_code 797505d05c7Sgtb krb5_libdefault_string(krb5_context context, const krb5_data *realm, 798505d05c7Sgtb const char *option, char **ret_value) 7997c478bd9Sstevel@tonic-gate { 8007c478bd9Sstevel@tonic-gate profile_t profile; 8017c478bd9Sstevel@tonic-gate const char *names[5]; 8027c478bd9Sstevel@tonic-gate char **nameval = NULL; 8037c478bd9Sstevel@tonic-gate krb5_error_code retval; 8047c478bd9Sstevel@tonic-gate char realmstr[1024]; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (realm->length > sizeof(realmstr)-1) 8077c478bd9Sstevel@tonic-gate return(EINVAL); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate strncpy(realmstr, realm->data, realm->length); 8107c478bd9Sstevel@tonic-gate realmstr[realm->length] = '\0'; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate if (!context || (context->magic != KV5M_CONTEXT)) 8137c478bd9Sstevel@tonic-gate return KV5M_CONTEXT; 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate profile = context->profile; 8167c478bd9Sstevel@tonic-gate 817159d09a2SMark Phalan /* Solaris Kerberos */ 8187c478bd9Sstevel@tonic-gate names[0] = "realms"; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Try number one: 8227c478bd9Sstevel@tonic-gate * 8237c478bd9Sstevel@tonic-gate * [realms] 8247c478bd9Sstevel@tonic-gate * REALM = { 8257c478bd9Sstevel@tonic-gate * option = <boolean> 8267c478bd9Sstevel@tonic-gate * } 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate names[1] = realmstr; 8307c478bd9Sstevel@tonic-gate names[2] = option; 8317c478bd9Sstevel@tonic-gate names[3] = 0; 8327c478bd9Sstevel@tonic-gate retval = profile_get_values(profile, names, &nameval); 8337c478bd9Sstevel@tonic-gate if (retval == 0 && nameval && nameval[0]) 8347c478bd9Sstevel@tonic-gate goto goodbye; 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* 8377c478bd9Sstevel@tonic-gate * Try number two: 8387c478bd9Sstevel@tonic-gate * 8397c478bd9Sstevel@tonic-gate * [libdefaults] 8407c478bd9Sstevel@tonic-gate * option = <boolean> 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate names[0] = "libdefaults"; 8447c478bd9Sstevel@tonic-gate names[1] = option; 8457c478bd9Sstevel@tonic-gate names[2] = 0; 8467c478bd9Sstevel@tonic-gate retval = profile_get_values(profile, names, &nameval); 8477c478bd9Sstevel@tonic-gate if (retval == 0 && nameval && nameval[0]) 8487c478bd9Sstevel@tonic-gate goto goodbye; 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate goodbye: 8517c478bd9Sstevel@tonic-gate if (!nameval) 8527c478bd9Sstevel@tonic-gate return(ENOENT); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate if (!nameval[0]) { 8557c478bd9Sstevel@tonic-gate retval = ENOENT; 8567c478bd9Sstevel@tonic-gate } else { 8577c478bd9Sstevel@tonic-gate *ret_value = malloc(strlen(nameval[0]) + 1); 8587c478bd9Sstevel@tonic-gate if (!*ret_value) 8597c478bd9Sstevel@tonic-gate retval = ENOMEM; 8607c478bd9Sstevel@tonic-gate else 8617c478bd9Sstevel@tonic-gate strcpy(*ret_value, nameval[0]); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate profile_free_list(nameval); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate return retval; 8677c478bd9Sstevel@tonic-gate } 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate /* not static so verify_init_creds() can call it */ 8707c478bd9Sstevel@tonic-gate /* as well as the DNS code */ 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate krb5_error_code 873505d05c7Sgtb krb5_libdefault_boolean(krb5_context context, const krb5_data *realm, 874505d05c7Sgtb const char *option, int *ret_value) 8757c478bd9Sstevel@tonic-gate { 8767c478bd9Sstevel@tonic-gate char *string = NULL; 8777c478bd9Sstevel@tonic-gate krb5_error_code retval; 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate retval = krb5_libdefault_string(context, realm, option, &string); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate if (retval) 8827c478bd9Sstevel@tonic-gate return(retval); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate *ret_value = _krb5_conf_boolean(string); 8857c478bd9Sstevel@tonic-gate free(string); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate return(0); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 890159d09a2SMark Phalan /* Sort a pa_data sequence so that types named in the "preferred_preauth_types" 891159d09a2SMark Phalan * libdefaults entry are listed before any others. */ 892159d09a2SMark Phalan static krb5_error_code 893159d09a2SMark Phalan sort_krb5_padata_sequence(krb5_context context, krb5_data *realm, 894159d09a2SMark Phalan krb5_pa_data **padata) 895159d09a2SMark Phalan { 896159d09a2SMark Phalan int i, j, base; 897159d09a2SMark Phalan krb5_error_code ret; 898159d09a2SMark Phalan const char *p; 899159d09a2SMark Phalan long l; 900159d09a2SMark Phalan char *q, *preauth_types = NULL; 901159d09a2SMark Phalan krb5_pa_data *tmp; 902159d09a2SMark Phalan int need_free_string = 1; 903159d09a2SMark Phalan 904159d09a2SMark Phalan if ((padata == NULL) || (padata[0] == NULL)) { 905159d09a2SMark Phalan return 0; 906159d09a2SMark Phalan } 907159d09a2SMark Phalan 908159d09a2SMark Phalan ret = krb5_libdefault_string(context, realm, "preferred_preauth_types", 909159d09a2SMark Phalan &preauth_types); 910159d09a2SMark Phalan if ((ret != 0) || (preauth_types == NULL)) { 911159d09a2SMark Phalan /* Try to use PKINIT first. */ 912159d09a2SMark Phalan preauth_types = "17, 16, 15, 14"; 913159d09a2SMark Phalan need_free_string = 0; 914159d09a2SMark Phalan } 915159d09a2SMark Phalan 916159d09a2SMark Phalan #ifdef DEBUG 917159d09a2SMark Phalan fprintf (stderr, "preauth data types before sorting:"); 918159d09a2SMark Phalan for (i = 0; padata[i]; i++) { 919159d09a2SMark Phalan fprintf (stderr, " %d", padata[i]->pa_type); 920159d09a2SMark Phalan } 921159d09a2SMark Phalan fprintf (stderr, "\n"); 922159d09a2SMark Phalan #endif 923159d09a2SMark Phalan 924159d09a2SMark Phalan base = 0; 925159d09a2SMark Phalan for (p = preauth_types; *p != '\0';) { 926159d09a2SMark Phalan /* skip whitespace to find an entry */ 927159d09a2SMark Phalan p += strspn(p, ", "); 928159d09a2SMark Phalan if (*p != '\0') { 929159d09a2SMark Phalan /* see if we can extract a number */ 930159d09a2SMark Phalan l = strtol(p, &q, 10); 931159d09a2SMark Phalan if ((q != NULL) && (q > p)) { 932159d09a2SMark Phalan /* got a valid number; search for a matchin entry */ 933159d09a2SMark Phalan for (i = base; padata[i] != NULL; i++) { 934159d09a2SMark Phalan /* bubble the matching entry to the front of the list */ 935159d09a2SMark Phalan if (padata[i]->pa_type == l) { 936159d09a2SMark Phalan tmp = padata[i]; 937159d09a2SMark Phalan for (j = i; j > base; j--) 938159d09a2SMark Phalan padata[j] = padata[j - 1]; 939159d09a2SMark Phalan padata[base] = tmp; 940159d09a2SMark Phalan base++; 941159d09a2SMark Phalan break; 942159d09a2SMark Phalan } 943159d09a2SMark Phalan } 944159d09a2SMark Phalan p = q; 945159d09a2SMark Phalan } else { 946159d09a2SMark Phalan break; 947159d09a2SMark Phalan } 948159d09a2SMark Phalan } 949159d09a2SMark Phalan } 950159d09a2SMark Phalan if (need_free_string) 951159d09a2SMark Phalan free(preauth_types); 952159d09a2SMark Phalan 953159d09a2SMark Phalan #ifdef DEBUG 954159d09a2SMark Phalan fprintf (stderr, "preauth data types after sorting:"); 955159d09a2SMark Phalan for (i = 0; padata[i]; i++) 956159d09a2SMark Phalan fprintf (stderr, " %d", padata[i]->pa_type); 957159d09a2SMark Phalan fprintf (stderr, "\n"); 958159d09a2SMark Phalan #endif 959159d09a2SMark Phalan 960159d09a2SMark Phalan return 0; 961159d09a2SMark Phalan } 962159d09a2SMark Phalan 9635e01956fSGlenn Barry /* 9645e01956fSGlenn Barry * Solaris Kerberos 9655e01956fSGlenn Barry * Return 1 if any char in string is lower-case. 9665e01956fSGlenn Barry */ 9675e01956fSGlenn Barry static int 9685e01956fSGlenn Barry is_lower_case(char *s) 9695e01956fSGlenn Barry { 9705e01956fSGlenn Barry if (!s) 9715e01956fSGlenn Barry return 0; 9725e01956fSGlenn Barry 9735e01956fSGlenn Barry while (*s) { 9745e01956fSGlenn Barry if (islower((int)*s)) 9755e01956fSGlenn Barry return 1; 9765e01956fSGlenn Barry s++; 9775e01956fSGlenn Barry } 9785e01956fSGlenn Barry return 0; 9795e01956fSGlenn Barry } 9805e01956fSGlenn Barry 981505d05c7Sgtb krb5_error_code KRB5_CALLCONV 982505d05c7Sgtb krb5_get_init_creds(krb5_context context, 983505d05c7Sgtb krb5_creds *creds, 984505d05c7Sgtb krb5_principal client, 985505d05c7Sgtb krb5_prompter_fct prompter, 986505d05c7Sgtb void *prompter_data, 987505d05c7Sgtb krb5_deltat start_time, 988505d05c7Sgtb char *in_tkt_service, 989159d09a2SMark Phalan krb5_gic_opt_ext *options, 990505d05c7Sgtb krb5_gic_get_as_key_fct gak_fct, 991505d05c7Sgtb void *gak_data, 992505d05c7Sgtb int *use_master, 993505d05c7Sgtb krb5_kdc_rep **as_reply) 9947c478bd9Sstevel@tonic-gate { 9957c478bd9Sstevel@tonic-gate krb5_error_code ret; 9967c478bd9Sstevel@tonic-gate krb5_kdc_req request; 997159d09a2SMark Phalan krb5_data *encoded_request_body, *encoded_previous_request; 998159d09a2SMark Phalan krb5_pa_data **preauth_to_use, **kdc_padata; 9997c478bd9Sstevel@tonic-gate int tempint; 1000505d05c7Sgtb char *tempstr = NULL; 1001505d05c7Sgtb krb5_deltat tkt_life; 10027c478bd9Sstevel@tonic-gate krb5_deltat renew_life; 10037c478bd9Sstevel@tonic-gate int loopcount; 10047c478bd9Sstevel@tonic-gate krb5_data salt; 10057c478bd9Sstevel@tonic-gate krb5_data s2kparams; 10067c478bd9Sstevel@tonic-gate krb5_keyblock as_key; 10075e01956fSGlenn Barry krb5_error *err_reply = NULL; 10087c478bd9Sstevel@tonic-gate krb5_kdc_rep *local_as_reply; 10097c478bd9Sstevel@tonic-gate krb5_timestamp time_now; 10107c478bd9Sstevel@tonic-gate krb5_enctype etype = 0; 1011159d09a2SMark Phalan krb5_preauth_client_rock get_data_rock; 10125e01956fSGlenn Barry char *hostname_used = NULL; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate /* initialize everything which will be freed at cleanup */ 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate s2kparams.data = NULL; 10177c478bd9Sstevel@tonic-gate s2kparams.length = 0; 10187c478bd9Sstevel@tonic-gate request.server = NULL; 10197c478bd9Sstevel@tonic-gate request.ktype = NULL; 10207c478bd9Sstevel@tonic-gate request.addresses = NULL; 10217c478bd9Sstevel@tonic-gate request.padata = NULL; 1022159d09a2SMark Phalan encoded_request_body = NULL; 1023159d09a2SMark Phalan encoded_previous_request = NULL; 1024159d09a2SMark Phalan preauth_to_use = NULL; 1025159d09a2SMark Phalan kdc_padata = NULL; 1026159d09a2SMark Phalan as_key.length = 0; 10277c478bd9Sstevel@tonic-gate salt.length = 0; 10287c478bd9Sstevel@tonic-gate salt.data = NULL; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate (void) memset(&as_key, 0, sizeof(as_key)); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate local_as_reply = 0; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate /* 10357c478bd9Sstevel@tonic-gate * Set up the basic request structure 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate request.magic = KV5M_KDC_REQ; 10387c478bd9Sstevel@tonic-gate request.msg_type = KRB5_AS_REQ; 10397c478bd9Sstevel@tonic-gate 1040159d09a2SMark Phalan /* request.nonce is filled in when we send a request to the kdc */ 1041159d09a2SMark Phalan request.nonce = 0; 1042159d09a2SMark Phalan 10437c478bd9Sstevel@tonic-gate /* request.padata is filled in later */ 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate request.kdc_options = context->kdc_default_options; 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* forwardable */ 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)) 10507c478bd9Sstevel@tonic-gate tempint = options->forwardable; 10517c478bd9Sstevel@tonic-gate else if ((ret = krb5_libdefault_boolean(context, &client->realm, 10527c478bd9Sstevel@tonic-gate "forwardable", &tempint)) == 0) 10537c478bd9Sstevel@tonic-gate /*EMPTY*/ 10547c478bd9Sstevel@tonic-gate ; 10557c478bd9Sstevel@tonic-gate else 10567c478bd9Sstevel@tonic-gate tempint = 0; 10577c478bd9Sstevel@tonic-gate if (tempint) 10587c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_FORWARDABLE; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* proxiable */ 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)) 10637c478bd9Sstevel@tonic-gate tempint = options->proxiable; 10647c478bd9Sstevel@tonic-gate else if ((ret = krb5_libdefault_boolean(context, &client->realm, 10657c478bd9Sstevel@tonic-gate "proxiable", &tempint)) == 0) 10667c478bd9Sstevel@tonic-gate /*EMPTY*/ 10677c478bd9Sstevel@tonic-gate ; 10687c478bd9Sstevel@tonic-gate else 10697c478bd9Sstevel@tonic-gate tempint = 0; 10707c478bd9Sstevel@tonic-gate if (tempint) 10717c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_PROXIABLE; 10727c478bd9Sstevel@tonic-gate 1073505d05c7Sgtb /* allow_postdate */ 1074505d05c7Sgtb 1075505d05c7Sgtb if (start_time > 0) 1076505d05c7Sgtb request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED); 1077505d05c7Sgtb 1078505d05c7Sgtb /* ticket lifetime */ 1079505d05c7Sgtb 1080505d05c7Sgtb if ((ret = krb5_timeofday(context, &request.from))) 1081505d05c7Sgtb goto cleanup; 1082505d05c7Sgtb request.from = krb5int_addint32(request.from, start_time); 1083505d05c7Sgtb 1084505d05c7Sgtb if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)) { 1085505d05c7Sgtb tkt_life = options->tkt_life; 1086505d05c7Sgtb } else if ((ret = krb5_libdefault_string(context, &client->realm, 1087505d05c7Sgtb "ticket_lifetime", &tempstr)) 1088505d05c7Sgtb == 0) { 1089159d09a2SMark Phalan ret = krb5_string_to_deltat(tempstr, &tkt_life); 1090505d05c7Sgtb free(tempstr); 1091159d09a2SMark Phalan if (ret) { 1092505d05c7Sgtb goto cleanup; 1093505d05c7Sgtb } 1094505d05c7Sgtb } else { 1095505d05c7Sgtb /* this used to be hardcoded in kinit.c */ 1096505d05c7Sgtb tkt_life = 24*60*60; 1097505d05c7Sgtb } 1098505d05c7Sgtb request.till = krb5int_addint32(request.from, tkt_life); 1099505d05c7Sgtb 1100505d05c7Sgtb /* renewable lifetime */ 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) { 11037c478bd9Sstevel@tonic-gate renew_life = options->renew_life; 11047c478bd9Sstevel@tonic-gate } else if ((ret = krb5_libdefault_string(context, &client->realm, 11057c478bd9Sstevel@tonic-gate "renew_lifetime", &tempstr)) 11067c478bd9Sstevel@tonic-gate == 0) { 1107159d09a2SMark Phalan ret = krb5_string_to_deltat(tempstr, &renew_life); 11087c478bd9Sstevel@tonic-gate free(tempstr); 1109159d09a2SMark Phalan if (ret) { 11107c478bd9Sstevel@tonic-gate goto cleanup; 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate } else { 11137c478bd9Sstevel@tonic-gate renew_life = 0; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate if (renew_life > 0) 11167c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_RENEWABLE; 11177c478bd9Sstevel@tonic-gate 1118505d05c7Sgtb if (renew_life > 0) { 1119505d05c7Sgtb request.rtime = krb5int_addint32(request.from, renew_life); 1120505d05c7Sgtb if (request.rtime < request.till) { 1121505d05c7Sgtb /* don't ask for a smaller renewable time than the lifetime */ 1122505d05c7Sgtb request.rtime = request.till; 1123505d05c7Sgtb } 1124505d05c7Sgtb /* we are already asking for renewable tickets so strip this option */ 1125505d05c7Sgtb request.kdc_options &= ~(KDC_OPT_RENEWABLE_OK); 1126505d05c7Sgtb } else { 1127505d05c7Sgtb request.rtime = 0; 1128505d05c7Sgtb } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* client */ 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate request.client = client; 11337c478bd9Sstevel@tonic-gate 1134505d05c7Sgtb /* service */ 1135505d05c7Sgtb 11367c478bd9Sstevel@tonic-gate if (in_tkt_service) { 11377c478bd9Sstevel@tonic-gate /* this is ugly, because so are the data structures involved. I'm 11387c478bd9Sstevel@tonic-gate in the library, so I'm going to manipulate the data structures 11397c478bd9Sstevel@tonic-gate directly, otherwise, it will be worse. */ 11407c478bd9Sstevel@tonic-gate 1141505d05c7Sgtb if ((ret = krb5_parse_name(context, in_tkt_service, &request.server))) 11427c478bd9Sstevel@tonic-gate goto cleanup; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* stuff the client realm into the server principal. 11457c478bd9Sstevel@tonic-gate realloc if necessary */ 11467c478bd9Sstevel@tonic-gate if (request.server->realm.length < request.client->realm.length) 11477c478bd9Sstevel@tonic-gate if ((request.server->realm.data = 11487c478bd9Sstevel@tonic-gate (char *) realloc(request.server->realm.data, 11497c478bd9Sstevel@tonic-gate request.client->realm.length)) == NULL) { 11507c478bd9Sstevel@tonic-gate ret = ENOMEM; 11517c478bd9Sstevel@tonic-gate goto cleanup; 11527c478bd9Sstevel@tonic-gate } 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate request.server->realm.length = request.client->realm.length; 11557c478bd9Sstevel@tonic-gate memcpy(request.server->realm.data, request.client->realm.data, 11567c478bd9Sstevel@tonic-gate request.client->realm.length); 11577c478bd9Sstevel@tonic-gate } else { 1158505d05c7Sgtb if ((ret = krb5_build_principal_ext(context, &request.server, 11597c478bd9Sstevel@tonic-gate request.client->realm.length, 11607c478bd9Sstevel@tonic-gate request.client->realm.data, 11617c478bd9Sstevel@tonic-gate KRB5_TGS_NAME_SIZE, 11627c478bd9Sstevel@tonic-gate KRB5_TGS_NAME, 11637c478bd9Sstevel@tonic-gate request.client->realm.length, 11647c478bd9Sstevel@tonic-gate request.client->realm.data, 1165505d05c7Sgtb 0))) 11667c478bd9Sstevel@tonic-gate goto cleanup; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 1169159d09a2SMark Phalan krb5_preauth_request_context_init(context); 1170159d09a2SMark Phalan 1171159d09a2SMark Phalan /* nonce is filled in by send_as_request if we don't take care of it */ 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)) { 11747c478bd9Sstevel@tonic-gate request.ktype = options->etype_list; 11757c478bd9Sstevel@tonic-gate request.nktypes = options->etype_list_length; 11767c478bd9Sstevel@tonic-gate } else if ((ret = krb5_get_default_in_tkt_ktypes(context, 11777c478bd9Sstevel@tonic-gate &request.ktype)) == 0) { 11787c478bd9Sstevel@tonic-gate for (request.nktypes = 0; 11797c478bd9Sstevel@tonic-gate request.ktype[request.nktypes]; 11807c478bd9Sstevel@tonic-gate request.nktypes++) 11817c478bd9Sstevel@tonic-gate ; 11827c478bd9Sstevel@tonic-gate } else { 11837c478bd9Sstevel@tonic-gate /* there isn't any useful default here. ret is set from above */ 11847c478bd9Sstevel@tonic-gate goto cleanup; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)) { 11887c478bd9Sstevel@tonic-gate request.addresses = options->address_list; 11897c478bd9Sstevel@tonic-gate } 11907c478bd9Sstevel@tonic-gate /* it would be nice if this parsed out an address list, but 11917c478bd9Sstevel@tonic-gate that would be work. */ 11927c478bd9Sstevel@tonic-gate else if (((ret = krb5_libdefault_boolean(context, &client->realm, 11937c478bd9Sstevel@tonic-gate "no_addresses", &tempint)) == 0) 1194505d05c7Sgtb || (tempint == 1)) { 11957c478bd9Sstevel@tonic-gate /*EMPTY*/ 11967c478bd9Sstevel@tonic-gate ; 11977c478bd9Sstevel@tonic-gate } else if (((ret = krb5_libdefault_boolean(context, &client->realm, 11987c478bd9Sstevel@tonic-gate "noaddresses", &tempint)) == 0) 1199505d05c7Sgtb || (tempint == 1)) { 12007c478bd9Sstevel@tonic-gate /*EMPTY*/ 12017c478bd9Sstevel@tonic-gate ; 12027c478bd9Sstevel@tonic-gate } else { 12037c478bd9Sstevel@tonic-gate if ((ret = krb5_os_localaddr(context, &request.addresses))) 12047c478bd9Sstevel@tonic-gate goto cleanup; 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate request.authorization_data.ciphertext.length = 0; 12087c478bd9Sstevel@tonic-gate request.authorization_data.ciphertext.data = 0; 12097c478bd9Sstevel@tonic-gate request.unenc_authdata = 0; 12107c478bd9Sstevel@tonic-gate request.second_ticket = 0; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* set up the other state. */ 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)) { 1215505d05c7Sgtb if ((ret = make_preauth_list(context, options->preauth_list, 12167c478bd9Sstevel@tonic-gate options->preauth_list_length, 1217159d09a2SMark Phalan &preauth_to_use))) 12187c478bd9Sstevel@tonic-gate goto cleanup; 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* the salt is allocated from somewhere, unless it is from the caller, 12227c478bd9Sstevel@tonic-gate then it is a reference */ 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate if (options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)) { 12257c478bd9Sstevel@tonic-gate salt = *options->salt; 12267c478bd9Sstevel@tonic-gate } else { 1227159d09a2SMark Phalan salt.length = SALT_TYPE_AFS_LENGTH; 12287c478bd9Sstevel@tonic-gate salt.data = NULL; 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate 1232159d09a2SMark Phalan /* set the request nonce */ 1233159d09a2SMark Phalan if ((ret = krb5_timeofday(context, &time_now))) 1234159d09a2SMark Phalan goto cleanup; 1235159d09a2SMark Phalan /* 1236159d09a2SMark Phalan * XXX we know they are the same size... and we should do 1237159d09a2SMark Phalan * something better than just the current time 1238159d09a2SMark Phalan */ 1239159d09a2SMark Phalan request.nonce = (krb5_int32) time_now; 1240159d09a2SMark Phalan 1241159d09a2SMark Phalan /* give the preauth plugins a chance to prep the request body */ 1242159d09a2SMark Phalan krb5_preauth_prepare_request(context, options, &request); 1243159d09a2SMark Phalan ret = encode_krb5_kdc_req_body(&request, &encoded_request_body); 1244159d09a2SMark Phalan if (ret) 1245159d09a2SMark Phalan goto cleanup; 1246159d09a2SMark Phalan 1247159d09a2SMark Phalan get_data_rock.magic = CLIENT_ROCK_MAGIC; 1248159d09a2SMark Phalan get_data_rock.as_reply = NULL; 1249159d09a2SMark Phalan 1250159d09a2SMark Phalan /* now, loop processing preauth data and talking to the kdc */ 12517c478bd9Sstevel@tonic-gate for (loopcount = 0; loopcount < MAX_IN_TKT_LOOPS; loopcount++) { 12527c478bd9Sstevel@tonic-gate if (request.padata) { 12537c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, request.padata); 12547c478bd9Sstevel@tonic-gate request.padata = NULL; 12557c478bd9Sstevel@tonic-gate } 1256159d09a2SMark Phalan if (!err_reply) { 1257159d09a2SMark Phalan /* either our first attempt, or retrying after PREAUTH_NEEDED */ 1258159d09a2SMark Phalan if ((ret = krb5_do_preauth(context, 1259159d09a2SMark Phalan &request, 1260159d09a2SMark Phalan encoded_request_body, 1261159d09a2SMark Phalan encoded_previous_request, 1262159d09a2SMark Phalan preauth_to_use, &request.padata, 1263159d09a2SMark Phalan &salt, &s2kparams, &etype, &as_key, 1264159d09a2SMark Phalan prompter, prompter_data, 1265159d09a2SMark Phalan gak_fct, gak_data, 1266159d09a2SMark Phalan &get_data_rock, options))) 12677c478bd9Sstevel@tonic-gate goto cleanup; 1268159d09a2SMark Phalan } else { 1269159d09a2SMark Phalan if (preauth_to_use != NULL) { 1270159d09a2SMark Phalan /* 1271159d09a2SMark Phalan * Retry after an error other than PREAUTH_NEEDED, 1272159d09a2SMark Phalan * using e-data to figure out what to change. 1273159d09a2SMark Phalan */ 1274159d09a2SMark Phalan ret = krb5_do_preauth_tryagain(context, 1275159d09a2SMark Phalan &request, 1276159d09a2SMark Phalan encoded_request_body, 1277159d09a2SMark Phalan encoded_previous_request, 1278159d09a2SMark Phalan preauth_to_use, &request.padata, 1279159d09a2SMark Phalan err_reply, 1280159d09a2SMark Phalan &salt, &s2kparams, &etype, 1281159d09a2SMark Phalan &as_key, 1282159d09a2SMark Phalan prompter, prompter_data, 1283159d09a2SMark Phalan gak_fct, gak_data, 1284159d09a2SMark Phalan &get_data_rock, options); 1285159d09a2SMark Phalan } else { 1286159d09a2SMark Phalan /* No preauth supplied, so can't query the plug-ins. */ 1287159d09a2SMark Phalan ret = KRB5KRB_ERR_GENERIC; 12887c478bd9Sstevel@tonic-gate } 1289159d09a2SMark Phalan if (ret) { 1290159d09a2SMark Phalan /* couldn't come up with anything better */ 1291159d09a2SMark Phalan ret = err_reply->error + ERROR_TABLE_BASE_krb5; 1292159d09a2SMark Phalan } 1293159d09a2SMark Phalan krb5_free_error(context, err_reply); 1294159d09a2SMark Phalan err_reply = NULL; 1295159d09a2SMark Phalan if (ret) 1296159d09a2SMark Phalan goto cleanup; 1297159d09a2SMark Phalan } 1298159d09a2SMark Phalan 1299159d09a2SMark Phalan if (encoded_previous_request != NULL) { 1300159d09a2SMark Phalan krb5_free_data(context, encoded_previous_request); 1301159d09a2SMark Phalan encoded_previous_request = NULL; 1302159d09a2SMark Phalan } 1303159d09a2SMark Phalan ret = encode_krb5_as_req(&request, &encoded_previous_request); 1304159d09a2SMark Phalan if (ret) 1305159d09a2SMark Phalan goto cleanup; 13067c478bd9Sstevel@tonic-gate 13075e01956fSGlenn Barry err_reply = NULL; 13087c478bd9Sstevel@tonic-gate local_as_reply = 0; 13095e01956fSGlenn Barry if ((ret = send_as_request2(context, &request, &err_reply, 13105e01956fSGlenn Barry &local_as_reply, use_master, 13115e01956fSGlenn Barry &hostname_used))) 13127c478bd9Sstevel@tonic-gate goto cleanup; 13137c478bd9Sstevel@tonic-gate 13147c478bd9Sstevel@tonic-gate if (err_reply) { 13157c478bd9Sstevel@tonic-gate if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED && 13167c478bd9Sstevel@tonic-gate err_reply->e_data.length > 0) { 1317159d09a2SMark Phalan /* reset the list of preauth types to try */ 1318159d09a2SMark Phalan if (preauth_to_use) { 1319159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 1320159d09a2SMark Phalan preauth_to_use = NULL; 1321159d09a2SMark Phalan } 13227c478bd9Sstevel@tonic-gate ret = decode_krb5_padata_sequence(&err_reply->e_data, 1323159d09a2SMark Phalan &preauth_to_use); 13247c478bd9Sstevel@tonic-gate krb5_free_error(context, err_reply); 1325159d09a2SMark Phalan err_reply = NULL; 13267c478bd9Sstevel@tonic-gate if (ret) 13277c478bd9Sstevel@tonic-gate goto cleanup; 1328159d09a2SMark Phalan ret = sort_krb5_padata_sequence(context, 1329159d09a2SMark Phalan &request.server->realm, 1330159d09a2SMark Phalan preauth_to_use); 1331159d09a2SMark Phalan if (ret) 1332159d09a2SMark Phalan goto cleanup; 1333159d09a2SMark Phalan /* continue to next iteration */ 13347c478bd9Sstevel@tonic-gate } else { 1335159d09a2SMark Phalan if (err_reply->e_data.length > 0) { 1336159d09a2SMark Phalan /* continue to next iteration */ 1337159d09a2SMark Phalan } else { 1338159d09a2SMark Phalan /* error + no hints = give up */ 1339505d05c7Sgtb ret = (krb5_error_code) err_reply->error 1340505d05c7Sgtb + ERROR_TABLE_BASE_krb5; 13417c478bd9Sstevel@tonic-gate goto cleanup; 13427c478bd9Sstevel@tonic-gate } 1343159d09a2SMark Phalan } 13447c478bd9Sstevel@tonic-gate } else if (local_as_reply) { 13457c478bd9Sstevel@tonic-gate break; 13467c478bd9Sstevel@tonic-gate } else { 13477c478bd9Sstevel@tonic-gate ret = KRB5KRB_AP_ERR_MSG_TYPE; 13487c478bd9Sstevel@tonic-gate goto cleanup; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate if (loopcount == MAX_IN_TKT_LOOPS) { 13537c478bd9Sstevel@tonic-gate ret = KRB5_GET_IN_TKT_LOOP; 13545e01956fSGlenn Barry /* Solaris Kerberos */ 13555e01956fSGlenn Barry { 13565e01956fSGlenn Barry char *s_name = NULL; 13575e01956fSGlenn Barry char *c_name = NULL; 13585e01956fSGlenn Barry krb5_error_code serr, cerr; 13595e01956fSGlenn Barry serr = krb5_unparse_name(context, creds->server, &s_name); 13605e01956fSGlenn Barry cerr = krb5_unparse_name(context, creds->client, &c_name); 13615e01956fSGlenn Barry krb5_set_error_message(context, ret, 13625e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 13635e01956fSGlenn Barry "Looping detected getting initial creds: '%s' requesting ticket '%s'. Max loops is %d. Make sure a KDC is available"), 13645e01956fSGlenn Barry cerr ? "unknown" : c_name, 13655e01956fSGlenn Barry serr ? "unknown" : s_name, 13665e01956fSGlenn Barry MAX_IN_TKT_LOOPS); 13675e01956fSGlenn Barry if (s_name) 13685e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name); 13695e01956fSGlenn Barry if (c_name) 13705e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name); 13715e01956fSGlenn Barry } 13727c478bd9Sstevel@tonic-gate goto cleanup; 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate /* process any preauth data in the as_reply */ 1376159d09a2SMark Phalan krb5_clear_preauth_context_use_counts(context); 1377159d09a2SMark Phalan if ((ret = sort_krb5_padata_sequence(context, &request.server->realm, 1378159d09a2SMark Phalan local_as_reply->padata))) 13797c478bd9Sstevel@tonic-gate goto cleanup; 1380159d09a2SMark Phalan get_data_rock.as_reply = local_as_reply; 1381159d09a2SMark Phalan if ((ret = krb5_do_preauth(context, 1382159d09a2SMark Phalan &request, 1383159d09a2SMark Phalan encoded_request_body, encoded_previous_request, 1384159d09a2SMark Phalan local_as_reply->padata, &kdc_padata, 1385159d09a2SMark Phalan &salt, &s2kparams, &etype, &as_key, prompter, 1386159d09a2SMark Phalan prompter_data, gak_fct, gak_data, 1387159d09a2SMark Phalan &get_data_rock, options))) 1388159d09a2SMark Phalan goto cleanup; 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY, 13917c478bd9Sstevel@tonic-gate the AS_REP comes back encrypted in the user's longterm key 13927c478bd9Sstevel@tonic-gate instead of in the SAD. If there was a SAM preauth, there 13937c478bd9Sstevel@tonic-gate will be an as_key here which will be the SAD. If that fails, 13947c478bd9Sstevel@tonic-gate use the gak_fct to get the password, and try again. */ 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate /* XXX because etypes are handled poorly (particularly wrt SAM, 13977c478bd9Sstevel@tonic-gate where the etype is fixed by the kdc), we may want to try 13987c478bd9Sstevel@tonic-gate decrypt_as_reply twice. If there's an as_key available, try 13997c478bd9Sstevel@tonic-gate it. If decrypting the as_rep fails, or if there isn't an 14007c478bd9Sstevel@tonic-gate as_key at all yet, then use the gak_fct to get one, and try 14017c478bd9Sstevel@tonic-gate again. */ 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate if (as_key.length) 1404159d09a2SMark Phalan ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, 1405159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc, 1406159d09a2SMark Phalan NULL); 14077c478bd9Sstevel@tonic-gate else 14087c478bd9Sstevel@tonic-gate ret = -1; 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate if (ret) { 14117c478bd9Sstevel@tonic-gate /* if we haven't get gotten a key, get it now */ 14127c478bd9Sstevel@tonic-gate 1413505d05c7Sgtb if ((ret = ((*gak_fct)(context, request.client, 14147c478bd9Sstevel@tonic-gate local_as_reply->enc_part.enctype, 14157c478bd9Sstevel@tonic-gate prompter, prompter_data, &salt, &s2kparams, 1416505d05c7Sgtb &as_key, gak_data)))) 14177c478bd9Sstevel@tonic-gate goto cleanup; 14187c478bd9Sstevel@tonic-gate 1419159d09a2SMark Phalan if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL, 1420159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc, 1421159d09a2SMark Phalan NULL))) 14227c478bd9Sstevel@tonic-gate goto cleanup; 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 1425505d05c7Sgtb if ((ret = verify_as_reply(context, time_now, &request, local_as_reply))) 14267c478bd9Sstevel@tonic-gate goto cleanup; 14277c478bd9Sstevel@tonic-gate 1428159d09a2SMark Phalan /* XXX this should be inside stash_as_reply, but as long as 1429159d09a2SMark Phalan get_in_tkt is still around using that arg as an in/out, I can't 1430159d09a2SMark Phalan do that */ 1431159d09a2SMark Phalan /* Solaris Kerberos */ 14327c478bd9Sstevel@tonic-gate (void) memset(creds, 0, sizeof(*creds)); 14337c478bd9Sstevel@tonic-gate 1434159d09a2SMark Phalan /* Solaris Kerberos */ 1435505d05c7Sgtb if ((ret = stash_as_reply(context, time_now, &request, local_as_reply, 1436505d05c7Sgtb creds, (krb5_ccache)NULL))) 14377c478bd9Sstevel@tonic-gate goto cleanup; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* success */ 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate ret = 0; 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate cleanup: 14445e01956fSGlenn Barry if (ret != 0) { 14455e01956fSGlenn Barry char *client_name = NULL; 14465e01956fSGlenn Barry /* See if we can produce a more detailed error message. */ 14475e01956fSGlenn Barry switch (ret) { 14485e01956fSGlenn Barry case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: 14495e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) { 14505e01956fSGlenn Barry krb5_set_error_message(context, ret, 14515e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 14525e01956fSGlenn Barry "Client '%s' not found in Kerberos database"), 14535e01956fSGlenn Barry client_name); 14545e01956fSGlenn Barry free(client_name); 14555e01956fSGlenn Barry } 14565e01956fSGlenn Barry break; 14575e01956fSGlenn Barry /* Solaris Kerberos: spruce-up the err msg */ 14585e01956fSGlenn Barry case KRB5_PREAUTH_FAILED: 14595e01956fSGlenn Barry case KRB5KDC_ERR_PREAUTH_FAILED: 14605e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) { 14615e01956fSGlenn Barry krb5_set_error_message(context, ret, 14625e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 14635e01956fSGlenn Barry "Client '%s' pre-authentication failed"), 14645e01956fSGlenn Barry client_name); 14655e01956fSGlenn Barry free(client_name); 14665e01956fSGlenn Barry } 14675e01956fSGlenn Barry break; 14685e01956fSGlenn Barry /* Solaris Kerberos: spruce-up the err msg */ 14695e01956fSGlenn Barry case KRB5KRB_AP_ERR_SKEW: /* KRB_AP_ERR_SKEW + ERROR_TABLE_BASE_krb5 */ 14705e01956fSGlenn Barry { 14715e01956fSGlenn Barry char *s_name = NULL; 14725e01956fSGlenn Barry char *c_name = NULL; 14735e01956fSGlenn Barry char stimestring[17]; 14745e01956fSGlenn Barry char fill = ' '; 14755e01956fSGlenn Barry krb5_error_code c_err, s_err, s_time; 14765e01956fSGlenn Barry 14775e01956fSGlenn Barry s_err = krb5_unparse_name(context, 14785e01956fSGlenn Barry err_reply->server, &s_name); 14795e01956fSGlenn Barry s_time = krb5_timestamp_to_sfstring(err_reply->stime, 14805e01956fSGlenn Barry stimestring, 14815e01956fSGlenn Barry sizeof (stimestring), 14825e01956fSGlenn Barry &fill); 14835e01956fSGlenn Barry c_err = krb5_unparse_name(context, client, &c_name); 14845e01956fSGlenn Barry krb5_set_error_message(context, ret, 14855e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 14865e01956fSGlenn Barry "Clock skew too great: '%s' requesting ticket '%s' from KDC '%s' (%s). Skew is %dm"), 14875e01956fSGlenn Barry c_err == 0 ? c_name : "unknown", 14885e01956fSGlenn Barry s_err == 0 ? s_name : "unknown", 14895e01956fSGlenn Barry hostname_used ? hostname_used : "unknown", 14905e01956fSGlenn Barry s_time == 0 ? stimestring : "unknown", 14915e01956fSGlenn Barry (s_time != 0) ? 0 : 14925e01956fSGlenn Barry (abs(err_reply->stime - time_now) / 60)); 14935e01956fSGlenn Barry if (s_name) 14945e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name); 14955e01956fSGlenn Barry if (c_name) 14965e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name); 14975e01956fSGlenn Barry } 14985e01956fSGlenn Barry break; 14995e01956fSGlenn Barry case KRB5_KDCREP_MODIFIED: 15005e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) { 15015e01956fSGlenn Barry /* 15025e01956fSGlenn Barry * Solaris Kerberos 15035e01956fSGlenn Barry * Extra err msg for common(?) case of 15045e01956fSGlenn Barry * 'kinit user@lower-case-def-realm'. 15055e01956fSGlenn Barry * DNS SRV recs will match (case insensitive) and trigger sendto 15065e01956fSGlenn Barry * KDC and result in this error (at least w/MSFT AD KDC). 15075e01956fSGlenn Barry */ 15085e01956fSGlenn Barry char *realm = strpbrk(client_name, "@"); 15095e01956fSGlenn Barry int set = 0; 15105e01956fSGlenn Barry if (realm++) { 15115e01956fSGlenn Barry if (realm && realm[0] && is_lower_case(realm)) { 15125e01956fSGlenn Barry krb5_set_error_message(context, ret, 15135e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 15145e01956fSGlenn Barry "KDC reply did not match expectations for client '%s': lower-case detected in realm '%s'"), 15155e01956fSGlenn Barry client_name, realm); 15165e01956fSGlenn Barry set = 1; 15175e01956fSGlenn Barry } 15185e01956fSGlenn Barry } 15195e01956fSGlenn Barry if (!set) 15205e01956fSGlenn Barry krb5_set_error_message(context, ret, 15215e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 15225e01956fSGlenn Barry "KDC reply did not match expectations for client '%s'"), 15235e01956fSGlenn Barry client_name); 15245e01956fSGlenn Barry free(client_name); 15255e01956fSGlenn Barry } 15265e01956fSGlenn Barry break; 15275e01956fSGlenn Barry default: 15285e01956fSGlenn Barry break; 15295e01956fSGlenn Barry } 15305e01956fSGlenn Barry } 15315e01956fSGlenn Barry if (err_reply) 15325e01956fSGlenn Barry krb5_free_error(context, err_reply); 1533159d09a2SMark Phalan krb5_preauth_request_context_fini(context); 1534159d09a2SMark Phalan if (encoded_previous_request != NULL) { 1535159d09a2SMark Phalan krb5_free_data(context, encoded_previous_request); 1536159d09a2SMark Phalan encoded_previous_request = NULL; 1537159d09a2SMark Phalan } 1538159d09a2SMark Phalan if (encoded_request_body != NULL) { 1539159d09a2SMark Phalan krb5_free_data(context, encoded_request_body); 1540159d09a2SMark Phalan encoded_request_body = NULL; 1541159d09a2SMark Phalan } 15427c478bd9Sstevel@tonic-gate if (request.server) 15437c478bd9Sstevel@tonic-gate krb5_free_principal(context, request.server); 15447c478bd9Sstevel@tonic-gate if (request.ktype && 15457c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST)))) 15467c478bd9Sstevel@tonic-gate free(request.ktype); 15477c478bd9Sstevel@tonic-gate if (request.addresses && 15487c478bd9Sstevel@tonic-gate (!(options && 15497c478bd9Sstevel@tonic-gate (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST)))) 15507c478bd9Sstevel@tonic-gate krb5_free_addresses(context, request.addresses); 1551159d09a2SMark Phalan if (preauth_to_use) 1552159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use); 1553159d09a2SMark Phalan if (kdc_padata) 1554159d09a2SMark Phalan krb5_free_pa_data(context, kdc_padata); 15557c478bd9Sstevel@tonic-gate if (request.padata) 15567c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, request.padata); 15577c478bd9Sstevel@tonic-gate if (as_key.length) 15587c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &as_key); 15597c478bd9Sstevel@tonic-gate if (salt.data && 15607c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT)))) 15617c478bd9Sstevel@tonic-gate krb5_xfree(salt.data); 1562505d05c7Sgtb krb5_free_data_contents(context, &s2kparams); 15637c478bd9Sstevel@tonic-gate if (as_reply) 15647c478bd9Sstevel@tonic-gate *as_reply = local_as_reply; 15657c478bd9Sstevel@tonic-gate else if (local_as_reply) 15667c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, local_as_reply); 15675e01956fSGlenn Barry if (hostname_used) 15685e01956fSGlenn Barry free(hostname_used); 15697c478bd9Sstevel@tonic-gate return(ret); 15707c478bd9Sstevel@tonic-gate } 1571