xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 12155)
16444Swnj #ifndef lint
2*12155Ssam static char sccsid[] = "@(#)rlogin.c	4.12 83/04/30";
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>
1611803Sedward #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 	}
9611803Sedward 	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,
113*12155Ssam 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n");
1146444Swnj 	exit(1);
1156444Swnj }
1166444Swnj 
1176444Swnj #define CRLF "\r\n"
1186444Swnj 
1199365Ssam int	child;
12011803Sedward int	catchild();
1219365Ssam 
1229962Ssam int	defflags;
123*12155Ssam int	tabflag;
1249962Ssam struct	ttychars deftc;
1259962Ssam struct	ttychars notc = {
1269962Ssam 	-1,	-1,	-1,	-1,	-1,
1279962Ssam 	-1,	-1,	-1,	-1,	-1,
1289962Ssam 	-1,	-1,	-1,	-1
1299962Ssam };
1306444Swnj 
1319365Ssam doit()
1326444Swnj {
1336444Swnj 	int exit();
1346444Swnj 
1359962Ssam 	ioctl(0, TIOCGET, (char *)&defflags);
136*12155Ssam 	tabflag = defflags & TBDELAY;
1379962Ssam 	defflags &= ECHO | CRMOD;
1389962Ssam 	ioctl(0, TIOCCGET, (char *)&deftc);
1399962Ssam 	notc.tc_startc = deftc.tc_startc;
1409962Ssam 	notc.tc_stopc = deftc.tc_stopc;
14111803Sedward 	sigset(SIGINT, exit);
14211803Sedward 	sigset(SIGHUP, exit);
14311803Sedward 	sigset(SIGQUIT, exit);
1449365Ssam 	child = fork();
1459365Ssam 	if (child == -1) {
1469365Ssam 		perror("rlogin: fork");
1479365Ssam 		done();
1489365Ssam 	}
14911803Sedward 	sigignore(SIGINT);
15011803Sedward 	mode(1);
1519365Ssam 	if (child == 0) {
1529365Ssam 		reader();
153*12155Ssam 		sleep(1);
154*12155Ssam 		prf("\007Connection closed.");
1556444Swnj 		exit(3);
1566444Swnj 	}
15711803Sedward 	sigset(SIGCHLD, catchild);
1589365Ssam 	writer();
159*12155Ssam 	prf("Closed connection.");
1606444Swnj 	done();
1616444Swnj }
1626444Swnj 
1636444Swnj done()
1646444Swnj {
1656444Swnj 
1666444Swnj 	mode(0);
1679365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1689365Ssam 		wait((int *)0);
1696444Swnj 	exit(0);
1706444Swnj }
1716444Swnj 
17211803Sedward catchild()
17311803Sedward {
17411803Sedward 	union wait status;
17511803Sedward 	int pid;
17611803Sedward 
17711803Sedward again:
17811803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
17911803Sedward 	if (pid == 0)
18011803Sedward 		return;
18111803Sedward 	/*
18211803Sedward 	 * if the child (reader) dies, just quit
18311803Sedward 	 */
18411803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
18511803Sedward 		done();
18611803Sedward 	goto again;
18711803Sedward }
18811803Sedward 
1896444Swnj /*
1909365Ssam  * writer: write to remote: 0 -> line.
1919365Ssam  * ~.	terminate
1929365Ssam  * ~^Z	suspend rlogin process.
19310415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
1946444Swnj  */
1959365Ssam writer()
1966444Swnj {
1979365Ssam 	char b[600], c;
1989365Ssam 	register char *p;
19911803Sedward 	register n;
2006444Swnj 
2019365Ssam top:
2029365Ssam 	p = b;
20311803Sedward 	for (;;) {
2049365Ssam 		int local;
2059365Ssam 
20611803Sedward 		n = read(0, &c, 1);
20711803Sedward 		if (n == 0)
20811803Sedward 			break;
20911803Sedward 		if (n < 0)
21011803Sedward 			if (errno == EINTR)
21111803Sedward 				continue;
21211803Sedward 			else
21311803Sedward 				break;
21411803Sedward 
2159365Ssam 		if (eight == 0)
2169365Ssam 			c &= 0177;
2179365Ssam 		/*
2189365Ssam 		 * If we're at the beginning of the line
2199365Ssam 		 * and recognize a command character, then
2209365Ssam 		 * we echo locally.  Otherwise, characters
2219365Ssam 		 * are echo'd remotely.  If the command
2229365Ssam 		 * character is doubled, this acts as a
2239365Ssam 		 * force and local echo is suppressed.
2249365Ssam 		 */
2259365Ssam 		if (p == b)
2269365Ssam 			local = (c == cmdchar);
2279365Ssam 		if (p == b + 1 && *b == cmdchar)
2289365Ssam 			local = (c != cmdchar);
2299365Ssam 		if (!local) {
2309365Ssam 			if (write(rem, &c, 1) == 0) {
2319365Ssam 				prf("line gone");
2329365Ssam 				return;
2336444Swnj 			}
2349365Ssam 			if (eight == 0)
2359365Ssam 				c &= 0177;
2369365Ssam 		} else {
2379365Ssam 			if (c == '\r' || c == '\n') {
2389962Ssam 				char cmdc = b[1];
2396444Swnj 
2409962Ssam 				if (cmdc == '.' || cmdc == deftc.tc_eofc) {
2419365Ssam 					write(0, CRLF, sizeof(CRLF));
2429365Ssam 					return;
2439962Ssam 				}
2449962Ssam 				if (cmdc == deftc.tc_suspc ||
2459962Ssam 				    cmdc == deftc.tc_dsuspc) {
2469365Ssam 					write(0, CRLF, sizeof(CRLF));
2479365Ssam 					mode(0);
24811803Sedward 					sigignore(SIGCHLD);
2499962Ssam 					kill(cmdc == deftc.tc_suspc ?
2509962Ssam 					  0 : getpid(), SIGTSTP);
25111803Sedward 					sigrelse(SIGCHLD);
2529365Ssam 					mode(1);
2539365Ssam 					goto top;
2546444Swnj 				}
2559365Ssam 				*p++ = c;
2569365Ssam 				write(rem, b, p - b);
2579365Ssam 				goto top;
2586444Swnj 			}
2599365Ssam 			write(1, &c, 1);
2606444Swnj 		}
2619365Ssam 		*p++ = c;
2629962Ssam 		if (c == deftc.tc_erase) {
2639365Ssam 			p -= 2;
2649365Ssam 			if (p < b)
2659365Ssam 				goto top;
2666444Swnj 		}
267*12155Ssam 		if (c == deftc.tc_kill || c == deftc.tc_eofc ||
2689365Ssam 		    c == '\r' || c == '\n')
2699365Ssam 			goto top;
27011803Sedward 		if (p >= &b[sizeof b])
27111803Sedward 			p--;
2726444Swnj 	}
2736444Swnj }
2746444Swnj 
2756444Swnj oob()
2766444Swnj {
27710839Ssam 	int out = 1+1, atmark;
2789365Ssam 	char waste[BUFSIZ], mark;
2796444Swnj 
2809365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2816444Swnj 	for (;;) {
28210839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
2836444Swnj 			perror("ioctl");
2846444Swnj 			break;
2856444Swnj 		}
28610839Ssam 		if (atmark)
2876444Swnj 			break;
2889365Ssam 		(void) read(rem, waste, sizeof (waste));
2896444Swnj 	}
2909207Ssam 	recv(rem, &mark, 1, SOF_OOB);
2916444Swnj 	if (mark & TIOCPKT_NOSTOP) {
2929962Ssam 		notc.tc_stopc = -1;
2939962Ssam 		notc.tc_startc = -1;
2949962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
2956444Swnj 	}
2966444Swnj 	if (mark & TIOCPKT_DOSTOP) {
2979962Ssam 		notc.tc_stopc = deftc.tc_stopc;
2989962Ssam 		notc.tc_startc = deftc.tc_startc;
2999962Ssam 		ioctl(0, TIOCCSET, (char *)&notc);
3006444Swnj 	}
3016444Swnj }
3026444Swnj 
3039365Ssam /*
3049365Ssam  * reader: read from remote: line -> 1
3059365Ssam  */
3069365Ssam reader()
3076444Swnj {
3089365Ssam 	char rb[BUFSIZ];
3099365Ssam 	register int cnt;
3106444Swnj 
31111803Sedward 	sigset(SIGURG, oob);
3126444Swnj 	{ int pid = -getpid();
3139365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
3146444Swnj 	for (;;) {
3159365Ssam 		cnt = read(rem, rb, sizeof (rb));
31611396Ssam 		if (cnt == 0)
31711396Ssam 			break;
31811396Ssam 		if (cnt < 0) {
3199365Ssam 			if (errno == EINTR)
3206444Swnj 				continue;
3216444Swnj 			break;
3226444Swnj 		}
3239365Ssam 		write(1, rb, cnt);
3246444Swnj 	}
3256444Swnj }
3266444Swnj 
3276444Swnj mode(f)
3286444Swnj {
3299962Ssam 	struct ttychars *tc;
3309962Ssam 	int flags;
3319365Ssam 
3329962Ssam 	ioctl(0, TIOCGET, (char *)&flags);
3339962Ssam 	switch (f) {
3349962Ssam 
3359962Ssam 	case 0:
336*12155Ssam 		flags &= ~(CBREAK|RAW|TBDELAY);
337*12155Ssam 		flags |= defflags|tabflag;
3389962Ssam 		tc = &deftc;
3399962Ssam 		break;
3409962Ssam 
3419962Ssam 	case 1:
342*12155Ssam 		flags |= (eight ? RAW : CBREAK);
3439962Ssam 		flags &= ~defflags;
344*12155Ssam 		/* preserve tab delays, but turn off XTABS */
345*12155Ssam 		if ((flags & TBDELAY) == XTABS)
346*12155Ssam 			flags &= ~TBDELAY;
3479962Ssam 		tc = &notc;
3489962Ssam 		break;
3499962Ssam 
3509962Ssam 	default:
3519962Ssam 		return;
3526444Swnj 	}
3539962Ssam 	ioctl(0, TIOCSET, (char *)&flags);
3549962Ssam 	ioctl(0, TIOCCSET, (char *)tc);
3556444Swnj }
3566444Swnj 
3579365Ssam /*VARARGS*/
3586444Swnj prf(f, a1, a2, a3)
3599365Ssam 	char *f;
3606444Swnj {
3616444Swnj 	fprintf(stderr, f, a1, a2, a3);
3626444Swnj 	fprintf(stderr, CRLF);
3636444Swnj }
3646444Swnj 
3659365Ssam lostpeer()
3666444Swnj {
36711803Sedward 	sigignore(SIGPIPE);
368*12155Ssam 	prf("\007Connection closed.");
3699365Ssam 	done();
3706444Swnj }
371