xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 25341)
121595Sdist /*
221595Sdist  * Copyright (c) 1983 Regents of the University of California.
321595Sdist  * All rights reserved.  The Berkeley software License Agreement
421595Sdist  * specifies the terms and conditions for redistribution.
521595Sdist  */
621595Sdist 
76444Swnj #ifndef lint
821595Sdist char copyright[] =
921595Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021595Sdist  All rights reserved.\n";
1121595Sdist #endif not lint
126444Swnj 
1321595Sdist #ifndef lint
14*25341Smckusick static char sccsid[] = "@(#)rlogin.c	5.7 (Berkeley) 10/30/85";
1521595Sdist #endif not lint
1621595Sdist 
1712990Ssam /*
1812990Ssam  * rlogin - remote login
1912990Ssam  */
206444Swnj #include <sys/types.h>
2124727Smckusick #include <sys/file.h>
226444Swnj #include <sys/socket.h>
2313620Ssam #include <sys/wait.h>
249365Ssam 
259207Ssam #include <netinet/in.h>
269365Ssam 
279365Ssam #include <stdio.h>
289365Ssam #include <sgtty.h>
296444Swnj #include <errno.h>
306444Swnj #include <pwd.h>
319365Ssam #include <signal.h>
329365Ssam #include <netdb.h>
336444Swnj 
3424726Smckusick # ifndef TIOCPKT_WINDOW
3524726Smckusick # define TIOCPKT_WINDOW 0x80
3624726Smckusick # endif TIOCPKT_WINDOW
3724726Smckusick 
386444Swnj char	*index(), *rindex(), *malloc(), *getenv();
396444Swnj struct	passwd *getpwuid();
409365Ssam char	*name;
416444Swnj int	rem;
426444Swnj char	cmdchar = '~';
436444Swnj int	eight;
4421583Sbloom int	litout;
456444Swnj char	*speeds[] =
466444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
476444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
4818358Ssam char	term[256] = "network";
499365Ssam extern	int errno;
509365Ssam int	lostpeer();
5124726Smckusick int	dosigwinch = 0;
5218358Ssam struct	winsize winsize;
5324726Smckusick int	sigwinch(), oob();
546444Swnj 
556444Swnj main(argc, argv)
566444Swnj 	int argc;
576444Swnj 	char **argv;
586444Swnj {
599365Ssam 	char *host, *cp;
606444Swnj 	struct sgttyb ttyb;
616444Swnj 	struct passwd *pwd;
629365Ssam 	struct servent *sp;
6324726Smckusick 	int uid, options = 0, oldmask;
6417449Slepreau 	int on = 1;
656444Swnj 
666444Swnj 	host = rindex(argv[0], '/');
676444Swnj 	if (host)
686444Swnj 		host++;
696444Swnj 	else
706444Swnj 		host = argv[0];
716444Swnj 	argv++, --argc;
726444Swnj 	if (!strcmp(host, "rlogin"))
736444Swnj 		host = *argv++, --argc;
746444Swnj another:
7510839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
766444Swnj 		argv++, argc--;
7710415Ssam 		options |= SO_DEBUG;
786444Swnj 		goto another;
796444Swnj 	}
8010839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
816444Swnj 		argv++, argc--;
826444Swnj 		if (argc == 0)
836444Swnj 			goto usage;
846444Swnj 		name = *argv++; argc--;
856444Swnj 		goto another;
866444Swnj 	}
8710839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
886444Swnj 		cmdchar = argv[0][2];
896444Swnj 		argv++, argc--;
906444Swnj 		goto another;
916444Swnj 	}
9210839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
936444Swnj 		eight = 1;
946444Swnj 		argv++, argc--;
956444Swnj 		goto another;
966444Swnj 	}
9721583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
9821583Sbloom 		litout = 1;
9921583Sbloom 		argv++, argc--;
10021583Sbloom 		goto another;
10121583Sbloom 	}
1026444Swnj 	if (host == 0)
1036444Swnj 		goto usage;
1046444Swnj 	if (argc > 0)
1056444Swnj 		goto usage;
1066444Swnj 	pwd = getpwuid(getuid());
1076444Swnj 	if (pwd == 0) {
1086444Swnj 		fprintf(stderr, "Who are you?\n");
1096444Swnj 		exit(1);
1106444Swnj 	}
1119365Ssam 	sp = getservbyname("login", "tcp");
1129365Ssam 	if (sp == 0) {
1139365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1149365Ssam 		exit(2);
1159365Ssam 	}
1169241Ssam 	cp = getenv("TERM");
1179241Ssam 	if (cp)
1189241Ssam 		strcpy(term, cp);
11918358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
1206444Swnj 		strcat(term, "/");
1216444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
1226444Swnj 	}
12324726Smckusick 	(void) ioctl(0, TIOCGWINSZ, &winsize);
12412990Ssam 	signal(SIGPIPE, lostpeer);
12524726Smckusick 	signal(SIGURG, oob);
12624726Smckusick 	oldmask = sigblock(sigmask(SIGURG));
1279365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1286444Swnj 	    name ? name : pwd->pw_name, term, 0);
1296444Swnj         if (rem < 0)
1306444Swnj                 exit(1);
13110415Ssam 	if (options & SO_DEBUG &&
13217449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
13310415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1349365Ssam 	uid = getuid();
1359365Ssam 	if (setuid(uid) < 0) {
1369365Ssam 		perror("rlogin: setuid");
1379365Ssam 		exit(1);
1389365Ssam 	}
13924726Smckusick 	doit(oldmask);
1409365Ssam 	/*NOTREACHED*/
1416444Swnj usage:
1426444Swnj 	fprintf(stderr,
143*25341Smckusick 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
1446444Swnj 	exit(1);
1456444Swnj }
1466444Swnj 
1476444Swnj #define CRLF "\r\n"
1486444Swnj 
1499365Ssam int	child;
15011803Sedward int	catchild();
15124726Smckusick int	writeroob();
1529365Ssam 
15313075Ssam int	defflags, tabflag;
15421583Sbloom int	deflflags;
15513075Ssam char	deferase, defkill;
15613075Ssam struct	tchars deftc;
15713075Ssam struct	ltchars defltc;
15813075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
15913075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1606444Swnj 
16124726Smckusick doit(oldmask)
1626444Swnj {
1636444Swnj 	int exit();
16413075Ssam 	struct sgttyb sb;
1656444Swnj 
16613075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
16713075Ssam 	defflags = sb.sg_flags;
16812155Ssam 	tabflag = defflags & TBDELAY;
1699962Ssam 	defflags &= ECHO | CRMOD;
17013075Ssam 	deferase = sb.sg_erase;
17113075Ssam 	defkill = sb.sg_kill;
17221583Sbloom 	ioctl(0, TIOCLGET, (char *)&deflflags);
17313075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
17413075Ssam 	notc.t_startc = deftc.t_startc;
17513075Ssam 	notc.t_stopc = deftc.t_stopc;
17613075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
17724726Smckusick 	signal(SIGINT, SIG_IGN);
17812990Ssam 	signal(SIGHUP, exit);
17912990Ssam 	signal(SIGQUIT, exit);
1809365Ssam 	child = fork();
1819365Ssam 	if (child == -1) {
1829365Ssam 		perror("rlogin: fork");
1839365Ssam 		done();
1849365Ssam 	}
1859365Ssam 	if (child == 0) {
18624726Smckusick 		mode(1);
18724726Smckusick 		sigsetmask(oldmask);
1889365Ssam 		reader();
18912155Ssam 		sleep(1);
19012155Ssam 		prf("\007Connection closed.");
1916444Swnj 		exit(3);
1926444Swnj 	}
19324726Smckusick 	signal(SIGURG, writeroob);
19424726Smckusick 	sigsetmask(oldmask);
19512990Ssam 	signal(SIGCHLD, catchild);
1969365Ssam 	writer();
19712155Ssam 	prf("Closed connection.");
1986444Swnj 	done();
1996444Swnj }
2006444Swnj 
2016444Swnj done()
2026444Swnj {
2036444Swnj 
2046444Swnj 	mode(0);
2059365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
2069365Ssam 		wait((int *)0);
2076444Swnj 	exit(0);
2086444Swnj }
2096444Swnj 
21024726Smckusick /*
21124726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
21224726Smckusick  * request to turn on the window-changing protocol.
21324726Smckusick  */
21424726Smckusick writeroob()
21524726Smckusick {
21624726Smckusick 
217*25341Smckusick 	if (dosigwinch == 0) {
21824919Smckusick 		sendwindow();
219*25341Smckusick 		signal(SIGWINCH, sigwinch);
220*25341Smckusick 	}
22124726Smckusick 	dosigwinch = 1;
22224726Smckusick }
22324726Smckusick 
22411803Sedward catchild()
22511803Sedward {
22611803Sedward 	union wait status;
22711803Sedward 	int pid;
22811803Sedward 
22911803Sedward again:
23011803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
23111803Sedward 	if (pid == 0)
23211803Sedward 		return;
23311803Sedward 	/*
23411803Sedward 	 * if the child (reader) dies, just quit
23511803Sedward 	 */
23611803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
23711803Sedward 		done();
23811803Sedward 	goto again;
23911803Sedward }
24011803Sedward 
2416444Swnj /*
2429365Ssam  * writer: write to remote: 0 -> line.
2439365Ssam  * ~.	terminate
2449365Ssam  * ~^Z	suspend rlogin process.
24510415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
2466444Swnj  */
2479365Ssam writer()
2486444Swnj {
24923530Sbloom 	char c;
25011803Sedward 	register n;
25123530Sbloom 	register bol = 1;               /* beginning of line */
25223530Sbloom 	register local = 0;
2536444Swnj 
25411803Sedward 	for (;;) {
25511803Sedward 		n = read(0, &c, 1);
25618358Ssam 		if (n <= 0) {
25718358Ssam 			if (n < 0 && errno == EINTR)
25818358Ssam 				continue;
25911803Sedward 			break;
26018358Ssam 		}
2619365Ssam 		/*
2629365Ssam 		 * If we're at the beginning of the line
2639365Ssam 		 * and recognize a command character, then
2649365Ssam 		 * we echo locally.  Otherwise, characters
2659365Ssam 		 * are echo'd remotely.  If the command
2669365Ssam 		 * character is doubled, this acts as a
2679365Ssam 		 * force and local echo is suppressed.
2689365Ssam 		 */
26923530Sbloom 		if (bol) {
27023530Sbloom 			bol = 0;
27123530Sbloom 			if (c == cmdchar) {
27223530Sbloom 				bol = 0;
27323530Sbloom 				local = 1;
27423530Sbloom 				continue;
2756444Swnj 			}
27623530Sbloom 		} else if (local) {
27723530Sbloom 			local = 0;
27823530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
27923530Sbloom 				echo(c);
28023530Sbloom 				break;
2816444Swnj 			}
28223530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
28323530Sbloom 				bol = 1;
28423530Sbloom 				echo(c);
28523530Sbloom 				stop(c);
28623530Sbloom 				continue;
28723530Sbloom 			}
28823530Sbloom 			if (c != cmdchar)
28923530Sbloom 				write(rem, &cmdchar, 1);
2906444Swnj 		}
29123530Sbloom 		if (write(rem, &c, 1) == 0) {
29223530Sbloom 			prf("line gone");
29323530Sbloom 			break;
2946444Swnj 		}
29523530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
29623530Sbloom 		    c == '\r' || c == '\n';
2976444Swnj 	}
2986444Swnj }
2996444Swnj 
30023530Sbloom echo(c)
30123530Sbloom register char c;
30223530Sbloom {
30323530Sbloom 	char buf[8];
30423530Sbloom 	register char *p = buf;
30523530Sbloom 
30623530Sbloom 	c &= 0177;
30723530Sbloom 	*p++ = cmdchar;
30823530Sbloom 	if (c < ' ') {
30923530Sbloom 		*p++ = '^';
31023530Sbloom 		*p++ = c + '@';
31123530Sbloom 	} else if (c == 0177) {
31223530Sbloom 		*p++ = '^';
31323530Sbloom 		*p++ = '?';
31423530Sbloom 	} else
31523530Sbloom 		*p++ = c;
31623530Sbloom 	*p++ = '\r';
31723530Sbloom 	*p++ = '\n';
31823530Sbloom 	write(1, buf, p - buf);
31923530Sbloom }
32023530Sbloom 
32118358Ssam stop(cmdc)
32218358Ssam 	char cmdc;
32318358Ssam {
32418358Ssam 	mode(0);
32518358Ssam 	signal(SIGCHLD, SIG_IGN);
32618358Ssam 	kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
32718358Ssam 	signal(SIGCHLD, catchild);
32818358Ssam 	mode(1);
32918358Ssam 	sigwinch();			/* check for size changes */
33018358Ssam }
33118358Ssam 
33218358Ssam sigwinch()
33318358Ssam {
33418358Ssam 	struct winsize ws;
33518358Ssam 
336*25341Smckusick 	if (dosigwinch && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
33718358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
33818358Ssam 		winsize = ws;
33924726Smckusick 		sendwindow();
34018358Ssam 	}
34118358Ssam }
34218358Ssam 
34324726Smckusick /*
34424726Smckusick  * Send the window size to the server via the magic escape
34524726Smckusick  */
34624726Smckusick sendwindow()
34724726Smckusick {
34824726Smckusick 	char obuf[4 + sizeof (struct winsize)];
34924726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
35024726Smckusick 
35124726Smckusick 	obuf[0] = 0377;
35224726Smckusick 	obuf[1] = 0377;
35324726Smckusick 	obuf[2] = 's';
35424726Smckusick 	obuf[3] = 's';
35524726Smckusick 	wp->ws_row = htons(winsize.ws_row);
35624726Smckusick 	wp->ws_col = htons(winsize.ws_col);
35724726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
35824726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
35924726Smckusick 	(void) write(rem, obuf, sizeof(obuf));
36024726Smckusick }
36124726Smckusick 
3626444Swnj oob()
3636444Swnj {
36410839Ssam 	int out = 1+1, atmark;
3659365Ssam 	char waste[BUFSIZ], mark;
36624726Smckusick 	struct sgttyb sb;
36724919Smckusick 	static int didnotify = 0;
3686444Swnj 
3699365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
3706444Swnj 	for (;;) {
37124726Smckusick 		int rv;
37210839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
3736444Swnj 			perror("ioctl");
3746444Swnj 			break;
3756444Swnj 		}
37610839Ssam 		if (atmark)
3776444Swnj 			break;
37824726Smckusick 		rv = read(rem, waste, sizeof (waste));
37924726Smckusick 		if (rv <= 0)
38023230Sbloom 			break;
3816444Swnj 	}
38212990Ssam 	recv(rem, &mark, 1, MSG_OOB);
38324919Smckusick 	if (didnotify == 0 && (mark & TIOCPKT_WINDOW)) {
38424726Smckusick 		/*
38524726Smckusick 		 * Let server know about window size changes
38624726Smckusick 		 */
38724726Smckusick 		kill(getppid(), SIGURG);
38824919Smckusick 		didnotify = 1;
38924726Smckusick 	}
39024726Smckusick 	if (eight)
39124726Smckusick 		return;
3926444Swnj 	if (mark & TIOCPKT_NOSTOP) {
39324726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
39424726Smckusick 		sb.sg_flags &= ~CBREAK;
39524726Smckusick 		sb.sg_flags |= RAW;
39624726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
39713075Ssam 		notc.t_stopc = -1;
39813075Ssam 		notc.t_startc = -1;
39913075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4006444Swnj 	}
4016444Swnj 	if (mark & TIOCPKT_DOSTOP) {
40224726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
40324726Smckusick 		sb.sg_flags &= ~RAW;
40424726Smckusick 		sb.sg_flags |= CBREAK;
40524726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
40613075Ssam 		notc.t_stopc = deftc.t_stopc;
40713075Ssam 		notc.t_startc = deftc.t_startc;
40813075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4096444Swnj 	}
4106444Swnj }
4116444Swnj 
4129365Ssam /*
4139365Ssam  * reader: read from remote: line -> 1
4149365Ssam  */
4159365Ssam reader()
4166444Swnj {
4179365Ssam 	char rb[BUFSIZ];
4189365Ssam 	register int cnt;
4196444Swnj 
42023530Sbloom 	signal(SIGTTOU, SIG_IGN);
42124727Smckusick 	{ int pid = getpid();
42224727Smckusick 	  fcntl(rem, F_SETOWN, pid); }
4236444Swnj 	for (;;) {
4249365Ssam 		cnt = read(rem, rb, sizeof (rb));
42511396Ssam 		if (cnt == 0)
42611396Ssam 			break;
42711396Ssam 		if (cnt < 0) {
4289365Ssam 			if (errno == EINTR)
4296444Swnj 				continue;
4306444Swnj 			break;
4316444Swnj 		}
4329365Ssam 		write(1, rb, cnt);
4336444Swnj 	}
4346444Swnj }
4356444Swnj 
4366444Swnj mode(f)
4376444Swnj {
43813075Ssam 	struct tchars *tc;
43913075Ssam 	struct ltchars *ltc;
44013075Ssam 	struct sgttyb sb;
44121583Sbloom 	int	lflags;
4429365Ssam 
44313075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
44421583Sbloom 	ioctl(0, TIOCLGET, (char *)&lflags);
4459962Ssam 	switch (f) {
4469962Ssam 
4479962Ssam 	case 0:
44813075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
44913075Ssam 		sb.sg_flags |= defflags|tabflag;
4509962Ssam 		tc = &deftc;
45113075Ssam 		ltc = &defltc;
45213075Ssam 		sb.sg_kill = defkill;
45313075Ssam 		sb.sg_erase = deferase;
45421583Sbloom 		lflags = deflflags;
4559962Ssam 		break;
4569962Ssam 
4579962Ssam 	case 1:
45813075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
45913075Ssam 		sb.sg_flags &= ~defflags;
46012155Ssam 		/* preserve tab delays, but turn off XTABS */
46113075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
46213075Ssam 			sb.sg_flags &= ~TBDELAY;
4639962Ssam 		tc = &notc;
46413075Ssam 		ltc = &noltc;
46513075Ssam 		sb.sg_kill = sb.sg_erase = -1;
46621583Sbloom 		if (litout)
46721583Sbloom 			lflags |= LLITOUT;
4689962Ssam 		break;
4699962Ssam 
4709962Ssam 	default:
4719962Ssam 		return;
4726444Swnj 	}
47313075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
47413075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
47513075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
47621583Sbloom 	ioctl(0, TIOCLSET, (char *)&lflags);
4776444Swnj }
4786444Swnj 
4799365Ssam /*VARARGS*/
48024726Smckusick prf(f, a1, a2, a3, a4, a5)
4819365Ssam 	char *f;
4826444Swnj {
48324726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
4846444Swnj 	fprintf(stderr, CRLF);
4856444Swnj }
4866444Swnj 
4879365Ssam lostpeer()
4886444Swnj {
48912990Ssam 	signal(SIGPIPE, SIG_IGN);
49012155Ssam 	prf("\007Connection closed.");
4919365Ssam 	done();
4926444Swnj }
493