Home | History | Annotate | Line # | Download | only in rlogind
rlogind.c revision 1.1
      1 /*-
      2  * Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 static char sccsid[] = "@(#)rlogind.c	5.53 (Berkeley) 4/20/91";
     42 #endif /* not lint */
     43 
     44 #ifdef KERBEROS
     45 /* From:
     46  *	$Source: /tank/opengrok/rsync2/NetBSD/src/libexec/rlogind/rlogind.c,v $
     47  *	$Header: /tank/opengrok/rsync2/NetBSD/src/libexec/rlogind/rlogind.c,v 1.1 1993/03/21 09:45:37 cgd Exp $
     48  */
     49 #endif
     50 
     51 /*
     52  * remote login server:
     53  *	\0
     54  *	remuser\0
     55  *	locuser\0
     56  *	terminal_type/speed\0
     57  *	data
     58  */
     59 
     60 #define	FD_SETSIZE	16		/* don't need many bits for select */
     61 #include <sys/param.h>
     62 #include <sys/stat.h>
     63 #include <sys/ioctl.h>
     64 #include <signal.h>
     65 #include <termios.h>
     66 
     67 #include <sys/socket.h>
     68 #include <netinet/in.h>
     69 #include <netinet/in_systm.h>
     70 #include <netinet/ip.h>
     71 #include <arpa/inet.h>
     72 #include <netdb.h>
     73 
     74 #include <pwd.h>
     75 #include <syslog.h>
     76 #include <errno.h>
     77 #include <stdio.h>
     78 #include <unistd.h>
     79 #include <stdlib.h>
     80 #include <string.h>
     81 #include "pathnames.h"
     82 
     83 #ifndef TIOCPKT_WINDOW
     84 #define TIOCPKT_WINDOW 0x80
     85 #endif
     86 
     87 #ifdef	KERBEROS
     88 #include <kerberosIV/des.h>
     89 #include <kerberosIV/krb.h>
     90 #define	SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
     91 
     92 AUTH_DAT	*kdata;
     93 KTEXT		ticket;
     94 u_char		auth_buf[sizeof(AUTH_DAT)];
     95 u_char		tick_buf[sizeof(KTEXT_ST)];
     96 Key_schedule	schedule;
     97 int		doencrypt, retval, use_kerberos, vacuous;
     98 
     99 #define		ARGSTR			"alnkvx"
    100 #else
    101 #define		ARGSTR			"aln"
    102 #endif	/* KERBEROS */
    103 
    104 char	*env[2];
    105 #define	NMAX 30
    106 char	lusername[NMAX+1], rusername[NMAX+1];
    107 static	char term[64] = "TERM=";
    108 #define	ENVSIZE	(sizeof("TERM=")-1)	/* skip null for concatenation */
    109 int	keepalive = 1;
    110 int	check_all = 0;
    111 
    112 struct	passwd *pwd;
    113 
    114 main(argc, argv)
    115 	int argc;
    116 	char **argv;
    117 {
    118 	extern int opterr, optind;
    119 	extern int _check_rhosts_file;
    120 	int ch;
    121 	int on = 1, fromlen;
    122 	struct sockaddr_in from;
    123 
    124 	openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
    125 
    126 	opterr = 0;
    127 	while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
    128 		switch (ch) {
    129 		case 'a':
    130 			check_all = 1;
    131 			break;
    132 		case 'l':
    133 			_check_rhosts_file = 0;
    134 			break;
    135 		case 'n':
    136 			keepalive = 0;
    137 			break;
    138 #ifdef KERBEROS
    139 		case 'k':
    140 			use_kerberos = 1;
    141 			break;
    142 		case 'v':
    143 			vacuous = 1;
    144 			break;
    145 #ifdef CRYPT
    146 		case 'x':
    147 			doencrypt = 1;
    148 			break;
    149 #endif
    150 #endif
    151 		case '?':
    152 		default:
    153 			usage();
    154 			break;
    155 		}
    156 	argc -= optind;
    157 	argv += optind;
    158 
    159 #ifdef	KERBEROS
    160 	if (use_kerberos && vacuous) {
    161 		usage();
    162 		fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
    163 	}
    164 #endif
    165 	fromlen = sizeof (from);
    166 	if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
    167 		syslog(LOG_ERR,"Can't get peer name of remote host: %m");
    168 		fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
    169 	}
    170 	if (keepalive &&
    171 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
    172 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
    173 	on = IPTOS_LOWDELAY;
    174 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
    175 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
    176 	doit(0, &from);
    177 }
    178 
    179 int	child;
    180 void	cleanup();
    181 int	netf;
    182 char	line[MAXPATHLEN];
    183 int	confirmed;
    184 extern	char	*inet_ntoa();
    185 
    186 struct winsize win = { 0, 0, 0, 0 };
    187 
    188 
    189 doit(f, fromp)
    190 	int f;
    191 	struct sockaddr_in *fromp;
    192 {
    193 	int i, master, pid, on = 1;
    194 	int authenticated = 0, hostok = 0;
    195 	register struct hostent *hp;
    196 	char remotehost[2 * MAXHOSTNAMELEN + 1];
    197 	struct hostent hostent;
    198 	char c;
    199 
    200 	alarm(60);
    201 	read(f, &c, 1);
    202 
    203 	if (c != 0)
    204 		exit(1);
    205 #ifdef	KERBEROS
    206 	if (vacuous)
    207 		fatal(f, "Remote host requires Kerberos authentication", 0);
    208 #endif
    209 
    210 	alarm(0);
    211 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
    212 	hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
    213 		fromp->sin_family);
    214 	if (hp == 0) {
    215 		/*
    216 		 * Only the name is used below.
    217 		 */
    218 		hp = &hostent;
    219 		hp->h_name = inet_ntoa(fromp->sin_addr);
    220 		hostok++;
    221 	} else if (check_all || local_domain(hp->h_name)) {
    222 		/*
    223 		 * If name returned by gethostbyaddr is in our domain,
    224 		 * attempt to verify that we haven't been fooled by someone
    225 		 * in a remote net; look up the name and check that this
    226 		 * address corresponds to the name.
    227 		 */
    228 		strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
    229 		remotehost[sizeof(remotehost) - 1] = 0;
    230 		hp = gethostbyname(remotehost);
    231 		if (hp)
    232 		    for (; hp->h_addr_list[0]; hp->h_addr_list++)
    233 			if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr,
    234 			    sizeof(fromp->sin_addr))) {
    235 				hostok++;
    236 				break;
    237 			}
    238 	} else
    239 		hostok++;
    240 
    241 #ifdef	KERBEROS
    242 	if (use_kerberos) {
    243 		if (!hostok)
    244 			fatal(f, "rlogind: Host address mismatch.", 0);
    245 		retval = do_krb_login(hp->h_name, fromp);
    246 		if (retval == 0)
    247 			authenticated++;
    248 		else if (retval > 0)
    249 			fatal(f, krb_err_txt[retval], 0);
    250 		write(f, &c, 1);
    251 		confirmed = 1;		/* we sent the null! */
    252 	} else
    253 #endif
    254 	{
    255 	    if (fromp->sin_family != AF_INET ||
    256 	        fromp->sin_port >= IPPORT_RESERVED ||
    257 	        fromp->sin_port < IPPORT_RESERVED/2) {
    258 		    syslog(LOG_NOTICE, "Connection from %s on illegal port",
    259 			    inet_ntoa(fromp->sin_addr));
    260 		    fatal(f, "Permission denied", 0);
    261 	    }
    262 #ifdef IP_OPTIONS
    263 	    {
    264 	    u_char optbuf[BUFSIZ/3], *cp;
    265 	    char lbuf[BUFSIZ], *lp;
    266 	    int optsize = sizeof(optbuf), ipproto;
    267 	    struct protoent *ip;
    268 
    269 	    if ((ip = getprotobyname("ip")) != NULL)
    270 		    ipproto = ip->p_proto;
    271 	    else
    272 		    ipproto = IPPROTO_IP;
    273 	    if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
    274 		&optsize) == 0 && optsize != 0) {
    275 		    lp = lbuf;
    276 		    for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
    277 			    sprintf(lp, " %2.2x", *cp);
    278 		    syslog(LOG_NOTICE,
    279 			"Connection received using IP options (ignored):%s",
    280 			lbuf);
    281 		    if (setsockopt(0, ipproto, IP_OPTIONS,
    282 			(char *)NULL, optsize) != 0) {
    283 			    syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
    284 			    exit(1);
    285 		    }
    286 	        }
    287 	    }
    288 #endif
    289 	    if (do_rlogin(hp->h_name) == 0 && hostok)
    290 		    authenticated++;
    291 	}
    292 	if (confirmed == 0) {
    293 		write(f, "", 1);
    294 		confirmed = 1;		/* we sent the null! */
    295 	}
    296 #ifdef	KERBEROS
    297 #ifdef	CRYPT
    298 	if (doencrypt)
    299 		(void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE));
    300 #endif
    301 	if (use_kerberos == 0)
    302 #endif
    303 	   if (!authenticated && !hostok)
    304 		write(f, "rlogind: Host address mismatch.\r\n",
    305 		    sizeof("rlogind: Host address mismatch.\r\n") - 1);
    306 
    307 	netf = f;
    308 
    309 	pid = forkpty(&master, line, NULL, &win);
    310 	if (pid < 0) {
    311 		if (errno == ENOENT)
    312 			fatal(f, "Out of ptys", 0);
    313 		else
    314 			fatal(f, "Forkpty", 1);
    315 	}
    316 	if (pid == 0) {
    317 		if (f > 2)	/* f should always be 0, but... */
    318 			(void) close(f);
    319 		setup_term(0);
    320 		if (authenticated) {
    321 #ifdef	KERBEROS
    322 			if (use_kerberos && (pwd->pw_uid == 0))
    323 				syslog(LOG_INFO|LOG_AUTH,
    324 				    "ROOT Kerberos login from %s.%s@%s on %s\n",
    325 				    kdata->pname, kdata->pinst, kdata->prealm,
    326 				    hp->h_name);
    327 #endif
    328 
    329 			execl(_PATH_LOGIN, "login", "-p",
    330 			    "-h", hp->h_name, "-f", lusername, 0);
    331 		} else
    332 			execl(_PATH_LOGIN, "login", "-p",
    333 			    "-h", hp->h_name, lusername, 0);
    334 		fatal(STDERR_FILENO, _PATH_LOGIN, 1);
    335 		/*NOTREACHED*/
    336 	}
    337 #ifdef	CRYPT
    338 #ifdef	KERBEROS
    339 	/*
    340 	 * If encrypted, don't turn on NBIO or the des read/write
    341 	 * routines will croak.
    342 	 */
    343 
    344 	if (!doencrypt)
    345 #endif
    346 #endif
    347 		ioctl(f, FIONBIO, &on);
    348 	ioctl(master, FIONBIO, &on);
    349 	ioctl(master, TIOCPKT, &on);
    350 	signal(SIGCHLD, cleanup);
    351 	protocol(f, master);
    352 	signal(SIGCHLD, SIG_IGN);
    353 	cleanup();
    354 }
    355 
    356 char	magic[2] = { 0377, 0377 };
    357 char	oobdata[] = {TIOCPKT_WINDOW};
    358 
    359 /*
    360  * Handle a "control" request (signaled by magic being present)
    361  * in the data stream.  For now, we are only willing to handle
    362  * window size changes.
    363  */
    364 control(pty, cp, n)
    365 	int pty;
    366 	char *cp;
    367 	int n;
    368 {
    369 	struct winsize w;
    370 
    371 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
    372 		return (0);
    373 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
    374 	bcopy(cp+4, (char *)&w, sizeof(w));
    375 	w.ws_row = ntohs(w.ws_row);
    376 	w.ws_col = ntohs(w.ws_col);
    377 	w.ws_xpixel = ntohs(w.ws_xpixel);
    378 	w.ws_ypixel = ntohs(w.ws_ypixel);
    379 	(void)ioctl(pty, TIOCSWINSZ, &w);
    380 	return (4+sizeof (w));
    381 }
    382 
    383 /*
    384  * rlogin "protocol" machine.
    385  */
    386 protocol(f, p)
    387 	register int f, p;
    388 {
    389 	char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
    390 	register pcc = 0, fcc = 0;
    391 	int cc, nfd, n;
    392 	char cntl;
    393 
    394 	/*
    395 	 * Must ignore SIGTTOU, otherwise we'll stop
    396 	 * when we try and set slave pty's window shape
    397 	 * (our controlling tty is the master pty).
    398 	 */
    399 	(void) signal(SIGTTOU, SIG_IGN);
    400 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
    401 	if (f > p)
    402 		nfd = f + 1;
    403 	else
    404 		nfd = p + 1;
    405 	if (nfd > FD_SETSIZE) {
    406 		syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
    407 		fatal(f, "internal error (select mask too small)", 0);
    408 	}
    409 	for (;;) {
    410 		fd_set ibits, obits, ebits, *omask;
    411 
    412 		FD_ZERO(&ebits);
    413 		FD_ZERO(&ibits);
    414 		FD_ZERO(&obits);
    415 		omask = (fd_set *)NULL;
    416 		if (fcc) {
    417 			FD_SET(p, &obits);
    418 			omask = &obits;
    419 		} else
    420 			FD_SET(f, &ibits);
    421 		if (pcc >= 0)
    422 			if (pcc) {
    423 				FD_SET(f, &obits);
    424 				omask = &obits;
    425 			} else
    426 				FD_SET(p, &ibits);
    427 		FD_SET(p, &ebits);
    428 		if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
    429 			if (errno == EINTR)
    430 				continue;
    431 			fatal(f, "select", 1);
    432 		}
    433 		if (n == 0) {
    434 			/* shouldn't happen... */
    435 			sleep(5);
    436 			continue;
    437 		}
    438 #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
    439 		if (FD_ISSET(p, &ebits)) {
    440 			cc = read(p, &cntl, 1);
    441 			if (cc == 1 && pkcontrol(cntl)) {
    442 				cntl |= oobdata[0];
    443 				send(f, &cntl, 1, MSG_OOB);
    444 				if (cntl & TIOCPKT_FLUSHWRITE) {
    445 					pcc = 0;
    446 					FD_CLR(p, &ibits);
    447 				}
    448 			}
    449 		}
    450 		if (FD_ISSET(f, &ibits)) {
    451 #ifdef	CRYPT
    452 #ifdef	KERBEROS
    453 			if (doencrypt)
    454 				fcc = des_read(f, fibuf, sizeof(fibuf));
    455 			else
    456 #endif
    457 #endif
    458 				fcc = read(f, fibuf, sizeof(fibuf));
    459 			if (fcc < 0 && errno == EWOULDBLOCK)
    460 				fcc = 0;
    461 			else {
    462 				register char *cp;
    463 				int left, n;
    464 
    465 				if (fcc <= 0)
    466 					break;
    467 				fbp = fibuf;
    468 
    469 			top:
    470 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
    471 					if (cp[0] == magic[0] &&
    472 					    cp[1] == magic[1]) {
    473 						left = fcc - (cp-fibuf);
    474 						n = control(p, cp, left);
    475 						if (n) {
    476 							left -= n;
    477 							if (left > 0)
    478 								bcopy(cp+n, cp, left);
    479 							fcc -= n;
    480 							goto top; /* n^2 */
    481 						}
    482 					}
    483 				FD_SET(p, &obits);		/* try write */
    484 			}
    485 		}
    486 
    487 		if (FD_ISSET(p, &obits) && fcc > 0) {
    488 			cc = write(p, fbp, fcc);
    489 			if (cc > 0) {
    490 				fcc -= cc;
    491 				fbp += cc;
    492 			}
    493 		}
    494 
    495 		if (FD_ISSET(p, &ibits)) {
    496 			pcc = read(p, pibuf, sizeof (pibuf));
    497 			pbp = pibuf;
    498 			if (pcc < 0 && errno == EWOULDBLOCK)
    499 				pcc = 0;
    500 			else if (pcc <= 0)
    501 				break;
    502 			else if (pibuf[0] == 0) {
    503 				pbp++, pcc--;
    504 #ifdef	CRYPT
    505 #ifdef	KERBEROS
    506 				if (!doencrypt)
    507 #endif
    508 #endif
    509 					FD_SET(f, &obits);	/* try write */
    510 			} else {
    511 				if (pkcontrol(pibuf[0])) {
    512 					pibuf[0] |= oobdata[0];
    513 					send(f, &pibuf[0], 1, MSG_OOB);
    514 				}
    515 				pcc = 0;
    516 			}
    517 		}
    518 		if ((FD_ISSET(f, &obits)) && pcc > 0) {
    519 #ifdef	CRYPT
    520 #ifdef	KERBEROS
    521 			if (doencrypt)
    522 				cc = des_write(f, pbp, pcc);
    523 			else
    524 #endif
    525 #endif
    526 				cc = write(f, pbp, pcc);
    527 			if (cc < 0 && errno == EWOULDBLOCK) {
    528 				/*
    529 				 * This happens when we try write after read
    530 				 * from p, but some old kernels balk at large
    531 				 * writes even when select returns true.
    532 				 */
    533 				if (!FD_ISSET(p, &ibits))
    534 					sleep(5);
    535 				continue;
    536 			}
    537 			if (cc > 0) {
    538 				pcc -= cc;
    539 				pbp += cc;
    540 			}
    541 		}
    542 	}
    543 }
    544 
    545 void
    546 cleanup()
    547 {
    548 	char *p;
    549 
    550 	p = line + sizeof(_PATH_DEV) - 1;
    551 	if (logout(p))
    552 		logwtmp(p, "", "");
    553 	(void)chmod(line, 0666);
    554 	(void)chown(line, 0, 0);
    555 	*p = 'p';
    556 	(void)chmod(line, 0666);
    557 	(void)chown(line, 0, 0);
    558 	shutdown(netf, 2);
    559 	exit(1);
    560 }
    561 
    562 fatal(f, msg, syserr)
    563 	int f, syserr;
    564 	char *msg;
    565 {
    566 	int len;
    567 	char buf[BUFSIZ], *bp = buf;
    568 
    569 	/*
    570 	 * Prepend binary one to message if we haven't sent
    571 	 * the magic null as confirmation.
    572 	 */
    573 	if (!confirmed)
    574 		*bp++ = '\01';		/* error indicator */
    575 	if (syserr)
    576 		len = sprintf(bp, "rlogind: %s: %s.\r\n",
    577 		    msg, strerror(errno));
    578 	else
    579 		len = sprintf(bp, "rlogind: %s.\r\n", msg);
    580 	(void) write(f, buf, bp + len - buf);
    581 	exit(1);
    582 }
    583 
    584 do_rlogin(host)
    585 	char *host;
    586 {
    587 	getstr(rusername, sizeof(rusername), "remuser too long");
    588 	getstr(lusername, sizeof(lusername), "locuser too long");
    589 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
    590 
    591 	pwd = getpwnam(lusername);
    592 	if (pwd == NULL)
    593 		return(-1);
    594 	if (pwd->pw_uid == 0)
    595 		return(-1);
    596 	return(ruserok(host, 0, rusername, lusername));
    597 }
    598 
    599 
    600 getstr(buf, cnt, errmsg)
    601 	char *buf;
    602 	int cnt;
    603 	char *errmsg;
    604 {
    605 	char c;
    606 
    607 	do {
    608 		if (read(0, &c, 1) != 1)
    609 			exit(1);
    610 		if (--cnt < 0)
    611 			fatal(STDOUT_FILENO, errmsg, 0);
    612 		*buf++ = c;
    613 	} while (c != 0);
    614 }
    615 
    616 extern	char **environ;
    617 
    618 setup_term(fd)
    619 	int fd;
    620 {
    621 	register char *cp = index(term+ENVSIZE, '/');
    622 	char *speed;
    623 	struct termios tt;
    624 
    625 #ifndef notyet
    626 	tcgetattr(fd, &tt);
    627 	if (cp) {
    628 		*cp++ = '\0';
    629 		speed = cp;
    630 		cp = index(speed, '/');
    631 		if (cp)
    632 			*cp++ = '\0';
    633 		cfsetspeed(&tt, atoi(speed));
    634 	}
    635 
    636 	tt.c_iflag = TTYDEF_IFLAG;
    637 	tt.c_oflag = TTYDEF_OFLAG;
    638 	tt.c_lflag = TTYDEF_LFLAG;
    639 	tcsetattr(fd, TCSAFLUSH, &tt);
    640 #else
    641 	if (cp) {
    642 		*cp++ = '\0';
    643 		speed = cp;
    644 		cp = index(speed, '/');
    645 		if (cp)
    646 			*cp++ = '\0';
    647 		tcgetattr(fd, &tt);
    648 		cfsetspeed(&tt, atoi(speed));
    649 		tcsetattr(fd, TCSAFLUSH, &tt);
    650 	}
    651 #endif
    652 
    653 	env[0] = term;
    654 	env[1] = 0;
    655 	environ = env;
    656 }
    657 
    658 #ifdef	KERBEROS
    659 #define	VERSION_SIZE	9
    660 
    661 /*
    662  * Do the remote kerberos login to the named host with the
    663  * given inet address
    664  *
    665  * Return 0 on valid authorization
    666  * Return -1 on valid authentication, no authorization
    667  * Return >0 for error conditions
    668  */
    669 do_krb_login(host, dest)
    670 	char *host;
    671 	struct sockaddr_in *dest;
    672 {
    673 	int rc;
    674 	char instance[INST_SZ], version[VERSION_SIZE];
    675 	long authopts = 0L;	/* !mutual */
    676 	struct sockaddr_in faddr;
    677 
    678 	kdata = (AUTH_DAT *) auth_buf;
    679 	ticket = (KTEXT) tick_buf;
    680 
    681 	instance[0] = '*';
    682 	instance[1] = '\0';
    683 
    684 #ifdef	CRYPT
    685 	if (doencrypt) {
    686 		rc = sizeof(faddr);
    687 		if (getsockname(0, (struct sockaddr *)&faddr, &rc))
    688 			return(-1);
    689 		authopts = KOPT_DO_MUTUAL;
    690 		rc = krb_recvauth(
    691 			authopts, 0,
    692 			ticket, "rcmd",
    693 			instance, dest, &faddr,
    694 			kdata, "", schedule, version);
    695 		 des_set_key(kdata->session, schedule);
    696 
    697 	} else
    698 #endif
    699 		rc = krb_recvauth(
    700 			authopts, 0,
    701 			ticket, "rcmd",
    702 			instance, dest, (struct sockaddr_in *) 0,
    703 			kdata, "", (bit_64 *) 0, version);
    704 
    705 	if (rc != KSUCCESS)
    706 		return(rc);
    707 
    708 	getstr(lusername, sizeof(lusername), "locuser");
    709 	/* get the "cmd" in the rcmd protocol */
    710 	getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
    711 
    712 	pwd = getpwnam(lusername);
    713 	if (pwd == NULL)
    714 		return(-1);
    715 
    716 	/* returns nonzero for no access */
    717 	if (kuserok(kdata,lusername) != 0)
    718 		return(-1);
    719 
    720 	return(0);
    721 
    722 }
    723 #endif /* KERBEROS */
    724 
    725 usage()
    726 {
    727 #ifdef KERBEROS
    728 	syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
    729 #else
    730 	syslog(LOG_ERR, "usage: rlogind [-aln]");
    731 #endif
    732 }
    733 
    734 /*
    735  * Check whether host h is in our local domain,
    736  * defined as sharing the last two components of the domain part,
    737  * or the entire domain part if the local domain has only one component.
    738  * If either name is unqualified (contains no '.'),
    739  * assume that the host is local, as it will be
    740  * interpreted as such.
    741  */
    742 local_domain(h)
    743 	char *h;
    744 {
    745 	char localhost[MAXHOSTNAMELEN];
    746 	char *p1, *p2, *topdomain();
    747 
    748 	localhost[0] = 0;
    749 	(void) gethostname(localhost, sizeof(localhost));
    750 	p1 = topdomain(localhost);
    751 	p2 = topdomain(h);
    752 	if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
    753 		return(1);
    754 	return(0);
    755 }
    756 
    757 char *
    758 topdomain(h)
    759 	char *h;
    760 {
    761 	register char *p;
    762 	char *maybe = NULL;
    763 	int dots = 0;
    764 
    765 	for (p = h + strlen(h); p >= h; p--) {
    766 		if (*p == '.') {
    767 			if (++dots == 2)
    768 				return (p);
    769 			maybe = p;
    770 		}
    771 	}
    772 	return (maybe);
    773 }
    774