xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 10839)
16444Swnj #ifndef lint
2*10839Ssam static char sccsid[] = "@(#)rlogin.c	4.9 83/02/09";
36444Swnj #endif
46444Swnj 
56444Swnj #include <sys/types.h>
66444Swnj #include <sys/socket.h>
79365Ssam 
89207Ssam #include <netinet/in.h>
99365Ssam 
109365Ssam #include <stdio.h>
119365Ssam #include <sgtty.h>
126444Swnj #include <errno.h>
136444Swnj #include <pwd.h>
149365Ssam #include <signal.h>
159365Ssam #include <netdb.h>
166444Swnj 
176444Swnj /*
189365Ssam  * rlogin - remote login
196444Swnj  */
206444Swnj char	*index(), *rindex(), *malloc(), *getenv();
216444Swnj struct	passwd *getpwuid();
229365Ssam char	*name;
236444Swnj int	rem;
246444Swnj char	cmdchar = '~';
256444Swnj int	eight;
266444Swnj char	*speeds[] =
276444Swnj     { "0", "50", "75", "110", "134", "150", "200", "300",
286444Swnj       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
299365Ssam char	term[64] = "network";
309365Ssam extern	int errno;
319365Ssam int	lostpeer();
326444Swnj 
336444Swnj main(argc, argv)
346444Swnj 	int argc;
356444Swnj 	char **argv;
366444Swnj {
379365Ssam 	char *host, *cp;
386444Swnj 	struct sgttyb ttyb;
396444Swnj 	struct passwd *pwd;
409365Ssam 	struct servent *sp;
4110415Ssam 	int uid, options = 0;
426444Swnj 
436444Swnj 	host = rindex(argv[0], '/');
446444Swnj 	if (host)
456444Swnj 		host++;
466444Swnj 	else
476444Swnj 		host = argv[0];
486444Swnj 	argv++, --argc;
496444Swnj 	if (!strcmp(host, "rlogin"))
506444Swnj 		host = *argv++, --argc;
516444Swnj another:
52*10839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
536444Swnj 		argv++, argc--;
5410415Ssam 		options |= SO_DEBUG;
556444Swnj 		goto another;
566444Swnj 	}
57*10839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
586444Swnj 		argv++, argc--;
596444Swnj 		if (argc == 0)
606444Swnj 			goto usage;
616444Swnj 		name = *argv++; argc--;
626444Swnj 		goto another;
636444Swnj 	}
64*10839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
656444Swnj 		cmdchar = argv[0][2];
666444Swnj 		argv++, argc--;
676444Swnj 		goto another;
686444Swnj 	}
69*10839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
706444Swnj 		eight = 1;
716444Swnj 		argv++, argc--;
726444Swnj 		goto another;
736444Swnj 	}
746444Swnj 	if (host == 0)
756444Swnj 		goto usage;
766444Swnj 	if (argc > 0)
776444Swnj 		goto usage;
786444Swnj 	pwd = getpwuid(getuid());
796444Swnj 	if (pwd == 0) {
806444Swnj 		fprintf(stderr, "Who are you?\n");
816444Swnj 		exit(1);
826444Swnj 	}
839365Ssam 	sp = getservbyname("login", "tcp");
849365Ssam 	if (sp == 0) {
859365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
869365Ssam 		exit(2);
879365Ssam 	}
889241Ssam 	cp = getenv("TERM");
899241Ssam 	if (cp)
909241Ssam 		strcpy(term, cp);
919962Ssam 	if (ioctl(0, TIOCGETP, &ttyb)==0) {
926444Swnj 		strcat(term, "/");
936444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
946444Swnj 	}
959365Ssam 	signal(SIGPIPE, lostpeer);
969365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
976444Swnj 	    name ? name : pwd->pw_name, term, 0);
986444Swnj         if (rem < 0)
996444Swnj                 exit(1);
10010415Ssam 	if (options & SO_DEBUG &&
10110415Ssam 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
10210415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1039365Ssam 	uid = getuid();
1049365Ssam 	if (setuid(uid) < 0) {
1059365Ssam 		perror("rlogin: setuid");
1069365Ssam 		exit(1);
1079365Ssam 	}
1089365Ssam 	doit();
1099365Ssam 	/*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 
1189365Ssam int	child;
1199365Ssam int	done();
1209365Ssam 
1219962Ssam int	defflags;
1229962Ssam struct	ttychars deftc;
1239962Ssam struct	ttychars notc = {
1249962Ssam 	-1,	-1,	-1,	-1,	-1,
1259962Ssam 	-1,	-1,	-1,	-1,	-1,
1269962Ssam 	-1,	-1,	-1,	-1
1279962Ssam };
1286444Swnj 
1299365Ssam doit()
1306444Swnj {
1316444Swnj 	int exit();
1326444Swnj 
1339962Ssam 	ioctl(0, TIOCGET, (char *)&defflags);
1349962Ssam 	defflags &= ECHO | CRMOD;
1359962Ssam 	ioctl(0, TIOCCGET, (char *)&deftc);
1369962Ssam 	notc.tc_startc = deftc.tc_startc;
1379962Ssam 	notc.tc_stopc = deftc.tc_stopc;
1386444Swnj 	signal(SIGINT, exit);
1396444Swnj 	signal(SIGHUP, exit);
1406444Swnj 	signal(SIGQUIT, exit);
1419365Ssam 	child = fork();
1429365Ssam 	if (child == -1) {
1439365Ssam 		perror("rlogin: fork");
1449365Ssam 		done();
1459365Ssam 	}
1469365Ssam 	signal(SIGINT, SIG_IGN);
1479365Ssam 	if (child == 0) {
1489365Ssam 		reader();
1496444Swnj 		prf("\007Lost connection.");
1506444Swnj 		exit(3);
1516444Swnj 	}
1526444Swnj 	signal(SIGCHLD, done);
1536444Swnj 	mode(1);
1549365Ssam 	writer();
1556444Swnj 	prf("Disconnected.");
1566444Swnj 	done();
1576444Swnj }
1586444Swnj 
1596444Swnj done()
1606444Swnj {
1616444Swnj 
1626444Swnj 	mode(0);
1639365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1649365Ssam 		wait((int *)0);
1656444Swnj 	exit(0);
1666444Swnj }
1676444Swnj 
1686444Swnj /*
1699365Ssam  * writer: write to remote: 0 -> line.
1709365Ssam  * ~.	terminate
1719365Ssam  * ~^Z	suspend rlogin process.
17210415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
1736444Swnj  */
1749365Ssam writer()
1756444Swnj {
1769365Ssam 	char b[600], c;
1779365Ssam 	register char *p;
1786444Swnj 
1799365Ssam top:
1809365Ssam 	p = b;
1819365Ssam 	while (read(0, &c, 1) > 0) {
1829365Ssam 		int local;
1839365Ssam 
1849365Ssam 		if (eight == 0)
1859365Ssam 			c &= 0177;
1869365Ssam 		/*
1879365Ssam 		 * If we're at the beginning of the line
1889365Ssam 		 * and recognize a command character, then
1899365Ssam 		 * we echo locally.  Otherwise, characters
1909365Ssam 		 * are echo'd remotely.  If the command
1919365Ssam 		 * character is doubled, this acts as a
1929365Ssam 		 * force and local echo is suppressed.
1939365Ssam 		 */
1949365Ssam 		if (p == b)
1959365Ssam 			local = (c == cmdchar);
1969365Ssam 		if (p == b + 1 && *b == cmdchar)
1979365Ssam 			local = (c != cmdchar);
1989365Ssam 		if (!local) {
1999365Ssam 			if (write(rem, &c, 1) == 0) {
2009365Ssam 				prf("line gone");
2019365Ssam 				return;
2026444Swnj 			}
2039365Ssam 			if (eight == 0)
2049365Ssam 				c &= 0177;
2059365Ssam 		} else {
2069365Ssam 			if (c == 0177)
2079962Ssam 				c = deftc.tc_kill;
2089365Ssam 			if (c == '\r' || c == '\n') {
2099962Ssam 				char cmdc = b[1];
2106444Swnj 
2119962Ssam 				if (cmdc == '.' || cmdc == deftc.tc_eofc) {
2129365Ssam 					write(0, CRLF, sizeof(CRLF));
2139365Ssam 					return;
2149962Ssam 				}
2159962Ssam 				if (cmdc == deftc.tc_suspc ||
2169962Ssam 				    cmdc == deftc.tc_dsuspc) {
2179365Ssam 					write(0, CRLF, sizeof(CRLF));
2189365Ssam 					mode(0);
2199365Ssam 					signal(SIGCHLD, SIG_IGN);
2209962Ssam 					kill(cmdc == deftc.tc_suspc ?
2219962Ssam 					  0 : getpid(), SIGTSTP);
2229365Ssam 					signal(SIGCHLD, done);
2239365Ssam 					mode(1);
2249365Ssam 					goto top;
2256444Swnj 				}
2269365Ssam 				*p++ = c;
2279365Ssam 				write(rem, b, p - b);
2289365Ssam 				goto top;
2296444Swnj 			}
2309365Ssam 			write(1, &c, 1);
2316444Swnj 		}
2329365Ssam 		*p++ = c;
2339962Ssam 		if (c == deftc.tc_erase) {
2349365Ssam 			p -= 2;
2359365Ssam 			if (p < b)
2369365Ssam 				goto top;
2376444Swnj 		}
2389962Ssam 		if (c == deftc.tc_kill || c == 0177 || c == deftc.tc_eofc ||
2399365Ssam 		    c == '\r' || c == '\n')
2409365Ssam 			goto top;
2416444Swnj 	}
2426444Swnj }
2436444Swnj 
2446444Swnj oob()
2456444Swnj {
246*10839Ssam 	int out = 1+1, atmark;
2479365Ssam 	char waste[BUFSIZ], mark;
2486444Swnj 
2496444Swnj 	signal(SIGURG, oob);
2509365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2516444Swnj 	for (;;) {
252*10839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
2536444Swnj 			perror("ioctl");
2546444Swnj 			break;
2556444Swnj 		}
256*10839Ssam 		if (atmark)
2576444Swnj 			break;
2589365Ssam 		(void) read(rem, waste, sizeof (waste));
2596444Swnj 	}
2609207Ssam 	recv(rem, &mark, 1, SOF_OOB);
2616444Swnj 	if (mark & TIOCPKT_NOSTOP) {
2629962Ssam 		notc.tc_stopc = -1;
2639962Ssam 		notc.tc_startc = -1;
2649962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2656444Swnj 	}
2666444Swnj 	if (mark & TIOCPKT_DOSTOP) {
2679962Ssam 		notc.tc_stopc = deftc.tc_stopc;
2689962Ssam 		notc.tc_startc = deftc.tc_startc;
2699962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2706444Swnj 	}
2716444Swnj }
2726444Swnj 
2739365Ssam /*
2749365Ssam  * reader: read from remote: line -> 1
2759365Ssam  */
2769365Ssam reader()
2776444Swnj {
2789365Ssam 	char rb[BUFSIZ];
2799365Ssam 	register int cnt;
2806444Swnj 
2819365Ssam 	signal(SIGURG, oob);
2826444Swnj 	{ int pid = -getpid();
2839365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
2846444Swnj 	for (;;) {
2859365Ssam 		cnt = read(rem, rb, sizeof (rb));
2866444Swnj 		if (cnt <= 0) {
2879365Ssam 			if (errno == EINTR)
2886444Swnj 				continue;
2896444Swnj 			break;
2906444Swnj 		}
2919365Ssam 		write(1, rb, cnt);
2926444Swnj 	}
2936444Swnj }
2946444Swnj 
2956444Swnj mode(f)
2966444Swnj {
2979962Ssam 	struct ttychars *tc;
2989962Ssam 	int flags;
2999365Ssam 
3009962Ssam 	ioctl(0, TIOCGET, (char *)&flags);
3019962Ssam 	switch (f) {
3029962Ssam 
3039962Ssam 	case 0:
3049962Ssam 		flags &= ~CBREAK;
3059962Ssam 		flags |= defflags;
3069962Ssam 		tc = &deftc;
3079962Ssam 		break;
3089962Ssam 
3099962Ssam 	case 1:
3109962Ssam 		flags |= CBREAK;
3119962Ssam 		flags &= ~defflags;
3129962Ssam 		tc = &notc;
3139962Ssam 		break;
3149962Ssam 
3159962Ssam 	default:
3169962Ssam 		return;
3176444Swnj 	}
3189962Ssam 	ioctl(0, TIOCSET, (char *)&flags);
3199962Ssam 	ioctl(0, TIOCCSET, (char *)tc);
3206444Swnj }
3216444Swnj 
3229365Ssam /*VARARGS*/
3236444Swnj prf(f, a1, a2, a3)
3249365Ssam 	char *f;
3256444Swnj {
3266444Swnj 	fprintf(stderr, f, a1, a2, a3);
3276444Swnj 	fprintf(stderr, CRLF);
3286444Swnj }
3296444Swnj 
3309365Ssam lostpeer()
3316444Swnj {
3329365Ssam 	signal(SIGPIPE, SIG_IGN);
3339365Ssam 	prf("\007Lost connection");
3349365Ssam 	done();
3356444Swnj }
336