xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/telnet/kerberos5.c (revision 4807:661e1fe142fa)
10Sstevel@tonic-gate /*
2*4807Smp153739  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
70Sstevel@tonic-gate 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * usr/src/cmd/cmd-inet/usr.bin/telnet/kerberos5.c
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  * Copyright (c) 1991, 1993
120Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
150Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
160Sstevel@tonic-gate  * are met:
170Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
180Sstevel@tonic-gate  *	notice, this list of conditions and the following disclaimer.
190Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
200Sstevel@tonic-gate  *	notice, this list of conditions and the following disclaimer in the
210Sstevel@tonic-gate  *	documentation and/or other materials provided with the distribution.
220Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
230Sstevel@tonic-gate  *	must display the following acknowledgement:
240Sstevel@tonic-gate  *	This product includes software developed by the University of
250Sstevel@tonic-gate  *	California, Berkeley and its contributors.
260Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
270Sstevel@tonic-gate  *	may be used to endorse or promote products derived from this software
280Sstevel@tonic-gate  *	without specific prior written permission.
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
310Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
320Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
330Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
340Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
350Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
360Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
370Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
380Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
390Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
400Sstevel@tonic-gate  * SUCH DAMAGE.
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /* based on @(#)kerberos5.c	8.1 (Berkeley) 6/4/93 */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Copyright (C) 1990 by the Massachusetts Institute of Technology
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * Export of this software from the United States of America may
490Sstevel@tonic-gate  * require a specific license from the United States Government.
500Sstevel@tonic-gate  * It is the responsibility of any person or organization contemplating
510Sstevel@tonic-gate  * export to obtain such a license before exporting.
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
540Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
550Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
560Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
570Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
580Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
590Sstevel@tonic-gate  * to distribution of the software without specific, written prior
600Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
610Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
620Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
630Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
640Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
650Sstevel@tonic-gate  * or implied warranty.
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #include <arpa/telnet.h>
700Sstevel@tonic-gate #include <stdio.h>
710Sstevel@tonic-gate #include <ctype.h>
720Sstevel@tonic-gate #include <syslog.h>
730Sstevel@tonic-gate #include <stdlib.h>
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /* the following are from the kerberos tree */
760Sstevel@tonic-gate #include <k5-int.h>
770Sstevel@tonic-gate #include <com_err.h>
780Sstevel@tonic-gate #include <netdb.h>
790Sstevel@tonic-gate #include <profile/prof_int.h>
800Sstevel@tonic-gate #include <sys/param.h>
810Sstevel@tonic-gate #include "externs.h"
820Sstevel@tonic-gate 
830Sstevel@tonic-gate extern	char *RemoteHostName;
840Sstevel@tonic-gate extern	boolean_t auth_debug_mode;
850Sstevel@tonic-gate extern	int net;
860Sstevel@tonic-gate 
871347Smp153739 #define	ACCEPTED_ENCTYPE(a) \
881347Smp153739 	(a == ENCTYPE_DES_CBC_CRC || a == ENCTYPE_DES_CBC_MD5)
890Sstevel@tonic-gate /* for comapatibility with non-Solaris KDC's, this has to be big enough */
900Sstevel@tonic-gate #define	KERBEROS_BUFSIZ	8192
910Sstevel@tonic-gate 
920Sstevel@tonic-gate int	forward_flags = 0;  /* Flags get set in telnet/main.c on -f and -F */
930Sstevel@tonic-gate static	void kerberos5_forward(Authenticator *);
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static	unsigned char str_data[KERBEROS_BUFSIZ] = { IAC, SB,
960Sstevel@tonic-gate 		TELOPT_AUTHENTICATION, 0, AUTHTYPE_KERBEROS_V5, };
970Sstevel@tonic-gate static	char *appdef[] = { "appdefaults", "telnet", NULL };
980Sstevel@tonic-gate static	char *realmdef[] = { "realms", NULL, "telnet", NULL };
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate static	krb5_auth_context auth_context = 0;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static	krb5_data auth;	/* telnetd gets session key from here */
1030Sstevel@tonic-gate static	krb5_ticket *ticket = NULL;
1040Sstevel@tonic-gate 	/* telnet matches the AP_REQ and AP_REP with this */
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate static	krb5_keyblock	*session_key = 0;
1070Sstevel@tonic-gate char	*telnet_krb5_realm = NULL;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /*
1100Sstevel@tonic-gate  * Change the kerberos realm
1110Sstevel@tonic-gate  */
1120Sstevel@tonic-gate void
set_krb5_realm(char * name)1130Sstevel@tonic-gate set_krb5_realm(char *name)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	if (name == NULL) {
1160Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Could not set Kerberos realm, "
1170Sstevel@tonic-gate 			"no realm provided.\n"));
1180Sstevel@tonic-gate 		return;
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if (telnet_krb5_realm)
1220Sstevel@tonic-gate 		free(telnet_krb5_realm);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	telnet_krb5_realm = (char *)strdup(name);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (telnet_krb5_realm == NULL)
1270Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
1280Sstevel@tonic-gate 			"Could not set Kerberos realm, malloc failed\n"));
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate #define	RETURN_NOMEM	{ errno = ENOMEM; return (-1); }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate static int
krb5_send_data(Authenticator * ap,int type,krb5_pointer d,int c)1340Sstevel@tonic-gate krb5_send_data(Authenticator *ap, int type, krb5_pointer d, int c)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	/* the first 3 bytes are control chars */
1370Sstevel@tonic-gate 	unsigned char *p = str_data + 4;
1380Sstevel@tonic-gate 	unsigned char *cd = (unsigned char *)d;
1390Sstevel@tonic-gate 	/* spaceleft is incremented whenever p is decremented */
1400Sstevel@tonic-gate 	size_t spaceleft = sizeof (str_data) - 4;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (c == -1)
1430Sstevel@tonic-gate 		c = strlen((char *)cd);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	if (auth_debug_mode) {
1460Sstevel@tonic-gate 		(void) printf("%s:%d: [%d] (%d)",
1470Sstevel@tonic-gate 			str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
1480Sstevel@tonic-gate 			str_data[3], type, c);
1490Sstevel@tonic-gate 		printd(d, c);
1500Sstevel@tonic-gate 		(void) printf("\r\n");
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	if (spaceleft < 3)
1540Sstevel@tonic-gate 		RETURN_NOMEM;
1550Sstevel@tonic-gate 	*p++ = ap->type;
1560Sstevel@tonic-gate 	*p++ = ap->way;
1570Sstevel@tonic-gate 	*p++ = type;
1580Sstevel@tonic-gate 	spaceleft -= 3;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	while (c-- > 0) {
1610Sstevel@tonic-gate 		if (spaceleft < 2)
1620Sstevel@tonic-gate 			RETURN_NOMEM;
1630Sstevel@tonic-gate 		if ((*p++ = *cd++) == IAC) {
1640Sstevel@tonic-gate 			*p++ = IAC;
1650Sstevel@tonic-gate 			spaceleft -= 2;
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (spaceleft < 2)
1700Sstevel@tonic-gate 		RETURN_NOMEM;
1710Sstevel@tonic-gate 	*p++ = IAC;
1720Sstevel@tonic-gate 	*p++ = SE;
1730Sstevel@tonic-gate 	if (str_data[3] == TELQUAL_IS)
1740Sstevel@tonic-gate 		printsub('>', &str_data[2], p - &str_data[2]);
1750Sstevel@tonic-gate 	return (net_write(str_data, p - str_data));
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate krb5_context telnet_context = 0;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /* ARGSUSED */
1810Sstevel@tonic-gate int
kerberos5_init(Authenticator * ap)1820Sstevel@tonic-gate kerberos5_init(Authenticator *ap)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	krb5_error_code retval;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	str_data[3] = TELQUAL_IS;
1870Sstevel@tonic-gate 	if (krb5auth_flag && (telnet_context == 0)) {
1880Sstevel@tonic-gate 		retval = krb5_init_context(&telnet_context);
1890Sstevel@tonic-gate 		if (retval)
1900Sstevel@tonic-gate 			return (0);
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 	return (1);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate int
kerberos5_send(Authenticator * ap)1960Sstevel@tonic-gate kerberos5_send(Authenticator *ap)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate 	krb5_error_code retval;
1990Sstevel@tonic-gate 	krb5_ccache ccache;
2000Sstevel@tonic-gate 	krb5_creds creds;		/* telnet gets session key from here */
2010Sstevel@tonic-gate 	krb5_creds *new_creds = 0;
2020Sstevel@tonic-gate 	int ap_opts;
2030Sstevel@tonic-gate 	char type_check[2];
2040Sstevel@tonic-gate 	krb5_data check_data;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	krb5_keyblock *newkey = 0;
2070Sstevel@tonic-gate 
2081347Smp153739 	int i;
2091347Smp153739 	krb5_enctype *ktypes;
2101347Smp153739 
2110Sstevel@tonic-gate 	if (!UserNameRequested) {
2120Sstevel@tonic-gate 		if (auth_debug_mode)
2130Sstevel@tonic-gate 			(void) printf(gettext("telnet: Kerberos V5: "
2140Sstevel@tonic-gate 				"no user name supplied\r\n"));
2150Sstevel@tonic-gate 		return (0);
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if ((retval = krb5_cc_default(telnet_context, &ccache))) {
2190Sstevel@tonic-gate 		if (auth_debug_mode)
2200Sstevel@tonic-gate 		    (void) printf(gettext("telnet: Kerberos V5: "
2210Sstevel@tonic-gate 			"could not get default ccache\r\n"));
2220Sstevel@tonic-gate 		return (0);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	(void) memset((char *)&creds, 0, sizeof (creds));
226*4807Smp153739 	if (auth_debug_mode)
227*4807Smp153739 		printf("telnet: calling krb5_sname_to_principal\n");
2280Sstevel@tonic-gate 	if ((retval = krb5_sname_to_principal(telnet_context, RemoteHostName,
2290Sstevel@tonic-gate 		"host", KRB5_NT_SRV_HST, &creds.server))) {
2300Sstevel@tonic-gate 		if (auth_debug_mode)
2310Sstevel@tonic-gate 		    (void) printf(gettext("telnet: Kerberos V5: error "
2320Sstevel@tonic-gate 			"while constructing service name: %s\r\n"),
2330Sstevel@tonic-gate 			error_message(retval));
2340Sstevel@tonic-gate 		return (0);
2350Sstevel@tonic-gate 	}
236*4807Smp153739 	if (auth_debug_mode)
237*4807Smp153739 		printf("telnet: done calling krb5_sname_to_principal\n");
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if (telnet_krb5_realm != NULL) {
2400Sstevel@tonic-gate 		krb5_data rdata;
2410Sstevel@tonic-gate 
242*4807Smp153739 		rdata.magic = 0;
2430Sstevel@tonic-gate 		rdata.length = strlen(telnet_krb5_realm);
2440Sstevel@tonic-gate 		rdata.data = (char *)malloc(rdata.length + 1);
2450Sstevel@tonic-gate 		if (rdata.data == NULL) {
2460Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("malloc failed\n"));
2470Sstevel@tonic-gate 			return (0);
2480Sstevel@tonic-gate 		}
2490Sstevel@tonic-gate 		(void) strcpy(rdata.data, telnet_krb5_realm);
2500Sstevel@tonic-gate 		krb5_princ_set_realm(telnet_context, creds.server, &rdata);
2510Sstevel@tonic-gate 		if (auth_debug_mode)
2520Sstevel@tonic-gate 		    (void) printf(gettext(
2530Sstevel@tonic-gate 			"telnet: Kerberos V5: set kerberos realm to %s\r\n"),
2540Sstevel@tonic-gate 			telnet_krb5_realm);
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if ((retval = krb5_cc_get_principal(telnet_context, ccache,
2580Sstevel@tonic-gate 		&creds.client)) != NULL) {
2590Sstevel@tonic-gate 		if (auth_debug_mode) {
2600Sstevel@tonic-gate 			(void) printf(gettext(
2610Sstevel@tonic-gate 			    "telnet: Kerberos V5: failure on principal "
2620Sstevel@tonic-gate 			    "(%s)\r\n"), error_message(retval));
2630Sstevel@tonic-gate 		}
2640Sstevel@tonic-gate 		krb5_free_cred_contents(telnet_context, &creds);
2650Sstevel@tonic-gate 		return (0);
2660Sstevel@tonic-gate 	}
2671347Smp153739 /*
2681347Smp153739  * Check to to confirm that at least one of the supported
2691347Smp153739  * encryption types (des-cbc-md5, des-cbc-crc is available. If
2701347Smp153739  * one is available then use it to obtain credentials.
2711347Smp153739  */
2720Sstevel@tonic-gate 
2731347Smp153739 	if ((retval = krb5_get_tgs_ktypes(telnet_context, creds.server,
2741347Smp153739 		&ktypes))) {
2751347Smp153739 		if (auth_debug_mode) {
2761347Smp153739 			(void) printf(gettext(
2771347Smp153739 			    "telnet: Kerberos V5: could not determine "
2781347Smp153739 				"TGS encryption types "
2791347Smp153739 				"(see default_tgs_enctypes in krb5.conf) "
2801347Smp153739 			    "(%s)\r\n"), error_message(retval));
2811347Smp153739 		}
2821347Smp153739 		krb5_free_cred_contents(telnet_context, &creds);
2831347Smp153739 		return (0);
2841347Smp153739 	}
2851347Smp153739 
2861347Smp153739 	for (i = 0; ktypes[i]; i++) {
2871347Smp153739 		if (ACCEPTED_ENCTYPE(ktypes[i]))
2881347Smp153739 			break;
2891347Smp153739 	}
2901347Smp153739 
2911347Smp153739 	if (ktypes[i] == 0) {
2921347Smp153739 		if (auth_debug_mode) {
2931347Smp153739 			(void) printf(gettext(
2941347Smp153739 				"telnet: Kerberos V5: "
2951347Smp153739 				"failure on encryption types. "
2961347Smp153739 				"Cannot find des-cbc-md5 or des-cbc-crc "
2971347Smp153739 				"in list of TGS encryption types "
2981347Smp153739 				"(see default_tgs_enctypes in krb5.conf)\n"));
2991347Smp153739 		}
3001347Smp153739 		krb5_free_cred_contents(telnet_context, &creds);
3011347Smp153739 		return (0);
3021347Smp153739 	}
3031347Smp153739 
3041347Smp153739 	creds.keyblock.enctype = ktypes[i];
3050Sstevel@tonic-gate 	if ((retval = krb5_get_credentials(telnet_context, 0,
3060Sstevel@tonic-gate 		ccache, &creds, &new_creds))) {
3070Sstevel@tonic-gate 		if (auth_debug_mode) {
3080Sstevel@tonic-gate 			(void) printf(gettext(
3090Sstevel@tonic-gate 			    "telnet: Kerberos V5: failure on credentials "
3100Sstevel@tonic-gate 			    "(%s)\r\n"), error_message(retval));
3110Sstevel@tonic-gate 		}
3120Sstevel@tonic-gate 		krb5_free_cred_contents(telnet_context, &creds);
3130Sstevel@tonic-gate 		return (0);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	ap_opts = ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
3170Sstevel@tonic-gate 			AP_OPTS_MUTUAL_REQUIRED : 0;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	ap_opts |= AP_OPTS_USE_SUBKEY;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (auth_context) {
3220Sstevel@tonic-gate 		krb5_auth_con_free(telnet_context, auth_context);
3230Sstevel@tonic-gate 		auth_context = 0;
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 	if ((retval = krb5_auth_con_init(telnet_context, &auth_context))) {
3260Sstevel@tonic-gate 		if (auth_debug_mode) {
3270Sstevel@tonic-gate 			(void) printf(gettext(
3280Sstevel@tonic-gate 				"Kerberos V5: failed to init auth_context "
3290Sstevel@tonic-gate 				"(%s)\r\n"), error_message(retval));
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 		return (0);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	krb5_auth_con_setflags(telnet_context, auth_context,
3350Sstevel@tonic-gate 		KRB5_AUTH_CONTEXT_RET_TIME);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	type_check[0] = ap->type;
3380Sstevel@tonic-gate 	type_check[1] = ap->way;
3390Sstevel@tonic-gate 	check_data.magic = KV5M_DATA;
3400Sstevel@tonic-gate 	check_data.length = 2;
3410Sstevel@tonic-gate 	check_data.data = (char *)&type_check;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	retval = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts,
3440Sstevel@tonic-gate 		&check_data, new_creds, &auth);
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey);
3470Sstevel@tonic-gate 	if (session_key) {
3480Sstevel@tonic-gate 		krb5_free_keyblock(telnet_context, session_key);
3490Sstevel@tonic-gate 		session_key = 0;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (newkey) {
3530Sstevel@tonic-gate 		/*
3540Sstevel@tonic-gate 		 * keep the key in our private storage, but don't use it
3550Sstevel@tonic-gate 		 * yet---see kerberos5_reply() below
3560Sstevel@tonic-gate 		 */
3571347Smp153739 		if (!(ACCEPTED_ENCTYPE(newkey->enctype))) {
3581347Smp153739 		    if (!(ACCEPTED_ENCTYPE(new_creds->keyblock.enctype)))
3590Sstevel@tonic-gate 			/* use the session key in credentials instead */
3600Sstevel@tonic-gate 			krb5_copy_keyblock(telnet_context,
3610Sstevel@tonic-gate 				&new_creds->keyblock, &session_key);
3620Sstevel@tonic-gate 		} else
3630Sstevel@tonic-gate 			krb5_copy_keyblock(telnet_context,
3640Sstevel@tonic-gate 				newkey, &session_key);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		krb5_free_keyblock(telnet_context, newkey);
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	krb5_free_cred_contents(telnet_context, &creds);
3700Sstevel@tonic-gate 	krb5_free_creds(telnet_context, new_creds);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	if (retval) {
3730Sstevel@tonic-gate 		if (auth_debug_mode)
3740Sstevel@tonic-gate 			(void) printf(gettext(
3750Sstevel@tonic-gate 			    "telnet: Kerberos V5: mk_req failed (%s)\r\n"),
3760Sstevel@tonic-gate 			    error_message(retval));
3770Sstevel@tonic-gate 		return (0);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if ((auth_sendname((uchar_t *)UserNameRequested,
3810Sstevel@tonic-gate 		strlen(UserNameRequested))) == NULL) {
3820Sstevel@tonic-gate 		if (auth_debug_mode)
3830Sstevel@tonic-gate 			(void) printf(gettext(
3840Sstevel@tonic-gate 				"telnet: Not enough room for user name\r\n"));
3850Sstevel@tonic-gate 		return (0);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 	retval = krb5_send_data(ap, KRB_AUTH, auth.data, auth.length);
3880Sstevel@tonic-gate 	if (auth_debug_mode && retval) {
3890Sstevel@tonic-gate 		(void) printf(gettext(
3900Sstevel@tonic-gate 		    "telnet: Sent Kerberos V5 credentials to server\r\n"));
3910Sstevel@tonic-gate 	} else if (auth_debug_mode) {
3920Sstevel@tonic-gate 		(void) printf(gettext(
3930Sstevel@tonic-gate 		    "telnet: Not enough room for authentication data\r\n"));
3940Sstevel@tonic-gate 		return (0);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 	return (1);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate void
kerberos5_reply(Authenticator * ap,unsigned char * data,int cnt)4000Sstevel@tonic-gate kerberos5_reply(Authenticator *ap, unsigned char *data, int cnt)
4010Sstevel@tonic-gate {
4020Sstevel@tonic-gate 	Session_Key skey;
4030Sstevel@tonic-gate 	static boolean_t mutual_complete = B_FALSE;
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	if (cnt-- < 1)
4060Sstevel@tonic-gate 		return;
4070Sstevel@tonic-gate 	switch (*data++) {
4080Sstevel@tonic-gate 	case KRB_REJECT:
4090Sstevel@tonic-gate 		if (cnt > 0)
4100Sstevel@tonic-gate 		    (void) printf(gettext(
4110Sstevel@tonic-gate 			"[ Kerberos V5 refuses authentication because "
4120Sstevel@tonic-gate 			"%.*s ]\r\n"), cnt, data);
4130Sstevel@tonic-gate 		else
4140Sstevel@tonic-gate 		    (void) printf(gettext(
4150Sstevel@tonic-gate 			"[ Kerberos V5 refuses authentication ]\r\n"));
4160Sstevel@tonic-gate 		auth_send_retry();
4170Sstevel@tonic-gate 		return;
4180Sstevel@tonic-gate 	case KRB_ACCEPT:
4190Sstevel@tonic-gate 		if (!mutual_complete) {
4200Sstevel@tonic-gate 			if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
4210Sstevel@tonic-gate 			    (void) printf(gettext(
4220Sstevel@tonic-gate 				"[ Kerberos V5 accepted you, but didn't "
4230Sstevel@tonic-gate 				"provide mutual authentication! ]\r\n"));
4240Sstevel@tonic-gate 			    auth_send_retry();
4250Sstevel@tonic-gate 			    return;
4260Sstevel@tonic-gate 			}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 			if (session_key) {
4290Sstevel@tonic-gate 			    skey.type = SK_DES;
4300Sstevel@tonic-gate 			    skey.length = 8;
4310Sstevel@tonic-gate 			    skey.data = session_key->contents;
4320Sstevel@tonic-gate 			    encrypt_session_key(&skey);
4330Sstevel@tonic-gate 			}
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 		if (cnt)
4360Sstevel@tonic-gate 			(void) printf(gettext(
4370Sstevel@tonic-gate 			    "[ Kerberos V5 accepts you as ``%.*s'' ]\r\n"),
4380Sstevel@tonic-gate 			    cnt, data);
4390Sstevel@tonic-gate 		else
4400Sstevel@tonic-gate 			(void) printf(gettext(
4410Sstevel@tonic-gate 			    "[ Kerberos V5 accepts you ]\r\n"));
4420Sstevel@tonic-gate 		auth_finished(ap, AUTH_USER);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 		if (forward_flags & OPTS_FORWARD_CREDS)
4450Sstevel@tonic-gate 			kerberos5_forward(ap);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		break;
4480Sstevel@tonic-gate 	case KRB_RESPONSE:
4490Sstevel@tonic-gate 		if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
4500Sstevel@tonic-gate 			/* the rest of the reply should contain a krb_ap_rep */
4510Sstevel@tonic-gate 			krb5_ap_rep_enc_part *reply;
4520Sstevel@tonic-gate 			krb5_data inbuf;
4530Sstevel@tonic-gate 			krb5_error_code retval;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 			inbuf.length = cnt;
4560Sstevel@tonic-gate 			inbuf.data = (char *)data;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 			retval = krb5_rd_rep(telnet_context, auth_context,
4590Sstevel@tonic-gate 				&inbuf, &reply);
4600Sstevel@tonic-gate 			if (retval) {
4610Sstevel@tonic-gate 				(void) printf(gettext(
4620Sstevel@tonic-gate 					"[ Mutual authentication failed: "
4630Sstevel@tonic-gate 					"%s ]\r\n"), error_message(retval));
4640Sstevel@tonic-gate 				auth_send_retry();
4650Sstevel@tonic-gate 				return;
4660Sstevel@tonic-gate 			}
4670Sstevel@tonic-gate 			krb5_free_ap_rep_enc_part(telnet_context, reply);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 			if (session_key) {
4700Sstevel@tonic-gate 				skey.type = SK_DES;
4710Sstevel@tonic-gate 				skey.length = 8;
4720Sstevel@tonic-gate 				skey.data = session_key->contents;
4730Sstevel@tonic-gate 				encrypt_session_key(&skey);
4740Sstevel@tonic-gate 			}
4750Sstevel@tonic-gate 			mutual_complete = B_TRUE;
4760Sstevel@tonic-gate 		}
4770Sstevel@tonic-gate 		return;
4780Sstevel@tonic-gate 	case KRB_FORWARD_ACCEPT:
4790Sstevel@tonic-gate 		(void) printf(gettext(
4800Sstevel@tonic-gate 			"[ Kerberos V5 accepted forwarded credentials ]\r\n"));
4810Sstevel@tonic-gate 		return;
4820Sstevel@tonic-gate 	case KRB_FORWARD_REJECT:
4830Sstevel@tonic-gate 		(void) printf(gettext(
4840Sstevel@tonic-gate 			"[ Kerberos V5 refuses forwarded credentials because "
4850Sstevel@tonic-gate 			"%.*s ]\r\n"), cnt, data);
4860Sstevel@tonic-gate 		return;
4870Sstevel@tonic-gate 	default:
4880Sstevel@tonic-gate 		if (auth_debug_mode)
4890Sstevel@tonic-gate 			(void) printf(gettext(
4900Sstevel@tonic-gate 				"Unknown Kerberos option %d\r\n"), data[-1]);
4910Sstevel@tonic-gate 		return;
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate /* ARGSUSED */
4960Sstevel@tonic-gate int
kerberos5_status(Authenticator * ap,char * name,int level)4970Sstevel@tonic-gate kerberos5_status(Authenticator *ap, char *name, int level)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	if (level < AUTH_USER)
5000Sstevel@tonic-gate 		return (level);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (UserNameRequested && krb5_kuserok(telnet_context,
5030Sstevel@tonic-gate 		ticket->enc_part2->client, UserNameRequested)) {
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		/* the name buffer comes from telnetd/telnetd{-ktd}.c */
5060Sstevel@tonic-gate 		(void) strncpy(name, UserNameRequested, MAXNAMELEN);
5070Sstevel@tonic-gate 		name[MAXNAMELEN-1] = '\0';
5080Sstevel@tonic-gate 		return (AUTH_VALID);
5090Sstevel@tonic-gate 	} else
5100Sstevel@tonic-gate 		return (AUTH_USER);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len); }
5140Sstevel@tonic-gate #define	ADDC(buf, len, c)	if ((len) > 0) {*(buf)++ = (c); --(len); }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * Used with the set opt command to print suboptions
5180Sstevel@tonic-gate  */
5190Sstevel@tonic-gate void
kerberos5_printsub(unsigned char * data,int cnt,unsigned char * buf,int buflen)5200Sstevel@tonic-gate kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
5210Sstevel@tonic-gate {
5220Sstevel@tonic-gate 	char lbuf[AUTH_LBUF_BUFSIZ];
5230Sstevel@tonic-gate 	register int i;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	buf[buflen-1] = '\0';		/* make sure its NULL terminated */
5260Sstevel@tonic-gate 	buflen -= 1;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	switch (data[3]) {
5290Sstevel@tonic-gate 	case KRB_REJECT:		/* Rejected (reason might follow) */
5300Sstevel@tonic-gate 		(void) strncpy((char *)buf, " REJECT ", buflen);
5310Sstevel@tonic-gate 		goto common;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	case KRB_ACCEPT:		/* Accepted (name might follow) */
5340Sstevel@tonic-gate 		(void) strncpy((char *)buf, " ACCEPT ", buflen);
5350Sstevel@tonic-gate 	common:
5360Sstevel@tonic-gate 		BUMP(buf, buflen);
5370Sstevel@tonic-gate 		if (cnt <= 4)
5380Sstevel@tonic-gate 			break;
5390Sstevel@tonic-gate 		ADDC(buf, buflen, '"');
5400Sstevel@tonic-gate 		for (i = 4; i < cnt; i++)
5410Sstevel@tonic-gate 			ADDC(buf, buflen, data[i]);
5420Sstevel@tonic-gate 		ADDC(buf, buflen, '"');
5430Sstevel@tonic-gate 		ADDC(buf, buflen, '\0');
5440Sstevel@tonic-gate 		break;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	case KRB_AUTH:			/* Authentication data follows */
5470Sstevel@tonic-gate 		(void) strncpy((char *)buf, " AUTH", buflen);
5480Sstevel@tonic-gate 		goto common2;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	case KRB_RESPONSE:
5510Sstevel@tonic-gate 		(void) strncpy((char *)buf, " RESPONSE", buflen);
5520Sstevel@tonic-gate 		goto common2;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	case KRB_FORWARD:		/* Forwarded credentials follow */
5550Sstevel@tonic-gate 		(void) strncpy((char *)buf, " FORWARD", buflen);
5560Sstevel@tonic-gate 		goto common2;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	case KRB_FORWARD_ACCEPT:	/* Forwarded credentials accepted */
5590Sstevel@tonic-gate 		(void) strncpy((char *)buf, " FORWARD_ACCEPT", buflen);
5600Sstevel@tonic-gate 		goto common2;
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	case KRB_FORWARD_REJECT:	/* Forwarded credentials rejected */
5630Sstevel@tonic-gate 					/* (reason might follow) */
5640Sstevel@tonic-gate 		(void) strncpy((char *)buf, " FORWARD_REJECT", buflen);
5650Sstevel@tonic-gate 		goto common2;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	default:
5680Sstevel@tonic-gate 		(void) snprintf(lbuf, AUTH_LBUF_BUFSIZ,
5690Sstevel@tonic-gate 			gettext(" %d (unknown)"),
5700Sstevel@tonic-gate 			data[3]);
5710Sstevel@tonic-gate 		(void) strncpy((char *)buf, lbuf, buflen);
5720Sstevel@tonic-gate 	common2:
5730Sstevel@tonic-gate 		BUMP(buf, buflen);
5740Sstevel@tonic-gate 		for (i = 4; i < cnt; i++) {
5750Sstevel@tonic-gate 			(void) snprintf(lbuf, AUTH_LBUF_BUFSIZ, " %d", data[i]);
5760Sstevel@tonic-gate 			(void) strncpy((char *)buf, lbuf, buflen);
5770Sstevel@tonic-gate 			BUMP(buf, buflen);
5780Sstevel@tonic-gate 		}
5790Sstevel@tonic-gate 		break;
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate }
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate void
krb5_profile_get_options(char * host,char * realm,profile_options_boolean * optionsp)5840Sstevel@tonic-gate krb5_profile_get_options(char *host, char *realm,
5850Sstevel@tonic-gate 	profile_options_boolean *optionsp)
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate 	char	**realms = NULL;
5880Sstevel@tonic-gate 	krb5_error_code err = 0;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (!telnet_context) {
5910Sstevel@tonic-gate 	    err = krb5_init_context(&telnet_context);
5920Sstevel@tonic-gate 	    if (err) {
5930Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
5940Sstevel@tonic-gate 			"Error initializing Kerberos 5 library: %s\n"),
5950Sstevel@tonic-gate 			error_message(err));
5960Sstevel@tonic-gate 		return;
5970Sstevel@tonic-gate 	    }
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if ((realmdef[1] = realm) == NULL) {
6010Sstevel@tonic-gate 		err = krb5_get_host_realm(telnet_context, host, &realms);
6020Sstevel@tonic-gate 		if (err) {
6030Sstevel@tonic-gate 		    (void) fprintf(stderr, gettext(
6040Sstevel@tonic-gate 			"Error getting Kerberos 5 realms for: %s (%s)\n"),
6050Sstevel@tonic-gate 			host, error_message(err));
6060Sstevel@tonic-gate 		    return;
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 		realmdef[1] = realms[0];
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	profile_get_options_boolean(telnet_context->profile,
6120Sstevel@tonic-gate 		realmdef, optionsp);
6130Sstevel@tonic-gate 	profile_get_options_boolean(telnet_context->profile,
6140Sstevel@tonic-gate 		appdef, optionsp);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate static void
kerberos5_forward(Authenticator * ap)6180Sstevel@tonic-gate kerberos5_forward(Authenticator *ap)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	krb5_error_code retval;
6210Sstevel@tonic-gate 	krb5_ccache ccache;
6220Sstevel@tonic-gate 	krb5_principal client = 0;
6230Sstevel@tonic-gate 	krb5_principal server = 0;
6240Sstevel@tonic-gate 	krb5_data forw_creds;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	forw_creds.data = 0;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	if ((retval = krb5_cc_default(telnet_context, &ccache))) {
6290Sstevel@tonic-gate 	    if (auth_debug_mode)
6300Sstevel@tonic-gate 		(void) printf(gettext(
6310Sstevel@tonic-gate 			"Kerberos V5: could not get default ccache - %s\r\n"),
6320Sstevel@tonic-gate 			error_message(retval));
6330Sstevel@tonic-gate 	    return;
6340Sstevel@tonic-gate 	}
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 	retval = krb5_cc_get_principal(telnet_context, ccache, &client);
6370Sstevel@tonic-gate 	if (retval) {
6380Sstevel@tonic-gate 		if (auth_debug_mode)
6390Sstevel@tonic-gate 			(void) printf(gettext(
6400Sstevel@tonic-gate 				"Kerberos V5: could not get default "
6410Sstevel@tonic-gate 				"principal - %s\r\n"), error_message(retval));
6420Sstevel@tonic-gate 		goto cleanup;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	retval = krb5_sname_to_principal(telnet_context, RemoteHostName,
6460Sstevel@tonic-gate 		"host", KRB5_NT_SRV_HST, &server);
6470Sstevel@tonic-gate 	if (retval) {
6480Sstevel@tonic-gate 		if (auth_debug_mode)
6490Sstevel@tonic-gate 			(void) printf(gettext(
6500Sstevel@tonic-gate 				"Kerberos V5: could not make server "
6510Sstevel@tonic-gate 				"principal - %s\r\n"), error_message(retval));
6520Sstevel@tonic-gate 		goto cleanup;
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	retval = krb5_auth_con_genaddrs(telnet_context, auth_context, net,
6560Sstevel@tonic-gate 				KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
6570Sstevel@tonic-gate 	if (retval) {
6580Sstevel@tonic-gate 		if (auth_debug_mode)
6590Sstevel@tonic-gate 			(void) printf(gettext(
6600Sstevel@tonic-gate 				"Kerberos V5: could not gen local full "
6610Sstevel@tonic-gate 				"address - %s\r\n"), error_message(retval));
6620Sstevel@tonic-gate 		goto cleanup;
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	retval = krb5_fwd_tgt_creds(telnet_context, auth_context, 0, client,
6660Sstevel@tonic-gate 		server, ccache, forward_flags & OPTS_FORWARDABLE_CREDS,
6670Sstevel@tonic-gate 		&forw_creds);
6680Sstevel@tonic-gate 	if (retval) {
6690Sstevel@tonic-gate 		if (auth_debug_mode)
6700Sstevel@tonic-gate 			(void) printf(gettext(
6710Sstevel@tonic-gate 				"Kerberos V5: error getting forwarded "
6720Sstevel@tonic-gate 				"creds - %s\r\n"), error_message(retval));
6730Sstevel@tonic-gate 		goto cleanup;
6740Sstevel@tonic-gate 	}
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/* Send forwarded credentials */
6770Sstevel@tonic-gate 	if (!krb5_send_data(ap, KRB_FORWARD, forw_creds.data,
6780Sstevel@tonic-gate 		forw_creds.length)) {
6790Sstevel@tonic-gate 		    if (auth_debug_mode)
6800Sstevel@tonic-gate 			(void) printf(gettext(
6810Sstevel@tonic-gate 			    "Not enough room for authentication data\r\n"));
6820Sstevel@tonic-gate 	} else if (auth_debug_mode)
6830Sstevel@tonic-gate 		(void) printf(gettext(
6840Sstevel@tonic-gate 		    "Forwarded local Kerberos V5 credentials to server\r\n"));
6850Sstevel@tonic-gate cleanup:
6860Sstevel@tonic-gate 	if (client)
6870Sstevel@tonic-gate 		krb5_free_principal(telnet_context, client);
6880Sstevel@tonic-gate 	if (server)
6890Sstevel@tonic-gate 		krb5_free_principal(telnet_context, server);
6900Sstevel@tonic-gate 	if (forw_creds.data)
6910Sstevel@tonic-gate 		free(forw_creds.data);
6920Sstevel@tonic-gate 	/* LINTED */
6930Sstevel@tonic-gate 	krb5_cc_close(telnet_context, ccache);
6940Sstevel@tonic-gate }
695