Home | History | Annotate | Download | only in usr.sbin
      1     0       stevel /*
      2  6536          gtb  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3     0       stevel  * Use is subject to license terms.
      4     0       stevel  */
      5     0       stevel 
      6     0       stevel /*	Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
      7     0       stevel /*	  All Rights Reserved  	*/
      8     0       stevel 
      9     0       stevel /*
     10     0       stevel  * Copyright (c) 1983 The Regents of the University of California.
     11     0       stevel  * All rights reserved.
     12     0       stevel  *
     13     0       stevel  * Redistribution and use in source and binary forms are permitted
     14     0       stevel  * provided that the above copyright notice and this paragraph are
     15     0       stevel  * duplicated in all such forms and that any documentation,
     16     0       stevel  * advertising materials, and other materials related to such
     17     0       stevel  * distribution and use acknowledge that the software was developed
     18     0       stevel  * by the University of California, Berkeley.  The name of the
     19     0       stevel  * University may not be used to endorse or promote products derived
     20     0       stevel  * from this software without specific prior written permission.
     21     0       stevel  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     22     0       stevel  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     23     0       stevel  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     24     0       stevel  */
     25     0       stevel 
     26     0       stevel /*
     27     0       stevel  * remote login server:
     28     0       stevel  *	remuser\0
     29     0       stevel  *	locuser\0
     30     0       stevel  *	terminal info\0
     31     0       stevel  *	data
     32     0       stevel  */
     33     0       stevel 
     34     0       stevel #include <time.h>
     35     0       stevel #include <sys/types.h>
     36     0       stevel #include <sys/stat.h>
     37     0       stevel #include <sys/socket.h>
     38     0       stevel #include <sys/wait.h>
     39     0       stevel 
     40     0       stevel #include <netinet/in.h>
     41     0       stevel 
     42     0       stevel #include <errno.h>
     43     0       stevel #include <signal.h>
     44     0       stevel #include <fcntl.h>
     45     0       stevel #include <stdio.h>
     46     0       stevel #include <netdb.h>
     47     0       stevel #include <syslog.h>
     48     0       stevel #include <string.h>
     49     0       stevel #include <unistd.h>
     50     0       stevel #include <stdlib.h>
     51     0       stevel #include <alloca.h>
     52     0       stevel #include <stropts.h>
     53     0       stevel #include <sac.h>	/* for SC_WILDC */
     54     0       stevel #include <utmpx.h>
     55     0       stevel #include <sys/filio.h>
     56     0       stevel #include <sys/logindmux.h>
     57     0       stevel #include <sys/rlioctl.h>
     58     0       stevel #include <sys/termios.h>
     59     0       stevel #include <sys/tihdr.h>
     60     0       stevel #include <arpa/inet.h>
     61     0       stevel #include <security/pam_appl.h>
     62     0       stevel #include <strings.h>
     63     0       stevel #include <com_err.h>
     64     0       stevel #include <k5-int.h>
     65     0       stevel #include <kcmd.h>
     66     0       stevel #include <krb5_repository.h>
     67     0       stevel #include <sys/cryptmod.h>
     68     0       stevel #include <bsm/adt.h>
     69  3011        jbeck #include <addr_match.h>
     70  6536          gtb #include <store_forw_creds.h>
     71     0       stevel 
     72     0       stevel #define	KRB5_RECVAUTH_V5 5
     73     0       stevel #define	UT_NAMESIZE	sizeof (((struct utmpx *)0)->ut_name)
     74     0       stevel 
     75     0       stevel static char lusername[UT_NAMESIZE+1];
     76     0       stevel static char rusername[UT_NAMESIZE+1];
     77     0       stevel static char *krusername = NULL;
     78     0       stevel static char term[64];
     79     0       stevel 
     80     0       stevel static krb5_ccache ccache = NULL;
     81     0       stevel static krb5_keyblock *session_key = NULL;
     82     0       stevel static int chksum_flag = 0;
     83     0       stevel static int use_auth = 0;
     84     0       stevel static enum kcmd_proto kcmd_protocol;
     85     0       stevel #ifdef ALLOW_KCMD_V2
     86     0       stevel static krb5_data encr_iv = { NULL, 0 };
     87     0       stevel static krb5_data decr_iv = { NULL, 0 };
     88     0       stevel #endif /* ALLOW_KCMD_V2 */
     89     0       stevel 
     90     0       stevel #define	CHKSUM_REQUIRED 0x01
     91     0       stevel #define	CHKSUM_IGNORED  0x02
     92     0       stevel #define	VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\
     93     0       stevel 			(x) == CHKSUM_IGNORED)
     94     0       stevel 
     95     0       stevel #define	PWD_IF_FAIL  0x01
     96     0       stevel #define	PWD_REQUIRED 0x02
     97     0       stevel 
     98     0       stevel #define	AUTH_NONE 0x00
     99     0       stevel 
    100     0       stevel #define	ARGSTR "k5exEXciM:s:S:D:"
    101     0       stevel #define	DEFAULT_TOS 16
    102     0       stevel 
    103     0       stevel #define	KRB5_PROG_NAME "krlogin"
    104     0       stevel 
    105     0       stevel #define	SECURE_MSG "This rlogin session is using encryption " \
    106     0       stevel 	"for all data transmissions.\r\n"
    107     0       stevel 
    108     0       stevel #define	KRB_V5_SENDAUTH_VERS	"KRB5_SENDAUTH_V1.0"
    109     0       stevel #define	KRB5_RECVAUTH_V5	5
    110     0       stevel 
    111     0       stevel static krb5_error_code krb5_compat_recvauth(krb5_context context,
    112     0       stevel 					    krb5_auth_context *auth_context,
    113     0       stevel 					    krb5_pointer fdp,
    114     0       stevel 					    krb5_principal server,
    115     0       stevel 					    krb5_int32 flags,
    116     0       stevel 					    krb5_keytab keytab,
    117     0       stevel 					    krb5_ticket **ticket,
    118     0       stevel 					    krb5_int32 *auth_sys,
    119     0       stevel 					    krb5_data *version);
    120     0       stevel 
    121     0       stevel static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab);
    122     0       stevel static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t);
    123     0       stevel 
    124     0       stevel extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer,
    125     0       stevel 					krb5_data *);
    126     0       stevel extern krb5_error_code krb5_net_read(krb5_context, int, char *, int);
    127     0       stevel 
    128     0       stevel #define	LOGIN_PROGRAM "/bin/login"
    129     0       stevel 
    130     0       stevel #define	DEFAULT_PROG_NAME	"rlogin"
    131     0       stevel 
    132     0       stevel static const char *pam_prog_name = DEFAULT_PROG_NAME;
    133     0       stevel static void	rmut(void);
    134     0       stevel static void	doit(int,  struct sockaddr_storage *, krb5_context, int,
    135     0       stevel 		    krb5_keytab);
    136     0       stevel static void	protocol(int, int, int);
    137     0       stevel 
    138     0       stevel static int	readstream(int, char *, int);
    139     0       stevel static void	fatal(int, const char *);
    140     0       stevel static void	fatalperror(int, const char *);
    141     0       stevel static int	send_oob(int fd, void *ptr, size_t count);
    142     0       stevel static int	removemod(int f, char *modname);
    143     0       stevel 
    144     0       stevel static int
    145     0       stevel issock(int fd)
    146     0       stevel {
    147     0       stevel 	struct stat stats;
    148     0       stevel 
    149     0       stevel 	if (fstat(fd, &stats) == -1)
    150     0       stevel 		return (0);
    151     0       stevel 	return (S_ISSOCK(stats.st_mode));
    152     0       stevel }
    153     0       stevel 
    154     0       stevel /*
    155     0       stevel  * audit_rlogin_settid stores the terminal id while it is still
    156     0       stevel  * available.  Subsequent calls to adt_load_hostname() return
    157     0       stevel  * the id which is stored here.
    158     0       stevel  */
    159     0       stevel static int
    160     0       stevel audit_rlogin_settid(int fd) {
    161     0       stevel 	adt_session_data_t	*ah;
    162     0       stevel 	adt_termid_t		*termid;
    163     0       stevel 	int			rc;
    164     0       stevel 
    165     0       stevel 	if ((rc = adt_start_session(&ah, NULL, 0)) == 0) {
    166     0       stevel 		if ((rc = adt_load_termid(fd, &termid)) == 0) {
    167     0       stevel 			if ((rc = adt_set_user(ah, ADT_NO_AUDIT,
    168     0       stevel 			    ADT_NO_AUDIT, 0, ADT_NO_AUDIT,
    169     0       stevel 			    termid, ADT_SETTID)) == 0)
    170     0       stevel 				(void) adt_set_proc(ah);
    171     0       stevel 			free(termid);
    172     0       stevel 		}
    173     0       stevel 		(void) adt_end_session(ah);
    174     0       stevel 	}
    175     0       stevel 	return (rc);
    176     0       stevel }
    177     0       stevel 
    178     0       stevel 
    179     0       stevel /* ARGSUSED */
    180   473           bw int
    181     0       stevel main(int argc, char *argv[])
    182     0       stevel {
    183     0       stevel 	int on = 1;
    184     0       stevel 	socklen_t fromlen;
    185     0       stevel 	struct sockaddr_storage from;
    186     0       stevel 	int fd = -1;
    187     0       stevel 
    188     0       stevel 	extern char *optarg;
    189     0       stevel 	char c;
    190     0       stevel 	int tos = -1;
    191     0       stevel 	krb5_context krb_context;
    192     0       stevel 	krb5_keytab keytab = NULL;
    193     0       stevel 	krb5_error_code status;
    194     0       stevel 	char *realm = NULL;
    195     0       stevel 	char *keytab_file = NULL;
    196     0       stevel 	int encr_flag = 0;
    197     0       stevel 	struct sockaddr_storage ouraddr;
    198     0       stevel 	socklen_t ourlen;
    199     0       stevel #ifdef DEBUG
    200     0       stevel 	int debug_port = 0;
    201     0       stevel #endif /* DEBUG */
    202     0       stevel 	openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON);
    203     0       stevel 
    204     0       stevel 	while ((c = getopt(argc, argv, ARGSTR)) != -1) {
    205     0       stevel 		switch (c) {
    206     0       stevel 		case 'k':
    207     0       stevel 		case '5':
    208     0       stevel 			use_auth = KRB5_RECVAUTH_V5;
    209     0       stevel 			break;
    210     0       stevel 		case 'e':
    211     0       stevel 		case 'E':
    212     0       stevel 		case 'x':
    213     0       stevel 		case 'X':
    214     0       stevel 			encr_flag = 1;
    215     0       stevel 			break;
    216     0       stevel 		case 'M':
    217     0       stevel 			realm = (char *)strdup(optarg);
    218     0       stevel 			break;
    219     0       stevel 		case 'S':
    220     0       stevel 			keytab_file = (char *)strdup(optarg);
    221     0       stevel 			break;
    222     0       stevel 		case 'c':
    223     0       stevel 			chksum_flag |= CHKSUM_REQUIRED;
    224     0       stevel 			break;
    225     0       stevel 		case 'i':
    226     0       stevel 			chksum_flag |= CHKSUM_IGNORED;
    227     0       stevel 			break;
    228     0       stevel 		case 's':
    229     0       stevel 			if (optarg == NULL || (tos = atoi(optarg)) < 0 ||
    230     0       stevel 			    tos > 255) {
    231     0       stevel 				syslog(LOG_ERR, "%s: illegal tos value: "
    232     0       stevel 				    "%s\n", argv[0], optarg);
    233     0       stevel 			} else {
    234     0       stevel 				if (tos < 0)
    235     0       stevel 					tos = DEFAULT_TOS;
    236     0       stevel 			}
    237     0       stevel 			break;
    238     0       stevel #ifdef DEBUG
    239     0       stevel 		case 'D':
    240     0       stevel 			debug_port = atoi(optarg);
    241     0       stevel 			break;
    242     0       stevel #endif /* DEBUG */
    243     0       stevel 		default:
    244     0       stevel 			syslog(LOG_ERR, "Unrecognized command line option "
    245  7727  Rameshkumar 			    "(-%c), exiting", optopt);
    246     0       stevel 			exit(EXIT_FAILURE);
    247     0       stevel 		}
    248     0       stevel 	}
    249     0       stevel 	if (use_auth == KRB5_RECVAUTH_V5) {
    250     0       stevel 		status = krb5_init_context(&krb_context);
    251     0       stevel 		if (status) {
    252     0       stevel 			syslog(LOG_ERR, "Error initializing krb5: %s",
    253     0       stevel 			    error_message(status));
    254     0       stevel 			exit(EXIT_FAILURE);
    255     0       stevel 		}
    256     0       stevel 		if (realm != NULL)
    257     0       stevel 			krb5_set_default_realm(krb_context, realm);
    258     0       stevel 		if (keytab_file != NULL) {
    259     0       stevel 			if ((status = krb5_kt_resolve(krb_context,
    260     0       stevel 						    keytab_file,
    261     0       stevel 						    &keytab))) {
    262     0       stevel 				com_err(argv[0],
    263     0       stevel 					status,
    264     0       stevel 					"while resolving srvtab file %s",
    265     0       stevel 					keytab_file);
    266     0       stevel 				exit(EXIT_FAILURE);
    267     0       stevel 			}
    268     0       stevel 		}
    269     0       stevel 	}
    270     0       stevel 
    271     0       stevel #ifdef DEBUG
    272     0       stevel 	if (debug_port) {
    273     0       stevel 		int s;
    274     0       stevel 		struct sockaddr_in sin;
    275     0       stevel 
    276     0       stevel 		if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
    277     0       stevel 			fatalperror(STDERR_FILENO, "Error in socket");
    278     0       stevel 		}
    279     0       stevel 
    280     0       stevel 		(void) memset((char *)&sin, 0, sizeof (sin));
    281     0       stevel 		sin.sin_family = AF_INET;
    282     0       stevel 		sin.sin_port = htons(debug_port);
    283     0       stevel 		sin.sin_addr.s_addr = INADDR_ANY;
    284     0       stevel 
    285     0       stevel 		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
    286     0       stevel 					(char *)&on, sizeof (on));
    287     0       stevel 
    288     0       stevel 		if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
    289     0       stevel 			fatalperror(STDERR_FILENO, "bind error");
    290     0       stevel 		}
    291     0       stevel 
    292     0       stevel 		if ((listen(s, 5)) < 0) {
    293     0       stevel 			fatalperror(STDERR_FILENO, "listen error");
    294     0       stevel 		}
    295     0       stevel 
    296     0       stevel 		fromlen = sizeof (from);
    297     0       stevel 		if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) {
    298     0       stevel 			fatalperror(STDERR_FILENO, "accept error");
    299     0       stevel 		}
    300     0       stevel 
    301     0       stevel 		(void) close(s);
    302     0       stevel 	} else
    303     0       stevel #endif /* DEBUG */
    304     0       stevel 	{
    305     0       stevel 		if (!issock(STDIN_FILENO))
    306     0       stevel 			fatal(STDIN_FILENO,
    307     0       stevel 				"stdin is not a socket file descriptor");
    308     0       stevel 		fd = STDIN_FILENO;
    309     0       stevel 	}
    310     0       stevel 
    311     0       stevel 	fromlen = sizeof (from);
    312     0       stevel 	if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0)
    313     0       stevel 		fatalperror(STDERR_FILENO, "getpeername");
    314     0       stevel 
    315     0       stevel 	if (audit_rlogin_settid(fd))	/* set terminal ID */
    316     0       stevel 		fatalperror(STDERR_FILENO, "audit");
    317     0       stevel 
    318     0       stevel 	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
    319     0       stevel 	    sizeof (on)) < 0)
    320     0       stevel 		syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m");
    321     0       stevel 
    322     0       stevel 	if (!VALID_CHKSUM(chksum_flag)) {
    323     0       stevel 		syslog(LOG_ERR, "Configuration error: mutually exclusive "
    324     0       stevel 		    "options specified (-c and -i)");
    325     0       stevel 		fatal(fd, "Checksums are required and ignored (-c and -i);"
    326     0       stevel 		    "these options are mutually exclusive - check "
    327     0       stevel 		    "the documentation.");
    328     0       stevel 	}
    329     0       stevel 	ourlen = sizeof (ouraddr);
    330     0       stevel 	if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) {
    331     0       stevel 		syslog(LOG_ERR, "getsockname error: %m");
    332     0       stevel 		exit(EXIT_FAILURE);
    333     0       stevel 	}
    334     0       stevel 
    335     0       stevel 	if (tos != -1 &&
    336     0       stevel 	    ouraddr.ss_family != AF_INET6 &&
    337     0       stevel 	    setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos,
    338     0       stevel 					sizeof (tos)) < 0 &&
    339     0       stevel 					errno != ENOPROTOOPT) {
    340     0       stevel 		syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos);
    341     0       stevel 	}
    342     0       stevel 	doit(fd, &from, krb_context, encr_flag, keytab);
    343   473           bw 	return (0);
    344     0       stevel }
    345     0       stevel 
    346     0       stevel static void	cleanup(int);
    347     0       stevel static int	nsize = 0;	/* bytes read prior to pushing rlmod */
    348     0       stevel static char	*rlbuf;		/* buffer where nbytes are read to */
    349     0       stevel static char	*line;
    350     0       stevel 
    351     0       stevel static struct winsize win = { 0, 0, 0, 0 };
    352     0       stevel static pid_t pid;
    353     0       stevel static char hostname[MAXHOSTNAMELEN + 1];
    354     0       stevel 
    355     0       stevel static void
    356     0       stevel getstr(int f, char *buf, int cnt, char *err)
    357     0       stevel {
    358     0       stevel 	char c;
    359     0       stevel 	do {
    360     0       stevel 		if (read(f, &c, 1) != 1 || (--cnt < 0)) {
    361     0       stevel 			syslog(LOG_ERR, "Error reading \'%s\' field", err);
    362     0       stevel 			exit(EXIT_FAILURE);
    363     0       stevel 		}
    364     0       stevel 		*buf++ = c;
    365     0       stevel 	} while (c != '\0');
    366     0       stevel }
    367     0       stevel 
    368     0       stevel static krb5_error_code
    369     0       stevel recvauth(int f,
    370     0       stevel 	krb5_context krb_context,
    371     0       stevel 	unsigned int *valid_checksum,
    372     0       stevel 	krb5_ticket **ticket,
    373     0       stevel 	int *auth_type,
    374     0       stevel 	krb5_principal *client,
    375     0       stevel 	int encr_flag,
    376     0       stevel 	krb5_keytab keytab)
    377     0       stevel {
    378     0       stevel 	krb5_error_code status = 0;
    379     0       stevel 	krb5_auth_context auth_context = NULL;
    380     0       stevel 	krb5_rcache rcache;
    381     0       stevel 	krb5_authenticator *authenticator;
    382     0       stevel 	krb5_data inbuf;
    383     0       stevel 	krb5_data auth_version;
    384     0       stevel 
    385     0       stevel 	*valid_checksum = 0;
    386     0       stevel 
    387     0       stevel 	if ((status = krb5_auth_con_init(krb_context, &auth_context)))
    388     0       stevel 		return (status);
    389     0       stevel 
    390     0       stevel 	/* Only need remote address for rd_cred() to verify client */
    391     0       stevel 	if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
    392     0       stevel 			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
    393     0       stevel 		return (status);
    394     0       stevel 
    395     0       stevel 	status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
    396     0       stevel 	if (status)
    397     0       stevel 		return (status);
    398     0       stevel 
    399     0       stevel 	if (!rcache) {
    400     0       stevel 		krb5_principal server;
    401     0       stevel 
    402     0       stevel 		status = krb5_sname_to_principal(krb_context, 0, 0,
    403     0       stevel 						KRB5_NT_SRV_HST, &server);
    404     0       stevel 		if (status)
    405     0       stevel 			return (status);
    406     0       stevel 
    407     0       stevel 		status = krb5_get_server_rcache(krb_context,
    408     0       stevel 				krb5_princ_component(krb_context, server, 0),
    409     0       stevel 				&rcache);
    410     0       stevel 		krb5_free_principal(krb_context, server);
    411     0       stevel 		if (status)
    412     0       stevel 			return (status);
    413     0       stevel 
    414     0       stevel 		status = krb5_auth_con_setrcache(krb_context, auth_context,
    415     0       stevel 						rcache);
    416     0       stevel 		if (status)
    417     0       stevel 			return (status);
    418     0       stevel 	}
    419     0       stevel 	if ((status = krb5_compat_recvauth(krb_context,
    420     0       stevel 					&auth_context,
    421     0       stevel 					&f,
    422     0       stevel 					NULL,	/* Specify daemon principal */
    423     0       stevel 					0,	/* no flags */
    424     0       stevel 					keytab,	/* NULL to use v5srvtab */
    425     0       stevel 					ticket,	/* return ticket */
    426     0       stevel 					auth_type, /* authentication system */
    427     0       stevel 					&auth_version))) {
    428     0       stevel 		if (*auth_type == KRB5_RECVAUTH_V5) {
    429     0       stevel 			/*
    430     0       stevel 			 * clean up before exiting
    431     0       stevel 			 */
    432     0       stevel 			getstr(f, rusername, sizeof (rusername), "remuser");
    433     0       stevel 			getstr(f, lusername, sizeof (lusername), "locuser");
    434     0       stevel 			getstr(f, term, sizeof (term), "Terminal type");
    435     0       stevel 		}
    436     0       stevel 		return (status);
    437     0       stevel 	}
    438     0       stevel 
    439     0       stevel 	getstr(f, lusername, sizeof (lusername), "locuser");
    440     0       stevel 	getstr(f, term, sizeof (term), "Terminal type");
    441     0       stevel 
    442     0       stevel 	kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
    443     0       stevel 	if (auth_version.length != 9 || auth_version.data == NULL) {
    444     0       stevel 		syslog(LOG_ERR, "Bad application protocol version length in "
    445     0       stevel 		    "KRB5 exchange, exiting");
    446     0       stevel 		fatal(f, "Bad application version length, exiting.");
    447     0       stevel 	}
    448     0       stevel 	/*
    449     0       stevel 	 * Determine which Kerberos CMD protocol was used.
    450     0       stevel 	 */
    451     0       stevel 	if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
    452     0       stevel 		kcmd_protocol = KCMD_OLD_PROTOCOL;
    453     0       stevel 	} else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
    454     0       stevel 		kcmd_protocol = KCMD_NEW_PROTOCOL;
    455     0       stevel 	} else {
    456     0       stevel 		syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
    457     0       stevel 			(char *)auth_version.data);
    458     0       stevel 		fatal(f, "Unrecognized KCMD protocol, exiting");
    459     0       stevel 	}
    460     0       stevel 
    461     0       stevel 	if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
    462     0       stevel 		kcmd_protocol == KCMD_OLD_PROTOCOL) {
    463     0       stevel 		if ((status = krb5_auth_con_getauthenticator(krb_context,
    464     0       stevel 							    auth_context,
    465     0       stevel 							    &authenticator)))
    466     0       stevel 			return (status);
    467     0       stevel 		if (authenticator->checksum) {
    468     0       stevel 			struct sockaddr_storage adr;
    469     0       stevel 			int adr_length = sizeof (adr);
    470     0       stevel 			int buflen;
    471     0       stevel 			krb5_data input;
    472     0       stevel 			krb5_keyblock key;
    473     0       stevel 			char *chksumbuf;
    474     0       stevel 
    475     0       stevel 			/*
    476     0       stevel 			 * Define the lenght of the chksum buffer.
    477     0       stevel 			 * chksum string = "[portnum]:termstr:username"
    478     0       stevel 			 * The extra 32 is to hold a integer string for
    479     0       stevel 			 * the portnumber.
    480     0       stevel 			 */
    481     0       stevel 			buflen = strlen(term) + strlen(lusername) + 32;
    482     0       stevel 			chksumbuf = (char *)malloc(buflen);
    483     0       stevel 			if (chksumbuf == 0) {
    484     0       stevel 				krb5_free_authenticator(krb_context,
    485     0       stevel 							authenticator);
    486     0       stevel 				fatal(f, "Out of memory error");
    487     0       stevel 			}
    488     0       stevel 
    489     0       stevel 			if (getsockname(f, (struct sockaddr *)&adr,
    490     0       stevel 							&adr_length) != 0) {
    491     0       stevel 				krb5_free_authenticator(krb_context,
    492     0       stevel 							authenticator);
    493     0       stevel 				fatal(f, "getsockname error");
    494     0       stevel 			}
    495     0       stevel 
    496     0       stevel 			(void) snprintf(chksumbuf, buflen,
    497     0       stevel 					"%u:%s%s",
    498     0       stevel 					ntohs(SOCK_PORT(adr)),
    499     0       stevel 					term, lusername);
    500     0       stevel 
    501     0       stevel 			input.data = chksumbuf;
    502     0       stevel 			input.length = strlen(chksumbuf);
    503     0       stevel 			key.contents = (*ticket)->enc_part2->session->contents;
    504     0       stevel 			key.length = (*ticket)->enc_part2->session->length;
    505     0       stevel 			status = krb5_c_verify_checksum(krb_context,
    506     0       stevel 						&key, 0,
    507     0       stevel 						&input,
    508     0       stevel 						authenticator->checksum,
    509     0       stevel 						valid_checksum);
    510     0       stevel 
    511     0       stevel 			if (status == 0 && *valid_checksum == 0)
    512     0       stevel 				status = KRB5KRB_AP_ERR_BAD_INTEGRITY;
    513     0       stevel 
    514     0       stevel 			if (chksumbuf)
    515     0       stevel 				krb5_xfree(chksumbuf);
    516     0       stevel 			if (status) {
    517     0       stevel 				krb5_free_authenticator(krb_context,
    518     0       stevel 							authenticator);
    519     0       stevel 				return (status);
    520     0       stevel 			}
    521     0       stevel 		}
    522     0       stevel 		krb5_free_authenticator(krb_context, authenticator);
    523     0       stevel 	}
    524     0       stevel 
    525     0       stevel 	if ((status = krb5_copy_principal(krb_context,
    526     0       stevel 					(*ticket)->enc_part2->client,
    527     0       stevel 					client)))
    528     0       stevel 		return (status);
    529     0       stevel 
    530     0       stevel 	/* Get the Unix username of the remote user */
    531     0       stevel 	getstr(f, rusername, sizeof (rusername), "remuser");
    532     0       stevel 
    533     0       stevel 	/* Get the Kerberos principal name string of the remote user */
    534     0       stevel 	if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
    535     0       stevel 		return (status);
    536     0       stevel 
    537     0       stevel #ifdef DEBUG
    538     0       stevel 	syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
    539     0       stevel 	    (krusername != NULL ? krusername : "<unknown>"));
    540     0       stevel #endif
    541     0       stevel 
    542     0       stevel 	if (encr_flag) {
    543     0       stevel 		status = krb5_auth_con_getremotesubkey(krb_context,
    544     0       stevel 						    auth_context,
    545     0       stevel 						    &session_key);
    546     0       stevel 		if (status) {
    547     0       stevel 			syslog(LOG_ERR, "Error getting KRB5 session "
    548     0       stevel 			    "subkey, exiting");
    549     0       stevel 			fatal(f, "Error getting KRB5 session subkey, exiting");
    550     0       stevel 		}
    551     0       stevel 		/*
    552     0       stevel 		 * The "new" protocol requires that a subkey be sent.
    553     0       stevel 		 */
    554     0       stevel 		if (session_key == NULL &&
    555     0       stevel 		    kcmd_protocol == KCMD_NEW_PROTOCOL) {
    556     0       stevel 			syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
    557     0       stevel 			fatal(f, "No KRB5 session subkey sent, exiting");
    558     0       stevel 		}
    559     0       stevel 		/*
    560     0       stevel 		 * The "old" protocol does not permit an authenticator subkey.
    561     0       stevel 		 * The key is taken from the ticket instead (see below).
    562     0       stevel 		 */
    563     0       stevel 		if (session_key != NULL &&
    564     0       stevel 		    kcmd_protocol == KCMD_OLD_PROTOCOL) {
    565     0       stevel 			syslog(LOG_ERR, "KRB5 session subkey not permitted "
    566     0       stevel 			    "with old KCMD protocol, exiting");
    567     0       stevel 
    568     0       stevel 			fatal(f, "KRB5 session subkey not permitted "
    569     0       stevel 			    "with old KCMD protocol, exiting");
    570     0       stevel 		}
    571     0       stevel 		/*
    572     0       stevel 		 * If no key at this point, use the session key from
    573     0       stevel 		 * the ticket.
    574     0       stevel 		 */
    575     0       stevel 		if (session_key == NULL) {
    576     0       stevel 			/*
    577     0       stevel 			 * Save the session key so we can configure the crypto
    578     0       stevel 			 * module later.
    579     0       stevel 			 */
    580     0       stevel 			status = krb5_copy_keyblock(krb_context,
    581     0       stevel 					    (*ticket)->enc_part2->session,
    582     0       stevel 					    &session_key);
    583     0       stevel 			if (status) {
    584     0       stevel 				syslog(LOG_ERR, "krb5_copy_keyblock failed");
    585     0       stevel 				fatal(f, "krb5_copy_keyblock failed");
    586     0       stevel 			}
    587     0       stevel 		}
    588     0       stevel 		/*
    589     0       stevel 		 * If session key still cannot be found, we must
    590     0       stevel 		 * exit because encryption is required here
    591     0       stevel 		 * when encr_flag (-x) is set.
    592     0       stevel 		 */
    593     0       stevel 		if (session_key == NULL) {
    594     0       stevel 			syslog(LOG_ERR, "Could not find an encryption key,"
    595     0       stevel 				    "exiting");
    596     0       stevel 			fatal(f, "Encryption required but key not found, "
    597     0       stevel 			    "exiting");
    598     0       stevel 		}
    599     0       stevel 	}
    600     0       stevel 	/*
    601     0       stevel 	 * Use krb5_read_message to read the principal stuff.
    602     0       stevel 	 */
    603     0       stevel 	if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
    604     0       stevel 					&inbuf)))
    605     0       stevel 		fatal(f, "Error reading krb5 message");
    606     0       stevel 
    607  6536          gtb 	if (inbuf.length) { /* Forwarding being done, read creds */
    608  6536          gtb 		krb5_creds **creds = NULL;
    609  6536          gtb 
    610  6536          gtb 		if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
    611  6536          gtb 					    &creds, NULL)) {
    612  6536          gtb 			if (rcache)
    613  6536          gtb 				(void) krb5_rc_close(krb_context, rcache);
    614  6536          gtb 			krb5_free_creds(krb_context, *creds);
    615  6536          gtb 			fatal(f, "Can't get forwarded credentials");
    616  6536          gtb 		}
    617  6536          gtb 
    618  6536          gtb 		/* Store the forwarded creds in the ccache */
    619  6536          gtb 		if (status = store_forw_creds(krb_context,
    620  6536          gtb 					    creds, *ticket, lusername,
    621  6536          gtb 					    &ccache)) {
    622  6536          gtb 			if (rcache)
    623  6536          gtb 				(void) krb5_rc_close(krb_context, rcache);
    624  6536          gtb 			krb5_free_creds(krb_context, *creds);
    625  6536          gtb 			fatal(f, "Can't store forwarded credentials");
    626  6536          gtb 		}
    627  6536          gtb 		krb5_free_creds(krb_context, *creds);
    628     0       stevel 	}
    629  6536          gtb 
    630     0       stevel 	if (rcache)
    631     0       stevel 		(void) krb5_rc_close(krb_context, rcache);
    632     0       stevel 
    633     0       stevel 	return (status);
    634     0       stevel }
    635     0       stevel 
    636     0       stevel static void
    637     0       stevel do_krb_login(int f, char *host_addr, char *hostname,
    638     0       stevel 	    krb5_context krb_context, int encr_flag,
    639     0       stevel 	    krb5_keytab keytab)
    640     0       stevel {
    641     0       stevel 	krb5_error_code status;
    642     0       stevel 	uint_t valid_checksum;
    643     0       stevel 	krb5_ticket	*ticket = NULL;
    644     0       stevel 	int auth_sys = 0;
    645     0       stevel 	int auth_sent = 0;
    646     0       stevel 	krb5_principal client = NULL;
    647     0       stevel 
    648     0       stevel 	if (getuid())
    649     0       stevel 		fatal(f, "Error authorizing KRB5 connection, "
    650     0       stevel 			"server lacks privilege");
    651     0       stevel 
    652     0       stevel 	status = recvauth(f, krb_context, &valid_checksum, &ticket,
    653     0       stevel 			&auth_sys, &client, encr_flag, keytab);
    654     0       stevel 	if (status) {
    655     0       stevel 		if (ticket)
    656     0       stevel 			krb5_free_ticket(krb_context, ticket);
    657     0       stevel 		if (status != 255)
    658     0       stevel 			syslog(LOG_ERR,
    659     0       stevel 			    "Authentication failed from %s(%s): %s\n",
    660     0       stevel 			    host_addr, hostname, error_message(status));
    661     0       stevel 		fatal(f, "Kerberos authentication failed, exiting");
    662     0       stevel 	}
    663     0       stevel 
    664     0       stevel 	if (auth_sys != KRB5_RECVAUTH_V5) {
    665     0       stevel 		fatal(f, "This server only supports Kerberos V5");
    666     0       stevel 	} else {
    667     0       stevel 		/*
    668     0       stevel 		 * Authenticated OK, now check authorization.
    669     0       stevel 		 */
    670     0       stevel 		if (client && krb5_kuserok(krb_context, client, lusername))
    671     0       stevel 		    auth_sent = KRB5_RECVAUTH_V5;
    672     0       stevel 	}
    673     0       stevel 
    674     0       stevel 	if (auth_sent == KRB5_RECVAUTH_V5 &&
    675     0       stevel 	    kcmd_protocol == KCMD_OLD_PROTOCOL &&
    676     0       stevel 	    chksum_flag == CHKSUM_REQUIRED && !valid_checksum) {
    677     0       stevel 		syslog(LOG_ERR, "Client did not supply required checksum, "
    678     0       stevel 		    "connection rejected.");
    679     0       stevel 		fatal(f, "Client did not supply required checksum, "
    680     0       stevel 		    "connection rejected.");
    681     0       stevel 	}
    682     0       stevel 
    683     0       stevel 	if (auth_sys != auth_sent) {
    684     0       stevel 		char *msg_fail = NULL;
    685     0       stevel 		int msgsize = 0;
    686     0       stevel 
    687     0       stevel 		if (ticket)
    688     0       stevel 			krb5_free_ticket(krb_context, ticket);
    689     0       stevel 
    690     0       stevel 		if (krusername != NULL) {
    691     0       stevel 			/*
    692     0       stevel 			 * msgsize must be enough to hold
    693     0       stevel 			 * krusername, lusername and a brief
    694     0       stevel 			 * message describing the failure.
    695     0       stevel 			 */
    696     0       stevel 			msgsize = strlen(krusername) +
    697     0       stevel 				strlen(lusername) + 80;
    698     0       stevel 			msg_fail = (char *)malloc(msgsize);
    699     0       stevel 		}
    700     0       stevel 		if (msg_fail == NULL) {
    701     0       stevel 			syslog(LOG_ERR, "User is not authorized to login to "
    702     0       stevel 			    "specified account");
    703     0       stevel 
    704     0       stevel 			fatal(f, "User is not authorized to login to "
    705     0       stevel 			    "specified account");
    706     0       stevel 		}
    707     0       stevel 		if (auth_sent != 0)
    708     0       stevel 			(void) snprintf(msg_fail, msgsize,
    709     0       stevel 					"Access denied because of improper "
    710     0       stevel 					"KRB5 credentials");
    711     0       stevel 		else
    712     0       stevel 			(void) snprintf(msg_fail, msgsize,
    713     0       stevel 					"User %s is not authorized to login "
    714     0       stevel 					"to account %s",
    715     0       stevel 					krusername, lusername);
    716     0       stevel 		syslog(LOG_ERR, "%s", msg_fail);
    717     0       stevel 		fatal(f, msg_fail);
    718     0       stevel 	}
    719     0       stevel }
    720     0       stevel 
    721     0       stevel /*
    722     0       stevel  * stop_stream
    723     0       stevel  *
    724     0       stevel  * Utility routine to send a CRYPTIOCSTOP ioctl to the
    725     0       stevel  * crypto module(cryptmod).
    726     0       stevel  */
    727     0       stevel static void
    728     0       stevel stop_stream(int fd, int dir)
    729     0       stevel {
    730     0       stevel 	struct strioctl  crioc;
    731     0       stevel 	uint32_t stopdir = dir;
    732     0       stevel 
    733     0       stevel 	crioc.ic_cmd = CRYPTIOCSTOP;
    734     0       stevel 	crioc.ic_timout = -1;
    735     0       stevel 	crioc.ic_len = sizeof (stopdir);
    736     0       stevel 	crioc.ic_dp = (char *)&stopdir;
    737     0       stevel 
    738     0       stevel 	if (ioctl(fd, I_STR, &crioc))
    739     0       stevel 		syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m");
    740     0       stevel }
    741     0       stevel 
    742     0       stevel /*
    743     0       stevel  * start_stream
    744     0       stevel  *
    745     0       stevel  * Utility routine to send a CRYPTIOCSTART ioctl to the
    746     0       stevel  * crypto module(cryptmod).  This routine may contain optional
    747     0       stevel  * payload data that the cryptmod will interpret as bytes that
    748     0       stevel  * need to be decrypted and sent back up to the application
    749     0       stevel  * via the data stream.
    750     0       stevel  */
    751     0       stevel static void
    752     0       stevel start_stream(int fd, int dir)
    753     0       stevel {
    754     0       stevel 	struct strioctl crioc;
    755     0       stevel 	uint32_t iocval;
    756     0       stevel 	size_t datalen = 0;
    757     0       stevel 	char *data = NULL;
    758     0       stevel 
    759     0       stevel 	if (dir == CRYPT_DECRYPT) {
    760     0       stevel 		iocval = CRYPTIOCSTARTDEC;
    761     0       stevel 
    762     0       stevel 		/* Look for data not yet processed */
    763     0       stevel 		if (ioctl(fd, I_NREAD, &datalen) < 0) {
    764     0       stevel 			syslog(LOG_ERR, "I_NREAD returned error %m");
    765     0       stevel 			datalen = 0;
    766     0       stevel 		} else {
    767     0       stevel 			if (datalen > 0) {
    768     0       stevel 				data = malloc(datalen);
    769     0       stevel 				if (data != NULL) {
    770     0       stevel 					int nbytes = read(fd, data, datalen);
    771     0       stevel 					datalen = nbytes;
    772     0       stevel 				} else {
    773     0       stevel 					syslog(LOG_ERR,
    774     0       stevel 						"malloc error (%d bytes)",
    775     0       stevel 						datalen);
    776     0       stevel 					datalen = 0;
    777     0       stevel 				}
    778     0       stevel 			} else {
    779     0       stevel 				datalen = 0;
    780     0       stevel 			}
    781     0       stevel 		}
    782     0       stevel 	} else {
    783     0       stevel 		iocval = CRYPTIOCSTARTENC;
    784     0       stevel 	}
    785     0       stevel 
    786     0       stevel 	crioc.ic_cmd = iocval;
    787     0       stevel 	crioc.ic_timout = -1;
    788     0       stevel 	crioc.ic_len = datalen;
    789     0       stevel 	crioc.ic_dp = data;
    790     0       stevel 
    791     0       stevel 	if (ioctl(fd, I_STR, &crioc))
    792     0       stevel 		syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m");
    793     0       stevel 
    794     0       stevel 	if (data != NULL)
    795     0       stevel 		free(data);
    796     0       stevel }
    797     0       stevel 
    798     0       stevel static int
    799     0       stevel configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec,
    800     0       stevel 		uint_t iv_usage)
    801     0       stevel {
    802     0       stevel 	struct cr_info_t setup_info;
    803     0       stevel 	struct strioctl crioc;
    804     0       stevel 	int retval = 0;
    805     0       stevel 
    806     0       stevel 	switch (skey->enctype) {
    807     0       stevel 	case ENCTYPE_DES_CBC_CRC:
    808     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC;
    809     0       stevel 		break;
    810     0       stevel 	case ENCTYPE_DES_CBC_MD5:
    811     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5;
    812     0       stevel 		break;
    813     0       stevel 	case ENCTYPE_DES_CBC_RAW:
    814     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL;
    815     0       stevel 		break;
    816     0       stevel 	case ENCTYPE_DES3_CBC_SHA1:
    817     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1;
    818     0       stevel 		break;
    819     0       stevel 	case ENCTYPE_ARCFOUR_HMAC:
    820     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5;
    821     0       stevel 		break;
    822     0       stevel 	case ENCTYPE_ARCFOUR_HMAC_EXP:
    823     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP;
    824     0       stevel 		break;
    825     0       stevel 	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
    826     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_AES128;
    827     0       stevel 		break;
    828     0       stevel 	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
    829     0       stevel 		setup_info.crypto_method = CRYPT_METHOD_AES256;
    830     0       stevel 		break;
    831     0       stevel 	default:
    832     0       stevel 		syslog(LOG_ERR, "Enctype in kerberos session key "
    833     0       stevel 		    "is not supported by crypto module(%d)",
    834     0       stevel 		    skey->enctype);
    835     0       stevel 		return (-1);
    836     0       stevel 	}
    837     0       stevel 	if (ivec == NULL || ivec->length == 0) {
    838     0       stevel 		(void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec));
    839     0       stevel 
    840     0       stevel 		if (skey->enctype != ENCTYPE_ARCFOUR_HMAC &&
    841     0       stevel 		    skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP)
    842     0       stevel 			/* Kerberos IVs are 8 bytes long for DES keys */
    843     0       stevel 			setup_info.iveclen = KRB5_MIT_DES_KEYSIZE;
    844     0       stevel 		else
    845     0       stevel 			setup_info.iveclen = 0;
    846     0       stevel 	} else {
    847     0       stevel 		(void) memcpy(&setup_info.ivec, ivec->data, ivec->length);
    848     0       stevel 		setup_info.iveclen = ivec->length;
    849     0       stevel 	}
    850     0       stevel 
    851     0       stevel 	setup_info.ivec_usage = iv_usage;
    852     0       stevel 	(void) memcpy(&setup_info.key, skey->contents, skey->length);
    853     0       stevel 
    854     0       stevel 	setup_info.keylen = skey->length;
    855     0       stevel 	setup_info.direction_mask = dir;
    856     0       stevel 	/*
    857     0       stevel 	 * R* commands get special handling by crypto module -
    858     0       stevel 	 * 4 byte length field is used before each encrypted block
    859     0       stevel 	 * of data.
    860     0       stevel 	 */
    861     0       stevel 	setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ?
    862     0       stevel 				CRYPTOPT_RCMD_MODE_V1 :
    863     0       stevel 				CRYPTOPT_RCMD_MODE_V2);
    864     0       stevel 
    865     0       stevel 	crioc.ic_cmd = CRYPTIOCSETUP;
    866     0       stevel 	crioc.ic_timout = -1;
    867     0       stevel 	crioc.ic_len = sizeof (setup_info);
    868     0       stevel 	crioc.ic_dp = (char *)&setup_info;
    869     0       stevel 
    870     0       stevel 	if (ioctl(fd, I_STR, &crioc)) {
    871     0       stevel 		syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m");
    872     0       stevel 		retval = -1;
    873     0       stevel 	}
    874     0       stevel 	return (retval);
    875     0       stevel }
    876     0       stevel 
    877     0       stevel static krb5_error_code
    878     0       stevel krb5_compat_recvauth(krb5_context context,
    879     0       stevel 		    krb5_auth_context *auth_context,
    880     0       stevel 		    krb5_pointer fdp,	/* IN */
    881     0       stevel 		    krb5_principal server,	/* IN */
    882     0       stevel 		    krb5_int32 flags,	/* IN */
    883     0       stevel 		    krb5_keytab keytab,	/* IN */
    884     0       stevel 		    krb5_ticket **ticket, /* OUT */
    885     0       stevel 		    krb5_int32 *auth_sys, /* OUT */
    886     0       stevel 		    krb5_data *version)   /* OUT */
    887     0       stevel {
    888     0       stevel 	krb5_int32 vlen;
    889     0       stevel 	char	*buf;
    890     0       stevel 	int	len, length;
    891     0       stevel 	krb5_int32	retval;
    892     0       stevel 	int		fd = *((int *)fdp);
    893     0       stevel 
    894     0       stevel 	if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4)
    895     0       stevel 		return ((retval < 0) ? errno : ECONNABORTED);
    896     0       stevel 
    897     0       stevel 	/*
    898     0       stevel 	 * Assume that we're talking to a V5 recvauth; read in the
    899     0       stevel 	 * the version string, and make sure it matches.
    900     0       stevel 	 */
    901     0       stevel 	len = (int)ntohl(vlen);
    902     0       stevel 
    903     0       stevel 	if (len < 0 || len > 255)
    904     0       stevel 		return (KRB5_SENDAUTH_BADAUTHVERS);
    905     0       stevel 
    906     0       stevel 	buf = malloc(len);
    907     0       stevel 	if (buf == NULL)
    908     0       stevel 		return (ENOMEM);
    909     0       stevel 
    910     0       stevel 	length = krb5_net_read(context, fd, buf, len);
    911     0       stevel 	if (len != length) {
    912     0       stevel 		krb5_xfree(buf);
    913     0       stevel 		return ((len < 0) ? errno : ECONNABORTED);
    914     0       stevel 	}
    915     0       stevel 
    916     0       stevel 	if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) {
    917     0       stevel 		krb5_xfree(buf);
    918     0       stevel 		return (KRB5_SENDAUTH_BADAUTHVERS);
    919     0       stevel 	}
    920     0       stevel 	krb5_xfree(buf);
    921     0       stevel 
    922     0       stevel 	*auth_sys = KRB5_RECVAUTH_V5;
    923     0       stevel 
    924     0       stevel 	retval = krb5_recvauth_version(context, auth_context, fdp,
    925     0       stevel 				    server, flags | KRB5_RECVAUTH_SKIP_VERSION,
    926     0       stevel 				    keytab, ticket, version);
    927     0       stevel 
    928     0       stevel 	return (retval);
    929     0       stevel }
    930     0       stevel 
    931     0       stevel 
    932     0       stevel static void
    933     0       stevel doit(int f,
    934     0       stevel 	struct sockaddr_storage *fromp,
    935     0       stevel 	krb5_context krb_context,
    936     0       stevel 	int encr_flag,
    937     0       stevel 	krb5_keytab keytab)
    938     0       stevel {
    939     0       stevel 	int p, t, on = 1;
    940     0       stevel 	char c;
    941     0       stevel 	char abuf[INET6_ADDRSTRLEN];
    942     0       stevel 	struct sockaddr_in *sin;
    943     0       stevel 	struct sockaddr_in6 *sin6;
    944     0       stevel 	int fromplen;
    945     0       stevel 	in_port_t port;
    946     0       stevel 	struct termios tp;
    947     0       stevel 	boolean_t bad_port;
    948     0       stevel 	boolean_t no_name;
    949     0       stevel 	char rhost_addra[INET6_ADDRSTRLEN];
    950     0       stevel 
    951     0       stevel 	if (!(rlbuf = malloc(BUFSIZ))) {
    952     0       stevel 		syslog(LOG_ERR, "rlbuf malloc failed\n");
    953     0       stevel 		exit(EXIT_FAILURE);
    954     0       stevel 	}
    955     0       stevel 	(void) alarm(60);
    956     0       stevel 	if (read(f, &c, 1) != 1 || c != 0) {
    957     0       stevel 		syslog(LOG_ERR, "failed to receive protocol zero byte\n");
    958     0       stevel 		exit(EXIT_FAILURE);
    959     0       stevel 	}
    960     0       stevel 	(void) alarm(0);
    961     0       stevel 	if (fromp->ss_family == AF_INET) {
    962     0       stevel 		sin = (struct sockaddr_in *)fromp;
    963     0       stevel 		port = sin->sin_port = ntohs((ushort_t)sin->sin_port);
    964     0       stevel 		fromplen = sizeof (struct sockaddr_in);
    965     0       stevel 
    966     0       stevel 		if (!inet_ntop(AF_INET, &sin->sin_addr,
    967     0       stevel 			    rhost_addra, sizeof (rhost_addra)))
    968     0       stevel 			goto badconversion;
    969     0       stevel 	} else if (fromp->ss_family == AF_INET6) {
    970     0       stevel 		sin6 = (struct sockaddr_in6 *)fromp;
    971     0       stevel 		port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port);
    972     0       stevel 		fromplen = sizeof (struct sockaddr_in6);
    973     0       stevel 
    974     0       stevel 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
    975     0       stevel 			struct in_addr ipv4_addr;
    976     0       stevel 
    977     0       stevel 			IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
    978     0       stevel 					    &ipv4_addr);
    979     0       stevel 			if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra,
    980     0       stevel 				    sizeof (rhost_addra)))
    981     0       stevel 				goto badconversion;
    982     0       stevel 		} else {
    983     0       stevel 			if (!inet_ntop(AF_INET6, &sin6->sin6_addr,
    984     0       stevel 				    rhost_addra, sizeof (rhost_addra)))
    985     0       stevel 				goto badconversion;
    986     0       stevel 		}
    987     0       stevel 	} else {
    988     0       stevel 		syslog(LOG_ERR, "unknown address family %d\n",
    989     0       stevel 		    fromp->ss_family);
    990     0       stevel 		fatal(f, "Permission denied");
    991     0       stevel 	}
    992     0       stevel 
    993     0       stevel 	/*
    994     0       stevel 	 * Allow connections only from the "ephemeral" reserved
    995     0       stevel 	 * ports(ports 512 - 1023) by checking the remote port
    996     0       stevel 	 * because other utilities(e.g. in.ftpd) can be used to
    997     0       stevel 	 * allow a unprivileged user to originate a connection
    998     0       stevel 	 * from a privileged port and provide untrustworthy
    999     0       stevel 	 * authentication.
   1000     0       stevel 	 */
   1001     0       stevel 	bad_port = (use_auth != KRB5_RECVAUTH_V5 &&
   1002     0       stevel 		    (port >= (in_port_t)IPPORT_RESERVED) ||
   1003     0       stevel 		    (port < (in_port_t)(IPPORT_RESERVED/2)));
   1004     0       stevel 	no_name = getnameinfo((const struct sockaddr *) fromp,
   1005     0       stevel 			    fromplen, hostname, sizeof (hostname),
   1006     0       stevel 			    NULL, 0, 0) != 0;
   1007     0       stevel 
   1008     0       stevel 	if (no_name || bad_port) {
   1009     0       stevel 		(void) strlcpy(abuf, rhost_addra, sizeof (abuf));
   1010     0       stevel 		/* If no host name, use IP address for name later on. */
   1011     0       stevel 		if (no_name)
   1012     0       stevel 			(void) strlcpy(hostname, abuf, sizeof (hostname));
   1013     0       stevel 	}
   1014     0       stevel 
   1015  3011        jbeck 	if (!no_name) {
   1016  3011        jbeck 		/*
   1017  3011        jbeck 		 * Even if getnameinfo() succeeded, we still have to check
   1018  3011        jbeck 		 * for spoofing.
   1019  3011        jbeck 		 */
   1020  3011        jbeck 		check_address("rlogind", fromp, sin, sin6, rhost_addra,
   1021  3011        jbeck 		    hostname, sizeof (hostname));
   1022  3011        jbeck 	}
   1023  3011        jbeck 
   1024     0       stevel 	if (bad_port) {
   1025     0       stevel 		if (no_name)
   1026     0       stevel 			syslog(LOG_NOTICE,
   1027     0       stevel 			    "connection from %s - bad port\n",
   1028     0       stevel 			    abuf);
   1029     0       stevel 		else
   1030     0       stevel 			syslog(LOG_NOTICE,
   1031     0       stevel 			    "connection from %s(%s) - bad port\n",
   1032     0       stevel 			    hostname, abuf);
   1033     0       stevel 		fatal(f, "Permission denied");
   1034     0       stevel 	}
   1035     0       stevel 
   1036     0       stevel 	if (use_auth == KRB5_RECVAUTH_V5) {
   1037     0       stevel 		do_krb_login(f, rhost_addra, hostname,
   1038     0       stevel 			    krb_context, encr_flag, keytab);
   1039     0       stevel 		if (krusername != NULL && strlen(krusername)) {
   1040     0       stevel 			/*
   1041     0       stevel 			 * Kerberos Authentication succeeded,
   1042     0       stevel 			 * so set the proper program name to use
   1043     0       stevel 			 * with pam (important during 'cleanup'
   1044     0       stevel 			 * routine later).
   1045     0       stevel 			 */
   1046     0       stevel 			pam_prog_name = KRB5_PROG_NAME;
   1047     0       stevel 		}
   1048     0       stevel 	}
   1049     0       stevel 
   1050     0       stevel 	if (write(f, "", 1) != 1) {
   1051     0       stevel 		syslog(LOG_NOTICE,
   1052     0       stevel 		    "send of the zero byte(to %s) failed:"
   1053     0       stevel 		    " cannot start data transfer mode\n",
   1054     0       stevel 		    (no_name ? abuf : hostname));
   1055     0       stevel 		exit(EXIT_FAILURE);
   1056     0       stevel 	}
   1057     0       stevel 	if ((p = open("/dev/ptmx", O_RDWR)) == -1)
   1058     0       stevel 		fatalperror(f, "cannot open /dev/ptmx");
   1059     0       stevel 	if (grantpt(p) == -1)
   1060     0       stevel 		fatal(f, "could not grant slave pty");
   1061     0       stevel 	if (unlockpt(p) == -1)
   1062     0       stevel 		fatal(f, "could not unlock slave pty");
   1063     0       stevel 	if ((line = ptsname(p)) == NULL)
   1064     0       stevel 		fatal(f, "could not enable slave pty");
   1065     0       stevel 	if ((t = open(line, O_RDWR)) == -1)
   1066     0       stevel 		fatal(f, "could not open slave pty");
   1067     0       stevel 	if (ioctl(t, I_PUSH, "ptem") == -1)
   1068     0       stevel 		fatalperror(f, "ioctl I_PUSH ptem");
   1069     0       stevel 	if (ioctl(t, I_PUSH, "ldterm") == -1)
   1070     0       stevel 		fatalperror(f, "ioctl I_PUSH ldterm");
   1071     0       stevel 	if (ioctl(t, I_PUSH, "ttcompat") == -1)
   1072     0       stevel 		fatalperror(f, "ioctl I_PUSH ttcompat");
   1073     0       stevel 	/*
   1074     0       stevel 	 * POP the sockmod and push the rlmod module.
   1075     0       stevel 	 *
   1076     0       stevel 	 * Note that sockmod has to be removed since readstream assumes
   1077     0       stevel 	 * a "raw" TPI endpoint(e.g. it uses getmsg).
   1078     0       stevel 	 */
   1079     0       stevel 	if (removemod(f, "sockmod") < 0)
   1080     0       stevel 		fatalperror(f, "couldn't remove sockmod");
   1081     0       stevel 
   1082     0       stevel 	if (encr_flag) {
   1083     0       stevel 		if (ioctl(f, I_PUSH, "cryptmod") < 0)
   1084     0       stevel 		    fatalperror(f, "ioctl I_PUSH rlmod");
   1085     0       stevel 
   1086     0       stevel 	}
   1087     0       stevel 
   1088     0       stevel 	if (ioctl(f, I_PUSH, "rlmod") < 0)
   1089     0       stevel 		fatalperror(f, "ioctl I_PUSH rlmod");
   1090     0       stevel 
   1091     0       stevel 	if (encr_flag) {
   1092     0       stevel 		/*
   1093     0       stevel 		 * Make sure rlmod will pass unrecognized IOCTLs to cryptmod
   1094     0       stevel 		 */
   1095     0       stevel 		uchar_t passthru = 1;
   1096     0       stevel 		struct strioctl rlmodctl;
   1097     0       stevel 
   1098     0       stevel 		rlmodctl.ic_cmd = CRYPTPASSTHRU;
   1099     0       stevel 		rlmodctl.ic_timout = -1;
   1100     0       stevel 		rlmodctl.ic_len = sizeof (uchar_t);
   1101     0       stevel 		rlmodctl.ic_dp = (char *)&passthru;
   1102     0       stevel 
   1103     0       stevel 		if (ioctl(f, I_STR, &rlmodctl) < 0)
   1104     0       stevel 			fatal(f, "ioctl CRYPTPASSTHRU failed\n");
   1105     0       stevel 	}
   1106     0       stevel 
   1107     0       stevel 	/*
   1108     0       stevel 	 * readstream will do a getmsg till it receives
   1109     0       stevel 	 * M_PROTO type T_DATA_REQ from rloginmodopen()
   1110     0       stevel 	 * indicating all data on the stream prior to pushing rlmod has
   1111     0       stevel 	 * been drained at the stream head.
   1112     0       stevel 	 */
   1113     0       stevel 	if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0)
   1114     0       stevel 		fatalperror(f, "readstream failed");
   1115     0       stevel 	/*
   1116     0       stevel 	 * Make sure the pty doesn't modify the strings passed
   1117     0       stevel 	 * to login as part of the "rlogin protocol."  The login
   1118     0       stevel 	 * program should set these flags to apropriate values
   1119     0       stevel 	 * after it has read the strings.
   1120     0       stevel 	 */
   1121     0       stevel 	if (ioctl(t, TCGETS, &tp) == -1)
   1122     0       stevel 		fatalperror(f, "ioctl TCGETS");
   1123     0       stevel 	tp.c_lflag &= ~(ECHO|ICANON);
   1124     0       stevel 	tp.c_oflag &= ~(XTABS|OCRNL);
   1125     0       stevel 	tp.c_iflag &= ~(IGNPAR|ICRNL);
   1126     0       stevel 	if (ioctl(t, TCSETS, &tp) == -1)
   1127     0       stevel 		fatalperror(f, "ioctl TCSETS");
   1128     0       stevel 
   1129     0       stevel 	/*
   1130     0       stevel 	 * System V ptys allow the TIOC{SG}WINSZ ioctl to be
   1131     0       stevel 	 * issued on the master side of the pty.  Luckily, that's
   1132     0       stevel 	 * the only tty ioctl we need to do do, so we can close the
   1133     0       stevel 	 * slave side in the parent process after the fork.
   1134     0       stevel 	 */
   1135     0       stevel 	(void) ioctl(p, TIOCSWINSZ, &win);
   1136     0       stevel 
   1137     0       stevel 	pid = fork();
   1138     0       stevel 	if (pid < 0)
   1139     0       stevel 		fatalperror(f, "fork");
   1140     0       stevel 	if (pid == 0) {
   1141     0       stevel 		int tt;
   1142     0       stevel 		struct utmpx ut;
   1143     0       stevel 
   1144     0       stevel 		/* System V login expects a utmp entry to already be there */
   1145     0       stevel 		(void) memset(&ut, 0, sizeof (ut));
   1146     0       stevel 		(void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user));
   1147     0       stevel 		(void) strncpy(ut.ut_line, line, sizeof (ut.ut_line));
   1148     0       stevel 		ut.ut_pid = getpid();
   1149     0       stevel 		ut.ut_id[0] = 'r';
   1150     0       stevel 		ut.ut_id[1] = (char)SC_WILDC;
   1151     0       stevel 		ut.ut_id[2] = (char)SC_WILDC;
   1152     0       stevel 		ut.ut_id[3] = (char)SC_WILDC;
   1153     0       stevel 		ut.ut_type = LOGIN_PROCESS;
   1154     0       stevel 		ut.ut_exit.e_termination = 0;
   1155     0       stevel 		ut.ut_exit.e_exit = 0;
   1156     0       stevel 		(void) time(&ut.ut_tv.tv_sec);
   1157     0       stevel 		if (makeutx(&ut) == NULL)
   1158     0       stevel 			syslog(LOG_INFO, "in.rlogind:\tmakeutx failed");
   1159     0       stevel 
   1160     0       stevel 		/* controlling tty */
   1161     0       stevel 		if (setsid() == -1)
   1162     0       stevel 			fatalperror(f, "setsid");
   1163     0       stevel 		if ((tt = open(line, O_RDWR)) == -1)
   1164     0       stevel 			fatalperror(f, "could not re-open slave pty");
   1165     0       stevel 
   1166     0       stevel 		if (close(p) == -1)
   1167     0       stevel 			fatalperror(f, "error closing pty master");
   1168     0       stevel 		if (close(t) == -1)
   1169     0       stevel 			fatalperror(f, "error closing pty slave"
   1170     0       stevel 				    " opened before session established");
   1171     0       stevel 		/*
   1172     0       stevel 		 * If this fails we may or may not be able to output an
   1173     0       stevel 		 * error message.
   1174     0       stevel 		 */
   1175     0       stevel 		if (close(f) == -1)
   1176     0       stevel 			fatalperror(f, "error closing deamon stdout");
   1177     0       stevel 		if (dup2(tt, STDIN_FILENO) == -1 ||
   1178     0       stevel 		    dup2(tt, STDOUT_FILENO) == -1 ||
   1179     0       stevel 		    dup2(tt, STDERR_FILENO) == -1)
   1180     0       stevel 			exit(EXIT_FAILURE);	/* Disaster! No stderr! */
   1181     0       stevel 
   1182     0       stevel 		(void) close(tt);
   1183     0       stevel 
   1184     0       stevel 		if (use_auth == KRB5_RECVAUTH_V5 &&
   1185     0       stevel 		    krusername != NULL && strlen(krusername)) {
   1186     0       stevel 			(void) execl(LOGIN_PROGRAM, "login",
   1187     0       stevel 				    "-d", line,
   1188     0       stevel 				    "-r", hostname,
   1189     0       stevel 				    "-u", krusername, /* KRB5 principal name */
   1190     0       stevel 				    "-s", pam_prog_name,
   1191     0       stevel 				    "-t", term,	/* Remote Terminal */
   1192     0       stevel 				    "-U", rusername,	/* Remote User */
   1193     0       stevel 				    "-R", KRB5_REPOSITORY_NAME,
   1194     0       stevel 				    lusername,  /* local user */
   1195     0       stevel 				    NULL);
   1196     0       stevel 		} else {
   1197     0       stevel 			(void) execl(LOGIN_PROGRAM, "login",
   1198     0       stevel 				"-d", line,
   1199     0       stevel 				"-r", hostname,
   1200     0       stevel 				NULL);
   1201     0       stevel 		}
   1202     0       stevel 
   1203     0       stevel 		fatalperror(STDERR_FILENO, "/bin/login");
   1204     0       stevel 		/*NOTREACHED*/
   1205     0       stevel 	}
   1206     0       stevel 	(void) close(t);
   1207     0       stevel 	(void) ioctl(f, FIONBIO, &on);
   1208     0       stevel 	(void) ioctl(p, FIONBIO, &on);
   1209     0       stevel 
   1210     0       stevel 	/*
   1211     0       stevel 	 * Must ignore SIGTTOU, otherwise we'll stop
   1212     0       stevel 	 * when we try and set slave pty's window shape
   1213     0       stevel 	 * (our controlling tty is the master pty).
   1214     0       stevel 	 * Likewise, we don't want any of the tty-generated
   1215     0       stevel 	 * signals from chars passing through.
   1216     0       stevel 	 */
   1217     0       stevel 	(void) sigset(SIGTSTP, SIG_IGN);
   1218     0       stevel 	(void) sigset(SIGINT, SIG_IGN);
   1219     0       stevel 	(void) sigset(SIGQUIT, SIG_IGN);
   1220     0       stevel 	(void) sigset(SIGTTOU, SIG_IGN);
   1221     0       stevel 	(void) sigset(SIGTTIN, SIG_IGN);
   1222     0       stevel 	(void) sigset(SIGCHLD, cleanup);
   1223     0       stevel 	(void) setpgrp();
   1224     0       stevel 
   1225     0       stevel 	if (encr_flag) {
   1226     0       stevel 		krb5_data ivec, *ivptr;
   1227     0       stevel 		uint_t ivec_usage;
   1228     0       stevel 		stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT);
   1229     0       stevel 
   1230     0       stevel 		/*
   1231     0       stevel 		 * Configure the STREAMS crypto module.  For now,
   1232     0       stevel 		 * don't use any IV parameter.  KCMDV0.2 support
   1233     0       stevel 		 * will require the use of Initialization Vectors
   1234     0       stevel 		 * for both encrypt and decrypt modes.
   1235     0       stevel 		 */
   1236     0       stevel 		if (kcmd_protocol == KCMD_OLD_PROTOCOL) {
   1237     0       stevel 			if (session_key->enctype == ENCTYPE_DES_CBC_CRC) {
   1238     0       stevel 				/*
   1239     0       stevel 				 * This is gross but necessary for MIT compat.
   1240     0       stevel 				 */
   1241     0       stevel 				ivec.length = session_key->length;
   1242     0       stevel 				ivec.data = (char *)session_key->contents;
   1243     0       stevel 				ivec_usage = IVEC_REUSE;
   1244     0       stevel 				ivptr = &ivec;
   1245     0       stevel 			} else {
   1246     0       stevel 				ivptr = NULL; /* defaults to all 0's */
   1247     0       stevel 				ivec_usage = IVEC_NEVER;
   1248     0       stevel 			}
   1249     0       stevel 			/*
   1250     0       stevel 			 * configure both sides of stream together
   1251     0       stevel 			 * since they share the same IV.
   1252     0       stevel 			 * This is what makes the OLD KCMD protocol
   1253     0       stevel 			 * less secure than the newer one - Bad ivecs.
   1254     0       stevel 			 */
   1255     0       stevel 			if (configure_stream(f, session_key,
   1256     0       stevel 				CRYPT_ENCRYPT|CRYPT_DECRYPT,
   1257     0       stevel 				ivptr, ivec_usage) != 0)
   1258     0       stevel 				fatal(f, "Cannot initialize encryption -"
   1259     0       stevel 					" exiting.\n");
   1260     0       stevel 		} else {
   1261     0       stevel 			size_t blocksize;
   1262     0       stevel 			if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC ||
   1263     0       stevel 			    session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
   1264     0       stevel 				if (configure_stream(f, session_key,
   1265     0       stevel 					CRYPT_ENCRYPT|CRYPT_DECRYPT,
   1266     0       stevel 					NULL, IVEC_NEVER) != 0)
   1267     0       stevel 					fatal(f,
   1268     0       stevel 					"Cannot initialize encryption -"
   1269     0       stevel 					" exiting.\n");
   1270     0       stevel 				goto startcrypto;
   1271     0       stevel 			}
   1272     0       stevel 			if (krb5_c_block_size(krb_context,
   1273     0       stevel 					    session_key->enctype,
   1274     0       stevel 					    &blocksize)) {
   1275     0       stevel 				syslog(LOG_ERR, "Cannot determine blocksize "
   1276     0       stevel 				    "for encryption type %d",
   1277     0       stevel 				    session_key->enctype);
   1278     0       stevel 				fatal(f, "Cannot determine blocksize "
   1279     0       stevel 				    "for encryption - exiting.\n");
   1280     0       stevel 			}
   1281     0       stevel 			ivec.data = (char *)malloc(blocksize);
   1282     0       stevel 			ivec.length = blocksize;
   1283     0       stevel 			if (ivec.data == NULL)
   1284     0       stevel 				fatal(f, "memory error - exiting\n");
   1285     0       stevel 			/*
   1286     0       stevel 			 * Following MIT convention -
   1287     0       stevel 			 *   encrypt IV = 0x01 x blocksize
   1288     0       stevel 			 *   decrypt IV = 0x00 x blocksize
   1289     0       stevel 			 *   ivec_usage = IVEC_ONETIME
   1290     0       stevel 			 *
   1291     0       stevel 			 * configure_stream separately for encrypt and
   1292     0       stevel 			 * decrypt because there are 2 different IVs.
   1293     0       stevel 			 *
   1294     0       stevel 			 * AES uses 0's for IV.
   1295     0       stevel 			 */
   1296     0       stevel 			if (session_key->enctype ==
   1297     0       stevel 				ENCTYPE_AES128_CTS_HMAC_SHA1_96 ||
   1298     0       stevel 			    session_key->enctype ==
   1299     0       stevel 				ENCTYPE_AES256_CTS_HMAC_SHA1_96)
   1300     0       stevel 				(void) memset(ivec.data, 0x00, blocksize);
   1301     0       stevel 			else
   1302     0       stevel 				(void) memset(ivec.data, 0x01, blocksize);
   1303     0       stevel 			if (configure_stream(f, session_key, CRYPT_ENCRYPT,
   1304     0       stevel 				&ivec, IVEC_ONETIME) != 0)
   1305     0       stevel 				fatal(f, "Cannot initialize encryption -"
   1306     0       stevel 					" exiting.\n");
   1307     0       stevel 			(void) memset(ivec.data, 0x00, blocksize);
   1308     0       stevel 			if (configure_stream(f, session_key, CRYPT_DECRYPT,
   1309     0       stevel 				&ivec, IVEC_ONETIME) != 0)
   1310     0       stevel 				fatal(f, "Cannot initialize encryption -"
   1311     0       stevel 					" exiting.\n");
   1312     0       stevel 
   1313     0       stevel 			(void) free(ivec.data);
   1314     0       stevel 		}
   1315     0       stevel startcrypto:
   1316     0       stevel 		start_stream(f, CRYPT_ENCRYPT);
   1317     0       stevel 		start_stream(f, CRYPT_DECRYPT);
   1318     0       stevel 	}
   1319     0       stevel 	protocol(f, p, encr_flag);
   1320     0       stevel 	cleanup(0);
   1321     0       stevel 	/*NOTREACHED*/
   1322     0       stevel 
   1323     0       stevel badconversion:
   1324     0       stevel 	fatalperror(f, "address conversion");
   1325     0       stevel 	/*NOTREACHED*/
   1326     0       stevel }
   1327     0       stevel 
   1328     0       stevel /*
   1329     0       stevel  * rlogin "protocol" machine.
   1330     0       stevel  */
   1331     0       stevel static void
   1332     0       stevel protocol(int f, int p, int encr_flag)
   1333     0       stevel {
   1334     0       stevel 	struct	stat	buf;
   1335     0       stevel 	struct 	protocol_arg	rloginp;
   1336     0       stevel 	struct	strioctl	rloginmod;
   1337     0       stevel 	int	ptmfd;	/* fd of logindmux coneected to ptmx */
   1338     0       stevel 	int	netfd;	/* fd of logindmux connected to netf */
   1339     0       stevel 	static uchar_t	oobdata[] = {TIOCPKT_WINDOW};
   1340     0       stevel 
   1341     0       stevel 	/* indicate new rlogin */
   1342     0       stevel 	if (send_oob(f, oobdata, 1) < 0)
   1343     0       stevel 		fatalperror(f, "send_oob");
   1344     0       stevel 	/*
   1345     0       stevel 	 * We cannot send the SECURE_MSG until after the
   1346     0       stevel 	 * client has been signaled with the oobdata (above).
   1347     0       stevel 	 */
   1348     0       stevel 	if (encr_flag) {
   1349     0       stevel 		if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0)
   1350     0       stevel 			fatalperror(f, "Error writing SECURE message");
   1351     0       stevel 	}
   1352     0       stevel 
   1353     0       stevel 	/*
   1354     0       stevel 	 * Open logindmux driver and link netf and ptmx
   1355     0       stevel 	 * underneath logindmux.
   1356     0       stevel 	 */
   1357     0       stevel 	if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1)
   1358     0       stevel 		fatalperror(f, "open /dev/logindmux");
   1359     0       stevel 
   1360     0       stevel 	if ((netfd = open("/dev/logindmux", O_RDWR)) == -1)
   1361     0       stevel 		fatalperror(f, "open /dev/logindmux");
   1362     0       stevel 
   1363     0       stevel 	if (ioctl(ptmfd, I_LINK, p) < 0)
   1364     0       stevel 		fatal(f, "ioctl I_LINK of /dev/ptmx failed\n");
   1365     0       stevel 
   1366     0       stevel 	if (ioctl(netfd, I_LINK, f) < 0)
   1367     0       stevel 		fatal(f, "ioctl I_LINK of tcp connection failed\n");
   1368     0       stevel 
   1369     0       stevel 	/*
   1370     0       stevel 	 * Figure out the device number of the ptm's mux fd, and pass that
   1371     0       stevel 	 * to the net's mux.
   1372     0       stevel 	 */
   1373     0       stevel 	if (fstat(ptmfd, &buf) < 0)
   1374     0       stevel 		fatalperror(f, "cannot determine device number"
   1375     0       stevel 		    " of pty side of /dev/logindmux");
   1376     0       stevel 	rloginp.dev = buf.st_rdev;
   1377     0       stevel 	rloginp.flag = 0;
   1378     0       stevel 
   1379     0       stevel 	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
   1380     0       stevel 	rloginmod.ic_timout = -1;
   1381     0       stevel 	rloginmod.ic_len = sizeof (struct protocol_arg);
   1382     0       stevel 	rloginmod.ic_dp = (char *)&rloginp;
   1383     0       stevel 
   1384     0       stevel 	if (ioctl(netfd, I_STR, &rloginmod) < 0)
   1385     0       stevel 		fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n");
   1386     0       stevel 
   1387     0       stevel 	/*
   1388     0       stevel 	 * Figure out the device number of the net's mux fd, and pass that
   1389     0       stevel 	 * to the ptm's mux.
   1390     0       stevel 	 */
   1391     0       stevel 	if (fstat(netfd, &buf))
   1392     0       stevel 		fatalperror(f, "cannot determine device number"
   1393     0       stevel 		    " of network side of /dev/logindmux");
   1394     0       stevel 	rloginp.dev = buf.st_rdev;
   1395     0       stevel 	rloginp.flag = 1;
   1396     0       stevel 
   1397     0       stevel 	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
   1398     0       stevel 	rloginmod.ic_timout = -1;
   1399     0       stevel 	rloginmod.ic_len = sizeof (struct protocol_arg);
   1400     0       stevel 	rloginmod.ic_dp = (char *)&rloginp;
   1401     0       stevel 
   1402     0       stevel 	if (ioctl(ptmfd, I_STR, &rloginmod) < 0)
   1403     0       stevel 		fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n");
   1404     0       stevel 	/*
   1405     0       stevel 	 * Send an ioctl type RL_IOC_ENABLE to reenable the
   1406     0       stevel 	 * message queue and reinsert the data read from streamhead
   1407     0       stevel 	 * at the time of pushing rloginmod module.
   1408     0       stevel 	 * We need to send this ioctl even if no data was read earlier
   1409     0       stevel 	 * since we need to reenable the message queue of rloginmod module.
   1410     0       stevel 	 */
   1411     0       stevel 	rloginmod.ic_cmd = RL_IOC_ENABLE;
   1412     0       stevel 	rloginmod.ic_timout = -1;
   1413     0       stevel 	if (nsize) {
   1414     0       stevel 		rloginmod.ic_len = nsize;
   1415     0       stevel 		rloginmod.ic_dp = rlbuf;
   1416     0       stevel 	} else {
   1417     0       stevel 		rloginmod.ic_len = 0;
   1418     0       stevel 		rloginmod.ic_dp = NULL;
   1419     0       stevel 	}
   1420     0       stevel 
   1421     0       stevel 	if (ioctl(netfd, I_STR, &rloginmod) < 0)
   1422     0       stevel 		fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n");
   1423     0       stevel 
   1424     0       stevel 	/*
   1425     0       stevel 	 * User level daemon now pauses till the shell exits.
   1426     0       stevel 	 */
   1427     0       stevel 	(void) pause();
   1428     0       stevel }
   1429     0       stevel 
   1430     0       stevel /* This is a signal handler, hence the dummy argument */
   1431     0       stevel /*ARGSUSED*/
   1432     0       stevel static void
   1433     0       stevel cleanup(int dummy)
   1434     0       stevel {
   1435     0       stevel 	rmut();
   1436     0       stevel 	exit(EXIT_FAILURE);
   1437     0       stevel 	/*NOTREACHED*/
   1438     0       stevel }
   1439     0       stevel 
   1440     0       stevel /*
   1441     0       stevel  * TPI style replacement for socket send() primitive, so we don't require
   1442     0       stevel  * sockmod to be on the stream.
   1443     0       stevel  */
   1444     0       stevel static int
   1445     0       stevel send_oob(int fd, void *ptr, size_t count)
   1446     0       stevel {
   1447     0       stevel 	struct T_exdata_req exd_req;
   1448     0       stevel 	struct strbuf hdr, dat;
   1449     0       stevel 	int ret;
   1450     0       stevel 
   1451     0       stevel 	exd_req.PRIM_type = T_EXDATA_REQ;
   1452     0       stevel 	exd_req.MORE_flag = 0;
   1453     0       stevel 
   1454     0       stevel 	hdr.buf = (char *)&exd_req;
   1455     0       stevel 	hdr.len = sizeof (exd_req);
   1456     0       stevel 
   1457     0       stevel 	dat.buf = ptr;
   1458     0       stevel 	dat.len = count;
   1459     0       stevel 
   1460     0       stevel 	ret = putmsg(fd, &hdr, &dat, 0);
   1461     0       stevel 	if (ret == 0)
   1462     0       stevel 		ret = count;
   1463     0       stevel 	return (ret);
   1464     0       stevel }
   1465     0       stevel 
   1466     0       stevel static void
   1467     0       stevel fatal(int fd, const char *msg)
   1468     0       stevel {
   1469     0       stevel 	char *bufp;
   1470     0       stevel 	size_t len = strlen(msg) + 16;		/* enough for our wrapper */
   1471     0       stevel 
   1472     0       stevel 	bufp = alloca(len);
   1473     0       stevel 	/* ASCII 001 is the error indicator */
   1474     0       stevel 	len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg);
   1475     0       stevel 	(void) write(fd, bufp, len);
   1476     0       stevel 	exit(EXIT_FAILURE);
   1477     0       stevel 	/*NOTREACHED*/
   1478     0       stevel }
   1479     0       stevel 
   1480     0       stevel /*PRINTFLIKE2*/
   1481     0       stevel static void
   1482     0       stevel fatalperror(int fd, const char *msg)
   1483     0       stevel {
   1484     0       stevel 	char *bufp;
   1485     0       stevel 	const char *errstr;
   1486     0       stevel 	int save_errno = errno;
   1487     0       stevel 	size_t len = strlen(msg);
   1488     0       stevel 
   1489     0       stevel 	if ((errstr = strerror(save_errno))) {
   1490     0       stevel 		len += strlen(errstr) + 3;	/* 3 for ": " and \0 below */
   1491     0       stevel 		bufp = alloca(len);
   1492     0       stevel 		(void) snprintf(bufp, len, "%s: %s", msg, errstr);
   1493     0       stevel 	} else {
   1494     0       stevel 		const char fmt[] = "%s: Error %d";
   1495     0       stevel 
   1496     0       stevel 		/* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */
   1497     0       stevel 		len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3);
   1498     0       stevel 		bufp = alloca(len);
   1499     0       stevel 		(void) snprintf(bufp, len, fmt, msg, save_errno);
   1500     0       stevel 	}
   1501     0       stevel 	fatal(fd, bufp);
   1502     0       stevel 	/*NOTREACHED*/
   1503     0       stevel }
   1504     0       stevel 
   1505     0       stevel static void
   1506     0       stevel rmut(void)
   1507     0       stevel {
   1508     0       stevel 	pam_handle_t *pamh;
   1509     0       stevel 	struct utmpx *up;
   1510     0       stevel 	char user[sizeof (up->ut_user) + 1];
   1511     0       stevel 	char ttyn[sizeof (up->ut_line) + 1];
   1512     0       stevel 	char rhost[sizeof (up->ut_host) + 1];
   1513     0       stevel 
   1514     0       stevel 	/* while cleaning up dont allow disruption */
   1515     0       stevel 	(void) sigset(SIGCHLD, SIG_IGN);
   1516     0       stevel 
   1517     0       stevel 	setutxent();
   1518     0       stevel 	while (up = getutxent()) {
   1519     0       stevel 		if (up->ut_pid == pid) {
   1520     0       stevel 			if (up->ut_type == DEAD_PROCESS)
   1521     0       stevel 				break;		/* Cleaned up elsewhere. */
   1522     0       stevel 
   1523     0       stevel 			/*
   1524     0       stevel 			 * call pam_close_session if login changed
   1525     0       stevel 			 * the utmpx user entry from type LOGIN_PROCESS
   1526     0       stevel 			 * to type USER_PROCESS, which happens
   1527     0       stevel 			 * after pam_open_session is called.
   1528     0       stevel 			 */
   1529     0       stevel 			if (up->ut_type == USER_PROCESS) {
   1530     0       stevel 				(void) strlcpy(user, up->ut_user,
   1531     0       stevel 					    sizeof (user));
   1532     0       stevel 				(void) strlcpy(ttyn, up->ut_line,
   1533     0       stevel 					    sizeof (ttyn));
   1534     0       stevel 				(void) strlcpy(rhost, up->ut_host,
   1535     0       stevel 					    sizeof (rhost));
   1536     0       stevel 
   1537     0       stevel 				/*
   1538     0       stevel 				 * Use the same pam_prog_name that
   1539     0       stevel 				 * 'login' used.
   1540     0       stevel 				 */
   1541     0       stevel 				if ((pam_start(pam_prog_name, user,  NULL,
   1542     0       stevel 					    &pamh))
   1543     0       stevel 				    == PAM_SUCCESS) {
   1544     0       stevel 					(void) pam_set_item(pamh, PAM_TTY,
   1545     0       stevel 							    ttyn);
   1546     0       stevel 					(void) pam_set_item(pamh, PAM_RHOST,
   1547     0       stevel 							    rhost);
   1548     0       stevel 					(void) pam_close_session(pamh, 0);
   1549     0       stevel 					(void) pam_end(pamh, PAM_SUCCESS);
   1550     0       stevel 				}
   1551     0       stevel 			}
   1552     0       stevel 
   1553     0       stevel 			up->ut_type = DEAD_PROCESS;
   1554     0       stevel 			up->ut_exit.e_termination = WTERMSIG(0);
   1555     0       stevel 			up->ut_exit.e_exit = WEXITSTATUS(0);
   1556     0       stevel 			(void) time(&up->ut_tv.tv_sec);
   1557     0       stevel 
   1558     0       stevel 			if (modutx(up) == NULL) {
   1559     0       stevel 				/*
   1560     0       stevel 				 * Since modutx failed we'll
   1561     0       stevel 				 * write out the new entry
   1562     0       stevel 				 * ourselves.
   1563     0       stevel 				 */
   1564     0       stevel 				(void) pututxline(up);
   1565     0       stevel 				updwtmpx("wtmpx", up);
   1566     0       stevel 			}
   1567     0       stevel 			break;
   1568     0       stevel 		}
   1569     0       stevel 	}
   1570     0       stevel 
   1571     0       stevel 	endutxent();
   1572     0       stevel 
   1573     0       stevel 	(void) sigset(SIGCHLD, cleanup);
   1574     0       stevel }
   1575     0       stevel 
   1576     0       stevel static int
   1577     0       stevel readstream(int fd, char *buf, int size)
   1578     0       stevel {
   1579     0       stevel 	struct strbuf ctlbuf, datbuf;
   1580     0       stevel 	union T_primitives tpi;
   1581     0       stevel 	int	nbytes = 0;
   1582     0       stevel 	int	ret = 0;
   1583     0       stevel 	int	flags = 0;
   1584     0       stevel 	int	bufsize = size;
   1585     0       stevel 	int	nread;
   1586     0       stevel 
   1587     0       stevel 	(void) memset(&ctlbuf, 0, sizeof (ctlbuf));
   1588     0       stevel 	(void) memset(&datbuf, 0, sizeof (datbuf));
   1589     0       stevel 
   1590     0       stevel 	ctlbuf.buf = (char *)&tpi;
   1591     0       stevel 	ctlbuf.maxlen = sizeof (tpi);
   1592     0       stevel 	datbuf.buf = buf;
   1593     0       stevel 	datbuf.maxlen = size;
   1594     0       stevel 
   1595     0       stevel 	for (;;) {
   1596     0       stevel 		if (ioctl(fd, I_NREAD, &nread) < 0) {
   1597     0       stevel 			syslog(LOG_ERR, "I_NREAD returned error %m");
   1598     0       stevel 			return (-1);
   1599     0       stevel 		}
   1600     0       stevel 		if (nread + nbytes > bufsize) {
   1601     0       stevel 			buf = (char *)realloc(buf, (unsigned)(bufsize + nread));
   1602     0       stevel 			if (buf == NULL) {
   1603     0       stevel 				syslog(LOG_WARNING,
   1604     0       stevel 				    "buffer allocation failed\n");
   1605     0       stevel 				return (-1);
   1606     0       stevel 			}
   1607     0       stevel 			bufsize += nread;
   1608     0       stevel 			rlbuf = buf;
   1609     0       stevel 			datbuf.buf = buf + nbytes;
   1610     0       stevel 		}
   1611     0       stevel 		datbuf.maxlen = bufsize - nbytes;
   1612     0       stevel 		ret = getmsg(fd, &ctlbuf, &datbuf, &flags);
   1613     0       stevel 		if (ret < 0) {
   1614     0       stevel 			syslog(LOG_ERR, "getmsg failed error %m");
   1615     0       stevel 			return (-1);
   1616     0       stevel 		}
   1617     0       stevel 		if ((ctlbuf.len == 0) && (datbuf.len == 0)) {
   1618     0       stevel 			/*
   1619     0       stevel 			 * getmsg() returned no data - this indicates
   1620     0       stevel 			 * that the connection is closing down.
   1621     0       stevel 			 */
   1622     0       stevel 			cleanup(0);
   1623     0       stevel 		}
   1624     0       stevel 		if (ctlbuf.len <= 0) {
   1625     0       stevel 			nbytes += datbuf.len;
   1626     0       stevel 			datbuf.buf += datbuf.len;
   1627     0       stevel 			continue;
   1628     0       stevel 		}
   1629     0       stevel 		if (tpi.type == T_DATA_REQ) {
   1630     0       stevel 			return (nbytes);
   1631     0       stevel 		}
   1632     0       stevel 		if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND))
   1633     0       stevel 			cleanup(0);
   1634     0       stevel 	}
   1635     0       stevel }
   1636     0       stevel 
   1637     0       stevel /*
   1638     0       stevel  * Verify that the named module is at the top of the stream
   1639     0       stevel  * and then pop it off.
   1640     0       stevel  */
   1641     0       stevel static int
   1642     0       stevel removemod(int f, char *modname)
   1643     0       stevel {
   1644     0       stevel 	char topmodname[BUFSIZ];
   1645     0       stevel 
   1646     0       stevel 	if (ioctl(f, I_LOOK, topmodname) < 0)
   1647     0       stevel 		return (-1);
   1648     0       stevel 	if (strcmp(modname, topmodname) != 0) {
   1649     0       stevel 		errno = ENXIO;
   1650     0       stevel 		return (-1);
   1651     0       stevel 	}
   1652     0       stevel 	if (ioctl(f, I_POP, 0) < 0)
   1653     0       stevel 		return (-1);
   1654     0       stevel 	return (0);
   1655     0       stevel }
   1656