xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 8380)
16446Swnj #ifndef lint
2*8380Ssam static char sccsid[] = "@(#)rlogind.c	4.2 82/10/07";
36446Swnj #endif
46446Swnj 
56446Swnj #include <stdio.h>
66446Swnj #include <sys/types.h>
76446Swnj #include <sys/stat.h>
86446Swnj #include <sys/socket.h>
96446Swnj #include <net/in.h>
106446Swnj #include <errno.h>
116446Swnj #include <pwd.h>
126446Swnj #include <wait.h>
136446Swnj #include <signal.h>
146446Swnj #include <sgtty.h>
156446Swnj #include <stdio.h>
16*8380Ssam #include <netdb.h>
176446Swnj 
186446Swnj extern	errno;
196446Swnj struct	passwd *getpwnam();
20*8380Ssam char	*crypt(), *rindex(), *index(), *malloc();
216446Swnj int	options = SO_ACCEPTCONN|SO_KEEPALIVE;
22*8380Ssam struct	sockaddr_in sin = { AF_INET };
236446Swnj /*
246446Swnj  * remote login server:
256446Swnj  *	remuser\0
266446Swnj  *	locuser\0
276446Swnj  *	terminal type\0
286446Swnj  *	data
296446Swnj  */
306446Swnj main(argc, argv)
316446Swnj 	int argc;
326446Swnj 	char **argv;
336446Swnj {
346446Swnj 	union wait status;
356446Swnj 	int f, debug = 0;
366446Swnj 	struct sockaddr_in from;
37*8380Ssam 	struct servent *sp;
386446Swnj 
39*8380Ssam 	sp = getservbyname("login", "tcp");
40*8380Ssam 	if (sp == 0) {
41*8380Ssam 		fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n");
42*8380Ssam 		exit(1);
43*8380Ssam 	}
446446Swnj #ifndef DEBUG
456446Swnj 	if (fork())
466446Swnj 		exit(0);
476446Swnj 	for (f = 0; f < 10; f++)
486446Swnj 		(void) close(f);
496446Swnj 	(void) open("/", 0);
506446Swnj 	(void) dup2(0, 1);
516446Swnj 	(void) dup2(0, 2);
526446Swnj 	{ int tt = open("/dev/tty", 2);
536446Swnj 	  if (tt > 0) {
546446Swnj 		ioctl(tt, TIOCNOTTY, 0);
556446Swnj 		close(tt);
566446Swnj 	  }
576446Swnj 	}
586446Swnj #endif
59*8380Ssam 	sin.sin_port = htons(sp->s_port);
606446Swnj 	argc--, argv++;
616446Swnj 	if (argc > 0 && !strcmp(argv[0], "-d"))
62*8380Ssam 		options |= SO_DEBUG, argv++, argc--;
63*8380Ssam 	if (argc > 0) {
64*8380Ssam 		int port = atoi(argv[0]);
65*8380Ssam 
66*8380Ssam 		if (port < 0) {
67*8380Ssam 			fprintf(stderr, "%s: bad port #\n", argv[0]);
68*8380Ssam 			exit(1);
69*8380Ssam 		}
70*8380Ssam 		sin.sin_port = htons(port);
71*8380Ssam 		argv++, argc--;
72*8380Ssam 	}
736446Swnj 	for (;;) {
746446Swnj 		f = socket(SOCK_STREAM, 0, &sin, options);
756446Swnj 		if (f < 0) {
766446Swnj 			perror("socket");
776446Swnj 			sleep(5);
786446Swnj 			continue;
796446Swnj 		}
806446Swnj 		if (accept(f, &from) < 0) {
816446Swnj 			perror("accept");
826446Swnj 			close(f);
836446Swnj 			sleep(1);
846446Swnj 			continue;
856446Swnj 		}
866446Swnj 		if (fork() == 0)
876446Swnj 			doit(f, &from);
886446Swnj 		close(f);
896446Swnj 		while (wait3(status, WNOHANG, 0) > 0)
906446Swnj 			continue;
916446Swnj 	}
926446Swnj }
936446Swnj 
946446Swnj char	locuser[32], remuser[32];
956446Swnj char	buf[BUFSIZ];
966446Swnj int	child;
976446Swnj int	cleanup();
986446Swnj int	netf;
996446Swnj extern	errno;
1006446Swnj char	*line;
1016446Swnj 
1026446Swnj doit(f, fromp)
1036446Swnj 	int f;
1046446Swnj 	struct sockaddr_in *fromp;
1056446Swnj {
106*8380Ssam 	char c;
1076446Swnj 	int i, p, cc, t;
1086446Swnj 	int stop = TIOCPKT_DOSTOP;
109*8380Ssam 	register struct hostent *hp;
1106446Swnj 
1116446Swnj 	alarm(60);
1126446Swnj 	read(f, &c, 1);
1136446Swnj 	if (c != 0)
1146446Swnj 		exit(1);
1156446Swnj 	alarm(0);
1166446Swnj 	fromp->sin_port = htons(fromp->sin_port);
117*8380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
118*8380Ssam 		fromp->sin_family);
1196446Swnj 	if (fromp->sin_family != AF_INET ||
1206446Swnj 	    fromp->sin_port >= IPPORT_RESERVED ||
121*8380Ssam 	    hp == 0) {
1226446Swnj 		write(f, "\01Permission denied.\n", 20);
1236446Swnj 		exit(1);
1246446Swnj 	}
1256446Swnj 	write(f, "", 1);
1266446Swnj 	for (c = 'p'; c <= 's'; c++) {
1276446Swnj 		struct stat stb;
1286446Swnj 		line = "/dev/ptyXX";
1296446Swnj 		line[strlen("/dev/pty")] = c;
1306446Swnj 		line[strlen("/dev/ptyp")] = '0';
1316446Swnj 		if (stat(line, &stb) < 0)
1326446Swnj 			break;
1336446Swnj 		for (i = 0; i < 16; i++) {
1346446Swnj 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
1356446Swnj 			p = open(line, 2);
1366446Swnj 			if (p > 0)
1376446Swnj 				goto gotpty;
1386446Swnj 		}
1396446Swnj 	}
1406446Swnj 	dup2(f, 1);
1416446Swnj 	printf("All network ports in use.\r\n");
1426446Swnj 	exit(1);
1436446Swnj gotpty:
1446446Swnj 	dup2(f, 0);
1456446Swnj 	line[strlen("/dev/")] = 't';
1466446Swnj #ifdef DEBUG
1476446Swnj 	{ int tt = open("/dev/tty", 2);
1486446Swnj 	  if (tt > 0) {
1496446Swnj 		ioctl(tt, TIOCNOTTY, 0);
1506446Swnj 		close(tt);
1516446Swnj 	  }
1526446Swnj 	}
1536446Swnj #endif
1546446Swnj 	t = open(line, 2);
1556446Swnj 	if (t < 0) {
1566446Swnj 		dup2(f, 2);
1576446Swnj 		perror(line);
1586446Swnj 		exit(1);
1596446Swnj 	}
1606446Swnj 	{ struct sgttyb b;
1616446Swnj 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
1626446Swnj 	}
1636446Swnj 	if (fork()) {
1646446Swnj 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
1656446Swnj 		int pcc = 0, fcc = 0, on = 1;
1666446Swnj /* FILE *console = fopen("/dev/console", "w");  */
1676446Swnj /* setbuf(console, 0); */
1686446Swnj 
1696446Swnj /* fprintf(console, "f %d p %d\r\n", f, p); */
1706446Swnj 		ioctl(f, FIONBIO, &on);
1716446Swnj 		ioctl(p, FIONBIO, &on);
1726446Swnj 		ioctl(p, TIOCPKT, &on);
1736446Swnj 		signal(SIGTSTP, SIG_IGN);
1746446Swnj 		sigset(SIGCHLD, cleanup);
1756446Swnj 		for (;;) {
1766446Swnj 			int ibits = 0, obits = 0;
1776446Swnj 			if (fcc) obits |= (1<<p); else ibits |= (1<<f);
1786446Swnj 			if (pcc >= 0)
1796446Swnj 			if (pcc) obits |= (1<<f); else ibits |= (1<<p);
1806446Swnj 			if (fcc < 0 && pcc < 0) break;
1816446Swnj /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
1826446Swnj 			select(32, &ibits, &obits, 10000000);
1836446Swnj /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
1846446Swnj 			if (ibits == 0 && obits == 0) {
1856446Swnj 				sleep(5);
1866446Swnj 				continue;
1876446Swnj 			}
1886446Swnj 			if (ibits & (1<<f)) {
1896446Swnj 				fcc = read(f, fibuf, sizeof (fibuf));
1906446Swnj /* fprintf(console, "%d from f\r\n", fcc); */
1916446Swnj 				if (fcc < 0 && errno == EWOULDBLOCK)
1926446Swnj 					fcc = 0;
1936446Swnj 				else {
1946446Swnj 					if (fcc <= 0)
1956446Swnj 						break;
1966446Swnj 					fbp = fibuf;
1976446Swnj 				}
1986446Swnj 			}
1996446Swnj 			if (ibits & (1<<p)) {
2006446Swnj 				pcc = read(p, pibuf, sizeof (pibuf));
2016446Swnj /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
2026446Swnj 				pbp = pibuf;
2036446Swnj 				if (pcc < 0 && errno == EWOULDBLOCK)
2046446Swnj 					pcc = 0;
2056446Swnj 				else if (pcc <= 0)
2066446Swnj 					pcc = -1;
2076446Swnj 				else if (pibuf[0] == 0)
2086446Swnj 					pbp++, pcc--;
2096446Swnj 				else {
2106446Swnj 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
2116446Swnj 						      TIOCPKT_NOSTOP|
2126446Swnj 						      TIOCPKT_DOSTOP)) {
2136446Swnj 						int nstop = pibuf[0] &
2146446Swnj 						    (TIOCPKT_NOSTOP|
2156446Swnj 						     TIOCPKT_DOSTOP);
2166446Swnj 						if (nstop)
2176446Swnj 							stop = nstop;
2186446Swnj 						pibuf[0] |= nstop;
2196446Swnj 						ioctl(f,SIOCSENDOOB,&pibuf[0]);
2206446Swnj 					}
2216446Swnj 					pcc = 0;
2226446Swnj 				}
2236446Swnj 			}
2246446Swnj 			if ((obits & (1<<f)) && pcc > 0) {
2256446Swnj 				cc = write(f, pbp, pcc);
2266446Swnj /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
2276446Swnj 				if (cc > 0) {
2286446Swnj 					pcc -= cc;
2296446Swnj 					pbp += cc;
2306446Swnj 				}
2316446Swnj 			}
2326446Swnj 			if ((obits & (1<<p)) && fcc > 0) {
2336446Swnj 				cc = write(p, fbp, fcc);
2346446Swnj /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
2356446Swnj 				if (cc > 0) {
2366446Swnj 					fcc -= cc;
2376446Swnj 					fbp += cc;
2386446Swnj 				}
2396446Swnj 			}
2406446Swnj 		}
2416446Swnj 		cleanup();
2426446Swnj 	}
2436446Swnj 	close(f);
2446446Swnj 	close(p);
2456446Swnj 	dup2(t, 0);
2466446Swnj 	dup2(t, 1);
2476446Swnj 	dup2(t, 2);
2486446Swnj 	close(t);
249*8380Ssam 	execl("/bin/login", "login", "-r", hp->h_name, 0);
2506446Swnj 	perror("/bin/login");
2516446Swnj 	exit(1);
2526446Swnj }
2536446Swnj 
2546446Swnj cleanup()
2556446Swnj {
2566446Swnj 	int how = 2;
2576446Swnj 
2586446Swnj 	rmut();
2596446Swnj 	ioctl(netf, SIOCDONE, &how);
2606446Swnj 	kill(0, SIGKILL);
2616446Swnj 	exit(1);
2626446Swnj }
2636446Swnj 
2646446Swnj #include <utmp.h>
2656446Swnj 
2666446Swnj struct	utmp wtmp;
2676446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
2686446Swnj char	utmp[] = "/etc/utmp";
2696446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
2706446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
2716446Swnj 
2726446Swnj rmut()
2736446Swnj {
2746446Swnj 	register f;
2756446Swnj 	int found = 0;
2766446Swnj 
2776446Swnj 	f = open(utmp, 2);
2786446Swnj 	if (f >= 0) {
2796446Swnj 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
2806446Swnj 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
2816446Swnj 				continue;
2826446Swnj 			lseek(f, -(long)sizeof(wtmp), 1);
2836446Swnj 			SCPYN(wtmp.ut_name, "");
2846446Swnj 			time(&wtmp.ut_time);
2856446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
2866446Swnj 			found++;
2876446Swnj 		}
2886446Swnj 		close(f);
2896446Swnj 	}
2906446Swnj 	if (found) {
2916446Swnj 		f = open(wtmpf, 1);
2926446Swnj 		if (f >= 0) {
2936446Swnj 			SCPYN(wtmp.ut_line, line+5);
2946446Swnj 			SCPYN(wtmp.ut_name, "");
2956446Swnj 			time(&wtmp.ut_time);
2966446Swnj 			lseek(f, (long)0, 2);
2976446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
2986446Swnj 			close(f);
2996446Swnj 		}
3006446Swnj 	}
3016446Swnj 	chmod(line, 0666);
3026446Swnj 	chown(line, 0, 0);
3036446Swnj 	line[strlen("/dev/")] = 'p';
3046446Swnj 	chmod(line, 0666);
3056446Swnj 	chown(line, 0, 0);
3066446Swnj }
307