xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 17187)
16446Swnj #ifndef lint
2*17187Sralph static	char sccsid[] = "@(#)rlogind.c	4.22 (Berkeley) 09/13/84";
36446Swnj #endif
46446Swnj 
516369Skarels /*
616369Skarels  * remote login server:
716369Skarels  *	remuser\0
816369Skarels  *	locuser\0
916369Skarels  *	terminal type\0
1016369Skarels  *	data
1116369Skarels  */
1216369Skarels 
136446Swnj #include <stdio.h>
146446Swnj #include <sys/types.h>
156446Swnj #include <sys/stat.h>
166446Swnj #include <sys/socket.h>
1713554Ssam #include <sys/wait.h>
189208Ssam 
199208Ssam #include <netinet/in.h>
209208Ssam 
216446Swnj #include <errno.h>
226446Swnj #include <pwd.h>
236446Swnj #include <signal.h>
246446Swnj #include <sgtty.h>
256446Swnj #include <stdio.h>
268380Ssam #include <netdb.h>
27*17187Sralph #include <syslog.h>
286446Swnj 
296446Swnj extern	errno;
3010417Ssam int	reapchild();
316446Swnj struct	passwd *getpwnam();
3211345Ssam char	*crypt(), *rindex(), *index(), *malloc(), *ntoa();
3316369Skarels 
346446Swnj main(argc, argv)
356446Swnj 	int argc;
366446Swnj 	char **argv;
376446Swnj {
3817156Ssam 	int on = 1, options = 0, fromlen;
396446Swnj 	struct sockaddr_in from;
406446Swnj 
4116369Skarels 	fromlen = sizeof (from);
4216369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
4316369Skarels 		fprintf(stderr, "%s: ", argv[0]);
4416369Skarels 		perror("getpeername");
4516369Skarels 		_exit(1);
468380Ssam 	}
4717156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
48*17187Sralph 		openlog(argv[0], LOG_PID, 0);
49*17187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
506446Swnj 	}
5116369Skarels 	doit(0, &from);
526446Swnj }
536446Swnj 
546446Swnj char	locuser[32], remuser[32];
556446Swnj char	buf[BUFSIZ];
566446Swnj int	child;
576446Swnj int	cleanup();
586446Swnj int	netf;
596446Swnj extern	errno;
606446Swnj char	*line;
616446Swnj 
626446Swnj doit(f, fromp)
636446Swnj 	int f;
646446Swnj 	struct sockaddr_in *fromp;
656446Swnj {
668380Ssam 	char c;
679242Ssam 	int i, p, cc, t, pid;
686446Swnj 	int stop = TIOCPKT_DOSTOP;
698380Ssam 	register struct hostent *hp;
706446Swnj 
716446Swnj 	alarm(60);
726446Swnj 	read(f, &c, 1);
736446Swnj 	if (c != 0)
746446Swnj 		exit(1);
756446Swnj 	alarm(0);
7616227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
778380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
788380Ssam 		fromp->sin_family);
7911345Ssam 	if (hp == 0) {
8016227Skarels 		char buf[BUFSIZ];
8111345Ssam 
8211345Ssam 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
8311345Ssam 			ntoa(fromp->sin_addr)));
8411345Ssam 	}
856446Swnj 	if (fromp->sin_family != AF_INET ||
8616227Skarels 	    fromp->sin_port >= IPPORT_RESERVED)
879242Ssam 		fatal(f, "Permission denied");
886446Swnj 	write(f, "", 1);
896446Swnj 	for (c = 'p'; c <= 's'; c++) {
906446Swnj 		struct stat stb;
916446Swnj 		line = "/dev/ptyXX";
926446Swnj 		line[strlen("/dev/pty")] = c;
936446Swnj 		line[strlen("/dev/ptyp")] = '0';
946446Swnj 		if (stat(line, &stb) < 0)
956446Swnj 			break;
966446Swnj 		for (i = 0; i < 16; i++) {
976446Swnj 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
986446Swnj 			p = open(line, 2);
996446Swnj 			if (p > 0)
1006446Swnj 				goto gotpty;
1016446Swnj 		}
1026446Swnj 	}
1039242Ssam 	fatal(f, "All network ports in use");
1049242Ssam 	/*NOTREACHED*/
1056446Swnj gotpty:
10616227Skarels 	netf = f;
1076446Swnj 	line[strlen("/dev/")] = 't';
1086446Swnj #ifdef DEBUG
1096446Swnj 	{ int tt = open("/dev/tty", 2);
1106446Swnj 	  if (tt > 0) {
1116446Swnj 		ioctl(tt, TIOCNOTTY, 0);
1126446Swnj 		close(tt);
1136446Swnj 	  }
1146446Swnj 	}
1156446Swnj #endif
1166446Swnj 	t = open(line, 2);
1179242Ssam 	if (t < 0)
1189242Ssam 		fatalperror(f, line, errno);
1196446Swnj 	{ struct sgttyb b;
1206446Swnj 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
1216446Swnj 	}
1229242Ssam 	pid = fork();
1239242Ssam 	if (pid < 0)
1249242Ssam 		fatalperror(f, "", errno);
1259242Ssam 	if (pid) {
1266446Swnj 		char pibuf[1024], fibuf[1024], *pbp, *fbp;
12716227Skarels 		register pcc = 0, fcc = 0;
12816227Skarels 		int on = 1;
1296446Swnj /* FILE *console = fopen("/dev/console", "w");  */
1306446Swnj /* setbuf(console, 0); */
1316446Swnj 
1326446Swnj /* fprintf(console, "f %d p %d\r\n", f, p); */
13316227Skarels 		close(t);
1346446Swnj 		ioctl(f, FIONBIO, &on);
1356446Swnj 		ioctl(p, FIONBIO, &on);
1366446Swnj 		ioctl(p, TIOCPKT, &on);
1376446Swnj 		signal(SIGTSTP, SIG_IGN);
13813024Ssam 		signal(SIGCHLD, cleanup);
1396446Swnj 		for (;;) {
1406446Swnj 			int ibits = 0, obits = 0;
1419242Ssam 
1429242Ssam 			if (fcc)
1439242Ssam 				obits |= (1<<p);
1449242Ssam 			else
1459242Ssam 				ibits |= (1<<f);
1466446Swnj 			if (pcc >= 0)
1479242Ssam 				if (pcc)
1489242Ssam 					obits |= (1<<f);
1499242Ssam 				else
1509242Ssam 					ibits |= (1<<p);
1516446Swnj /* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
15216227Skarels 			if (select(16, &ibits, &obits, 0, 0) < 0) {
15316227Skarels 				if (errno == EINTR)
15416227Skarels 					continue;
15516227Skarels 				fatalperror(f, "select", errno);
15616227Skarels 			}
1576446Swnj /* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
1586446Swnj 			if (ibits == 0 && obits == 0) {
15916227Skarels 				/* shouldn't happen... */
1606446Swnj 				sleep(5);
1616446Swnj 				continue;
1626446Swnj 			}
1636446Swnj 			if (ibits & (1<<f)) {
1646446Swnj 				fcc = read(f, fibuf, sizeof (fibuf));
1656446Swnj /* fprintf(console, "%d from f\r\n", fcc); */
1666446Swnj 				if (fcc < 0 && errno == EWOULDBLOCK)
1676446Swnj 					fcc = 0;
1686446Swnj 				else {
1696446Swnj 					if (fcc <= 0)
1706446Swnj 						break;
1716446Swnj 					fbp = fibuf;
1726446Swnj 				}
1736446Swnj 			}
1746446Swnj 			if (ibits & (1<<p)) {
1756446Swnj 				pcc = read(p, pibuf, sizeof (pibuf));
1766446Swnj /* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
1776446Swnj 				pbp = pibuf;
1786446Swnj 				if (pcc < 0 && errno == EWOULDBLOCK)
1796446Swnj 					pcc = 0;
1806446Swnj 				else if (pcc <= 0)
18116227Skarels 					break;
1826446Swnj 				else if (pibuf[0] == 0)
1836446Swnj 					pbp++, pcc--;
1846446Swnj 				else {
1856446Swnj 					if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
1866446Swnj 						      TIOCPKT_NOSTOP|
1876446Swnj 						      TIOCPKT_DOSTOP)) {
18816227Skarels 					/* The following 3 lines do nothing. */
1896446Swnj 						int nstop = pibuf[0] &
1906446Swnj 						    (TIOCPKT_NOSTOP|
1916446Swnj 						     TIOCPKT_DOSTOP);
1926446Swnj 						if (nstop)
1936446Swnj 							stop = nstop;
1946446Swnj 						pibuf[0] |= nstop;
19512898Ssam 						send(f,&pibuf[0],1,MSG_OOB);
1966446Swnj 					}
1976446Swnj 					pcc = 0;
1986446Swnj 				}
1996446Swnj 			}
2006446Swnj 			if ((obits & (1<<f)) && pcc > 0) {
2016446Swnj 				cc = write(f, pbp, pcc);
20216227Skarels 				if (cc < 0 && errno == EWOULDBLOCK) {
20316227Skarels 					/* also shouldn't happen */
20416227Skarels 					sleep(5);
20516227Skarels 					continue;
20616227Skarels 				}
2076446Swnj /* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
2086446Swnj 				if (cc > 0) {
2096446Swnj 					pcc -= cc;
2106446Swnj 					pbp += cc;
2116446Swnj 				}
2126446Swnj 			}
2136446Swnj 			if ((obits & (1<<p)) && fcc > 0) {
2146446Swnj 				cc = write(p, fbp, fcc);
2156446Swnj /* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
2166446Swnj 				if (cc > 0) {
2176446Swnj 					fcc -= cc;
2186446Swnj 					fbp += cc;
2196446Swnj 				}
2206446Swnj 			}
2216446Swnj 		}
2226446Swnj 		cleanup();
2236446Swnj 	}
2246446Swnj 	close(f);
2256446Swnj 	close(p);
2266446Swnj 	dup2(t, 0);
2276446Swnj 	dup2(t, 1);
2286446Swnj 	dup2(t, 2);
2296446Swnj 	close(t);
2308380Ssam 	execl("/bin/login", "login", "-r", hp->h_name, 0);
2319242Ssam 	fatalperror(2, "/bin/login", errno);
2329242Ssam 	/*NOTREACHED*/
2336446Swnj }
2346446Swnj 
2356446Swnj cleanup()
2366446Swnj {
2376446Swnj 
2386446Swnj 	rmut();
23910009Ssam 	vhangup();		/* XXX */
24010192Ssam 	shutdown(netf, 2);
2416446Swnj 	kill(0, SIGKILL);
2426446Swnj 	exit(1);
2436446Swnj }
2446446Swnj 
2459242Ssam fatal(f, msg)
2469242Ssam 	int f;
2479242Ssam 	char *msg;
2489242Ssam {
2499242Ssam 	char buf[BUFSIZ];
2509242Ssam 
2519242Ssam 	buf[0] = '\01';		/* error indicator */
25213554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
2539242Ssam 	(void) write(f, buf, strlen(buf));
2549242Ssam 	exit(1);
2559242Ssam }
2569242Ssam 
2579242Ssam fatalperror(f, msg, errno)
2589242Ssam 	int f;
2599242Ssam 	char *msg;
2609242Ssam 	int errno;
2619242Ssam {
2629242Ssam 	char buf[BUFSIZ];
26316227Skarels 	extern int sys_nerr;
2649242Ssam 	extern char *sys_errlist[];
2659242Ssam 
26616227Skarels 	if ((unsigned) errno < sys_nerr)
26716227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
26816227Skarels 	else
26916227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
2709242Ssam 	fatal(f, buf);
2719242Ssam }
2729242Ssam 
2736446Swnj #include <utmp.h>
2746446Swnj 
2756446Swnj struct	utmp wtmp;
2766446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
2776446Swnj char	utmp[] = "/etc/utmp";
2786446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
2796446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
2806446Swnj 
2816446Swnj rmut()
2826446Swnj {
2836446Swnj 	register f;
2846446Swnj 	int found = 0;
2856446Swnj 
2866446Swnj 	f = open(utmp, 2);
2876446Swnj 	if (f >= 0) {
2886446Swnj 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
2896446Swnj 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
2906446Swnj 				continue;
2916446Swnj 			lseek(f, -(long)sizeof(wtmp), 1);
2926446Swnj 			SCPYN(wtmp.ut_name, "");
29312681Ssam 			SCPYN(wtmp.ut_host, "");
2946446Swnj 			time(&wtmp.ut_time);
2956446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
2966446Swnj 			found++;
2976446Swnj 		}
2986446Swnj 		close(f);
2996446Swnj 	}
3006446Swnj 	if (found) {
3016446Swnj 		f = open(wtmpf, 1);
3026446Swnj 		if (f >= 0) {
3036446Swnj 			SCPYN(wtmp.ut_line, line+5);
3046446Swnj 			SCPYN(wtmp.ut_name, "");
30512681Ssam 			SCPYN(wtmp.ut_host, "");
3066446Swnj 			time(&wtmp.ut_time);
3076446Swnj 			lseek(f, (long)0, 2);
3086446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3096446Swnj 			close(f);
3106446Swnj 		}
3116446Swnj 	}
3126446Swnj 	chmod(line, 0666);
3136446Swnj 	chown(line, 0, 0);
3146446Swnj 	line[strlen("/dev/")] = 'p';
3156446Swnj 	chmod(line, 0666);
3166446Swnj 	chown(line, 0, 0);
3176446Swnj }
31811345Ssam 
31911345Ssam /*
32011345Ssam  * Convert network-format internet address
32111345Ssam  * to base 256 d.d.d.d representation.
32211345Ssam  */
32311345Ssam char *
32411345Ssam ntoa(in)
32511345Ssam 	struct in_addr in;
32611345Ssam {
32711345Ssam 	static char b[18];
32811345Ssam 	register char *p;
32911345Ssam 
33011345Ssam 	p = (char *)&in;
33111345Ssam #define	UC(b)	(((int)b)&0xff)
33211345Ssam 	sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
33311345Ssam 	return (b);
33411345Ssam }
335