17c478bd9Sstevel@tonic-gate /*
212b65585SGordon Ross * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3cfed4d70SMatt Barden * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
412b65585SGordon 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.
15*55fea89dSDan Cross *
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.
29*55fea89dSDan Cross *
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,
49*55fea89dSDan Cross 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,
84159d09a2SMark Phalan krb5_kdc_rep * );
857c478bd9Sstevel@tonic-gate
86*55fea89dSDan Cross 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 */
krb5int_addint32(krb5_int32 x,krb5_int32 y)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 }
106*55fea89dSDan Cross
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
send_as_request2(krb5_context context,krb5_kdc_req * request,krb5_error ** ret_err_reply,krb5_kdc_rep ** ret_as_reply,int * use_master,char ** hostname_used)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
13512b65585SGordon Ross /* Solaris Kerberos (illumos) */
13612b65585SGordon Ross if (krb5_getenv("MS_INTEROP")) {
13712b65585SGordon Ross /* Don't bother with UDP. */
13812b65585SGordon Ross tcp_only = 1;
13912b65585SGordon Ross }
14012b65585SGordon 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)))
144159d09a2SMark Phalan 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:
154*55fea89dSDan Cross retval = krb5_sendto_kdc2(context, packet,
1555e01956fSGlenn Barry 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)))
165*55fea89dSDan Cross /* some other error code--??? */
1667c478bd9Sstevel@tonic-gate goto cleanup;
167*55fea89dSDan Cross
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
2355e01956fSGlenn Barry static krb5_error_code
send_as_request(krb5_context context,krb5_kdc_req * request,krb5_error ** ret_err_reply,krb5_kdc_rep ** ret_as_reply,int * use_master)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
2507c478bd9Sstevel@tonic-gate static krb5_error_code
decrypt_as_reply(krb5_context context,krb5_kdc_req * request,krb5_kdc_rep * as_reply,git_key_proc key_proc,krb5_const_pointer keyseed,krb5_keyblock * key,git_decrypt_proc decrypt_proc,krb5_const_pointer decryptarg)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;
263*55fea89dSDan Cross
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);
273*55fea89dSDan Cross
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
verify_as_reply(krb5_context context,krb5_timestamp time_now,krb5_kdc_req * request,krb5_kdc_rep * as_reply)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;
328*55fea89dSDan Cross
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;
333*55fea89dSDan Cross
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
stash_as_reply(krb5_context context,krb5_timestamp time_now,krb5_kdc_req * request,krb5_kdc_rep * as_reply,krb5_creds * creds,krb5_ccache ccache)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 */
412*55fea89dSDan Cross 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
make_preauth_list(krb5_context context,krb5_preauthtype * ptypes,int nptypes,krb5_pa_data *** ret_list)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 }
484*55fea89dSDan Cross
4857c478bd9Sstevel@tonic-gate /* allocate space for a NULL to terminate the list */
486*55fea89dSDan Cross
4877c478bd9Sstevel@tonic-gate if ((preauthp =
4887c478bd9Sstevel@tonic-gate (krb5_pa_data **) malloc((nptypes+1)*sizeof(krb5_pa_data *))) == NULL)
4897c478bd9Sstevel@tonic-gate return(ENOMEM);
490*55fea89dSDan Cross
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 }
504*55fea89dSDan Cross
5057c478bd9Sstevel@tonic-gate /* fill in the terminating NULL */
506*55fea89dSDan Cross
5077c478bd9Sstevel@tonic-gate preauthp[nptypes] = NULL;
508*55fea89dSDan Cross
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
krb5_get_in_tkt(krb5_context context,const krb5_flags options,krb5_address * const * addrs,krb5_enctype * ktypes,krb5_preauthtype * ptypes,git_key_proc key_proc,krb5_const_pointer keyseed,git_decrypt_proc decrypt_proc,krb5_const_pointer decryptarg,krb5_creds * creds,krb5_ccache ccache,krb5_kdc_rep ** ret_as_reply)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;
571*55fea89dSDan Cross
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 }
640*55fea89dSDan Cross
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;
671*55fea89dSDan Cross
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 {
705*55fea89dSDan Cross 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,
716*55fea89dSDan Cross 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 }
724*55fea89dSDan Cross
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
_krb5_conf_boolean(const char * s)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
krb5_libdefault_string(krb5_context context,const krb5_data * realm,const char * option,char ** ret_value)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
812*55fea89dSDan Cross if (!context || (context->magic != KV5M_CONTEXT))
8137c478bd9Sstevel@tonic-gate return KV5M_CONTEXT;
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate profile = context->profile;
816*55fea89dSDan Cross
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 */
842*55fea89dSDan Cross
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:
851*55fea89dSDan Cross 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
krb5_libdefault_boolean(krb5_context context,const krb5_data * realm,const char * option,int * ret_value)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
sort_krb5_padata_sequence(krb5_context context,krb5_data * realm,krb5_pa_data ** padata)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
is_lower_case(char * s)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
krb5_get_init_creds(krb5_context context,krb5_creds * creds,krb5_principal client,krb5_prompter_fct prompter,void * prompter_data,krb5_deltat start_time,char * in_tkt_service,krb5_gic_opt_ext * options,krb5_gic_get_as_key_fct gak_fct,void * gak_data,int * use_master,krb5_kdc_rep ** as_reply)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
10325e01956fSGlenn Barry 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
1056159d09a2SMark Phalan 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
1069159d09a2SMark Phalan tempint = 0;
10707c478bd9Sstevel@tonic-gate if (tempint)
10717c478bd9Sstevel@tonic-gate request.kdc_options |= KDC_OPT_PROXIABLE;
10727c478bd9Sstevel@tonic-gate
1073505d05c7Sgtb /* allow_postdate */
1074*55fea89dSDan Cross
1075505d05c7Sgtb if (start_time > 0)
1076505d05c7Sgtb request.kdc_options |= (KDC_OPT_ALLOW_POSTDATE|KDC_OPT_POSTDATED);
1077*55fea89dSDan Cross
1078505d05c7Sgtb /* ticket lifetime */
1079*55fea89dSDan Cross
1080505d05c7Sgtb if ((ret = krb5_timeofday(context, &request.from)))
1081505d05c7Sgtb goto cleanup;
1082505d05c7Sgtb request.from = krb5int_addint32(request.from, start_time);
1083*55fea89dSDan Cross
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);
1090159d09a2SMark Phalan 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);
1099*55fea89dSDan Cross
1100505d05c7Sgtb /* renewable lifetime */
1101*55fea89dSDan Cross
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);
1108159d09a2SMark Phalan 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;
1117*55fea89dSDan Cross
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 }
1129*55fea89dSDan Cross
11307c478bd9Sstevel@tonic-gate /* client */
11317c478bd9Sstevel@tonic-gate
11327c478bd9Sstevel@tonic-gate request.client = client;
11337c478bd9Sstevel@tonic-gate
1134505d05c7Sgtb /* service */
1135*55fea89dSDan Cross
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,
1216159d09a2SMark Phalan 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)))
1267159d09a2SMark Phalan 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;
1288159d09a2SMark Phalan }
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 }
12987c478bd9Sstevel@tonic-gate
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)
13057c478bd9Sstevel@tonic-gate goto cleanup;
13067c478bd9Sstevel@tonic-gate
13075e01956fSGlenn Barry err_reply = NULL;
13087c478bd9Sstevel@tonic-gate local_as_reply = 0;
1309cfed4d70SMatt Barden
1310cfed4d70SMatt Barden free(hostname_used);
1311cfed4d70SMatt Barden hostname_used = NULL;
1312cfed4d70SMatt Barden
13135e01956fSGlenn Barry if ((ret = send_as_request2(context, &request, &err_reply,
13145e01956fSGlenn Barry &local_as_reply, use_master,
13155e01956fSGlenn Barry &hostname_used)))
13167c478bd9Sstevel@tonic-gate goto cleanup;
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate if (err_reply) {
13197c478bd9Sstevel@tonic-gate if (err_reply->error == KDC_ERR_PREAUTH_REQUIRED &&
13207c478bd9Sstevel@tonic-gate err_reply->e_data.length > 0) {
1321159d09a2SMark Phalan /* reset the list of preauth types to try */
1322159d09a2SMark Phalan if (preauth_to_use) {
1323159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use);
1324159d09a2SMark Phalan preauth_to_use = NULL;
1325159d09a2SMark Phalan }
13267c478bd9Sstevel@tonic-gate ret = decode_krb5_padata_sequence(&err_reply->e_data,
1327159d09a2SMark Phalan &preauth_to_use);
13285e01956fSGlenn Barry krb5_free_error(context, err_reply);
13295e01956fSGlenn Barry err_reply = NULL;
1330159d09a2SMark Phalan if (ret)
1331159d09a2SMark Phalan goto cleanup;
1332159d09a2SMark Phalan ret = sort_krb5_padata_sequence(context,
1333159d09a2SMark Phalan &request.server->realm,
1334159d09a2SMark Phalan preauth_to_use);
13357c478bd9Sstevel@tonic-gate if (ret)
13367c478bd9Sstevel@tonic-gate goto cleanup;
1337159d09a2SMark Phalan /* continue to next iteration */
13387c478bd9Sstevel@tonic-gate } else {
1339159d09a2SMark Phalan if (err_reply->e_data.length > 0) {
1340159d09a2SMark Phalan /* continue to next iteration */
1341159d09a2SMark Phalan } else {
1342159d09a2SMark Phalan /* error + no hints = give up */
1343159d09a2SMark Phalan ret = (krb5_error_code) err_reply->error
1344159d09a2SMark Phalan + ERROR_TABLE_BASE_krb5;
1345159d09a2SMark Phalan goto cleanup;
1346159d09a2SMark Phalan }
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate } else if (local_as_reply) {
13497c478bd9Sstevel@tonic-gate break;
13507c478bd9Sstevel@tonic-gate } else {
13517c478bd9Sstevel@tonic-gate ret = KRB5KRB_AP_ERR_MSG_TYPE;
13527c478bd9Sstevel@tonic-gate goto cleanup;
13537c478bd9Sstevel@tonic-gate }
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate
13567c478bd9Sstevel@tonic-gate if (loopcount == MAX_IN_TKT_LOOPS) {
13577c478bd9Sstevel@tonic-gate ret = KRB5_GET_IN_TKT_LOOP;
13585e01956fSGlenn Barry /* Solaris Kerberos */
13595e01956fSGlenn Barry {
13605e01956fSGlenn Barry char *s_name = NULL;
13615e01956fSGlenn Barry char *c_name = NULL;
13625e01956fSGlenn Barry krb5_error_code serr, cerr;
13635e01956fSGlenn Barry serr = krb5_unparse_name(context, creds->server, &s_name);
13645e01956fSGlenn Barry cerr = krb5_unparse_name(context, creds->client, &c_name);
13655e01956fSGlenn Barry krb5_set_error_message(context, ret,
13665e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
13675e01956fSGlenn Barry "Looping detected getting initial creds: '%s' requesting ticket '%s'. Max loops is %d. Make sure a KDC is available"),
13685e01956fSGlenn Barry cerr ? "unknown" : c_name,
13695e01956fSGlenn Barry serr ? "unknown" : s_name,
13705e01956fSGlenn Barry MAX_IN_TKT_LOOPS);
13715e01956fSGlenn Barry if (s_name)
13725e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name);
13735e01956fSGlenn Barry if (c_name)
13745e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name);
13755e01956fSGlenn Barry }
13767c478bd9Sstevel@tonic-gate goto cleanup;
13777c478bd9Sstevel@tonic-gate }
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate /* process any preauth data in the as_reply */
1380159d09a2SMark Phalan krb5_clear_preauth_context_use_counts(context);
1381159d09a2SMark Phalan if ((ret = sort_krb5_padata_sequence(context, &request.server->realm,
1382159d09a2SMark Phalan local_as_reply->padata)))
1383159d09a2SMark Phalan goto cleanup;
1384159d09a2SMark Phalan get_data_rock.as_reply = local_as_reply;
1385159d09a2SMark Phalan if ((ret = krb5_do_preauth(context,
1386159d09a2SMark Phalan &request,
1387159d09a2SMark Phalan encoded_request_body, encoded_previous_request,
1388159d09a2SMark Phalan local_as_reply->padata, &kdc_padata,
1389159d09a2SMark Phalan &salt, &s2kparams, &etype, &as_key, prompter,
1390159d09a2SMark Phalan prompter_data, gak_fct, gak_data,
1391159d09a2SMark Phalan &get_data_rock, options)))
13927c478bd9Sstevel@tonic-gate goto cleanup;
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate /* XXX For 1.1.1 and prior KDC's, when SAM is used w/ USE_SAD_AS_KEY,
13957c478bd9Sstevel@tonic-gate the AS_REP comes back encrypted in the user's longterm key
13967c478bd9Sstevel@tonic-gate instead of in the SAD. If there was a SAM preauth, there
13977c478bd9Sstevel@tonic-gate will be an as_key here which will be the SAD. If that fails,
13987c478bd9Sstevel@tonic-gate use the gak_fct to get the password, and try again. */
1399*55fea89dSDan Cross
14007c478bd9Sstevel@tonic-gate /* XXX because etypes are handled poorly (particularly wrt SAM,
14017c478bd9Sstevel@tonic-gate where the etype is fixed by the kdc), we may want to try
14027c478bd9Sstevel@tonic-gate decrypt_as_reply twice. If there's an as_key available, try
14037c478bd9Sstevel@tonic-gate it. If decrypting the as_rep fails, or if there isn't an
14047c478bd9Sstevel@tonic-gate as_key at all yet, then use the gak_fct to get one, and try
14057c478bd9Sstevel@tonic-gate again. */
14067c478bd9Sstevel@tonic-gate
14077c478bd9Sstevel@tonic-gate if (as_key.length)
1408159d09a2SMark Phalan ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1409159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1410159d09a2SMark Phalan NULL);
14117c478bd9Sstevel@tonic-gate else
14127c478bd9Sstevel@tonic-gate ret = -1;
1413*55fea89dSDan Cross
14147c478bd9Sstevel@tonic-gate if (ret) {
14157c478bd9Sstevel@tonic-gate /* if we haven't get gotten a key, get it now */
14167c478bd9Sstevel@tonic-gate
1417505d05c7Sgtb if ((ret = ((*gak_fct)(context, request.client,
1418159d09a2SMark Phalan local_as_reply->enc_part.enctype,
1419159d09a2SMark Phalan prompter, prompter_data, &salt, &s2kparams,
1420159d09a2SMark Phalan &as_key, gak_data))))
14217c478bd9Sstevel@tonic-gate goto cleanup;
14227c478bd9Sstevel@tonic-gate
1423159d09a2SMark Phalan if ((ret = decrypt_as_reply(context, NULL, local_as_reply, NULL,
1424159d09a2SMark Phalan NULL, &as_key, krb5_kdc_rep_decrypt_proc,
1425159d09a2SMark Phalan NULL)))
14267c478bd9Sstevel@tonic-gate goto cleanup;
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate
1429505d05c7Sgtb if ((ret = verify_as_reply(context, time_now, &request, local_as_reply)))
14307c478bd9Sstevel@tonic-gate goto cleanup;
14317c478bd9Sstevel@tonic-gate
1432159d09a2SMark Phalan /* XXX this should be inside stash_as_reply, but as long as
1433159d09a2SMark Phalan get_in_tkt is still around using that arg as an in/out, I can't
1434159d09a2SMark Phalan do that */
1435159d09a2SMark Phalan /* Solaris Kerberos */
14367c478bd9Sstevel@tonic-gate (void) memset(creds, 0, sizeof(*creds));
14377c478bd9Sstevel@tonic-gate
1438159d09a2SMark Phalan /* Solaris Kerberos */
1439505d05c7Sgtb if ((ret = stash_as_reply(context, time_now, &request, local_as_reply,
1440505d05c7Sgtb creds, (krb5_ccache)NULL)))
14417c478bd9Sstevel@tonic-gate goto cleanup;
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate /* success */
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate ret = 0;
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate cleanup:
14485e01956fSGlenn Barry if (ret != 0) {
14495e01956fSGlenn Barry char *client_name = NULL;
14505e01956fSGlenn Barry /* See if we can produce a more detailed error message. */
14515e01956fSGlenn Barry switch (ret) {
14525e01956fSGlenn Barry case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
14535e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) {
14545e01956fSGlenn Barry krb5_set_error_message(context, ret,
14555e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
14565e01956fSGlenn Barry "Client '%s' not found in Kerberos database"),
14575e01956fSGlenn Barry client_name);
14585e01956fSGlenn Barry free(client_name);
14595e01956fSGlenn Barry }
14605e01956fSGlenn Barry break;
14615e01956fSGlenn Barry /* Solaris Kerberos: spruce-up the err msg */
14625e01956fSGlenn Barry case KRB5_PREAUTH_FAILED:
14635e01956fSGlenn Barry case KRB5KDC_ERR_PREAUTH_FAILED:
14645e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) {
14655e01956fSGlenn Barry krb5_set_error_message(context, ret,
14665e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
14675e01956fSGlenn Barry "Client '%s' pre-authentication failed"),
14685e01956fSGlenn Barry client_name);
14695e01956fSGlenn Barry free(client_name);
14705e01956fSGlenn Barry }
14715e01956fSGlenn Barry break;
14725e01956fSGlenn Barry /* Solaris Kerberos: spruce-up the err msg */
14735e01956fSGlenn Barry case KRB5KRB_AP_ERR_SKEW: /* KRB_AP_ERR_SKEW + ERROR_TABLE_BASE_krb5 */
14745e01956fSGlenn Barry {
14755e01956fSGlenn Barry char *s_name = NULL;
14765e01956fSGlenn Barry char *c_name = NULL;
14775e01956fSGlenn Barry char stimestring[17];
14785e01956fSGlenn Barry char fill = ' ';
14795e01956fSGlenn Barry krb5_error_code c_err, s_err, s_time;
14805e01956fSGlenn Barry
14815e01956fSGlenn Barry s_err = krb5_unparse_name(context,
14825e01956fSGlenn Barry err_reply->server, &s_name);
14835e01956fSGlenn Barry s_time = krb5_timestamp_to_sfstring(err_reply->stime,
14845e01956fSGlenn Barry stimestring,
14855e01956fSGlenn Barry sizeof (stimestring),
14865e01956fSGlenn Barry &fill);
14875e01956fSGlenn Barry c_err = krb5_unparse_name(context, client, &c_name);
14885e01956fSGlenn Barry krb5_set_error_message(context, ret,
14895e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
14905e01956fSGlenn Barry "Clock skew too great: '%s' requesting ticket '%s' from KDC '%s' (%s). Skew is %dm"),
14915e01956fSGlenn Barry c_err == 0 ? c_name : "unknown",
14925e01956fSGlenn Barry s_err == 0 ? s_name : "unknown",
14935e01956fSGlenn Barry hostname_used ? hostname_used : "unknown",
14945e01956fSGlenn Barry s_time == 0 ? stimestring : "unknown",
14955e01956fSGlenn Barry (s_time != 0) ? 0 :
14965e01956fSGlenn Barry (abs(err_reply->stime - time_now) / 60));
14975e01956fSGlenn Barry if (s_name)
14985e01956fSGlenn Barry krb5_free_unparsed_name(context, s_name);
14995e01956fSGlenn Barry if (c_name)
15005e01956fSGlenn Barry krb5_free_unparsed_name(context, c_name);
15015e01956fSGlenn Barry }
15025e01956fSGlenn Barry break;
15035e01956fSGlenn Barry case KRB5_KDCREP_MODIFIED:
15045e01956fSGlenn Barry if (krb5_unparse_name(context, client, &client_name) == 0) {
15055e01956fSGlenn Barry /*
15065e01956fSGlenn Barry * Solaris Kerberos
1507*55fea89dSDan Cross * Extra err msg for common(?) case of
15085e01956fSGlenn Barry * 'kinit user@lower-case-def-realm'.
15095e01956fSGlenn Barry * DNS SRV recs will match (case insensitive) and trigger sendto
15105e01956fSGlenn Barry * KDC and result in this error (at least w/MSFT AD KDC).
15115e01956fSGlenn Barry */
15125e01956fSGlenn Barry char *realm = strpbrk(client_name, "@");
15135e01956fSGlenn Barry int set = 0;
15145e01956fSGlenn Barry if (realm++) {
15155e01956fSGlenn Barry if (realm && realm[0] && is_lower_case(realm)) {
15165e01956fSGlenn Barry krb5_set_error_message(context, ret,
15175e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
15185e01956fSGlenn Barry "KDC reply did not match expectations for client '%s': lower-case detected in realm '%s'"),
15195e01956fSGlenn Barry client_name, realm);
15205e01956fSGlenn Barry set = 1;
15215e01956fSGlenn Barry }
15225e01956fSGlenn Barry }
15235e01956fSGlenn Barry if (!set)
15245e01956fSGlenn Barry krb5_set_error_message(context, ret,
15255e01956fSGlenn Barry dgettext(TEXT_DOMAIN,
1526*55fea89dSDan Cross "KDC reply did not match expectations for client '%s'"),
15275e01956fSGlenn Barry client_name);
15285e01956fSGlenn Barry free(client_name);
15295e01956fSGlenn Barry }
15305e01956fSGlenn Barry break;
15315e01956fSGlenn Barry default:
15325e01956fSGlenn Barry break;
15335e01956fSGlenn Barry }
15345e01956fSGlenn Barry }
15355e01956fSGlenn Barry if (err_reply)
15365e01956fSGlenn Barry krb5_free_error(context, err_reply);
1537159d09a2SMark Phalan krb5_preauth_request_context_fini(context);
1538159d09a2SMark Phalan if (encoded_previous_request != NULL) {
1539159d09a2SMark Phalan krb5_free_data(context, encoded_previous_request);
1540159d09a2SMark Phalan encoded_previous_request = NULL;
1541159d09a2SMark Phalan }
1542159d09a2SMark Phalan if (encoded_request_body != NULL) {
1543159d09a2SMark Phalan krb5_free_data(context, encoded_request_body);
1544159d09a2SMark Phalan encoded_request_body = NULL;
1545159d09a2SMark Phalan }
15467c478bd9Sstevel@tonic-gate if (request.server)
15477c478bd9Sstevel@tonic-gate krb5_free_principal(context, request.server);
15487c478bd9Sstevel@tonic-gate if (request.ktype &&
15497c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST))))
15507c478bd9Sstevel@tonic-gate free(request.ktype);
15517c478bd9Sstevel@tonic-gate if (request.addresses &&
15527c478bd9Sstevel@tonic-gate (!(options &&
15537c478bd9Sstevel@tonic-gate (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST))))
15547c478bd9Sstevel@tonic-gate krb5_free_addresses(context, request.addresses);
1555159d09a2SMark Phalan if (preauth_to_use)
1556159d09a2SMark Phalan krb5_free_pa_data(context, preauth_to_use);
1557159d09a2SMark Phalan if (kdc_padata)
1558159d09a2SMark Phalan krb5_free_pa_data(context, kdc_padata);
15597c478bd9Sstevel@tonic-gate if (request.padata)
15607c478bd9Sstevel@tonic-gate krb5_free_pa_data(context, request.padata);
15617c478bd9Sstevel@tonic-gate if (as_key.length)
15627c478bd9Sstevel@tonic-gate krb5_free_keyblock_contents(context, &as_key);
15637c478bd9Sstevel@tonic-gate if (salt.data &&
15647c478bd9Sstevel@tonic-gate (!(options && (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT))))
15657c478bd9Sstevel@tonic-gate krb5_xfree(salt.data);
1566505d05c7Sgtb krb5_free_data_contents(context, &s2kparams);
15677c478bd9Sstevel@tonic-gate if (as_reply)
15687c478bd9Sstevel@tonic-gate *as_reply = local_as_reply;
15697c478bd9Sstevel@tonic-gate else if (local_as_reply)
15707c478bd9Sstevel@tonic-gate krb5_free_kdc_rep(context, local_as_reply);
15715e01956fSGlenn Barry if (hostname_used)
15725e01956fSGlenn Barry free(hostname_used);
15737c478bd9Sstevel@tonic-gate return(ret);
15747c478bd9Sstevel@tonic-gate }
1575