narrow possible window for losing window size change
[unix-history] / usr / src / usr.bin / rlogin / rlogin.c
index 514d562..db58360 100644 (file)
 /*
 /*
- * Copyright (c) 1983 The Regents of the University of California.
+ * Copyright (c) 1983, 1990 The Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+"@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)rlogin.c   5.12 (Berkeley) 9/19/88";
+static char sccsid[] = "@(#)rlogin.c   5.37 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
+/*
+ * $Source: mit/rlogin/RCS/rlogin.c,v $
+ * $Header: mit/rlogin/RCS/rlogin.c,v 5.2 89/07/26 12:11:21 kfall
+ *     Exp Locker: kfall $
+ */
+
 /*
  * rlogin - remote login
  */
 #include <sys/param.h>
 /*
  * rlogin - remote login
  */
 #include <sys/param.h>
-#include <sys/errno.h>
 #include <sys/file.h>
 #include <sys/socket.h>
 #include <sys/file.h>
 #include <sys/socket.h>
+#include <sys/signal.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/wait.h>
 
 #include <netinet/in.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/wait.h>
 
 #include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netdb.h>
 
 
-#include <stdio.h>
 #include <sgtty.h>
 #include <sgtty.h>
+#include <setjmp.h>
+#include <varargs.h>
 #include <errno.h>
 #include <pwd.h>
 #include <errno.h>
 #include <pwd.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#ifdef KERBEROS
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+CREDENTIALS cred;
+Key_schedule schedule;
+int use_kerberos = 1, doencrypt;
+char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
+extern char *krb_realmofhost();
+#endif
+
+#ifndef TIOCPKT_WINDOW
+#define        TIOCPKT_WINDOW  0x80
+#endif
 
 
-#ifdef KERBEROS
-#include <kerberos/krb.h>
-int            encrypt = 0;
-char           krb_realm[REALM_SZ];
-CREDENTIALS    cred;
-Key_schedule   schedule;
-int            use_kerberos = 1;
-#endif /* KERBEROS */
-
-# ifndef TIOCPKT_WINDOW
-# define TIOCPKT_WINDOW 0x80
-# endif TIOCPKT_WINDOW
-
-/* concession to sun */
-# ifndef SIGUSR1
-# define SIGUSR1 30
-# endif SIGUSR1
-
-char   *index(), *rindex(), *malloc(), *getenv(), *strcat(), *strcpy();
-struct passwd *getpwuid();
-char   *name;
-int    rem;
-char   cmdchar = '~';
-int    eight;
-int    litout;
-char   *speeds[] =
-    { "0", "50", "75", "110", "134", "150", "200", "300",
-      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
-char   term[256] = "network";
-extern int errno;
-int    lostpeer();
-int    dosigwinch = 0;
-#ifndef sigmask
-#define sigmask(m)     (1 << ((m)-1))
+/* concession to Sun */
+#ifndef SIGUSR1
+#define        SIGUSR1 30
 #endif
 #endif
+
+int eight, litout, rem;
+
+int noescape;
+u_char escapechar = '~';
+
+char *speeds[] = {
+       "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
+       "1800", "2400", "4800", "9600", "19200", "38400"
+};
+
 #ifdef sun
 struct winsize {
        unsigned short ws_row, ws_col;
        unsigned short ws_xpixel, ws_ypixel;
 };
 #ifdef sun
 struct winsize {
        unsigned short ws_row, ws_col;
        unsigned short ws_xpixel, ws_ypixel;
 };
-#endif sun
+#endif
 struct winsize winsize;
 struct winsize winsize;
-int    sigwinch(), oob();
 
 
-/*
- * The following routine provides compatibility (such as it is)
- * between 4.2BSD Suns and others.  Suns have only a `ttysize',
- * so we convert it to a winsize.
- */
-#ifdef sun
-int
-get_window_size(fd, wp)
-       int fd;
-       struct winsize *wp;
-{
-       struct ttysize ts;
-       int error;
+#ifndef sun
+#define        get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
+#endif
 
 
-       if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
-               return (error);
-       wp->ws_row = ts.ts_lines;
-       wp->ws_col = ts.ts_cols;
-       wp->ws_xpixel = 0;
-       wp->ws_ypixel = 0;
-       return (0);
-}
-#else sun
-#define get_window_size(fd, wp)        ioctl(fd, TIOCGWINSZ, wp)
-#endif sun
+void exit();
 
 main(argc, argv)
        int argc;
        char **argv;
 {
 
 main(argc, argv)
        int argc;
        char **argv;
 {
-       char *host, *cp;
-       struct sgttyb ttyb;
-       struct passwd *pwd;
+       extern char *optarg;
+       extern int optind;
+       struct passwd *pw;
        struct servent *sp;
        struct servent *sp;
-       int uid, options = 0, oldmask;
-       int on = 1;
-
-       host = rindex(argv[0], '/');
-       if (host)
-               host++;
+       struct hostent *hp;
+       struct sgttyb ttyb;
+       long omask;
+       int argoff, ch, dflag, one, uid;
+       char *host, *p, *user, term[1024];
+       void lostpeer(), copytochild(), writeroob();
+       u_char getescape();
+       char *getenv();
+
+       argoff = dflag = 0;
+       one = 1;
+       host = user = NULL;
+
+       if (p = rindex(argv[0], '/'))
+               ++p;
        else
        else
-               host = argv[0];
-       argv++, --argc;
-       if (!strcmp(host, "rlogin"))
-               host = *argv++, --argc;
-another:
-       if (argc > 0 && !strcmp(*argv, "-d")) {
-               argv++, argc--;
-               options |= SO_DEBUG;
-               goto another;
-       }
-       if (argc > 0 && !strcmp(*argv, "-l")) {
-               argv++, argc--;
-               if (argc == 0)
-                       goto usage;
-               name = *argv++; argc--;
-               goto another;
-       }
-       if (argc > 0 && !strncmp(*argv, "-e", 2)) {
-               cmdchar = argv[0][2];
-               argv++, argc--;
-               goto another;
-       }
-       if (argc > 0 && !strcmp(*argv, "-8")) {
-               eight = 1;
-               argv++, argc--;
-               goto another;
-       }
-       if (argc > 0 && !strcmp(*argv, "-L")) {
-               litout = 1;
-               argv++, argc--;
-               goto another;
-       }
+               p = argv[0];
+
+       if (strcmp(p, "rlogin"))
+               host = p;
 
 
-#ifdef KERBEROS
-       if (argc > 0 && !strcmp(*argv, "-x")) {
-               encrypt = 1;
-               des_set_key(cred.session, schedule);
-               argv++, argc--;
-               goto another;
+       /* handle "rlogin host flags" */
+       if (!host && argc > 2 && argv[1][0] != '-') {
+               host = argv[1];
+               argoff = 1;
        }
        }
-#endif /* KERBEROS */
-
-       if (host == 0)
-               goto usage;
-       if (argc > 0)
-               goto usage;
-       pwd = getpwuid(getuid());
-       if (pwd == 0) {
-               fprintf(stderr, "Who are you?\n");
+
+#ifdef KERBEROS
+#define        OPTIONS "8EKLde:k:l:x"
+#else
+#define        OPTIONS "8EKLde:l:"
+#endif
+       while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
+               switch(ch) {
+               case '8':
+                       eight = 1;
+                       break;
+               case 'E':
+                       noescape = 1;
+                       break;
+               case 'K':
+#ifdef KERBEROS
+                       use_kerberos = 0;
+#endif
+                       break;
+               case 'L':
+                       litout = 1;
+                       break;
+               case 'd':
+                       dflag = 1;
+                       break;
+               case 'e':
+                       noescape = 0;
+                       escapechar = getescape(optarg);
+                       break;
+#ifdef KERBEROS
+               case 'k':
+                       dest_realm = dst_realm_buf;
+                       (void)strncpy(dest_realm, optarg, REALM_SZ);
+                       break;
+#endif
+               case 'l':
+                       user = optarg;
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       optind += argoff;
+       argc -= optind;
+       argv += optind;
+
+       /* if haven't gotten a host yet, do so */
+       if (!host && !(host = *argv++))
+               usage();
+
+       if (*argv)
+               usage();
+
+       if (!(pw = getpwuid(uid = getuid()))) {
+               (void)fprintf(stderr, "rlogin: unknown user id.\n");
                exit(1);
        }
                exit(1);
        }
-#ifdef KERBEROS
-       sp = getservbyname("klogin", "tcp");
-       if(sp == NULL) {
-               use_kerberos = 0;
-               old_warning("klogin service unknown");
-               sp = getservbyname("login", "tcp");
+       if (!user)
+               user = pw->pw_name;
+
+       sp = NULL;
+#ifdef KERBEROS
+       if (use_kerberos) {
+               sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
+               if (sp == NULL) {
+                       use_kerberos = 0;
+                       warning("can't get entry for %s/tcp service",
+                           doencrypt ? "eklogin" : "klogin");
+               }
        }
        }
-#else
-       sp = getservbyname("login", "tcp");
 #endif
 #endif
-       if (sp == 0) {
-               fprintf(stderr, "rlogin: login/tcp: unknown service\n");
-               exit(2);
+       if (sp == NULL)
+               sp = getservbyname("login", "tcp");
+       if (sp == NULL) {
+               (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
+               exit(1);
        }
        }
-       cp = getenv("TERM");
-       if (cp)
-               (void) strcpy(term, cp);
+
+       (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
        if (ioctl(0, TIOCGETP, &ttyb) == 0) {
        if (ioctl(0, TIOCGETP, &ttyb) == 0) {
-               (void) strcat(term, "/");
-               (void) strcat(term, speeds[ttyb.sg_ospeed]);
+               (void)strcat(term, "/");
+               (void)strcat(term, speeds[ttyb.sg_ospeed]);
        }
        }
-       (void) get_window_size(0, &winsize);
-       (void) signal(SIGPIPE, lostpeer);
+
+       (void)get_window_size(0, &winsize);
+
+       (void)signal(SIGPIPE, lostpeer);
        /* will use SIGUSR1 for window size hack, so hold it off */
        /* will use SIGUSR1 for window size hack, so hold it off */
-       oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+       omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+       /*
+        * We set SIGURG and SIGUSR1 below so that an
+        * incoming signal will be held pending rather than being
+        * discarded. Note that these routines will be ready to get
+        * a signal by the time that they are unblocked below.
+        */
+       (void)signal(SIGURG, copytochild);
+       (void)signal(SIGUSR1, writeroob);
 
 
-#ifdef KERBEROS
+#ifdef KERBEROS
 try_connect:
 try_connect:
-       if(use_kerberos) {
-               rem = KSUCCESS;
-               if(krb_realm[0] == '\0') {
-                       rem = get_krbrlm(krb_realm, 1);
-               }
-               if(rem == KSUCCESS) {
-                       if(encrypt) {
-                               rem = krcmd_mutual(
-                                       &host, sp->s_port,
-                                       name ? name : pwd->pw_name, term,
-                                       0, krb_realm,
-                                       &cred, schedule
-                               );
-                       } else {
-                               rem = krcmd(
-                                       &host, sp->s_port,
-                                       name ? name : pwd->pw_name, term,
-                                       0, krb_realm
-                               );
-                       }
-               } else {
-                       fprintf(
-                               stderr,
-                               "rlogin: Kerberos error getting local realm %s\n",
-                               krb_err_txt[rem]
-                       );
+       if (use_kerberos) {
+               /* fully qualify hostname (needed for krb_realmofhost) */
+               hp = gethostbyname(host);
+               if (hp != NULL && !(host = strdup(hp->h_name))) {
+                       (void)fprintf(stderr, "rlogin: %s.\n", strerror(ENOMEM));
                        exit(1);
                }
                        exit(1);
                }
-               if((rem < 0) && errno == ECONNREFUSED) {
+
+               rem = KSUCCESS;
+               errno = 0;
+               if (dest_realm == NULL)
+                       dest_realm = krb_realmofhost(host);
+
+                       rem = krcmd(&host, sp->s_port, user, term, 0,
+                           dest_realm);
+               if (rem < 0) {
                        use_kerberos = 0;
                        use_kerberos = 0;
-                       old_warning("remote host doesn't support Kerberos");
+                       sp = getservbyname("login", "tcp");
+                       if (sp == NULL) {
+                               (void)fprintf(stderr,
+                                   "rlogin: unknown service login/tcp.\n");
+                               exit(1);
+                       }
+                       if (errno == ECONNREFUSED)
+                               warning("remote host doesn't support Kerberos");
+                       if (errno == ENOENT)
+                               warning("can't provide Kerberos auth data");
                        goto try_connect;
                }
        } else {
                        goto try_connect;
                }
        } else {
-               if(encrypt) {
-                       fprintf(stderr, "The -x flag requires Kerberos authencation\n");
-                       exit(1);
-               }
-               rem = rcmd(&host, sp->s_port, pwd->pw_name,
-                       name ? name : pwd->pw_name, term, 0);
+               rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
        }
 #else
        }
 #else
-               rem = rcmd(&host, sp->s_port, pwd->pw_name,
-               name ? name : pwd->pw_name, term, 0);
-#endif
+       rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
+#endif /* KERBEROS */
 
 
-       if(rem < 0) 
+       if (rem < 0)
                exit(1);
 
                exit(1);
 
-       if (options & SO_DEBUG &&
-           setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
-               perror("rlogin: setsockopt (SO_DEBUG)");
-       uid = getuid();
-       if (setuid(uid) < 0) {
-               perror("rlogin: setuid");
-               exit(1);
-       }
-       doit(oldmask);
+       if (dflag &&
+           setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
+               (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
+                   strerror(errno));
+       one = IPTOS_LOWDELAY;
+       if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
+               perror("rlogin: setsockopt TOS (ignored)");
+
+       (void)setuid(uid);
+       doit(omask);
        /*NOTREACHED*/
        /*NOTREACHED*/
-usage:
-       fprintf(stderr,
-#ifdef KERBEROS
-           "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -x ]\n");
-#else
-           "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ]\n");
-#endif
-       exit(1);
 }
 
 }
 
-#define CRLF "\r\n"
-
-int    child;
-int    catchild();
-int    copytochild(), writeroob();
+int child, defflags, deflflags, tabflag;
+char deferase, defkill;
+struct tchars deftc;
+struct ltchars defltc;
+struct tchars notc = { -1, -1, -1, -1, -1, -1 };
+struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
 
 
-int    defflags, tabflag;
-int    deflflags;
-char   deferase, defkill;
-struct tchars deftc;
-struct ltchars defltc;
-struct tchars notc =   { -1, -1, -1, -1, -1, -1 };
-struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
-
-doit(oldmask)
+doit(omask)
+       long omask;
 {
 {
-       int exit();
        struct sgttyb sb;
        struct sgttyb sb;
+       void catch_child(), exit();
 
 
-       (void) ioctl(0, TIOCGETP, (char *)&sb);
+       (void)ioctl(0, TIOCGETP, (char *)&sb);
        defflags = sb.sg_flags;
        tabflag = defflags & TBDELAY;
        defflags &= ECHO | CRMOD;
        deferase = sb.sg_erase;
        defkill = sb.sg_kill;
        defflags = sb.sg_flags;
        tabflag = defflags & TBDELAY;
        defflags &= ECHO | CRMOD;
        deferase = sb.sg_erase;
        defkill = sb.sg_kill;
-       (void) ioctl(0, TIOCLGET, (char *)&deflflags);
-       (void) ioctl(0, TIOCGETC, (char *)&deftc);
+       (void)ioctl(0, TIOCLGET, (char *)&deflflags);
+       (void)ioctl(0, TIOCGETC, (char *)&deftc);
        notc.t_startc = deftc.t_startc;
        notc.t_stopc = deftc.t_stopc;
        notc.t_startc = deftc.t_startc;
        notc.t_stopc = deftc.t_stopc;
-       (void) ioctl(0, TIOCGLTC, (char *)&defltc);
-       (void) signal(SIGINT, SIG_IGN);
+       (void)ioctl(0, TIOCGLTC, (char *)&defltc);
+       (void)signal(SIGINT, SIG_IGN);
        setsignal(SIGHUP, exit);
        setsignal(SIGQUIT, exit);
        child = fork();
        if (child == -1) {
        setsignal(SIGHUP, exit);
        setsignal(SIGQUIT, exit);
        child = fork();
        if (child == -1) {
-               perror("rlogin: fork");
+               (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
                done(1);
        }
        if (child == 0) {
                mode(1);
                done(1);
        }
        if (child == 0) {
                mode(1);
-               if (reader(oldmask) == 0) {
-                       prf("Connection closed.");
+               if (reader(omask) == 0) {
+                       msg("connection closed.");
                        exit(0);
                }
                sleep(1);
                        exit(0);
                }
                sleep(1);
-               prf("\007Connection closed.");
-               exit(3);
+               msg("\007connection closed.");
+               exit(1);
        }
 
        /*
        }
 
        /*
-        * We may still own the socket, and may have a pending SIGURG
-        * (or might receive one soon) that we really want to send to
-        * the reader.  Set a trap that simply copies such signals to
-        * the child.
+        * We may still own the socket, and may have a pending SIGURG (or might
+        * receive one soon) that we really want to send to the reader.  When
+        * one of these comes in, the trap copytochild simply copies such
+        * signals to the child. We can now unblock SIGURG and SIGUSR1
+        * that were set above.
         */
         */
-       (void) signal(SIGURG, copytochild);
-       (void) signal(SIGUSR1, writeroob);
-       (void) sigsetmask(oldmask);
-       (void) signal(SIGCHLD, catchild);
+       (void)sigsetmask(omask);
+       (void)signal(SIGCHLD, catch_child);
        writer();
        writer();
-       prf("Closed connection.");
+       msg("closed connection.");
        done(0);
 }
 
        done(0);
 }
 
-/*
- * Trap a signal, unless it is being ignored.
- */
+/* trap a signal, unless it is being ignored. */
 setsignal(sig, act)
 setsignal(sig, act)
-       int sig, (*act)();
+       int sig;
+       void (*act)();
 {
        int omask = sigblock(sigmask(sig));
 
        if (signal(sig, act) == SIG_IGN)
 {
        int omask = sigblock(sigmask(sig));
 
        if (signal(sig, act) == SIG_IGN)
-               (void) signal(sig, SIG_IGN);
-       (void) sigsetmask(omask);
+               (void)signal(sig, SIG_IGN);
+       (void)sigsetmask(omask);
 }
 
 done(status)
        int status;
 {
 }
 
 done(status)
        int status;
 {
-       int w;
+       int w, wstatus;
 
        mode(0);
        if (child > 0) {
 
        mode(0);
        if (child > 0) {
-               /* make sure catchild does not snap it up */
-               (void) signal(SIGCHLD, SIG_DFL);
+               /* make sure catch_child does not snap it up */
+               (void)signal(SIGCHLD, SIG_DFL);
                if (kill(child, SIGKILL) >= 0)
                if (kill(child, SIGKILL) >= 0)
-                       while ((w = wait((union wait *)0)) > 0 && w != child)
-                               /*void*/;
+                       while ((w = wait(&wstatus)) > 0 && w != child);
        }
        exit(status);
 }
 
        }
        exit(status);
 }
 
-/*
- * Copy SIGURGs to the child process.
- */
-copytochild()
-{
-
-       (void) kill(child, SIGURG);
-}
+int dosigwinch;
+void sigwinch();
 
 /*
  * This is called when the reader process gets the out-of-band (urgent)
  * request to turn on the window-changing protocol.
  */
 
 /*
  * This is called when the reader process gets the out-of-band (urgent)
  * request to turn on the window-changing protocol.
  */
+void
 writeroob()
 {
 writeroob()
 {
-
        if (dosigwinch == 0) {
                sendwindow();
        if (dosigwinch == 0) {
                sendwindow();
-               (void) signal(SIGWINCH, sigwinch);
+               (void)signal(SIGWINCH, sigwinch);
        }
        dosigwinch = 1;
 }
 
        }
        dosigwinch = 1;
 }
 
-catchild()
+void
+catch_child()
 {
        union wait status;
        int pid;
 
 {
        union wait status;
        int pid;
 
-again:
-       pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
-       if (pid == 0)
-               return;
-       /*
-        * if the child (reader) dies, just quit
-        */
-       if (pid < 0 || pid == child && !WIFSTOPPED(status))
-               done((int)(status.w_termsig | status.w_retcode));
-       goto again;
+       for (;;) {
+               pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
+               if (pid == 0)
+                       return;
+               /* if the child (reader) dies, just quit */
+               if (pid < 0 || pid == child && !WIFSTOPPED(status))
+                       done((int)(status.w_termsig | status.w_retcode));
+       }
+       /* NOTREACHED */
 }
 
 /*
  * writer: write to remote: 0 -> line.
 }
 
 /*
  * writer: write to remote: 0 -> line.
- * ~.  terminate
- * ~^Z suspend rlogin process.
- * ~^Y  suspend rlogin process, but leave reader alone.
+ * ~.                          terminate
+ * ~^Z                         suspend rlogin process.
+ * ~<delayed-suspend char>     suspend rlogin process, but leave reader alone.
  */
 writer()
 {
  */
 writer()
 {
+       register int bol, local, n;
        char c;
        char c;
-       register n;
-       register bol = 1;               /* beginning of line */
-       register local = 0;
 
 
+       bol = 1;                        /* beginning of line */
+       local = 0;
        for (;;) {
        for (;;) {
-               n = read(0, &c, 1);
+               n = read(STDIN_FILENO, &c, 1);
                if (n <= 0) {
                        if (n < 0 && errno == EINTR)
                                continue;
                        break;
                }
                /*
                if (n <= 0) {
                        if (n < 0 && errno == EINTR)
                                continue;
                        break;
                }
                /*
-                * If we're at the beginning of the line
-                * and recognize a command character, then
-                * we echo locally.  Otherwise, characters
-                * are echo'd remotely.  If the command
-                * character is doubled, this acts as a 
-                * force and local echo is suppressed.
+                * If we're at the beginning of the line and recognize a
+                * command character, then we echo locally.  Otherwise,
+                * characters are echo'd remotely.  If the command character
+                * is doubled, this acts as a force and local echo is
+                * suppressed.
                 */
                if (bol) {
                        bol = 0;
                 */
                if (bol) {
                        bol = 0;
-                       if (c == cmdchar) {
-                               bol = 0;
+                       if (!noescape && c == escapechar) {
                                local = 1;
                                continue;
                        }
                                local = 1;
                                continue;
                        }
@@ -459,34 +439,12 @@ writer()
                                stop(c);
                                continue;
                        }
                                stop(c);
                                continue;
                        }
-                       if (c != cmdchar) {
-#ifdef KERBEROS
-                               if(encrypt) {
-                                       (void) des_write(
-                                               rem,
-                                               &cmdchar,
-                                               1
-                                       );
-                               } else
-#endif
-                                       (void) write(
-                                               rem,
-                                               &cmdchar,
-                                               1
-                                       );
-                       }
+                       if (c != escapechar)
+                                       (void)write(rem, &escapechar, 1);
                }
 
                }
 
-#ifdef KERBEROS
-               if(encrypt) {
-                       if (des_write(rem, &c, 1) == 0) {
-                               prf("line gone");
-                               break;
-                       }
-               } else
-#endif
                        if (write(rem, &c, 1) == 0) {
                        if (write(rem, &c, 1) == 0) {
-                               prf("line gone");
+                               msg("line gone");
                                break;
                        }
                bol = c == defkill || c == deftc.t_eofc ||
                                break;
                        }
                bol = c == defkill || c == deftc.t_eofc ||
@@ -498,11 +456,12 @@ writer()
 echo(c)
 register char c;
 {
 echo(c)
 register char c;
 {
+       register char *p;
        char buf[8];
        char buf[8];
-       register char *p = buf;
 
 
+       p = buf;
        c &= 0177;
        c &= 0177;
-       *p++ = cmdchar;
+       *p++ = escapechar;
        if (c < ' ') {
                *p++ = '^';
                *p++ = c + '@';
        if (c < ' ') {
                *p++ = '^';
                *p++ = c + '@';
@@ -513,26 +472,27 @@ register char c;
                *p++ = c;
        *p++ = '\r';
        *p++ = '\n';
                *p++ = c;
        *p++ = '\r';
        *p++ = '\n';
-       (void) write(1, buf, p - buf);
+       (void)write(STDOUT_FILENO, buf, p - buf);
 }
 
 stop(cmdc)
        char cmdc;
 {
        mode(0);
 }
 
 stop(cmdc)
        char cmdc;
 {
        mode(0);
-       (void) signal(SIGCHLD, SIG_IGN);
-       (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
-       (void) signal(SIGCHLD, catchild);
+       (void)signal(SIGCHLD, SIG_IGN);
+       (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
+       (void)signal(SIGCHLD, catch_child);
        mode(1);
        sigwinch();                     /* check for size changes */
 }
 
        mode(1);
        sigwinch();                     /* check for size changes */
 }
 
+void
 sigwinch()
 {
        struct winsize ws;
 
        if (dosigwinch && get_window_size(0, &ws) == 0 &&
 sigwinch()
 {
        struct winsize ws;
 
        if (dosigwinch && get_window_size(0, &ws) == 0 &&
-           bcmp(&ws, &winsize, sizeof (ws))) {
+           bcmp(&ws, &winsize, sizeof(ws))) {
                winsize = ws;
                sendwindow();
        }
                winsize = ws;
                sendwindow();
        }
@@ -543,9 +503,10 @@ sigwinch()
  */
 sendwindow()
 {
  */
 sendwindow()
 {
+       struct winsize *wp;
        char obuf[4 + sizeof (struct winsize)];
        char obuf[4 + sizeof (struct winsize)];
-       struct winsize *wp = (struct winsize *)(obuf+4);
 
 
+       wp = (struct winsize *)(obuf+4);
        obuf[0] = 0377;
        obuf[1] = 0377;
        obuf[2] = 's';
        obuf[0] = 0377;
        obuf[1] = 0377;
        obuf[2] = 's';
@@ -555,12 +516,7 @@ sendwindow()
        wp->ws_xpixel = htons(winsize.ws_xpixel);
        wp->ws_ypixel = htons(winsize.ws_ypixel);
 
        wp->ws_xpixel = htons(winsize.ws_xpixel);
        wp->ws_ypixel = htons(winsize.ws_ypixel);
 
-#ifdef KERBEROS
-       if(encrypt)
-               (void) des_write(rem, obuf, sizeof(obuf));
-       else
-#endif
-               (void) write(rem, obuf, sizeof(obuf));
+               (void)write(rem, obuf, sizeof(obuf));
 }
 
 /*
 }
 
 /*
@@ -569,32 +525,30 @@ sendwindow()
 #define        READING 1
 #define        WRITING 2
 
 #define        READING 1
 #define        WRITING 2
 
-char   rcvbuf[8 * 1024];
-int    rcvcnt;
-int    rcvstate;
-int    ppid;
-jmp_buf        rcvtop;
+jmp_buf rcvtop;
+int ppid, rcvcnt, rcvstate;
+char rcvbuf[8 * 1024];
 
 
+void
 oob()
 {
 oob()
 {
-       int out = FWRITE, atmark, n;
-       int rcvd = 0;
-       char waste[BUFSIZ], mark;
        struct sgttyb sb;
        struct sgttyb sb;
+       int atmark, n, out, rcvd;
+       char waste[BUFSIZ], mark;
 
 
+       out = O_RDWR;
+       rcvd = 0;
        while (recv(rem, &mark, 1, MSG_OOB) < 0)
                switch (errno) {
        while (recv(rem, &mark, 1, MSG_OOB) < 0)
                switch (errno) {
-               
                case EWOULDBLOCK:
                        /*
                case EWOULDBLOCK:
                        /*
-                        * Urgent data not here yet.
-                        * It may not be possible to send it yet
-                        * if we are blocked for output
-                        * and our input buffer is full.
+                        * Urgent data not here yet.  It may not be possible
+                        * to send it yet if we are blocked for output and
+                        * our input buffer is full.
                         */
                        if (rcvcnt < sizeof(rcvbuf)) {
                                n = read(rem, rcvbuf + rcvcnt,
                         */
                        if (rcvcnt < sizeof(rcvbuf)) {
                                n = read(rem, rcvbuf + rcvcnt,
-                                       sizeof(rcvbuf) - rcvcnt);
+                                   sizeof(rcvbuf) - rcvcnt);
                                if (n <= 0)
                                        return;
                                rcvd += n;
                                if (n <= 0)
                                        return;
                                rcvd += n;
@@ -604,39 +558,37 @@ oob()
                                        return;
                        }
                        continue;
                                        return;
                        }
                        continue;
-                               
                default:
                        return;
        }
        if (mark & TIOCPKT_WINDOW) {
                default:
                        return;
        }
        if (mark & TIOCPKT_WINDOW) {
-               /*
-                * Let server know about window size changes
-                */
-               (void) kill(ppid, SIGUSR1);
+               /* Let server know about window size changes */
+               (void)kill(ppid, SIGUSR1);
        }
        if (!eight && (mark & TIOCPKT_NOSTOP)) {
        }
        if (!eight && (mark & TIOCPKT_NOSTOP)) {
-               (void) ioctl(0, TIOCGETP, (char *)&sb);
+               (void)ioctl(0, TIOCGETP, (char *)&sb);
                sb.sg_flags &= ~CBREAK;
                sb.sg_flags |= RAW;
                sb.sg_flags &= ~CBREAK;
                sb.sg_flags |= RAW;
-               (void) ioctl(0, TIOCSETN, (char *)&sb);
+               (void)ioctl(0, TIOCSETN, (char *)&sb);
                notc.t_stopc = -1;
                notc.t_startc = -1;
                notc.t_stopc = -1;
                notc.t_startc = -1;
-               (void) ioctl(0, TIOCSETC, (char *)&notc);
+               (void)ioctl(0, TIOCSETC, (char *)&notc);
        }
        if (!eight && (mark & TIOCPKT_DOSTOP)) {
        }
        if (!eight && (mark & TIOCPKT_DOSTOP)) {
-               (void) ioctl(0, TIOCGETP, (char *)&sb);
+               (void)ioctl(0, TIOCGETP, (char *)&sb);
                sb.sg_flags &= ~RAW;
                sb.sg_flags |= CBREAK;
                sb.sg_flags &= ~RAW;
                sb.sg_flags |= CBREAK;
-               (void) ioctl(0, TIOCSETN, (char *)&sb);
+               (void)ioctl(0, TIOCSETN, (char *)&sb);
                notc.t_stopc = deftc.t_stopc;
                notc.t_startc = deftc.t_startc;
                notc.t_stopc = deftc.t_stopc;
                notc.t_startc = deftc.t_startc;
-               (void) ioctl(0, TIOCSETC, (char *)&notc);
+               (void)ioctl(0, TIOCSETC, (char *)&notc);
        }
        if (mark & TIOCPKT_FLUSHWRITE) {
        }
        if (mark & TIOCPKT_FLUSHWRITE) {
-               (void) ioctl(1, TIOCFLUSH, (char *)&out);
+               (void)ioctl(1, TIOCFLUSH, (char *)&out);
                for (;;) {
                        if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
                for (;;) {
                        if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
-                               perror("ioctl");
+                               (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
+                                   strerror(errno));
                                break;
                        }
                        if (atmark)
                                break;
                        }
                        if (atmark)
@@ -646,35 +598,32 @@ oob()
                                break;
                }
                /*
                                break;
                }
                /*
-                * Don't want any pending data to be output,
-                * so clear the recv buffer.
-                * If we were hanging on a write when interrupted,
-                * don't want it to restart.  If we were reading,
-                * restart anyway.
+                * Don't want any pending data to be output, so clear the recv
+                * buffer.  If we were hanging on a write when interrupted,
+                * don't want it to restart.  If we were reading, restart
+                * anyway.
                 */
                rcvcnt = 0;
                longjmp(rcvtop, 1);
        }
 
                 */
                rcvcnt = 0;
                longjmp(rcvtop, 1);
        }
 
-       /*
-        * oob does not do FLUSHREAD (alas!)
-        */
+       /* oob does not do FLUSHREAD (alas!) */
 
        /*
 
        /*
-        * If we filled the receive buffer while a read was pending,
-        * longjmp to the top to restart appropriately.  Don't abort
-        * a pending write, however, or we won't know how much was written.
+        * If we filled the receive buffer while a read was pending, longjmp
+        * to the top to restart appropriately.  Don't abort a pending write,
+        * however, or we won't know how much was written.
         */
        if (rcvd && rcvstate == READING)
                longjmp(rcvtop, 1);
 }
 
         */
        if (rcvd && rcvstate == READING)
                longjmp(rcvtop, 1);
 }
 
-/*
- * reader: read from remote: line -> 1
- */
-reader(oldmask)
-       int oldmask;
+/* reader: read from remote: line -> 1 */
+reader(omask)
+       int omask;
 {
 {
+       void oob();
+
 #if !defined(BSD) || BSD < 43
        int pid = -getpid();
 #else
 #if !defined(BSD) || BSD < 43
        int pid = -getpid();
 #else
@@ -683,19 +632,19 @@ reader(oldmask)
        int n, remaining;
        char *bufp = rcvbuf;
 
        int n, remaining;
        char *bufp = rcvbuf;
 
-       (void) signal(SIGTTOU, SIG_IGN);
-       (void) signal(SIGURG, oob);
+       (void)signal(SIGTTOU, SIG_IGN);
+       (void)signal(SIGURG, oob);
        ppid = getppid();
        ppid = getppid();
-       (void) fcntl(rem, F_SETOWN, pid);
-       (void) setjmp(rcvtop);
-       (void) sigsetmask(oldmask);
+       (void)fcntl(rem, F_SETOWN, pid);
+       (void)setjmp(rcvtop);
+       (void)sigsetmask(omask);
        for (;;) {
                while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
                        rcvstate = WRITING;
        for (;;) {
                while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
                        rcvstate = WRITING;
-                       n = write(1, bufp, remaining);
+                       n = write(STDOUT_FILENO, bufp, remaining);
                        if (n < 0) {
                                if (errno != EINTR)
                        if (n < 0) {
                                if (errno != EINTR)
-                                       return (-1);
+                                       return(-1);
                                continue;
                        }
                        bufp += n;
                                continue;
                        }
                        bufp += n;
@@ -704,34 +653,29 @@ reader(oldmask)
                rcvcnt = 0;
                rcvstate = READING;
 
                rcvcnt = 0;
                rcvstate = READING;
 
-#ifdef KERBEROS
-               if(encrypt)
-                       rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf));
-               else
-#endif
                        rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
                if (rcvcnt == 0)
                        return (0);
                if (rcvcnt < 0) {
                        if (errno == EINTR)
                                continue;
                        rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
                if (rcvcnt == 0)
                        return (0);
                if (rcvcnt < 0) {
                        if (errno == EINTR)
                                continue;
-                       perror("read");
-                       return (-1);
+                       (void)fprintf(stderr, "rlogin: read: %s.\n",
+                           strerror(errno));
+                       return(-1);
                }
        }
 }
 
 mode(f)
 {
                }
        }
 }
 
 mode(f)
 {
-       struct tchars *tc;
        struct ltchars *ltc;
        struct sgttyb sb;
        struct ltchars *ltc;
        struct sgttyb sb;
-       int     lflags;
-
-       (void) ioctl(0, TIOCGETP, (char *)&sb);
-       (void) ioctl(0, TIOCLGET, (char *)&lflags);
-       switch (f) {
+       struct tchars *tc;
+       int lflags;
 
 
+       (void)ioctl(0, TIOCGETP, (char *)&sb);
+       (void)ioctl(0, TIOCLGET, (char *)&lflags);
+       switch(f) {
        case 0:
                sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
                sb.sg_flags |= defflags|tabflag;
        case 0:
                sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
                sb.sg_flags |= defflags|tabflag;
@@ -741,7 +685,6 @@ mode(f)
                sb.sg_erase = deferase;
                lflags = deflflags;
                break;
                sb.sg_erase = deferase;
                lflags = deflflags;
                break;
-
        case 1:
                sb.sg_flags |= (eight ? RAW : CBREAK);
                sb.sg_flags &= ~defflags;
        case 1:
                sb.sg_flags |= (eight ? RAW : CBREAK);
                sb.sg_flags &= ~defflags;
@@ -754,35 +697,107 @@ mode(f)
                if (litout)
                        lflags |= LLITOUT;
                break;
                if (litout)
                        lflags |= LLITOUT;
                break;
-
        default:
                return;
        }
        default:
                return;
        }
-       (void) ioctl(0, TIOCSLTC, (char *)ltc);
-       (void) ioctl(0, TIOCSETC, (char *)tc);
-       (void) ioctl(0, TIOCSETN, (char *)&sb);
-       (void) ioctl(0, TIOCLSET, (char *)&lflags);
+       (void)ioctl(0, TIOCSLTC, (char *)ltc);
+       (void)ioctl(0, TIOCSETC, (char *)tc);
+       (void)ioctl(0, TIOCSETN, (char *)&sb);
+       (void)ioctl(0, TIOCLSET, (char *)&lflags);
 }
 
 }
 
-/*VARARGS*/
-prf(f, a1, a2, a3, a4, a5)
-       char *f;
+void
+lostpeer()
 {
 {
+       (void)signal(SIGPIPE, SIG_IGN);
+       msg("\007connection closed.");
+       done(1);
+}
 
 
-       fprintf(stderr, f, a1, a2, a3, a4, a5);
-       fprintf(stderr, CRLF);
+/* copy SIGURGs to the child process. */
+void
+copytochild()
+{
+       (void)kill(child, SIGURG);
 }
 
 }
 
-lostpeer()
+msg(str)
+       char *str;
 {
 {
+       (void)fprintf(stderr, "rlogin: %s\r\n", str);
+}
 
 
-       (void) signal(SIGPIPE, SIG_IGN);
-       prf("\007Connection closed.");
-       done(1);
+#ifdef KERBEROS
+/* VARARGS */
+warning(va_alist)
+va_dcl
+{
+       va_list ap;
+       char *fmt;
+
+       (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
+       va_start(ap);
+       fmt = va_arg(ap, char *);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void)fprintf(stderr, ".\n");
+}
+#endif
+
+usage()
+{
+       (void)fprintf(stderr,
+           "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
+#ifdef KERBEROS
+           "8EKL", " [-k realm] ");
+#else
+           "8EL", " ");
+#endif
+       exit(1);
+}
+
+/*
+ * The following routine provides compatibility (such as it is) between 4.2BSD
+ * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
+ */
+#ifdef sun
+get_window_size(fd, wp)
+       int fd;
+       struct winsize *wp;
+{
+       struct ttysize ts;
+       int error;
+
+       if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
+               return(error);
+       wp->ws_row = ts.ts_lines;
+       wp->ws_col = ts.ts_cols;
+       wp->ws_xpixel = 0;
+       wp->ws_ypixel = 0;
+       return(0);
 }
 }
+#endif
 
 
-old_warning(str)
-       char    *str;
+u_char
+getescape(p)
+       register char *p;
 {
 {
-       prf("Warning: %s, using standard rlogin", str);
+       long val;
+       int len;
+
+       if ((len = strlen(p)) == 1)     /* use any single char, including '\' */
+               return((u_char)*p);
+                                       /* otherwise, \nnn */
+       if (*p == '\\' && len >= 2 && len <= 4) {
+               val = strtol(++p, (char **)NULL, 8);
+               for (;;) {
+                       if (!*++p)
+                               return((u_char)val);
+                       if (*p < '0' || *p > '8')
+                               break;
+               }
+       }
+       msg("illegal option value -- e");
+       usage();
+       /* NOTREACHED */
 }
 }