xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 9365)
16444Swnj #ifndef lint
2*9365Ssam static char sccsid[] = "@(#)rlogin.c	4.5 82/11/27";
36444Swnj #endif
46444Swnj 
56444Swnj #include <sys/types.h>
66444Swnj #include <sys/socket.h>
7*9365Ssam 
89207Ssam #include <netinet/in.h>
9*9365Ssam 
10*9365Ssam #include <stdio.h>
11*9365Ssam #include <sgtty.h>
126444Swnj #include <errno.h>
136444Swnj #include <pwd.h>
14*9365Ssam #include <signal.h>
15*9365Ssam #include <netdb.h>
166444Swnj 
176444Swnj /*
18*9365Ssam  * rlogin - remote login
196444Swnj  */
206444Swnj char	*index(), *rindex(), *malloc(), *getenv();
216444Swnj struct	passwd *getpwuid();
22*9365Ssam char	*name;
236444Swnj int	rem;
246444Swnj char	cmdchar = '~';
256444Swnj int	rcmdoptions = 0;
266444Swnj int	eight;
276444Swnj char	*speeds[] =
286444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
296444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
30*9365Ssam char	term[64] = "network";
31*9365Ssam extern	int errno;
32*9365Ssam int	lostpeer();
336444Swnj 
34*9365Ssam #define	CTRL(c)	('c' & 037)
35*9365Ssam 
366444Swnj main(argc, argv)
376444Swnj 	int argc;
386444Swnj 	char **argv;
396444Swnj {
40*9365Ssam 	char *host, *cp;
416444Swnj 	struct sgttyb ttyb;
426444Swnj 	struct passwd *pwd;
43*9365Ssam 	struct servent *sp;
44*9365Ssam 	int uid;
456444Swnj 
466444Swnj 	host = rindex(argv[0], '/');
476444Swnj 	if (host)
486444Swnj 		host++;
496444Swnj 	else
506444Swnj 		host = argv[0];
516444Swnj 	argv++, --argc;
526444Swnj 	if (!strcmp(host, "rlogin"))
536444Swnj 		host = *argv++, --argc;
546444Swnj another:
556444Swnj 	if (!strcmp(*argv, "-d")) {
566444Swnj 		argv++, argc--;
576444Swnj 		rcmdoptions |= SO_DEBUG;
586444Swnj 		goto another;
596444Swnj 	}
606444Swnj 	if (!strcmp(*argv, "-l")) {
616444Swnj 		argv++, argc--;
626444Swnj 		if (argc == 0)
636444Swnj 			goto usage;
646444Swnj 		name = *argv++; argc--;
656444Swnj 		goto another;
666444Swnj 	}
676444Swnj 	if (!strncmp(*argv, "-e", 2)) {
686444Swnj 		cmdchar = argv[0][2];
696444Swnj 		argv++, argc--;
706444Swnj 		goto another;
716444Swnj 	}
726444Swnj 	if (!strcmp(*argv, "-8")) {
736444Swnj 		eight = 1;
746444Swnj 		argv++, argc--;
756444Swnj 		goto another;
766444Swnj 	}
776444Swnj 	if (host == 0)
786444Swnj 		goto usage;
796444Swnj 	if (argc > 0)
806444Swnj 		goto usage;
816444Swnj 	pwd = getpwuid(getuid());
826444Swnj 	if (pwd == 0) {
836444Swnj 		fprintf(stderr, "Who are you?\n");
846444Swnj 		exit(1);
856444Swnj 	}
86*9365Ssam 	sp = getservbyname("login", "tcp");
87*9365Ssam 	if (sp == 0) {
88*9365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
89*9365Ssam 		exit(2);
90*9365Ssam 	}
919241Ssam 	cp = getenv("TERM");
929241Ssam 	if (cp)
939241Ssam 		strcpy(term, cp);
946444Swnj 	if (gtty(0, &ttyb)==0) {
956444Swnj 		strcat(term, "/");
966444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
976444Swnj 	}
98*9365Ssam 	signal(SIGPIPE, lostpeer);
99*9365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1006444Swnj 	    name ? name : pwd->pw_name, term, 0);
1016444Swnj         if (rem < 0)
1026444Swnj                 exit(1);
103*9365Ssam 	uid = getuid();
104*9365Ssam 	if (setuid(uid) < 0) {
105*9365Ssam 		perror("rlogin: setuid");
106*9365Ssam 		exit(1);
107*9365Ssam 	}
108*9365Ssam 	doit();
109*9365Ssam 	/*NOTREACHED*/
1106444Swnj usage:
1116444Swnj 	fprintf(stderr,
1126444Swnj 	    "usage: rlogin host [ -ex ] [ -l username ]\n");
1136444Swnj 	exit(1);
1146444Swnj }
1156444Swnj 
1166444Swnj #define CRLF "\r\n"
1176444Swnj 
118*9365Ssam int	child;
119*9365Ssam int	done();
120*9365Ssam 
1216444Swnj char	tkill, terase;	/* current input kill & erase */
122*9365Ssam char	defkill, deferase, defflags;
1236444Swnj 
124*9365Ssam struct	tchars deftchars;
125*9365Ssam struct	tchars notchars = { -1, -1, CTRL(q), CTRL(s), -1, -1 };
126*9365Ssam struct	ltchars defltchars;
127*9365Ssam struct	ltchars noltchars = { -1, -1, -1, -1, -1, -1 };
1286444Swnj 
129*9365Ssam doit()
1306444Swnj {
1316444Swnj 	struct sgttyb stbuf;
1326444Swnj 	int exit();
1336444Swnj 
134*9365Ssam 	ioctl(0, TIOCGETP, (char *)&stbuf);
1356444Swnj 	defkill = stbuf.sg_kill;
1366444Swnj 	deferase = stbuf.sg_erase;
1376481Sjkf 	defflags = stbuf.sg_flags & (ECHO | CRMOD);
138*9365Ssam 	ioctl(0, TIOCGETC, (char *)&deftchars);
139*9365Ssam 	ioctl(0, TIOCGLTC, (char *)&defltchars);
1406444Swnj 	signal(SIGINT, exit);
1416444Swnj 	signal(SIGHUP, exit);
1426444Swnj 	signal(SIGQUIT, exit);
143*9365Ssam 	child = fork();
144*9365Ssam 	if (child == -1) {
145*9365Ssam 		perror("rlogin: fork");
146*9365Ssam 		done();
147*9365Ssam 	}
148*9365Ssam 	signal(SIGINT, SIG_IGN);
149*9365Ssam 	if (child == 0) {
150*9365Ssam 		signal(SIGPIPE, SIG_IGN);
151*9365Ssam 		reader();
1526444Swnj 		prf("\007Lost connection.");
1536444Swnj 		exit(3);
1546444Swnj 	}
1556444Swnj 	signal(SIGCHLD, done);
1566444Swnj 	mode(1);
157*9365Ssam 	writer();
1586444Swnj 	prf("Disconnected.");
1596444Swnj 	done();
1606444Swnj }
1616444Swnj 
1626444Swnj done()
1636444Swnj {
1646444Swnj 
1656444Swnj 	mode(0);
166*9365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
167*9365Ssam 		wait((int *)0);
1686444Swnj 	exit(0);
1696444Swnj }
1706444Swnj 
1716444Swnj /*
172*9365Ssam  * writer: write to remote: 0 -> line.
173*9365Ssam  * ~.	terminate
174*9365Ssam  * ~^Z	suspend rlogin process.
1756444Swnj  */
176*9365Ssam writer()
1776444Swnj {
178*9365Ssam 	char b[600], c;
179*9365Ssam 	register char *p;
1806444Swnj 
181*9365Ssam top:
182*9365Ssam 	p = b;
183*9365Ssam 	while (read(0, &c, 1) > 0) {
184*9365Ssam 		int local;
185*9365Ssam 
186*9365Ssam 		if (eight == 0)
187*9365Ssam 			c &= 0177;
188*9365Ssam 		/*
189*9365Ssam 		 * If we're at the beginning of the line
190*9365Ssam 		 * and recognize a command character, then
191*9365Ssam 		 * we echo locally.  Otherwise, characters
192*9365Ssam 		 * are echo'd remotely.  If the command
193*9365Ssam 		 * character is doubled, this acts as a
194*9365Ssam 		 * force and local echo is suppressed.
195*9365Ssam 		 */
196*9365Ssam 		if (p == b)
197*9365Ssam 			local = (c == cmdchar);
198*9365Ssam 		if (p == b + 1 && *b == cmdchar)
199*9365Ssam 			local = (c != cmdchar);
200*9365Ssam 		if (!local) {
201*9365Ssam 			if (write(rem, &c, 1) == 0) {
202*9365Ssam 				prf("line gone");
203*9365Ssam 				return;
2046444Swnj 			}
205*9365Ssam 			if (eight == 0)
206*9365Ssam 				c &= 0177;
207*9365Ssam 		} else {
208*9365Ssam 			if (c == 0177)
209*9365Ssam 				c = tkill;
210*9365Ssam 			if (c == '\r' || c == '\n') {
211*9365Ssam 				switch (b[1]) {
2126444Swnj 
213*9365Ssam 				case '.':
214*9365Ssam 				case CTRL(d):
215*9365Ssam 					write(0, CRLF, sizeof(CRLF));
216*9365Ssam 					return;
217*9365Ssam 
218*9365Ssam 				case CTRL(z):
219*9365Ssam 					write(0, CRLF, sizeof(CRLF));
220*9365Ssam 					mode(0);
221*9365Ssam 					signal(SIGCHLD, SIG_IGN);
222*9365Ssam 					kill(0, SIGTSTP);
223*9365Ssam 					signal(SIGCHLD, done);
224*9365Ssam 					mode(1);
225*9365Ssam 					goto top;
2266444Swnj 				}
227*9365Ssam 				*p++ = c;
228*9365Ssam 				write(rem, b, p - b);
229*9365Ssam 				goto top;
2306444Swnj 			}
231*9365Ssam 			write(1, &c, 1);
2326444Swnj 		}
233*9365Ssam 		*p++ = c;
234*9365Ssam 		if (c == terase) {
235*9365Ssam 			p -= 2;
236*9365Ssam 			if (p < b)
237*9365Ssam 				goto top;
2386444Swnj 		}
239*9365Ssam 		if (c == tkill || c == 0177 || c == CTRL(d) ||
240*9365Ssam 		    c == '\r' || c == '\n')
241*9365Ssam 			goto top;
2426444Swnj 	}
2436444Swnj }
2446444Swnj 
2456444Swnj oob()
2466444Swnj {
247*9365Ssam 	int out = 1+1;
248*9365Ssam 	char waste[BUFSIZ], mark;
2496444Swnj 
2506444Swnj 	signal(SIGURG, oob);
251*9365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2526444Swnj 	for (;;) {
2536444Swnj 		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
2546444Swnj 			perror("ioctl");
2556444Swnj 			break;
2566444Swnj 		}
2576444Swnj 		if (mark)
2586444Swnj 			break;
259*9365Ssam 		(void) read(rem, waste, sizeof (waste));
2606444Swnj 	}
2619207Ssam 	recv(rem, &mark, 1, SOF_OOB);
2626444Swnj 	if (mark & TIOCPKT_NOSTOP) {
263*9365Ssam 		notchars.t_stopc = -1;
264*9365Ssam 		notchars.t_startc = -1;
265*9365Ssam 		ioctl(0, TIOCSETC, (char *)&notchars);
2666444Swnj 	}
2676444Swnj 	if (mark & TIOCPKT_DOSTOP) {
268*9365Ssam 		notchars.t_stopc = CTRL(s);
269*9365Ssam 		notchars.t_startc = CTRL(q);
270*9365Ssam 		ioctl(0, TIOCSETC, (char *)&notchars);
2716444Swnj 	}
2726444Swnj }
2736444Swnj 
274*9365Ssam /*
275*9365Ssam  * reader: read from remote: line -> 1
276*9365Ssam  */
277*9365Ssam reader()
2786444Swnj {
279*9365Ssam 	char rb[BUFSIZ];
280*9365Ssam 	register int cnt;
2816444Swnj 
282*9365Ssam 	signal(SIGURG, oob);
283*9365Ssam #ifdef notdef
2846444Swnj 	{ int pid = -getpid();
285*9365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
286*9365Ssam #endif
2876444Swnj 	for (;;) {
288*9365Ssam 		cnt = read(rem, rb, sizeof (rb));
2896444Swnj 		if (cnt <= 0) {
290*9365Ssam 			if (errno == EINTR)
2916444Swnj 				continue;
2926444Swnj 			break;
2936444Swnj 		}
294*9365Ssam 		write(1, rb, cnt);
2956444Swnj 	}
2966444Swnj }
2976444Swnj 
2986444Swnj mode(f)
2996444Swnj {
3006444Swnj 	struct sgttyb stbuf;
301*9365Ssam 
302*9365Ssam 	ioctl(0, TIOCGETP, (char *)&stbuf);
3036444Swnj 	if (f == 0) {
3046444Swnj 		stbuf.sg_flags &= ~CBREAK;
3056481Sjkf 		stbuf.sg_flags |= defflags;
306*9365Ssam 		ioctl(0, TIOCSETC, (char *)&deftchars);
307*9365Ssam 		ioctl(0, TIOCSLTC, (char *)&defltchars);
3086444Swnj 		stbuf.sg_kill = defkill;
3096444Swnj 		stbuf.sg_erase = deferase;
3106444Swnj 	}
3116444Swnj 	if (f == 1) {
3126444Swnj 		stbuf.sg_flags |= CBREAK;
3136444Swnj 		stbuf.sg_flags &= ~(ECHO|CRMOD);
314*9365Ssam 		ioctl(0, TIOCSETC, (char *)&notchars);
315*9365Ssam 		ioctl(0, TIOCSLTC, (char *)&noltchars);
316*9365Ssam 		stbuf.sg_kill = -1;
317*9365Ssam 		stbuf.sg_erase = -1;
3186444Swnj 	}
3196444Swnj 	if (f == 2) {
3206444Swnj 		stbuf.sg_flags &= ~CBREAK;
3216444Swnj 		stbuf.sg_flags &= ~(ECHO|CRMOD);
322*9365Ssam 		ioctl(0, TIOCSETC, (char *)&deftchars);
323*9365Ssam 		ioctl(0, TIOCSLTC, (char *)&defltchars);
324*9365Ssam 		stbuf.sg_kill = -1;
325*9365Ssam 		stbuf.sg_erase = -1;
3266444Swnj 	}
327*9365Ssam 	ioctl(0, TIOCSETN, (char *)&stbuf);
3286444Swnj }
3296444Swnj 
330*9365Ssam /*VARARGS*/
3316444Swnj prf(f, a1, a2, a3)
332*9365Ssam 	char *f;
3336444Swnj {
3346444Swnj 	fprintf(stderr, f, a1, a2, a3);
3356444Swnj 	fprintf(stderr, CRLF);
3366444Swnj }
3376444Swnj 
338*9365Ssam lostpeer()
3396444Swnj {
340*9365Ssam 	signal(SIGPIPE, SIG_IGN);
341*9365Ssam 	prf("\007Lost connection");
342*9365Ssam 	done();
3436444Swnj }
344