xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 21595)
1*21595Sdist /*
2*21595Sdist  * Copyright (c) 1983 Regents of the University of California.
3*21595Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21595Sdist  * specifies the terms and conditions for redistribution.
5*21595Sdist  */
6*21595Sdist 
76444Swnj #ifndef lint
8*21595Sdist char copyright[] =
9*21595Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10*21595Sdist  All rights reserved.\n";
11*21595Sdist #endif not lint
126444Swnj 
13*21595Sdist #ifndef lint
14*21595Sdist static char sccsid[] = "@(#)rlogin.c	5.1 (Berkeley) 05/31/85";
15*21595Sdist #endif not lint
16*21595Sdist 
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>
3218358Ssam #include <setjmp.h>
336444Swnj 
346444Swnj char	*index(), *rindex(), *malloc(), *getenv();
356444Swnj struct	passwd *getpwuid();
369365Ssam char	*name;
376444Swnj int	rem;
386444Swnj char	cmdchar = '~';
396444Swnj int	eight;
4021583Sbloom int	litout;
416444Swnj char	*speeds[] =
426444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
436444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
4418358Ssam char	term[256] = "network";
459365Ssam extern	int errno;
469365Ssam int	lostpeer();
4718358Ssam int	nosigwin;
4818358Ssam jmp_buf	winsizechanged;
4918358Ssam struct	winsize winsize;
5018358Ssam int	sigwinch();
516444Swnj 
526444Swnj main(argc, argv)
536444Swnj 	int argc;
546444Swnj 	char **argv;
556444Swnj {
569365Ssam 	char *host, *cp;
576444Swnj 	struct sgttyb ttyb;
586444Swnj 	struct passwd *pwd;
599365Ssam 	struct servent *sp;
6010415Ssam 	int uid, options = 0;
6117449Slepreau 	int on = 1;
626444Swnj 
636444Swnj 	host = rindex(argv[0], '/');
646444Swnj 	if (host)
656444Swnj 		host++;
666444Swnj 	else
676444Swnj 		host = argv[0];
686444Swnj 	argv++, --argc;
696444Swnj 	if (!strcmp(host, "rlogin"))
706444Swnj 		host = *argv++, --argc;
716444Swnj another:
7210839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
736444Swnj 		argv++, argc--;
7410415Ssam 		options |= SO_DEBUG;
756444Swnj 		goto another;
766444Swnj 	}
7710839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
786444Swnj 		argv++, argc--;
796444Swnj 		if (argc == 0)
806444Swnj 			goto usage;
816444Swnj 		name = *argv++; argc--;
826444Swnj 		goto another;
836444Swnj 	}
8410839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
856444Swnj 		cmdchar = argv[0][2];
866444Swnj 		argv++, argc--;
876444Swnj 		goto another;
886444Swnj 	}
8910839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
906444Swnj 		eight = 1;
916444Swnj 		argv++, argc--;
926444Swnj 		goto another;
936444Swnj 	}
9421583Sbloom 	if (argc > 0 && !strcmp(*argv, "-L")) {
9521583Sbloom 		litout = 1;
9621583Sbloom 		argv++, argc--;
9721583Sbloom 		goto another;
9821583Sbloom 	}
9918358Ssam 	if (argc > 0 && !strcmp(*argv, "-w")) {
10018358Ssam 		nosigwin++;
10118358Ssam 		argv++, argc--;
10218358Ssam 		goto another;
10318358Ssam 	}
1046444Swnj 	if (host == 0)
1056444Swnj 		goto usage;
1066444Swnj 	if (argc > 0)
1076444Swnj 		goto usage;
1086444Swnj 	pwd = getpwuid(getuid());
1096444Swnj 	if (pwd == 0) {
1106444Swnj 		fprintf(stderr, "Who are you?\n");
1116444Swnj 		exit(1);
1126444Swnj 	}
1139365Ssam 	sp = getservbyname("login", "tcp");
1149365Ssam 	if (sp == 0) {
1159365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
1169365Ssam 		exit(2);
1179365Ssam 	}
1189241Ssam 	cp = getenv("TERM");
1199241Ssam 	if (cp)
1209241Ssam 		strcpy(term, cp);
12118358Ssam 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
1226444Swnj 		strcat(term, "/");
1236444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
1246444Swnj 	}
12518358Ssam 	if (!nosigwin && ioctl(0, TIOCGWINSZ, &winsize) == 0) {
12618358Ssam 		cp = index(term, '\0');
12718358Ssam 		sprintf(cp, "/%u,%u,%u,%u", winsize.ws_row, winsize.ws_col,
12818358Ssam 		    winsize.ws_xpixel, winsize.ws_ypixel);
12918358Ssam 	}
13012990Ssam 	signal(SIGPIPE, lostpeer);
1319365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
1326444Swnj 	    name ? name : pwd->pw_name, term, 0);
1336444Swnj         if (rem < 0)
1346444Swnj                 exit(1);
13510415Ssam 	if (options & SO_DEBUG &&
13617449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
13710415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1389365Ssam 	uid = getuid();
1399365Ssam 	if (setuid(uid) < 0) {
1409365Ssam 		perror("rlogin: setuid");
1419365Ssam 		exit(1);
1429365Ssam 	}
1439365Ssam 	doit();
1449365Ssam 	/*NOTREACHED*/
1456444Swnj usage:
1466444Swnj 	fprintf(stderr,
14721583Sbloom 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n");
1486444Swnj 	exit(1);
1496444Swnj }
1506444Swnj 
1516444Swnj #define CRLF "\r\n"
1526444Swnj 
1539365Ssam int	child;
15411803Sedward int	catchild();
1559365Ssam 
15613075Ssam int	defflags, tabflag;
15721583Sbloom int	deflflags;
15813075Ssam char	deferase, defkill;
15913075Ssam struct	tchars deftc;
16013075Ssam struct	ltchars defltc;
16113075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
16213075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1636444Swnj 
1649365Ssam doit()
1656444Swnj {
1666444Swnj 	int exit();
16713075Ssam 	struct sgttyb sb;
1686444Swnj 
16913075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
17013075Ssam 	defflags = sb.sg_flags;
17112155Ssam 	tabflag = defflags & TBDELAY;
1729962Ssam 	defflags &= ECHO | CRMOD;
17313075Ssam 	deferase = sb.sg_erase;
17413075Ssam 	defkill = sb.sg_kill;
17521583Sbloom 	ioctl(0, TIOCLGET, (char *)&deflflags);
17613075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
17713075Ssam 	notc.t_startc = deftc.t_startc;
17813075Ssam 	notc.t_stopc = deftc.t_stopc;
17913075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
18012990Ssam 	signal(SIGINT, exit);
18112990Ssam 	signal(SIGHUP, exit);
18212990Ssam 	signal(SIGQUIT, exit);
1839365Ssam 	child = fork();
1849365Ssam 	if (child == -1) {
1859365Ssam 		perror("rlogin: fork");
1869365Ssam 		done();
1879365Ssam 	}
18812990Ssam 	signal(SIGINT, SIG_IGN);
18911803Sedward 	mode(1);
1909365Ssam 	if (child == 0) {
1919365Ssam 		reader();
19212155Ssam 		sleep(1);
19312155Ssam 		prf("\007Connection closed.");
1946444Swnj 		exit(3);
1956444Swnj 	}
19612990Ssam 	signal(SIGCHLD, catchild);
19718358Ssam 	if (!nosigwin)
19818358Ssam 		signal(SIGWINCH, sigwinch);
1999365Ssam 	writer();
20012155Ssam 	prf("Closed connection.");
2016444Swnj 	done();
2026444Swnj }
2036444Swnj 
2046444Swnj done()
2056444Swnj {
2066444Swnj 
2076444Swnj 	mode(0);
2089365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
2099365Ssam 		wait((int *)0);
2106444Swnj 	exit(0);
2116444Swnj }
2126444Swnj 
21311803Sedward catchild()
21411803Sedward {
21511803Sedward 	union wait status;
21611803Sedward 	int pid;
21711803Sedward 
21811803Sedward again:
21911803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
22011803Sedward 	if (pid == 0)
22111803Sedward 		return;
22211803Sedward 	/*
22311803Sedward 	 * if the child (reader) dies, just quit
22411803Sedward 	 */
22511803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
22611803Sedward 		done();
22711803Sedward 	goto again;
22811803Sedward }
22911803Sedward 
2306444Swnj /*
2319365Ssam  * writer: write to remote: 0 -> line.
2329365Ssam  * ~.	terminate
2339365Ssam  * ~^Z	suspend rlogin process.
23410415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
2356444Swnj  */
2369365Ssam writer()
2376444Swnj {
23818358Ssam 	char obuf[600], c;
23918358Ssam 	register char *op;
24011803Sedward 	register n;
2416444Swnj 
24218358Ssam 	/*
24318358Ssam 	 * Handle SIGWINCH's with in-band signaling of new
24418358Ssam 	 * window size.  It seems reasonable that we flush
24518358Ssam 	 * pending input and not force out of band signal
24618358Ssam 	 * as this most likely will occur from an input device
24718358Ssam 	 * other than the keyboard (e.g. a mouse).
24818358Ssam 	 *
24918358Ssam 	 * The hack of using 0377 to signal an in-band signal
25018358Ssam 	 * is pretty bad, but otherwise we'd be forced to
25118358Ssam 	 * either get complicated (use MSG_OOB) or go to a
25218358Ssam 	 * serious (telnet-style) protocol.
25318358Ssam 	 */
25418358Ssam 	if (setjmp(winsizechanged)) {
25518358Ssam 		struct winsize *wp = (struct winsize *)(obuf+4);
25618358Ssam 
25718358Ssam 		obuf[0] = 0377;			/* XXX */
25818358Ssam 		obuf[1] = 0377;			/* XXX */
25918358Ssam 		obuf[2] = 's';			/* XXX */
26018358Ssam 		obuf[3] = 's';			/* XXX */
26118358Ssam 		wp->ws_row = htons(winsize.ws_row);
26218358Ssam 		wp->ws_col = htons(winsize.ws_col);
26318358Ssam 		wp->ws_xpixel = htons(winsize.ws_xpixel);
26418358Ssam 		wp->ws_ypixel = htons(winsize.ws_ypixel);
26518358Ssam 		(void) write(rem, obuf, 4+sizeof (*wp));
26618358Ssam 	}
2679365Ssam top:
26818358Ssam 	op = obuf;
26911803Sedward 	for (;;) {
2709365Ssam 		int local;
2719365Ssam 
27211803Sedward 		n = read(0, &c, 1);
27318358Ssam 		if (n <= 0) {
27418358Ssam 			if (n < 0 && errno == EINTR)
27518358Ssam 				continue;
27611803Sedward 			break;
27718358Ssam 		}
27818358Ssam 		if (!eight)
2799365Ssam 			c &= 0177;
2809365Ssam 		/*
2819365Ssam 		 * If we're at the beginning of the line
2829365Ssam 		 * and recognize a command character, then
2839365Ssam 		 * we echo locally.  Otherwise, characters
2849365Ssam 		 * are echo'd remotely.  If the command
2859365Ssam 		 * character is doubled, this acts as a
2869365Ssam 		 * force and local echo is suppressed.
2879365Ssam 		 */
28818358Ssam 		if (op == obuf)
2899365Ssam 			local = (c == cmdchar);
29018358Ssam 		if (op == obuf + 1 && *obuf == cmdchar)
2919365Ssam 			local = (c != cmdchar);
2929365Ssam 		if (!local) {
2939365Ssam 			if (write(rem, &c, 1) == 0) {
2949365Ssam 				prf("line gone");
2959365Ssam 				return;
2966444Swnj 			}
29718358Ssam 			if (!eight)
2989365Ssam 				c &= 0177;
2999365Ssam 		} else {
3009365Ssam 			if (c == '\r' || c == '\n') {
30118358Ssam 				char cmdc = obuf[1];
3026444Swnj 
30313075Ssam 				if (cmdc == '.' || cmdc == deftc.t_eofc) {
3049365Ssam 					write(0, CRLF, sizeof(CRLF));
3059365Ssam 					return;
3069962Ssam 				}
30713075Ssam 				if (cmdc == defltc.t_suspc ||
30813075Ssam 				    cmdc == defltc.t_dsuspc) {
30918358Ssam 					stop(cmdc);
3109365Ssam 					goto top;
3116444Swnj 				}
31218358Ssam 				*op++ = c;
31318358Ssam 				write(rem, obuf, op - obuf);
3149365Ssam 				goto top;
3156444Swnj 			}
3169365Ssam 			write(1, &c, 1);
3176444Swnj 		}
31818358Ssam 		*op++ = c;
31913075Ssam 		if (c == deferase) {
32018358Ssam 			op -= 2;
32118358Ssam 			if (op < obuf)
3229365Ssam 				goto top;
3236444Swnj 		}
32413075Ssam 		if (c == defkill || c == deftc.t_eofc ||
3259365Ssam 		    c == '\r' || c == '\n')
3269365Ssam 			goto top;
32718358Ssam 		if (op >= &obuf[sizeof (obuf)])
32818358Ssam 			op--;
3296444Swnj 	}
3306444Swnj }
3316444Swnj 
33218358Ssam stop(cmdc)
33318358Ssam 	char cmdc;
33418358Ssam {
33518358Ssam 	struct winsize ws;
33618358Ssam 
33718358Ssam 	write(0, CRLF, sizeof(CRLF));
33818358Ssam 	mode(0);
33918358Ssam 	signal(SIGCHLD, SIG_IGN);
34018358Ssam 	kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
34118358Ssam 	signal(SIGCHLD, catchild);
34218358Ssam 	mode(1);
34318358Ssam 	sigwinch();			/* check for size changes */
34418358Ssam }
34518358Ssam 
34618358Ssam sigwinch()
34718358Ssam {
34818358Ssam 	struct winsize ws;
34918358Ssam 
35018358Ssam 	if (!nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
35118358Ssam 	    bcmp(&ws, &winsize, sizeof (ws))) {
35218358Ssam 		winsize = ws;
35318358Ssam 		longjmp(winsizechanged, 1);
35418358Ssam 	}
35518358Ssam }
35618358Ssam 
3576444Swnj oob()
3586444Swnj {
35910839Ssam 	int out = 1+1, atmark;
3609365Ssam 	char waste[BUFSIZ], mark;
3616444Swnj 
3629365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
3636444Swnj 	for (;;) {
36410839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
3656444Swnj 			perror("ioctl");
3666444Swnj 			break;
3676444Swnj 		}
36810839Ssam 		if (atmark)
3696444Swnj 			break;
3709365Ssam 		(void) read(rem, waste, sizeof (waste));
3716444Swnj 	}
37212990Ssam 	recv(rem, &mark, 1, MSG_OOB);
3736444Swnj 	if (mark & TIOCPKT_NOSTOP) {
37413075Ssam 		notc.t_stopc = -1;
37513075Ssam 		notc.t_startc = -1;
37613075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
3776444Swnj 	}
3786444Swnj 	if (mark & TIOCPKT_DOSTOP) {
37913075Ssam 		notc.t_stopc = deftc.t_stopc;
38013075Ssam 		notc.t_startc = deftc.t_startc;
38113075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
3826444Swnj 	}
3836444Swnj }
3846444Swnj 
3859365Ssam /*
3869365Ssam  * reader: read from remote: line -> 1
3879365Ssam  */
3889365Ssam reader()
3896444Swnj {
3909365Ssam 	char rb[BUFSIZ];
3919365Ssam 	register int cnt;
3926444Swnj 
39312990Ssam 	signal(SIGURG, oob);
3946444Swnj 	{ int pid = -getpid();
3959365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
3966444Swnj 	for (;;) {
3979365Ssam 		cnt = read(rem, rb, sizeof (rb));
39811396Ssam 		if (cnt == 0)
39911396Ssam 			break;
40011396Ssam 		if (cnt < 0) {
4019365Ssam 			if (errno == EINTR)
4026444Swnj 				continue;
4036444Swnj 			break;
4046444Swnj 		}
4059365Ssam 		write(1, rb, cnt);
4066444Swnj 	}
4076444Swnj }
4086444Swnj 
4096444Swnj mode(f)
4106444Swnj {
41113075Ssam 	struct tchars *tc;
41213075Ssam 	struct ltchars *ltc;
41313075Ssam 	struct sgttyb sb;
41421583Sbloom 	int	lflags;
4159365Ssam 
41613075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
41721583Sbloom 	ioctl(0, TIOCLGET, (char *)&lflags);
4189962Ssam 	switch (f) {
4199962Ssam 
4209962Ssam 	case 0:
42113075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
42213075Ssam 		sb.sg_flags |= defflags|tabflag;
4239962Ssam 		tc = &deftc;
42413075Ssam 		ltc = &defltc;
42513075Ssam 		sb.sg_kill = defkill;
42613075Ssam 		sb.sg_erase = deferase;
42721583Sbloom 		lflags = deflflags;
4289962Ssam 		break;
4299962Ssam 
4309962Ssam 	case 1:
43113075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
43213075Ssam 		sb.sg_flags &= ~defflags;
43312155Ssam 		/* preserve tab delays, but turn off XTABS */
43413075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
43513075Ssam 			sb.sg_flags &= ~TBDELAY;
4369962Ssam 		tc = &notc;
43713075Ssam 		ltc = &noltc;
43813075Ssam 		sb.sg_kill = sb.sg_erase = -1;
43921583Sbloom 		if (litout)
44021583Sbloom 			lflags |= LLITOUT;
4419962Ssam 		break;
4429962Ssam 
4439962Ssam 	default:
4449962Ssam 		return;
4456444Swnj 	}
44613075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
44713075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
44813075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
44921583Sbloom 	ioctl(0, TIOCLSET, (char *)&lflags);
4506444Swnj }
4516444Swnj 
4529365Ssam /*VARARGS*/
4536444Swnj prf(f, a1, a2, a3)
4549365Ssam 	char *f;
4556444Swnj {
4566444Swnj 	fprintf(stderr, f, a1, a2, a3);
4576444Swnj 	fprintf(stderr, CRLF);
4586444Swnj }
4596444Swnj 
4609365Ssam lostpeer()
4616444Swnj {
46212990Ssam 	signal(SIGPIPE, SIG_IGN);
46312155Ssam 	prf("\007Connection closed.");
4649365Ssam 	done();
4656444Swnj }
466