xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 13075)
16444Swnj #ifndef lint
2*13075Ssam static char sccsid[] = "@(#)rlogin.c	4.14 83/06/13";
36444Swnj #endif
46444Swnj 
512990Ssam /*
612990Ssam  * rlogin - remote login
712990Ssam  */
86444Swnj #include <sys/types.h>
96444Swnj #include <sys/socket.h>
109365Ssam 
119207Ssam #include <netinet/in.h>
129365Ssam 
139365Ssam #include <stdio.h>
149365Ssam #include <sgtty.h>
156444Swnj #include <errno.h>
166444Swnj #include <pwd.h>
179365Ssam #include <signal.h>
189365Ssam #include <netdb.h>
1911803Sedward #include <wait.h>
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 	}
9612990Ssam 	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);
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,
11312155Ssam 	    "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 
122*13075Ssam int	defflags, tabflag;
123*13075Ssam char	deferase, defkill;
124*13075Ssam struct	tchars deftc;
125*13075Ssam struct	ltchars defltc;
126*13075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
127*13075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1286444Swnj 
1299365Ssam doit()
1306444Swnj {
1316444Swnj 	int exit();
132*13075Ssam 	struct sgttyb sb;
1336444Swnj 
134*13075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
135*13075Ssam 	defflags = sb.sg_flags;
13612155Ssam 	tabflag = defflags & TBDELAY;
1379962Ssam 	defflags &= ECHO | CRMOD;
138*13075Ssam 	deferase = sb.sg_erase;
139*13075Ssam 	defkill = sb.sg_kill;
140*13075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
141*13075Ssam 	notc.t_startc = deftc.t_startc;
142*13075Ssam 	notc.t_stopc = deftc.t_stopc;
143*13075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
14412990Ssam 	signal(SIGINT, exit);
14512990Ssam 	signal(SIGHUP, exit);
14612990Ssam 	signal(SIGQUIT, exit);
1479365Ssam 	child = fork();
1489365Ssam 	if (child == -1) {
1499365Ssam 		perror("rlogin: fork");
1509365Ssam 		done();
1519365Ssam 	}
15212990Ssam 	signal(SIGINT, SIG_IGN);
15311803Sedward 	mode(1);
1549365Ssam 	if (child == 0) {
1559365Ssam 		reader();
15612155Ssam 		sleep(1);
15712155Ssam 		prf("\007Connection closed.");
1586444Swnj 		exit(3);
1596444Swnj 	}
16012990Ssam 	signal(SIGCHLD, catchild);
1619365Ssam 	writer();
16212155Ssam 	prf("Closed connection.");
1636444Swnj 	done();
1646444Swnj }
1656444Swnj 
1666444Swnj done()
1676444Swnj {
1686444Swnj 
1696444Swnj 	mode(0);
1709365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1719365Ssam 		wait((int *)0);
1726444Swnj 	exit(0);
1736444Swnj }
1746444Swnj 
17511803Sedward catchild()
17611803Sedward {
17711803Sedward 	union wait status;
17811803Sedward 	int pid;
17911803Sedward 
18011803Sedward again:
18111803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
18211803Sedward 	if (pid == 0)
18311803Sedward 		return;
18411803Sedward 	/*
18511803Sedward 	 * if the child (reader) dies, just quit
18611803Sedward 	 */
18711803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
18811803Sedward 		done();
18911803Sedward 	goto again;
19011803Sedward }
19111803Sedward 
1926444Swnj /*
1939365Ssam  * writer: write to remote: 0 -> line.
1949365Ssam  * ~.	terminate
1959365Ssam  * ~^Z	suspend rlogin process.
19610415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
1976444Swnj  */
1989365Ssam writer()
1996444Swnj {
2009365Ssam 	char b[600], c;
2019365Ssam 	register char *p;
20211803Sedward 	register n;
2036444Swnj 
2049365Ssam top:
2059365Ssam 	p = b;
20611803Sedward 	for (;;) {
2079365Ssam 		int local;
2089365Ssam 
20911803Sedward 		n = read(0, &c, 1);
21011803Sedward 		if (n == 0)
21111803Sedward 			break;
21211803Sedward 		if (n < 0)
21311803Sedward 			if (errno == EINTR)
21411803Sedward 				continue;
21511803Sedward 			else
21611803Sedward 				break;
21711803Sedward 
2189365Ssam 		if (eight == 0)
2199365Ssam 			c &= 0177;
2209365Ssam 		/*
2219365Ssam 		 * If we're at the beginning of the line
2229365Ssam 		 * and recognize a command character, then
2239365Ssam 		 * we echo locally.  Otherwise, characters
2249365Ssam 		 * are echo'd remotely.  If the command
2259365Ssam 		 * character is doubled, this acts as a
2269365Ssam 		 * force and local echo is suppressed.
2279365Ssam 		 */
2289365Ssam 		if (p == b)
2299365Ssam 			local = (c == cmdchar);
2309365Ssam 		if (p == b + 1 && *b == cmdchar)
2319365Ssam 			local = (c != cmdchar);
2329365Ssam 		if (!local) {
2339365Ssam 			if (write(rem, &c, 1) == 0) {
2349365Ssam 				prf("line gone");
2359365Ssam 				return;
2366444Swnj 			}
2379365Ssam 			if (eight == 0)
2389365Ssam 				c &= 0177;
2399365Ssam 		} else {
2409365Ssam 			if (c == '\r' || c == '\n') {
2419962Ssam 				char cmdc = b[1];
2426444Swnj 
243*13075Ssam 				if (cmdc == '.' || cmdc == deftc.t_eofc) {
2449365Ssam 					write(0, CRLF, sizeof(CRLF));
2459365Ssam 					return;
2469962Ssam 				}
247*13075Ssam 				if (cmdc == defltc.t_suspc ||
248*13075Ssam 				    cmdc == defltc.t_dsuspc) {
2499365Ssam 					write(0, CRLF, sizeof(CRLF));
2509365Ssam 					mode(0);
25112990Ssam 					signal(SIGCHLD, SIG_IGN);
252*13075Ssam 					kill(cmdc == defltc.t_suspc ?
2539962Ssam 					  0 : getpid(), SIGTSTP);
25412990Ssam 					signal(SIGCHLD, catchild);
2559365Ssam 					mode(1);
2569365Ssam 					goto top;
2576444Swnj 				}
2589365Ssam 				*p++ = c;
2599365Ssam 				write(rem, b, p - b);
2609365Ssam 				goto top;
2616444Swnj 			}
2629365Ssam 			write(1, &c, 1);
2636444Swnj 		}
2649365Ssam 		*p++ = c;
265*13075Ssam 		if (c == deferase) {
2669365Ssam 			p -= 2;
2679365Ssam 			if (p < b)
2689365Ssam 				goto top;
2696444Swnj 		}
270*13075Ssam 		if (c == defkill || c == deftc.t_eofc ||
2719365Ssam 		    c == '\r' || c == '\n')
2729365Ssam 			goto top;
27311803Sedward 		if (p >= &b[sizeof b])
27411803Sedward 			p--;
2756444Swnj 	}
2766444Swnj }
2776444Swnj 
2786444Swnj oob()
2796444Swnj {
28010839Ssam 	int out = 1+1, atmark;
2819365Ssam 	char waste[BUFSIZ], mark;
2826444Swnj 
2839365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2846444Swnj 	for (;;) {
28510839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
2866444Swnj 			perror("ioctl");
2876444Swnj 			break;
2886444Swnj 		}
28910839Ssam 		if (atmark)
2906444Swnj 			break;
2919365Ssam 		(void) read(rem, waste, sizeof (waste));
2926444Swnj 	}
29312990Ssam 	recv(rem, &mark, 1, MSG_OOB);
2946444Swnj 	if (mark & TIOCPKT_NOSTOP) {
295*13075Ssam 		notc.t_stopc = -1;
296*13075Ssam 		notc.t_startc = -1;
297*13075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
2986444Swnj 	}
2996444Swnj 	if (mark & TIOCPKT_DOSTOP) {
300*13075Ssam 		notc.t_stopc = deftc.t_stopc;
301*13075Ssam 		notc.t_startc = deftc.t_startc;
302*13075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
3036444Swnj 	}
3046444Swnj }
3056444Swnj 
3069365Ssam /*
3079365Ssam  * reader: read from remote: line -> 1
3089365Ssam  */
3099365Ssam reader()
3106444Swnj {
3119365Ssam 	char rb[BUFSIZ];
3129365Ssam 	register int cnt;
3136444Swnj 
31412990Ssam 	signal(SIGURG, oob);
3156444Swnj 	{ int pid = -getpid();
3169365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
3176444Swnj 	for (;;) {
3189365Ssam 		cnt = read(rem, rb, sizeof (rb));
31911396Ssam 		if (cnt == 0)
32011396Ssam 			break;
32111396Ssam 		if (cnt < 0) {
3229365Ssam 			if (errno == EINTR)
3236444Swnj 				continue;
3246444Swnj 			break;
3256444Swnj 		}
3269365Ssam 		write(1, rb, cnt);
3276444Swnj 	}
3286444Swnj }
3296444Swnj 
3306444Swnj mode(f)
3316444Swnj {
332*13075Ssam 	struct tchars *tc;
333*13075Ssam 	struct ltchars *ltc;
334*13075Ssam 	struct sgttyb sb;
3359365Ssam 
336*13075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
3379962Ssam 	switch (f) {
3389962Ssam 
3399962Ssam 	case 0:
340*13075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
341*13075Ssam 		sb.sg_flags |= defflags|tabflag;
3429962Ssam 		tc = &deftc;
343*13075Ssam 		ltc = &defltc;
344*13075Ssam 		sb.sg_kill = defkill;
345*13075Ssam 		sb.sg_erase = deferase;
3469962Ssam 		break;
3479962Ssam 
3489962Ssam 	case 1:
349*13075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
350*13075Ssam 		sb.sg_flags &= ~defflags;
35112155Ssam 		/* preserve tab delays, but turn off XTABS */
352*13075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
353*13075Ssam 			sb.sg_flags &= ~TBDELAY;
3549962Ssam 		tc = &notc;
355*13075Ssam 		ltc = &noltc;
356*13075Ssam 		sb.sg_kill = sb.sg_erase = -1;
3579962Ssam 		break;
3589962Ssam 
3599962Ssam 	default:
3609962Ssam 		return;
3616444Swnj 	}
362*13075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
363*13075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
364*13075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
3656444Swnj }
3666444Swnj 
3679365Ssam /*VARARGS*/
3686444Swnj prf(f, a1, a2, a3)
3699365Ssam 	char *f;
3706444Swnj {
3716444Swnj 	fprintf(stderr, f, a1, a2, a3);
3726444Swnj 	fprintf(stderr, CRLF);
3736444Swnj }
3746444Swnj 
3759365Ssam lostpeer()
3766444Swnj {
37712990Ssam 	signal(SIGPIPE, SIG_IGN);
37812155Ssam 	prf("\007Connection closed.");
3799365Ssam 	done();
3806444Swnj }
381