xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 24722)
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*24722Smckusick static char sccsid[] = "@(#)rlogind.c	5.2.1.1 (Berkeley) 09/12/85";
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 
436446Swnj extern	errno;
4410417Ssam int	reapchild();
456446Swnj struct	passwd *getpwnam();
4618357Ssam char	*crypt(), *malloc();
4716369Skarels 
486446Swnj main(argc, argv)
496446Swnj 	int argc;
506446Swnj 	char **argv;
516446Swnj {
5217156Ssam 	int on = 1, options = 0, fromlen;
536446Swnj 	struct sockaddr_in from;
546446Swnj 
5516369Skarels 	fromlen = sizeof (from);
5616369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
5716369Skarels 		fprintf(stderr, "%s: ", argv[0]);
5816369Skarels 		perror("getpeername");
5916369Skarels 		_exit(1);
608380Ssam 	}
6117156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
6217187Sralph 		openlog(argv[0], LOG_PID, 0);
6317187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
646446Swnj 	}
6516369Skarels 	doit(0, &from);
666446Swnj }
676446Swnj 
686446Swnj int	child;
696446Swnj int	cleanup();
706446Swnj int	netf;
716446Swnj extern	errno;
726446Swnj char	*line;
736446Swnj 
746446Swnj doit(f, fromp)
756446Swnj 	int f;
766446Swnj 	struct sockaddr_in *fromp;
776446Swnj {
7818357Ssam 	int i, p, t, pid, on = 1;
7918357Ssam 	register struct hostent *hp;
808380Ssam 	char c;
816446Swnj 
826446Swnj 	alarm(60);
836446Swnj 	read(f, &c, 1);
846446Swnj 	if (c != 0)
856446Swnj 		exit(1);
866446Swnj 	alarm(0);
8716227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
888380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
898380Ssam 		fromp->sin_family);
9011345Ssam 	if (hp == 0) {
91*24722Smckusick 		char buf[BUFSIZ];
92*24722Smckusick 
93*24722Smckusick 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
94*24722Smckusick 			inet_ntoa(fromp->sin_addr)));
9511345Ssam 	}
966446Swnj 	if (fromp->sin_family != AF_INET ||
9716227Skarels 	    fromp->sin_port >= IPPORT_RESERVED)
989242Ssam 		fatal(f, "Permission denied");
996446Swnj 	write(f, "", 1);
1006446Swnj 	for (c = 'p'; c <= 's'; c++) {
1016446Swnj 		struct stat stb;
1026446Swnj 		line = "/dev/ptyXX";
1036446Swnj 		line[strlen("/dev/pty")] = c;
1046446Swnj 		line[strlen("/dev/ptyp")] = '0';
1056446Swnj 		if (stat(line, &stb) < 0)
1066446Swnj 			break;
1076446Swnj 		for (i = 0; i < 16; i++) {
1086446Swnj 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
1096446Swnj 			p = open(line, 2);
1106446Swnj 			if (p > 0)
1116446Swnj 				goto gotpty;
1126446Swnj 		}
1136446Swnj 	}
1149242Ssam 	fatal(f, "All network ports in use");
1159242Ssam 	/*NOTREACHED*/
1166446Swnj gotpty:
11716227Skarels 	netf = f;
1186446Swnj 	line[strlen("/dev/")] = 't';
1196446Swnj #ifdef DEBUG
1206446Swnj 	{ int tt = open("/dev/tty", 2);
1216446Swnj 	  if (tt > 0) {
1226446Swnj 		ioctl(tt, TIOCNOTTY, 0);
1236446Swnj 		close(tt);
1246446Swnj 	  }
1256446Swnj 	}
1266446Swnj #endif
1276446Swnj 	t = open(line, 2);
1289242Ssam 	if (t < 0)
1299242Ssam 		fatalperror(f, line, errno);
1306446Swnj 	{ struct sgttyb b;
1316446Swnj 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
1326446Swnj 	}
1339242Ssam 	pid = fork();
1349242Ssam 	if (pid < 0)
1359242Ssam 		fatalperror(f, "", errno);
13618357Ssam 	if (pid == 0) {
13718357Ssam 		close(f), close(p);
13818357Ssam 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
13916227Skarels 		close(t);
14018357Ssam 		execl("/bin/login", "login", "-r", hp->h_name, 0);
14118357Ssam 		fatalperror(2, "/bin/login", errno);
14218357Ssam 		/*NOTREACHED*/
14318357Ssam 	}
14418357Ssam 	close(t);
14518357Ssam 	ioctl(f, FIONBIO, &on);
14618357Ssam 	ioctl(p, FIONBIO, &on);
14718357Ssam 	ioctl(p, TIOCPKT, &on);
14818357Ssam 	signal(SIGTSTP, SIG_IGN);
14918357Ssam 	signal(SIGCHLD, cleanup);
15018357Ssam 	protocol(f, p);
15118357Ssam 	cleanup();
15218357Ssam }
1539242Ssam 
15418357Ssam char	magic[2] = { 0377, 0377 };
15518357Ssam 
15618357Ssam /*
15718357Ssam  * Handle a "control" request (signaled by magic being present)
15818357Ssam  * in the data stream.  For now, we are only willing to handle
15918357Ssam  * window size changes.
16018357Ssam  */
16118357Ssam control(pty, cp, n)
16218357Ssam 	int pty;
16318357Ssam 	char *cp;
16418357Ssam 	int n;
16518357Ssam {
16618357Ssam 	struct winsize *wp;
16718357Ssam 
16818357Ssam 	if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's')
16918357Ssam 		return (0);
17018357Ssam 	wp = (struct winsize *)(cp+4);
17118357Ssam 	wp->ws_row = ntohs(wp->ws_row);
17218357Ssam 	wp->ws_col = ntohs(wp->ws_col);
17318357Ssam 	wp->ws_xpixel = ntohs(wp->ws_xpixel);
17418357Ssam 	wp->ws_ypixel = ntohs(wp->ws_ypixel);
17518357Ssam 	(void)ioctl(pty, TIOCSWINSZ, wp);
17618357Ssam 	return (4+sizeof (*wp));
17718357Ssam }
17818357Ssam 
17918357Ssam /*
18018357Ssam  * rlogin "protocol" machine.
18118357Ssam  */
18218357Ssam protocol(f, p)
18318357Ssam 	int f, p;
18418357Ssam {
18518357Ssam 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
18618357Ssam 	register pcc = 0, fcc = 0;
18718357Ssam 	int cc, stop = TIOCPKT_DOSTOP;
18818357Ssam 
18918482Ssam 	/*
19018484Ssam 	 * Must ignore SIGTTOU, otherwise we'll stop
19118484Ssam 	 * when we try and set slave pty's window shape
19218484Ssam 	 * (our pgrp is that of the master pty).
19318482Ssam 	 */
19418484Ssam 	(void) signal(SIGTTOU, SIG_IGN);
19518357Ssam 	for (;;) {
19618357Ssam 		int ibits = 0, obits = 0;
19718357Ssam 
19818357Ssam 		if (fcc)
19918357Ssam 			obits |= (1<<p);
20018357Ssam 		else
20118357Ssam 			ibits |= (1<<f);
20218357Ssam 		if (pcc >= 0)
20318357Ssam 			if (pcc)
20418357Ssam 				obits |= (1<<f);
2059242Ssam 			else
20618357Ssam 				ibits |= (1<<p);
20718357Ssam 		if (select(16, &ibits, &obits, 0, 0) < 0) {
20818357Ssam 			if (errno == EINTR)
2096446Swnj 				continue;
21018357Ssam 			fatalperror(f, "select", errno);
21118357Ssam 		}
21218357Ssam 		if (ibits == 0 && obits == 0) {
21318357Ssam 			/* shouldn't happen... */
21418357Ssam 			sleep(5);
21518357Ssam 			continue;
21618357Ssam 		}
21718357Ssam 		if (ibits & (1<<f)) {
21818357Ssam 			fcc = read(f, fibuf, sizeof (fibuf));
21918357Ssam 			if (fcc < 0 && errno == EWOULDBLOCK)
22018357Ssam 				fcc = 0;
22118357Ssam 			else {
22218357Ssam 				register char *cp;
22318357Ssam 				int left, n;
22418357Ssam 
22518357Ssam 				if (fcc <= 0)
22616227Skarels 					break;
22718357Ssam 				fbp = fibuf;
22818357Ssam 			top:
22918357Ssam 				for (cp = fibuf; cp < fibuf+fcc; cp++)
23018357Ssam 					if (cp[0] == magic[0] &&
23118357Ssam 					    cp[1] == magic[1]) {
23218357Ssam 						left = fcc - (cp-fibuf);
23318357Ssam 						n = control(p, cp, left);
23418357Ssam 						if (n) {
23518357Ssam 							left -= n;
23618357Ssam 							if (left > 0)
23718357Ssam 								bcopy(cp, cp+n, left);
23818357Ssam 							fcc -= n;
23918357Ssam 							goto top; /* n^2 */
24018357Ssam 						}
2416446Swnj 					}
2426446Swnj 			}
24318357Ssam 		}
24418357Ssam 		if (ibits & (1<<p)) {
24518357Ssam 			pcc = read(p, pibuf, sizeof (pibuf));
24618357Ssam 			pbp = pibuf;
24718357Ssam 			if (pcc < 0 && errno == EWOULDBLOCK)
24818357Ssam 				pcc = 0;
24918357Ssam 			else if (pcc <= 0)
25018357Ssam 				break;
25118357Ssam 			else if (pibuf[0] == 0)
25218357Ssam 				pbp++, pcc--;
25318357Ssam 			else {
25418357Ssam #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
25518357Ssam 				if (pkcontrol(pibuf[0])) {
25618357Ssam 				/* The following 3 lines do nothing. */
25718357Ssam 					int nstop = pibuf[0] &
25818357Ssam 					    (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP);
25918357Ssam 
26018357Ssam 					if (nstop)
26118357Ssam 						stop = nstop;
26218357Ssam 					pibuf[0] |= nstop;
26318357Ssam 					send(f, &pibuf[0], 1, MSG_OOB);
26416227Skarels 				}
26518357Ssam 				pcc = 0;
2666446Swnj 			}
26718357Ssam 		}
26818357Ssam 		if ((obits & (1<<f)) && pcc > 0) {
26918357Ssam 			cc = write(f, pbp, pcc);
27018357Ssam 			if (cc < 0 && errno == EWOULDBLOCK) {
27118357Ssam 				/* also shouldn't happen */
27218357Ssam 				sleep(5);
27318357Ssam 				continue;
2746446Swnj 			}
27518357Ssam 			if (cc > 0) {
27618357Ssam 				pcc -= cc;
27718357Ssam 				pbp += cc;
27818357Ssam 			}
2796446Swnj 		}
28018357Ssam 		if ((obits & (1<<p)) && fcc > 0) {
28118357Ssam 			cc = write(p, fbp, fcc);
28218357Ssam 			if (cc > 0) {
28318357Ssam 				fcc -= cc;
28418357Ssam 				fbp += cc;
28518357Ssam 			}
28618357Ssam 		}
2876446Swnj 	}
2886446Swnj }
2896446Swnj 
2906446Swnj cleanup()
2916446Swnj {
2926446Swnj 
2936446Swnj 	rmut();
29410009Ssam 	vhangup();		/* XXX */
29510192Ssam 	shutdown(netf, 2);
2966446Swnj 	kill(0, SIGKILL);
2976446Swnj 	exit(1);
2986446Swnj }
2996446Swnj 
3009242Ssam fatal(f, msg)
3019242Ssam 	int f;
3029242Ssam 	char *msg;
3039242Ssam {
3049242Ssam 	char buf[BUFSIZ];
3059242Ssam 
3069242Ssam 	buf[0] = '\01';		/* error indicator */
30713554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3089242Ssam 	(void) write(f, buf, strlen(buf));
3099242Ssam 	exit(1);
3109242Ssam }
3119242Ssam 
3129242Ssam fatalperror(f, msg, errno)
3139242Ssam 	int f;
3149242Ssam 	char *msg;
3159242Ssam 	int errno;
3169242Ssam {
3179242Ssam 	char buf[BUFSIZ];
31816227Skarels 	extern int sys_nerr;
3199242Ssam 	extern char *sys_errlist[];
3209242Ssam 
32118357Ssam 	if ((unsigned)errno < sys_nerr)
32216227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
32316227Skarels 	else
32416227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3259242Ssam 	fatal(f, buf);
3269242Ssam }
3279242Ssam 
3286446Swnj #include <utmp.h>
3296446Swnj 
3306446Swnj struct	utmp wtmp;
3316446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
33223566Sbloom char	utmpf[] = "/etc/utmp";
3336446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
3346446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
3356446Swnj 
3366446Swnj rmut()
3376446Swnj {
3386446Swnj 	register f;
3396446Swnj 	int found = 0;
34023566Sbloom 	struct utmp *u, *utmp;
34123566Sbloom 	int nutmp;
34223566Sbloom 	struct stat statbf;
3436446Swnj 
34423566Sbloom 	f = open(utmpf, O_RDWR);
3456446Swnj 	if (f >= 0) {
34623566Sbloom 		fstat(f, &statbf);
34723566Sbloom 		utmp = (struct utmp *)malloc(statbf.st_size);
34823566Sbloom 		if (!utmp)
34923566Sbloom 			syslog(LOG_ERR, "utmp malloc failed");
35023566Sbloom 		if (statbf.st_size && utmp) {
35123566Sbloom 			nutmp = read(f, utmp, statbf.st_size);
35223566Sbloom 			nutmp /= sizeof(struct utmp);
35323566Sbloom 
35423566Sbloom 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
35523566Sbloom 				if (SCMPN(u->ut_line, line+5) ||
35623566Sbloom 				    u->ut_name[0]==0)
35723566Sbloom 					continue;
35823566Sbloom 				lseek(f, ((long)u)-((long)utmp), L_SET);
35923566Sbloom 				SCPYN(u->ut_name, "");
36023566Sbloom 				SCPYN(u->ut_host, "");
36123566Sbloom 				time(&u->ut_time);
36223566Sbloom 				write(f, (char *)u, sizeof(wtmp));
36323566Sbloom 				found++;
36423566Sbloom 			}
3656446Swnj 		}
3666446Swnj 		close(f);
3676446Swnj 	}
3686446Swnj 	if (found) {
36923566Sbloom 		f = open(wtmpf, O_WRONLY|O_APPEND);
3706446Swnj 		if (f >= 0) {
3716446Swnj 			SCPYN(wtmp.ut_line, line+5);
3726446Swnj 			SCPYN(wtmp.ut_name, "");
37312681Ssam 			SCPYN(wtmp.ut_host, "");
3746446Swnj 			time(&wtmp.ut_time);
3756446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3766446Swnj 			close(f);
3776446Swnj 		}
3786446Swnj 	}
3796446Swnj 	chmod(line, 0666);
3806446Swnj 	chown(line, 0, 0);
3816446Swnj 	line[strlen("/dev/")] = 'p';
3826446Swnj 	chmod(line, 0666);
3836446Swnj 	chown(line, 0, 0);
3846446Swnj }
385