xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 24726)
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*24726Smckusick static char sccsid[] = "@(#)rlogin.c	5.3.1.2 (Berkeley) 09/12/85";
1521595Sdist #endif not lint
1621595Sdist 
1712990Ssam /*
1812990Ssam  * rlogin - remote login
1912990Ssam  */
206444Swnj #include <sys/types.h>
216444Swnj #include <sys/socket.h>
2213620Ssam #include <sys/wait.h>
239365Ssam 
249207Ssam #include <netinet/in.h>
259365Ssam 
269365Ssam #include <stdio.h>
279365Ssam #include <sgtty.h>
286444Swnj #include <errno.h>
296444Swnj #include <pwd.h>
309365Ssam #include <signal.h>
319365Ssam #include <netdb.h>
326444Swnj 
33*24726Smckusick # ifndef TIOCPKT_WINDOW
34*24726Smckusick # define TIOCPKT_WINDOW 0x80
35*24726Smckusick # endif TIOCPKT_WINDOW
36*24726Smckusick 
376444Swnj char	*index(), *rindex(), *malloc(), *getenv();
386444Swnj struct	passwd *getpwuid();
399365Ssam char	*name;
406444Swnj int	rem;
416444Swnj char	cmdchar = '~';
426444Swnj int	eight;
4321583Sbloom int	litout;
446444Swnj char	*speeds[] =
456444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
466444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
4718358Ssam char	term[256] = "network";
489365Ssam extern	int errno;
499365Ssam int	lostpeer();
50*24726Smckusick int	dosigwinch = 0;
51*24726Smckusick int	nosigwin = 0;
5218358Ssam struct	winsize winsize;
53*24726Smckusick 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;
63*24726Smckusick 	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 	}
10218358Ssam 	if (argc > 0 && !strcmp(*argv, "-w")) {
10318358Ssam 		nosigwin++;
10418358Ssam 		argv++, argc--;
10518358Ssam 		goto another;
10618358Ssam 	}
1076444Swnj 	if (host == 0)
1086444Swnj 		goto usage;
1096444Swnj 	if (argc > 0)
1106444Swnj 		goto usage;
1116444Swnj 	pwd = getpwuid(getuid());
1126444Swnj 	if (pwd == 0) {
1136444Swnj 		fprintf(stderr, "Who are you?\n");
1146444Swnj 		exit(1);
1156444Swnj 	}
1169365Ssam 	sp = getservbyname("login", "tcp");
1179365Ssam 	if (sp == 0) {
1189365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1199365Ssam 		exit(2);
1209365Ssam 	}
1219241Ssam 	cp = getenv("TERM");
1229241Ssam 	if (cp)
1239241Ssam 		strcpy(term, cp);
12418358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
1256444Swnj 		strcat(term, "/");
1266444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
1276444Swnj 	}
128*24726Smckusick 	(void) ioctl(0, TIOCGWINSZ, &winsize);
12912990Ssam 	signal(SIGPIPE, lostpeer);
130*24726Smckusick 	signal(SIGURG, oob);
131*24726Smckusick 	oldmask = sigblock(sigmask(SIGURG));
1329365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1336444Swnj 	    name ? name : pwd->pw_name, term, 0);
1346444Swnj         if (rem < 0)
1356444Swnj                 exit(1);
13610415Ssam 	if (options & SO_DEBUG &&
13717449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
13810415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1399365Ssam 	uid = getuid();
1409365Ssam 	if (setuid(uid) < 0) {
1419365Ssam 		perror("rlogin: setuid");
1429365Ssam 		exit(1);
1439365Ssam 	}
144*24726Smckusick 	doit(oldmask);
1459365Ssam 	/*NOTREACHED*/
1466444Swnj usage:
1476444Swnj 	fprintf(stderr,
14821583Sbloom 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n");
1496444Swnj 	exit(1);
1506444Swnj }
1516444Swnj 
1526444Swnj #define CRLF "\r\n"
1536444Swnj 
1549365Ssam int	child;
15511803Sedward int	catchild();
156*24726Smckusick int	writeroob();
1579365Ssam 
15813075Ssam int	defflags, tabflag;
15921583Sbloom int	deflflags;
16013075Ssam char	deferase, defkill;
16113075Ssam struct	tchars deftc;
16213075Ssam struct	ltchars defltc;
16313075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
16413075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1656444Swnj 
166*24726Smckusick doit(oldmask)
1676444Swnj {
1686444Swnj 	int exit();
16913075Ssam 	struct sgttyb sb;
1706444Swnj 
17113075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
17213075Ssam 	defflags = sb.sg_flags;
17312155Ssam 	tabflag = defflags & TBDELAY;
1749962Ssam 	defflags &= ECHO | CRMOD;
17513075Ssam 	deferase = sb.sg_erase;
17613075Ssam 	defkill = sb.sg_kill;
17721583Sbloom 	ioctl(0, TIOCLGET, (char *)&deflflags);
17813075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
17913075Ssam 	notc.t_startc = deftc.t_startc;
18013075Ssam 	notc.t_stopc = deftc.t_stopc;
18113075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
182*24726Smckusick 	signal(SIGINT, SIG_IGN);
18312990Ssam 	signal(SIGHUP, exit);
18412990Ssam 	signal(SIGQUIT, exit);
1859365Ssam 	child = fork();
1869365Ssam 	if (child == -1) {
1879365Ssam 		perror("rlogin: fork");
1889365Ssam 		done();
1899365Ssam 	}
1909365Ssam 	if (child == 0) {
191*24726Smckusick 		mode(1);
192*24726Smckusick 		sigsetmask(oldmask);
1939365Ssam 		reader();
19412155Ssam 		sleep(1);
19512155Ssam 		prf("\007Connection closed.");
1966444Swnj 		exit(3);
1976444Swnj 	}
198*24726Smckusick 	signal(SIGURG, writeroob);
199*24726Smckusick 	sigsetmask(oldmask);
20012990Ssam 	signal(SIGCHLD, catchild);
20118358Ssam 	if (!nosigwin)
20218358Ssam 		signal(SIGWINCH, sigwinch);
2039365Ssam 	writer();
20412155Ssam 	prf("Closed connection.");
2056444Swnj 	done();
2066444Swnj }
2076444Swnj 
2086444Swnj done()
2096444Swnj {
2106444Swnj 
2116444Swnj 	mode(0);
2129365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
2139365Ssam 		wait((int *)0);
2146444Swnj 	exit(0);
2156444Swnj }
2166444Swnj 
217*24726Smckusick /*
218*24726Smckusick  * This is called when the reader process gets the out-of-band (urgent)
219*24726Smckusick  * request to turn on the window-changing protocol.
220*24726Smckusick  */
221*24726Smckusick writeroob()
222*24726Smckusick {
223*24726Smckusick 
224*24726Smckusick 	dosigwinch = 1;
225*24726Smckusick 	sendwindow();
226*24726Smckusick }
227*24726Smckusick 
22811803Sedward catchild()
22911803Sedward {
23011803Sedward 	union wait status;
23111803Sedward 	int pid;
23211803Sedward 
23311803Sedward again:
23411803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
23511803Sedward 	if (pid == 0)
23611803Sedward 		return;
23711803Sedward 	/*
23811803Sedward 	 * if the child (reader) dies, just quit
23911803Sedward 	 */
24011803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
24111803Sedward 		done();
24211803Sedward 	goto again;
24311803Sedward }
24411803Sedward 
2456444Swnj /*
2469365Ssam  * writer: write to remote: 0 -> line.
2479365Ssam  * ~.	terminate
2489365Ssam  * ~^Z	suspend rlogin process.
24910415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
2506444Swnj  */
2519365Ssam writer()
2526444Swnj {
25323530Sbloom 	char c;
25411803Sedward 	register n;
25523530Sbloom 	register bol = 1;               /* beginning of line */
25623530Sbloom 	register local = 0;
2576444Swnj 
25811803Sedward 	for (;;) {
25911803Sedward 		n = read(0, &c, 1);
26018358Ssam 		if (n <= 0) {
26118358Ssam 			if (n < 0 && errno == EINTR)
26218358Ssam 				continue;
26311803Sedward 			break;
26418358Ssam 		}
2659365Ssam 		/*
2669365Ssam 		 * If we're at the beginning of the line
2679365Ssam 		 * and recognize a command character, then
2689365Ssam 		 * we echo locally.  Otherwise, characters
2699365Ssam 		 * are echo'd remotely.  If the command
2709365Ssam 		 * character is doubled, this acts as a
2719365Ssam 		 * force and local echo is suppressed.
2729365Ssam 		 */
27323530Sbloom 		if (bol) {
27423530Sbloom 			bol = 0;
27523530Sbloom 			if (c == cmdchar) {
27623530Sbloom 				bol = 0;
27723530Sbloom 				local = 1;
27823530Sbloom 				continue;
2796444Swnj 			}
28023530Sbloom 		} else if (local) {
28123530Sbloom 			local = 0;
28223530Sbloom 			if (c == '.' || c == deftc.t_eofc) {
28323530Sbloom 				echo(c);
28423530Sbloom 				break;
2856444Swnj 			}
28623530Sbloom 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
28723530Sbloom 				bol = 1;
28823530Sbloom 				echo(c);
28923530Sbloom 				stop(c);
29023530Sbloom 				continue;
29123530Sbloom 			}
29223530Sbloom 			if (c != cmdchar)
29323530Sbloom 				write(rem, &cmdchar, 1);
2946444Swnj 		}
29523530Sbloom 		if (write(rem, &c, 1) == 0) {
29623530Sbloom 			prf("line gone");
29723530Sbloom 			break;
2986444Swnj 		}
29923530Sbloom 		bol = c == defkill || c == deftc.t_eofc ||
30023530Sbloom 		    c == '\r' || c == '\n';
3016444Swnj 	}
3026444Swnj }
3036444Swnj 
30423530Sbloom echo(c)
30523530Sbloom register char c;
30623530Sbloom {
30723530Sbloom 	char buf[8];
30823530Sbloom 	register char *p = buf;
30923530Sbloom 
31023530Sbloom 	c &= 0177;
31123530Sbloom 	*p++ = cmdchar;
31223530Sbloom 	if (c < ' ') {
31323530Sbloom 		*p++ = '^';
31423530Sbloom 		*p++ = c + '@';
31523530Sbloom 	} else if (c == 0177) {
31623530Sbloom 		*p++ = '^';
31723530Sbloom 		*p++ = '?';
31823530Sbloom 	} else
31923530Sbloom 		*p++ = c;
32023530Sbloom 	*p++ = '\r';
32123530Sbloom 	*p++ = '\n';
32223530Sbloom 	write(1, buf, p - buf);
32323530Sbloom }
32423530Sbloom 
32518358Ssam stop(cmdc)
32618358Ssam 	char cmdc;
32718358Ssam {
32818358Ssam 	mode(0);
32918358Ssam 	signal(SIGCHLD, SIG_IGN);
33018358Ssam 	kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
33118358Ssam 	signal(SIGCHLD, catchild);
33218358Ssam 	mode(1);
33318358Ssam 	sigwinch();			/* check for size changes */
33418358Ssam }
33518358Ssam 
33618358Ssam sigwinch()
33718358Ssam {
33818358Ssam 	struct winsize ws;
33918358Ssam 
340*24726Smckusick 	if (dosigwinch && !nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
34118358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
34218358Ssam 		winsize = ws;
343*24726Smckusick 		sendwindow();
34418358Ssam 	}
34518358Ssam }
34618358Ssam 
347*24726Smckusick /*
348*24726Smckusick  * Send the window size to the server via the magic escape
349*24726Smckusick  */
350*24726Smckusick sendwindow()
351*24726Smckusick {
352*24726Smckusick 	char obuf[4 + sizeof (struct winsize)];
353*24726Smckusick 	struct winsize *wp = (struct winsize *)(obuf+4);
354*24726Smckusick 
355*24726Smckusick 	obuf[0] = 0377;
356*24726Smckusick 	obuf[1] = 0377;
357*24726Smckusick 	obuf[2] = 's';
358*24726Smckusick 	obuf[3] = 's';
359*24726Smckusick 	wp->ws_row = htons(winsize.ws_row);
360*24726Smckusick 	wp->ws_col = htons(winsize.ws_col);
361*24726Smckusick 	wp->ws_xpixel = htons(winsize.ws_xpixel);
362*24726Smckusick 	wp->ws_ypixel = htons(winsize.ws_ypixel);
363*24726Smckusick 	(void) write(rem, obuf, sizeof(obuf));
364*24726Smckusick }
365*24726Smckusick 
3666444Swnj oob()
3676444Swnj {
36810839Ssam 	int out = 1+1, atmark;
3699365Ssam 	char waste[BUFSIZ], mark;
370*24726Smckusick 	struct sgttyb sb;
3716444Swnj 
3729365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
3736444Swnj 	for (;;) {
374*24726Smckusick 		int rv;
37510839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
3766444Swnj 			perror("ioctl");
3776444Swnj 			break;
3786444Swnj 		}
37910839Ssam 		if (atmark)
3806444Swnj 			break;
381*24726Smckusick 		rv = read(rem, waste, sizeof (waste));
382*24726Smckusick 		if (rv <= 0)
38323230Sbloom 			break;
3846444Swnj 	}
38512990Ssam 	recv(rem, &mark, 1, MSG_OOB);
386*24726Smckusick 	if (mark & TIOCPKT_WINDOW) {
387*24726Smckusick 		/*
388*24726Smckusick 		 * Let server know about window size changes
389*24726Smckusick 		 */
390*24726Smckusick 		kill(getppid(), SIGURG);
391*24726Smckusick 	}
392*24726Smckusick 	if (eight)
393*24726Smckusick 		return;
3946444Swnj 	if (mark & TIOCPKT_NOSTOP) {
395*24726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
396*24726Smckusick 		sb.sg_flags &= ~CBREAK;
397*24726Smckusick 		sb.sg_flags |= RAW;
398*24726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
39913075Ssam 		notc.t_stopc = -1;
40013075Ssam 		notc.t_startc = -1;
40113075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4026444Swnj 	}
4036444Swnj 	if (mark & TIOCPKT_DOSTOP) {
404*24726Smckusick 		ioctl(0, TIOCGETP, (char *)&sb);
405*24726Smckusick 		sb.sg_flags &= ~RAW;
406*24726Smckusick 		sb.sg_flags |= CBREAK;
407*24726Smckusick 		ioctl(0, TIOCSETN, (char *)&sb);
40813075Ssam 		notc.t_stopc = deftc.t_stopc;
40913075Ssam 		notc.t_startc = deftc.t_startc;
41013075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
4116444Swnj 	}
4126444Swnj }
4136444Swnj 
4149365Ssam /*
4159365Ssam  * reader: read from remote: line -> 1
4169365Ssam  */
4179365Ssam reader()
4186444Swnj {
4199365Ssam 	char rb[BUFSIZ];
4209365Ssam 	register int cnt;
4216444Swnj 
42223530Sbloom 	signal(SIGTTOU, SIG_IGN);
42324725Smckusick 	{ int pid = -getpid();
42424725Smckusick 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
4256444Swnj 	for (;;) {
4269365Ssam 		cnt = read(rem, rb, sizeof (rb));
42711396Ssam 		if (cnt == 0)
42811396Ssam 			break;
42911396Ssam 		if (cnt < 0) {
4309365Ssam 			if (errno == EINTR)
4316444Swnj 				continue;
4326444Swnj 			break;
4336444Swnj 		}
4349365Ssam 		write(1, rb, cnt);
4356444Swnj 	}
4366444Swnj }
4376444Swnj 
4386444Swnj mode(f)
4396444Swnj {
44013075Ssam 	struct tchars *tc;
44113075Ssam 	struct ltchars *ltc;
44213075Ssam 	struct sgttyb sb;
44321583Sbloom 	int	lflags;
4449365Ssam 
44513075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
44621583Sbloom 	ioctl(0, TIOCLGET, (char *)&lflags);
4479962Ssam 	switch (f) {
4489962Ssam 
4499962Ssam 	case 0:
45013075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
45113075Ssam 		sb.sg_flags |= defflags|tabflag;
4529962Ssam 		tc = &deftc;
45313075Ssam 		ltc = &defltc;
45413075Ssam 		sb.sg_kill = defkill;
45513075Ssam 		sb.sg_erase = deferase;
45621583Sbloom 		lflags = deflflags;
4579962Ssam 		break;
4589962Ssam 
4599962Ssam 	case 1:
46013075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
46113075Ssam 		sb.sg_flags &= ~defflags;
46212155Ssam 		/* preserve tab delays, but turn off XTABS */
46313075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
46413075Ssam 			sb.sg_flags &= ~TBDELAY;
4659962Ssam 		tc = &notc;
46613075Ssam 		ltc = &noltc;
46713075Ssam 		sb.sg_kill = sb.sg_erase = -1;
46821583Sbloom 		if (litout)
46921583Sbloom 			lflags |= LLITOUT;
4709962Ssam 		break;
4719962Ssam 
4729962Ssam 	default:
4739962Ssam 		return;
4746444Swnj 	}
47513075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
47613075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
47713075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
47821583Sbloom 	ioctl(0, TIOCLSET, (char *)&lflags);
4796444Swnj }
4806444Swnj 
4819365Ssam /*VARARGS*/
482*24726Smckusick prf(f, a1, a2, a3, a4, a5)
4839365Ssam 	char *f;
4846444Swnj {
485*24726Smckusick 	fprintf(stderr, f, a1, a2, a3, a4, a5);
4866444Swnj 	fprintf(stderr, CRLF);
4876444Swnj }
4886444Swnj 
4899365Ssam lostpeer()
4906444Swnj {
49112990Ssam 	signal(SIGPIPE, SIG_IGN);
49212155Ssam 	prf("\007Connection closed.");
4939365Ssam 	done();
4946444Swnj }
495