17c478bd9Sstevel@tonic-gate /*
20b4fd3b1SSurya Prakki  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
61fa2a664SJoshua M. Clulow /*	Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
71fa2a664SJoshua M. Clulow /*	  All Rights Reserved */
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 The Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
147c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
157c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
167c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
177c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
187c478bd9Sstevel@tonic-gate  * by the University of California, Berkeley.  The name of the
197c478bd9Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
207c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
217c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
227c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
237c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * remote login server:
287c478bd9Sstevel@tonic-gate  *	remuser\0
297c478bd9Sstevel@tonic-gate  *	locuser\0
307c478bd9Sstevel@tonic-gate  *	terminal info\0
317c478bd9Sstevel@tonic-gate  *	data
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <time.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <sys/socket.h>
387c478bd9Sstevel@tonic-gate #include <sys/wait.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <netinet/in.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate #include <signal.h>
447c478bd9Sstevel@tonic-gate #include <fcntl.h>
457c478bd9Sstevel@tonic-gate #include <stdio.h>
467c478bd9Sstevel@tonic-gate #include <netdb.h>
477c478bd9Sstevel@tonic-gate #include <syslog.h>
487c478bd9Sstevel@tonic-gate #include <string.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <alloca.h>
527c478bd9Sstevel@tonic-gate #include <stropts.h>
537c478bd9Sstevel@tonic-gate #include <sac.h>	/* for SC_WILDC */
547c478bd9Sstevel@tonic-gate #include <utmpx.h>
557c478bd9Sstevel@tonic-gate #include <sys/filio.h>
567c478bd9Sstevel@tonic-gate #include <sys/logindmux.h>
577c478bd9Sstevel@tonic-gate #include <sys/rlioctl.h>
587c478bd9Sstevel@tonic-gate #include <sys/termios.h>
597c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
607c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
617c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
627c478bd9Sstevel@tonic-gate #include <strings.h>
637c478bd9Sstevel@tonic-gate #include <com_err.h>
647c478bd9Sstevel@tonic-gate #include <k5-int.h>
657c478bd9Sstevel@tonic-gate #include <kcmd.h>
667c478bd9Sstevel@tonic-gate #include <krb5_repository.h>
677c478bd9Sstevel@tonic-gate #include <sys/cryptmod.h>
687c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
697243fb49Sjbeck #include <addr_match.h>
7032885d59Sgtb #include <store_forw_creds.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	KRB5_RECVAUTH_V5 5
737c478bd9Sstevel@tonic-gate #define	UT_NAMESIZE	sizeof (((struct utmpx *)0)->ut_name)
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static char lusername[UT_NAMESIZE+1];
767c478bd9Sstevel@tonic-gate static char rusername[UT_NAMESIZE+1];
777c478bd9Sstevel@tonic-gate static char *krusername = NULL;
787c478bd9Sstevel@tonic-gate static char term[64];
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static krb5_ccache ccache = NULL;
817c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key = NULL;
827c478bd9Sstevel@tonic-gate static int chksum_flag = 0;
837c478bd9Sstevel@tonic-gate static int use_auth = 0;
847c478bd9Sstevel@tonic-gate static enum kcmd_proto kcmd_protocol;
857c478bd9Sstevel@tonic-gate #ifdef ALLOW_KCMD_V2
867c478bd9Sstevel@tonic-gate static krb5_data encr_iv = { NULL, 0 };
877c478bd9Sstevel@tonic-gate static krb5_data decr_iv = { NULL, 0 };
887c478bd9Sstevel@tonic-gate #endif /* ALLOW_KCMD_V2 */
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #define	CHKSUM_REQUIRED 0x01
917c478bd9Sstevel@tonic-gate #define	CHKSUM_IGNORED  0x02
927c478bd9Sstevel@tonic-gate #define	VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\
937c478bd9Sstevel@tonic-gate 			(x) == CHKSUM_IGNORED)
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	PWD_IF_FAIL  0x01
967c478bd9Sstevel@tonic-gate #define	PWD_REQUIRED 0x02
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate #define	AUTH_NONE 0x00
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate #define	ARGSTR "k5exEXciM:s:S:D:"
1017c478bd9Sstevel@tonic-gate #define	DEFAULT_TOS 16
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #define	KRB5_PROG_NAME "krlogin"
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	SECURE_MSG "This rlogin session is using encryption " \
1067c478bd9Sstevel@tonic-gate 	"for all data transmissions.\r\n"
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate #define	KRB_V5_SENDAUTH_VERS	"KRB5_SENDAUTH_V1.0"
1097c478bd9Sstevel@tonic-gate #define	KRB5_RECVAUTH_V5	5
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static krb5_error_code krb5_compat_recvauth(krb5_context context,
1127c478bd9Sstevel@tonic-gate 					    krb5_auth_context *auth_context,
1137c478bd9Sstevel@tonic-gate 					    krb5_pointer fdp,
1147c478bd9Sstevel@tonic-gate 					    krb5_principal server,
1157c478bd9Sstevel@tonic-gate 					    krb5_int32 flags,
1167c478bd9Sstevel@tonic-gate 					    krb5_keytab keytab,
1177c478bd9Sstevel@tonic-gate 					    krb5_ticket **ticket,
1187c478bd9Sstevel@tonic-gate 					    krb5_int32 *auth_sys,
1197c478bd9Sstevel@tonic-gate 					    krb5_data *version);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab);
1227c478bd9Sstevel@tonic-gate static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer,
1257c478bd9Sstevel@tonic-gate 					krb5_data *);
1267c478bd9Sstevel@tonic-gate extern krb5_error_code krb5_net_read(krb5_context, int, char *, int);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate #define	LOGIN_PROGRAM "/bin/login"
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate #define	DEFAULT_PROG_NAME	"rlogin"
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static const char *pam_prog_name = DEFAULT_PROG_NAME;
1337c478bd9Sstevel@tonic-gate static void	rmut(void);
1347c478bd9Sstevel@tonic-gate static void	doit(int,  struct sockaddr_storage *, krb5_context, int,
1357c478bd9Sstevel@tonic-gate 		    krb5_keytab);
1367c478bd9Sstevel@tonic-gate static void	protocol(int, int, int);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static int	readstream(int, char *, int);
1397c478bd9Sstevel@tonic-gate static void	fatal(int, const char *);
1407c478bd9Sstevel@tonic-gate static void	fatalperror(int, const char *);
1417c478bd9Sstevel@tonic-gate static int	send_oob(int fd, void *ptr, size_t count);
1427c478bd9Sstevel@tonic-gate static int	removemod(int f, char *modname);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static int
issock(int fd)1457c478bd9Sstevel@tonic-gate issock(int fd)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	struct stat stats;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (fstat(fd, &stats) == -1)
1507c478bd9Sstevel@tonic-gate 		return (0);
1517c478bd9Sstevel@tonic-gate 	return (S_ISSOCK(stats.st_mode));
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * audit_rlogin_settid stores the terminal id while it is still
1567c478bd9Sstevel@tonic-gate  * available.  Subsequent calls to adt_load_hostname() return
1577c478bd9Sstevel@tonic-gate  * the id which is stored here.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static int
audit_rlogin_settid(int fd)1607c478bd9Sstevel@tonic-gate audit_rlogin_settid(int fd) {
1617c478bd9Sstevel@tonic-gate 	adt_session_data_t	*ah;
1627c478bd9Sstevel@tonic-gate 	adt_termid_t		*termid;
1637c478bd9Sstevel@tonic-gate 	int			rc;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if ((rc = adt_start_session(&ah, NULL, 0)) == 0) {
1667c478bd9Sstevel@tonic-gate 		if ((rc = adt_load_termid(fd, &termid)) == 0) {
1677c478bd9Sstevel@tonic-gate 			if ((rc = adt_set_user(ah, ADT_NO_AUDIT,
1687c478bd9Sstevel@tonic-gate 			    ADT_NO_AUDIT, 0, ADT_NO_AUDIT,
1697c478bd9Sstevel@tonic-gate 			    termid, ADT_SETTID)) == 0)
1707c478bd9Sstevel@tonic-gate 				(void) adt_set_proc(ah);
1717c478bd9Sstevel@tonic-gate 			free(termid);
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 		(void) adt_end_session(ah);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	return (rc);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /* ARGSUSED */
180740638c8Sbw int
main(int argc,char * argv[])1817c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	int on = 1;
1847c478bd9Sstevel@tonic-gate 	socklen_t fromlen;
1857c478bd9Sstevel@tonic-gate 	struct sockaddr_storage from;
1867c478bd9Sstevel@tonic-gate 	int fd = -1;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	extern char *optarg;
189*ef150c2bSRichard Lowe 	int c;
1907c478bd9Sstevel@tonic-gate 	int tos = -1;
1917c478bd9Sstevel@tonic-gate 	krb5_context krb_context;
1927c478bd9Sstevel@tonic-gate 	krb5_keytab keytab = NULL;
1937c478bd9Sstevel@tonic-gate 	krb5_error_code status;
1947c478bd9Sstevel@tonic-gate 	char *realm = NULL;
1957c478bd9Sstevel@tonic-gate 	char *keytab_file = NULL;
1967c478bd9Sstevel@tonic-gate 	int encr_flag = 0;
1977c478bd9Sstevel@tonic-gate 	struct sockaddr_storage ouraddr;
1987c478bd9Sstevel@tonic-gate 	socklen_t ourlen;
1997c478bd9Sstevel@tonic-gate #ifdef DEBUG
2007c478bd9Sstevel@tonic-gate 	int debug_port = 0;
2017c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2027c478bd9Sstevel@tonic-gate 	openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, ARGSTR)) != -1) {
2057c478bd9Sstevel@tonic-gate 		switch (c) {
2067c478bd9Sstevel@tonic-gate 		case 'k':
2077c478bd9Sstevel@tonic-gate 		case '5':
2087c478bd9Sstevel@tonic-gate 			use_auth = KRB5_RECVAUTH_V5;
2097c478bd9Sstevel@tonic-gate 			break;
2107c478bd9Sstevel@tonic-gate 		case 'e':
2117c478bd9Sstevel@tonic-gate 		case 'E':
2127c478bd9Sstevel@tonic-gate 		case 'x':
2137c478bd9Sstevel@tonic-gate 		case 'X':
2147c478bd9Sstevel@tonic-gate 			encr_flag = 1;
2157c478bd9Sstevel@tonic-gate 			break;
2167c478bd9Sstevel@tonic-gate 		case 'M':
2177c478bd9Sstevel@tonic-gate 			realm = (char *)strdup(optarg);
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 		case 'S':
2207c478bd9Sstevel@tonic-gate 			keytab_file = (char *)strdup(optarg);
2217c478bd9Sstevel@tonic-gate 			break;
2227c478bd9Sstevel@tonic-gate 		case 'c':
2237c478bd9Sstevel@tonic-gate 			chksum_flag |= CHKSUM_REQUIRED;
2247c478bd9Sstevel@tonic-gate 			break;
2257c478bd9Sstevel@tonic-gate 		case 'i':
2267c478bd9Sstevel@tonic-gate 			chksum_flag |= CHKSUM_IGNORED;
2277c478bd9Sstevel@tonic-gate 			break;
2287c478bd9Sstevel@tonic-gate 		case 's':
2297c478bd9Sstevel@tonic-gate 			if (optarg == NULL || (tos = atoi(optarg)) < 0 ||
2307c478bd9Sstevel@tonic-gate 			    tos > 255) {
2317c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "%s: illegal tos value: "
2327c478bd9Sstevel@tonic-gate 				    "%s\n", argv[0], optarg);
2337c478bd9Sstevel@tonic-gate 			} else {
2347c478bd9Sstevel@tonic-gate 				if (tos < 0)
2357c478bd9Sstevel@tonic-gate 					tos = DEFAULT_TOS;
2367c478bd9Sstevel@tonic-gate 			}
2377c478bd9Sstevel@tonic-gate 			break;
2387c478bd9Sstevel@tonic-gate #ifdef DEBUG
2397c478bd9Sstevel@tonic-gate 		case 'D':
2407c478bd9Sstevel@tonic-gate 			debug_port = atoi(optarg);
2417c478bd9Sstevel@tonic-gate 			break;
2427c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2437c478bd9Sstevel@tonic-gate 		default:
2447c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Unrecognized command line option "
245e1317789SRameshkumar Ramasamy 			    "(-%c), exiting", optopt);
2467c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	if (use_auth == KRB5_RECVAUTH_V5) {
2507c478bd9Sstevel@tonic-gate 		status = krb5_init_context(&krb_context);
2517c478bd9Sstevel@tonic-gate 		if (status) {
2527c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Error initializing krb5: %s",
2537c478bd9Sstevel@tonic-gate 			    error_message(status));
2547c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 		if (realm != NULL)
2570b4fd3b1SSurya Prakki 			(void) krb5_set_default_realm(krb_context, realm);
2587c478bd9Sstevel@tonic-gate 		if (keytab_file != NULL) {
2597c478bd9Sstevel@tonic-gate 			if ((status = krb5_kt_resolve(krb_context,
2607c478bd9Sstevel@tonic-gate 						    keytab_file,
2617c478bd9Sstevel@tonic-gate 						    &keytab))) {
2627c478bd9Sstevel@tonic-gate 				com_err(argv[0],
2637c478bd9Sstevel@tonic-gate 					status,
2647c478bd9Sstevel@tonic-gate 					"while resolving srvtab file %s",
2657c478bd9Sstevel@tonic-gate 					keytab_file);
2667c478bd9Sstevel@tonic-gate 				exit(EXIT_FAILURE);
2677c478bd9Sstevel@tonic-gate 			}
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate #ifdef DEBUG
2727c478bd9Sstevel@tonic-gate 	if (debug_port) {
2737c478bd9Sstevel@tonic-gate 		int s;
2747c478bd9Sstevel@tonic-gate 		struct sockaddr_in sin;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 		if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
2777c478bd9Sstevel@tonic-gate 			fatalperror(STDERR_FILENO, "Error in socket");
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		(void) memset((char *)&sin, 0, sizeof (sin));
2817c478bd9Sstevel@tonic-gate 		sin.sin_family = AF_INET;
2827c478bd9Sstevel@tonic-gate 		sin.sin_port = htons(debug_port);
2837c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = INADDR_ANY;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
2867c478bd9Sstevel@tonic-gate 					(char *)&on, sizeof (on));
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 		if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
2897c478bd9Sstevel@tonic-gate 			fatalperror(STDERR_FILENO, "bind error");
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		if ((listen(s, 5)) < 0) {
2937c478bd9Sstevel@tonic-gate 			fatalperror(STDERR_FILENO, "listen error");
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		fromlen = sizeof (from);
2977c478bd9Sstevel@tonic-gate 		if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) {
2987c478bd9Sstevel@tonic-gate 			fatalperror(STDERR_FILENO, "accept error");
2997c478bd9Sstevel@tonic-gate 		}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		(void) close(s);
3027c478bd9Sstevel@tonic-gate 	} else
3037c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3047c478bd9Sstevel@tonic-gate 	{
3057c478bd9Sstevel@tonic-gate 		if (!issock(STDIN_FILENO))
3067c478bd9Sstevel@tonic-gate 			fatal(STDIN_FILENO,
3077c478bd9Sstevel@tonic-gate 				"stdin is not a socket file descriptor");
3087c478bd9Sstevel@tonic-gate 		fd = STDIN_FILENO;
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	fromlen = sizeof (from);
3127c478bd9Sstevel@tonic-gate 	if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0)
3137c478bd9Sstevel@tonic-gate 		fatalperror(STDERR_FILENO, "getpeername");
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (audit_rlogin_settid(fd))	/* set terminal ID */
3167c478bd9Sstevel@tonic-gate 		fatalperror(STDERR_FILENO, "audit");
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
3197c478bd9Sstevel@tonic-gate 	    sizeof (on)) < 0)
3207c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m");
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (!VALID_CHKSUM(chksum_flag)) {
3237c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Configuration error: mutually exclusive "
3247c478bd9Sstevel@tonic-gate 		    "options specified (-c and -i)");
3257c478bd9Sstevel@tonic-gate 		fatal(fd, "Checksums are required and ignored (-c and -i);"
3267c478bd9Sstevel@tonic-gate 		    "these options are mutually exclusive - check "
3277c478bd9Sstevel@tonic-gate 		    "the documentation.");
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 	ourlen = sizeof (ouraddr);
3307c478bd9Sstevel@tonic-gate 	if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) {
3317c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "getsockname error: %m");
3327c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	if (tos != -1 &&
3367c478bd9Sstevel@tonic-gate 	    ouraddr.ss_family != AF_INET6 &&
3377c478bd9Sstevel@tonic-gate 	    setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos,
3387c478bd9Sstevel@tonic-gate 					sizeof (tos)) < 0 &&
3397c478bd9Sstevel@tonic-gate 					errno != ENOPROTOOPT) {
3407c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 	doit(fd, &from, krb_context, encr_flag, keytab);
343740638c8Sbw 	return (0);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate static void	cleanup(int);
3477c478bd9Sstevel@tonic-gate static int	nsize = 0;	/* bytes read prior to pushing rlmod */
3487c478bd9Sstevel@tonic-gate static char	*rlbuf;		/* buffer where nbytes are read to */
3497c478bd9Sstevel@tonic-gate static char	*line;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate static struct winsize win = { 0, 0, 0, 0 };
3527c478bd9Sstevel@tonic-gate static pid_t pid;
3537c478bd9Sstevel@tonic-gate static char hostname[MAXHOSTNAMELEN + 1];
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate static void
getstr(int f,char * buf,int cnt,char * err)3567c478bd9Sstevel@tonic-gate getstr(int f, char *buf, int cnt, char *err)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	char c;
3597c478bd9Sstevel@tonic-gate 	do {
3607c478bd9Sstevel@tonic-gate 		if (read(f, &c, 1) != 1 || (--cnt < 0)) {
3617c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Error reading \'%s\' field", err);
3627c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 		*buf++ = c;
3657c478bd9Sstevel@tonic-gate 	} while (c != '\0');
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate static krb5_error_code
recvauth(int f,krb5_context krb_context,unsigned int * valid_checksum,krb5_ticket ** ticket,int * auth_type,krb5_principal * client,int encr_flag,krb5_keytab keytab)3697c478bd9Sstevel@tonic-gate recvauth(int f,
3707c478bd9Sstevel@tonic-gate 	krb5_context krb_context,
3717c478bd9Sstevel@tonic-gate 	unsigned int *valid_checksum,
3727c478bd9Sstevel@tonic-gate 	krb5_ticket **ticket,
3737c478bd9Sstevel@tonic-gate 	int *auth_type,
3747c478bd9Sstevel@tonic-gate 	krb5_principal *client,
3757c478bd9Sstevel@tonic-gate 	int encr_flag,
3767c478bd9Sstevel@tonic-gate 	krb5_keytab keytab)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	krb5_error_code status = 0;
3797c478bd9Sstevel@tonic-gate 	krb5_auth_context auth_context = NULL;
3807c478bd9Sstevel@tonic-gate 	krb5_rcache rcache;
3817c478bd9Sstevel@tonic-gate 	krb5_authenticator *authenticator;
3827c478bd9Sstevel@tonic-gate 	krb5_data inbuf;
3837c478bd9Sstevel@tonic-gate 	krb5_data auth_version;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	*valid_checksum = 0;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if ((status = krb5_auth_con_init(krb_context, &auth_context)))
3887c478bd9Sstevel@tonic-gate 		return (status);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/* Only need remote address for rd_cred() to verify client */
3917c478bd9Sstevel@tonic-gate 	if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
3927c478bd9Sstevel@tonic-gate 			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
3937c478bd9Sstevel@tonic-gate 		return (status);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
3967c478bd9Sstevel@tonic-gate 	if (status)
3977c478bd9Sstevel@tonic-gate 		return (status);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (!rcache) {
4007c478bd9Sstevel@tonic-gate 		krb5_principal server;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		status = krb5_sname_to_principal(krb_context, 0, 0,
4037c478bd9Sstevel@tonic-gate 						KRB5_NT_SRV_HST, &server);
4047c478bd9Sstevel@tonic-gate 		if (status)
4057c478bd9Sstevel@tonic-gate 			return (status);
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		status = krb5_get_server_rcache(krb_context,
4087c478bd9Sstevel@tonic-gate 				krb5_princ_component(krb_context, server, 0),
4097c478bd9Sstevel@tonic-gate 				&rcache);
4107c478bd9Sstevel@tonic-gate 		krb5_free_principal(krb_context, server);
4117c478bd9Sstevel@tonic-gate 		if (status)
4127c478bd9Sstevel@tonic-gate 			return (status);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		status = krb5_auth_con_setrcache(krb_context, auth_context,
4157c478bd9Sstevel@tonic-gate 						rcache);
4167c478bd9Sstevel@tonic-gate 		if (status)
4177c478bd9Sstevel@tonic-gate 			return (status);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 	if ((status = krb5_compat_recvauth(krb_context,
4207c478bd9Sstevel@tonic-gate 					&auth_context,
4217c478bd9Sstevel@tonic-gate 					&f,
4227c478bd9Sstevel@tonic-gate 					NULL,	/* Specify daemon principal */
4237c478bd9Sstevel@tonic-gate 					0,	/* no flags */
4247c478bd9Sstevel@tonic-gate 					keytab,	/* NULL to use v5srvtab */
4257c478bd9Sstevel@tonic-gate 					ticket,	/* return ticket */
4267c478bd9Sstevel@tonic-gate 					auth_type, /* authentication system */
4277c478bd9Sstevel@tonic-gate 					&auth_version))) {
4287c478bd9Sstevel@tonic-gate 		if (*auth_type == KRB5_RECVAUTH_V5) {
4297c478bd9Sstevel@tonic-gate 			/*
4307c478bd9Sstevel@tonic-gate 			 * clean up before exiting
4317c478bd9Sstevel@tonic-gate 			 */
4327c478bd9Sstevel@tonic-gate 			getstr(f, rusername, sizeof (rusername), "remuser");
4337c478bd9Sstevel@tonic-gate 			getstr(f, lusername, sizeof (lusername), "locuser");
4347c478bd9Sstevel@tonic-gate 			getstr(f, term, sizeof (term), "Terminal type");
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 		return (status);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	getstr(f, lusername, sizeof (lusername), "locuser");
4407c478bd9Sstevel@tonic-gate 	getstr(f, term, sizeof (term), "Terminal type");
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
4437c478bd9Sstevel@tonic-gate 	if (auth_version.length != 9 || auth_version.data == NULL) {
4447c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Bad application protocol version length in "
4457c478bd9Sstevel@tonic-gate 		    "KRB5 exchange, exiting");
4467c478bd9Sstevel@tonic-gate 		fatal(f, "Bad application version length, exiting.");
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Determine which Kerberos CMD protocol was used.
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
4527c478bd9Sstevel@tonic-gate 		kcmd_protocol = KCMD_OLD_PROTOCOL;
4537c478bd9Sstevel@tonic-gate 	} else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
4547c478bd9Sstevel@tonic-gate 		kcmd_protocol = KCMD_NEW_PROTOCOL;
4557c478bd9Sstevel@tonic-gate 	} else {
4567c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
4577c478bd9Sstevel@tonic-gate 			(char *)auth_version.data);
4587c478bd9Sstevel@tonic-gate 		fatal(f, "Unrecognized KCMD protocol, exiting");
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
4627c478bd9Sstevel@tonic-gate 		kcmd_protocol == KCMD_OLD_PROTOCOL) {
4637c478bd9Sstevel@tonic-gate 		if ((status = krb5_auth_con_getauthenticator(krb_context,
4647c478bd9Sstevel@tonic-gate 							    auth_context,
4657c478bd9Sstevel@tonic-gate 							    &authenticator)))
4667c478bd9Sstevel@tonic-gate 			return (status);
4677c478bd9Sstevel@tonic-gate 		if (authenticator->checksum) {
4687c478bd9Sstevel@tonic-gate 			struct sockaddr_storage adr;
4697c478bd9Sstevel@tonic-gate 			int adr_length = sizeof (adr);
4707c478bd9Sstevel@tonic-gate 			int buflen;
4717c478bd9Sstevel@tonic-gate 			krb5_data input;
4727c478bd9Sstevel@tonic-gate 			krb5_keyblock key;
4737c478bd9Sstevel@tonic-gate 			char *chksumbuf;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 			/*
4767c478bd9Sstevel@tonic-gate 			 * Define the lenght of the chksum buffer.
4777c478bd9Sstevel@tonic-gate 			 * chksum string = "[portnum]:termstr:username"
4787c478bd9Sstevel@tonic-gate 			 * The extra 32 is to hold a integer string for
4797c478bd9Sstevel@tonic-gate 			 * the portnumber.
4807c478bd9Sstevel@tonic-gate 			 */
4817c478bd9Sstevel@tonic-gate 			buflen = strlen(term) + strlen(lusername) + 32;
4827c478bd9Sstevel@tonic-gate 			chksumbuf = (char *)malloc(buflen);
4837c478bd9Sstevel@tonic-gate 			if (chksumbuf == 0) {
4847c478bd9Sstevel@tonic-gate 				krb5_free_authenticator(krb_context,
4857c478bd9Sstevel@tonic-gate 							authenticator);
4867c478bd9Sstevel@tonic-gate 				fatal(f, "Out of memory error");
4877c478bd9Sstevel@tonic-gate 			}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			if (getsockname(f, (struct sockaddr *)&adr,
4907c478bd9Sstevel@tonic-gate 							&adr_length) != 0) {
4917c478bd9Sstevel@tonic-gate 				krb5_free_authenticator(krb_context,
4927c478bd9Sstevel@tonic-gate 							authenticator);
4937c478bd9Sstevel@tonic-gate 				fatal(f, "getsockname error");
4947c478bd9Sstevel@tonic-gate 			}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 			(void) snprintf(chksumbuf, buflen,
4977c478bd9Sstevel@tonic-gate 					"%u:%s%s",
4987c478bd9Sstevel@tonic-gate 					ntohs(SOCK_PORT(adr)),
4997c478bd9Sstevel@tonic-gate 					term, lusername);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 			input.data = chksumbuf;
5027c478bd9Sstevel@tonic-gate 			input.length = strlen(chksumbuf);
5037c478bd9Sstevel@tonic-gate 			key.contents = (*ticket)->enc_part2->session->contents;
5047c478bd9Sstevel@tonic-gate 			key.length = (*ticket)->enc_part2->session->length;
5057c478bd9Sstevel@tonic-gate 			status = krb5_c_verify_checksum(krb_context,
5067c478bd9Sstevel@tonic-gate 						&key, 0,
5077c478bd9Sstevel@tonic-gate 						&input,
5087c478bd9Sstevel@tonic-gate 						authenticator->checksum,
5097c478bd9Sstevel@tonic-gate 						valid_checksum);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 			if (status == 0 && *valid_checksum == 0)
5127c478bd9Sstevel@tonic-gate 				status = KRB5KRB_AP_ERR_BAD_INTEGRITY;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 			if (chksumbuf)
5157c478bd9Sstevel@tonic-gate 				krb5_xfree(chksumbuf);
5167c478bd9Sstevel@tonic-gate 			if (status) {
5177c478bd9Sstevel@tonic-gate 				krb5_free_authenticator(krb_context,
5187c478bd9Sstevel@tonic-gate 							authenticator);
5197c478bd9Sstevel@tonic-gate 				return (status);
5207c478bd9Sstevel@tonic-gate 			}
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 		krb5_free_authenticator(krb_context, authenticator);
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if ((status = krb5_copy_principal(krb_context,
5267c478bd9Sstevel@tonic-gate 					(*ticket)->enc_part2->client,
5277c478bd9Sstevel@tonic-gate 					client)))
5287c478bd9Sstevel@tonic-gate 		return (status);
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	/* Get the Unix username of the remote user */
5317c478bd9Sstevel@tonic-gate 	getstr(f, rusername, sizeof (rusername), "remuser");
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/* Get the Kerberos principal name string of the remote user */
5347c478bd9Sstevel@tonic-gate 	if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
5357c478bd9Sstevel@tonic-gate 		return (status);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate #ifdef DEBUG
5387c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
5397c478bd9Sstevel@tonic-gate 	    (krusername != NULL ? krusername : "<unknown>"));
5407c478bd9Sstevel@tonic-gate #endif
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	if (encr_flag) {
5437c478bd9Sstevel@tonic-gate 		status = krb5_auth_con_getremotesubkey(krb_context,
5447c478bd9Sstevel@tonic-gate 						    auth_context,
5457c478bd9Sstevel@tonic-gate 						    &session_key);
5467c478bd9Sstevel@tonic-gate 		if (status) {
5477c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Error getting KRB5 session "
5487c478bd9Sstevel@tonic-gate 			    "subkey, exiting");
5497c478bd9Sstevel@tonic-gate 			fatal(f, "Error getting KRB5 session subkey, exiting");
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 		/*
5527c478bd9Sstevel@tonic-gate 		 * The "new" protocol requires that a subkey be sent.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		if (session_key == NULL &&
5557c478bd9Sstevel@tonic-gate 		    kcmd_protocol == KCMD_NEW_PROTOCOL) {
5567c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
5577c478bd9Sstevel@tonic-gate 			fatal(f, "No KRB5 session subkey sent, exiting");
5587c478bd9Sstevel@tonic-gate 		}
5597c478bd9Sstevel@tonic-gate 		/*
5607c478bd9Sstevel@tonic-gate 		 * The "old" protocol does not permit an authenticator subkey.
5617c478bd9Sstevel@tonic-gate 		 * The key is taken from the ticket instead (see below).
5627c478bd9Sstevel@tonic-gate 		 */
5637c478bd9Sstevel@tonic-gate 		if (session_key != NULL &&
5647c478bd9Sstevel@tonic-gate 		    kcmd_protocol == KCMD_OLD_PROTOCOL) {
5657c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "KRB5 session subkey not permitted "
5667c478bd9Sstevel@tonic-gate 			    "with old KCMD protocol, exiting");
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 			fatal(f, "KRB5 session subkey not permitted "
5697c478bd9Sstevel@tonic-gate 			    "with old KCMD protocol, exiting");
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 		/*
5727c478bd9Sstevel@tonic-gate 		 * If no key at this point, use the session key from
5737c478bd9Sstevel@tonic-gate 		 * the ticket.
5747c478bd9Sstevel@tonic-gate 		 */
5757c478bd9Sstevel@tonic-gate 		if (session_key == NULL) {
5767c478bd9Sstevel@tonic-gate 			/*
5777c478bd9Sstevel@tonic-gate 			 * Save the session key so we can configure the crypto
5787c478bd9Sstevel@tonic-gate 			 * module later.
5797c478bd9Sstevel@tonic-gate 			 */
5807c478bd9Sstevel@tonic-gate 			status = krb5_copy_keyblock(krb_context,
5817c478bd9Sstevel@tonic-gate 					    (*ticket)->enc_part2->session,
5827c478bd9Sstevel@tonic-gate 					    &session_key);
5837c478bd9Sstevel@tonic-gate 			if (status) {
5847c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "krb5_copy_keyblock failed");
5857c478bd9Sstevel@tonic-gate 				fatal(f, "krb5_copy_keyblock failed");
5867c478bd9Sstevel@tonic-gate 			}
5877c478bd9Sstevel@tonic-gate 		}
5887c478bd9Sstevel@tonic-gate 		/*
5897c478bd9Sstevel@tonic-gate 		 * If session key still cannot be found, we must
5907c478bd9Sstevel@tonic-gate 		 * exit because encryption is required here
5917c478bd9Sstevel@tonic-gate 		 * when encr_flag (-x) is set.
5927c478bd9Sstevel@tonic-gate 		 */
5937c478bd9Sstevel@tonic-gate 		if (session_key == NULL) {
5947c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "Could not find an encryption key,"
5957c478bd9Sstevel@tonic-gate 				    "exiting");
5967c478bd9Sstevel@tonic-gate 			fatal(f, "Encryption required but key not found, "
5977c478bd9Sstevel@tonic-gate 			    "exiting");
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	/*
6017c478bd9Sstevel@tonic-gate 	 * Use krb5_read_message to read the principal stuff.
6027c478bd9Sstevel@tonic-gate 	 */
6037c478bd9Sstevel@tonic-gate 	if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
6047c478bd9Sstevel@tonic-gate 					&inbuf)))
6057c478bd9Sstevel@tonic-gate 		fatal(f, "Error reading krb5 message");
6067c478bd9Sstevel@tonic-gate 
60732885d59Sgtb 	if (inbuf.length) { /* Forwarding being done, read creds */
60832885d59Sgtb 		krb5_creds **creds = NULL;
60932885d59Sgtb 
61032885d59Sgtb 		if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
61132885d59Sgtb 					    &creds, NULL)) {
61232885d59Sgtb 			if (rcache)
61332885d59Sgtb 				(void) krb5_rc_close(krb_context, rcache);
61432885d59Sgtb 			krb5_free_creds(krb_context, *creds);
61532885d59Sgtb 			fatal(f, "Can't get forwarded credentials");
61632885d59Sgtb 		}
61732885d59Sgtb 
61832885d59Sgtb 		/* Store the forwarded creds in the ccache */
61932885d59Sgtb 		if (status = store_forw_creds(krb_context,
62032885d59Sgtb 					    creds, *ticket, lusername,
62132885d59Sgtb 					    &ccache)) {
62232885d59Sgtb 			if (rcache)
62332885d59Sgtb 				(void) krb5_rc_close(krb_context, rcache);
62432885d59Sgtb 			krb5_free_creds(krb_context, *creds);
62532885d59Sgtb 			fatal(f, "Can't store forwarded credentials");
62632885d59Sgtb 		}
62732885d59Sgtb 		krb5_free_creds(krb_context, *creds);
6287c478bd9Sstevel@tonic-gate 	}
62932885d59Sgtb 
6307c478bd9Sstevel@tonic-gate 	if (rcache)
6317c478bd9Sstevel@tonic-gate 		(void) krb5_rc_close(krb_context, rcache);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	return (status);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate static void
do_krb_login(int f,char * host_addr,char * hostname,krb5_context krb_context,int encr_flag,krb5_keytab keytab)6377c478bd9Sstevel@tonic-gate do_krb_login(int f, char *host_addr, char *hostname,
6387c478bd9Sstevel@tonic-gate 	    krb5_context krb_context, int encr_flag,
6397c478bd9Sstevel@tonic-gate 	    krb5_keytab keytab)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 	krb5_error_code status;
6427c478bd9Sstevel@tonic-gate 	uint_t valid_checksum;
6437c478bd9Sstevel@tonic-gate 	krb5_ticket	*ticket = NULL;
6447c478bd9Sstevel@tonic-gate 	int auth_sys = 0;
6457c478bd9Sstevel@tonic-gate 	int auth_sent = 0;
6467c478bd9Sstevel@tonic-gate 	krb5_principal client = NULL;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (getuid())
6497c478bd9Sstevel@tonic-gate 		fatal(f, "Error authorizing KRB5 connection, "
6507c478bd9Sstevel@tonic-gate 			"server lacks privilege");
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	status = recvauth(f, krb_context, &valid_checksum, &ticket,
6537c478bd9Sstevel@tonic-gate 			&auth_sys, &client, encr_flag, keytab);
6547c478bd9Sstevel@tonic-gate 	if (status) {
6557c478bd9Sstevel@tonic-gate 		if (ticket)
6567c478bd9Sstevel@tonic-gate 			krb5_free_ticket(krb_context, ticket);
6577c478bd9Sstevel@tonic-gate 		if (status != 255)
6587c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
6597c478bd9Sstevel@tonic-gate 			    "Authentication failed from %s(%s): %s\n",
6607c478bd9Sstevel@tonic-gate 			    host_addr, hostname, error_message(status));
6617c478bd9Sstevel@tonic-gate 		fatal(f, "Kerberos authentication failed, exiting");
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	if (auth_sys != KRB5_RECVAUTH_V5) {
6657c478bd9Sstevel@tonic-gate 		fatal(f, "This server only supports Kerberos V5");
6667c478bd9Sstevel@tonic-gate 	} else {
6677c478bd9Sstevel@tonic-gate 		/*
6687c478bd9Sstevel@tonic-gate 		 * Authenticated OK, now check authorization.
6697c478bd9Sstevel@tonic-gate 		 */
6707c478bd9Sstevel@tonic-gate 		if (client && krb5_kuserok(krb_context, client, lusername))
6717c478bd9Sstevel@tonic-gate 		    auth_sent = KRB5_RECVAUTH_V5;
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	if (auth_sent == KRB5_RECVAUTH_V5 &&
6757c478bd9Sstevel@tonic-gate 	    kcmd_protocol == KCMD_OLD_PROTOCOL &&
6767c478bd9Sstevel@tonic-gate 	    chksum_flag == CHKSUM_REQUIRED && !valid_checksum) {
6777c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Client did not supply required checksum, "
6787c478bd9Sstevel@tonic-gate 		    "connection rejected.");
6797c478bd9Sstevel@tonic-gate 		fatal(f, "Client did not supply required checksum, "
6807c478bd9Sstevel@tonic-gate 		    "connection rejected.");
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (auth_sys != auth_sent) {
6847c478bd9Sstevel@tonic-gate 		char *msg_fail = NULL;
6857c478bd9Sstevel@tonic-gate 		int msgsize = 0;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 		if (ticket)
6887c478bd9Sstevel@tonic-gate 			krb5_free_ticket(krb_context, ticket);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		if (krusername != NULL) {
6917c478bd9Sstevel@tonic-gate 			/*
6927c478bd9Sstevel@tonic-gate 			 * msgsize must be enough to hold
6937c478bd9Sstevel@tonic-gate 			 * krusername, lusername and a brief
6947c478bd9Sstevel@tonic-gate 			 * message describing the failure.
6957c478bd9Sstevel@tonic-gate 			 */
6967c478bd9Sstevel@tonic-gate 			msgsize = strlen(krusername) +
6977c478bd9Sstevel@tonic-gate 				strlen(lusername) + 80;
6987c478bd9Sstevel@tonic-gate 			msg_fail = (char *)malloc(msgsize);
6997c478bd9Sstevel@tonic-gate 		}
7007c478bd9Sstevel@tonic-gate 		if (msg_fail == NULL) {
7017c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "User is not authorized to login to "
7027c478bd9Sstevel@tonic-gate 			    "specified account");
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			fatal(f, "User is not authorized to login to "
7057c478bd9Sstevel@tonic-gate 			    "specified account");
7067c478bd9Sstevel@tonic-gate 		}
7077c478bd9Sstevel@tonic-gate 		if (auth_sent != 0)
7087c478bd9Sstevel@tonic-gate 			(void) snprintf(msg_fail, msgsize,
7097c478bd9Sstevel@tonic-gate 					"Access denied because of improper "
7107c478bd9Sstevel@tonic-gate 					"KRB5 credentials");
7117c478bd9Sstevel@tonic-gate 		else
7127c478bd9Sstevel@tonic-gate 			(void) snprintf(msg_fail, msgsize,
7137c478bd9Sstevel@tonic-gate 					"User %s is not authorized to login "
7147c478bd9Sstevel@tonic-gate 					"to account %s",
7157c478bd9Sstevel@tonic-gate 					krusername, lusername);
7167c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "%s", msg_fail);
7177c478bd9Sstevel@tonic-gate 		fatal(f, msg_fail);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate  * stop_stream
7237c478bd9Sstevel@tonic-gate  *
7247c478bd9Sstevel@tonic-gate  * Utility routine to send a CRYPTIOCSTOP ioctl to the
7257c478bd9Sstevel@tonic-gate  * crypto module(cryptmod).
7267c478bd9Sstevel@tonic-gate  */
7277c478bd9Sstevel@tonic-gate static void
stop_stream(int fd,int dir)7287c478bd9Sstevel@tonic-gate stop_stream(int fd, int dir)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	struct strioctl  crioc;
7317c478bd9Sstevel@tonic-gate 	uint32_t stopdir = dir;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	crioc.ic_cmd = CRYPTIOCSTOP;
7347c478bd9Sstevel@tonic-gate 	crioc.ic_timout = -1;
7357c478bd9Sstevel@tonic-gate 	crioc.ic_len = sizeof (stopdir);
7367c478bd9Sstevel@tonic-gate 	crioc.ic_dp = (char *)&stopdir;
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &crioc))
7397c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m");
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate /*
7437c478bd9Sstevel@tonic-gate  * start_stream
7447c478bd9Sstevel@tonic-gate  *
7457c478bd9Sstevel@tonic-gate  * Utility routine to send a CRYPTIOCSTART ioctl to the
7467c478bd9Sstevel@tonic-gate  * crypto module(cryptmod).  This routine may contain optional
7477c478bd9Sstevel@tonic-gate  * payload data that the cryptmod will interpret as bytes that
7487c478bd9Sstevel@tonic-gate  * need to be decrypted and sent back up to the application
7497c478bd9Sstevel@tonic-gate  * via the data stream.
7507c478bd9Sstevel@tonic-gate  */
7517c478bd9Sstevel@tonic-gate static void
start_stream(int fd,int dir)7527c478bd9Sstevel@tonic-gate start_stream(int fd, int dir)
7537c478bd9Sstevel@tonic-gate {
7547c478bd9Sstevel@tonic-gate 	struct strioctl crioc;
7557c478bd9Sstevel@tonic-gate 	uint32_t iocval;
7567c478bd9Sstevel@tonic-gate 	size_t datalen = 0;
7577c478bd9Sstevel@tonic-gate 	char *data = NULL;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	if (dir == CRYPT_DECRYPT) {
7607c478bd9Sstevel@tonic-gate 		iocval = CRYPTIOCSTARTDEC;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 		/* Look for data not yet processed */
7637c478bd9Sstevel@tonic-gate 		if (ioctl(fd, I_NREAD, &datalen) < 0) {
7647c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "I_NREAD returned error %m");
7657c478bd9Sstevel@tonic-gate 			datalen = 0;
7667c478bd9Sstevel@tonic-gate 		} else {
7677c478bd9Sstevel@tonic-gate 			if (datalen > 0) {
7687c478bd9Sstevel@tonic-gate 				data = malloc(datalen);
7697c478bd9Sstevel@tonic-gate 				if (data != NULL) {
7707c478bd9Sstevel@tonic-gate 					int nbytes = read(fd, data, datalen);
7717c478bd9Sstevel@tonic-gate 					datalen = nbytes;
7727c478bd9Sstevel@tonic-gate 				} else {
7737c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
7747c478bd9Sstevel@tonic-gate 						"malloc error (%d bytes)",
7757c478bd9Sstevel@tonic-gate 						datalen);
7767c478bd9Sstevel@tonic-gate 					datalen = 0;
7777c478bd9Sstevel@tonic-gate 				}
7787c478bd9Sstevel@tonic-gate 			} else {
7797c478bd9Sstevel@tonic-gate 				datalen = 0;
7807c478bd9Sstevel@tonic-gate 			}
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 	} else {
7837c478bd9Sstevel@tonic-gate 		iocval = CRYPTIOCSTARTENC;
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	crioc.ic_cmd = iocval;
7877c478bd9Sstevel@tonic-gate 	crioc.ic_timout = -1;
7887c478bd9Sstevel@tonic-gate 	crioc.ic_len = datalen;
7897c478bd9Sstevel@tonic-gate 	crioc.ic_dp = data;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &crioc))
7927c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m");
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (data != NULL)
7957c478bd9Sstevel@tonic-gate 		free(data);
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate static int
configure_stream(int fd,krb5_keyblock * skey,int dir,krb5_data * ivec,uint_t iv_usage)7997c478bd9Sstevel@tonic-gate configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec,
8007c478bd9Sstevel@tonic-gate 		uint_t iv_usage)
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate 	struct cr_info_t setup_info;
8037c478bd9Sstevel@tonic-gate 	struct strioctl crioc;
8047c478bd9Sstevel@tonic-gate 	int retval = 0;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	switch (skey->enctype) {
8077c478bd9Sstevel@tonic-gate 	case ENCTYPE_DES_CBC_CRC:
8087c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC;
8097c478bd9Sstevel@tonic-gate 		break;
8107c478bd9Sstevel@tonic-gate 	case ENCTYPE_DES_CBC_MD5:
8117c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5;
8127c478bd9Sstevel@tonic-gate 		break;
8137c478bd9Sstevel@tonic-gate 	case ENCTYPE_DES_CBC_RAW:
8147c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL;
8157c478bd9Sstevel@tonic-gate 		break;
8167c478bd9Sstevel@tonic-gate 	case ENCTYPE_DES3_CBC_SHA1:
8177c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1;
8187c478bd9Sstevel@tonic-gate 		break;
8197c478bd9Sstevel@tonic-gate 	case ENCTYPE_ARCFOUR_HMAC:
8207c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5;
8217c478bd9Sstevel@tonic-gate 		break;
8227c478bd9Sstevel@tonic-gate 	case ENCTYPE_ARCFOUR_HMAC_EXP:
8237c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP;
8247c478bd9Sstevel@tonic-gate 		break;
8257c478bd9Sstevel@tonic-gate 	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
8267c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_AES128;
8277c478bd9Sstevel@tonic-gate 		break;
8287c478bd9Sstevel@tonic-gate 	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
8297c478bd9Sstevel@tonic-gate 		setup_info.crypto_method = CRYPT_METHOD_AES256;
8307c478bd9Sstevel@tonic-gate 		break;
8317c478bd9Sstevel@tonic-gate 	default:
8327c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Enctype in kerberos session key "
8337c478bd9Sstevel@tonic-gate 		    "is not supported by crypto module(%d)",
8347c478bd9Sstevel@tonic-gate 		    skey->enctype);
8357c478bd9Sstevel@tonic-gate 		return (-1);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 	if (ivec == NULL || ivec->length == 0) {
8387c478bd9Sstevel@tonic-gate 		(void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec));
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 		if (skey->enctype != ENCTYPE_ARCFOUR_HMAC &&
8417c478bd9Sstevel@tonic-gate 		    skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP)
8427c478bd9Sstevel@tonic-gate 			/* Kerberos IVs are 8 bytes long for DES keys */
8437c478bd9Sstevel@tonic-gate 			setup_info.iveclen = KRB5_MIT_DES_KEYSIZE;
8447c478bd9Sstevel@tonic-gate 		else
8457c478bd9Sstevel@tonic-gate 			setup_info.iveclen = 0;
8467c478bd9Sstevel@tonic-gate 	} else {
8477c478bd9Sstevel@tonic-gate 		(void) memcpy(&setup_info.ivec, ivec->data, ivec->length);
8487c478bd9Sstevel@tonic-gate 		setup_info.iveclen = ivec->length;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	setup_info.ivec_usage = iv_usage;
8527c478bd9Sstevel@tonic-gate 	(void) memcpy(&setup_info.key, skey->contents, skey->length);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	setup_info.keylen = skey->length;
8557c478bd9Sstevel@tonic-gate 	setup_info.direction_mask = dir;
8567c478bd9Sstevel@tonic-gate 	/*
8577c478bd9Sstevel@tonic-gate 	 * R* commands get special handling by crypto module -
8587c478bd9Sstevel@tonic-gate 	 * 4 byte length field is used before each encrypted block
8597c478bd9Sstevel@tonic-gate 	 * of data.
8607c478bd9Sstevel@tonic-gate 	 */
8617c478bd9Sstevel@tonic-gate 	setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ?
8627c478bd9Sstevel@tonic-gate 				CRYPTOPT_RCMD_MODE_V1 :
8637c478bd9Sstevel@tonic-gate 				CRYPTOPT_RCMD_MODE_V2);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	crioc.ic_cmd = CRYPTIOCSETUP;
8667c478bd9Sstevel@tonic-gate 	crioc.ic_timout = -1;
8677c478bd9Sstevel@tonic-gate 	crioc.ic_len = sizeof (setup_info);
8687c478bd9Sstevel@tonic-gate 	crioc.ic_dp = (char *)&setup_info;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &crioc)) {
8717c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m");
8727c478bd9Sstevel@tonic-gate 		retval = -1;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 	return (retval);
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate static krb5_error_code
krb5_compat_recvauth(krb5_context context,krb5_auth_context * auth_context,krb5_pointer fdp,krb5_principal server,krb5_int32 flags,krb5_keytab keytab,krb5_ticket ** ticket,krb5_int32 * auth_sys,krb5_data * version)8787c478bd9Sstevel@tonic-gate krb5_compat_recvauth(krb5_context context,
8797c478bd9Sstevel@tonic-gate 		    krb5_auth_context *auth_context,
8807c478bd9Sstevel@tonic-gate 		    krb5_pointer fdp,	/* IN */
8817c478bd9Sstevel@tonic-gate 		    krb5_principal server,	/* IN */
8827c478bd9Sstevel@tonic-gate 		    krb5_int32 flags,	/* IN */
8837c478bd9Sstevel@tonic-gate 		    krb5_keytab keytab,	/* IN */
8847c478bd9Sstevel@tonic-gate 		    krb5_ticket **ticket, /* OUT */
8857c478bd9Sstevel@tonic-gate 		    krb5_int32 *auth_sys, /* OUT */
8867c478bd9Sstevel@tonic-gate 		    krb5_data *version)   /* OUT */
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	krb5_int32 vlen;
8897c478bd9Sstevel@tonic-gate 	char	*buf;
8907c478bd9Sstevel@tonic-gate 	int	len, length;
8917c478bd9Sstevel@tonic-gate 	krb5_int32	retval;
8927c478bd9Sstevel@tonic-gate 	int		fd = *((int *)fdp);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4)
8957c478bd9Sstevel@tonic-gate 		return ((retval < 0) ? errno : ECONNABORTED);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	/*
8987c478bd9Sstevel@tonic-gate 	 * Assume that we're talking to a V5 recvauth; read in the
8997c478bd9Sstevel@tonic-gate 	 * the version string, and make sure it matches.
9007c478bd9Sstevel@tonic-gate 	 */
9017c478bd9Sstevel@tonic-gate 	len = (int)ntohl(vlen);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	if (len < 0 || len > 255)
9047c478bd9Sstevel@tonic-gate 		return (KRB5_SENDAUTH_BADAUTHVERS);
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	buf = malloc(len);
9077c478bd9Sstevel@tonic-gate 	if (buf == NULL)
9087c478bd9Sstevel@tonic-gate 		return (ENOMEM);
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	length = krb5_net_read(context, fd, buf, len);
9117c478bd9Sstevel@tonic-gate 	if (len != length) {
9127c478bd9Sstevel@tonic-gate 		krb5_xfree(buf);
9137c478bd9Sstevel@tonic-gate 		return ((len < 0) ? errno : ECONNABORTED);
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) {
9177c478bd9Sstevel@tonic-gate 		krb5_xfree(buf);
9187c478bd9Sstevel@tonic-gate 		return (KRB5_SENDAUTH_BADAUTHVERS);
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 	krb5_xfree(buf);
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	*auth_sys = KRB5_RECVAUTH_V5;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	retval = krb5_recvauth_version(context, auth_context, fdp,
9257c478bd9Sstevel@tonic-gate 				    server, flags | KRB5_RECVAUTH_SKIP_VERSION,
9267c478bd9Sstevel@tonic-gate 				    keytab, ticket, version);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	return (retval);
9297c478bd9Sstevel@tonic-gate }
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate static void
doit(int f,struct sockaddr_storage * fromp,krb5_context krb_context,int encr_flag,krb5_keytab keytab)9337c478bd9Sstevel@tonic-gate doit(int f,
9347c478bd9Sstevel@tonic-gate 	struct sockaddr_storage *fromp,
9357c478bd9Sstevel@tonic-gate 	krb5_context krb_context,
9367c478bd9Sstevel@tonic-gate 	int encr_flag,
9377c478bd9Sstevel@tonic-gate 	krb5_keytab keytab)
9387c478bd9Sstevel@tonic-gate {
9397c478bd9Sstevel@tonic-gate 	int p, t, on = 1;
9407c478bd9Sstevel@tonic-gate 	char c;
9417c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
9427c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
9437c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
9447c478bd9Sstevel@tonic-gate 	int fromplen;
9457c478bd9Sstevel@tonic-gate 	in_port_t port;
9467c478bd9Sstevel@tonic-gate 	struct termios tp;
9477c478bd9Sstevel@tonic-gate 	boolean_t bad_port;
9487c478bd9Sstevel@tonic-gate 	boolean_t no_name;
9497c478bd9Sstevel@tonic-gate 	char rhost_addra[INET6_ADDRSTRLEN];
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	if (!(rlbuf = malloc(BUFSIZ))) {
9527c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "rlbuf malloc failed\n");
9537c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
9547c478bd9Sstevel@tonic-gate 	}
9557c478bd9Sstevel@tonic-gate 	(void) alarm(60);
9567c478bd9Sstevel@tonic-gate 	if (read(f, &c, 1) != 1 || c != 0) {
9577c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "failed to receive protocol zero byte\n");
9587c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 	(void) alarm(0);
9617c478bd9Sstevel@tonic-gate 	if (fromp->ss_family == AF_INET) {
9627c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)fromp;
9637c478bd9Sstevel@tonic-gate 		port = sin->sin_port = ntohs((ushort_t)sin->sin_port);
9647c478bd9Sstevel@tonic-gate 		fromplen = sizeof (struct sockaddr_in);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		if (!inet_ntop(AF_INET, &sin->sin_addr,
9677c478bd9Sstevel@tonic-gate 			    rhost_addra, sizeof (rhost_addra)))
9687c478bd9Sstevel@tonic-gate 			goto badconversion;
9697c478bd9Sstevel@tonic-gate 	} else if (fromp->ss_family == AF_INET6) {
9707c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)fromp;
9717c478bd9Sstevel@tonic-gate 		port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port);
9727c478bd9Sstevel@tonic-gate 		fromplen = sizeof (struct sockaddr_in6);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
9757c478bd9Sstevel@tonic-gate 			struct in_addr ipv4_addr;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
9787c478bd9Sstevel@tonic-gate 					    &ipv4_addr);
9797c478bd9Sstevel@tonic-gate 			if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra,
9807c478bd9Sstevel@tonic-gate 				    sizeof (rhost_addra)))
9817c478bd9Sstevel@tonic-gate 				goto badconversion;
9827c478bd9Sstevel@tonic-gate 		} else {
9837c478bd9Sstevel@tonic-gate 			if (!inet_ntop(AF_INET6, &sin6->sin6_addr,
9847c478bd9Sstevel@tonic-gate 				    rhost_addra, sizeof (rhost_addra)))
9857c478bd9Sstevel@tonic-gate 				goto badconversion;
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	} else {
9887c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "unknown address family %d\n",
9897c478bd9Sstevel@tonic-gate 		    fromp->ss_family);
9907c478bd9Sstevel@tonic-gate 		fatal(f, "Permission denied");
9917c478bd9Sstevel@tonic-gate 	}
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	/*
9947c478bd9Sstevel@tonic-gate 	 * Allow connections only from the "ephemeral" reserved
9957c478bd9Sstevel@tonic-gate 	 * ports(ports 512 - 1023) by checking the remote port
9967c478bd9Sstevel@tonic-gate 	 * because other utilities(e.g. in.ftpd) can be used to
9977c478bd9Sstevel@tonic-gate 	 * allow a unprivileged user to originate a connection
9987c478bd9Sstevel@tonic-gate 	 * from a privileged port and provide untrustworthy
9997c478bd9Sstevel@tonic-gate 	 * authentication.
10007c478bd9Sstevel@tonic-gate 	 */
10017c478bd9Sstevel@tonic-gate 	bad_port = (use_auth != KRB5_RECVAUTH_V5 &&
10027c478bd9Sstevel@tonic-gate 		    (port >= (in_port_t)IPPORT_RESERVED) ||
10037c478bd9Sstevel@tonic-gate 		    (port < (in_port_t)(IPPORT_RESERVED/2)));
10047c478bd9Sstevel@tonic-gate 	no_name = getnameinfo((const struct sockaddr *) fromp,
10057c478bd9Sstevel@tonic-gate 			    fromplen, hostname, sizeof (hostname),
10067c478bd9Sstevel@tonic-gate 			    NULL, 0, 0) != 0;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	if (no_name || bad_port) {
10097c478bd9Sstevel@tonic-gate 		(void) strlcpy(abuf, rhost_addra, sizeof (abuf));
10107c478bd9Sstevel@tonic-gate 		/* If no host name, use IP address for name later on. */
10117c478bd9Sstevel@tonic-gate 		if (no_name)
10127c478bd9Sstevel@tonic-gate 			(void) strlcpy(hostname, abuf, sizeof (hostname));
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 
10157243fb49Sjbeck 	if (!no_name) {
10167243fb49Sjbeck 		/*
10177243fb49Sjbeck 		 * Even if getnameinfo() succeeded, we still have to check
10187243fb49Sjbeck 		 * for spoofing.
10197243fb49Sjbeck 		 */
10207243fb49Sjbeck 		check_address("rlogind", fromp, sin, sin6, rhost_addra,
10217243fb49Sjbeck 		    hostname, sizeof (hostname));
10227243fb49Sjbeck 	}
10237243fb49Sjbeck 
10247c478bd9Sstevel@tonic-gate 	if (bad_port) {
10257c478bd9Sstevel@tonic-gate 		if (no_name)
10267c478bd9Sstevel@tonic-gate 			syslog(LOG_NOTICE,
10277c478bd9Sstevel@tonic-gate 			    "connection from %s - bad port\n",
10287c478bd9Sstevel@tonic-gate 			    abuf);
10297c478bd9Sstevel@tonic-gate 		else
10307c478bd9Sstevel@tonic-gate 			syslog(LOG_NOTICE,
10317c478bd9Sstevel@tonic-gate 			    "connection from %s(%s) - bad port\n",
10327c478bd9Sstevel@tonic-gate 			    hostname, abuf);
10337c478bd9Sstevel@tonic-gate 		fatal(f, "Permission denied");
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	if (use_auth == KRB5_RECVAUTH_V5) {
10377c478bd9Sstevel@tonic-gate 		do_krb_login(f, rhost_addra, hostname,
10387c478bd9Sstevel@tonic-gate 			    krb_context, encr_flag, keytab);
10397c478bd9Sstevel@tonic-gate 		if (krusername != NULL && strlen(krusername)) {
10407c478bd9Sstevel@tonic-gate 			/*
10417c478bd9Sstevel@tonic-gate 			 * Kerberos Authentication succeeded,
10427c478bd9Sstevel@tonic-gate 			 * so set the proper program name to use
10437c478bd9Sstevel@tonic-gate 			 * with pam (important during 'cleanup'
10447c478bd9Sstevel@tonic-gate 			 * routine later).
10457c478bd9Sstevel@tonic-gate 			 */
10467c478bd9Sstevel@tonic-gate 			pam_prog_name = KRB5_PROG_NAME;
10477c478bd9Sstevel@tonic-gate 		}
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	if (write(f, "", 1) != 1) {
10517c478bd9Sstevel@tonic-gate 		syslog(LOG_NOTICE,
10527c478bd9Sstevel@tonic-gate 		    "send of the zero byte(to %s) failed:"
10537c478bd9Sstevel@tonic-gate 		    " cannot start data transfer mode\n",
10547c478bd9Sstevel@tonic-gate 		    (no_name ? abuf : hostname));
10557c478bd9Sstevel@tonic-gate 		exit(EXIT_FAILURE);
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 	if ((p = open("/dev/ptmx", O_RDWR)) == -1)
10587c478bd9Sstevel@tonic-gate 		fatalperror(f, "cannot open /dev/ptmx");
10597c478bd9Sstevel@tonic-gate 	if (grantpt(p) == -1)
10601fa2a664SJoshua M. Clulow 		fatal(f, "could not grant subsidiary pty");
10617c478bd9Sstevel@tonic-gate 	if (unlockpt(p) == -1)
10621fa2a664SJoshua M. Clulow 		fatal(f, "could not unlock subsidiary pty");
10637c478bd9Sstevel@tonic-gate 	if ((line = ptsname(p)) == NULL)
10641fa2a664SJoshua M. Clulow 		fatal(f, "could not enable subsidiary pty");
10657c478bd9Sstevel@tonic-gate 	if ((t = open(line, O_RDWR)) == -1)
10661fa2a664SJoshua M. Clulow 		fatal(f, "could not open subsidiary pty");
10677c478bd9Sstevel@tonic-gate 	if (ioctl(t, I_PUSH, "ptem") == -1)
10687c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl I_PUSH ptem");
10697c478bd9Sstevel@tonic-gate 	if (ioctl(t, I_PUSH, "ldterm") == -1)
10707c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl I_PUSH ldterm");
10717c478bd9Sstevel@tonic-gate 	if (ioctl(t, I_PUSH, "ttcompat") == -1)
10727c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl I_PUSH ttcompat");
10737c478bd9Sstevel@tonic-gate 	/*
10747c478bd9Sstevel@tonic-gate 	 * POP the sockmod and push the rlmod module.
10757c478bd9Sstevel@tonic-gate 	 *
10767c478bd9Sstevel@tonic-gate 	 * Note that sockmod has to be removed since readstream assumes
10777c478bd9Sstevel@tonic-gate 	 * a "raw" TPI endpoint(e.g. it uses getmsg).
10787c478bd9Sstevel@tonic-gate 	 */
10797c478bd9Sstevel@tonic-gate 	if (removemod(f, "sockmod") < 0)
10807c478bd9Sstevel@tonic-gate 		fatalperror(f, "couldn't remove sockmod");
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if (encr_flag) {
10837c478bd9Sstevel@tonic-gate 		if (ioctl(f, I_PUSH, "cryptmod") < 0)
10847c478bd9Sstevel@tonic-gate 		    fatalperror(f, "ioctl I_PUSH rlmod");
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	}
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	if (ioctl(f, I_PUSH, "rlmod") < 0)
10897c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl I_PUSH rlmod");
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	if (encr_flag) {
10927c478bd9Sstevel@tonic-gate 		/*
10937c478bd9Sstevel@tonic-gate 		 * Make sure rlmod will pass unrecognized IOCTLs to cryptmod
10947c478bd9Sstevel@tonic-gate 		 */
10957c478bd9Sstevel@tonic-gate 		uchar_t passthru = 1;
10967c478bd9Sstevel@tonic-gate 		struct strioctl rlmodctl;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		rlmodctl.ic_cmd = CRYPTPASSTHRU;
10997c478bd9Sstevel@tonic-gate 		rlmodctl.ic_timout = -1;
11007c478bd9Sstevel@tonic-gate 		rlmodctl.ic_len = sizeof (uchar_t);
11017c478bd9Sstevel@tonic-gate 		rlmodctl.ic_dp = (char *)&passthru;
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 		if (ioctl(f, I_STR, &rlmodctl) < 0)
11047c478bd9Sstevel@tonic-gate 			fatal(f, "ioctl CRYPTPASSTHRU failed\n");
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/*
11087c478bd9Sstevel@tonic-gate 	 * readstream will do a getmsg till it receives
11097c478bd9Sstevel@tonic-gate 	 * M_PROTO type T_DATA_REQ from rloginmodopen()
11107c478bd9Sstevel@tonic-gate 	 * indicating all data on the stream prior to pushing rlmod has
11117c478bd9Sstevel@tonic-gate 	 * been drained at the stream head.
11127c478bd9Sstevel@tonic-gate 	 */
11137c478bd9Sstevel@tonic-gate 	if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0)
11147c478bd9Sstevel@tonic-gate 		fatalperror(f, "readstream failed");
11157c478bd9Sstevel@tonic-gate 	/*
11167c478bd9Sstevel@tonic-gate 	 * Make sure the pty doesn't modify the strings passed
11177c478bd9Sstevel@tonic-gate 	 * to login as part of the "rlogin protocol."  The login
11187c478bd9Sstevel@tonic-gate 	 * program should set these flags to apropriate values
11197c478bd9Sstevel@tonic-gate 	 * after it has read the strings.
11207c478bd9Sstevel@tonic-gate 	 */
11217c478bd9Sstevel@tonic-gate 	if (ioctl(t, TCGETS, &tp) == -1)
11227c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl TCGETS");
11237c478bd9Sstevel@tonic-gate 	tp.c_lflag &= ~(ECHO|ICANON);
11247c478bd9Sstevel@tonic-gate 	tp.c_oflag &= ~(XTABS|OCRNL);
11257c478bd9Sstevel@tonic-gate 	tp.c_iflag &= ~(IGNPAR|ICRNL);
11267c478bd9Sstevel@tonic-gate 	if (ioctl(t, TCSETS, &tp) == -1)
11277c478bd9Sstevel@tonic-gate 		fatalperror(f, "ioctl TCSETS");
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	/*
11307c478bd9Sstevel@tonic-gate 	 * System V ptys allow the TIOC{SG}WINSZ ioctl to be
11311fa2a664SJoshua M. Clulow 	 * issued on the manager side of the pty.  Luckily, that's
11327c478bd9Sstevel@tonic-gate 	 * the only tty ioctl we need to do do, so we can close the
11331fa2a664SJoshua M. Clulow 	 * subsidiary side in the parent process after the fork.
11347c478bd9Sstevel@tonic-gate 	 */
11357c478bd9Sstevel@tonic-gate 	(void) ioctl(p, TIOCSWINSZ, &win);
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	pid = fork();
11387c478bd9Sstevel@tonic-gate 	if (pid < 0)
11397c478bd9Sstevel@tonic-gate 		fatalperror(f, "fork");
11407c478bd9Sstevel@tonic-gate 	if (pid == 0) {
11417c478bd9Sstevel@tonic-gate 		int tt;
11427c478bd9Sstevel@tonic-gate 		struct utmpx ut;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 		/* System V login expects a utmp entry to already be there */
11457c478bd9Sstevel@tonic-gate 		(void) memset(&ut, 0, sizeof (ut));
11467c478bd9Sstevel@tonic-gate 		(void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user));
11477c478bd9Sstevel@tonic-gate 		(void) strncpy(ut.ut_line, line, sizeof (ut.ut_line));
11487c478bd9Sstevel@tonic-gate 		ut.ut_pid = getpid();
11497c478bd9Sstevel@tonic-gate 		ut.ut_id[0] = 'r';
11507c478bd9Sstevel@tonic-gate 		ut.ut_id[1] = (char)SC_WILDC;
11517c478bd9Sstevel@tonic-gate 		ut.ut_id[2] = (char)SC_WILDC;
11527c478bd9Sstevel@tonic-gate 		ut.ut_id[3] = (char)SC_WILDC;
11537c478bd9Sstevel@tonic-gate 		ut.ut_type = LOGIN_PROCESS;
11547c478bd9Sstevel@tonic-gate 		ut.ut_exit.e_termination = 0;
11557c478bd9Sstevel@tonic-gate 		ut.ut_exit.e_exit = 0;
11567c478bd9Sstevel@tonic-gate 		(void) time(&ut.ut_tv.tv_sec);
11577c478bd9Sstevel@tonic-gate 		if (makeutx(&ut) == NULL)
11587c478bd9Sstevel@tonic-gate 			syslog(LOG_INFO, "in.rlogind:\tmakeutx failed");
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 		/* controlling tty */
11617c478bd9Sstevel@tonic-gate 		if (setsid() == -1)
11627c478bd9Sstevel@tonic-gate 			fatalperror(f, "setsid");
11637c478bd9Sstevel@tonic-gate 		if ((tt = open(line, O_RDWR)) == -1)
11641fa2a664SJoshua M. Clulow 			fatalperror(f, "could not re-open subsidiary pty");
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 		if (close(p) == -1)
11671fa2a664SJoshua M. Clulow 			fatalperror(f, "error closing pty manager");
11687c478bd9Sstevel@tonic-gate 		if (close(t) == -1)
11691fa2a664SJoshua M. Clulow 			fatalperror(f, "error closing pty subsidiary"
11707c478bd9Sstevel@tonic-gate 				    " opened before session established");
11717c478bd9Sstevel@tonic-gate 		/*
11727c478bd9Sstevel@tonic-gate 		 * If this fails we may or may not be able to output an
11737c478bd9Sstevel@tonic-gate 		 * error message.
11747c478bd9Sstevel@tonic-gate 		 */
11757c478bd9Sstevel@tonic-gate 		if (close(f) == -1)
11767c478bd9Sstevel@tonic-gate 			fatalperror(f, "error closing deamon stdout");
11777c478bd9Sstevel@tonic-gate 		if (dup2(tt, STDIN_FILENO) == -1 ||
11787c478bd9Sstevel@tonic-gate 		    dup2(tt, STDOUT_FILENO) == -1 ||
11797c478bd9Sstevel@tonic-gate 		    dup2(tt, STDERR_FILENO) == -1)
11807c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);	/* Disaster! No stderr! */
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 		(void) close(tt);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 		if (use_auth == KRB5_RECVAUTH_V5 &&
11857c478bd9Sstevel@tonic-gate 		    krusername != NULL && strlen(krusername)) {
11867c478bd9Sstevel@tonic-gate 			(void) execl(LOGIN_PROGRAM, "login",
11877c478bd9Sstevel@tonic-gate 				    "-d", line,
11887c478bd9Sstevel@tonic-gate 				    "-r", hostname,
11897c478bd9Sstevel@tonic-gate 				    "-u", krusername, /* KRB5 principal name */
11907c478bd9Sstevel@tonic-gate 				    "-s", pam_prog_name,
11917c478bd9Sstevel@tonic-gate 				    "-t", term,	/* Remote Terminal */
11927c478bd9Sstevel@tonic-gate 				    "-U", rusername,	/* Remote User */
11937c478bd9Sstevel@tonic-gate 				    "-R", KRB5_REPOSITORY_NAME,
11947c478bd9Sstevel@tonic-gate 				    lusername,  /* local user */
11957c478bd9Sstevel@tonic-gate 				    NULL);
11967c478bd9Sstevel@tonic-gate 		} else {
11977c478bd9Sstevel@tonic-gate 			(void) execl(LOGIN_PROGRAM, "login",
11987c478bd9Sstevel@tonic-gate 				"-d", line,
11997c478bd9Sstevel@tonic-gate 				"-r", hostname,
12007c478bd9Sstevel@tonic-gate 				NULL);
12017c478bd9Sstevel@tonic-gate 		}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		fatalperror(STDERR_FILENO, "/bin/login");
12047c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate 	(void) close(t);
12077c478bd9Sstevel@tonic-gate 	(void) ioctl(f, FIONBIO, &on);
12087c478bd9Sstevel@tonic-gate 	(void) ioctl(p, FIONBIO, &on);
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 	/*
12117c478bd9Sstevel@tonic-gate 	 * Must ignore SIGTTOU, otherwise we'll stop
12121fa2a664SJoshua M. Clulow 	 * when we try and set subsidiary pty's window shape
12131fa2a664SJoshua M. Clulow 	 * (our controlling tty is the manager pty).
12147c478bd9Sstevel@tonic-gate 	 * Likewise, we don't want any of the tty-generated
12157c478bd9Sstevel@tonic-gate 	 * signals from chars passing through.
12167c478bd9Sstevel@tonic-gate 	 */
12177c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTSTP, SIG_IGN);
12187c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, SIG_IGN);
12197c478bd9Sstevel@tonic-gate 	(void) sigset(SIGQUIT, SIG_IGN);
12207c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTTOU, SIG_IGN);
12217c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTTIN, SIG_IGN);
12227c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCHLD, cleanup);
12237c478bd9Sstevel@tonic-gate 	(void) setpgrp();
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	if (encr_flag) {
12267c478bd9Sstevel@tonic-gate 		krb5_data ivec, *ivptr;
12277c478bd9Sstevel@tonic-gate 		uint_t ivec_usage;
12287c478bd9Sstevel@tonic-gate 		stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 		/*
12317c478bd9Sstevel@tonic-gate 		 * Configure the STREAMS crypto module.  For now,
12327c478bd9Sstevel@tonic-gate 		 * don't use any IV parameter.  KCMDV0.2 support
12337c478bd9Sstevel@tonic-gate 		 * will require the use of Initialization Vectors
12347c478bd9Sstevel@tonic-gate 		 * for both encrypt and decrypt modes.
12357c478bd9Sstevel@tonic-gate 		 */
12367c478bd9Sstevel@tonic-gate 		if (kcmd_protocol == KCMD_OLD_PROTOCOL) {
12377c478bd9Sstevel@tonic-gate 			if (session_key->enctype == ENCTYPE_DES_CBC_CRC) {
12387c478bd9Sstevel@tonic-gate 				/*
12397c478bd9Sstevel@tonic-gate 				 * This is gross but necessary for MIT compat.
12407c478bd9Sstevel@tonic-gate 				 */
12417c478bd9Sstevel@tonic-gate 				ivec.length = session_key->length;
12427c478bd9Sstevel@tonic-gate 				ivec.data = (char *)session_key->contents;
12437c478bd9Sstevel@tonic-gate 				ivec_usage = IVEC_REUSE;
12447c478bd9Sstevel@tonic-gate 				ivptr = &ivec;
12457c478bd9Sstevel@tonic-gate 			} else {
12467c478bd9Sstevel@tonic-gate 				ivptr = NULL; /* defaults to all 0's */
12477c478bd9Sstevel@tonic-gate 				ivec_usage = IVEC_NEVER;
12487c478bd9Sstevel@tonic-gate 			}
12497c478bd9Sstevel@tonic-gate 			/*
12507c478bd9Sstevel@tonic-gate 			 * configure both sides of stream together
12517c478bd9Sstevel@tonic-gate 			 * since they share the same IV.
12527c478bd9Sstevel@tonic-gate 			 * This is what makes the OLD KCMD protocol
12537c478bd9Sstevel@tonic-gate 			 * less secure than the newer one - Bad ivecs.
12547c478bd9Sstevel@tonic-gate 			 */
12557c478bd9Sstevel@tonic-gate 			if (configure_stream(f, session_key,
12567c478bd9Sstevel@tonic-gate 				CRYPT_ENCRYPT|CRYPT_DECRYPT,
12577c478bd9Sstevel@tonic-gate 				ivptr, ivec_usage) != 0)
12587c478bd9Sstevel@tonic-gate 				fatal(f, "Cannot initialize encryption -"
12597c478bd9Sstevel@tonic-gate 					" exiting.\n");
12607c478bd9Sstevel@tonic-gate 		} else {
12617c478bd9Sstevel@tonic-gate 			size_t blocksize;
12627c478bd9Sstevel@tonic-gate 			if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC ||
12637c478bd9Sstevel@tonic-gate 			    session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
12647c478bd9Sstevel@tonic-gate 				if (configure_stream(f, session_key,
12657c478bd9Sstevel@tonic-gate 					CRYPT_ENCRYPT|CRYPT_DECRYPT,
12667c478bd9Sstevel@tonic-gate 					NULL, IVEC_NEVER) != 0)
12677c478bd9Sstevel@tonic-gate 					fatal(f,
12687c478bd9Sstevel@tonic-gate 					"Cannot initialize encryption -"
12697c478bd9Sstevel@tonic-gate 					" exiting.\n");
12707c478bd9Sstevel@tonic-gate 				goto startcrypto;
12717c478bd9Sstevel@tonic-gate 			}
12727c478bd9Sstevel@tonic-gate 			if (krb5_c_block_size(krb_context,
12737c478bd9Sstevel@tonic-gate 					    session_key->enctype,
12747c478bd9Sstevel@tonic-gate 					    &blocksize)) {
12757c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "Cannot determine blocksize "
12767c478bd9Sstevel@tonic-gate 				    "for encryption type %d",
12777c478bd9Sstevel@tonic-gate 				    session_key->enctype);
12787c478bd9Sstevel@tonic-gate 				fatal(f, "Cannot determine blocksize "
12797c478bd9Sstevel@tonic-gate 				    "for encryption - exiting.\n");
12807c478bd9Sstevel@tonic-gate 			}
12817c478bd9Sstevel@tonic-gate 			ivec.data = (char *)malloc(blocksize);
12827c478bd9Sstevel@tonic-gate 			ivec.length = blocksize;
12837c478bd9Sstevel@tonic-gate 			if (ivec.data == NULL)
12847c478bd9Sstevel@tonic-gate 				fatal(f, "memory error - exiting\n");
12857c478bd9Sstevel@tonic-gate 			/*
12867c478bd9Sstevel@tonic-gate 			 * Following MIT convention -
12877c478bd9Sstevel@tonic-gate 			 *   encrypt IV = 0x01 x blocksize
12887c478bd9Sstevel@tonic-gate 			 *   decrypt IV = 0x00 x blocksize
12897c478bd9Sstevel@tonic-gate 			 *   ivec_usage = IVEC_ONETIME
12907c478bd9Sstevel@tonic-gate 			 *
12917c478bd9Sstevel@tonic-gate 			 * configure_stream separately for encrypt and
12927c478bd9Sstevel@tonic-gate 			 * decrypt because there are 2 different IVs.
12937c478bd9Sstevel@tonic-gate 			 *
12947c478bd9Sstevel@tonic-gate 			 * AES uses 0's for IV.
12957c478bd9Sstevel@tonic-gate 			 */
12967c478bd9Sstevel@tonic-gate 			if (session_key->enctype ==
12977c478bd9Sstevel@tonic-gate 				ENCTYPE_AES128_CTS_HMAC_SHA1_96 ||
12987c478bd9Sstevel@tonic-gate 			    session_key->enctype ==
12997c478bd9Sstevel@tonic-gate 				ENCTYPE_AES256_CTS_HMAC_SHA1_96)
13007c478bd9Sstevel@tonic-gate 				(void) memset(ivec.data, 0x00, blocksize);
13017c478bd9Sstevel@tonic-gate 			else
13027c478bd9Sstevel@tonic-gate 				(void) memset(ivec.data, 0x01, blocksize);
13037c478bd9Sstevel@tonic-gate 			if (configure_stream(f, session_key, CRYPT_ENCRYPT,
13047c478bd9Sstevel@tonic-gate 				&ivec, IVEC_ONETIME) != 0)
13057c478bd9Sstevel@tonic-gate 				fatal(f, "Cannot initialize encryption -"
13067c478bd9Sstevel@tonic-gate 					" exiting.\n");
13077c478bd9Sstevel@tonic-gate 			(void) memset(ivec.data, 0x00, blocksize);
13087c478bd9Sstevel@tonic-gate 			if (configure_stream(f, session_key, CRYPT_DECRYPT,
13097c478bd9Sstevel@tonic-gate 				&ivec, IVEC_ONETIME) != 0)
13107c478bd9Sstevel@tonic-gate 				fatal(f, "Cannot initialize encryption -"
13117c478bd9Sstevel@tonic-gate 					" exiting.\n");
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 			(void) free(ivec.data);
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate startcrypto:
13167c478bd9Sstevel@tonic-gate 		start_stream(f, CRYPT_ENCRYPT);
13177c478bd9Sstevel@tonic-gate 		start_stream(f, CRYPT_DECRYPT);
13187c478bd9Sstevel@tonic-gate 	}
13197c478bd9Sstevel@tonic-gate 	protocol(f, p, encr_flag);
13207c478bd9Sstevel@tonic-gate 	cleanup(0);
13217c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate badconversion:
13247c478bd9Sstevel@tonic-gate 	fatalperror(f, "address conversion");
13257c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
13267c478bd9Sstevel@tonic-gate }
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate /*
13297c478bd9Sstevel@tonic-gate  * rlogin "protocol" machine.
13307c478bd9Sstevel@tonic-gate  */
13317c478bd9Sstevel@tonic-gate static void
protocol(int f,int p,int encr_flag)13327c478bd9Sstevel@tonic-gate protocol(int f, int p, int encr_flag)
13337c478bd9Sstevel@tonic-gate {
13347c478bd9Sstevel@tonic-gate 	struct	stat	buf;
13351fa2a664SJoshua M. Clulow 	struct	protocol_arg	rloginp;
13367c478bd9Sstevel@tonic-gate 	struct	strioctl	rloginmod;
13377c478bd9Sstevel@tonic-gate 	int	ptmfd;	/* fd of logindmux coneected to ptmx */
13387c478bd9Sstevel@tonic-gate 	int	netfd;	/* fd of logindmux connected to netf */
13397c478bd9Sstevel@tonic-gate 	static uchar_t	oobdata[] = {TIOCPKT_WINDOW};
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	/* indicate new rlogin */
13427c478bd9Sstevel@tonic-gate 	if (send_oob(f, oobdata, 1) < 0)
13437c478bd9Sstevel@tonic-gate 		fatalperror(f, "send_oob");
13447c478bd9Sstevel@tonic-gate 	/*
13457c478bd9Sstevel@tonic-gate 	 * We cannot send the SECURE_MSG until after the
13467c478bd9Sstevel@tonic-gate 	 * client has been signaled with the oobdata (above).
13477c478bd9Sstevel@tonic-gate 	 */
13487c478bd9Sstevel@tonic-gate 	if (encr_flag) {
13497c478bd9Sstevel@tonic-gate 		if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0)
13507c478bd9Sstevel@tonic-gate 			fatalperror(f, "Error writing SECURE message");
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	/*
13547c478bd9Sstevel@tonic-gate 	 * Open logindmux driver and link netf and ptmx
13557c478bd9Sstevel@tonic-gate 	 * underneath logindmux.
13567c478bd9Sstevel@tonic-gate 	 */
13577c478bd9Sstevel@tonic-gate 	if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1)
13587c478bd9Sstevel@tonic-gate 		fatalperror(f, "open /dev/logindmux");
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	if ((netfd = open("/dev/logindmux", O_RDWR)) == -1)
13617c478bd9Sstevel@tonic-gate 		fatalperror(f, "open /dev/logindmux");
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	if (ioctl(ptmfd, I_LINK, p) < 0)
13647c478bd9Sstevel@tonic-gate 		fatal(f, "ioctl I_LINK of /dev/ptmx failed\n");
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	if (ioctl(netfd, I_LINK, f) < 0)
13677c478bd9Sstevel@tonic-gate 		fatal(f, "ioctl I_LINK of tcp connection failed\n");
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	/*
13707c478bd9Sstevel@tonic-gate 	 * Figure out the device number of the ptm's mux fd, and pass that
13717c478bd9Sstevel@tonic-gate 	 * to the net's mux.
13727c478bd9Sstevel@tonic-gate 	 */
13737c478bd9Sstevel@tonic-gate 	if (fstat(ptmfd, &buf) < 0)
13747c478bd9Sstevel@tonic-gate 		fatalperror(f, "cannot determine device number"
13757c478bd9Sstevel@tonic-gate 		    " of pty side of /dev/logindmux");
13767c478bd9Sstevel@tonic-gate 	rloginp.dev = buf.st_rdev;
13777c478bd9Sstevel@tonic-gate 	rloginp.flag = 0;
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
13807c478bd9Sstevel@tonic-gate 	rloginmod.ic_timout = -1;
13817c478bd9Sstevel@tonic-gate 	rloginmod.ic_len = sizeof (struct protocol_arg);
13827c478bd9Sstevel@tonic-gate 	rloginmod.ic_dp = (char *)&rloginp;
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if (ioctl(netfd, I_STR, &rloginmod) < 0)
13857c478bd9Sstevel@tonic-gate 		fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n");
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	/*
13887c478bd9Sstevel@tonic-gate 	 * Figure out the device number of the net's mux fd, and pass that
13897c478bd9Sstevel@tonic-gate 	 * to the ptm's mux.
13907c478bd9Sstevel@tonic-gate 	 */
13917c478bd9Sstevel@tonic-gate 	if (fstat(netfd, &buf))
13927c478bd9Sstevel@tonic-gate 		fatalperror(f, "cannot determine device number"
13937c478bd9Sstevel@tonic-gate 		    " of network side of /dev/logindmux");
13947c478bd9Sstevel@tonic-gate 	rloginp.dev = buf.st_rdev;
13957c478bd9Sstevel@tonic-gate 	rloginp.flag = 1;
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
13987c478bd9Sstevel@tonic-gate 	rloginmod.ic_timout = -1;
13997c478bd9Sstevel@tonic-gate 	rloginmod.ic_len = sizeof (struct protocol_arg);
14007c478bd9Sstevel@tonic-gate 	rloginmod.ic_dp = (char *)&rloginp;
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	if (ioctl(ptmfd, I_STR, &rloginmod) < 0)
14037c478bd9Sstevel@tonic-gate 		fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n");
14047c478bd9Sstevel@tonic-gate 	/*
14057c478bd9Sstevel@tonic-gate 	 * Send an ioctl type RL_IOC_ENABLE to reenable the
14067c478bd9Sstevel@tonic-gate 	 * message queue and reinsert the data read from streamhead
14077c478bd9Sstevel@tonic-gate 	 * at the time of pushing rloginmod module.
14087c478bd9Sstevel@tonic-gate 	 * We need to send this ioctl even if no data was read earlier
14097c478bd9Sstevel@tonic-gate 	 * since we need to reenable the message queue of rloginmod module.
14107c478bd9Sstevel@tonic-gate 	 */
14117c478bd9Sstevel@tonic-gate 	rloginmod.ic_cmd = RL_IOC_ENABLE;
14127c478bd9Sstevel@tonic-gate 	rloginmod.ic_timout = -1;
14137c478bd9Sstevel@tonic-gate 	if (nsize) {
14147c478bd9Sstevel@tonic-gate 		rloginmod.ic_len = nsize;
14157c478bd9Sstevel@tonic-gate 		rloginmod.ic_dp = rlbuf;
14167c478bd9Sstevel@tonic-gate 	} else {
14177c478bd9Sstevel@tonic-gate 		rloginmod.ic_len = 0;
14187c478bd9Sstevel@tonic-gate 		rloginmod.ic_dp = NULL;
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	if (ioctl(netfd, I_STR, &rloginmod) < 0)
14227c478bd9Sstevel@tonic-gate 		fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n");
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	/*
14257c478bd9Sstevel@tonic-gate 	 * User level daemon now pauses till the shell exits.
14267c478bd9Sstevel@tonic-gate 	 */
14277c478bd9Sstevel@tonic-gate 	(void) pause();
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate /* This is a signal handler, hence the dummy argument */
14317c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14327c478bd9Sstevel@tonic-gate static void
cleanup(int dummy)14337c478bd9Sstevel@tonic-gate cleanup(int dummy)
14347c478bd9Sstevel@tonic-gate {
14357c478bd9Sstevel@tonic-gate 	rmut();
14367c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
14377c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
14387c478bd9Sstevel@tonic-gate }
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate /*
14417c478bd9Sstevel@tonic-gate  * TPI style replacement for socket send() primitive, so we don't require
14427c478bd9Sstevel@tonic-gate  * sockmod to be on the stream.
14437c478bd9Sstevel@tonic-gate  */
14447c478bd9Sstevel@tonic-gate static int
send_oob(int fd,void * ptr,size_t count)14457c478bd9Sstevel@tonic-gate send_oob(int fd, void *ptr, size_t count)
14467c478bd9Sstevel@tonic-gate {
14477c478bd9Sstevel@tonic-gate 	struct T_exdata_req exd_req;
14487c478bd9Sstevel@tonic-gate 	struct strbuf hdr, dat;
14497c478bd9Sstevel@tonic-gate 	int ret;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	exd_req.PRIM_type = T_EXDATA_REQ;
14527c478bd9Sstevel@tonic-gate 	exd_req.MORE_flag = 0;
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	hdr.buf = (char *)&exd_req;
14557c478bd9Sstevel@tonic-gate 	hdr.len = sizeof (exd_req);
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	dat.buf = ptr;
14587c478bd9Sstevel@tonic-gate 	dat.len = count;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	ret = putmsg(fd, &hdr, &dat, 0);
14617c478bd9Sstevel@tonic-gate 	if (ret == 0)
14627c478bd9Sstevel@tonic-gate 		ret = count;
14637c478bd9Sstevel@tonic-gate 	return (ret);
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate static void
fatal(int fd,const char * msg)14677c478bd9Sstevel@tonic-gate fatal(int fd, const char *msg)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate 	char *bufp;
14707c478bd9Sstevel@tonic-gate 	size_t len = strlen(msg) + 16;		/* enough for our wrapper */
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	bufp = alloca(len);
14737c478bd9Sstevel@tonic-gate 	/* ASCII 001 is the error indicator */
14747c478bd9Sstevel@tonic-gate 	len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg);
14757c478bd9Sstevel@tonic-gate 	(void) write(fd, bufp, len);
14767c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
14777c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
14817c478bd9Sstevel@tonic-gate static void
fatalperror(int fd,const char * msg)14827c478bd9Sstevel@tonic-gate fatalperror(int fd, const char *msg)
14837c478bd9Sstevel@tonic-gate {
14847c478bd9Sstevel@tonic-gate 	char *bufp;
14857c478bd9Sstevel@tonic-gate 	const char *errstr;
14867c478bd9Sstevel@tonic-gate 	int save_errno = errno;
14877c478bd9Sstevel@tonic-gate 	size_t len = strlen(msg);
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 	if ((errstr = strerror(save_errno))) {
14907c478bd9Sstevel@tonic-gate 		len += strlen(errstr) + 3;	/* 3 for ": " and \0 below */
14917c478bd9Sstevel@tonic-gate 		bufp = alloca(len);
14927c478bd9Sstevel@tonic-gate 		(void) snprintf(bufp, len, "%s: %s", msg, errstr);
14937c478bd9Sstevel@tonic-gate 	} else {
14947c478bd9Sstevel@tonic-gate 		const char fmt[] = "%s: Error %d";
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 		/* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */
14977c478bd9Sstevel@tonic-gate 		len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3);
14987c478bd9Sstevel@tonic-gate 		bufp = alloca(len);
14997c478bd9Sstevel@tonic-gate 		(void) snprintf(bufp, len, fmt, msg, save_errno);
15007c478bd9Sstevel@tonic-gate 	}
15017c478bd9Sstevel@tonic-gate 	fatal(fd, bufp);
15027c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate static void
rmut(void)15067c478bd9Sstevel@tonic-gate rmut(void)
15077c478bd9Sstevel@tonic-gate {
15087c478bd9Sstevel@tonic-gate 	pam_handle_t *pamh;
15097c478bd9Sstevel@tonic-gate 	struct utmpx *up;
15107c478bd9Sstevel@tonic-gate 	char user[sizeof (up->ut_user) + 1];
15117c478bd9Sstevel@tonic-gate 	char ttyn[sizeof (up->ut_line) + 1];
15127c478bd9Sstevel@tonic-gate 	char rhost[sizeof (up->ut_host) + 1];
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	/* while cleaning up dont allow disruption */
15157c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCHLD, SIG_IGN);
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	setutxent();
15187c478bd9Sstevel@tonic-gate 	while (up = getutxent()) {
15197c478bd9Sstevel@tonic-gate 		if (up->ut_pid == pid) {
15207c478bd9Sstevel@tonic-gate 			if (up->ut_type == DEAD_PROCESS)
15217c478bd9Sstevel@tonic-gate 				break;		/* Cleaned up elsewhere. */
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 			/*
15247c478bd9Sstevel@tonic-gate 			 * call pam_close_session if login changed
15257c478bd9Sstevel@tonic-gate 			 * the utmpx user entry from type LOGIN_PROCESS
15267c478bd9Sstevel@tonic-gate 			 * to type USER_PROCESS, which happens
15277c478bd9Sstevel@tonic-gate 			 * after pam_open_session is called.
15287c478bd9Sstevel@tonic-gate 			 */
15297c478bd9Sstevel@tonic-gate 			if (up->ut_type == USER_PROCESS) {
15307c478bd9Sstevel@tonic-gate 				(void) strlcpy(user, up->ut_user,
15317c478bd9Sstevel@tonic-gate 					    sizeof (user));
15327c478bd9Sstevel@tonic-gate 				(void) strlcpy(ttyn, up->ut_line,
15337c478bd9Sstevel@tonic-gate 					    sizeof (ttyn));
15347c478bd9Sstevel@tonic-gate 				(void) strlcpy(rhost, up->ut_host,
15357c478bd9Sstevel@tonic-gate 					    sizeof (rhost));
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 				/*
15387c478bd9Sstevel@tonic-gate 				 * Use the same pam_prog_name that
15397c478bd9Sstevel@tonic-gate 				 * 'login' used.
15407c478bd9Sstevel@tonic-gate 				 */
15417c478bd9Sstevel@tonic-gate 				if ((pam_start(pam_prog_name, user,  NULL,
15427c478bd9Sstevel@tonic-gate 					    &pamh))
15437c478bd9Sstevel@tonic-gate 				    == PAM_SUCCESS) {
15447c478bd9Sstevel@tonic-gate 					(void) pam_set_item(pamh, PAM_TTY,
15457c478bd9Sstevel@tonic-gate 							    ttyn);
15467c478bd9Sstevel@tonic-gate 					(void) pam_set_item(pamh, PAM_RHOST,
15477c478bd9Sstevel@tonic-gate 							    rhost);
15487c478bd9Sstevel@tonic-gate 					(void) pam_close_session(pamh, 0);
15497c478bd9Sstevel@tonic-gate 					(void) pam_end(pamh, PAM_SUCCESS);
15507c478bd9Sstevel@tonic-gate 				}
15517c478bd9Sstevel@tonic-gate 			}
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 			up->ut_type = DEAD_PROCESS;
15547c478bd9Sstevel@tonic-gate 			up->ut_exit.e_termination = WTERMSIG(0);
15557c478bd9Sstevel@tonic-gate 			up->ut_exit.e_exit = WEXITSTATUS(0);
15567c478bd9Sstevel@tonic-gate 			(void) time(&up->ut_tv.tv_sec);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 			if (modutx(up) == NULL) {
15597c478bd9Sstevel@tonic-gate 				/*
15607c478bd9Sstevel@tonic-gate 				 * Since modutx failed we'll
15617c478bd9Sstevel@tonic-gate 				 * write out the new entry
15627c478bd9Sstevel@tonic-gate 				 * ourselves.
15637c478bd9Sstevel@tonic-gate 				 */
15647c478bd9Sstevel@tonic-gate 				(void) pututxline(up);
15657c478bd9Sstevel@tonic-gate 				updwtmpx("wtmpx", up);
15667c478bd9Sstevel@tonic-gate 			}
15677c478bd9Sstevel@tonic-gate 			break;
15687c478bd9Sstevel@tonic-gate 		}
15697c478bd9Sstevel@tonic-gate 	}
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	endutxent();
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCHLD, cleanup);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate static int
readstream(int fd,char * buf,int size)15777c478bd9Sstevel@tonic-gate readstream(int fd, char *buf, int size)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	struct strbuf ctlbuf, datbuf;
15807c478bd9Sstevel@tonic-gate 	union T_primitives tpi;
15817c478bd9Sstevel@tonic-gate 	int	nbytes = 0;
15827c478bd9Sstevel@tonic-gate 	int	ret = 0;
15837c478bd9Sstevel@tonic-gate 	int	flags = 0;
15847c478bd9Sstevel@tonic-gate 	int	bufsize = size;
15857c478bd9Sstevel@tonic-gate 	int	nread;
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	(void) memset(&ctlbuf, 0, sizeof (ctlbuf));
15887c478bd9Sstevel@tonic-gate 	(void) memset(&datbuf, 0, sizeof (datbuf));
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	ctlbuf.buf = (char *)&tpi;
15917c478bd9Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (tpi);
15927c478bd9Sstevel@tonic-gate 	datbuf.buf = buf;
15937c478bd9Sstevel@tonic-gate 	datbuf.maxlen = size;
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	for (;;) {
15967c478bd9Sstevel@tonic-gate 		if (ioctl(fd, I_NREAD, &nread) < 0) {
15977c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "I_NREAD returned error %m");
15987c478bd9Sstevel@tonic-gate 			return (-1);
15997c478bd9Sstevel@tonic-gate 		}
16007c478bd9Sstevel@tonic-gate 		if (nread + nbytes > bufsize) {
16017c478bd9Sstevel@tonic-gate 			buf = (char *)realloc(buf, (unsigned)(bufsize + nread));
16027c478bd9Sstevel@tonic-gate 			if (buf == NULL) {
16037c478bd9Sstevel@tonic-gate 				syslog(LOG_WARNING,
16047c478bd9Sstevel@tonic-gate 				    "buffer allocation failed\n");
16057c478bd9Sstevel@tonic-gate 				return (-1);
16067c478bd9Sstevel@tonic-gate 			}
16077c478bd9Sstevel@tonic-gate 			bufsize += nread;
16087c478bd9Sstevel@tonic-gate 			rlbuf = buf;
16097c478bd9Sstevel@tonic-gate 			datbuf.buf = buf + nbytes;
16107c478bd9Sstevel@tonic-gate 		}
16117c478bd9Sstevel@tonic-gate 		datbuf.maxlen = bufsize - nbytes;
16127c478bd9Sstevel@tonic-gate 		ret = getmsg(fd, &ctlbuf, &datbuf, &flags);
16137c478bd9Sstevel@tonic-gate 		if (ret < 0) {
16147c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "getmsg failed error %m");
16157c478bd9Sstevel@tonic-gate 			return (-1);
16167c478bd9Sstevel@tonic-gate 		}
16177c478bd9Sstevel@tonic-gate 		if ((ctlbuf.len == 0) && (datbuf.len == 0)) {
16187c478bd9Sstevel@tonic-gate 			/*
16197c478bd9Sstevel@tonic-gate 			 * getmsg() returned no data - this indicates
16207c478bd9Sstevel@tonic-gate 			 * that the connection is closing down.
16217c478bd9Sstevel@tonic-gate 			 */
16227c478bd9Sstevel@tonic-gate 			cleanup(0);
16237c478bd9Sstevel@tonic-gate 		}
16247c478bd9Sstevel@tonic-gate 		if (ctlbuf.len <= 0) {
16257c478bd9Sstevel@tonic-gate 			nbytes += datbuf.len;
16267c478bd9Sstevel@tonic-gate 			datbuf.buf += datbuf.len;
16277c478bd9Sstevel@tonic-gate 			continue;
16287c478bd9Sstevel@tonic-gate 		}
16297c478bd9Sstevel@tonic-gate 		if (tpi.type == T_DATA_REQ) {
16307c478bd9Sstevel@tonic-gate 			return (nbytes);
16317c478bd9Sstevel@tonic-gate 		}
16327c478bd9Sstevel@tonic-gate 		if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND))
16337c478bd9Sstevel@tonic-gate 			cleanup(0);
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate }
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate /*
16387c478bd9Sstevel@tonic-gate  * Verify that the named module is at the top of the stream
16397c478bd9Sstevel@tonic-gate  * and then pop it off.
16407c478bd9Sstevel@tonic-gate  */
16417c478bd9Sstevel@tonic-gate static int
removemod(int f,char * modname)16427c478bd9Sstevel@tonic-gate removemod(int f, char *modname)
16437c478bd9Sstevel@tonic-gate {
16447c478bd9Sstevel@tonic-gate 	char topmodname[BUFSIZ];
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 	if (ioctl(f, I_LOOK, topmodname) < 0)
16477c478bd9Sstevel@tonic-gate 		return (-1);
16487c478bd9Sstevel@tonic-gate 	if (strcmp(modname, topmodname) != 0) {
16497c478bd9Sstevel@tonic-gate 		errno = ENXIO;
16507c478bd9Sstevel@tonic-gate 		return (-1);
16517c478bd9Sstevel@tonic-gate 	}
16527c478bd9Sstevel@tonic-gate 	if (ioctl(f, I_POP, 0) < 0)
16537c478bd9Sstevel@tonic-gate 		return (-1);
16547c478bd9Sstevel@tonic-gate 	return (0);
16557c478bd9Sstevel@tonic-gate }
1656