xref: /csrg-svn/libexec/rlogind/rlogind.c (revision 18357)
16446Swnj #ifndef lint
2*18357Ssam static	char sccsid[] = "@(#)rlogind.c	4.23 (Berkeley) 03/17/85";
36446Swnj #endif
46446Swnj 
516369Skarels /*
616369Skarels  * remote login server:
716369Skarels  *	remuser\0
816369Skarels  *	locuser\0
9*18357Ssam  *	terminal info\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>
18*18357Ssam #include <sys/file.h>
199208Ssam 
209208Ssam #include <netinet/in.h>
219208Ssam 
226446Swnj #include <errno.h>
236446Swnj #include <pwd.h>
246446Swnj #include <signal.h>
256446Swnj #include <sgtty.h>
266446Swnj #include <stdio.h>
278380Ssam #include <netdb.h>
2817187Sralph #include <syslog.h>
29*18357Ssam #include <strings.h>
306446Swnj 
316446Swnj extern	errno;
3210417Ssam int	reapchild();
336446Swnj struct	passwd *getpwnam();
34*18357Ssam char	*crypt(), *malloc();
3516369Skarels 
366446Swnj main(argc, argv)
376446Swnj 	int argc;
386446Swnj 	char **argv;
396446Swnj {
4017156Ssam 	int on = 1, options = 0, fromlen;
416446Swnj 	struct sockaddr_in from;
426446Swnj 
4316369Skarels 	fromlen = sizeof (from);
4416369Skarels 	if (getpeername(0, &from, &fromlen) < 0) {
4516369Skarels 		fprintf(stderr, "%s: ", argv[0]);
4616369Skarels 		perror("getpeername");
4716369Skarels 		_exit(1);
488380Ssam 	}
4917156Ssam 	if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
5017187Sralph 		openlog(argv[0], LOG_PID, 0);
5117187Sralph 		syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
526446Swnj 	}
5316369Skarels 	doit(0, &from);
546446Swnj }
556446Swnj 
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 {
66*18357Ssam 	int i, p, t, pid, on = 1;
67*18357Ssam 	register struct hostent *hp;
688380Ssam 	char c;
696446Swnj 
706446Swnj 	alarm(60);
716446Swnj 	read(f, &c, 1);
726446Swnj 	if (c != 0)
736446Swnj 		exit(1);
746446Swnj 	alarm(0);
7516227Skarels 	fromp->sin_port = ntohs((u_short)fromp->sin_port);
768380Ssam 	hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
778380Ssam 		fromp->sin_family);
7811345Ssam 	if (hp == 0) {
7916227Skarels 		char buf[BUFSIZ];
8011345Ssam 
8111345Ssam 		fatal(f, sprintf(buf, "Host name for your address (%s) unknown",
82*18357Ssam 			inet_ntoa(fromp->sin_addr)));
8311345Ssam 	}
846446Swnj 	if (fromp->sin_family != AF_INET ||
8516227Skarels 	    fromp->sin_port >= IPPORT_RESERVED)
869242Ssam 		fatal(f, "Permission denied");
876446Swnj 	write(f, "", 1);
886446Swnj 	for (c = 'p'; c <= 's'; c++) {
896446Swnj 		struct stat stb;
906446Swnj 		line = "/dev/ptyXX";
916446Swnj 		line[strlen("/dev/pty")] = c;
926446Swnj 		line[strlen("/dev/ptyp")] = '0';
936446Swnj 		if (stat(line, &stb) < 0)
946446Swnj 			break;
956446Swnj 		for (i = 0; i < 16; i++) {
966446Swnj 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
976446Swnj 			p = open(line, 2);
986446Swnj 			if (p > 0)
996446Swnj 				goto gotpty;
1006446Swnj 		}
1016446Swnj 	}
1029242Ssam 	fatal(f, "All network ports in use");
1039242Ssam 	/*NOTREACHED*/
1046446Swnj gotpty:
10516227Skarels 	netf = f;
1066446Swnj 	line[strlen("/dev/")] = 't';
1076446Swnj #ifdef DEBUG
1086446Swnj 	{ int tt = open("/dev/tty", 2);
1096446Swnj 	  if (tt > 0) {
1106446Swnj 		ioctl(tt, TIOCNOTTY, 0);
1116446Swnj 		close(tt);
1126446Swnj 	  }
1136446Swnj 	}
1146446Swnj #endif
1156446Swnj 	t = open(line, 2);
1169242Ssam 	if (t < 0)
1179242Ssam 		fatalperror(f, line, errno);
1186446Swnj 	{ struct sgttyb b;
1196446Swnj 	  gtty(t, &b); b.sg_flags = RAW|ANYP; stty(t, &b);
1206446Swnj 	}
1219242Ssam 	pid = fork();
1229242Ssam 	if (pid < 0)
1239242Ssam 		fatalperror(f, "", errno);
124*18357Ssam 	if (pid == 0) {
125*18357Ssam 		close(f), close(p);
126*18357Ssam 		dup2(t, 0), dup2(t, 1), dup2(t, 2);
12716227Skarels 		close(t);
128*18357Ssam 		execl("/bin/login", "login", "-r", hp->h_name, 0);
129*18357Ssam 		fatalperror(2, "/bin/login", errno);
130*18357Ssam 		/*NOTREACHED*/
131*18357Ssam 	}
132*18357Ssam 	close(t);
133*18357Ssam 	ioctl(f, FIONBIO, &on);
134*18357Ssam 	ioctl(p, FIONBIO, &on);
135*18357Ssam 	ioctl(p, TIOCPKT, &on);
136*18357Ssam 	signal(SIGTSTP, SIG_IGN);
137*18357Ssam 	signal(SIGCHLD, cleanup);
138*18357Ssam 	protocol(f, p);
139*18357Ssam 	cleanup();
140*18357Ssam }
1419242Ssam 
142*18357Ssam char	magic[2] = { 0377, 0377 };
143*18357Ssam 
144*18357Ssam /*
145*18357Ssam  * Handle a "control" request (signaled by magic being present)
146*18357Ssam  * in the data stream.  For now, we are only willing to handle
147*18357Ssam  * window size changes.
148*18357Ssam  */
149*18357Ssam control(pty, cp, n)
150*18357Ssam 	int pty;
151*18357Ssam 	char *cp;
152*18357Ssam 	int n;
153*18357Ssam {
154*18357Ssam 	struct winsize *wp;
155*18357Ssam 
156*18357Ssam 	if (n < 4+sizeof (*wp) || cp[2] != 's' || cp[3] != 's')
157*18357Ssam 		return (0);
158*18357Ssam 	wp = (struct winsize *)(cp+4);
159*18357Ssam 	wp->ws_row = ntohs(wp->ws_row);
160*18357Ssam 	wp->ws_col = ntohs(wp->ws_col);
161*18357Ssam 	wp->ws_xpixel = ntohs(wp->ws_xpixel);
162*18357Ssam 	wp->ws_ypixel = ntohs(wp->ws_ypixel);
163*18357Ssam 	(void)ioctl(pty, TIOCSWINSZ, wp);
164*18357Ssam 	return (4+sizeof (*wp));
165*18357Ssam }
166*18357Ssam 
167*18357Ssam /*
168*18357Ssam  * rlogin "protocol" machine.
169*18357Ssam  */
170*18357Ssam protocol(f, p)
171*18357Ssam 	int f, p;
172*18357Ssam {
173*18357Ssam 	char pibuf[1024], fibuf[1024], *pbp, *fbp;
174*18357Ssam 	register pcc = 0, fcc = 0;
175*18357Ssam 	int cc, stop = TIOCPKT_DOSTOP;
176*18357Ssam 
177*18357Ssam 	for (;;) {
178*18357Ssam 		int ibits = 0, obits = 0;
179*18357Ssam 
180*18357Ssam 		if (fcc)
181*18357Ssam 			obits |= (1<<p);
182*18357Ssam 		else
183*18357Ssam 			ibits |= (1<<f);
184*18357Ssam 		if (pcc >= 0)
185*18357Ssam 			if (pcc)
186*18357Ssam 				obits |= (1<<f);
1879242Ssam 			else
188*18357Ssam 				ibits |= (1<<p);
189*18357Ssam 		if (select(16, &ibits, &obits, 0, 0) < 0) {
190*18357Ssam 			if (errno == EINTR)
1916446Swnj 				continue;
192*18357Ssam 			fatalperror(f, "select", errno);
193*18357Ssam 		}
194*18357Ssam 		if (ibits == 0 && obits == 0) {
195*18357Ssam 			/* shouldn't happen... */
196*18357Ssam 			sleep(5);
197*18357Ssam 			continue;
198*18357Ssam 		}
199*18357Ssam 		if (ibits & (1<<f)) {
200*18357Ssam 			fcc = read(f, fibuf, sizeof (fibuf));
201*18357Ssam 			if (fcc < 0 && errno == EWOULDBLOCK)
202*18357Ssam 				fcc = 0;
203*18357Ssam 			else {
204*18357Ssam 				register char *cp;
205*18357Ssam 				int left, n;
206*18357Ssam 
207*18357Ssam 				if (fcc <= 0)
20816227Skarels 					break;
209*18357Ssam 				fbp = fibuf;
210*18357Ssam 			top:
211*18357Ssam 				for (cp = fibuf; cp < fibuf+fcc; cp++)
212*18357Ssam 					if (cp[0] == magic[0] &&
213*18357Ssam 					    cp[1] == magic[1]) {
214*18357Ssam 						left = fcc - (cp-fibuf);
215*18357Ssam 						n = control(p, cp, left);
216*18357Ssam 						if (n) {
217*18357Ssam 							left -= n;
218*18357Ssam 							if (left > 0)
219*18357Ssam 								bcopy(cp, cp+n, left);
220*18357Ssam 							fcc -= n;
221*18357Ssam 							goto top; /* n^2 */
222*18357Ssam 						}
2236446Swnj 					}
2246446Swnj 			}
225*18357Ssam 		}
226*18357Ssam 		if (ibits & (1<<p)) {
227*18357Ssam 			pcc = read(p, pibuf, sizeof (pibuf));
228*18357Ssam 			pbp = pibuf;
229*18357Ssam 			if (pcc < 0 && errno == EWOULDBLOCK)
230*18357Ssam 				pcc = 0;
231*18357Ssam 			else if (pcc <= 0)
232*18357Ssam 				break;
233*18357Ssam 			else if (pibuf[0] == 0)
234*18357Ssam 				pbp++, pcc--;
235*18357Ssam 			else {
236*18357Ssam #define	pkcontrol(c)	((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
237*18357Ssam 				if (pkcontrol(pibuf[0])) {
238*18357Ssam 				/* The following 3 lines do nothing. */
239*18357Ssam 					int nstop = pibuf[0] &
240*18357Ssam 					    (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP);
241*18357Ssam 
242*18357Ssam 					if (nstop)
243*18357Ssam 						stop = nstop;
244*18357Ssam 					pibuf[0] |= nstop;
245*18357Ssam 					send(f, &pibuf[0], 1, MSG_OOB);
24616227Skarels 				}
247*18357Ssam 				pcc = 0;
2486446Swnj 			}
249*18357Ssam 		}
250*18357Ssam 		if ((obits & (1<<f)) && pcc > 0) {
251*18357Ssam 			cc = write(f, pbp, pcc);
252*18357Ssam 			if (cc < 0 && errno == EWOULDBLOCK) {
253*18357Ssam 				/* also shouldn't happen */
254*18357Ssam 				sleep(5);
255*18357Ssam 				continue;
2566446Swnj 			}
257*18357Ssam 			if (cc > 0) {
258*18357Ssam 				pcc -= cc;
259*18357Ssam 				pbp += cc;
260*18357Ssam 			}
2616446Swnj 		}
262*18357Ssam 		if ((obits & (1<<p)) && fcc > 0) {
263*18357Ssam 			cc = write(p, fbp, fcc);
264*18357Ssam 			if (cc > 0) {
265*18357Ssam 				fcc -= cc;
266*18357Ssam 				fbp += cc;
267*18357Ssam 			}
268*18357Ssam 		}
2696446Swnj 	}
2706446Swnj }
2716446Swnj 
2726446Swnj cleanup()
2736446Swnj {
2746446Swnj 
2756446Swnj 	rmut();
27610009Ssam 	vhangup();		/* XXX */
27710192Ssam 	shutdown(netf, 2);
2786446Swnj 	kill(0, SIGKILL);
2796446Swnj 	exit(1);
2806446Swnj }
2816446Swnj 
2829242Ssam fatal(f, msg)
2839242Ssam 	int f;
2849242Ssam 	char *msg;
2859242Ssam {
2869242Ssam 	char buf[BUFSIZ];
2879242Ssam 
2889242Ssam 	buf[0] = '\01';		/* error indicator */
28913554Ssam 	(void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
2909242Ssam 	(void) write(f, buf, strlen(buf));
2919242Ssam 	exit(1);
2929242Ssam }
2939242Ssam 
2949242Ssam fatalperror(f, msg, errno)
2959242Ssam 	int f;
2969242Ssam 	char *msg;
2979242Ssam 	int errno;
2989242Ssam {
2999242Ssam 	char buf[BUFSIZ];
30016227Skarels 	extern int sys_nerr;
3019242Ssam 	extern char *sys_errlist[];
3029242Ssam 
303*18357Ssam 	if ((unsigned)errno < sys_nerr)
30416227Skarels 		(void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
30516227Skarels 	else
30616227Skarels 		(void) sprintf(buf, "%s: Error %d", msg, errno);
3079242Ssam 	fatal(f, buf);
3089242Ssam }
3099242Ssam 
3106446Swnj #include <utmp.h>
3116446Swnj 
3126446Swnj struct	utmp wtmp;
3136446Swnj char	wtmpf[]	= "/usr/adm/wtmp";
3146446Swnj char	utmp[] = "/etc/utmp";
3156446Swnj #define SCPYN(a, b)	strncpy(a, b, sizeof(a))
3166446Swnj #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
3176446Swnj 
3186446Swnj rmut()
3196446Swnj {
3206446Swnj 	register f;
3216446Swnj 	int found = 0;
3226446Swnj 
323*18357Ssam 	f = open(utmp, O_RDWR);
3246446Swnj 	if (f >= 0) {
3256446Swnj 		while(read(f, (char *)&wtmp, sizeof(wtmp)) == sizeof(wtmp)) {
3266446Swnj 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
3276446Swnj 				continue;
328*18357Ssam 			lseek(f, -(long)sizeof(wtmp), L_INCR);
3296446Swnj 			SCPYN(wtmp.ut_name, "");
33012681Ssam 			SCPYN(wtmp.ut_host, "");
3316446Swnj 			time(&wtmp.ut_time);
3326446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3336446Swnj 			found++;
3346446Swnj 		}
3356446Swnj 		close(f);
3366446Swnj 	}
3376446Swnj 	if (found) {
338*18357Ssam 		f = open(wtmpf, O_WRONLY);
3396446Swnj 		if (f >= 0) {
3406446Swnj 			SCPYN(wtmp.ut_line, line+5);
3416446Swnj 			SCPYN(wtmp.ut_name, "");
34212681Ssam 			SCPYN(wtmp.ut_host, "");
3436446Swnj 			time(&wtmp.ut_time);
344*18357Ssam 			lseek(f, (long)0, L_XTND);
3456446Swnj 			write(f, (char *)&wtmp, sizeof(wtmp));
3466446Swnj 			close(f);
3476446Swnj 		}
3486446Swnj 	}
3496446Swnj 	chmod(line, 0666);
3506446Swnj 	chown(line, 0, 0);
3516446Swnj 	line[strlen("/dev/")] = 'p';
3526446Swnj 	chmod(line, 0666);
3536446Swnj 	chown(line, 0, 0);
3546446Swnj }
355