xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 34424)
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*34424Sbostic static char sccsid[] = "@(#)rlogind.c	5.14 (Berkeley) 05/22/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 
47*34424Sbostic extern	int errno;
4810417Ssam int	reapchild();
496446Swnj struct	passwd *getpwnam();
5024723Smckusick char	*malloc();
5116369Skarels 
52*34424Sbostic /*ARGSUSED*/
536446Swnj main(argc, argv)
546446Swnj 	int argc;
556446Swnj 	char **argv;
566446Swnj {
57*34424Sbostic 	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++) {
119*34424Sbostic 			line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
120*34424Sbostic 			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';
131*34424Sbostic 	t = open(line, O_RDWR);
132*34424Sbostic 	if (t < 0)
133*34424Sbostic 		fatalperror(f, line);
134*34424Sbostic 	if (fchmod(t, 0))
135*34424Sbostic 		fatalperror(f, line);
136*34424Sbostic 	(void)signal(SIGHUP, SIG_IGN);
137*34424Sbostic 	vhangup();
138*34424Sbostic 	(void)signal(SIGHUP, SIG_DFL);
139*34424Sbostic 	t = open(line, O_RDWR);
140*34424Sbostic 	if (t < 0)
141*34424Sbostic 		fatalperror(f, line);
142*34424Sbostic 	{
143*34424Sbostic 		struct sgttyb b;
144*34424Sbostic 
145*34424Sbostic 		(void)ioctl(t, TIOCGETP, &b);
146*34424Sbostic 		b.sg_flags = RAW|ANYP;
147*34424Sbostic 		(void)ioctl(t, TIOCSETP, &b);
148*34424Sbostic 	}
1496446Swnj #ifdef DEBUG
150*34424Sbostic 	{
151*34424Sbostic 		int tt = open("/dev/tty", O_RDWR);
152*34424Sbostic 		if (tt > 0) {
153*34424Sbostic 			(void)ioctl(tt, TIOCNOTTY, 0);
154*34424Sbostic 			(void)close(tt);
155*34424Sbostic 		}
1566446Swnj 	}
1576446Swnj #endif
1589242Ssam 	pid = fork();
1599242Ssam 	if (pid < 0)
160*34424Sbostic 		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);
166*34424Sbostic 		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;
244*34424Sbostic 			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 {
3346446Swnj 
3356446Swnj 	rmut();
33610009Ssam 	vhangup();		/* XXX */
33710192Ssam 	shutdown(netf, 2);
3386446Swnj 	exit(1);
3396446Swnj }
3406446Swnj 
3419242Ssam fatal(f, msg)
3429242Ssam 	int f;
3439242Ssam 	char *msg;
3449242Ssam {
3459242Ssam 	char buf[BUFSIZ];
3469242Ssam 
3479242Ssam 	buf[0] = '\01';		/* error indicator */
34813554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3499242Ssam 	(void) write(f, buf, strlen(buf));
3509242Ssam 	exit(1);
3519242Ssam }
3529242Ssam 
353*34424Sbostic fatalperror(f, msg)
3549242Ssam 	int f;
3559242Ssam 	char *msg;
3569242Ssam {
3579242Ssam 	char buf[BUFSIZ];
35816227Skarels 	extern int sys_nerr;
3599242Ssam 	extern char *sys_errlist[];
3609242Ssam 
36118357Ssam 	if ((unsigned)errno < sys_nerr)
36216227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
36316227Skarels 	else
36416227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3659242Ssam 	fatal(f, buf);
3669242Ssam }
3679242Ssam 
3686446Swnj #include <utmp.h>
3696446Swnj 
3706446Swnj struct	utmp wtmp;
3716446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
37223566Sbloom char	utmpf[] = "/etc/utmp";
3736446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
3746446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
3756446Swnj 
3766446Swnj rmut()
3776446Swnj {
3786446Swnj 	register f;
3796446Swnj 	int found = 0;
38023566Sbloom 	struct utmp *u, *utmp;
38123566Sbloom 	int nutmp;
38223566Sbloom 	struct stat statbf;
3836446Swnj 
38423566Sbloom 	f = open(utmpf, O_RDWR);
3856446Swnj 	if (f >= 0) {
38623566Sbloom 		fstat(f, &statbf);
38723566Sbloom 		utmp = (struct utmp *)malloc(statbf.st_size);
38823566Sbloom 		if (!utmp)
38923566Sbloom 			syslog(LOG_ERR, "utmp malloc failed");
39023566Sbloom 		if (statbf.st_size && utmp) {
39123566Sbloom 			nutmp = read(f, utmp, statbf.st_size);
39223566Sbloom 			nutmp /= sizeof(struct utmp);
39323566Sbloom 
39423566Sbloom 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
39523566Sbloom 				if (SCMPN(u->ut_line, line+5) ||
39623566Sbloom 				    u->ut_name[0]==0)
39723566Sbloom 					continue;
39823566Sbloom 				lseek(f, ((long)u)-((long)utmp), L_SET);
39923566Sbloom 				SCPYN(u->ut_name, "");
40023566Sbloom 				SCPYN(u->ut_host, "");
40123566Sbloom 				time(&u->ut_time);
40223566Sbloom 				write(f, (char *)u, sizeof(wtmp));
40323566Sbloom 				found++;
40423566Sbloom 			}
4056446Swnj 		}
4066446Swnj 		close(f);
4076446Swnj 	}
4086446Swnj 	if (found) {
40923566Sbloom 		f = open(wtmpf, O_WRONLY|O_APPEND);
4106446Swnj 		if (f >= 0) {
4116446Swnj 			SCPYN(wtmp.ut_line, line+5);
4126446Swnj 			SCPYN(wtmp.ut_name, "");
41312681Ssam 			SCPYN(wtmp.ut_host, "");
4146446Swnj 			time(&wtmp.ut_time);
4156446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
4166446Swnj 			close(f);
4176446Swnj 		}
4186446Swnj 	}
4196446Swnj 	chmod(line, 0666);
4206446Swnj 	chown(line, 0, 0);
4216446Swnj 	line[strlen("/dev/")] = 'p';
4226446Swnj 	chmod(line, 0666);
4236446Swnj 	chown(line, 0, 0);
4246446Swnj }
425