xref: /csrg-svn/usr.bin/rlogin/rlogin.c (revision 17449)
16444Swnj #ifndef lint
2*17449Slepreau static char sccsid[] = "@(#)rlogin.c	4.16 (Berkeley) 84/12/03";
36444Swnj #endif
46444Swnj 
512990Ssam /*
612990Ssam  * rlogin - remote login
712990Ssam  */
86444Swnj #include <sys/types.h>
96444Swnj #include <sys/socket.h>
1013620Ssam #include <sys/wait.h>
119365Ssam 
129207Ssam #include <netinet/in.h>
139365Ssam 
149365Ssam #include <stdio.h>
159365Ssam #include <sgtty.h>
166444Swnj #include <errno.h>
176444Swnj #include <pwd.h>
189365Ssam #include <signal.h>
199365Ssam #include <netdb.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;
43*17449Slepreau 	int on = 1;
446444Swnj 
456444Swnj 	host = rindex(argv[0], '/');
466444Swnj 	if (host)
476444Swnj 		host++;
486444Swnj 	else
496444Swnj 		host = argv[0];
506444Swnj 	argv++, --argc;
516444Swnj 	if (!strcmp(host, "rlogin"))
526444Swnj 		host = *argv++, --argc;
536444Swnj another:
5410839Ssam 	if (argc > 0 && !strcmp(*argv, "-d")) {
556444Swnj 		argv++, argc--;
5610415Ssam 		options |= SO_DEBUG;
576444Swnj 		goto another;
586444Swnj 	}
5910839Ssam 	if (argc > 0 && !strcmp(*argv, "-l")) {
606444Swnj 		argv++, argc--;
616444Swnj 		if (argc == 0)
626444Swnj 			goto usage;
636444Swnj 		name = *argv++; argc--;
646444Swnj 		goto another;
656444Swnj 	}
6610839Ssam 	if (argc > 0 && !strncmp(*argv, "-e", 2)) {
676444Swnj 		cmdchar = argv[0][2];
686444Swnj 		argv++, argc--;
696444Swnj 		goto another;
706444Swnj 	}
7110839Ssam 	if (argc > 0 && !strcmp(*argv, "-8")) {
726444Swnj 		eight = 1;
736444Swnj 		argv++, argc--;
746444Swnj 		goto another;
756444Swnj 	}
766444Swnj 	if (host == 0)
776444Swnj 		goto usage;
786444Swnj 	if (argc > 0)
796444Swnj 		goto usage;
806444Swnj 	pwd = getpwuid(getuid());
816444Swnj 	if (pwd == 0) {
826444Swnj 		fprintf(stderr, "Who are you?\n");
836444Swnj 		exit(1);
846444Swnj 	}
859365Ssam 	sp = getservbyname("login", "tcp");
869365Ssam 	if (sp == 0) {
879365Ssam 		fprintf(stderr, "rlogin: login/tcp: unknown service\n");
889365Ssam 		exit(2);
899365Ssam 	}
909241Ssam 	cp = getenv("TERM");
919241Ssam 	if (cp)
929241Ssam 		strcpy(term, cp);
939962Ssam 	if (ioctl(0, TIOCGETP, &ttyb)==0) {
946444Swnj 		strcat(term, "/");
956444Swnj 		strcat(term, speeds[ttyb.sg_ospeed]);
966444Swnj 	}
9712990Ssam 	signal(SIGPIPE, lostpeer);
989365Ssam         rem = rcmd(&host, sp->s_port, pwd->pw_name,
996444Swnj 	    name ? name : pwd->pw_name, term, 0);
1006444Swnj         if (rem < 0)
1016444Swnj                 exit(1);
10210415Ssam 	if (options & SO_DEBUG &&
103*17449Slepreau 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
10410415Ssam 		perror("rlogin: setsockopt (SO_DEBUG)");
1059365Ssam 	uid = getuid();
1069365Ssam 	if (setuid(uid) < 0) {
1079365Ssam 		perror("rlogin: setuid");
1089365Ssam 		exit(1);
1099365Ssam 	}
1109365Ssam 	doit();
1119365Ssam 	/*NOTREACHED*/
1126444Swnj usage:
1136444Swnj 	fprintf(stderr,
11412155Ssam 	    "usage: rlogin host [ -ex ] [ -l username ] [ -8 ]\n");
1156444Swnj 	exit(1);
1166444Swnj }
1176444Swnj 
1186444Swnj #define CRLF "\r\n"
1196444Swnj 
1209365Ssam int	child;
12111803Sedward int	catchild();
1229365Ssam 
12313075Ssam int	defflags, tabflag;
12413075Ssam char	deferase, defkill;
12513075Ssam struct	tchars deftc;
12613075Ssam struct	ltchars defltc;
12713075Ssam struct	tchars notc =	{ -1, -1, -1, -1, -1, -1 };
12813075Ssam struct	ltchars noltc =	{ -1, -1, -1, -1, -1, -1 };
1296444Swnj 
1309365Ssam doit()
1316444Swnj {
1326444Swnj 	int exit();
13313075Ssam 	struct sgttyb sb;
1346444Swnj 
13513075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
13613075Ssam 	defflags = sb.sg_flags;
13712155Ssam 	tabflag = defflags & TBDELAY;
1389962Ssam 	defflags &= ECHO | CRMOD;
13913075Ssam 	deferase = sb.sg_erase;
14013075Ssam 	defkill = sb.sg_kill;
14113075Ssam 	ioctl(0, TIOCGETC, (char *)&deftc);
14213075Ssam 	notc.t_startc = deftc.t_startc;
14313075Ssam 	notc.t_stopc = deftc.t_stopc;
14413075Ssam 	ioctl(0, TIOCGLTC, (char *)&defltc);
14512990Ssam 	signal(SIGINT, exit);
14612990Ssam 	signal(SIGHUP, exit);
14712990Ssam 	signal(SIGQUIT, exit);
1489365Ssam 	child = fork();
1499365Ssam 	if (child == -1) {
1509365Ssam 		perror("rlogin: fork");
1519365Ssam 		done();
1529365Ssam 	}
15312990Ssam 	signal(SIGINT, SIG_IGN);
15411803Sedward 	mode(1);
1559365Ssam 	if (child == 0) {
1569365Ssam 		reader();
15712155Ssam 		sleep(1);
15812155Ssam 		prf("\007Connection closed.");
1596444Swnj 		exit(3);
1606444Swnj 	}
16112990Ssam 	signal(SIGCHLD, catchild);
1629365Ssam 	writer();
16312155Ssam 	prf("Closed connection.");
1646444Swnj 	done();
1656444Swnj }
1666444Swnj 
1676444Swnj done()
1686444Swnj {
1696444Swnj 
1706444Swnj 	mode(0);
1719365Ssam 	if (child > 0 && kill(child, SIGKILL) >= 0)
1729365Ssam 		wait((int *)0);
1736444Swnj 	exit(0);
1746444Swnj }
1756444Swnj 
17611803Sedward catchild()
17711803Sedward {
17811803Sedward 	union wait status;
17911803Sedward 	int pid;
18011803Sedward 
18111803Sedward again:
18211803Sedward 	pid = wait3(&status, WNOHANG|WUNTRACED, 0);
18311803Sedward 	if (pid == 0)
18411803Sedward 		return;
18511803Sedward 	/*
18611803Sedward 	 * if the child (reader) dies, just quit
18711803Sedward 	 */
18811803Sedward 	if (pid < 0 || pid == child && !WIFSTOPPED(status))
18911803Sedward 		done();
19011803Sedward 	goto again;
19111803Sedward }
19211803Sedward 
1936444Swnj /*
1949365Ssam  * writer: write to remote: 0 -> line.
1959365Ssam  * ~.	terminate
1969365Ssam  * ~^Z	suspend rlogin process.
19710415Ssam  * ~^Y  suspend rlogin process, but leave reader alone.
1986444Swnj  */
1999365Ssam writer()
2006444Swnj {
2019365Ssam 	char b[600], c;
2029365Ssam 	register char *p;
20311803Sedward 	register n;
2046444Swnj 
2059365Ssam top:
2069365Ssam 	p = b;
20711803Sedward 	for (;;) {
2089365Ssam 		int local;
2099365Ssam 
21011803Sedward 		n = read(0, &c, 1);
21111803Sedward 		if (n == 0)
21211803Sedward 			break;
21311803Sedward 		if (n < 0)
21411803Sedward 			if (errno == EINTR)
21511803Sedward 				continue;
21611803Sedward 			else
21711803Sedward 				break;
21811803Sedward 
2199365Ssam 		if (eight == 0)
2209365Ssam 			c &= 0177;
2219365Ssam 		/*
2229365Ssam 		 * If we're at the beginning of the line
2239365Ssam 		 * and recognize a command character, then
2249365Ssam 		 * we echo locally.  Otherwise, characters
2259365Ssam 		 * are echo'd remotely.  If the command
2269365Ssam 		 * character is doubled, this acts as a
2279365Ssam 		 * force and local echo is suppressed.
2289365Ssam 		 */
2299365Ssam 		if (p == b)
2309365Ssam 			local = (c == cmdchar);
2319365Ssam 		if (p == b + 1 && *b == cmdchar)
2329365Ssam 			local = (c != cmdchar);
2339365Ssam 		if (!local) {
2349365Ssam 			if (write(rem, &c, 1) == 0) {
2359365Ssam 				prf("line gone");
2369365Ssam 				return;
2376444Swnj 			}
2389365Ssam 			if (eight == 0)
2399365Ssam 				c &= 0177;
2409365Ssam 		} else {
2419365Ssam 			if (c == '\r' || c == '\n') {
2429962Ssam 				char cmdc = b[1];
2436444Swnj 
24413075Ssam 				if (cmdc == '.' || cmdc == deftc.t_eofc) {
2459365Ssam 					write(0, CRLF, sizeof(CRLF));
2469365Ssam 					return;
2479962Ssam 				}
24813075Ssam 				if (cmdc == defltc.t_suspc ||
24913075Ssam 				    cmdc == defltc.t_dsuspc) {
2509365Ssam 					write(0, CRLF, sizeof(CRLF));
2519365Ssam 					mode(0);
25212990Ssam 					signal(SIGCHLD, SIG_IGN);
25313075Ssam 					kill(cmdc == defltc.t_suspc ?
2549962Ssam 					  0 : getpid(), SIGTSTP);
25512990Ssam 					signal(SIGCHLD, catchild);
2569365Ssam 					mode(1);
2579365Ssam 					goto top;
2586444Swnj 				}
2599365Ssam 				*p++ = c;
2609365Ssam 				write(rem, b, p - b);
2619365Ssam 				goto top;
2626444Swnj 			}
2639365Ssam 			write(1, &c, 1);
2646444Swnj 		}
2659365Ssam 		*p++ = c;
26613075Ssam 		if (c == deferase) {
2679365Ssam 			p -= 2;
2689365Ssam 			if (p < b)
2699365Ssam 				goto top;
2706444Swnj 		}
27113075Ssam 		if (c == defkill || c == deftc.t_eofc ||
2729365Ssam 		    c == '\r' || c == '\n')
2739365Ssam 			goto top;
27411803Sedward 		if (p >= &b[sizeof b])
27511803Sedward 			p--;
2766444Swnj 	}
2776444Swnj }
2786444Swnj 
2796444Swnj oob()
2806444Swnj {
28110839Ssam 	int out = 1+1, atmark;
2829365Ssam 	char waste[BUFSIZ], mark;
2836444Swnj 
2849365Ssam 	ioctl(1, TIOCFLUSH, (char *)&out);
2856444Swnj 	for (;;) {
28610839Ssam 		if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
2876444Swnj 			perror("ioctl");
2886444Swnj 			break;
2896444Swnj 		}
29010839Ssam 		if (atmark)
2916444Swnj 			break;
2929365Ssam 		(void) read(rem, waste, sizeof (waste));
2936444Swnj 	}
29412990Ssam 	recv(rem, &mark, 1, MSG_OOB);
2956444Swnj 	if (mark & TIOCPKT_NOSTOP) {
29613075Ssam 		notc.t_stopc = -1;
29713075Ssam 		notc.t_startc = -1;
29813075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
2996444Swnj 	}
3006444Swnj 	if (mark & TIOCPKT_DOSTOP) {
30113075Ssam 		notc.t_stopc = deftc.t_stopc;
30213075Ssam 		notc.t_startc = deftc.t_startc;
30313075Ssam 		ioctl(0, TIOCSETC, (char *)&notc);
3046444Swnj 	}
3056444Swnj }
3066444Swnj 
3079365Ssam /*
3089365Ssam  * reader: read from remote: line -> 1
3099365Ssam  */
3109365Ssam reader()
3116444Swnj {
3129365Ssam 	char rb[BUFSIZ];
3139365Ssam 	register int cnt;
3146444Swnj 
31512990Ssam 	signal(SIGURG, oob);
3166444Swnj 	{ int pid = -getpid();
3179365Ssam 	  ioctl(rem, SIOCSPGRP, (char *)&pid); }
3186444Swnj 	for (;;) {
3199365Ssam 		cnt = read(rem, rb, sizeof (rb));
32011396Ssam 		if (cnt == 0)
32111396Ssam 			break;
32211396Ssam 		if (cnt < 0) {
3239365Ssam 			if (errno == EINTR)
3246444Swnj 				continue;
3256444Swnj 			break;
3266444Swnj 		}
3279365Ssam 		write(1, rb, cnt);
3286444Swnj 	}
3296444Swnj }
3306444Swnj 
3316444Swnj mode(f)
3326444Swnj {
33313075Ssam 	struct tchars *tc;
33413075Ssam 	struct ltchars *ltc;
33513075Ssam 	struct sgttyb sb;
3369365Ssam 
33713075Ssam 	ioctl(0, TIOCGETP, (char *)&sb);
3389962Ssam 	switch (f) {
3399962Ssam 
3409962Ssam 	case 0:
34113075Ssam 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
34213075Ssam 		sb.sg_flags |= defflags|tabflag;
3439962Ssam 		tc = &deftc;
34413075Ssam 		ltc = &defltc;
34513075Ssam 		sb.sg_kill = defkill;
34613075Ssam 		sb.sg_erase = deferase;
3479962Ssam 		break;
3489962Ssam 
3499962Ssam 	case 1:
35013075Ssam 		sb.sg_flags |= (eight ? RAW : CBREAK);
35113075Ssam 		sb.sg_flags &= ~defflags;
35212155Ssam 		/* preserve tab delays, but turn off XTABS */
35313075Ssam 		if ((sb.sg_flags & TBDELAY) == XTABS)
35413075Ssam 			sb.sg_flags &= ~TBDELAY;
3559962Ssam 		tc = &notc;
35613075Ssam 		ltc = &noltc;
35713075Ssam 		sb.sg_kill = sb.sg_erase = -1;
3589962Ssam 		break;
3599962Ssam 
3609962Ssam 	default:
3619962Ssam 		return;
3626444Swnj 	}
36313075Ssam 	ioctl(0, TIOCSLTC, (char *)ltc);
36413075Ssam 	ioctl(0, TIOCSETC, (char *)tc);
36513075Ssam 	ioctl(0, TIOCSETN, (char *)&sb);
3666444Swnj }
3676444Swnj 
3689365Ssam /*VARARGS*/
3696444Swnj prf(f, a1, a2, a3)
3709365Ssam 	char *f;
3716444Swnj {
3726444Swnj 	fprintf(stderr, f, a1, a2, a3);
3736444Swnj 	fprintf(stderr, CRLF);
3746444Swnj }
3756444Swnj 
3769365Ssam lostpeer()
3776444Swnj {
37812990Ssam 	signal(SIGPIPE, SIG_IGN);
37912155Ssam 	prf("\007Connection closed.");
3809365Ssam 	done();
3816444Swnj }
382