xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 36319)
121174Sdist /*
235441Sbostic  * Copyright (c) 1983 The Regents of the University of California.
335441Sbostic  * All rights reserved.
435441Sbostic  *
535441Sbostic  * Redistribution and use in source and binary forms are permitted
635441Sbostic  * provided that the above copyright notice and this paragraph are
735441Sbostic  * duplicated in all such forms and that any documentation,
835441Sbostic  * advertising materials, and other materials related to such
935441Sbostic  * distribution and use acknowledge that the software was developed
1035441Sbostic  * by the University of California, Berkeley.  The name of the
1135441Sbostic  * University may not be used to endorse or promote products derived
1235441Sbostic  * from this software without specific prior written permission.
1335441Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435441Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535441Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621174Sdist  */
1721174Sdist 
186446Swnj #ifndef lint
1921174Sdist char copyright[] =
2035441Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
2121174Sdist  All rights reserved.\n";
2235441Sbostic #endif /* not lint */
236446Swnj 
2421174Sdist #ifndef lint
25*36319Sbostic static char sccsid[] = "@(#)rlogind.c	5.18 (Berkeley) 12/08/88";
2635441Sbostic #endif /* not lint */
2721174Sdist 
2816369Skarels /*
2916369Skarels  * remote login server:
3016369Skarels  *	remuser\0
3116369Skarels  *	locuser\0
3218357Ssam  *	terminal info\0
3316369Skarels  *	data
3416369Skarels  */
3516369Skarels 
366446Swnj #include <stdio.h>
376446Swnj #include <sys/types.h>
386446Swnj #include <sys/stat.h>
396446Swnj #include <sys/socket.h>
4013554Ssam #include <sys/wait.h>
4118357Ssam #include <sys/file.h>
429208Ssam 
439208Ssam #include <netinet/in.h>
449208Ssam 
456446Swnj #include <errno.h>
466446Swnj #include <pwd.h>
476446Swnj #include <signal.h>
486446Swnj #include <sgtty.h>
496446Swnj #include <stdio.h>
508380Ssam #include <netdb.h>
5117187Sralph #include <syslog.h>
5218357Ssam #include <strings.h>
536446Swnj 
5424723Smckusick # ifndef TIOCPKT_WINDOW
5524723Smckusick # define TIOCPKT_WINDOW 0x80
5624723Smckusick # endif TIOCPKT_WINDOW
5724723Smckusick 
5834424Sbostic extern	int errno;
5910417Ssam int	reapchild();
606446Swnj struct	passwd *getpwnam();
6124723Smckusick char	*malloc();
6216369Skarels 
6334424Sbostic /*ARGSUSED*/
646446Swnj main(argc, argv)
656446Swnj 	int argc;
666446Swnj 	char **argv;
676446Swnj {
68*36319Sbostic 	extern int opterr, optind, _check_rhosts_file;
69*36319Sbostic 	int ch;
7034424Sbostic 	int on = 1, fromlen;
716446Swnj 	struct sockaddr_in from;
726446Swnj 
7324855Seric 	openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
74*36319Sbostic 
75*36319Sbostic 	opterr = 0;
76*36319Sbostic 	while ((ch = getopt(argc, argv, "l")) != EOF)
77*36319Sbostic 		switch((char)ch) {
78*36319Sbostic 		case 'l':
79*36319Sbostic 			_check_rhosts_file = 0;
80*36319Sbostic 			break;
81*36319Sbostic 		case '?':
82*36319Sbostic 		default:
83*36319Sbostic 			syslog(LOG_ERR, "usage: rlogind [-l]");
84*36319Sbostic 			break;
85*36319Sbostic 		}
86*36319Sbostic 	argc -= optind;
87*36319Sbostic 	argv += optind;
88*36319Sbostic 
8916369Skarels 	fromlen = sizeof (from);
9016369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
9116369Skarels 		fprintf(stderr, "%s: ", argv[0]);
9216369Skarels 		perror("getpeername");
93*36319Sbostic 		exit(1);
948380Ssam 	}
9517156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
9617187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
976446Swnj 	}
9816369Skarels 	doit(0, &from);
996446Swnj }
1006446Swnj 
1016446Swnj int	child;
1026446Swnj int	cleanup();
1036446Swnj int	netf;
1046446Swnj char	*line;
10524724Smckusick extern	char	*inet_ntoa();
1066446Swnj 
10724889Smckusick struct winsize win = { 0, 0, 0, 0 };
10824723Smckusick 
10924889Smckusick 
1106446Swnj doit(f, fromp)
1116446Swnj 	int f;
1126446Swnj 	struct sockaddr_in *fromp;
1136446Swnj {
11418357Ssam 	int i, p, t, pid, on = 1;
11518357Ssam 	register struct hostent *hp;
11624724Smckusick 	struct hostent hostent;
1178380Ssam 	char c;
1186446Swnj 
1196446Swnj 	alarm(60);
1206446Swnj 	read(f, &c, 1);
1216446Swnj 	if (c != 0)
1226446Swnj 		exit(1);
1236446Swnj 	alarm(0);
12416227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
1258380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
1268380Ssam 		fromp->sin_family);
12711345Ssam 	if (hp == 0) {
12824724Smckusick 		/*
12924724Smckusick 		 * Only the name is used below.
13024724Smckusick 		 */
13124724Smckusick 		hp = &hostent;
13224724Smckusick 		hp->h_name = inet_ntoa(fromp->sin_addr);
13311345Ssam 	}
1346446Swnj 	if (fromp->sin_family != AF_INET ||
13532116Skarels 	    fromp->sin_port >= IPPORT_RESERVED ||
13632116Skarels 	    fromp->sin_port < IPPORT_RESERVED/2)
1379242Ssam 		fatal(f, "Permission denied");
1386446Swnj 	write(f, "", 1);
1396446Swnj 	for (c = 'p'; c <= 's'; c++) {
1406446Swnj 		struct stat stb;
1416446Swnj 		line = "/dev/ptyXX";
1426446Swnj 		line[strlen("/dev/pty")] = c;
1436446Swnj 		line[strlen("/dev/ptyp")] = '0';
1446446Swnj 		if (stat(line, &stb) < 0)
1456446Swnj 			break;
1466446Swnj 		for (i = 0; i < 16; i++) {
14734424Sbostic 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
14834424Sbostic 			p = open(line, O_RDWR);
1496446Swnj 			if (p > 0)
1506446Swnj 				goto gotpty;
1516446Swnj 		}
1526446Swnj 	}
15324723Smckusick 	fatal(f, "Out of ptys");
1549242Ssam 	/*NOTREACHED*/
1556446Swnj gotpty:
15624889Smckusick 	(void) ioctl(p, TIOCSWINSZ, &win);
15716227Skarels 	netf = f;
1586446Swnj 	line[strlen("/dev/")] = 't';
15934424Sbostic 	t = open(line, O_RDWR);
16034424Sbostic 	if (t < 0)
16134424Sbostic 		fatalperror(f, line);
16234424Sbostic 	if (fchmod(t, 0))
16334424Sbostic 		fatalperror(f, line);
16434424Sbostic 	(void)signal(SIGHUP, SIG_IGN);
16534424Sbostic 	vhangup();
16634424Sbostic 	(void)signal(SIGHUP, SIG_DFL);
16734424Sbostic 	t = open(line, O_RDWR);
16834424Sbostic 	if (t < 0)
16934424Sbostic 		fatalperror(f, line);
17034424Sbostic 	{
17134424Sbostic 		struct sgttyb b;
17234424Sbostic 
17334424Sbostic 		(void)ioctl(t, TIOCGETP, &b);
17434424Sbostic 		b.sg_flags = RAW|ANYP;
17534424Sbostic 		(void)ioctl(t, TIOCSETP, &b);
17634424Sbostic 	}
1776446Swnj #ifdef DEBUG
17834424Sbostic 	{
17934424Sbostic 		int tt = open("/dev/tty", O_RDWR);
18034424Sbostic 		if (tt > 0) {
18134424Sbostic 			(void)ioctl(tt, TIOCNOTTY, 0);
18234424Sbostic 			(void)close(tt);
18334424Sbostic 		}
1846446Swnj 	}
1856446Swnj #endif
1869242Ssam 	pid = fork();
1879242Ssam 	if (pid < 0)
18834424Sbostic 		fatalperror(f, "");
18918357Ssam 	if (pid == 0) {
19018357Ssam 		close(f), close(p);
19118357Ssam 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
19216227Skarels 		close(t);
19318357Ssam 		execl("/bin/login", "login", "-r", hp->h_name, 0);
19434424Sbostic 		fatalperror(2, "/bin/login");
19518357Ssam 		/*NOTREACHED*/
19618357Ssam 	}
19718357Ssam 	close(t);
19818357Ssam 	ioctl(f, FIONBIO, &on);
19918357Ssam 	ioctl(p, FIONBIO, &on);
20018357Ssam 	ioctl(p, TIOCPKT, &on);
20118357Ssam 	signal(SIGTSTP, SIG_IGN);
20218357Ssam 	signal(SIGCHLD, cleanup);
20324724Smckusick 	setpgrp(0, 0);
20418357Ssam 	protocol(f, p);
20530600Smckusick 	signal(SIGCHLD, SIG_IGN);
20618357Ssam 	cleanup();
20718357Ssam }
2089242Ssam 
20918357Ssam char	magic[2] = { 0377, 0377 };
21025423Skarels char	oobdata[] = {TIOCPKT_WINDOW};
21118357Ssam 
21218357Ssam /*
21318357Ssam  * Handle a "control" request (signaled by magic being present)
21418357Ssam  * in the data stream.  For now, we are only willing to handle
21518357Ssam  * window size changes.
21618357Ssam  */
21718357Ssam control(pty, cp, n)
21818357Ssam 	int pty;
21918357Ssam 	char *cp;
22018357Ssam 	int n;
22118357Ssam {
22228705Smckusick 	struct winsize w;
22318357Ssam 
22428705Smckusick 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
22518357Ssam 		return (0);
22625423Skarels 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
22728705Smckusick 	bcopy(cp+4, (char *)&w, sizeof(w));
22828705Smckusick 	w.ws_row = ntohs(w.ws_row);
22928705Smckusick 	w.ws_col = ntohs(w.ws_col);
23028705Smckusick 	w.ws_xpixel = ntohs(w.ws_xpixel);
23128705Smckusick 	w.ws_ypixel = ntohs(w.ws_ypixel);
23228705Smckusick 	(void)ioctl(pty, TIOCSWINSZ, &w);
23328705Smckusick 	return (4+sizeof (w));
23418357Ssam }
23518357Ssam 
23618357Ssam /*
23718357Ssam  * rlogin "protocol" machine.
23818357Ssam  */
23918357Ssam protocol(f, p)
24018357Ssam 	int f, p;
24118357Ssam {
24218357Ssam 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
24318357Ssam 	register pcc = 0, fcc = 0;
24425423Skarels 	int cc;
24525740Skarels 	char cntl;
24618357Ssam 
24718482Ssam 	/*
24818484Ssam 	 * Must ignore SIGTTOU, otherwise we'll stop
24918484Ssam 	 * when we try and set slave pty's window shape
25025423Skarels 	 * (our controlling tty is the master pty).
25118482Ssam 	 */
25218484Ssam 	(void) signal(SIGTTOU, SIG_IGN);
25325423Skarels 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
25418357Ssam 	for (;;) {
25525740Skarels 		int ibits, obits, ebits;
25618357Ssam 
25725740Skarels 		ibits = 0;
25825740Skarels 		obits = 0;
25918357Ssam 		if (fcc)
26018357Ssam 			obits |= (1<<p);
26118357Ssam 		else
26218357Ssam 			ibits |= (1<<f);
26318357Ssam 		if (pcc >= 0)
26418357Ssam 			if (pcc)
26518357Ssam 				obits |= (1<<f);
2669242Ssam 			else
26718357Ssam 				ibits |= (1<<p);
26825740Skarels 		ebits = (1<<p);
26925740Skarels 		if (select(16, &ibits, &obits, &ebits, 0) < 0) {
27018357Ssam 			if (errno == EINTR)
2716446Swnj 				continue;
27234424Sbostic 			fatalperror(f, "select");
27318357Ssam 		}
27425740Skarels 		if (ibits == 0 && obits == 0 && ebits == 0) {
27518357Ssam 			/* shouldn't happen... */
27618357Ssam 			sleep(5);
27718357Ssam 			continue;
27818357Ssam 		}
27925740Skarels #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
28025740Skarels 		if (ebits & (1<<p)) {
28125740Skarels 			cc = read(p, &cntl, 1);
28225740Skarels 			if (cc == 1 && pkcontrol(cntl)) {
28325740Skarels 				cntl |= oobdata[0];
28425740Skarels 				send(f, &cntl, 1, MSG_OOB);
28525740Skarels 				if (cntl & TIOCPKT_FLUSHWRITE) {
28625740Skarels 					pcc = 0;
28725740Skarels 					ibits &= ~(1<<p);
28825740Skarels 				}
28925740Skarels 			}
29025740Skarels 		}
29118357Ssam 		if (ibits & (1<<f)) {
29218357Ssam 			fcc = read(f, fibuf, sizeof (fibuf));
29318357Ssam 			if (fcc < 0 && errno == EWOULDBLOCK)
29418357Ssam 				fcc = 0;
29518357Ssam 			else {
29618357Ssam 				register char *cp;
29718357Ssam 				int left, n;
29818357Ssam 
29918357Ssam 				if (fcc <= 0)
30016227Skarels 					break;
30118357Ssam 				fbp = fibuf;
30224723Smckusick 
30318357Ssam 			top:
30425423Skarels 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
30518357Ssam 					if (cp[0] == magic[0] &&
30618357Ssam 					    cp[1] == magic[1]) {
30718357Ssam 						left = fcc - (cp-fibuf);
30818357Ssam 						n = control(p, cp, left);
30918357Ssam 						if (n) {
31018357Ssam 							left -= n;
31118357Ssam 							if (left > 0)
31225423Skarels 								bcopy(cp+n, cp, left);
31318357Ssam 							fcc -= n;
31418357Ssam 							goto top; /* n^2 */
31525423Skarels 						}
31625423Skarels 					}
31725423Skarels 			}
31825423Skarels 		}
31924723Smckusick 
32024723Smckusick 		if ((obits & (1<<p)) && fcc > 0) {
32125423Skarels 			cc = write(p, fbp, fcc);
32224723Smckusick 			if (cc > 0) {
32324723Smckusick 				fcc -= cc;
32424723Smckusick 				fbp += cc;
3256446Swnj 			}
32618357Ssam 		}
32724723Smckusick 
32818357Ssam 		if (ibits & (1<<p)) {
32918357Ssam 			pcc = read(p, pibuf, sizeof (pibuf));
33018357Ssam 			pbp = pibuf;
33118357Ssam 			if (pcc < 0 && errno == EWOULDBLOCK)
33218357Ssam 				pcc = 0;
33318357Ssam 			else if (pcc <= 0)
33418357Ssam 				break;
33518357Ssam 			else if (pibuf[0] == 0)
33618357Ssam 				pbp++, pcc--;
33718357Ssam 			else {
33818357Ssam 				if (pkcontrol(pibuf[0])) {
33925423Skarels 					pibuf[0] |= oobdata[0];
34018357Ssam 					send(f, &pibuf[0], 1, MSG_OOB);
34116227Skarels 				}
34218357Ssam 				pcc = 0;
3436446Swnj 			}
34418357Ssam 		}
34518357Ssam 		if ((obits & (1<<f)) && pcc > 0) {
34625423Skarels 			cc = write(f, pbp, pcc);
34725423Skarels 			if (cc < 0 && errno == EWOULDBLOCK) {
34825423Skarels 				/* also shouldn't happen */
34925423Skarels 				sleep(5);
35025423Skarels 				continue;
35125423Skarels 			}
35218357Ssam 			if (cc > 0) {
35318357Ssam 				pcc -= cc;
35418357Ssam 				pbp += cc;
35518357Ssam 			}
3566446Swnj 		}
3576446Swnj 	}
3586446Swnj }
3596446Swnj 
3606446Swnj cleanup()
3616446Swnj {
36235440Sbostic 	char *p;
36335440Sbostic 
36435440Sbostic 	p = line + sizeof("/dev/") - 1;
36535440Sbostic 	if (logout(p))
36635440Sbostic 		logwtmp(p, "", "");
36735440Sbostic 	(void)chmod(line, 0666);
36835440Sbostic 	(void)chown(line, 0, 0);
36935440Sbostic 	*p = 'p';
37035440Sbostic 	(void)chmod(line, 0666);
37135440Sbostic 	(void)chown(line, 0, 0);
37210192Ssam 	shutdown(netf, 2);
3736446Swnj 	exit(1);
3746446Swnj }
3756446Swnj 
3769242Ssam fatal(f, msg)
3779242Ssam 	int f;
3789242Ssam 	char *msg;
3799242Ssam {
3809242Ssam 	char buf[BUFSIZ];
3819242Ssam 
3829242Ssam 	buf[0] = '\01';		/* error indicator */
38313554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3849242Ssam 	(void) write(f, buf, strlen(buf));
3859242Ssam 	exit(1);
3869242Ssam }
3879242Ssam 
38834424Sbostic fatalperror(f, msg)
3899242Ssam 	int f;
3909242Ssam 	char *msg;
3919242Ssam {
3929242Ssam 	char buf[BUFSIZ];
39316227Skarels 	extern int sys_nerr;
3949242Ssam 	extern char *sys_errlist[];
3959242Ssam 
39618357Ssam 	if ((unsigned)errno < sys_nerr)
39716227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
39816227Skarels 	else
39916227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
4009242Ssam 	fatal(f, buf);
4019242Ssam }
402