xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 11803)
16444Swnj #ifndef lint
2*11803Sedward static char sccsid[] = "@(#)rlogin.c	4.11 83/03/31";
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>
16*11803Sedward #include <wait.h>
176444Swnj 
186444Swnj /*
199365Ssam  * rlogin - remote login
206444Swnj  */
216444Swnj char	*index(), *rindex(), *malloc(), *getenv();
226444Swnj struct	passwd *getpwuid();
239365Ssam char	*name;
246444Swnj int	rem;
256444Swnj char	cmdchar = '~';
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;
4210415Ssam 	int uid, options = 0;
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:
5310839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
546444Swnj 		argv++, argc--;
5510415Ssam 		options |= SO_DEBUG;
566444Swnj 		goto another;
576444Swnj 	}
5810839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
596444Swnj 		argv++, argc--;
606444Swnj 		if (argc == 0)
616444Swnj 			goto usage;
626444Swnj 		name = *argv++; argc--;
636444Swnj 		goto another;
646444Swnj 	}
6510839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
666444Swnj 		cmdchar = argv[0][2];
676444Swnj 		argv++, argc--;
686444Swnj 		goto another;
696444Swnj 	}
7010839Ssam 	if (argc > 0 && !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);
929962Ssam 	if (ioctl(0, TIOCGETP, &ttyb)==0) {
936444Swnj 		strcat(term, "/");
946444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
956444Swnj 	}
96*11803Sedward 	sigset(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);
10110415Ssam 	if (options & SO_DEBUG &&
10210415Ssam 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
10310415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1049365Ssam 	uid = getuid();
1059365Ssam 	if (setuid(uid) < 0) {
1069365Ssam 		perror("rlogin: setuid");
1079365Ssam 		exit(1);
1089365Ssam 	}
1099365Ssam 	doit();
1109365Ssam 	/*NOTREACHED*/
1116444Swnj usage:
1126444Swnj 	fprintf(stderr,
1136444Swnj 	    "usage: rlogin host [ -ex ] [ -l username ]\n");
1146444Swnj 	exit(1);
1156444Swnj }
1166444Swnj 
1176444Swnj #define CRLF "\r\n"
1186444Swnj 
1199365Ssam int	child;
120*11803Sedward int	catchild();
1219365Ssam 
1229962Ssam int	defflags;
1239962Ssam struct	ttychars deftc;
1249962Ssam struct	ttychars notc = {
1259962Ssam 	-1,	-1,	-1,	-1,	-1,
1269962Ssam 	-1,	-1,	-1,	-1,	-1,
1279962Ssam 	-1,	-1,	-1,	-1
1289962Ssam };
1296444Swnj 
1309365Ssam doit()
1316444Swnj {
1326444Swnj 	int exit();
1336444Swnj 
1349962Ssam 	ioctl(0, TIOCGET, (char *)&defflags);
1359962Ssam 	defflags &= ECHO | CRMOD;
1369962Ssam 	ioctl(0, TIOCCGET, (char *)&deftc);
1379962Ssam 	notc.tc_startc = deftc.tc_startc;
1389962Ssam 	notc.tc_stopc = deftc.tc_stopc;
139*11803Sedward 	sigset(SIGINT, exit);
140*11803Sedward 	sigset(SIGHUP, exit);
141*11803Sedward 	sigset(SIGQUIT, exit);
1429365Ssam 	child = fork();
1439365Ssam 	if (child == -1) {
1449365Ssam 		perror("rlogin: fork");
1459365Ssam 		done();
1469365Ssam 	}
147*11803Sedward 	sigignore(SIGINT);
148*11803Sedward 	mode(1);
1499365Ssam 	if (child == 0) {
1509365Ssam 		reader();
1516444Swnj 		prf("\007Lost connection.");
1526444Swnj 		exit(3);
1536444Swnj 	}
154*11803Sedward 	sigset(SIGCHLD, catchild);
1559365Ssam 	writer();
1566444Swnj 	prf("Disconnected.");
1576444Swnj 	done();
1586444Swnj }
1596444Swnj 
1606444Swnj done()
1616444Swnj {
1626444Swnj 
1636444Swnj 	mode(0);
1649365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1659365Ssam 		wait((int *)0);
1666444Swnj 	exit(0);
1676444Swnj }
1686444Swnj 
169*11803Sedward catchild()
170*11803Sedward {
171*11803Sedward 	union wait status;
172*11803Sedward 	int pid;
173*11803Sedward 
174*11803Sedward again:
175*11803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
176*11803Sedward 	if (pid == 0)
177*11803Sedward 		return;
178*11803Sedward 	/*
179*11803Sedward 	 * if the child (reader) dies, just quit
180*11803Sedward 	 */
181*11803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
182*11803Sedward 		done();
183*11803Sedward 	goto again;
184*11803Sedward }
185*11803Sedward 
1866444Swnj /*
1879365Ssam  * writer: write to remote: 0 -> line.
1889365Ssam  * ~.	terminate
1899365Ssam  * ~^Z	suspend rlogin process.
19010415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
1916444Swnj  */
1929365Ssam writer()
1936444Swnj {
1949365Ssam 	char b[600], c;
1959365Ssam 	register char *p;
196*11803Sedward 	register n;
1976444Swnj 
1989365Ssam top:
1999365Ssam 	p = b;
200*11803Sedward 	for (;;) {
2019365Ssam 		int local;
2029365Ssam 
203*11803Sedward 		n = read(0, &c, 1);
204*11803Sedward 		if (n == 0)
205*11803Sedward 			break;
206*11803Sedward 		if (n < 0)
207*11803Sedward 			if (errno == EINTR)
208*11803Sedward 				continue;
209*11803Sedward 			else
210*11803Sedward 				break;
211*11803Sedward 
2129365Ssam 		if (eight == 0)
2139365Ssam 			c &= 0177;
2149365Ssam 		/*
2159365Ssam 		 * If we're at the beginning of the line
2169365Ssam 		 * and recognize a command character, then
2179365Ssam 		 * we echo locally.  Otherwise, characters
2189365Ssam 		 * are echo'd remotely.  If the command
2199365Ssam 		 * character is doubled, this acts as a
2209365Ssam 		 * force and local echo is suppressed.
2219365Ssam 		 */
2229365Ssam 		if (p == b)
2239365Ssam 			local = (c == cmdchar);
2249365Ssam 		if (p == b + 1 && *b == cmdchar)
2259365Ssam 			local = (c != cmdchar);
2269365Ssam 		if (!local) {
2279365Ssam 			if (write(rem, &c, 1) == 0) {
2289365Ssam 				prf("line gone");
2299365Ssam 				return;
2306444Swnj 			}
2319365Ssam 			if (eight == 0)
2329365Ssam 				c &= 0177;
2339365Ssam 		} else {
2349365Ssam 			if (c == 0177)
2359962Ssam 				c = deftc.tc_kill;
2369365Ssam 			if (c == '\r' || c == '\n') {
2379962Ssam 				char cmdc = b[1];
2386444Swnj 
2399962Ssam 				if (cmdc == '.' || cmdc == deftc.tc_eofc) {
2409365Ssam 					write(0, CRLF, sizeof(CRLF));
2419365Ssam 					return;
2429962Ssam 				}
2439962Ssam 				if (cmdc == deftc.tc_suspc ||
2449962Ssam 				    cmdc == deftc.tc_dsuspc) {
2459365Ssam 					write(0, CRLF, sizeof(CRLF));
2469365Ssam 					mode(0);
247*11803Sedward 					sigignore(SIGCHLD);
2489962Ssam 					kill(cmdc == deftc.tc_suspc ?
2499962Ssam 					  0 : getpid(), SIGTSTP);
250*11803Sedward 					sigrelse(SIGCHLD);
2519365Ssam 					mode(1);
2529365Ssam 					goto top;
2536444Swnj 				}
2549365Ssam 				*p++ = c;
2559365Ssam 				write(rem, b, p - b);
2569365Ssam 				goto top;
2576444Swnj 			}
2589365Ssam 			write(1, &c, 1);
2596444Swnj 		}
2609365Ssam 		*p++ = c;
2619962Ssam 		if (c == deftc.tc_erase) {
2629365Ssam 			p -= 2;
2639365Ssam 			if (p < b)
2649365Ssam 				goto top;
2656444Swnj 		}
2669962Ssam 		if (c == deftc.tc_kill || c == 0177 || c == deftc.tc_eofc ||
2679365Ssam 		    c == '\r' || c == '\n')
2689365Ssam 			goto top;
269*11803Sedward 		if (p >= &b[sizeof b])
270*11803Sedward 			p--;
2716444Swnj 	}
2726444Swnj }
2736444Swnj 
2746444Swnj oob()
2756444Swnj {
27610839Ssam 	int out = 1+1, atmark;
2779365Ssam 	char waste[BUFSIZ], mark;
2786444Swnj 
2799365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2806444Swnj 	for (;;) {
28110839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
2826444Swnj 			perror("ioctl");
2836444Swnj 			break;
2846444Swnj 		}
28510839Ssam 		if (atmark)
2866444Swnj 			break;
2879365Ssam 		(void) read(rem, waste, sizeof (waste));
2886444Swnj 	}
2899207Ssam 	recv(rem, &mark, 1, SOF_OOB);
2906444Swnj 	if (mark & TIOCPKT_NOSTOP) {
2919962Ssam 		notc.tc_stopc = -1;
2929962Ssam 		notc.tc_startc = -1;
2939962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2946444Swnj 	}
2956444Swnj 	if (mark & TIOCPKT_DOSTOP) {
2969962Ssam 		notc.tc_stopc = deftc.tc_stopc;
2979962Ssam 		notc.tc_startc = deftc.tc_startc;
2989962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2996444Swnj 	}
3006444Swnj }
3016444Swnj 
3029365Ssam /*
3039365Ssam  * reader: read from remote: line -> 1
3049365Ssam  */
3059365Ssam reader()
3066444Swnj {
3079365Ssam 	char rb[BUFSIZ];
3089365Ssam 	register int cnt;
3096444Swnj 
310*11803Sedward 	sigset(SIGURG, oob);
3116444Swnj 	{ int pid = -getpid();
3129365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
3136444Swnj 	for (;;) {
3149365Ssam 		cnt = read(rem, rb, sizeof (rb));
31511396Ssam 		if (cnt == 0)
31611396Ssam 			break;
31711396Ssam 		if (cnt < 0) {
3189365Ssam 			if (errno == EINTR)
3196444Swnj 				continue;
3206444Swnj 			break;
3216444Swnj 		}
3229365Ssam 		write(1, rb, cnt);
3236444Swnj 	}
3246444Swnj }
3256444Swnj 
3266444Swnj mode(f)
3276444Swnj {
3289962Ssam 	struct ttychars *tc;
3299962Ssam 	int flags;
3309365Ssam 
3319962Ssam 	ioctl(0, TIOCGET, (char *)&flags);
3329962Ssam 	switch (f) {
3339962Ssam 
3349962Ssam 	case 0:
3359962Ssam 		flags &= ~CBREAK;
3369962Ssam 		flags |= defflags;
3379962Ssam 		tc = &deftc;
3389962Ssam 		break;
3399962Ssam 
3409962Ssam 	case 1:
3419962Ssam 		flags |= CBREAK;
3429962Ssam 		flags &= ~defflags;
3439962Ssam 		tc = &notc;
3449962Ssam 		break;
3459962Ssam 
3469962Ssam 	default:
3479962Ssam 		return;
3486444Swnj 	}
3499962Ssam 	ioctl(0, TIOCSET, (char *)&flags);
3509962Ssam 	ioctl(0, TIOCCSET, (char *)tc);
3516444Swnj }
3526444Swnj 
3539365Ssam /*VARARGS*/
3546444Swnj prf(f, a1, a2, a3)
3559365Ssam 	char *f;
3566444Swnj {
3576444Swnj 	fprintf(stderr, f, a1, a2, a3);
3586444Swnj 	fprintf(stderr, CRLF);
3596444Swnj }
3606444Swnj 
3619365Ssam lostpeer()
3626444Swnj {
363*11803Sedward 	sigignore(SIGPIPE);
3649365Ssam 	prf("\007Lost connection");
3659365Ssam 	done();
3666444Swnj }
367