xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 16227)
16446Swnj #ifndef lint
2*16227Skarels static char sccsid[] = "@(#)rlogind.c	4.19 84/03/22";
36446Swnj #endif
46446Swnj 
56446Swnj #include <stdio.h>
66446Swnj #include <sys/types.h>
76446Swnj #include <sys/stat.h>
86446Swnj #include <sys/socket.h>
913554Ssam #include <sys/wait.h>
109208Ssam 
119208Ssam #include <netinet/in.h>
129208Ssam 
136446Swnj #include <errno.h>
146446Swnj #include <pwd.h>
156446Swnj #include <signal.h>
166446Swnj #include <sgtty.h>
176446Swnj #include <stdio.h>
188380Ssam #include <netdb.h>
196446Swnj 
206446Swnj extern	errno;
2110417Ssam int	reapchild();
226446Swnj struct	passwd *getpwnam();
2311345Ssam char	*crypt(), *rindex(), *index(), *malloc(), *ntoa();
248380Ssam struct	sockaddr_in sin = { AF_INET };
256446Swnj /*
266446Swnj  * remote login server:
276446Swnj  *	remuser\0
286446Swnj  *	locuser\0
296446Swnj  *	terminal type\0
306446Swnj  *	data
316446Swnj  */
326446Swnj main(argc, argv)
336446Swnj 	int argc;
346446Swnj 	char **argv;
356446Swnj {
3612216Ssam 	int f, options = 0;
376446Swnj 	struct sockaddr_in from;
388380Ssam 	struct servent *sp;
396446Swnj 
408380Ssam 	sp = getservbyname("login", "tcp");
418380Ssam 	if (sp == 0) {
428380Ssam 		fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n");
438380Ssam 		exit(1);
448380Ssam 	}
456446Swnj #ifndef DEBUG
466446Swnj 	if (fork())
476446Swnj 		exit(0);
486446Swnj 	for (f = 0; f < 10; f++)
496446Swnj 		(void) close(f);
506446Swnj 	(void) open("/", 0);
516446Swnj 	(void) dup2(0, 1);
526446Swnj 	(void) dup2(0, 2);
536446Swnj 	{ int tt = open("/dev/tty", 2);
546446Swnj 	  if (tt > 0) {
556446Swnj 		ioctl(tt, TIOCNOTTY, 0);
566446Swnj 		close(tt);
576446Swnj 	  }
586446Swnj 	}
596446Swnj #endif
609961Ssam 	sin.sin_port = sp->s_port;
616446Swnj 	argc--, argv++;
629208Ssam 	if (argc > 0 && !strcmp(argv[0], "-d")) {
6310417Ssam 		options |= SO_DEBUG;
6410417Ssam 		argc--, argv++;
6510417Ssam 	}
6610417Ssam 	if (argc > 0) {
678380Ssam 		int port = atoi(argv[0]);
688380Ssam 
698380Ssam 		if (port < 0) {
708380Ssam 			fprintf(stderr, "%s: bad port #\n", argv[0]);
718380Ssam 			exit(1);
728380Ssam 		}
739961Ssam 		sin.sin_port = htons((u_short)port);
748380Ssam 		argv++, argc--;
758380Ssam 	}
769259Ssam 	f = socket(AF_INET, SOCK_STREAM, 0, 0);
779208Ssam 	if (f < 0) {
789208Ssam 		perror("rlogind: socket");
799208Ssam 		exit(1);
809208Ssam 	}
8110417Ssam 	if (options & SO_DEBUG)
8210417Ssam 		if (setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
8310417Ssam 			perror("rlogind: setsockopt (SO_DEBUG)");
8410417Ssam 	if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
8512216Ssam 		perror("rlogind: setsockopt (SO_KEEPALIVE)");
869208Ssam 	if (bind(f, &sin, sizeof (sin), 0) < 0) {
879208Ssam 		perror("rlogind: bind");
889208Ssam 		exit(1);
899208Ssam 	}
9013024Ssam 	signal(SIGCHLD, reapchild);
919208Ssam 	listen(f, 10);
926446Swnj 	for (;;) {
939208Ssam 		int s, len = sizeof (from);
949208Ssam 
959208Ssam 		s = accept(f, &from, &len, 0);
969208Ssam 		if (s < 0) {
9710417Ssam 			if (errno == EINTR)
9810417Ssam 				continue;
999242Ssam 			perror("rlogind: accept");
1006446Swnj 			continue;
1016446Swnj 		}
10211222Ssam 		if (fork() == 0) {
10311222Ssam 			signal(SIGCHLD, SIG_IGN);
10413267Ssam 			close(f);
1059208Ssam 			doit(s, &from);
10611222Ssam 		}
1079208Ssam 		close(s);
1086446Swnj 	}
1096446Swnj }
1106446Swnj 
11110417Ssam reapchild()
11210417Ssam {
11310417Ssam 	union wait status;
11410417Ssam 
11510417Ssam 	while (wait3(&status, WNOHANG, 0) > 0)
11610417Ssam 		;
11710417Ssam }
11810417Ssam 
1196446Swnj char	locuser[32], remuser[32];
1206446Swnj char	buf[BUFSIZ];
1216446Swnj int	child;
1226446Swnj int	cleanup();
1236446Swnj int	netf;
1246446Swnj extern	errno;
1256446Swnj char	*line;
1266446Swnj 
1276446Swnj doit(f, fromp)
1286446Swnj 	int f;
1296446Swnj 	struct sockaddr_in *fromp;
1306446Swnj {
1318380Ssam 	char c;
1329242Ssam 	int i, p, cc, t, pid;
1336446Swnj 	int stop = TIOCPKT_DOSTOP;
1348380Ssam 	register struct hostent *hp;
1356446Swnj 
1366446Swnj 	alarm(60);
1376446Swnj 	read(f, &c, 1);
1386446Swnj 	if (c != 0)
1396446Swnj 		exit(1);
1406446Swnj 	alarm(0);
141*16227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
1428380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
1438380Ssam 		fromp->sin_family);
14411345Ssam 	if (hp == 0) {
145*16227Skarels 		char buf[BUFSIZ];
14611345Ssam 
14711345Ssam 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
14811345Ssam 			ntoa(fromp->sin_addr)));
14911345Ssam 	}
1506446Swnj 	if (fromp->sin_family != AF_INET ||
151*16227Skarels 	    fromp->sin_port >= IPPORT_RESERVED)
1529242Ssam 		fatal(f, "Permission denied");
1536446Swnj 	write(f, "", 1);
1546446Swnj 	for (c = 'p'; c <= 's'; c++) {
1556446Swnj 		struct stat stb;
1566446Swnj 		line = "/dev/ptyXX";
1576446Swnj 		line[strlen("/dev/pty")] = c;
1586446Swnj 		line[strlen("/dev/ptyp")] = '0';
1596446Swnj 		if (stat(line, &stb) < 0)
1606446Swnj 			break;
1616446Swnj 		for (i = 0; i < 16; i++) {
1626446Swnj 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
1636446Swnj 			p = open(line, 2);
1646446Swnj 			if (p > 0)
1656446Swnj 				goto gotpty;
1666446Swnj 		}
1676446Swnj 	}
1689242Ssam 	fatal(f, "All network ports in use");
1699242Ssam 	/*NOTREACHED*/
1706446Swnj gotpty:
171*16227Skarels 	netf = f;
1726446Swnj 	line[strlen("/dev/")] = 't';
1736446Swnj #ifdef DEBUG
1746446Swnj 	{ int tt = open("/dev/tty", 2);
1756446Swnj 	  if (tt > 0) {
1766446Swnj 		ioctl(tt, TIOCNOTTY, 0);
1776446Swnj 		close(tt);
1786446Swnj 	  }
1796446Swnj 	}
1806446Swnj #endif
1816446Swnj 	t = open(line, 2);
1829242Ssam 	if (t < 0)
1839242Ssam 		fatalperror(f, line, errno);
1846446Swnj 	{ struct sgttyb b;
1856446Swnj 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
1866446Swnj 	}
1879242Ssam 	pid = fork();
1889242Ssam 	if (pid < 0)
1899242Ssam 		fatalperror(f, "", errno);
1909242Ssam 	if (pid) {
1916446Swnj 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
192*16227Skarels 		register pcc = 0, fcc = 0;
193*16227Skarels 		int on = 1;
1946446Swnj /* FILE *console = fopen("/dev/console", "w");  */
1956446Swnj /* setbuf(console, 0); */
1966446Swnj 
1976446Swnj /* fprintf(console, "f %d p %d\r\n", f, p); */
198*16227Skarels 		close(t);
1996446Swnj 		ioctl(f, FIONBIO, &on);
2006446Swnj 		ioctl(p, FIONBIO, &on);
2016446Swnj 		ioctl(p, TIOCPKT, &on);
2026446Swnj 		signal(SIGTSTP, SIG_IGN);
20313024Ssam 		signal(SIGCHLD, cleanup);
2046446Swnj 		for (;;) {
2056446Swnj 			int ibits = 0, obits = 0;
2069242Ssam 
2079242Ssam 			if (fcc)
2089242Ssam 				obits |= (1<<p);
2099242Ssam 			else
2109242Ssam 				ibits |= (1<<f);
2116446Swnj 			if (pcc >= 0)
2129242Ssam 				if (pcc)
2139242Ssam 					obits |= (1<<f);
2149242Ssam 				else
2159242Ssam 					ibits |= (1<<p);
2166446Swnj /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
217*16227Skarels 			if (select(16, &ibits, &obits, 0, 0) < 0) {
218*16227Skarels 				if (errno == EINTR)
219*16227Skarels 					continue;
220*16227Skarels 				fatalperror(f, "select", errno);
221*16227Skarels 			}
2226446Swnj /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
2236446Swnj 			if (ibits == 0 && obits == 0) {
224*16227Skarels 				/* shouldn't happen... */
2256446Swnj 				sleep(5);
2266446Swnj 				continue;
2276446Swnj 			}
2286446Swnj 			if (ibits & (1<<f)) {
2296446Swnj 				fcc = read(f, fibuf, sizeof (fibuf));
2306446Swnj /* fprintf(console, "%d from f\r\n", fcc); */
2316446Swnj 				if (fcc < 0 && errno == EWOULDBLOCK)
2326446Swnj 					fcc = 0;
2336446Swnj 				else {
2346446Swnj 					if (fcc <= 0)
2356446Swnj 						break;
2366446Swnj 					fbp = fibuf;
2376446Swnj 				}
2386446Swnj 			}
2396446Swnj 			if (ibits & (1<<p)) {
2406446Swnj 				pcc = read(p, pibuf, sizeof (pibuf));
2416446Swnj /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
2426446Swnj 				pbp = pibuf;
2436446Swnj 				if (pcc < 0 && errno == EWOULDBLOCK)
2446446Swnj 					pcc = 0;
2456446Swnj 				else if (pcc <= 0)
246*16227Skarels 					break;
2476446Swnj 				else if (pibuf[0] == 0)
2486446Swnj 					pbp++, pcc--;
2496446Swnj 				else {
2506446Swnj 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
2516446Swnj 						      TIOCPKT_NOSTOP|
2526446Swnj 						      TIOCPKT_DOSTOP)) {
253*16227Skarels 					/* The following 3 lines do nothing. */
2546446Swnj 						int nstop = pibuf[0] &
2556446Swnj 						    (TIOCPKT_NOSTOP|
2566446Swnj 						     TIOCPKT_DOSTOP);
2576446Swnj 						if (nstop)
2586446Swnj 							stop = nstop;
2596446Swnj 						pibuf[0] |= nstop;
26012898Ssam 						send(f,&pibuf[0],1,MSG_OOB);
2616446Swnj 					}
2626446Swnj 					pcc = 0;
2636446Swnj 				}
2646446Swnj 			}
2656446Swnj 			if ((obits & (1<<f)) && pcc > 0) {
2666446Swnj 				cc = write(f, pbp, pcc);
267*16227Skarels 				if (cc < 0 && errno == EWOULDBLOCK) {
268*16227Skarels 					/* also shouldn't happen */
269*16227Skarels 					sleep(5);
270*16227Skarels 					continue;
271*16227Skarels 				}
2726446Swnj /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
2736446Swnj 				if (cc > 0) {
2746446Swnj 					pcc -= cc;
2756446Swnj 					pbp += cc;
2766446Swnj 				}
2776446Swnj 			}
2786446Swnj 			if ((obits & (1<<p)) && fcc > 0) {
2796446Swnj 				cc = write(p, fbp, fcc);
2806446Swnj /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
2816446Swnj 				if (cc > 0) {
2826446Swnj 					fcc -= cc;
2836446Swnj 					fbp += cc;
2846446Swnj 				}
2856446Swnj 			}
2866446Swnj 		}
2876446Swnj 		cleanup();
2886446Swnj 	}
2896446Swnj 	close(f);
2906446Swnj 	close(p);
2916446Swnj 	dup2(t, 0);
2926446Swnj 	dup2(t, 1);
2936446Swnj 	dup2(t, 2);
2946446Swnj 	close(t);
2958380Ssam 	execl("/bin/login", "login", "-r", hp->h_name, 0);
2969242Ssam 	fatalperror(2, "/bin/login", errno);
2979242Ssam 	/*NOTREACHED*/
2986446Swnj }
2996446Swnj 
3006446Swnj cleanup()
3016446Swnj {
3026446Swnj 
3036446Swnj 	rmut();
30410009Ssam 	vhangup();		/* XXX */
30510192Ssam 	shutdown(netf, 2);
3066446Swnj 	kill(0, SIGKILL);
3076446Swnj 	exit(1);
3086446Swnj }
3096446Swnj 
3109242Ssam fatal(f, msg)
3119242Ssam 	int f;
3129242Ssam 	char *msg;
3139242Ssam {
3149242Ssam 	char buf[BUFSIZ];
3159242Ssam 
3169242Ssam 	buf[0] = '\01';		/* error indicator */
31713554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
3189242Ssam 	(void) write(f, buf, strlen(buf));
3199242Ssam 	exit(1);
3209242Ssam }
3219242Ssam 
3229242Ssam fatalperror(f, msg, errno)
3239242Ssam 	int f;
3249242Ssam 	char *msg;
3259242Ssam 	int errno;
3269242Ssam {
3279242Ssam 	char buf[BUFSIZ];
328*16227Skarels 	extern int sys_nerr;
3299242Ssam 	extern char *sys_errlist[];
3309242Ssam 
331*16227Skarels 	if ((unsigned) errno < sys_nerr)
332*16227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
333*16227Skarels 	else
334*16227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3359242Ssam 	fatal(f, buf);
3369242Ssam }
3379242Ssam 
3386446Swnj #include <utmp.h>
3396446Swnj 
3406446Swnj struct	utmp wtmp;
3416446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
3426446Swnj char	utmp[] = "/etc/utmp";
3436446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
3446446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
3456446Swnj 
3466446Swnj rmut()
3476446Swnj {
3486446Swnj 	register f;
3496446Swnj 	int found = 0;
3506446Swnj 
3516446Swnj 	f = open(utmp, 2);
3526446Swnj 	if (f >= 0) {
3536446Swnj 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
3546446Swnj 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
3556446Swnj 				continue;
3566446Swnj 			lseek(f, -(long)sizeof(wtmp), 1);
3576446Swnj 			SCPYN(wtmp.ut_name, "");
35812681Ssam 			SCPYN(wtmp.ut_host, "");
3596446Swnj 			time(&wtmp.ut_time);
3606446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3616446Swnj 			found++;
3626446Swnj 		}
3636446Swnj 		close(f);
3646446Swnj 	}
3656446Swnj 	if (found) {
3666446Swnj 		f = open(wtmpf, 1);
3676446Swnj 		if (f >= 0) {
3686446Swnj 			SCPYN(wtmp.ut_line, line+5);
3696446Swnj 			SCPYN(wtmp.ut_name, "");
37012681Ssam 			SCPYN(wtmp.ut_host, "");
3716446Swnj 			time(&wtmp.ut_time);
3726446Swnj 			lseek(f, (long)0, 2);
3736446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3746446Swnj 			close(f);
3756446Swnj 		}
3766446Swnj 	}
3776446Swnj 	chmod(line, 0666);
3786446Swnj 	chown(line, 0, 0);
3796446Swnj 	line[strlen("/dev/")] = 'p';
3806446Swnj 	chmod(line, 0666);
3816446Swnj 	chown(line, 0, 0);
3826446Swnj }
38311345Ssam 
38411345Ssam /*
38511345Ssam  * Convert network-format internet address
38611345Ssam  * to base 256 d.d.d.d representation.
38711345Ssam  */
38811345Ssam char *
38911345Ssam ntoa(in)
39011345Ssam 	struct in_addr in;
39111345Ssam {
39211345Ssam 	static char b[18];
39311345Ssam 	register char *p;
39411345Ssam 
39511345Ssam 	p = (char *)&in;
39611345Ssam #define	UC(b)	(((int)b)&0xff)
39711345Ssam 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
39811345Ssam 	return (b);
39911345Ssam }
400