Home | History | Annotate | Line # | Download | only in rlogin
rlogin.c revision 1.2
      1 /*
      2  * Copyright (c) 1983, 1990 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 /*static char sccsid[] = "from: @(#)rlogin.c	5.33 (Berkeley) 3/1/91";*/
     42 static char rcsid[] = "$Id: rlogin.c,v 1.2 1993/08/01 18:09:30 mycroft Exp $";
     43 #endif /* not lint */
     44 
     45 /*
     46  * $Source: /tank/opengrok/rsync2/NetBSD/src/usr.bin/rlogin/rlogin.c,v $
     47  * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall
     48  *	Exp Locker: kfall $
     49  */
     50 
     51 /*
     52  * rlogin - remote login
     53  */
     54 #include <sys/param.h>
     55 #include <sys/file.h>
     56 #include <sys/socket.h>
     57 #include <sys/signal.h>
     58 #include <sys/time.h>
     59 #include <sys/resource.h>
     60 #include <sys/wait.h>
     61 
     62 #include <netinet/in.h>
     63 #include <netinet/in_systm.h>
     64 #include <netinet/ip.h>
     65 #include <netdb.h>
     66 
     67 #include <sgtty.h>
     68 #include <setjmp.h>
     69 #include <varargs.h>
     70 #include <errno.h>
     71 #include <pwd.h>
     72 #include <stdio.h>
     73 #include <unistd.h>
     74 #include <string.h>
     75 
     76 #ifdef KERBEROS
     77 #include <kerberosIV/des.h>
     78 #include <kerberosIV/krb.h>
     79 
     80 CREDENTIALS cred;
     81 Key_schedule schedule;
     82 int use_kerberos = 1, doencrypt;
     83 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
     84 extern char *krb_realmofhost();
     85 #endif
     86 
     87 #ifndef TIOCPKT_WINDOW
     88 #define	TIOCPKT_WINDOW	0x80
     89 #endif
     90 
     91 /* concession to Sun */
     92 #ifndef SIGUSR1
     93 #define	SIGUSR1	30
     94 #endif
     95 
     96 extern int errno;
     97 int eight, litout, rem;
     98 
     99 int noescape;
    100 u_char escapechar = '~';
    101 
    102 char *speeds[] = {
    103 	"0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
    104 	"1800", "2400", "4800", "9600", "19200", "38400"
    105 };
    106 
    107 #ifdef sun
    108 struct winsize {
    109 	unsigned short ws_row, ws_col;
    110 	unsigned short ws_xpixel, ws_ypixel;
    111 };
    112 #endif
    113 struct	winsize winsize;
    114 
    115 #ifndef sun
    116 #define	get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
    117 #endif
    118 
    119 void exit();
    120 
    121 main(argc, argv)
    122 	int argc;
    123 	char **argv;
    124 {
    125 	extern char *optarg;
    126 	extern int optind;
    127 	struct passwd *pw;
    128 	struct servent *sp;
    129 	struct sgttyb ttyb;
    130 	long omask;
    131 	int argoff, ch, dflag, one, uid;
    132 	char *host, *p, *user, term[1024];
    133 	void lostpeer();
    134 	u_char getescape();
    135 	char *getenv();
    136 
    137 	argoff = dflag = 0;
    138 	one = 1;
    139 	host = user = NULL;
    140 
    141 	if (p = rindex(argv[0], '/'))
    142 		++p;
    143 	else
    144 		p = argv[0];
    145 
    146 	if (strcmp(p, "rlogin"))
    147 		host = p;
    148 
    149 	/* handle "rlogin host flags" */
    150 	if (!host && argc > 2 && argv[1][0] != '-') {
    151 		host = argv[1];
    152 		argoff = 1;
    153 	}
    154 
    155 #ifdef KERBEROS
    156 #define	OPTIONS	"8EKLde:k:l:x"
    157 #else
    158 #define	OPTIONS	"8EKLde:l:"
    159 #endif
    160 	while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
    161 		switch(ch) {
    162 		case '8':
    163 			eight = 1;
    164 			break;
    165 		case 'E':
    166 			noescape = 1;
    167 			break;
    168 		case 'K':
    169 #ifdef KERBEROS
    170 			use_kerberos = 0;
    171 #endif
    172 			break;
    173 		case 'L':
    174 			litout = 1;
    175 			break;
    176 		case 'd':
    177 			dflag = 1;
    178 			break;
    179 		case 'e':
    180 			escapechar = getescape(optarg);
    181 			break;
    182 #ifdef KERBEROS
    183 		case 'k':
    184 			dest_realm = dst_realm_buf;
    185 			(void)strncpy(dest_realm, optarg, REALM_SZ);
    186 			break;
    187 #endif
    188 		case 'l':
    189 			user = optarg;
    190 			break;
    191 #ifdef CRYPT
    192 #ifdef KERBEROS
    193 		case 'x':
    194 			doencrypt = 1;
    195 			des_set_key(cred.session, schedule);
    196 			break;
    197 #endif
    198 #endif
    199 		case '?':
    200 		default:
    201 			usage();
    202 		}
    203 	optind += argoff;
    204 	argc -= optind;
    205 	argv += optind;
    206 
    207 	/* if haven't gotten a host yet, do so */
    208 	if (!host && !(host = *argv++))
    209 		usage();
    210 
    211 	if (*argv)
    212 		usage();
    213 
    214 	if (!(pw = getpwuid(uid = getuid()))) {
    215 		(void)fprintf(stderr, "rlogin: unknown user id.\n");
    216 		exit(1);
    217 	}
    218 	if (!user)
    219 		user = pw->pw_name;
    220 
    221 	sp = NULL;
    222 #ifdef KERBEROS
    223 	if (use_kerberos) {
    224 		sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
    225 		if (sp == NULL) {
    226 			use_kerberos = 0;
    227 			warning("can't get entry for %s/tcp service",
    228 			    doencrypt ? "eklogin" : "klogin");
    229 		}
    230 	}
    231 #endif
    232 	if (sp == NULL)
    233 		sp = getservbyname("login", "tcp");
    234 	if (sp == NULL) {
    235 		(void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
    236 		exit(1);
    237 	}
    238 
    239 	(void)strcpy(term, (p = getenv("TERM")) ? p : "network");
    240 	if (ioctl(0, TIOCGETP, &ttyb) == 0) {
    241 		(void)strcat(term, "/");
    242 		(void)strcat(term, speeds[ttyb.sg_ospeed]);
    243 	}
    244 
    245 	(void)get_window_size(0, &winsize);
    246 
    247 	(void)signal(SIGPIPE, lostpeer);
    248 	/* will use SIGUSR1 for window size hack, so hold it off */
    249 	omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
    250 
    251 #ifdef KERBEROS
    252 try_connect:
    253 	if (use_kerberos) {
    254 		rem = KSUCCESS;
    255 		errno = 0;
    256 		if (dest_realm == NULL)
    257 			dest_realm = krb_realmofhost(host);
    258 
    259 #ifdef CRYPT
    260 		if (doencrypt)
    261 			rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
    262 			    dest_realm, &cred, schedule);
    263 		else
    264 #endif /* CRYPT */
    265 			rem = krcmd(&host, sp->s_port, user, term, 0,
    266 			    dest_realm);
    267 		if (rem < 0) {
    268 			use_kerberos = 0;
    269 			sp = getservbyname("login", "tcp");
    270 			if (sp == NULL) {
    271 				(void)fprintf(stderr,
    272 				    "rlogin: unknown service login/tcp.\n");
    273 				exit(1);
    274 			}
    275 			if (errno == ECONNREFUSED)
    276 				warning("remote host doesn't support Kerberos");
    277 			if (errno == ENOENT)
    278 				warning("can't provide Kerberos auth data");
    279 			goto try_connect;
    280 		}
    281 	} else {
    282 #ifdef CRYPT
    283 		if (doencrypt) {
    284 			(void)fprintf(stderr,
    285 			    "rlogin: the -x flag requires Kerberos authentication.\n");
    286 			exit(1);
    287 		}
    288 #endif /* CRYPT */
    289 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
    290 	}
    291 #else
    292 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
    293 #endif /* KERBEROS */
    294 
    295 	if (rem < 0)
    296 		exit(1);
    297 
    298 	if (dflag &&
    299 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
    300 		(void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
    301 		    strerror(errno));
    302 	one = IPTOS_LOWDELAY;
    303 	if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
    304 		perror("rlogin: setsockopt TOS (ignored)");
    305 
    306 	(void)setuid(uid);
    307 	doit(omask);
    308 	/*NOTREACHED*/
    309 }
    310 
    311 int child, defflags, deflflags, tabflag;
    312 char deferase, defkill;
    313 struct tchars deftc;
    314 struct ltchars defltc;
    315 struct tchars notc = { -1, -1, -1, -1, -1, -1 };
    316 struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
    317 
    318 doit(omask)
    319 	long omask;
    320 {
    321 	struct sgttyb sb;
    322 	void catch_child(), copytochild(), exit(), writeroob();
    323 
    324 	(void)ioctl(0, TIOCGETP, (char *)&sb);
    325 	defflags = sb.sg_flags;
    326 	tabflag = defflags & TBDELAY;
    327 	defflags &= ECHO | CRMOD;
    328 	deferase = sb.sg_erase;
    329 	defkill = sb.sg_kill;
    330 	(void)ioctl(0, TIOCLGET, (char *)&deflflags);
    331 	(void)ioctl(0, TIOCGETC, (char *)&deftc);
    332 	notc.t_startc = deftc.t_startc;
    333 	notc.t_stopc = deftc.t_stopc;
    334 	(void)ioctl(0, TIOCGLTC, (char *)&defltc);
    335 	(void)signal(SIGINT, SIG_IGN);
    336 	setsignal(SIGHUP, exit);
    337 	setsignal(SIGQUIT, exit);
    338 	child = fork();
    339 	if (child == -1) {
    340 		(void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
    341 		done(1);
    342 	}
    343 	if (child == 0) {
    344 		mode(1);
    345 		if (reader(omask) == 0) {
    346 			msg("connection closed.");
    347 			exit(0);
    348 		}
    349 		sleep(1);
    350 		msg("\007connection closed.");
    351 		exit(1);
    352 	}
    353 
    354 	/*
    355 	 * We may still own the socket, and may have a pending SIGURG (or might
    356 	 * receive one soon) that we really want to send to the reader.  Set a
    357 	 * trap that simply copies such signals to the child.
    358 	 */
    359 	(void)signal(SIGURG, copytochild);
    360 	(void)signal(SIGUSR1, writeroob);
    361 	(void)sigsetmask(omask);
    362 	(void)signal(SIGCHLD, catch_child);
    363 	writer();
    364 	msg("closed connection.");
    365 	done(0);
    366 }
    367 
    368 /* trap a signal, unless it is being ignored. */
    369 setsignal(sig, act)
    370 	int sig;
    371 	void (*act)();
    372 {
    373 	int omask = sigblock(sigmask(sig));
    374 
    375 	if (signal(sig, act) == SIG_IGN)
    376 		(void)signal(sig, SIG_IGN);
    377 	(void)sigsetmask(omask);
    378 }
    379 
    380 done(status)
    381 	int status;
    382 {
    383 	int w, wstatus;
    384 
    385 	mode(0);
    386 	if (child > 0) {
    387 		/* make sure catch_child does not snap it up */
    388 		(void)signal(SIGCHLD, SIG_DFL);
    389 		if (kill(child, SIGKILL) >= 0)
    390 			while ((w = wait(&wstatus)) > 0 && w != child);
    391 	}
    392 	exit(status);
    393 }
    394 
    395 int dosigwinch;
    396 void sigwinch();
    397 
    398 /*
    399  * This is called when the reader process gets the out-of-band (urgent)
    400  * request to turn on the window-changing protocol.
    401  */
    402 void
    403 writeroob()
    404 {
    405 	if (dosigwinch == 0) {
    406 		sendwindow();
    407 		(void)signal(SIGWINCH, sigwinch);
    408 	}
    409 	dosigwinch = 1;
    410 }
    411 
    412 void
    413 catch_child()
    414 {
    415 	union wait status;
    416 	int pid;
    417 
    418 	for (;;) {
    419 		pid = wait3((int *)&status,
    420 		    WNOHANG|WUNTRACED, (struct rusage *)0);
    421 		if (pid == 0)
    422 			return;
    423 		/* if the child (reader) dies, just quit */
    424 		if (pid < 0 || pid == child && !WIFSTOPPED(status))
    425 			done((int)(status.w_termsig | status.w_retcode));
    426 	}
    427 	/* NOTREACHED */
    428 }
    429 
    430 /*
    431  * writer: write to remote: 0 -> line.
    432  * ~.				terminate
    433  * ~^Z				suspend rlogin process.
    434  * ~<delayed-suspend char>	suspend rlogin process, but leave reader alone.
    435  */
    436 writer()
    437 {
    438 	register int bol, local, n;
    439 	char c;
    440 
    441 	bol = 1;			/* beginning of line */
    442 	local = 0;
    443 	for (;;) {
    444 		n = read(STDIN_FILENO, &c, 1);
    445 		if (n <= 0) {
    446 			if (n < 0 && errno == EINTR)
    447 				continue;
    448 			break;
    449 		}
    450 		/*
    451 		 * If we're at the beginning of the line and recognize a
    452 		 * command character, then we echo locally.  Otherwise,
    453 		 * characters are echo'd remotely.  If the command character
    454 		 * is doubled, this acts as a force and local echo is
    455 		 * suppressed.
    456 		 */
    457 		if (bol) {
    458 			bol = 0;
    459 			if (!noescape && c == escapechar) {
    460 				local = 1;
    461 				continue;
    462 			}
    463 		} else if (local) {
    464 			local = 0;
    465 			if (c == '.' || c == deftc.t_eofc) {
    466 				echo(c);
    467 				break;
    468 			}
    469 			if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
    470 				bol = 1;
    471 				echo(c);
    472 				stop(c);
    473 				continue;
    474 			}
    475 			if (c != escapechar)
    476 #ifdef CRYPT
    477 #ifdef KERBEROS
    478 				if (doencrypt)
    479 					(void)des_write(rem, &escapechar, 1);
    480 				else
    481 #endif
    482 #endif
    483 					(void)write(rem, &escapechar, 1);
    484 		}
    485 
    486 #ifdef CRYPT
    487 #ifdef KERBEROS
    488 		if (doencrypt) {
    489 			if (des_write(rem, &c, 1) == 0) {
    490 				msg("line gone");
    491 				break;
    492 			}
    493 		} else
    494 #endif
    495 #endif
    496 			if (write(rem, &c, 1) == 0) {
    497 				msg("line gone");
    498 				break;
    499 			}
    500 		bol = c == defkill || c == deftc.t_eofc ||
    501 		    c == deftc.t_intrc || c == defltc.t_suspc ||
    502 		    c == '\r' || c == '\n';
    503 	}
    504 }
    505 
    506 echo(c)
    507 register char c;
    508 {
    509 	register char *p;
    510 	char buf[8];
    511 
    512 	p = buf;
    513 	c &= 0177;
    514 	*p++ = escapechar;
    515 	if (c < ' ') {
    516 		*p++ = '^';
    517 		*p++ = c + '@';
    518 	} else if (c == 0177) {
    519 		*p++ = '^';
    520 		*p++ = '?';
    521 	} else
    522 		*p++ = c;
    523 	*p++ = '\r';
    524 	*p++ = '\n';
    525 	(void)write(STDOUT_FILENO, buf, p - buf);
    526 }
    527 
    528 stop(cmdc)
    529 	char cmdc;
    530 {
    531 	mode(0);
    532 	(void)signal(SIGCHLD, SIG_IGN);
    533 	(void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
    534 	(void)signal(SIGCHLD, catch_child);
    535 	mode(1);
    536 	sigwinch();			/* check for size changes */
    537 }
    538 
    539 void
    540 sigwinch()
    541 {
    542 	struct winsize ws;
    543 
    544 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
    545 	    bcmp(&ws, &winsize, sizeof(ws))) {
    546 		winsize = ws;
    547 		sendwindow();
    548 	}
    549 }
    550 
    551 /*
    552  * Send the window size to the server via the magic escape
    553  */
    554 sendwindow()
    555 {
    556 	struct winsize *wp;
    557 	char obuf[4 + sizeof (struct winsize)];
    558 
    559 	wp = (struct winsize *)(obuf+4);
    560 	obuf[0] = 0377;
    561 	obuf[1] = 0377;
    562 	obuf[2] = 's';
    563 	obuf[3] = 's';
    564 	wp->ws_row = htons(winsize.ws_row);
    565 	wp->ws_col = htons(winsize.ws_col);
    566 	wp->ws_xpixel = htons(winsize.ws_xpixel);
    567 	wp->ws_ypixel = htons(winsize.ws_ypixel);
    568 
    569 #ifdef CRYPT
    570 #ifdef KERBEROS
    571 	if(doencrypt)
    572 		(void)des_write(rem, obuf, sizeof(obuf));
    573 	else
    574 #endif
    575 #endif
    576 		(void)write(rem, obuf, sizeof(obuf));
    577 }
    578 
    579 /*
    580  * reader: read from remote: line -> 1
    581  */
    582 #define	READING	1
    583 #define	WRITING	2
    584 
    585 jmp_buf rcvtop;
    586 int ppid, rcvcnt, rcvstate;
    587 char rcvbuf[8 * 1024];
    588 
    589 void
    590 oob()
    591 {
    592 	struct sgttyb sb;
    593 	int atmark, n, out, rcvd;
    594 	char waste[BUFSIZ], mark;
    595 
    596 	out = O_RDWR;
    597 	rcvd = 0;
    598 	while (recv(rem, &mark, 1, MSG_OOB) < 0)
    599 		switch (errno) {
    600 		case EWOULDBLOCK:
    601 			/*
    602 			 * Urgent data not here yet.  It may not be possible
    603 			 * to send it yet if we are blocked for output and
    604 			 * our input buffer is full.
    605 			 */
    606 			if (rcvcnt < sizeof(rcvbuf)) {
    607 				n = read(rem, rcvbuf + rcvcnt,
    608 				    sizeof(rcvbuf) - rcvcnt);
    609 				if (n <= 0)
    610 					return;
    611 				rcvd += n;
    612 			} else {
    613 				n = read(rem, waste, sizeof(waste));
    614 				if (n <= 0)
    615 					return;
    616 			}
    617 			continue;
    618 		default:
    619 			return;
    620 	}
    621 	if (mark & TIOCPKT_WINDOW) {
    622 		/* Let server know about window size changes */
    623 		(void)kill(ppid, SIGUSR1);
    624 	}
    625 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
    626 		(void)ioctl(0, TIOCGETP, (char *)&sb);
    627 		sb.sg_flags &= ~CBREAK;
    628 		sb.sg_flags |= RAW;
    629 		(void)ioctl(0, TIOCSETN, (char *)&sb);
    630 		notc.t_stopc = -1;
    631 		notc.t_startc = -1;
    632 		(void)ioctl(0, TIOCSETC, (char *)&notc);
    633 	}
    634 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
    635 		(void)ioctl(0, TIOCGETP, (char *)&sb);
    636 		sb.sg_flags &= ~RAW;
    637 		sb.sg_flags |= CBREAK;
    638 		(void)ioctl(0, TIOCSETN, (char *)&sb);
    639 		notc.t_stopc = deftc.t_stopc;
    640 		notc.t_startc = deftc.t_startc;
    641 		(void)ioctl(0, TIOCSETC, (char *)&notc);
    642 	}
    643 	if (mark & TIOCPKT_FLUSHWRITE) {
    644 		(void)ioctl(1, TIOCFLUSH, (char *)&out);
    645 		for (;;) {
    646 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
    647 				(void)fprintf(stderr, "rlogin: ioctl: %s.\n",
    648 				    strerror(errno));
    649 				break;
    650 			}
    651 			if (atmark)
    652 				break;
    653 			n = read(rem, waste, sizeof (waste));
    654 			if (n <= 0)
    655 				break;
    656 		}
    657 		/*
    658 		 * Don't want any pending data to be output, so clear the recv
    659 		 * buffer.  If we were hanging on a write when interrupted,
    660 		 * don't want it to restart.  If we were reading, restart
    661 		 * anyway.
    662 		 */
    663 		rcvcnt = 0;
    664 		longjmp(rcvtop, 1);
    665 	}
    666 
    667 	/* oob does not do FLUSHREAD (alas!) */
    668 
    669 	/*
    670 	 * If we filled the receive buffer while a read was pending, longjmp
    671 	 * to the top to restart appropriately.  Don't abort a pending write,
    672 	 * however, or we won't know how much was written.
    673 	 */
    674 	if (rcvd && rcvstate == READING)
    675 		longjmp(rcvtop, 1);
    676 }
    677 
    678 /* reader: read from remote: line -> 1 */
    679 reader(omask)
    680 	int omask;
    681 {
    682 	void oob();
    683 
    684 #if !defined(BSD) || BSD < 43
    685 	int pid = -getpid();
    686 #else
    687 	int pid = getpid();
    688 #endif
    689 	int n, remaining;
    690 	char *bufp = rcvbuf;
    691 
    692 	(void)signal(SIGTTOU, SIG_IGN);
    693 	(void)signal(SIGURG, oob);
    694 	ppid = getppid();
    695 	(void)fcntl(rem, F_SETOWN, pid);
    696 	(void)setjmp(rcvtop);
    697 	(void)sigsetmask(omask);
    698 	for (;;) {
    699 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
    700 			rcvstate = WRITING;
    701 			n = write(STDOUT_FILENO, bufp, remaining);
    702 			if (n < 0) {
    703 				if (errno != EINTR)
    704 					return(-1);
    705 				continue;
    706 			}
    707 			bufp += n;
    708 		}
    709 		bufp = rcvbuf;
    710 		rcvcnt = 0;
    711 		rcvstate = READING;
    712 
    713 #ifdef CRYPT
    714 #ifdef KERBEROS
    715 		if (doencrypt)
    716 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
    717 		else
    718 #endif
    719 #endif
    720 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
    721 		if (rcvcnt == 0)
    722 			return (0);
    723 		if (rcvcnt < 0) {
    724 			if (errno == EINTR)
    725 				continue;
    726 			(void)fprintf(stderr, "rlogin: read: %s.\n",
    727 			    strerror(errno));
    728 			return(-1);
    729 		}
    730 	}
    731 }
    732 
    733 mode(f)
    734 {
    735 	struct ltchars *ltc;
    736 	struct sgttyb sb;
    737 	struct tchars *tc;
    738 	int lflags;
    739 
    740 	(void)ioctl(0, TIOCGETP, (char *)&sb);
    741 	(void)ioctl(0, TIOCLGET, (char *)&lflags);
    742 	switch(f) {
    743 	case 0:
    744 		sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
    745 		sb.sg_flags |= defflags|tabflag;
    746 		tc = &deftc;
    747 		ltc = &defltc;
    748 		sb.sg_kill = defkill;
    749 		sb.sg_erase = deferase;
    750 		lflags = deflflags;
    751 		break;
    752 	case 1:
    753 		sb.sg_flags |= (eight ? RAW : CBREAK);
    754 		sb.sg_flags &= ~defflags;
    755 		/* preserve tab delays, but turn off XTABS */
    756 		if ((sb.sg_flags & TBDELAY) == XTABS)
    757 			sb.sg_flags &= ~TBDELAY;
    758 		tc = &notc;
    759 		ltc = &noltc;
    760 		sb.sg_kill = sb.sg_erase = -1;
    761 		if (litout)
    762 			lflags |= LLITOUT;
    763 		break;
    764 	default:
    765 		return;
    766 	}
    767 	(void)ioctl(0, TIOCSLTC, (char *)ltc);
    768 	(void)ioctl(0, TIOCSETC, (char *)tc);
    769 	(void)ioctl(0, TIOCSETN, (char *)&sb);
    770 	(void)ioctl(0, TIOCLSET, (char *)&lflags);
    771 }
    772 
    773 void
    774 lostpeer()
    775 {
    776 	(void)signal(SIGPIPE, SIG_IGN);
    777 	msg("\007connection closed.");
    778 	done(1);
    779 }
    780 
    781 /* copy SIGURGs to the child process. */
    782 void
    783 copytochild()
    784 {
    785 	(void)kill(child, SIGURG);
    786 }
    787 
    788 msg(str)
    789 	char *str;
    790 {
    791 	(void)fprintf(stderr, "rlogin: %s\r\n", str);
    792 }
    793 
    794 #ifdef KERBEROS
    795 /* VARARGS */
    796 warning(va_alist)
    797 va_dcl
    798 {
    799 	va_list ap;
    800 	char *fmt;
    801 
    802 	(void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
    803 	va_start(ap);
    804 	fmt = va_arg(ap, char *);
    805 	vfprintf(stderr, fmt, ap);
    806 	va_end(ap);
    807 	(void)fprintf(stderr, ".\n");
    808 }
    809 #endif
    810 
    811 usage()
    812 {
    813 	(void)fprintf(stderr,
    814 	    "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
    815 #ifdef KERBEROS
    816 #ifdef CRYPT
    817 	    "8ELx", " [-k realm] ");
    818 #else
    819 	    "8EL", " [-k realm] ");
    820 #endif
    821 #else
    822 	    "8EL", " ");
    823 #endif
    824 	exit(1);
    825 }
    826 
    827 /*
    828  * The following routine provides compatibility (such as it is) between 4.2BSD
    829  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
    830  */
    831 #ifdef sun
    832 get_window_size(fd, wp)
    833 	int fd;
    834 	struct winsize *wp;
    835 {
    836 	struct ttysize ts;
    837 	int error;
    838 
    839 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
    840 		return(error);
    841 	wp->ws_row = ts.ts_lines;
    842 	wp->ws_col = ts.ts_cols;
    843 	wp->ws_xpixel = 0;
    844 	wp->ws_ypixel = 0;
    845 	return(0);
    846 }
    847 #endif
    848 
    849 u_char
    850 getescape(p)
    851 	register char *p;
    852 {
    853 	long val;
    854 	int len;
    855 
    856 	if ((len = strlen(p)) == 1)	/* use any single char, including '\' */
    857 		return((u_char)*p);
    858 					/* otherwise, \nnn */
    859 	if (*p == '\\' && len >= 2 && len <= 4) {
    860 		val = strtol(++p, (char **)NULL, 8);
    861 		for (;;) {
    862 			if (!*++p)
    863 				return((u_char)val);
    864 			if (*p < '0' || *p > '8')
    865 				break;
    866 		}
    867 	}
    868 	msg("illegal option value -- e");
    869 	usage();
    870 	/* NOTREACHED */
    871 }
    872