narrow possible window for losing window size change
[unix-history] / usr / src / usr.bin / rlogin / rlogin.c
index a1a31bb..db58360 100644 (file)
@@ -1,4 +1,4 @@
-/*-
+/*
  * Copyright (c) 1983, 1990 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1983, 1990 The Regents of the University of California.
  * All rights reserved.
  *
@@ -12,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)rlogin.c   5.28 (Berkeley) %G%";
+static char sccsid[] = "@(#)rlogin.c   5.37 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -33,12 +33,14 @@ static char sccsid[] = "@(#)rlogin.c        5.28 (Berkeley) %G%";
 #include <sys/wait.h>
 
 #include <netinet/in.h>
 #include <sys/wait.h>
 
 #include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
 #include <netdb.h>
 
 #include <sgtty.h>
 #include <setjmp.h>
 #include <netdb.h>
 
 #include <sgtty.h>
 #include <setjmp.h>
-#include <errno.h>
 #include <varargs.h>
 #include <varargs.h>
+#include <errno.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -50,7 +52,7 @@ static char sccsid[] = "@(#)rlogin.c  5.28 (Berkeley) %G%";
 
 CREDENTIALS cred;
 Key_schedule schedule;
 
 CREDENTIALS cred;
 Key_schedule schedule;
-int use_kerberos = 1, encrypt;
+int use_kerberos = 1, doencrypt;
 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
 extern char *krb_realmofhost();
 #endif
 char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
 extern char *krb_realmofhost();
 #endif
@@ -64,9 +66,11 @@ extern char *krb_realmofhost();
 #define        SIGUSR1 30
 #endif
 
 #define        SIGUSR1 30
 #endif
 
-extern int errno;
 int eight, litout, rem;
 int eight, litout, rem;
-char cmdchar;
+
+int noescape;
+u_char escapechar = '~';
+
 char *speeds[] = {
        "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
        "1800", "2400", "4800", "9600", "19200", "38400"
 char *speeds[] = {
        "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
        "1800", "2400", "4800", "9600", "19200", "38400"
@@ -94,17 +98,18 @@ main(argc, argv)
        extern int optind;
        struct passwd *pw;
        struct servent *sp;
        extern int optind;
        struct passwd *pw;
        struct servent *sp;
+       struct hostent *hp;
        struct sgttyb ttyb;
        long omask;
        int argoff, ch, dflag, one, uid;
        char *host, *p, *user, term[1024];
        struct sgttyb ttyb;
        long omask;
        int argoff, ch, dflag, one, uid;
        char *host, *p, *user, term[1024];
-       void lostpeer();
+       void lostpeer(), copytochild(), writeroob();
+       u_char getescape();
        char *getenv();
 
        argoff = dflag = 0;
        one = 1;
        host = user = NULL;
        char *getenv();
 
        argoff = dflag = 0;
        one = 1;
        host = user = NULL;
-       cmdchar = '~';
 
        if (p = rindex(argv[0], '/'))
                ++p;
 
        if (p = rindex(argv[0], '/'))
                ++p;
@@ -121,15 +126,18 @@ main(argc, argv)
        }
 
 #ifdef KERBEROS
        }
 
 #ifdef KERBEROS
-#define        OPTIONS "8KLde:k:l:x"
+#define        OPTIONS "8EKLde:k:l:x"
 #else
 #else
-#define        OPTIONS "8KLde:l:"
+#define        OPTIONS "8EKLde:l:"
 #endif
        while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
                switch(ch) {
                case '8':
                        eight = 1;
                        break;
 #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;
                case 'K':
 #ifdef KERBEROS
                        use_kerberos = 0;
@@ -142,7 +150,8 @@ main(argc, argv)
                        dflag = 1;
                        break;
                case 'e':
                        dflag = 1;
                        break;
                case 'e':
-                       cmdchar = optarg[0];
+                       noescape = 0;
+                       escapechar = getescape(optarg);
                        break;
 #ifdef KERBEROS
                case 'k':
                        break;
 #ifdef KERBEROS
                case 'k':
@@ -153,12 +162,6 @@ main(argc, argv)
                case 'l':
                        user = optarg;
                        break;
                case 'l':
                        user = optarg;
                        break;
-#ifdef KERBEROS
-               case 'x':
-                       encrypt = 1;
-                       des_set_key(cred.session, schedule);
-                       break;
-#endif
                case '?':
                default:
                        usage();
                case '?':
                default:
                        usage();
@@ -184,11 +187,11 @@ main(argc, argv)
        sp = NULL;
 #ifdef KERBEROS
        if (use_kerberos) {
        sp = NULL;
 #ifdef KERBEROS
        if (use_kerberos) {
-               sp = getservbyname((encrypt ? "eklogin" : "klogin"), "tcp");
+               sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
                if (sp == NULL) {
                        use_kerberos = 0;
                        warning("can't get entry for %s/tcp service",
                if (sp == NULL) {
                        use_kerberos = 0;
                        warning("can't get entry for %s/tcp service",
-                           encrypt ? "eklogin" : "klogin");
+                           doencrypt ? "eklogin" : "klogin");
                }
        }
 #endif
                }
        }
 #endif
@@ -210,19 +213,30 @@ main(argc, argv)
        (void)signal(SIGPIPE, lostpeer);
        /* will use SIGUSR1 for window size hack, so hold it off */
        omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
        (void)signal(SIGPIPE, lostpeer);
        /* will use SIGUSR1 for window size hack, so hold it off */
        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
 try_connect:
        if (use_kerberos) {
 
 #ifdef KERBEROS
 try_connect:
        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);
+               }
+
                rem = KSUCCESS;
                errno = 0;
                if (dest_realm == NULL)
                        dest_realm = krb_realmofhost(host);
 
                rem = KSUCCESS;
                errno = 0;
                if (dest_realm == NULL)
                        dest_realm = krb_realmofhost(host);
 
-               if (encrypt)
-                       rem = krcmd_mutual(&host, sp->s_port, user, term, 0,
-                           dest_realm, &cred, schedule);
-               else
                        rem = krcmd(&host, sp->s_port, user, term, 0,
                            dest_realm);
                if (rem < 0) {
                        rem = krcmd(&host, sp->s_port, user, term, 0,
                            dest_realm);
                if (rem < 0) {
@@ -240,16 +254,11 @@ try_connect:
                        goto try_connect;
                }
        } else {
                        goto try_connect;
                }
        } else {
-               if (encrypt) {
-                       (void)fprintf(stderr,
-                           "rlogin: the -x flag requires Kerberos authentication.\n");
-                       exit(1);
-               }
                rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
        }
 #else
        rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
                rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
        }
 #else
        rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
-#endif
+#endif /* KERBEROS */
 
        if (rem < 0)
                exit(1);
 
        if (rem < 0)
                exit(1);
@@ -258,6 +267,9 @@ try_connect:
            setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
                (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
                    strerror(errno));
            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);
 
        (void)setuid(uid);
        doit(omask);
@@ -275,7 +287,7 @@ doit(omask)
        long omask;
 {
        struct sgttyb sb;
        long omask;
 {
        struct sgttyb sb;
-       void catch_child(), copytochild(), exit(), writeroob();
+       void catch_child(), exit();
 
        (void)ioctl(0, TIOCGETP, (char *)&sb);
        defflags = sb.sg_flags;
 
        (void)ioctl(0, TIOCGETP, (char *)&sb);
        defflags = sb.sg_flags;
@@ -309,11 +321,11 @@ doit(omask)
 
        /*
         * We may still own the socket, and may have a pending SIGURG (or might
 
        /*
         * 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.
+        * 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(omask);
        (void)signal(SIGCHLD, catch_child);
        writer();
        (void)sigsetmask(omask);
        (void)signal(SIGCHLD, catch_child);
        writer();
@@ -336,19 +348,20 @@ setsignal(sig, act)
 done(status)
        int status;
 {
 done(status)
        int status;
 {
-       int w;
+       int w, wstatus;
 
        mode(0);
        if (child > 0) {
                /* make sure catch_child does not snap it up */
                (void)signal(SIGCHLD, SIG_DFL);
                if (kill(child, SIGKILL) >= 0)
 
        mode(0);
        if (child > 0) {
                /* make sure catch_child does not snap it up */
                (void)signal(SIGCHLD, SIG_DFL);
                if (kill(child, SIGKILL) >= 0)
-                       while ((w = wait((union wait *)0)) > 0 && w != child);
+                       while ((w = wait(&wstatus)) > 0 && w != child);
        }
        exit(status);
 }
 
 int dosigwinch;
        }
        exit(status);
 }
 
 int dosigwinch;
+void sigwinch();
 
 /*
  * This is called when the reader process gets the out-of-band (urgent)
 
 /*
  * This is called when the reader process gets the out-of-band (urgent)
@@ -357,8 +370,6 @@ int dosigwinch;
 void
 writeroob()
 {
 void
 writeroob()
 {
-       void sigwinch();
-
        if (dosigwinch == 0) {
                sendwindow();
                (void)signal(SIGWINCH, sigwinch);
        if (dosigwinch == 0) {
                sendwindow();
                (void)signal(SIGWINCH, sigwinch);
@@ -373,7 +384,7 @@ catch_child()
        int pid;
 
        for (;;) {
        int pid;
 
        for (;;) {
-               pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
+               pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
                if (pid == 0)
                        return;
                /* if the child (reader) dies, just quit */
                if (pid == 0)
                        return;
                /* if the child (reader) dies, just quit */
@@ -385,14 +396,14 @@ catch_child()
 
 /*
  * 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()
 {
-       char c;
        register int bol, local, n;
        register int bol, local, n;
+       char c;
 
        bol = 1;                        /* beginning of line */
        local = 0;
 
        bol = 1;                        /* beginning of line */
        local = 0;
@@ -412,8 +423,7 @@ writer()
                 */
                if (bol) {
                        bol = 0;
                 */
                if (bol) {
                        bol = 0;
-                       if (c == cmdchar) {
-                               bol = 0;
+                       if (!noescape && c == escapechar) {
                                local = 1;
                                continue;
                        }
                                local = 1;
                                continue;
                        }
@@ -429,24 +439,10 @@ 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) {
-                               msg("line gone");
-                               break;
-                       }
-               } else
-#endif
                        if (write(rem, &c, 1) == 0) {
                                msg("line gone");
                                break;
                        if (write(rem, &c, 1) == 0) {
                                msg("line gone");
                                break;
@@ -465,7 +461,7 @@ register char c;
 
        p = buf;
        c &= 0177;
 
        p = buf;
        c &= 0177;
-       *p++ = cmdchar;
+       *p++ = escapechar;
        if (c < ' ') {
                *p++ = '^';
                *p++ = c + '@';
        if (c < ' ') {
                *p++ = '^';
                *p++ = c + '@';
@@ -476,7 +472,7 @@ 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)
 }
 
 stop(cmdc)
@@ -520,11 +516,6 @@ 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));
 }
 
@@ -650,7 +641,7 @@ reader(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)
                                        return(-1);
                        if (n < 0) {
                                if (errno != EINTR)
                                        return(-1);
@@ -662,11 +653,6 @@ reader(omask)
                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);
                        rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
                if (rcvcnt == 0)
                        return (0);
@@ -763,9 +749,9 @@ usage()
        (void)fprintf(stderr,
            "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
 #ifdef KERBEROS
        (void)fprintf(stderr,
            "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
 #ifdef KERBEROS
-           "8Lx", " [-k realm] ");
+           "8EKL", " [-k realm] ");
 #else
 #else
-           "8L", " ");
+           "8EL", " ");
 #endif
        exit(1);
 }
 #endif
        exit(1);
 }
@@ -775,7 +761,6 @@ usage()
  * Suns and others.  Suns have only a `ttysize', so we convert it to a winsize.
  */
 #ifdef sun
  * 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;
 get_window_size(fd, wp)
        int fd;
        struct winsize *wp;
@@ -792,3 +777,27 @@ get_window_size(fd, wp)
        return(0);
 }
 #endif
        return(0);
 }
 #endif
+
+u_char
+getescape(p)
+       register char *p;
+{
+       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 */
+}