1/*	$NetBSD: kerberos5.c,v 1.18 2011/04/24 19:00:31 elric Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (C) 1990 by the Massachusetts Institute of Technology
34 *
35 * Export of this software from the United States of America may
36 * require a specific license from the United States Government.
37 * It is the responsibility of any person or organization contemplating
38 * export to obtain such a license before exporting.
39 *
40 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
41 * distribute this software and its documentation for any purpose and
42 * without fee is hereby granted, provided that the above copyright
43 * notice appear in all copies and that both that copyright notice and
44 * this permission notice appear in supporting documentation, and that
45 * the name of M.I.T. not be used in advertising or publicity pertaining
46 * to distribution of the software without specific, written prior
47 * permission.  M.I.T. makes no representations about the suitability of
48 * this software for any purpose.  It is provided "as is" without express
49 * or implied warranty.
50 */
51
52#ifdef	KRB5
53#include <arpa/telnet.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <string.h>
57#include <unistd.h>
58#include <netdb.h>
59#include <ctype.h>
60#include <pwd.h>
61#define Authenticator k5_Authenticator
62#include <krb5.h>
63#undef Authenticator
64/* #include <roken.h> */
65
66#include "encrypt.h"
67#include "auth.h"
68#include "misc.h"
69
70extern int net;
71
72int forward_flags;	/* Flags get set in telnet/main.c on -f and -F */
73int got_forwarded_creds;/* Tell telnetd to pass -F or -f to login. */
74
75int require_hwpreauth;
76
77const char *get_krb5_err_text(krb5_context, krb5_error_code);
78void kerberos5_forward(Authenticator *);
79
80static unsigned char str_data[1024] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
81				       AUTHTYPE_KERBEROS_V5,};
82
83#define	KRB_AUTH		0	/* Authentication data follows */
84#define	KRB_REJECT		1	/* Rejected (reason might follow) */
85#define	KRB_ACCEPT		2	/* Accepted */
86#define	KRB_RESPONSE		3	/* Response for mutual auth. */
87
88#define KRB_FORWARD     	4	/* Forwarded credentials follow */
89#define KRB_FORWARD_ACCEPT     	5	/* Forwarded credentials accepted */
90#define KRB_FORWARD_REJECT     	6	/* Forwarded credentials rejected */
91
92static krb5_data auth;
93static krb5_ticket *ticket;
94
95krb5_context telnet_context;
96static krb5_auth_context auth_context;
97
98static int
99Data(Authenticator *ap, int type, const void *d, int c)
100{
101	unsigned char *p = str_data + 4;
102	const unsigned char *cd = (const unsigned char *) d;
103
104	if (c == -1)
105		c = strlen(cd);
106
107	if (auth_debug_mode) {
108		printf("%s:%d: [%d] (%d)",
109		    str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
110		    str_data[3],
111		    type, c);
112		printd(d, c);
113		printf("\r\n");
114	}
115	*p++ = ap->type;
116	*p++ = ap->way;
117	*p++ = type;
118	while (c-- > 0) {
119		if ((*p++ = *cd++) == IAC)
120			*p++ = IAC;
121	}
122	*p++ = IAC;
123	*p++ = SE;
124	if (str_data[3] == TELQUAL_IS)
125		printsub('>', &str_data[2], p - &str_data[2]);
126	return (telnet_net_write(str_data, p - str_data));
127}
128
129const char *
130get_krb5_err_text(krb5_context ctx, krb5_error_code ret)
131{
132	static const char	*str = NULL;
133
134	if (str)
135		krb5_free_error_message(ctx, str);
136
137	str = krb5_get_error_message(ctx, ret);
138
139	if (str != NULL)
140		return str;
141
142	return "unknown";
143}
144
145int
146kerberos5_init(Authenticator *ap, int server)
147{
148	krb5_error_code ret;
149
150	if (telnet_context == 0) {
151		ret = krb5_init_context(&telnet_context);
152		if (ret)
153			return 0;
154	}
155
156	if (server) {
157		krb5_keytab kt;
158		krb5_kt_cursor cursor;
159
160		ret = krb5_kt_default(telnet_context, &kt);
161		if (ret)
162			return 0;
163
164		ret = krb5_kt_start_seq_get(telnet_context, kt, &cursor);
165		if (ret) {
166			krb5_kt_close(telnet_context, kt);
167			return 0;
168		}
169		krb5_kt_end_seq_get(telnet_context, kt, &cursor);
170		krb5_kt_close(telnet_context, kt);
171
172		str_data[3] = TELQUAL_REPLY;
173	} else
174		str_data[3] = TELQUAL_IS;
175	return (1);
176}
177
178int
179kerberos5_send(Authenticator *ap)
180{
181	krb5_error_code ret;
182	krb5_ccache ccache;
183	int ap_opts;
184	krb5_data cksum_data;
185	char foo[2];
186
187	printf("[ Trying KERBEROS5 ... ]\r\n");
188
189	if (!UserNameRequested) {
190		if (auth_debug_mode) {
191			printf("Kerberos V5: no user name supplied\r\n");
192		}
193		return (0);
194	}
195	ret = krb5_cc_default(telnet_context, &ccache);
196	if (ret) {
197		if (auth_debug_mode) {
198			printf(
199			"Kerberos V5: could not get default ccache: %s\r\n",
200			    get_krb5_err_text(telnet_context, ret));
201		}
202		return (0);
203	}
204	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
205		ap_opts = AP_OPTS_MUTUAL_REQUIRED;
206	else
207		ap_opts = 0;
208
209	ap_opts |= AP_OPTS_USE_SUBKEY;
210
211	ret = krb5_auth_con_init(telnet_context, &auth_context);
212	if (ret) {
213		if (auth_debug_mode) {
214			printf(
215			"Kerberos V5: krb5_auth_con_init failed: %s\r\n",
216			    get_krb5_err_text(telnet_context, ret));
217		}
218		return (0);
219	}
220	ret = krb5_auth_con_setaddrs_from_fd(telnet_context,
221	    auth_context, &net);
222	if (ret) {
223		if (auth_debug_mode) {
224			printf("Kerberos V5: "
225			    "krb5_auth_con_setaddrs_from_fd failed: %s\r\n",
226			    get_krb5_err_text(telnet_context, ret));
227		}
228		return (0);
229	}
230	krb5_auth_con_setkeytype(telnet_context, auth_context, KEYTYPE_DES);
231
232	foo[0] = ap->type;
233	foo[1] = ap->way;
234
235	cksum_data.length = sizeof(foo);
236	cksum_data.data = foo;
237	ret = krb5_mk_req(telnet_context, &auth_context, ap_opts, "host",
238	    RemoteHostName, &cksum_data, ccache, &auth);
239	if (ret) {
240		if (1 || auth_debug_mode) {
241			printf("Kerberos V5: mk_req failed (%s)\r\n",
242			    get_krb5_err_text(telnet_context, ret));
243		}
244		return (0);
245	}
246
247	if (!auth_sendname((unsigned char *) UserNameRequested,
248		strlen(UserNameRequested))) {
249		if (auth_debug_mode)
250			printf("Not enough room for user name\r\n");
251		return (0);
252	}
253	if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
254		if (auth_debug_mode)
255			printf("Not enough room for authentication data\r\n");
256		return (0);
257	}
258	if (auth_debug_mode) {
259		printf("Sent Kerberos V5 credentials to server\r\n");
260	}
261	return (1);
262}
263
264void
265kerberos5_is(Authenticator * ap, unsigned char *data, int cnt)
266{
267	krb5_error_code ret;
268	krb5_data outbuf;
269	krb5_keyblock *key_block;
270	char *name;
271	krb5_principal server;
272	int zero = 0;
273
274	if (cnt-- < 1)
275		return;
276	switch (*data++) {
277	case KRB_AUTH:
278		auth.data = (char *) data;
279		auth.length = cnt;
280
281		auth_context = NULL;
282
283		ret = krb5_auth_con_init(telnet_context, &auth_context);
284		if (ret) {
285			Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
286			auth_finished(ap, AUTH_REJECT);
287			if (auth_debug_mode)
288				printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
289				    get_krb5_err_text(telnet_context, ret));
290			return;
291		}
292		ret = krb5_auth_con_setaddrs_from_fd(telnet_context,
293		    auth_context, &zero);
294		if (ret) {
295			Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
296			auth_finished(ap, AUTH_REJECT);
297			if (auth_debug_mode)
298				printf("Kerberos V5: "
299				    "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
300				    get_krb5_err_text(telnet_context, ret));
301			return;
302		}
303		ret = krb5_sock_to_principal(telnet_context, 0, "host",
304		    KRB5_NT_SRV_HST, &server);
305		if (ret) {
306			Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
307			auth_finished(ap, AUTH_REJECT);
308			if (auth_debug_mode)
309				printf("Kerberos V5: "
310				    "krb5_sock_to_principal failed (%s)\r\n",
311				    get_krb5_err_text(telnet_context, ret));
312			return;
313		}
314		ret = krb5_rd_req(telnet_context, &auth_context, &auth,
315		    server, NULL, NULL, &ticket);
316		krb5_free_principal(telnet_context, server);
317
318		if (ret) {
319			char *errbuf;
320
321			asprintf(&errbuf,
322			    "Read req failed: %s",
323			    get_krb5_err_text(telnet_context, ret));
324			Data(ap, KRB_REJECT, errbuf, -1);
325			if (auth_debug_mode)
326				printf("%s\r\n", errbuf);
327			free(errbuf);
328			return;
329		} {
330			char foo[2];
331
332			foo[0] = ap->type;
333			foo[1] = ap->way;
334
335			ret = krb5_verify_authenticator_checksum(telnet_context,
336			    auth_context, foo, sizeof(foo));
337
338			if (ret) {
339				char *errbuf;
340				asprintf(&errbuf, "Bad checksum: %s",
341				    get_krb5_err_text(telnet_context, ret));
342				Data(ap, KRB_REJECT, errbuf, -1);
343				if (auth_debug_mode)
344					printf("%s\r\n", errbuf);
345				free(errbuf);
346				return;
347			}
348		}
349		ret = krb5_auth_con_getremotesubkey(telnet_context,
350		    auth_context, &key_block);
351
352		if (ret) {
353			Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
354			auth_finished(ap, AUTH_REJECT);
355			if (auth_debug_mode)
356				printf("Kerberos V5: "
357				    "krb5_auth_con_getremotesubkey failed (%s)\r\n",
358				    get_krb5_err_text(telnet_context, ret));
359			return;
360		}
361		if (key_block == NULL) {
362			ret = krb5_auth_con_getkey(telnet_context,
363						   auth_context,
364						   &key_block);
365		}
366		if (ret) {
367			Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
368			auth_finished(ap, AUTH_REJECT);
369			if (auth_debug_mode)
370				printf("Kerberos V5: "
371				       "krb5_auth_con_getkey failed (%s)\r\n",
372				       get_krb5_err_text(telnet_context, ret));
373			return;
374		}
375		if (key_block == NULL) {
376			Data(ap, KRB_REJECT, "no subkey received", -1);
377			auth_finished(ap, AUTH_REJECT);
378			if (auth_debug_mode)
379				printf("Kerberos V5: "
380				       "krb5_auth_con_getremotesubkey returned NULL key\r\n");
381			return;
382		}
383		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
384			ret = krb5_mk_rep(telnet_context,
385			    auth_context, &outbuf);
386			if (ret) {
387				Data(ap, KRB_REJECT,
388				    "krb5_mk_rep failed", -1);
389				auth_finished(ap, AUTH_REJECT);
390				if (auth_debug_mode)
391					printf("Kerberos V5: "
392					    "krb5_mk_rep failed (%s)\r\n",
393					    get_krb5_err_text(telnet_context,
394					    ret));
395				krb5_free_keyblock(telnet_context, key_block);
396				return;
397			}
398			Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
399		}
400		if (krb5_unparse_name(telnet_context, ticket->client, &name))
401			name = 0;
402
403		if (UserNameRequested && krb5_kuserok(telnet_context,
404		    ticket->client, UserNameRequested)) {
405			Data(ap, KRB_ACCEPT, name ? name : "", name ? -1 : 0);
406			if (auth_debug_mode) {
407				printf("Kerberos5 identifies him as ``%s''\r\n",
408				    name ? name : "");
409			}
410			if (key_block->keytype == ETYPE_DES_CBC_MD5 ||
411			    key_block->keytype == ETYPE_DES_CBC_MD4 ||
412			    key_block->keytype == ETYPE_DES_CBC_CRC) {
413				Session_Key skey;
414
415				skey.type = SK_DES;
416				skey.length = 8;
417				skey.data = key_block->keyvalue.data;
418				encrypt_session_key(&skey, 0);
419			}
420		} else {
421			char *msg;
422
423			asprintf(&msg, "user `%s' is not authorized to "
424			    "login as `%s'",
425			    name ? name : "<unknown>",
426			    UserNameRequested ? UserNameRequested : "<nobody>");
427			if (msg == NULL)
428				Data(ap, KRB_REJECT, NULL, 0);
429			else {
430				Data(ap, KRB_REJECT, (void *) msg, -1);
431				free(msg);
432			}
433			auth_finished(ap, AUTH_REJECT);
434			krb5_free_keyblock(telnet_context, key_block);
435			break;
436		}
437		auth_finished(ap, AUTH_USER);
438		krb5_free_keyblock(telnet_context, key_block);
439		break;
440	case KRB_FORWARD:{
441			struct passwd pws, *pwd;
442			char pwbuf[1024];
443			char ccname[1024];	/* XXX */
444			krb5_data inbuf;
445			krb5_ccache ccache;
446			inbuf.data = (char *) data;
447			inbuf.length = cnt;
448
449			if (getpwnam_r(UserNameRequested, &pws, pwbuf,
450			    sizeof(pwbuf), &pwd) != 0 || pwd == NULL)
451				break;
452
453			snprintf(ccname, sizeof(ccname),
454			    "FILE:/tmp/krb5cc_%u", pwd->pw_uid);
455
456			ret = krb5_cc_resolve(telnet_context, ccname, &ccache);
457			if (ret) {
458				if (auth_debug_mode)
459					printf("Kerberos V5: could not get ccache: %s\r\n",
460					    get_krb5_err_text(telnet_context,
461					    ret));
462				break;
463			}
464			ret = krb5_cc_initialize(telnet_context, ccache,
465			    ticket->client);
466			if (ret) {
467				if (auth_debug_mode)
468					printf("Kerberos V5: could not init ccache: %s\r\n",
469					    get_krb5_err_text(telnet_context,
470					        ret));
471				break;
472			}
473			ret = krb5_rd_cred2(telnet_context, auth_context,
474			    ccache, &inbuf);
475			if (ret) {
476				char *errbuf;
477
478				asprintf(&errbuf,
479				    "Read forwarded creds failed: %s",
480				    get_krb5_err_text(telnet_context, ret));
481				if (errbuf == NULL)
482					Data(ap, KRB_FORWARD_REJECT, NULL, 0);
483				else
484					Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
485				if (auth_debug_mode)
486					printf("Could not read forwarded credentials: %s\r\n",
487					    errbuf);
488				free(errbuf);
489			} else
490				Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
491			chown(ccname + 5, pwd->pw_uid, -1);
492			if (auth_debug_mode)
493				printf("Forwarded credentials obtained\r\n");
494			break;
495		}
496	default:
497		if (auth_debug_mode)
498			printf("Unknown Kerberos option %d\r\n", data[-1]);
499		Data(ap, KRB_REJECT, 0, 0);
500		break;
501	}
502}
503
504void
505kerberos5_reply(Authenticator * ap, unsigned char *data, int cnt)
506{
507	static int mutual_complete = 0;
508
509	if (cnt-- < 1)
510		return;
511	switch (*data++) {
512	case KRB_REJECT:
513		if (cnt > 0) {
514			printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
515			    cnt, data);
516		} else
517			printf("[ Kerberos V5 refuses authentication ]\r\n");
518		auth_send_retry();
519		return;
520	case KRB_ACCEPT:{
521			krb5_error_code ret;
522			Session_Key skey;
523			krb5_keyblock *keyblock;
524
525			if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
526			    !mutual_complete) {
527				printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
528				auth_send_retry();
529				return;
530			}
531			if (cnt)
532				printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
533			else
534				printf("[ Kerberos V5 accepts you ]\r\n");
535
536			ret = krb5_auth_con_getlocalsubkey(telnet_context,
537			    auth_context, &keyblock);
538			if (ret)
539				ret = krb5_auth_con_getkey(telnet_context,
540				    auth_context, &keyblock);
541			if (ret) {
542				printf("[ krb5_auth_con_getkey: %s ]\r\n",
543				    get_krb5_err_text(telnet_context, ret));
544				auth_send_retry();
545				return;
546			}
547			skey.type = SK_DES;
548			skey.length = 8;
549			skey.data = keyblock->keyvalue.data;
550			encrypt_session_key(&skey, 0);
551			krb5_free_keyblock(telnet_context, keyblock);
552			auth_finished(ap, AUTH_USER);
553			if (forward_flags & OPTS_FORWARD_CREDS)
554				kerberos5_forward(ap);
555			break;
556		}
557	case KRB_RESPONSE:
558		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
559			/* the rest of the reply should contain a krb_ap_rep */
560			krb5_ap_rep_enc_part *reply;
561			krb5_data inbuf;
562			krb5_error_code ret;
563
564			inbuf.length = cnt;
565			inbuf.data = (char *) data;
566
567			ret = krb5_rd_rep(telnet_context,
568			    auth_context, &inbuf, &reply);
569			if (ret) {
570				printf("[ Mutual authentication failed: %s ]\r\n",
571				    get_krb5_err_text(telnet_context, ret));
572				auth_send_retry();
573				return;
574			}
575			krb5_free_ap_rep_enc_part(telnet_context, reply);
576			mutual_complete = 1;
577		}
578		return;
579	case KRB_FORWARD_ACCEPT:
580		printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
581		return;
582	case KRB_FORWARD_REJECT:
583		printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
584		    cnt, data);
585		return;
586	default:
587		if (auth_debug_mode)
588			printf("Unknown Kerberos option %d\r\n", data[-1]);
589		return;
590	}
591}
592
593int
594kerberos5_status(Authenticator *ap, char *name, size_t l, int level)
595{
596	if (level < AUTH_USER)
597		return (level);
598
599	if (UserNameRequested &&
600	    krb5_kuserok(telnet_context, ticket->client, UserNameRequested)) {
601		strlcpy(name, UserNameRequested, l);
602		return (AUTH_VALID);
603	} else
604		return (AUTH_USER);
605}
606#define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
607#define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len);}
608
609void
610kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
611{
612	int i;
613
614	buf[buflen - 1] = '\0';	/* make sure its NULL terminated */
615	buflen -= 1;
616
617	switch (data[3]) {
618	case KRB_REJECT:	/* Rejected (reason might follow) */
619		strlcpy((char *) buf, " REJECT ", buflen);
620		goto common;
621
622	case KRB_ACCEPT:	/* Accepted (name might follow) */
623		strlcpy((char *) buf, " ACCEPT ", buflen);
624common:
625		BUMP(buf, buflen);
626		if (cnt <= 4)
627			break;
628		ADDC(buf, buflen, '"');
629		for (i = 4; i < cnt; i++)
630			ADDC(buf, buflen, data[i]);
631		ADDC(buf, buflen, '"');
632		ADDC(buf, buflen, '\0');
633		break;
634
635
636	case KRB_AUTH:		/* Authentication data follows */
637		strlcpy((char *) buf, " AUTH", buflen);
638		goto common2;
639
640	case KRB_RESPONSE:
641		strlcpy((char *) buf, " RESPONSE", buflen);
642		goto common2;
643
644	case KRB_FORWARD:	/* Forwarded credentials follow */
645		strlcpy((char *) buf, " FORWARD", buflen);
646		goto common2;
647
648	case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
649		strlcpy((char *) buf, " FORWARD_ACCEPT", buflen);
650		goto common2;
651
652	case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
653		/* (reason might follow) */
654		strlcpy((char *) buf, " FORWARD_REJECT", buflen);
655		goto common2;
656
657	default:
658		snprintf(buf, buflen, " %d (unknown)", data[3]);
659common2:
660		BUMP(buf, buflen);
661		for (i = 4; i < cnt; i++) {
662			snprintf(buf, buflen, " %d", data[i]);
663			BUMP(buf, buflen);
664		}
665		break;
666	}
667}
668
669void
670kerberos5_forward(Authenticator * ap)
671{
672	krb5_error_code ret;
673	krb5_ccache ccache;
674	krb5_creds creds;
675	krb5_kdc_flags flags;
676	krb5_data out_data;
677	krb5_principal principal;
678
679	ret = krb5_cc_default(telnet_context, &ccache);
680	if (ret) {
681		if (auth_debug_mode)
682			printf("KerberosV5: could not get default ccache: %s\r\n",
683			    get_krb5_err_text(telnet_context, ret));
684		return;
685	}
686	ret = krb5_cc_get_principal(telnet_context, ccache, &principal);
687	if (ret) {
688		if (auth_debug_mode)
689			printf("KerberosV5: could not get principal: %s\r\n",
690			    get_krb5_err_text(telnet_context, ret));
691		return;
692	}
693	memset(&creds, 0, sizeof(creds));
694
695	creds.client = principal;
696
697	ret = krb5_build_principal(telnet_context, &creds.server,
698	    strlen(principal->realm), principal->realm, "krbtgt",
699	    principal->realm, NULL);
700
701	if (ret) {
702		if (auth_debug_mode)
703			printf("KerberosV5: could not get principal: %s\r\n",
704			    get_krb5_err_text(telnet_context, ret));
705		return;
706	}
707	creds.times.endtime = 0;
708
709	flags.i = 0;
710	flags.b.forwarded = 1;
711	if (forward_flags & OPTS_FORWARDABLE_CREDS)
712		flags.b.forwardable = 1;
713
714	ret = krb5_get_forwarded_creds(telnet_context, auth_context,
715	    ccache, flags.i, RemoteHostName, &creds, &out_data);
716	if (ret) {
717		if (auth_debug_mode)
718			printf("Kerberos V5: error getting forwarded creds: %s\r\n",
719			    get_krb5_err_text(telnet_context, ret));
720		return;
721	}
722	if (!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
723		if (auth_debug_mode)
724			printf("Not enough room for authentication data\r\n");
725	} else {
726		if (auth_debug_mode)
727			printf("Forwarded local Kerberos V5 credentials to server\r\n");
728	}
729}
730#endif /* KRB5 */
731