add Berkeley specific copyright
[unix-history] / usr / src / libexec / telnetd / telnetd.c
index 3dbdd80..bf80eb2 100644 (file)
@@ -1,18 +1,24 @@
 /*
 /*
- * Copyright (c) 1983,1986 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1983, 1986 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at 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'' without express or implied warranty.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1983, 1986 Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  5.17 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)telnetd.c  5.26 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
  * Telnet server.
 
 /*
  * Telnet server.
@@ -65,9 +71,7 @@ char  *neturg = 0;            /* one past last bye of urgent data */
        /* the remote system seems to NOT be an old 4.2 */
 int    not42 = 1;
 
        /* the remote system seems to NOT be an old 4.2 */
 int    not42 = 1;
 
-
-char BANNER1[] = "\r\n\r\n4.3 BSD UNIX (",
-    BANNER2[] = ")\r\n\r\0\r\n\r\0";
+#define        BANNER  "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r"
 
                /* buffer for sub-options */
 char   subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
 
                /* buffer for sub-options */
 char   subbuffer[100], *subpointer= subbuffer, *subend= subbuffer;
@@ -189,6 +193,10 @@ ttloop()
     ncc = read(net, netibuf, sizeof netibuf);
     if (ncc < 0) {
        syslog(LOG_INFO, "ttloop:  read: %m\n");
     ncc = read(net, netibuf, sizeof netibuf);
     if (ncc < 0) {
        syslog(LOG_INFO, "ttloop:  read: %m\n");
+       exit(1);
+    } else if (ncc == 0) {
+       syslog(LOG_INFO, "ttloop:  peer died: %m\n");
+       exit(1);
     }
     netip = netibuf;
     telrcv();                  /* state machine */
     }
     netip = netibuf;
     telrcv();                  /* state machine */
@@ -213,6 +221,7 @@ getterminaltype()
     settimer(getterminal);
     bcopy(sbuf, nfrontp, sizeof sbuf);
     nfrontp += sizeof sbuf;
     settimer(getterminal);
     bcopy(sbuf, nfrontp, sizeof sbuf);
     nfrontp += sizeof sbuf;
+    hisopts[TELOPT_TTYPE] = OPT_YES_BUT_ALWAYS_LOOK;
     while (sequenceIs(ttypeopt, getterminal)) {
        ttloop();
     }
     while (sequenceIs(ttypeopt, getterminal)) {
        ttloop();
     }
@@ -374,13 +383,26 @@ telnet(f, p)
 {
        int on = 1;
        char hostname[MAXHOSTNAMELEN];
 {
        int on = 1;
        char hostname[MAXHOSTNAMELEN];
+#define        TABBUFSIZ       512
+       char    defent[TABBUFSIZ];
+       char    defstrs[TABBUFSIZ];
+#undef TABBUFSIZ
+       char *HE;
+       char *HN;
+       char *IM;
 
        ioctl(f, FIONBIO, &on);
        ioctl(p, FIONBIO, &on);
 
        ioctl(f, FIONBIO, &on);
        ioctl(p, FIONBIO, &on);
+       ioctl(p, TIOCPKT, &on);
 #if    defined(SO_OOBINLINE)
        setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
 #endif /* defined(SO_OOBINLINE) */
        signal(SIGTSTP, SIG_IGN);
 #if    defined(SO_OOBINLINE)
        setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
 #endif /* defined(SO_OOBINLINE) */
        signal(SIGTSTP, SIG_IGN);
+       /*
+        * Ignoring SIGTTOU keeps the kernel from blocking us
+        * in ttioctl() in /sys/tty.c.
+        */
+       signal(SIGTTOU, SIG_IGN);
        signal(SIGCHLD, cleanup);
        setpgrp(0, 0);
 
        signal(SIGCHLD, cleanup);
        setpgrp(0, 0);
 
@@ -403,25 +425,40 @@ telnet(f, p)
         * WE, the server, sends it; it does NOT mean that the client will
         * echo the terminal input).
         */
         * WE, the server, sends it; it does NOT mean that the client will
         * echo the terminal input).
         */
-       sprintf(nfrontp, doopt, TELOPT_ECHO);
+       (void) sprintf(nfrontp, doopt, TELOPT_ECHO);
        nfrontp += sizeof doopt-2;
        hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
 
        /*
         * Show banner that getty never gave.
         *
        nfrontp += sizeof doopt-2;
        hisopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
 
        /*
         * Show banner that getty never gave.
         *
-        * The banner includes some null's (for TELNET CR disambiguation),
-        * so we have to be somewhat complicated.
+        * We put the banner in the pty input buffer.  This way, it
+        * gets carriage return null processing, etc., just like all
+        * other pty --> client data.
         */
 
        gethostname(hostname, sizeof (hostname));
         */
 
        gethostname(hostname, sizeof (hostname));
+       if (getent(defent, "default") == 1) {
+               char *getstr();
+               char *p=defstrs;
+
+               HE = getstr("he", &p);
+               HN = getstr("hn", &p);
+               IM = getstr("im", &p);
+               if (HN && *HN)
+                       strcpy(hostname, HN);
+               edithost(HE, hostname);
+               if (IM && *IM)
+                       putf(IM, ptyibuf+1, p);
+       } else {
+               sprintf(ptyibuf+1, BANNER, hostname);
+       }
 
 
-       bcopy(BANNER1, nfrontp, sizeof BANNER1 -1);
-       nfrontp += sizeof BANNER1 - 1;
-       bcopy(hostname, nfrontp, strlen(hostname));
-       nfrontp += strlen(hostname);
-       bcopy(BANNER2, nfrontp, sizeof BANNER2 -1);
-       nfrontp += sizeof BANNER2 - 1;
+       ptyip = ptyibuf+1;              /* Prime the pump */
+       pcc = strlen(ptyip);            /* ditto */
+
+       /* Clear ptybuf[0] - where the packet information is received */
+       ptyibuf[0] = 0;
 
        /*
         * Call telrcv() once to pick up anything received during
 
        /*
         * Call telrcv() once to pick up anything received during
@@ -445,6 +482,7 @@ telnet(f, p)
                 */
                if (nfrontp - nbackp || pcc > 0) {
                        FD_SET(f, &obits);
                 */
                if (nfrontp - nbackp || pcc > 0) {
                        FD_SET(f, &obits);
+                       FD_SET(p, &xbits);
                } else {
                        FD_SET(p, &ibits);
                }
                } else {
                        FD_SET(p, &ibits);
                }
@@ -548,6 +586,11 @@ telnet(f, p)
                /*
                 * Something to read from the pty...
                 */
                /*
                 * Something to read from the pty...
                 */
+               if (FD_ISSET(p, &xbits)) {
+                       if (read(p, ptyibuf, 1) != 1) {
+                               break;
+                       }
+               }
                if (FD_ISSET(p, &ibits)) {
                        pcc = read(p, ptyibuf, BUFSIZ);
                        if (pcc < 0 && errno == EWOULDBLOCK)
                if (FD_ISSET(p, &ibits)) {
                        pcc = read(p, ptyibuf, BUFSIZ);
                        if (pcc < 0 && errno == EWOULDBLOCK)
@@ -555,9 +598,18 @@ telnet(f, p)
                        else {
                                if (pcc <= 0)
                                        break;
                        else {
                                if (pcc <= 0)
                                        break;
-                               ptyip = ptyibuf;
+                               /* Skip past "packet" */
+                               pcc--;
+                               ptyip = ptyibuf+1;
                        }
                }
                        }
                }
+               if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+                       netclear();     /* clear buffer back */
+                       *nfrontp++ = IAC;
+                       *nfrontp++ = DM;
+                       neturg = nfrontp-1;  /* off by one XXX */
+                       ptyibuf[0] = 0;
+               }
 
                while (pcc > 0) {
                        if ((&netobuf[BUFSIZ] - nfrontp) < 2)
 
                while (pcc > 0) {
                        if ((&netobuf[BUFSIZ] - nfrontp) < 2)
@@ -566,7 +618,8 @@ telnet(f, p)
                        if (c == IAC)
                                *nfrontp++ = c;
                        *nfrontp++ = c;
                        if (c == IAC)
                                *nfrontp++ = c;
                        *nfrontp++ = c;
-                       if (c == '\r') {
+                       /* Don't do CR-NUL if we are in binary mode */
+                       if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
@@ -610,6 +663,7 @@ telrcv()
 
                case TS_CR:
                        state = TS_DATA;
 
                case TS_CR:
                        state = TS_DATA;
+                       /* Strip off \n or \0 after a \r */
                        if ((c == 0) || (c == '\n')) {
                                break;
                        }
                        if ((c == 0) || (c == '\n')) {
                                break;
                        }
@@ -623,19 +677,18 @@ telrcv()
                        if (inter > 0)
                                break;
                        /*
                        if (inter > 0)
                                break;
                        /*
-                        * We map \r\n ==> \n, since \r\n says
+                        * We now map \r\n ==> \r for pragmatic reasons.
+                        * Many client implementations send \r\n when
+                        * the user hits the CarriageReturn key.
+                        *
+                        * We USED to map \r\n ==> \n, since \r\n says
                         * that we want to be in column 1 of the next
                         * printable line, and \n is the standard
                         * unix way of saying that (\r is only good
                         * if CRMOD is set, which it normally is).
                         */
                         * that we want to be in column 1 of the next
                         * printable line, and \n is the standard
                         * unix way of saying that (\r is only good
                         * if CRMOD is set, which it normally is).
                         */
-                       if ((myopts[TELOPT_BINARY] == OPT_NO) && c == '\r') {
-                               if ((ncc > 0) && ('\n' == *netip)) {
-                                       netip++; ncc--;
-                                       c = '\n';
-                               } else {
-                                       state = TS_CR;
-                               }
+                       if ((c == '\r') && (hisopts[TELOPT_BINARY] == OPT_NO)) {
+                               state = TS_CR;
                        }
                        *pfrontp++ = c;
                        break;
                        }
                        *pfrontp++ = c;
                        break;
@@ -846,7 +899,7 @@ willoption(option)
        } else {
                hisopts[option] = OPT_NO;
        }
        } else {
                hisopts[option] = OPT_NO;
        }
-       sprintf(nfrontp, fmt, option);
+       (void) sprintf(nfrontp, fmt, option);
        nfrontp += sizeof (dont) - 2;
 }
 
        nfrontp += sizeof (dont) - 2;
 }
 
@@ -863,10 +916,15 @@ wontoption(option)
        case TELOPT_BINARY:
                mode(0, RAW);
                break;
        case TELOPT_BINARY:
                mode(0, RAW);
                break;
+
+       case TELOPT_TTYPE:
+           settimer(ttypeopt);
+           break;
        }
        }
+
        fmt = dont;
        hisopts[option] = OPT_NO;
        fmt = dont;
        hisopts[option] = OPT_NO;
-       sprintf(nfrontp, fmt, option);
+       (void) sprintf(nfrontp, fmt, option);
        nfrontp += sizeof (doopt) - 2;
 }
 
        nfrontp += sizeof (doopt) - 2;
 }
 
@@ -904,7 +962,7 @@ dooption(option)
        } else {
            myopts[option] = OPT_NO;
        }
        } else {
            myopts[option] = OPT_NO;
        }
-       sprintf(nfrontp, fmt, option);
+       (void) sprintf(nfrontp, fmt, option);
        nfrontp += sizeof (doopt) - 2;
 }
 
        nfrontp += sizeof (doopt) - 2;
 }
 
@@ -916,13 +974,8 @@ int option;
 
     switch (option) {
     case TELOPT_ECHO:          /* we should stop echoing */
 
     switch (option) {
     case TELOPT_ECHO:          /* we should stop echoing */
-       mode(0, ECHO|CRMOD);
-       fmt = wont;
-       break;
-
-    case TELOPT_TTYPE:
+       mode(0, ECHO);
        fmt = wont;
        fmt = wont;
-       settimer(ttypeopt);
        break;
 
     default:
        break;
 
     default:
@@ -935,7 +988,7 @@ int option;
     } else {
        myopts[option] = OPT_YES;
     }
     } else {
        myopts[option] = OPT_YES;
     }
-    sprintf(nfrontp, fmt, option);
+    (void) sprintf(nfrontp, fmt, option);
     nfrontp += sizeof (wont) - 2;
 }
 
     nfrontp += sizeof (wont) - 2;
 }
 
@@ -1264,3 +1317,102 @@ rmut()
        chmod(line, 0666);
        chown(line, 0, 0);
 }
        chmod(line, 0666);
        chown(line, 0, 0);
 }
+
+char   editedhost[32];
+
+edithost(pat, host)
+       register char *pat;
+       register char *host;
+{
+       register char *res = editedhost;
+
+       if (!pat)
+               pat = "";
+       while (*pat) {
+               switch (*pat) {
+
+               case '#':
+                       if (*host)
+                               host++;
+                       break;
+
+               case '@':
+                       if (*host)
+                               *res++ = *host++;
+                       break;
+
+               default:
+                       *res++ = *pat;
+                       break;
+
+               }
+               if (res == &editedhost[sizeof editedhost - 1]) {
+                       *res = '\0';
+                       return;
+               }
+               pat++;
+       }
+       if (*host)
+               strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
+       else
+               *res = '\0';
+       editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static char *putlocation;
+
+puts(s)
+register char *s;
+{
+
+       while (*s)
+               putchr(*s++);
+}
+
+putchr(cc)
+{
+       *putlocation++ = cc;
+}
+
+putf(cp, where, tty)
+register char *cp;
+char *where;
+int tty;
+{
+       char *slash;
+       char datebuffer[60];
+       extern char *rindex();
+
+       putlocation = where;
+
+       while (*cp) {
+               if (*cp != '%') {
+                       putchr(*cp++);
+                       continue;
+               }
+               switch (*++cp) {
+
+               case 't':
+                       slash = rindex(line, '/');
+                       if (slash == (char *) 0)
+                               puts(line);
+                       else
+                               puts(&slash[1]);
+                       break;
+
+               case 'h':
+                       puts(editedhost);
+                       break;
+
+               case 'd':
+                       get_date(datebuffer);
+                       puts(datebuffer);
+                       break;
+
+               case '%':
+                       putchr('%');
+                       break;
+               }
+               cp++;
+       }
+}