xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 35440)
121174Sdist /*
221174Sdist  * Copyright (c) 1983 Regents of the University of California.
321174Sdist  * All rights reserved.  The Berkeley software License Agreement
421174Sdist  * specifies the terms and conditions for redistribution.
521174Sdist  */
621174Sdist 
76446Swnj #ifndef lint
821174Sdist char copyright[] =
921174Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021174Sdist  All rights reserved.\n";
1121174Sdist #endif not lint
126446Swnj 
1321174Sdist #ifndef lint
14*35440Sbostic static char sccsid[] = "@(#)rlogind.c	5.16 (Berkeley) 08/31/88";
1521174Sdist #endif not lint
1621174Sdist 
1716369Skarels /*
1816369Skarels  * remote login server:
1916369Skarels  *	remuser\0
2016369Skarels  *	locuser\0
2118357Ssam  *	terminal info\0
2216369Skarels  *	data
2316369Skarels  */
2416369Skarels 
256446Swnj #include <stdio.h>
266446Swnj #include <sys/types.h>
276446Swnj #include <sys/stat.h>
286446Swnj #include <sys/socket.h>
2913554Ssam #include <sys/wait.h>
3018357Ssam #include <sys/file.h>
319208Ssam 
329208Ssam #include <netinet/in.h>
339208Ssam 
346446Swnj #include <errno.h>
356446Swnj #include <pwd.h>
366446Swnj #include <signal.h>
376446Swnj #include <sgtty.h>
386446Swnj #include <stdio.h>
398380Ssam #include <netdb.h>
4017187Sralph #include <syslog.h>
4118357Ssam #include <strings.h>
426446Swnj 
4324723Smckusick # ifndef TIOCPKT_WINDOW
4424723Smckusick # define TIOCPKT_WINDOW 0x80
4524723Smckusick # endif TIOCPKT_WINDOW
4624723Smckusick 
4734424Sbostic extern	int errno;
4810417Ssam int	reapchild();
496446Swnj struct	passwd *getpwnam();
5024723Smckusick char	*malloc();
5116369Skarels 
5234424Sbostic /*ARGSUSED*/
536446Swnj main(argc, argv)
546446Swnj 	int argc;
556446Swnj 	char **argv;
566446Swnj {
5734424Sbostic 	int on = 1, fromlen;
586446Swnj 	struct sockaddr_in from;
596446Swnj 
6024855Seric 	openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
6116369Skarels 	fromlen = sizeof (from);
6216369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
6316369Skarels 		fprintf(stderr, "%s: ", argv[0]);
6416369Skarels 		perror("getpeername");
6516369Skarels 		_exit(1);
668380Ssam 	}
6717156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
6817187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
696446Swnj 	}
7016369Skarels 	doit(0, &from);
716446Swnj }
726446Swnj 
736446Swnj int	child;
746446Swnj int	cleanup();
756446Swnj int	netf;
766446Swnj char	*line;
7724724Smckusick extern	char	*inet_ntoa();
786446Swnj 
7924889Smckusick struct winsize win = { 0, 0, 0, 0 };
8024723Smckusick 
8124889Smckusick 
826446Swnj doit(f, fromp)
836446Swnj 	int f;
846446Swnj 	struct sockaddr_in *fromp;
856446Swnj {
8618357Ssam 	int i, p, t, pid, on = 1;
8718357Ssam 	register struct hostent *hp;
8824724Smckusick 	struct hostent hostent;
898380Ssam 	char c;
906446Swnj 
916446Swnj 	alarm(60);
926446Swnj 	read(f, &c, 1);
936446Swnj 	if (c != 0)
946446Swnj 		exit(1);
956446Swnj 	alarm(0);
9616227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
978380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
988380Ssam 		fromp->sin_family);
9911345Ssam 	if (hp == 0) {
10024724Smckusick 		/*
10124724Smckusick 		 * Only the name is used below.
10224724Smckusick 		 */
10324724Smckusick 		hp = &hostent;
10424724Smckusick 		hp->h_name = inet_ntoa(fromp->sin_addr);
10511345Ssam 	}
1066446Swnj 	if (fromp->sin_family != AF_INET ||
10732116Skarels 	    fromp->sin_port >= IPPORT_RESERVED ||
10832116Skarels 	    fromp->sin_port < IPPORT_RESERVED/2)
1099242Ssam 		fatal(f, "Permission denied");
1106446Swnj 	write(f, "", 1);
1116446Swnj 	for (c = 'p'; c <= 's'; c++) {
1126446Swnj 		struct stat stb;
1136446Swnj 		line = "/dev/ptyXX";
1146446Swnj 		line[strlen("/dev/pty")] = c;
1156446Swnj 		line[strlen("/dev/ptyp")] = '0';
1166446Swnj 		if (stat(line, &stb) < 0)
1176446Swnj 			break;
1186446Swnj 		for (i = 0; i < 16; i++) {
11934424Sbostic 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
12034424Sbostic 			p = open(line, O_RDWR);
1216446Swnj 			if (p > 0)
1226446Swnj 				goto gotpty;
1236446Swnj 		}
1246446Swnj 	}
12524723Smckusick 	fatal(f, "Out of ptys");
1269242Ssam 	/*NOTREACHED*/
1276446Swnj gotpty:
12824889Smckusick 	(void) ioctl(p, TIOCSWINSZ, &win);
12916227Skarels 	netf = f;
1306446Swnj 	line[strlen("/dev/")] = 't';
13134424Sbostic 	t = open(line, O_RDWR);
13234424Sbostic 	if (t < 0)
13334424Sbostic 		fatalperror(f, line);
13434424Sbostic 	if (fchmod(t, 0))
13534424Sbostic 		fatalperror(f, line);
13634424Sbostic 	(void)signal(SIGHUP, SIG_IGN);
13734424Sbostic 	vhangup();
13834424Sbostic 	(void)signal(SIGHUP, SIG_DFL);
13934424Sbostic 	t = open(line, O_RDWR);
14034424Sbostic 	if (t < 0)
14134424Sbostic 		fatalperror(f, line);
14234424Sbostic 	{
14334424Sbostic 		struct sgttyb b;
14434424Sbostic 
14534424Sbostic 		(void)ioctl(t, TIOCGETP, &b);
14634424Sbostic 		b.sg_flags = RAW|ANYP;
14734424Sbostic 		(void)ioctl(t, TIOCSETP, &b);
14834424Sbostic 	}
1496446Swnj #ifdef DEBUG
15034424Sbostic 	{
15134424Sbostic 		int tt = open("/dev/tty", O_RDWR);
15234424Sbostic 		if (tt > 0) {
15334424Sbostic 			(void)ioctl(tt, TIOCNOTTY, 0);
15434424Sbostic 			(void)close(tt);
15534424Sbostic 		}
1566446Swnj 	}
1576446Swnj #endif
1589242Ssam 	pid = fork();
1599242Ssam 	if (pid < 0)
16034424Sbostic 		fatalperror(f, "");
16118357Ssam 	if (pid == 0) {
16218357Ssam 		close(f), close(p);
16318357Ssam 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
16416227Skarels 		close(t);
16518357Ssam 		execl("/bin/login", "login", "-r", hp->h_name, 0);
16634424Sbostic 		fatalperror(2, "/bin/login");
16718357Ssam 		/*NOTREACHED*/
16818357Ssam 	}
16918357Ssam 	close(t);
17018357Ssam 	ioctl(f, FIONBIO, &on);
17118357Ssam 	ioctl(p, FIONBIO, &on);
17218357Ssam 	ioctl(p, TIOCPKT, &on);
17318357Ssam 	signal(SIGTSTP, SIG_IGN);
17418357Ssam 	signal(SIGCHLD, cleanup);
17524724Smckusick 	setpgrp(0, 0);
17618357Ssam 	protocol(f, p);
17730600Smckusick 	signal(SIGCHLD, SIG_IGN);
17818357Ssam 	cleanup();
17918357Ssam }
1809242Ssam 
18118357Ssam char	magic[2] = { 0377, 0377 };
18225423Skarels char	oobdata[] = {TIOCPKT_WINDOW};
18318357Ssam 
18418357Ssam /*
18518357Ssam  * Handle a "control" request (signaled by magic being present)
18618357Ssam  * in the data stream.  For now, we are only willing to handle
18718357Ssam  * window size changes.
18818357Ssam  */
18918357Ssam control(pty, cp, n)
19018357Ssam 	int pty;
19118357Ssam 	char *cp;
19218357Ssam 	int n;
19318357Ssam {
19428705Smckusick 	struct winsize w;
19518357Ssam 
19628705Smckusick 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
19718357Ssam 		return (0);
19825423Skarels 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
19928705Smckusick 	bcopy(cp+4, (char *)&w, sizeof(w));
20028705Smckusick 	w.ws_row = ntohs(w.ws_row);
20128705Smckusick 	w.ws_col = ntohs(w.ws_col);
20228705Smckusick 	w.ws_xpixel = ntohs(w.ws_xpixel);
20328705Smckusick 	w.ws_ypixel = ntohs(w.ws_ypixel);
20428705Smckusick 	(void)ioctl(pty, TIOCSWINSZ, &w);
20528705Smckusick 	return (4+sizeof (w));
20618357Ssam }
20718357Ssam 
20818357Ssam /*
20918357Ssam  * rlogin "protocol" machine.
21018357Ssam  */
21118357Ssam protocol(f, p)
21218357Ssam 	int f, p;
21318357Ssam {
21418357Ssam 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
21518357Ssam 	register pcc = 0, fcc = 0;
21625423Skarels 	int cc;
21725740Skarels 	char cntl;
21818357Ssam 
21918482Ssam 	/*
22018484Ssam 	 * Must ignore SIGTTOU, otherwise we'll stop
22118484Ssam 	 * when we try and set slave pty's window shape
22225423Skarels 	 * (our controlling tty is the master pty).
22318482Ssam 	 */
22418484Ssam 	(void) signal(SIGTTOU, SIG_IGN);
22525423Skarels 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
22618357Ssam 	for (;;) {
22725740Skarels 		int ibits, obits, ebits;
22818357Ssam 
22925740Skarels 		ibits = 0;
23025740Skarels 		obits = 0;
23118357Ssam 		if (fcc)
23218357Ssam 			obits |= (1<<p);
23318357Ssam 		else
23418357Ssam 			ibits |= (1<<f);
23518357Ssam 		if (pcc >= 0)
23618357Ssam 			if (pcc)
23718357Ssam 				obits |= (1<<f);
2389242Ssam 			else
23918357Ssam 				ibits |= (1<<p);
24025740Skarels 		ebits = (1<<p);
24125740Skarels 		if (select(16, &ibits, &obits, &ebits, 0) < 0) {
24218357Ssam 			if (errno == EINTR)
2436446Swnj 				continue;
24434424Sbostic 			fatalperror(f, "select");
24518357Ssam 		}
24625740Skarels 		if (ibits == 0 && obits == 0 && ebits == 0) {
24718357Ssam 			/* shouldn't happen... */
24818357Ssam 			sleep(5);
24918357Ssam 			continue;
25018357Ssam 		}
25125740Skarels #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
25225740Skarels 		if (ebits & (1<<p)) {
25325740Skarels 			cc = read(p, &cntl, 1);
25425740Skarels 			if (cc == 1 && pkcontrol(cntl)) {
25525740Skarels 				cntl |= oobdata[0];
25625740Skarels 				send(f, &cntl, 1, MSG_OOB);
25725740Skarels 				if (cntl & TIOCPKT_FLUSHWRITE) {
25825740Skarels 					pcc = 0;
25925740Skarels 					ibits &= ~(1<<p);
26025740Skarels 				}
26125740Skarels 			}
26225740Skarels 		}
26318357Ssam 		if (ibits & (1<<f)) {
26418357Ssam 			fcc = read(f, fibuf, sizeof (fibuf));
26518357Ssam 			if (fcc < 0 && errno == EWOULDBLOCK)
26618357Ssam 				fcc = 0;
26718357Ssam 			else {
26818357Ssam 				register char *cp;
26918357Ssam 				int left, n;
27018357Ssam 
27118357Ssam 				if (fcc <= 0)
27216227Skarels 					break;
27318357Ssam 				fbp = fibuf;
27424723Smckusick 
27518357Ssam 			top:
27625423Skarels 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
27718357Ssam 					if (cp[0] == magic[0] &&
27818357Ssam 					    cp[1] == magic[1]) {
27918357Ssam 						left = fcc - (cp-fibuf);
28018357Ssam 						n = control(p, cp, left);
28118357Ssam 						if (n) {
28218357Ssam 							left -= n;
28318357Ssam 							if (left > 0)
28425423Skarels 								bcopy(cp+n, cp, left);
28518357Ssam 							fcc -= n;
28618357Ssam 							goto top; /* n^2 */
28725423Skarels 						}
28825423Skarels 					}
28925423Skarels 			}
29025423Skarels 		}
29124723Smckusick 
29224723Smckusick 		if ((obits & (1<<p)) && fcc > 0) {
29325423Skarels 			cc = write(p, fbp, fcc);
29424723Smckusick 			if (cc > 0) {
29524723Smckusick 				fcc -= cc;
29624723Smckusick 				fbp += cc;
2976446Swnj 			}
29818357Ssam 		}
29924723Smckusick 
30018357Ssam 		if (ibits & (1<<p)) {
30118357Ssam 			pcc = read(p, pibuf, sizeof (pibuf));
30218357Ssam 			pbp = pibuf;
30318357Ssam 			if (pcc < 0 && errno == EWOULDBLOCK)
30418357Ssam 				pcc = 0;
30518357Ssam 			else if (pcc <= 0)
30618357Ssam 				break;
30718357Ssam 			else if (pibuf[0] == 0)
30818357Ssam 				pbp++, pcc--;
30918357Ssam 			else {
31018357Ssam 				if (pkcontrol(pibuf[0])) {
31125423Skarels 					pibuf[0] |= oobdata[0];
31218357Ssam 					send(f, &pibuf[0], 1, MSG_OOB);
31316227Skarels 				}
31418357Ssam 				pcc = 0;
3156446Swnj 			}
31618357Ssam 		}
31718357Ssam 		if ((obits & (1<<f)) && pcc > 0) {
31825423Skarels 			cc = write(f, pbp, pcc);
31925423Skarels 			if (cc < 0 && errno == EWOULDBLOCK) {
32025423Skarels 				/* also shouldn't happen */
32125423Skarels 				sleep(5);
32225423Skarels 				continue;
32325423Skarels 			}
32418357Ssam 			if (cc > 0) {
32518357Ssam 				pcc -= cc;
32618357Ssam 				pbp += cc;
32718357Ssam 			}
3286446Swnj 		}
3296446Swnj 	}
3306446Swnj }
3316446Swnj 
3326446Swnj cleanup()
3336446Swnj {
334*35440Sbostic 	char *p;
335*35440Sbostic 
336*35440Sbostic 	p = line + sizeof("/dev/") - 1;
337*35440Sbostic 	if (logout(p))
338*35440Sbostic 		logwtmp(p, "", "");
339*35440Sbostic 	(void)chmod(line, 0666);
340*35440Sbostic 	(void)chown(line, 0, 0);
341*35440Sbostic 	*p = 'p';
342*35440Sbostic 	(void)chmod(line, 0666);
343*35440Sbostic 	(void)chown(line, 0, 0);
34410192Ssam 	shutdown(netf, 2);
3456446Swnj 	exit(1);
3466446Swnj }
3476446Swnj 
3489242Ssam fatal(f, msg)
3499242Ssam 	int f;
3509242Ssam 	char *msg;
3519242Ssam {
3529242Ssam 	char buf[BUFSIZ];
3539242Ssam 
3549242Ssam 	buf[0] = '\01';		/* error indicator */
35513554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3569242Ssam 	(void) write(f, buf, strlen(buf));
3579242Ssam 	exit(1);
3589242Ssam }
3599242Ssam 
36034424Sbostic fatalperror(f, msg)
3619242Ssam 	int f;
3629242Ssam 	char *msg;
3639242Ssam {
3649242Ssam 	char buf[BUFSIZ];
36516227Skarels 	extern int sys_nerr;
3669242Ssam 	extern char *sys_errlist[];
3679242Ssam 
36818357Ssam 	if ((unsigned)errno < sys_nerr)
36916227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
37016227Skarels 	else
37116227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3729242Ssam 	fatal(f, buf);
3739242Ssam }
374