xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 35441)
121174Sdist /*
2*35441Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*35441Sbostic  * All rights reserved.
4*35441Sbostic  *
5*35441Sbostic  * Redistribution and use in source and binary forms are permitted
6*35441Sbostic  * provided that the above copyright notice and this paragraph are
7*35441Sbostic  * duplicated in all such forms and that any documentation,
8*35441Sbostic  * advertising materials, and other materials related to such
9*35441Sbostic  * distribution and use acknowledge that the software was developed
10*35441Sbostic  * by the University of California, Berkeley.  The name of the
11*35441Sbostic  * University may not be used to endorse or promote products derived
12*35441Sbostic  * from this software without specific prior written permission.
13*35441Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35441Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35441Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621174Sdist  */
1721174Sdist 
186446Swnj #ifndef lint
1921174Sdist char copyright[] =
20*35441Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
2121174Sdist  All rights reserved.\n";
22*35441Sbostic #endif /* not lint */
236446Swnj 
2421174Sdist #ifndef lint
25*35441Sbostic static char sccsid[] = "@(#)rlogind.c	5.17 (Berkeley) 08/31/88";
26*35441Sbostic #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 {
6834424Sbostic 	int on = 1, fromlen;
696446Swnj 	struct sockaddr_in from;
706446Swnj 
7124855Seric 	openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
7216369Skarels 	fromlen = sizeof (from);
7316369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
7416369Skarels 		fprintf(stderr, "%s: ", argv[0]);
7516369Skarels 		perror("getpeername");
7616369Skarels 		_exit(1);
778380Ssam 	}
7817156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
7917187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
806446Swnj 	}
8116369Skarels 	doit(0, &from);
826446Swnj }
836446Swnj 
846446Swnj int	child;
856446Swnj int	cleanup();
866446Swnj int	netf;
876446Swnj char	*line;
8824724Smckusick extern	char	*inet_ntoa();
896446Swnj 
9024889Smckusick struct winsize win = { 0, 0, 0, 0 };
9124723Smckusick 
9224889Smckusick 
936446Swnj doit(f, fromp)
946446Swnj 	int f;
956446Swnj 	struct sockaddr_in *fromp;
966446Swnj {
9718357Ssam 	int i, p, t, pid, on = 1;
9818357Ssam 	register struct hostent *hp;
9924724Smckusick 	struct hostent hostent;
1008380Ssam 	char c;
1016446Swnj 
1026446Swnj 	alarm(60);
1036446Swnj 	read(f, &c, 1);
1046446Swnj 	if (c != 0)
1056446Swnj 		exit(1);
1066446Swnj 	alarm(0);
10716227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
1088380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
1098380Ssam 		fromp->sin_family);
11011345Ssam 	if (hp == 0) {
11124724Smckusick 		/*
11224724Smckusick 		 * Only the name is used below.
11324724Smckusick 		 */
11424724Smckusick 		hp = &hostent;
11524724Smckusick 		hp->h_name = inet_ntoa(fromp->sin_addr);
11611345Ssam 	}
1176446Swnj 	if (fromp->sin_family != AF_INET ||
11832116Skarels 	    fromp->sin_port >= IPPORT_RESERVED ||
11932116Skarels 	    fromp->sin_port < IPPORT_RESERVED/2)
1209242Ssam 		fatal(f, "Permission denied");
1216446Swnj 	write(f, "", 1);
1226446Swnj 	for (c = 'p'; c <= 's'; c++) {
1236446Swnj 		struct stat stb;
1246446Swnj 		line = "/dev/ptyXX";
1256446Swnj 		line[strlen("/dev/pty")] = c;
1266446Swnj 		line[strlen("/dev/ptyp")] = '0';
1276446Swnj 		if (stat(line, &stb) < 0)
1286446Swnj 			break;
1296446Swnj 		for (i = 0; i < 16; i++) {
13034424Sbostic 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
13134424Sbostic 			p = open(line, O_RDWR);
1326446Swnj 			if (p > 0)
1336446Swnj 				goto gotpty;
1346446Swnj 		}
1356446Swnj 	}
13624723Smckusick 	fatal(f, "Out of ptys");
1379242Ssam 	/*NOTREACHED*/
1386446Swnj gotpty:
13924889Smckusick 	(void) ioctl(p, TIOCSWINSZ, &win);
14016227Skarels 	netf = f;
1416446Swnj 	line[strlen("/dev/")] = 't';
14234424Sbostic 	t = open(line, O_RDWR);
14334424Sbostic 	if (t < 0)
14434424Sbostic 		fatalperror(f, line);
14534424Sbostic 	if (fchmod(t, 0))
14634424Sbostic 		fatalperror(f, line);
14734424Sbostic 	(void)signal(SIGHUP, SIG_IGN);
14834424Sbostic 	vhangup();
14934424Sbostic 	(void)signal(SIGHUP, SIG_DFL);
15034424Sbostic 	t = open(line, O_RDWR);
15134424Sbostic 	if (t < 0)
15234424Sbostic 		fatalperror(f, line);
15334424Sbostic 	{
15434424Sbostic 		struct sgttyb b;
15534424Sbostic 
15634424Sbostic 		(void)ioctl(t, TIOCGETP, &b);
15734424Sbostic 		b.sg_flags = RAW|ANYP;
15834424Sbostic 		(void)ioctl(t, TIOCSETP, &b);
15934424Sbostic 	}
1606446Swnj #ifdef DEBUG
16134424Sbostic 	{
16234424Sbostic 		int tt = open("/dev/tty", O_RDWR);
16334424Sbostic 		if (tt > 0) {
16434424Sbostic 			(void)ioctl(tt, TIOCNOTTY, 0);
16534424Sbostic 			(void)close(tt);
16634424Sbostic 		}
1676446Swnj 	}
1686446Swnj #endif
1699242Ssam 	pid = fork();
1709242Ssam 	if (pid < 0)
17134424Sbostic 		fatalperror(f, "");
17218357Ssam 	if (pid == 0) {
17318357Ssam 		close(f), close(p);
17418357Ssam 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
17516227Skarels 		close(t);
17618357Ssam 		execl("/bin/login", "login", "-r", hp->h_name, 0);
17734424Sbostic 		fatalperror(2, "/bin/login");
17818357Ssam 		/*NOTREACHED*/
17918357Ssam 	}
18018357Ssam 	close(t);
18118357Ssam 	ioctl(f, FIONBIO, &on);
18218357Ssam 	ioctl(p, FIONBIO, &on);
18318357Ssam 	ioctl(p, TIOCPKT, &on);
18418357Ssam 	signal(SIGTSTP, SIG_IGN);
18518357Ssam 	signal(SIGCHLD, cleanup);
18624724Smckusick 	setpgrp(0, 0);
18718357Ssam 	protocol(f, p);
18830600Smckusick 	signal(SIGCHLD, SIG_IGN);
18918357Ssam 	cleanup();
19018357Ssam }
1919242Ssam 
19218357Ssam char	magic[2] = { 0377, 0377 };
19325423Skarels char	oobdata[] = {TIOCPKT_WINDOW};
19418357Ssam 
19518357Ssam /*
19618357Ssam  * Handle a "control" request (signaled by magic being present)
19718357Ssam  * in the data stream.  For now, we are only willing to handle
19818357Ssam  * window size changes.
19918357Ssam  */
20018357Ssam control(pty, cp, n)
20118357Ssam 	int pty;
20218357Ssam 	char *cp;
20318357Ssam 	int n;
20418357Ssam {
20528705Smckusick 	struct winsize w;
20618357Ssam 
20728705Smckusick 	if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
20818357Ssam 		return (0);
20925423Skarels 	oobdata[0] &= ~TIOCPKT_WINDOW;	/* we know he heard */
21028705Smckusick 	bcopy(cp+4, (char *)&w, sizeof(w));
21128705Smckusick 	w.ws_row = ntohs(w.ws_row);
21228705Smckusick 	w.ws_col = ntohs(w.ws_col);
21328705Smckusick 	w.ws_xpixel = ntohs(w.ws_xpixel);
21428705Smckusick 	w.ws_ypixel = ntohs(w.ws_ypixel);
21528705Smckusick 	(void)ioctl(pty, TIOCSWINSZ, &w);
21628705Smckusick 	return (4+sizeof (w));
21718357Ssam }
21818357Ssam 
21918357Ssam /*
22018357Ssam  * rlogin "protocol" machine.
22118357Ssam  */
22218357Ssam protocol(f, p)
22318357Ssam 	int f, p;
22418357Ssam {
22518357Ssam 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
22618357Ssam 	register pcc = 0, fcc = 0;
22725423Skarels 	int cc;
22825740Skarels 	char cntl;
22918357Ssam 
23018482Ssam 	/*
23118484Ssam 	 * Must ignore SIGTTOU, otherwise we'll stop
23218484Ssam 	 * when we try and set slave pty's window shape
23325423Skarels 	 * (our controlling tty is the master pty).
23418482Ssam 	 */
23518484Ssam 	(void) signal(SIGTTOU, SIG_IGN);
23625423Skarels 	send(f, oobdata, 1, MSG_OOB);	/* indicate new rlogin */
23718357Ssam 	for (;;) {
23825740Skarels 		int ibits, obits, ebits;
23918357Ssam 
24025740Skarels 		ibits = 0;
24125740Skarels 		obits = 0;
24218357Ssam 		if (fcc)
24318357Ssam 			obits |= (1<<p);
24418357Ssam 		else
24518357Ssam 			ibits |= (1<<f);
24618357Ssam 		if (pcc >= 0)
24718357Ssam 			if (pcc)
24818357Ssam 				obits |= (1<<f);
2499242Ssam 			else
25018357Ssam 				ibits |= (1<<p);
25125740Skarels 		ebits = (1<<p);
25225740Skarels 		if (select(16, &ibits, &obits, &ebits, 0) < 0) {
25318357Ssam 			if (errno == EINTR)
2546446Swnj 				continue;
25534424Sbostic 			fatalperror(f, "select");
25618357Ssam 		}
25725740Skarels 		if (ibits == 0 && obits == 0 && ebits == 0) {
25818357Ssam 			/* shouldn't happen... */
25918357Ssam 			sleep(5);
26018357Ssam 			continue;
26118357Ssam 		}
26225740Skarels #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
26325740Skarels 		if (ebits & (1<<p)) {
26425740Skarels 			cc = read(p, &cntl, 1);
26525740Skarels 			if (cc == 1 && pkcontrol(cntl)) {
26625740Skarels 				cntl |= oobdata[0];
26725740Skarels 				send(f, &cntl, 1, MSG_OOB);
26825740Skarels 				if (cntl & TIOCPKT_FLUSHWRITE) {
26925740Skarels 					pcc = 0;
27025740Skarels 					ibits &= ~(1<<p);
27125740Skarels 				}
27225740Skarels 			}
27325740Skarels 		}
27418357Ssam 		if (ibits & (1<<f)) {
27518357Ssam 			fcc = read(f, fibuf, sizeof (fibuf));
27618357Ssam 			if (fcc < 0 && errno == EWOULDBLOCK)
27718357Ssam 				fcc = 0;
27818357Ssam 			else {
27918357Ssam 				register char *cp;
28018357Ssam 				int left, n;
28118357Ssam 
28218357Ssam 				if (fcc <= 0)
28316227Skarels 					break;
28418357Ssam 				fbp = fibuf;
28524723Smckusick 
28618357Ssam 			top:
28725423Skarels 				for (cp = fibuf; cp < fibuf+fcc-1; cp++)
28818357Ssam 					if (cp[0] == magic[0] &&
28918357Ssam 					    cp[1] == magic[1]) {
29018357Ssam 						left = fcc - (cp-fibuf);
29118357Ssam 						n = control(p, cp, left);
29218357Ssam 						if (n) {
29318357Ssam 							left -= n;
29418357Ssam 							if (left > 0)
29525423Skarels 								bcopy(cp+n, cp, left);
29618357Ssam 							fcc -= n;
29718357Ssam 							goto top; /* n^2 */
29825423Skarels 						}
29925423Skarels 					}
30025423Skarels 			}
30125423Skarels 		}
30224723Smckusick 
30324723Smckusick 		if ((obits & (1<<p)) && fcc > 0) {
30425423Skarels 			cc = write(p, fbp, fcc);
30524723Smckusick 			if (cc > 0) {
30624723Smckusick 				fcc -= cc;
30724723Smckusick 				fbp += cc;
3086446Swnj 			}
30918357Ssam 		}
31024723Smckusick 
31118357Ssam 		if (ibits & (1<<p)) {
31218357Ssam 			pcc = read(p, pibuf, sizeof (pibuf));
31318357Ssam 			pbp = pibuf;
31418357Ssam 			if (pcc < 0 && errno == EWOULDBLOCK)
31518357Ssam 				pcc = 0;
31618357Ssam 			else if (pcc <= 0)
31718357Ssam 				break;
31818357Ssam 			else if (pibuf[0] == 0)
31918357Ssam 				pbp++, pcc--;
32018357Ssam 			else {
32118357Ssam 				if (pkcontrol(pibuf[0])) {
32225423Skarels 					pibuf[0] |= oobdata[0];
32318357Ssam 					send(f, &pibuf[0], 1, MSG_OOB);
32416227Skarels 				}
32518357Ssam 				pcc = 0;
3266446Swnj 			}
32718357Ssam 		}
32818357Ssam 		if ((obits & (1<<f)) && pcc > 0) {
32925423Skarels 			cc = write(f, pbp, pcc);
33025423Skarels 			if (cc < 0 && errno == EWOULDBLOCK) {
33125423Skarels 				/* also shouldn't happen */
33225423Skarels 				sleep(5);
33325423Skarels 				continue;
33425423Skarels 			}
33518357Ssam 			if (cc > 0) {
33618357Ssam 				pcc -= cc;
33718357Ssam 				pbp += cc;
33818357Ssam 			}
3396446Swnj 		}
3406446Swnj 	}
3416446Swnj }
3426446Swnj 
3436446Swnj cleanup()
3446446Swnj {
34535440Sbostic 	char *p;
34635440Sbostic 
34735440Sbostic 	p = line + sizeof("/dev/") - 1;
34835440Sbostic 	if (logout(p))
34935440Sbostic 		logwtmp(p, "", "");
35035440Sbostic 	(void)chmod(line, 0666);
35135440Sbostic 	(void)chown(line, 0, 0);
35235440Sbostic 	*p = 'p';
35335440Sbostic 	(void)chmod(line, 0666);
35435440Sbostic 	(void)chown(line, 0, 0);
35510192Ssam 	shutdown(netf, 2);
3566446Swnj 	exit(1);
3576446Swnj }
3586446Swnj 
3599242Ssam fatal(f, msg)
3609242Ssam 	int f;
3619242Ssam 	char *msg;
3629242Ssam {
3639242Ssam 	char buf[BUFSIZ];
3649242Ssam 
3659242Ssam 	buf[0] = '\01';		/* error indicator */
36613554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3679242Ssam 	(void) write(f, buf, strlen(buf));
3689242Ssam 	exit(1);
3699242Ssam }
3709242Ssam 
37134424Sbostic fatalperror(f, msg)
3729242Ssam 	int f;
3739242Ssam 	char *msg;
3749242Ssam {
3759242Ssam 	char buf[BUFSIZ];
37616227Skarels 	extern int sys_nerr;
3779242Ssam 	extern char *sys_errlist[];
3789242Ssam 
37918357Ssam 	if ((unsigned)errno < sys_nerr)
38016227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
38116227Skarels 	else
38216227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3839242Ssam 	fatal(f, buf);
3849242Ssam }
385