Home | History | Annotate | Line # | Download | only in rlogin
rlogin.c revision 1.15
      1  1.15       tls /*	$NetBSD: rlogin.c,v 1.15 1997/01/09 06:57:46 tls Exp $	*/
      2   1.4       cgd 
      3   1.1       cgd /*
      4   1.4       cgd  * Copyright (c) 1983, 1990, 1993
      5   1.4       cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1       cgd  * modification, are permitted provided that the following conditions
      9   1.1       cgd  * are met:
     10   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15   1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     16   1.1       cgd  *    must display the following acknowledgement:
     17   1.1       cgd  *	This product includes software developed by the University of
     18   1.1       cgd  *	California, Berkeley and its contributors.
     19   1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     20   1.1       cgd  *    may be used to endorse or promote products derived from this software
     21   1.1       cgd  *    without specific prior written permission.
     22   1.1       cgd  *
     23   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33   1.1       cgd  * SUCH DAMAGE.
     34   1.1       cgd  */
     35   1.1       cgd 
     36   1.1       cgd #ifndef lint
     37   1.4       cgd static char copyright[] =
     38   1.4       cgd "@(#) Copyright (c) 1983, 1990, 1993\n\
     39   1.4       cgd 	The Regents of the University of California.  All rights reserved.\n";
     40   1.1       cgd #endif /* not lint */
     41   1.1       cgd 
     42   1.1       cgd #ifndef lint
     43   1.4       cgd #if 0
     44  1.15       tls static char sccsid[] = "@(#)rlogin.c	8.4 (Berkeley) 4/29/95";
     45   1.4       cgd #else
     46  1.15       tls static char rcsid[] = "$NetBSD: rlogin.c,v 1.15 1997/01/09 06:57:46 tls Exp $";
     47   1.4       cgd #endif
     48   1.1       cgd #endif /* not lint */
     49   1.1       cgd 
     50   1.1       cgd /*
     51   1.1       cgd  * rlogin - remote login
     52   1.1       cgd  */
     53   1.1       cgd #include <sys/param.h>
     54   1.5   mycroft #include <sys/ioctl.h>
     55   1.1       cgd #include <sys/socket.h>
     56   1.1       cgd #include <sys/time.h>
     57   1.1       cgd #include <sys/resource.h>
     58   1.1       cgd #include <sys/wait.h>
     59  1.15       tls #include <sys/ioctl.h>
     60   1.1       cgd 
     61   1.1       cgd #include <netinet/in.h>
     62   1.1       cgd #include <netinet/in_systm.h>
     63   1.1       cgd #include <netinet/ip.h>
     64   1.1       cgd 
     65   1.1       cgd #include <errno.h>
     66   1.4       cgd #include <fcntl.h>
     67   1.4       cgd #include <netdb.h>
     68   1.1       cgd #include <pwd.h>
     69   1.4       cgd #include <setjmp.h>
     70   1.5   mycroft #include <termios.h>
     71   1.4       cgd #include <signal.h>
     72   1.1       cgd #include <stdio.h>
     73   1.4       cgd #include <stdlib.h>
     74   1.4       cgd #include <string.h>
     75   1.1       cgd #include <unistd.h>
     76   1.4       cgd 
     77   1.4       cgd #ifdef __STDC__
     78   1.4       cgd #include <stdarg.h>
     79   1.4       cgd #else
     80   1.4       cgd #include <varargs.h>
     81   1.4       cgd #endif
     82   1.1       cgd 
     83   1.1       cgd #ifdef KERBEROS
     84   1.1       cgd #include <kerberosIV/des.h>
     85   1.1       cgd #include <kerberosIV/krb.h>
     86   1.1       cgd 
     87   1.4       cgd #include "krb.h"
     88   1.4       cgd 
     89   1.1       cgd CREDENTIALS cred;
     90   1.1       cgd Key_schedule schedule;
     91   1.1       cgd int use_kerberos = 1, doencrypt;
     92   1.1       cgd char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
     93   1.1       cgd #endif
     94   1.1       cgd 
     95   1.1       cgd #ifndef TIOCPKT_WINDOW
     96   1.1       cgd #define	TIOCPKT_WINDOW	0x80
     97   1.1       cgd #endif
     98   1.1       cgd 
     99   1.1       cgd /* concession to Sun */
    100   1.1       cgd #ifndef SIGUSR1
    101   1.1       cgd #define	SIGUSR1	30
    102   1.1       cgd #endif
    103   1.1       cgd 
    104   1.5   mycroft #ifndef CCEQ
    105   1.5   mycroft #define CCEQ(val, c)	(c == val ? val != _POSIX_VDISABLE : 0)
    106   1.5   mycroft #endif
    107   1.5   mycroft 
    108   1.5   mycroft int eight, rem;
    109   1.5   mycroft struct termios deftty;
    110   1.1       cgd 
    111   1.1       cgd int noescape;
    112   1.1       cgd u_char escapechar = '~';
    113   1.1       cgd 
    114   1.4       cgd #ifdef OLDSUN
    115   1.1       cgd struct winsize {
    116   1.1       cgd 	unsigned short ws_row, ws_col;
    117   1.1       cgd 	unsigned short ws_xpixel, ws_ypixel;
    118   1.1       cgd };
    119   1.4       cgd #else
    120   1.4       cgd #define	get_window_size(fd, wp)	ioctl(fd, TIOCGWINSZ, wp)
    121   1.1       cgd #endif
    122   1.1       cgd struct	winsize winsize;
    123   1.1       cgd 
    124   1.4       cgd void		catch_child __P((int));
    125   1.4       cgd void		copytochild __P((int));
    126  1.15       tls __dead void	doit __P((sigset_t *));
    127   1.4       cgd __dead void	done __P((int));
    128   1.4       cgd void		echo __P((char));
    129   1.4       cgd u_int		getescape __P((char *));
    130   1.4       cgd void		lostpeer __P((int));
    131   1.4       cgd void		mode __P((int));
    132   1.4       cgd void		msg __P((char *));
    133   1.4       cgd void		oob __P((int));
    134  1.15       tls int		reader __P((sigset_t *));
    135   1.4       cgd void		sendwindow __P((void));
    136   1.4       cgd void		setsignal __P((int));
    137  1.15       tls int		speed __P((int));
    138   1.4       cgd void		sigwinch __P((int));
    139   1.6   mycroft void		stop __P((int));
    140   1.4       cgd __dead void	usage __P((void));
    141   1.4       cgd void		writer __P((void));
    142   1.4       cgd void		writeroob __P((int));
    143   1.4       cgd 
    144   1.4       cgd #ifdef	KERBEROS
    145   1.4       cgd void		warning __P((const char *, ...));
    146   1.4       cgd #endif
    147   1.4       cgd #ifdef OLDSUN
    148   1.4       cgd int		get_window_size __P((int, struct winsize *));
    149   1.1       cgd #endif
    150   1.1       cgd 
    151   1.4       cgd int
    152   1.1       cgd main(argc, argv)
    153   1.1       cgd 	int argc;
    154   1.4       cgd 	char *argv[];
    155   1.1       cgd {
    156   1.1       cgd 	struct passwd *pw;
    157   1.1       cgd 	struct servent *sp;
    158   1.5   mycroft 	struct termios tty;
    159  1.15       tls 	sigset_t smask;
    160   1.1       cgd 	int argoff, ch, dflag, one, uid;
    161  1.12       mrg 	int i, len, len2;
    162  1.12       mrg 	char *host, *p, *user, term[1024] = "network";
    163  1.12       mrg 	speed_t ospeed;
    164  1.15       tls 	struct sigaction sa;
    165   1.1       cgd 
    166   1.1       cgd 	argoff = dflag = 0;
    167   1.1       cgd 	one = 1;
    168   1.1       cgd 	host = user = NULL;
    169   1.1       cgd 
    170  1.15       tls 	if (p = strrchr(argv[0], '/'))
    171   1.1       cgd 		++p;
    172   1.1       cgd 	else
    173   1.1       cgd 		p = argv[0];
    174   1.1       cgd 
    175  1.15       tls 	if (strcmp(p, "rlogin") != 0)
    176   1.1       cgd 		host = p;
    177   1.1       cgd 
    178   1.1       cgd 	/* handle "rlogin host flags" */
    179   1.1       cgd 	if (!host && argc > 2 && argv[1][0] != '-') {
    180   1.1       cgd 		host = argv[1];
    181   1.1       cgd 		argoff = 1;
    182   1.1       cgd 	}
    183   1.1       cgd 
    184   1.1       cgd #ifdef KERBEROS
    185   1.1       cgd #define	OPTIONS	"8EKLde:k:l:x"
    186   1.1       cgd #else
    187   1.1       cgd #define	OPTIONS	"8EKLde:l:"
    188   1.1       cgd #endif
    189   1.1       cgd 	while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
    190   1.1       cgd 		switch(ch) {
    191   1.1       cgd 		case '8':
    192   1.1       cgd 			eight = 1;
    193   1.1       cgd 			break;
    194   1.1       cgd 		case 'E':
    195   1.1       cgd 			noescape = 1;
    196   1.1       cgd 			break;
    197   1.1       cgd 		case 'K':
    198   1.1       cgd #ifdef KERBEROS
    199   1.1       cgd 			use_kerberos = 0;
    200   1.1       cgd #endif
    201   1.1       cgd 			break;
    202   1.1       cgd 		case 'd':
    203   1.1       cgd 			dflag = 1;
    204   1.1       cgd 			break;
    205   1.1       cgd 		case 'e':
    206   1.4       cgd 			noescape = 0;
    207   1.1       cgd 			escapechar = getescape(optarg);
    208   1.1       cgd 			break;
    209   1.1       cgd #ifdef KERBEROS
    210   1.1       cgd 		case 'k':
    211   1.1       cgd 			dest_realm = dst_realm_buf;
    212   1.1       cgd 			(void)strncpy(dest_realm, optarg, REALM_SZ);
    213   1.1       cgd 			break;
    214   1.1       cgd #endif
    215   1.1       cgd 		case 'l':
    216   1.1       cgd 			user = optarg;
    217   1.1       cgd 			break;
    218   1.1       cgd #ifdef CRYPT
    219   1.1       cgd #ifdef KERBEROS
    220   1.1       cgd 		case 'x':
    221   1.1       cgd 			doencrypt = 1;
    222   1.1       cgd 			des_set_key(cred.session, schedule);
    223   1.1       cgd 			break;
    224   1.1       cgd #endif
    225   1.1       cgd #endif
    226   1.1       cgd 		case '?':
    227   1.1       cgd 		default:
    228   1.1       cgd 			usage();
    229   1.1       cgd 		}
    230   1.1       cgd 	optind += argoff;
    231   1.1       cgd 	argc -= optind;
    232   1.1       cgd 	argv += optind;
    233   1.1       cgd 
    234   1.1       cgd 	/* if haven't gotten a host yet, do so */
    235   1.1       cgd 	if (!host && !(host = *argv++))
    236   1.1       cgd 		usage();
    237   1.1       cgd 
    238   1.1       cgd 	if (*argv)
    239   1.1       cgd 		usage();
    240   1.1       cgd 
    241  1.15       tls 	if (!(pw = getpwuid(uid = getuid())))
    242  1.15       tls 		errx(1, "unknown user id.");
    243  1.15       tls 	/* Accept user1@host format, though "-l user2" overrides user1 */
    244  1.15       tls 	p = strchr(host, '@');
    245  1.15       tls 	if (p) {
    246  1.15       tls 		*p = '\0';
    247  1.15       tls 		if (!user && p > host)
    248  1.15       tls 			user = host;
    249  1.15       tls 		host = p + 1;
    250  1.15       tls 		if (*host == '\0')
    251  1.15       tls 			usage();
    252   1.1       cgd 	}
    253   1.1       cgd 	if (!user)
    254   1.1       cgd 		user = pw->pw_name;
    255   1.1       cgd 
    256   1.1       cgd 	sp = NULL;
    257   1.1       cgd #ifdef KERBEROS
    258   1.1       cgd 	if (use_kerberos) {
    259   1.1       cgd 		sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
    260   1.1       cgd 		if (sp == NULL) {
    261   1.1       cgd 			use_kerberos = 0;
    262   1.1       cgd 			warning("can't get entry for %s/tcp service",
    263   1.1       cgd 			    doencrypt ? "eklogin" : "klogin");
    264   1.1       cgd 		}
    265   1.1       cgd 	}
    266   1.1       cgd #endif
    267   1.1       cgd 	if (sp == NULL)
    268   1.1       cgd 		sp = getservbyname("login", "tcp");
    269  1.15       tls 	if (sp == NULL)
    270  1.15       tls 		errx(1, "login/tcp: unknown service.");
    271   1.1       cgd 
    272  1.12       mrg 	if (p = getenv("TERM")) {
    273  1.12       mrg 		(void)strncpy(term, p, sizeof(term) - 1);
    274  1.12       mrg 		term[sizeof(term) - 1] = '\0';
    275  1.12       mrg 	}
    276  1.12       mrg 	len = strlen(term);
    277  1.12       mrg 	if (len < (sizeof(term) - 1) && tcgetattr(0, &tty) == 0) {
    278  1.12       mrg 		/* start at 2 to include the / */
    279  1.13   thorpej 		for (ospeed = i = cfgetospeed(&tty), len2 = 2; i > 9; len2++)
    280  1.12       mrg 			i /= 10;
    281  1.12       mrg 
    282  1.14  explorer 		if (len + len2 < sizeof(term))
    283  1.14  explorer 			(void)snprintf(term + len, len2 + 1, "/%d", ospeed);
    284   1.1       cgd 	}
    285   1.1       cgd 
    286   1.1       cgd 	(void)get_window_size(0, &winsize);
    287   1.1       cgd 
    288  1.15       tls 	sigemptyset(&sa.sa_mask);
    289  1.15       tls 	sa.sa_flags = SA_RESTART;
    290  1.15       tls 	sa.sa_handler = lostpeer;
    291  1.15       tls 	(void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
    292   1.1       cgd 	/* will use SIGUSR1 for window size hack, so hold it off */
    293  1.15       tls 	sigemptyset(&smask);
    294  1.15       tls 	sigaddset(&smask, SIGURG);
    295  1.15       tls 	sigaddset(&smask, SIGUSR1);
    296  1.15       tls 	(void)sigprocmask(SIG_SETMASK, &smask, &smask);
    297   1.4       cgd 	/*
    298   1.4       cgd 	 * We set SIGURG and SIGUSR1 below so that an
    299   1.4       cgd 	 * incoming signal will be held pending rather than being
    300   1.4       cgd 	 * discarded. Note that these routines will be ready to get
    301   1.4       cgd 	 * a signal by the time that they are unblocked below.
    302   1.4       cgd 	 */
    303  1.15       tls 	sa.sa_handler = copytochild;
    304  1.15       tls 	(void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
    305  1.15       tls 	sa.sa_handler = writeroob;
    306  1.15       tls 	(void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0);
    307   1.1       cgd 
    308   1.1       cgd #ifdef KERBEROS
    309   1.1       cgd try_connect:
    310   1.1       cgd 	if (use_kerberos) {
    311   1.4       cgd 		struct hostent *hp;
    312   1.4       cgd 
    313   1.4       cgd 		/* Fully qualify hostname (needed for krb_realmofhost). */
    314   1.4       cgd 		hp = gethostbyname(host);
    315  1.15       tls 		if (hp != NULL && !(host = strdup(hp->h_name)))
    316  1.15       tls 			errx(1, "%s", strerror(ENOMEM));
    317   1.4       cgd 
    318   1.1       cgd 		rem = KSUCCESS;
    319   1.1       cgd 		errno = 0;
    320   1.1       cgd 		if (dest_realm == NULL)
    321   1.1       cgd 			dest_realm = krb_realmofhost(host);
    322   1.1       cgd 
    323   1.1       cgd #ifdef CRYPT
    324   1.1       cgd 		if (doencrypt)
    325   1.1       cgd 			rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
    326   1.1       cgd 			    dest_realm, &cred, schedule);
    327   1.1       cgd 		else
    328   1.1       cgd #endif /* CRYPT */
    329   1.1       cgd 			rem = krcmd(&host, sp->s_port, user, term, 0,
    330   1.1       cgd 			    dest_realm);
    331   1.1       cgd 		if (rem < 0) {
    332   1.1       cgd 			use_kerberos = 0;
    333   1.1       cgd 			sp = getservbyname("login", "tcp");
    334  1.15       tls 			if (sp == NULL)
    335  1.15       tls 				errx(1, "unknown service login/tcp.");
    336   1.1       cgd 			if (errno == ECONNREFUSED)
    337   1.1       cgd 				warning("remote host doesn't support Kerberos");
    338   1.1       cgd 			if (errno == ENOENT)
    339   1.1       cgd 				warning("can't provide Kerberos auth data");
    340   1.1       cgd 			goto try_connect;
    341   1.1       cgd 		}
    342   1.1       cgd 	} else {
    343   1.1       cgd #ifdef CRYPT
    344  1.15       tls 		if (doencrypt)
    345  1.15       tls 			errx(1, "the -x flag requires Kerberos authentication.");
    346   1.1       cgd #endif /* CRYPT */
    347   1.1       cgd 		rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
    348   1.1       cgd 	}
    349   1.1       cgd #else
    350   1.1       cgd 	rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
    351   1.1       cgd #endif /* KERBEROS */
    352   1.1       cgd 
    353   1.1       cgd 	if (rem < 0)
    354   1.1       cgd 		exit(1);
    355   1.1       cgd 
    356   1.1       cgd 	if (dflag &&
    357   1.1       cgd 	    setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
    358  1.15       tls 		warn("setsockopt DEBUG (ignored)");
    359   1.1       cgd 	one = IPTOS_LOWDELAY;
    360   1.1       cgd 	if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
    361  1.15       tls 		warn("setsockopt TOS (ignored)");
    362   1.1       cgd 
    363   1.1       cgd 	(void)setuid(uid);
    364  1.15       tls 	doit(&smask);
    365   1.1       cgd 	/*NOTREACHED*/
    366   1.1       cgd }
    367   1.1       cgd 
    368  1.15       tls #if BSD >= 198810
    369  1.15       tls int
    370  1.15       tls speed(fd)
    371  1.15       tls 	int fd;
    372  1.15       tls {
    373  1.15       tls 	struct termios tt;
    374  1.15       tls 
    375  1.15       tls 	(void)tcgetattr(fd, &tt);
    376  1.15       tls 
    377  1.15       tls 	return ((int) cfgetispeed(&tt));
    378  1.15       tls }
    379  1.15       tls #else
    380  1.15       tls int    speeds[] = {	/* for older systems, B0 .. EXTB */
    381  1.15       tls 	0, 50, 75, 110,
    382  1.15       tls 	134, 150, 200, 300,
    383  1.15       tls 	600, 1200, 1800, 2400,
    384  1.15       tls 	4800, 9600, 19200, 38400
    385  1.15       tls };
    386  1.15       tls 
    387  1.15       tls int
    388  1.15       tls speed(fd)
    389  1.15       tls 	int fd;
    390  1.15       tls {
    391  1.15       tls 	struct termios tt;
    392  1.15       tls 
    393  1.15       tls 	(void)tcgetattr(fd, &tt);
    394  1.15       tls 
    395  1.15       tls 	return (speeds[(int)cfgetispeed(&tt)]);
    396  1.15       tls }
    397  1.15       tls #endif
    398  1.15       tls 
    399  1.15       tls pid_t child;
    400  1.15       tls struct termios deftt;
    401  1.15       tls struct termios nott;
    402   1.1       cgd 
    403   1.4       cgd void
    404  1.15       tls doit(smask)
    405  1.15       tls 	sigset_t *smask;
    406   1.1       cgd {
    407  1.15       tls 	int i;
    408  1.15       tls 	struct sigaction sa;
    409   1.1       cgd 
    410  1.15       tls 	for (i = 0; i < NCCS; i++)
    411  1.15       tls 		nott.c_cc[i] = _POSIX_VDISABLE;
    412  1.15       tls 	tcgetattr(0, &deftt);
    413  1.15       tls 	nott.c_cc[VSTART] = deftt.c_cc[VSTART];
    414  1.15       tls 	nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
    415  1.15       tls 	sigemptyset(&sa.sa_mask);
    416  1.15       tls 	sa.sa_flags = SA_RESTART;
    417  1.15       tls 	sa.sa_handler = SIG_IGN;
    418  1.15       tls 	(void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
    419   1.4       cgd 	setsignal(SIGHUP);
    420   1.4       cgd 	setsignal(SIGQUIT);
    421   1.5   mycroft 	mode(1);
    422   1.1       cgd 	child = fork();
    423   1.1       cgd 	if (child == -1) {
    424  1.15       tls 		warn("fork");
    425   1.1       cgd 		done(1);
    426   1.1       cgd 	}
    427   1.1       cgd 	if (child == 0) {
    428  1.15       tls 		mode(1);
    429  1.15       tls 		if (reader(smask) == 0) {
    430   1.1       cgd 			msg("connection closed.");
    431   1.1       cgd 			exit(0);
    432   1.1       cgd 		}
    433   1.1       cgd 		sleep(1);
    434   1.5   mycroft 		msg("\aconnection closed.");
    435   1.1       cgd 		exit(1);
    436   1.1       cgd 	}
    437   1.1       cgd 
    438   1.1       cgd 	/*
    439   1.1       cgd 	 * We may still own the socket, and may have a pending SIGURG (or might
    440   1.4       cgd 	 * receive one soon) that we really want to send to the reader.  When
    441   1.4       cgd 	 * one of these comes in, the trap copytochild simply copies such
    442   1.4       cgd 	 * signals to the child. We can now unblock SIGURG and SIGUSR1
    443   1.4       cgd 	 * that were set above.
    444   1.1       cgd 	 */
    445  1.15       tls 	(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
    446  1.15       tls 	sa.sa_handler = catch_child;
    447  1.15       tls 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
    448   1.1       cgd 	writer();
    449   1.1       cgd 	msg("closed connection.");
    450   1.1       cgd 	done(0);
    451   1.1       cgd }
    452   1.1       cgd 
    453   1.1       cgd /* trap a signal, unless it is being ignored. */
    454   1.4       cgd void
    455   1.4       cgd setsignal(sig)
    456   1.1       cgd 	int sig;
    457   1.1       cgd {
    458  1.15       tls 	struct sigaction sa;
    459  1.15       tls 	sigset_t sigs;
    460   1.1       cgd 
    461  1.15       tls 	sigemptyset(&sigs);
    462  1.15       tls 	sigaddset(&sigs, sig);
    463  1.15       tls 	sigprocmask(SIG_BLOCK, &sigs, &sigs);
    464  1.15       tls 
    465  1.15       tls 	sigemptyset(&sa.sa_mask);
    466  1.15       tls 	sa.sa_handler = exit;
    467  1.15       tls 	sa.sa_flags = SA_RESTART;
    468  1.15       tls 	(void)sigaction(sig, &sa, &sa);
    469  1.15       tls 	if (sa.sa_handler == SIG_IGN)
    470  1.15       tls 		(void)sigaction(sig, &sa, (struct sigaction *) 0);
    471  1.15       tls 
    472  1.15       tls 	(void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
    473   1.1       cgd }
    474   1.1       cgd 
    475   1.4       cgd __dead void
    476   1.1       cgd done(status)
    477   1.1       cgd 	int status;
    478   1.1       cgd {
    479  1.15       tls 	pid_t w;
    480  1.15       tls 	int wstatus;
    481  1.15       tls 	struct sigaction sa;
    482   1.1       cgd 
    483   1.1       cgd 	mode(0);
    484   1.1       cgd 	if (child > 0) {
    485   1.1       cgd 		/* make sure catch_child does not snap it up */
    486  1.15       tls 		sigemptyset(&sa.sa_mask);
    487  1.15       tls 		sa.sa_handler = SIG_DFL;
    488  1.15       tls 		sa.sa_flags = 0;
    489  1.15       tls 		(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
    490   1.1       cgd 		if (kill(child, SIGKILL) >= 0)
    491  1.15       tls 			while ((w = wait(&wstatus)) > 0 && w != child)
    492  1.15       tls 				continue;
    493   1.1       cgd 	}
    494   1.1       cgd 	exit(status);
    495   1.1       cgd }
    496   1.1       cgd 
    497   1.1       cgd int dosigwinch;
    498   1.1       cgd 
    499   1.1       cgd /*
    500   1.1       cgd  * This is called when the reader process gets the out-of-band (urgent)
    501   1.1       cgd  * request to turn on the window-changing protocol.
    502   1.1       cgd  */
    503   1.1       cgd void
    504   1.4       cgd writeroob(signo)
    505   1.4       cgd 	int signo;
    506   1.1       cgd {
    507  1.15       tls 	struct sigaction sa;
    508  1.15       tls 
    509   1.1       cgd 	if (dosigwinch == 0) {
    510   1.1       cgd 		sendwindow();
    511  1.15       tls 		sigemptyset(&sa.sa_mask);
    512  1.15       tls 		sa.sa_handler = sigwinch;
    513  1.15       tls 		sa.sa_flags = SA_RESTART;
    514  1.15       tls 		(void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
    515   1.1       cgd 	}
    516   1.1       cgd 	dosigwinch = 1;
    517   1.1       cgd }
    518   1.1       cgd 
    519   1.1       cgd void
    520   1.4       cgd catch_child(signo)
    521   1.4       cgd 	int signo;
    522   1.1       cgd {
    523  1.15       tls 	int status;
    524  1.15       tls 	pid_t pid;
    525   1.1       cgd 
    526   1.1       cgd 	for (;;) {
    527  1.15       tls 		pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
    528   1.1       cgd 		if (pid == 0)
    529   1.1       cgd 			return;
    530   1.1       cgd 		/* if the child (reader) dies, just quit */
    531   1.4       cgd 		if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
    532  1.15       tls 			done(WEXITSTATUS(status) | WTERMSIG(status));
    533   1.1       cgd 	}
    534   1.1       cgd 	/* NOTREACHED */
    535   1.1       cgd }
    536   1.1       cgd 
    537   1.1       cgd /*
    538   1.1       cgd  * writer: write to remote: 0 -> line.
    539   1.1       cgd  * ~.				terminate
    540   1.1       cgd  * ~^Z				suspend rlogin process.
    541   1.1       cgd  * ~<delayed-suspend char>	suspend rlogin process, but leave reader alone.
    542   1.1       cgd  */
    543   1.4       cgd void
    544   1.1       cgd writer()
    545   1.1       cgd {
    546   1.1       cgd 	register int bol, local, n;
    547   1.1       cgd 	char c;
    548   1.1       cgd 
    549   1.1       cgd 	bol = 1;			/* beginning of line */
    550   1.1       cgd 	local = 0;
    551   1.1       cgd 	for (;;) {
    552   1.1       cgd 		n = read(STDIN_FILENO, &c, 1);
    553   1.1       cgd 		if (n <= 0) {
    554   1.1       cgd 			if (n < 0 && errno == EINTR)
    555   1.1       cgd 				continue;
    556   1.1       cgd 			break;
    557   1.1       cgd 		}
    558   1.1       cgd 		/*
    559   1.1       cgd 		 * If we're at the beginning of the line and recognize a
    560   1.1       cgd 		 * command character, then we echo locally.  Otherwise,
    561   1.1       cgd 		 * characters are echo'd remotely.  If the command character
    562   1.1       cgd 		 * is doubled, this acts as a force and local echo is
    563   1.1       cgd 		 * suppressed.
    564   1.1       cgd 		 */
    565   1.1       cgd 		if (bol) {
    566   1.1       cgd 			bol = 0;
    567   1.1       cgd 			if (!noescape && c == escapechar) {
    568   1.1       cgd 				local = 1;
    569   1.1       cgd 				continue;
    570   1.1       cgd 			}
    571   1.1       cgd 		} else if (local) {
    572   1.1       cgd 			local = 0;
    573   1.5   mycroft 			if (c == '.' || CCEQ(deftty.c_cc[VEOF], c)) {
    574   1.1       cgd 				echo(c);
    575   1.1       cgd 				break;
    576   1.1       cgd 			}
    577   1.6   mycroft 			if (CCEQ(deftty.c_cc[VSUSP], c)) {
    578   1.1       cgd 				bol = 1;
    579   1.1       cgd 				echo(c);
    580   1.6   mycroft 				stop(1);
    581   1.6   mycroft 				continue;
    582   1.6   mycroft 			}
    583   1.6   mycroft 			if (CCEQ(deftty.c_cc[VDSUSP], c)) {
    584   1.6   mycroft 				bol = 1;
    585   1.6   mycroft 				echo(c);
    586   1.6   mycroft 				stop(0);
    587   1.1       cgd 				continue;
    588   1.1       cgd 			}
    589   1.1       cgd 			if (c != escapechar)
    590   1.1       cgd #ifdef CRYPT
    591   1.1       cgd #ifdef KERBEROS
    592   1.1       cgd 				if (doencrypt)
    593   1.4       cgd 					(void)des_write(rem,
    594   1.4       cgd 					    (char *)&escapechar, 1);
    595   1.1       cgd 				else
    596   1.1       cgd #endif
    597   1.1       cgd #endif
    598   1.1       cgd 					(void)write(rem, &escapechar, 1);
    599   1.1       cgd 		}
    600   1.1       cgd 
    601   1.1       cgd #ifdef CRYPT
    602   1.1       cgd #ifdef KERBEROS
    603   1.1       cgd 		if (doencrypt) {
    604   1.1       cgd 			if (des_write(rem, &c, 1) == 0) {
    605   1.1       cgd 				msg("line gone");
    606   1.1       cgd 				break;
    607   1.1       cgd 			}
    608   1.1       cgd 		} else
    609   1.1       cgd #endif
    610   1.1       cgd #endif
    611   1.1       cgd 			if (write(rem, &c, 1) == 0) {
    612   1.1       cgd 				msg("line gone");
    613   1.1       cgd 				break;
    614   1.1       cgd 			}
    615   1.5   mycroft 		bol = CCEQ(deftty.c_cc[VKILL], c) ||
    616   1.5   mycroft 		    CCEQ(deftty.c_cc[VEOF], c) ||
    617   1.5   mycroft 		    CCEQ(deftty.c_cc[VINTR], c) ||
    618   1.5   mycroft 		    CCEQ(deftty.c_cc[VSUSP], c) ||
    619   1.1       cgd 		    c == '\r' || c == '\n';
    620   1.1       cgd 	}
    621   1.1       cgd }
    622   1.1       cgd 
    623   1.4       cgd void
    624   1.4       cgd #if __STDC__
    625   1.4       cgd echo(register char c)
    626   1.4       cgd #else
    627   1.1       cgd echo(c)
    628   1.4       cgd 	register char c;
    629   1.4       cgd #endif
    630   1.1       cgd {
    631   1.1       cgd 	register char *p;
    632   1.1       cgd 	char buf[8];
    633   1.1       cgd 
    634   1.1       cgd 	p = buf;
    635   1.1       cgd 	c &= 0177;
    636   1.1       cgd 	*p++ = escapechar;
    637   1.1       cgd 	if (c < ' ') {
    638   1.1       cgd 		*p++ = '^';
    639   1.1       cgd 		*p++ = c + '@';
    640   1.1       cgd 	} else if (c == 0177) {
    641   1.1       cgd 		*p++ = '^';
    642   1.1       cgd 		*p++ = '?';
    643   1.1       cgd 	} else
    644   1.1       cgd 		*p++ = c;
    645   1.1       cgd 	*p++ = '\r';
    646   1.1       cgd 	*p++ = '\n';
    647   1.1       cgd 	(void)write(STDOUT_FILENO, buf, p - buf);
    648   1.1       cgd }
    649   1.1       cgd 
    650   1.4       cgd void
    651   1.6   mycroft stop(all)
    652   1.6   mycroft 	int all;
    653   1.1       cgd {
    654  1.15       tls 	struct sigaction sa;
    655  1.15       tls 
    656   1.1       cgd 	mode(0);
    657  1.15       tls 	sigemptyset(&sa.sa_mask);
    658  1.15       tls 	sa.sa_handler = SIG_IGN;
    659  1.15       tls 	sa.sa_flags = SA_RESTART;
    660  1.15       tls 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
    661   1.6   mycroft 	(void)kill(all ? 0 : getpid(), SIGTSTP);
    662  1.15       tls 	sa.sa_handler = catch_child;
    663  1.15       tls 	(void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
    664   1.1       cgd 	mode(1);
    665   1.4       cgd 	sigwinch(0);			/* check for size changes */
    666   1.1       cgd }
    667   1.1       cgd 
    668   1.1       cgd void
    669   1.4       cgd sigwinch(signo)
    670   1.4       cgd 	int signo;
    671   1.1       cgd {
    672   1.1       cgd 	struct winsize ws;
    673   1.1       cgd 
    674   1.1       cgd 	if (dosigwinch && get_window_size(0, &ws) == 0 &&
    675  1.15       tls 	    memcmp(&ws, &winsize, sizeof(ws))) {
    676   1.1       cgd 		winsize = ws;
    677   1.1       cgd 		sendwindow();
    678   1.1       cgd 	}
    679   1.1       cgd }
    680   1.1       cgd 
    681   1.1       cgd /*
    682   1.1       cgd  * Send the window size to the server via the magic escape
    683   1.1       cgd  */
    684   1.4       cgd void
    685   1.1       cgd sendwindow()
    686   1.1       cgd {
    687   1.1       cgd 	struct winsize *wp;
    688   1.1       cgd 	char obuf[4 + sizeof (struct winsize)];
    689   1.1       cgd 
    690   1.1       cgd 	wp = (struct winsize *)(obuf+4);
    691   1.1       cgd 	obuf[0] = 0377;
    692   1.1       cgd 	obuf[1] = 0377;
    693   1.1       cgd 	obuf[2] = 's';
    694   1.1       cgd 	obuf[3] = 's';
    695   1.1       cgd 	wp->ws_row = htons(winsize.ws_row);
    696   1.1       cgd 	wp->ws_col = htons(winsize.ws_col);
    697   1.1       cgd 	wp->ws_xpixel = htons(winsize.ws_xpixel);
    698   1.1       cgd 	wp->ws_ypixel = htons(winsize.ws_ypixel);
    699   1.1       cgd 
    700   1.1       cgd #ifdef CRYPT
    701   1.1       cgd #ifdef KERBEROS
    702   1.1       cgd 	if(doencrypt)
    703   1.1       cgd 		(void)des_write(rem, obuf, sizeof(obuf));
    704   1.1       cgd 	else
    705   1.1       cgd #endif
    706   1.1       cgd #endif
    707   1.1       cgd 		(void)write(rem, obuf, sizeof(obuf));
    708   1.1       cgd }
    709   1.1       cgd 
    710   1.1       cgd /*
    711   1.1       cgd  * reader: read from remote: line -> 1
    712   1.1       cgd  */
    713   1.1       cgd #define	READING	1
    714   1.1       cgd #define	WRITING	2
    715   1.1       cgd 
    716   1.1       cgd jmp_buf rcvtop;
    717  1.15       tls pid_t ppid;
    718  1.15       tls int rcvcnt, rcvstate;
    719   1.1       cgd char rcvbuf[8 * 1024];
    720   1.1       cgd 
    721   1.1       cgd void
    722   1.4       cgd oob(signo)
    723   1.4       cgd 	int signo;
    724   1.1       cgd {
    725   1.5   mycroft 	struct termios tty;
    726   1.8   mycroft 	int atmark, n, rcvd;
    727   1.1       cgd 	char waste[BUFSIZ], mark;
    728   1.1       cgd 
    729   1.1       cgd 	rcvd = 0;
    730   1.4       cgd 	while (recv(rem, &mark, 1, MSG_OOB) < 0) {
    731   1.1       cgd 		switch (errno) {
    732   1.1       cgd 		case EWOULDBLOCK:
    733   1.1       cgd 			/*
    734   1.1       cgd 			 * Urgent data not here yet.  It may not be possible
    735   1.1       cgd 			 * to send it yet if we are blocked for output and
    736   1.1       cgd 			 * our input buffer is full.
    737   1.1       cgd 			 */
    738   1.1       cgd 			if (rcvcnt < sizeof(rcvbuf)) {
    739   1.1       cgd 				n = read(rem, rcvbuf + rcvcnt,
    740   1.1       cgd 				    sizeof(rcvbuf) - rcvcnt);
    741   1.1       cgd 				if (n <= 0)
    742   1.1       cgd 					return;
    743   1.1       cgd 				rcvd += n;
    744   1.1       cgd 			} else {
    745   1.1       cgd 				n = read(rem, waste, sizeof(waste));
    746   1.1       cgd 				if (n <= 0)
    747   1.1       cgd 					return;
    748   1.1       cgd 			}
    749   1.1       cgd 			continue;
    750   1.1       cgd 		default:
    751   1.1       cgd 			return;
    752   1.4       cgd 		}
    753   1.1       cgd 	}
    754   1.1       cgd 	if (mark & TIOCPKT_WINDOW) {
    755   1.1       cgd 		/* Let server know about window size changes */
    756   1.1       cgd 		(void)kill(ppid, SIGUSR1);
    757   1.1       cgd 	}
    758   1.1       cgd 	if (!eight && (mark & TIOCPKT_NOSTOP)) {
    759   1.5   mycroft 		(void)tcgetattr(0, &tty);
    760   1.5   mycroft 		tty.c_iflag &= ~IXON;
    761   1.5   mycroft 		(void)tcsetattr(0, TCSANOW, &tty);
    762   1.1       cgd 	}
    763   1.1       cgd 	if (!eight && (mark & TIOCPKT_DOSTOP)) {
    764   1.5   mycroft 		(void)tcgetattr(0, &tty);
    765   1.5   mycroft 		tty.c_iflag |= (deftty.c_iflag & IXON);
    766   1.5   mycroft 		(void)tcsetattr(0, TCSANOW, &tty);
    767   1.1       cgd 	}
    768   1.1       cgd 	if (mark & TIOCPKT_FLUSHWRITE) {
    769   1.8   mycroft 		(void)tcflush(1, TCIOFLUSH);
    770   1.1       cgd 		for (;;) {
    771   1.1       cgd 			if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
    772  1.15       tls 				warn("ioctl SIOCATMARK (ignored)");
    773   1.1       cgd 				break;
    774   1.1       cgd 			}
    775   1.1       cgd 			if (atmark)
    776   1.1       cgd 				break;
    777   1.1       cgd 			n = read(rem, waste, sizeof (waste));
    778   1.1       cgd 			if (n <= 0)
    779   1.1       cgd 				break;
    780   1.1       cgd 		}
    781   1.1       cgd 		/*
    782   1.1       cgd 		 * Don't want any pending data to be output, so clear the recv
    783   1.1       cgd 		 * buffer.  If we were hanging on a write when interrupted,
    784   1.1       cgd 		 * don't want it to restart.  If we were reading, restart
    785   1.1       cgd 		 * anyway.
    786   1.1       cgd 		 */
    787   1.1       cgd 		rcvcnt = 0;
    788   1.1       cgd 		longjmp(rcvtop, 1);
    789   1.1       cgd 	}
    790   1.1       cgd 
    791   1.1       cgd 	/* oob does not do FLUSHREAD (alas!) */
    792   1.1       cgd 
    793   1.1       cgd 	/*
    794   1.1       cgd 	 * If we filled the receive buffer while a read was pending, longjmp
    795   1.1       cgd 	 * to the top to restart appropriately.  Don't abort a pending write,
    796   1.1       cgd 	 * however, or we won't know how much was written.
    797   1.1       cgd 	 */
    798   1.1       cgd 	if (rcvd && rcvstate == READING)
    799   1.1       cgd 		longjmp(rcvtop, 1);
    800   1.1       cgd }
    801   1.1       cgd 
    802   1.1       cgd /* reader: read from remote: line -> 1 */
    803   1.4       cgd int
    804  1.15       tls reader(smask)
    805  1.15       tls 	sigset_t *smask;
    806   1.1       cgd {
    807  1.15       tls 	pid_t pid;
    808  1.15       tls 	int n, remaining;
    809   1.4       cgd 	char *bufp;
    810  1.15       tls 	struct sigaction sa;
    811   1.1       cgd 
    812   1.4       cgd #if BSD >= 43 || defined(SUNOS4)
    813   1.4       cgd 	pid = getpid();		/* modern systems use positives for pid */
    814   1.1       cgd #else
    815   1.4       cgd 	pid = -getpid();	/* old broken systems use negatives */
    816   1.1       cgd #endif
    817  1.15       tls 	sigemptyset(&sa.sa_mask);
    818  1.15       tls 	sa.sa_flags = SA_RESTART;
    819  1.15       tls 	sa.sa_handler = SIG_IGN;
    820  1.15       tls 	(void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
    821  1.15       tls 	sa.sa_handler = oob;
    822  1.15       tls 	(void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
    823   1.1       cgd 	ppid = getppid();
    824   1.1       cgd 	(void)fcntl(rem, F_SETOWN, pid);
    825   1.1       cgd 	(void)setjmp(rcvtop);
    826  1.15       tls 	(void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
    827   1.4       cgd 	bufp = rcvbuf;
    828   1.1       cgd 	for (;;) {
    829   1.1       cgd 		while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
    830   1.1       cgd 			rcvstate = WRITING;
    831   1.1       cgd 			n = write(STDOUT_FILENO, bufp, remaining);
    832   1.1       cgd 			if (n < 0) {
    833   1.1       cgd 				if (errno != EINTR)
    834   1.4       cgd 					return (-1);
    835   1.1       cgd 				continue;
    836   1.1       cgd 			}
    837   1.1       cgd 			bufp += n;
    838   1.1       cgd 		}
    839   1.1       cgd 		bufp = rcvbuf;
    840   1.1       cgd 		rcvcnt = 0;
    841   1.1       cgd 		rcvstate = READING;
    842   1.1       cgd 
    843   1.1       cgd #ifdef CRYPT
    844   1.1       cgd #ifdef KERBEROS
    845   1.1       cgd 		if (doencrypt)
    846   1.1       cgd 			rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
    847   1.1       cgd 		else
    848   1.1       cgd #endif
    849   1.1       cgd #endif
    850   1.1       cgd 			rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
    851   1.1       cgd 		if (rcvcnt == 0)
    852   1.1       cgd 			return (0);
    853   1.1       cgd 		if (rcvcnt < 0) {
    854   1.1       cgd 			if (errno == EINTR)
    855   1.1       cgd 				continue;
    856  1.15       tls 			warn("read");
    857   1.4       cgd 			return (-1);
    858   1.1       cgd 		}
    859   1.1       cgd 	}
    860   1.1       cgd }
    861   1.1       cgd 
    862   1.4       cgd void
    863   1.1       cgd mode(f)
    864   1.4       cgd 	int f;
    865   1.1       cgd {
    866   1.5   mycroft 	struct termios tty;
    867   1.5   mycroft 
    868   1.5   mycroft 	switch (f) {
    869   1.1       cgd 	case 0:
    870   1.5   mycroft 		(void)tcsetattr(0, TCSANOW, &deftty);
    871   1.1       cgd 		break;
    872   1.1       cgd 	case 1:
    873   1.5   mycroft 		(void)tcgetattr(0, &deftty);
    874   1.5   mycroft 		tty = deftty;
    875   1.7   mycroft 		/* This is loosely derived from sys/compat/tty_compat.c. */
    876   1.7   mycroft 		tty.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN);
    877   1.5   mycroft 		tty.c_iflag &= ~ICRNL;
    878   1.5   mycroft 		tty.c_oflag &= ~OPOST;
    879   1.9  christos 		tty.c_cc[VMIN] = 1;
    880   1.9  christos 		tty.c_cc[VTIME] = 0;
    881   1.5   mycroft 		if (eight) {
    882   1.5   mycroft 			tty.c_iflag &= IXOFF;
    883   1.5   mycroft 			tty.c_cflag &= ~(CSIZE|PARENB);
    884   1.5   mycroft 			tty.c_cflag |= CS8;
    885   1.5   mycroft 		}
    886   1.5   mycroft 		(void)tcsetattr(0, TCSANOW, &tty);
    887   1.1       cgd 		break;
    888  1.15       tls 
    889   1.1       cgd 	default:
    890   1.1       cgd 		return;
    891   1.1       cgd 	}
    892   1.1       cgd }
    893   1.1       cgd 
    894   1.1       cgd void
    895   1.4       cgd lostpeer(signo)
    896   1.4       cgd 	int signo;
    897   1.1       cgd {
    898  1.15       tls 	struct sigaction sa;
    899  1.15       tls 	sa.sa_flags = SA_RESTART;
    900  1.15       tls 	sa.sa_handler = SIG_IGN;
    901  1.15       tls 	(void)sigaction(SIGPIPE, &sa, (struct sigaction *)0);
    902   1.5   mycroft 	msg("\aconnection closed.");
    903   1.1       cgd 	done(1);
    904   1.1       cgd }
    905   1.1       cgd 
    906   1.1       cgd /* copy SIGURGs to the child process. */
    907   1.1       cgd void
    908   1.4       cgd copytochild(signo)
    909   1.4       cgd 	int signo;
    910   1.1       cgd {
    911  1.15       tls 
    912   1.1       cgd 	(void)kill(child, SIGURG);
    913   1.1       cgd }
    914   1.1       cgd 
    915   1.4       cgd void
    916   1.1       cgd msg(str)
    917   1.1       cgd 	char *str;
    918   1.1       cgd {
    919  1.15       tls 
    920   1.1       cgd 	(void)fprintf(stderr, "rlogin: %s\r\n", str);
    921   1.1       cgd }
    922   1.1       cgd 
    923   1.1       cgd #ifdef KERBEROS
    924   1.1       cgd /* VARARGS */
    925   1.4       cgd void
    926   1.4       cgd #if __STDC__
    927   1.4       cgd warning(const char *fmt, ...)
    928   1.4       cgd #else
    929   1.4       cgd warning(fmt, va_alist)
    930   1.4       cgd 	char *fmt;
    931   1.4       cgd 	va_dcl
    932   1.4       cgd #endif
    933   1.1       cgd {
    934   1.1       cgd 	va_list ap;
    935   1.1       cgd 
    936   1.1       cgd 	(void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
    937   1.4       cgd #ifdef __STDC__
    938   1.4       cgd 	va_start(ap, fmt);
    939   1.4       cgd #else
    940   1.1       cgd 	va_start(ap);
    941   1.4       cgd #endif
    942   1.1       cgd 	vfprintf(stderr, fmt, ap);
    943   1.1       cgd 	va_end(ap);
    944   1.1       cgd 	(void)fprintf(stderr, ".\n");
    945   1.1       cgd }
    946   1.1       cgd #endif
    947   1.1       cgd 
    948   1.4       cgd __dead void
    949   1.1       cgd usage()
    950   1.1       cgd {
    951   1.1       cgd 	(void)fprintf(stderr,
    952  1.15       tls 	    "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
    953   1.1       cgd #ifdef KERBEROS
    954   1.1       cgd #ifdef CRYPT
    955   1.4       cgd 	    "8EKLx", " [-k realm] ");
    956   1.1       cgd #else
    957   1.4       cgd 	    "8EKL", " [-k realm] ");
    958   1.1       cgd #endif
    959   1.1       cgd #else
    960   1.1       cgd 	    "8EL", " ");
    961   1.1       cgd #endif
    962   1.1       cgd 	exit(1);
    963   1.1       cgd }
    964   1.1       cgd 
    965   1.1       cgd /*
    966   1.4       cgd  * The following routine provides compatibility (such as it is) between older
    967   1.1       cgd  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
    968   1.1       cgd  */
    969   1.4       cgd #ifdef OLDSUN
    970   1.4       cgd int
    971   1.1       cgd get_window_size(fd, wp)
    972   1.1       cgd 	int fd;
    973   1.1       cgd 	struct winsize *wp;
    974   1.1       cgd {
    975   1.1       cgd 	struct ttysize ts;
    976   1.1       cgd 	int error;
    977   1.1       cgd 
    978   1.1       cgd 	if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
    979   1.4       cgd 		return (error);
    980   1.1       cgd 	wp->ws_row = ts.ts_lines;
    981   1.1       cgd 	wp->ws_col = ts.ts_cols;
    982   1.1       cgd 	wp->ws_xpixel = 0;
    983   1.1       cgd 	wp->ws_ypixel = 0;
    984   1.4       cgd 	return (0);
    985   1.1       cgd }
    986   1.1       cgd #endif
    987   1.1       cgd 
    988   1.4       cgd u_int
    989   1.1       cgd getescape(p)
    990   1.1       cgd 	register char *p;
    991   1.1       cgd {
    992   1.1       cgd 	long val;
    993   1.1       cgd 	int len;
    994   1.1       cgd 
    995   1.1       cgd 	if ((len = strlen(p)) == 1)	/* use any single char, including '\' */
    996   1.4       cgd 		return ((u_int)*p);
    997   1.1       cgd 					/* otherwise, \nnn */
    998   1.1       cgd 	if (*p == '\\' && len >= 2 && len <= 4) {
    999   1.4       cgd 		val = strtol(++p, NULL, 8);
   1000   1.1       cgd 		for (;;) {
   1001   1.1       cgd 			if (!*++p)
   1002   1.4       cgd 				return ((u_int)val);
   1003   1.1       cgd 			if (*p < '0' || *p > '8')
   1004   1.1       cgd 				break;
   1005   1.1       cgd 		}
   1006   1.1       cgd 	}
   1007   1.1       cgd 	msg("illegal option value -- e");
   1008   1.1       cgd 	usage();
   1009   1.1       cgd 	/* NOTREACHED */
   1010   1.1       cgd }
   1011