xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 9962)
16444Swnj #ifndef lint
2*9962Ssam static char sccsid[] = "@(#)rlogin.c	4.7 82/12/25";
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	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" };
309365Ssam char	term[64] = "network";
319365Ssam extern	int errno;
329365Ssam int	lostpeer();
336444Swnj 
346444Swnj main(argc, argv)
356444Swnj 	int argc;
366444Swnj 	char **argv;
376444Swnj {
389365Ssam 	char *host, *cp;
396444Swnj 	struct sgttyb ttyb;
406444Swnj 	struct passwd *pwd;
419365Ssam 	struct servent *sp;
429365Ssam 	int uid;
436444Swnj 
446444Swnj 	host = rindex(argv[0], '/');
456444Swnj 	if (host)
466444Swnj 		host++;
476444Swnj 	else
486444Swnj 		host = argv[0];
496444Swnj 	argv++, --argc;
506444Swnj 	if (!strcmp(host, "rlogin"))
516444Swnj 		host = *argv++, --argc;
526444Swnj another:
536444Swnj 	if (!strcmp(*argv, "-d")) {
546444Swnj 		argv++, argc--;
556444Swnj 		rcmdoptions |= SO_DEBUG;
566444Swnj 		goto another;
576444Swnj 	}
586444Swnj 	if (!strcmp(*argv, "-l")) {
596444Swnj 		argv++, argc--;
606444Swnj 		if (argc == 0)
616444Swnj 			goto usage;
626444Swnj 		name = *argv++; argc--;
636444Swnj 		goto another;
646444Swnj 	}
656444Swnj 	if (!strncmp(*argv, "-e", 2)) {
666444Swnj 		cmdchar = argv[0][2];
676444Swnj 		argv++, argc--;
686444Swnj 		goto another;
696444Swnj 	}
706444Swnj 	if (!strcmp(*argv, "-8")) {
716444Swnj 		eight = 1;
726444Swnj 		argv++, argc--;
736444Swnj 		goto another;
746444Swnj 	}
756444Swnj 	if (host == 0)
766444Swnj 		goto usage;
776444Swnj 	if (argc > 0)
786444Swnj 		goto usage;
796444Swnj 	pwd = getpwuid(getuid());
806444Swnj 	if (pwd == 0) {
816444Swnj 		fprintf(stderr, "Who are you?\n");
826444Swnj 		exit(1);
836444Swnj 	}
849365Ssam 	sp = getservbyname("login", "tcp");
859365Ssam 	if (sp == 0) {
869365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
879365Ssam 		exit(2);
889365Ssam 	}
899241Ssam 	cp = getenv("TERM");
909241Ssam 	if (cp)
919241Ssam 		strcpy(term, cp);
92*9962Ssam 	if (ioctl(0, TIOCGETP, &ttyb)==0) {
936444Swnj 		strcat(term, "/");
946444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
956444Swnj 	}
969365Ssam 	signal(SIGPIPE, lostpeer);
979365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
986444Swnj 	    name ? name : pwd->pw_name, term, 0);
996444Swnj         if (rem < 0)
1006444Swnj                 exit(1);
1019365Ssam 	uid = getuid();
1029365Ssam 	if (setuid(uid) < 0) {
1039365Ssam 		perror("rlogin: setuid");
1049365Ssam 		exit(1);
1059365Ssam 	}
1069365Ssam 	doit();
1079365Ssam 	/*NOTREACHED*/
1086444Swnj usage:
1096444Swnj 	fprintf(stderr,
1106444Swnj 	    "usage: rlogin host [ -ex ] [ -l username ]\n");
1116444Swnj 	exit(1);
1126444Swnj }
1136444Swnj 
1146444Swnj #define CRLF "\r\n"
1156444Swnj 
1169365Ssam int	child;
1179365Ssam int	done();
1189365Ssam 
119*9962Ssam int	defflags;
120*9962Ssam struct	ttychars deftc;
121*9962Ssam struct	ttychars notc = {
122*9962Ssam 	-1,	-1,	-1,	-1,	-1,
123*9962Ssam 	-1,	-1,	-1,	-1,	-1,
124*9962Ssam 	-1,	-1,	-1,	-1
125*9962Ssam };
1266444Swnj 
1279365Ssam doit()
1286444Swnj {
1296444Swnj 	int exit();
1306444Swnj 
131*9962Ssam 	ioctl(0, TIOCGET, (char *)&defflags);
132*9962Ssam 	defflags &= ECHO | CRMOD;
133*9962Ssam 	ioctl(0, TIOCCGET, (char *)&deftc);
134*9962Ssam 	notc.tc_startc = deftc.tc_startc;
135*9962Ssam 	notc.tc_stopc = deftc.tc_stopc;
1366444Swnj 	signal(SIGINT, exit);
1376444Swnj 	signal(SIGHUP, exit);
1386444Swnj 	signal(SIGQUIT, exit);
1399365Ssam 	child = fork();
1409365Ssam 	if (child == -1) {
1419365Ssam 		perror("rlogin: fork");
1429365Ssam 		done();
1439365Ssam 	}
1449365Ssam 	signal(SIGINT, SIG_IGN);
1459365Ssam 	if (child == 0) {
1469365Ssam 		reader();
1476444Swnj 		prf("\007Lost connection.");
1486444Swnj 		exit(3);
1496444Swnj 	}
1506444Swnj 	signal(SIGCHLD, done);
1516444Swnj 	mode(1);
1529365Ssam 	writer();
1536444Swnj 	prf("Disconnected.");
1546444Swnj 	done();
1556444Swnj }
1566444Swnj 
1576444Swnj done()
1586444Swnj {
1596444Swnj 
1606444Swnj 	mode(0);
1619365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1629365Ssam 		wait((int *)0);
1636444Swnj 	exit(0);
1646444Swnj }
1656444Swnj 
1666444Swnj /*
1679365Ssam  * writer: write to remote: 0 -> line.
1689365Ssam  * ~.	terminate
1699365Ssam  * ~^Z	suspend rlogin process.
1706444Swnj  */
1719365Ssam writer()
1726444Swnj {
1739365Ssam 	char b[600], c;
1749365Ssam 	register char *p;
1756444Swnj 
1769365Ssam top:
1779365Ssam 	p = b;
1789365Ssam 	while (read(0, &c, 1) > 0) {
1799365Ssam 		int local;
1809365Ssam 
1819365Ssam 		if (eight == 0)
1829365Ssam 			c &= 0177;
1839365Ssam 		/*
1849365Ssam 		 * If we're at the beginning of the line
1859365Ssam 		 * and recognize a command character, then
1869365Ssam 		 * we echo locally.  Otherwise, characters
1879365Ssam 		 * are echo'd remotely.  If the command
1889365Ssam 		 * character is doubled, this acts as a
1899365Ssam 		 * force and local echo is suppressed.
1909365Ssam 		 */
1919365Ssam 		if (p == b)
1929365Ssam 			local = (c == cmdchar);
1939365Ssam 		if (p == b + 1 && *b == cmdchar)
1949365Ssam 			local = (c != cmdchar);
1959365Ssam 		if (!local) {
1969365Ssam 			if (write(rem, &c, 1) == 0) {
1979365Ssam 				prf("line gone");
1989365Ssam 				return;
1996444Swnj 			}
2009365Ssam 			if (eight == 0)
2019365Ssam 				c &= 0177;
2029365Ssam 		} else {
2039365Ssam 			if (c == 0177)
204*9962Ssam 				c = deftc.tc_kill;
2059365Ssam 			if (c == '\r' || c == '\n') {
206*9962Ssam 				char cmdc = b[1];
2076444Swnj 
208*9962Ssam 				if (cmdc == '.' || cmdc == deftc.tc_eofc) {
2099365Ssam 					write(0, CRLF, sizeof(CRLF));
2109365Ssam 					return;
211*9962Ssam 				}
212*9962Ssam 				if (cmdc == deftc.tc_suspc ||
213*9962Ssam 				    cmdc == deftc.tc_dsuspc) {
2149365Ssam 					write(0, CRLF, sizeof(CRLF));
2159365Ssam 					mode(0);
2169365Ssam 					signal(SIGCHLD, SIG_IGN);
217*9962Ssam 					kill(cmdc == deftc.tc_suspc ?
218*9962Ssam 					  0 : getpid(), SIGTSTP);
2199365Ssam 					signal(SIGCHLD, done);
2209365Ssam 					mode(1);
2219365Ssam 					goto top;
2226444Swnj 				}
2239365Ssam 				*p++ = c;
2249365Ssam 				write(rem, b, p - b);
2259365Ssam 				goto top;
2266444Swnj 			}
2279365Ssam 			write(1, &c, 1);
2286444Swnj 		}
2299365Ssam 		*p++ = c;
230*9962Ssam 		if (c == deftc.tc_erase) {
2319365Ssam 			p -= 2;
2329365Ssam 			if (p < b)
2339365Ssam 				goto top;
2346444Swnj 		}
235*9962Ssam 		if (c == deftc.tc_kill || c == 0177 || c == deftc.tc_eofc ||
2369365Ssam 		    c == '\r' || c == '\n')
2379365Ssam 			goto top;
2386444Swnj 	}
2396444Swnj }
2406444Swnj 
2416444Swnj oob()
2426444Swnj {
2439365Ssam 	int out = 1+1;
2449365Ssam 	char waste[BUFSIZ], mark;
2456444Swnj 
2466444Swnj 	signal(SIGURG, oob);
2479365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2486444Swnj 	for (;;) {
2496444Swnj 		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
2506444Swnj 			perror("ioctl");
2516444Swnj 			break;
2526444Swnj 		}
2536444Swnj 		if (mark)
2546444Swnj 			break;
2559365Ssam 		(void) read(rem, waste, sizeof (waste));
2566444Swnj 	}
2579207Ssam 	recv(rem, &mark, 1, SOF_OOB);
2586444Swnj 	if (mark & TIOCPKT_NOSTOP) {
259*9962Ssam 		notc.tc_stopc = -1;
260*9962Ssam 		notc.tc_startc = -1;
261*9962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2626444Swnj 	}
2636444Swnj 	if (mark & TIOCPKT_DOSTOP) {
264*9962Ssam 		notc.tc_stopc = deftc.tc_stopc;
265*9962Ssam 		notc.tc_startc = deftc.tc_startc;
266*9962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2676444Swnj 	}
2686444Swnj }
2696444Swnj 
2709365Ssam /*
2719365Ssam  * reader: read from remote: line -> 1
2729365Ssam  */
2739365Ssam reader()
2746444Swnj {
2759365Ssam 	char rb[BUFSIZ];
2769365Ssam 	register int cnt;
2776444Swnj 
2789365Ssam 	signal(SIGURG, oob);
2796444Swnj 	{ int pid = -getpid();
2809365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
2816444Swnj 	for (;;) {
2829365Ssam 		cnt = read(rem, rb, sizeof (rb));
2836444Swnj 		if (cnt <= 0) {
2849365Ssam 			if (errno == EINTR)
2856444Swnj 				continue;
2866444Swnj 			break;
2876444Swnj 		}
2889365Ssam 		write(1, rb, cnt);
2896444Swnj 	}
2906444Swnj }
2916444Swnj 
2926444Swnj mode(f)
2936444Swnj {
294*9962Ssam 	struct ttychars *tc;
295*9962Ssam 	int flags;
2969365Ssam 
297*9962Ssam 	ioctl(0, TIOCGET, (char *)&flags);
298*9962Ssam 	switch (f) {
299*9962Ssam 
300*9962Ssam 	case 0:
301*9962Ssam 		flags &= ~CBREAK;
302*9962Ssam 		flags |= defflags;
303*9962Ssam 		tc = &deftc;
304*9962Ssam 		break;
305*9962Ssam 
306*9962Ssam 	case 1:
307*9962Ssam 		flags |= CBREAK;
308*9962Ssam 		flags &= ~defflags;
309*9962Ssam 		tc = &notc;
310*9962Ssam 		break;
311*9962Ssam 
312*9962Ssam 	default:
313*9962Ssam 		return;
3146444Swnj 	}
315*9962Ssam 	ioctl(0, TIOCSET, (char *)&flags);
316*9962Ssam 	ioctl(0, TIOCCSET, (char *)tc);
3176444Swnj }
3186444Swnj 
3199365Ssam /*VARARGS*/
3206444Swnj prf(f, a1, a2, a3)
3219365Ssam 	char *f;
3226444Swnj {
3236444Swnj 	fprintf(stderr, f, a1, a2, a3);
3246444Swnj 	fprintf(stderr, CRLF);
3256444Swnj }
3266444Swnj 
3279365Ssam lostpeer()
3286444Swnj {
3299365Ssam 	signal(SIGPIPE, SIG_IGN);
3309365Ssam 	prf("\007Lost connection");
3319365Ssam 	done();
3326444Swnj }
333