Add copyright
[unix-history] / usr / src / libexec / telnetd / telnetd.c
index b52d35d..e8928a7 100644 (file)
@@ -1,23 +1,41 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  4.8 82/10/07";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)telnetd.c  5.1 (Berkeley) %G%";
+#endif not lint
 
 /*
  * Stripped-down telnet server.
  */
 
 /*
  * Stripped-down telnet server.
  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <arpa/telnet.h>
+
 #include <stdio.h>
 #include <signal.h>
 #include <errno.h>
 #include <sgtty.h>
 #include <stdio.h>
 #include <signal.h>
 #include <errno.h>
 #include <sgtty.h>
-#include <wait.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <net/in.h>
 #include <netdb.h>
 #include <netdb.h>
-#include "telnet.h"
+#include <syslog.h>
 
 
-#define        INFINITY        10000000
-#define        BELL            '\07'
+#define        BELL    '\07'
+#define BANNER "\r\n\r\n4.2 BSD UNIX (%s)\r\n\r\r\n\r%s"
 
 char   hisopts[256];
 char   myopts[256];
 
 char   hisopts[256];
 char   myopts[256];
@@ -38,105 +56,87 @@ int        pcc, ncc;
 
 int    pty, net;
 int    inter;
 
 int    pty, net;
 int    inter;
+extern char **environ;
 extern int errno;
 extern int errno;
-char   line[] = "/dev/ptyp0";
-
-struct sockaddr_in sin = { AF_INET };
-int    options = SO_ACCEPTCONN|SO_KEEPALIVE;
+char   *line;
 
 main(argc, argv)
        char *argv[];
 {
 
 main(argc, argv)
        char *argv[];
 {
-       int s, pid;
-       union wait status;
-       struct servent *sp;
-
-       sp = getservbyname("telnet", "tcp");
-       if (sp == 0) {
-               fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
-               exit(1);
-       }
-       sin.sin_port = sp->s_port;
-       argc--, argv++;
-       if (argc > 0 && !strcmp(argv[0], "-d"))
-               options |= SO_DEBUG, argc--, argv++;
-       if (argc > 0) {
-               sin.sin_port = atoi(*argv);
-               if (sin.sin_port <= 0) {
-                       fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
-                       exit(1);
-               }
+       struct sockaddr_in from;
+       int on = 1, fromlen;
+
+       fromlen = sizeof (from);
+       if (getpeername(0, &from, &fromlen) < 0) {
+               fprintf(stderr, "%s: ", argv[0]);
+               perror("getpeername");
+               _exit(1);
        }
        }
-       sin.sin_port = htons(sin.sin_port);
-       for (;;) {
-               errno = 0;
-               if ((s = socket(SOCK_STREAM, 0, &sin, options)) < 0) {
-                       perror("socket");
-                       sleep(5);
-                       continue;
-               }
-               if (accept(s, 0) < 0) {
-                       perror("accept");
-                       close(s);
-                       sleep(1);
-                       continue;
-               }
-               if ((pid = fork()) < 0)
-                       printf("Out of processes\n");
-               else if (pid == 0)
-                       doit(s);
-               close(s);
-               while (wait3(status, WNOHANG, 0) > 0)
-                       continue;
+       if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
+               openlog(argv[0], LOG_PID, 0);
+               syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
        }
-       /*NOTREACHED*/
+       doit(0, &from);
 }
 
 }
 
+char   *envinit[] = { "TERM=network", 0 };
 int    cleanup();
 
 /*
  * Get a pty, scan input lines.
  */
 int    cleanup();
 
 /*
  * Get a pty, scan input lines.
  */
-doit(f)
+doit(f, who)
+       int f;
+       struct sockaddr_in *who;
 {
 {
-       char *cp = line;
-       int i, p, cc, t;
+       char *host, *inet_ntoa();
+       int i, p, t;
        struct sgttyb b;
        struct sgttyb b;
+       struct hostent *hp;
+       char c;
 
 
-       for (i = 0; i < 16; i++) {
-               cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
-               p = open(cp, 2);
-               if (p > 0)
-                       goto gotpty;
+       for (c = 'p'; c <= 's'; c++) {
+               struct stat stb;
+
+               line = "/dev/ptyXX";
+               line[strlen("/dev/pty")] = c;
+               line[strlen("/dev/ptyp")] = '0';
+               if (stat(line, &stb) < 0)
+                       break;
+               for (i = 0; i < 16; i++) {
+                       line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
+                       p = open(line, 2);
+                       if (p > 0)
+                               goto gotpty;
+               }
        }
        }
-       dup2(f, 1);
-       printf("All network ports in use.\n");
-       exit(1);
+       fatal(f, "All network ports in use");
+       /*NOTREACHED*/
 gotpty:
        dup2(f, 0);
 gotpty:
        dup2(f, 0);
-       cp[strlen("/dev/")] = 't';
-       t = open("/dev/tty", 2);
+       line[strlen("/dev/")] = 't';
+       t = open("/dev/tty", O_RDWR);
        if (t >= 0) {
                ioctl(t, TIOCNOTTY, 0);
                close(t);
        }
        if (t >= 0) {
                ioctl(t, TIOCNOTTY, 0);
                close(t);
        }
-       t = open(cp, 2);
-       if (t < 0) {
-               dup2(f, 2);
-               perror(cp);
-               exit(1);
-       }
+       t = open(line, O_RDWR);
+       if (t < 0)
+               fatalperror(f, line, errno);
        ioctl(t, TIOCGETP, &b);
        b.sg_flags = CRMOD|XTABS|ANYP;
        ioctl(t, TIOCSETP, &b);
        ioctl(p, TIOCGETP, &b);
        b.sg_flags &= ~ECHO;
        ioctl(p, TIOCSETP, &b);
        ioctl(t, TIOCGETP, &b);
        b.sg_flags = CRMOD|XTABS|ANYP;
        ioctl(t, TIOCSETP, &b);
        ioctl(p, TIOCGETP, &b);
        b.sg_flags &= ~ECHO;
        ioctl(p, TIOCSETP, &b);
-       if ((i = fork()) < 0) {
-               dup2(f, 2);
-               perror("fork");
-               exit(1);
-       }
+       hp = gethostbyaddr(&who->sin_addr, sizeof (struct in_addr),
+               who->sin_family);
+       if (hp)
+               host = hp->h_name;
+       else
+               host = inet_ntoa(who->sin_addr);
+       if ((i = fork()) < 0)
+               fatalperror(f, "fork", errno);
        if (i)
                telnet(f, p);
        close(f);
        if (i)
                telnet(f, p);
        close(f);
@@ -145,11 +145,35 @@ gotpty:
        dup2(t, 1);
        dup2(t, 2);
        close(t);
        dup2(t, 1);
        dup2(t, 2);
        close(t);
-       execl("/bin/login", "telnet-login", 0);
-       perror("/bin/login");
+       environ = envinit;
+       execl("/bin/login", "login", "-h", host, 0);
+       fatalperror(f, "/bin/login", errno);
+       /*NOTREACHED*/
+}
+
+fatal(f, msg)
+       int f;
+       char *msg;
+{
+       char buf[BUFSIZ];
+
+       (void) sprintf(buf, "telnetd: %s.\r\n", msg);
+       (void) write(f, buf, strlen(buf));
        exit(1);
 }
 
        exit(1);
 }
 
+fatalperror(f, msg, errno)
+       int f;
+       char *msg;
+       int errno;
+{
+       char buf[BUFSIZ];
+       extern char *sys_errlist[];
+
+       (void) sprintf(buf, "%s: %s\r\n", msg, sys_errlist[errno]);
+       fatal(f, buf);
+}
+
 /*
  * Main loop.  Select from pty and network, and
  * hand data to telnet receiver finite state machine.
 /*
  * Main loop.  Select from pty and network, and
  * hand data to telnet receiver finite state machine.
@@ -157,18 +181,25 @@ gotpty:
 telnet(f, p)
 {
        int on = 1;
 telnet(f, p)
 {
        int on = 1;
+       char hostname[32];
 
        net = f, pty = p;
        ioctl(f, FIONBIO, &on);
        ioctl(p, FIONBIO, &on);
        signal(SIGTSTP, SIG_IGN);
 
        net = f, pty = p;
        ioctl(f, FIONBIO, &on);
        ioctl(p, FIONBIO, &on);
        signal(SIGTSTP, SIG_IGN);
-       sigset(SIGCHLD, cleanup);
+       signal(SIGCHLD, cleanup);
 
        /*
         * Request to do remote echo.
         */
        dooption(TELOPT_ECHO);
        myopts[TELOPT_ECHO] = 1;
 
        /*
         * Request to do remote echo.
         */
        dooption(TELOPT_ECHO);
        myopts[TELOPT_ECHO] = 1;
+       /*
+        * Show banner that getty never gave.
+        */
+       gethostname(hostname, sizeof (hostname));
+       sprintf(nfrontp, BANNER, hostname, "");
+       nfrontp += strlen(nfrontp);
        for (;;) {
                int ibits = 0, obits = 0;
                register int c;
        for (;;) {
                int ibits = 0, obits = 0;
                register int c;
@@ -177,17 +208,17 @@ telnet(f, p)
                 * Never look for input if there's still
                 * stuff in the corresponding output buffer
                 */
                 * Never look for input if there's still
                 * stuff in the corresponding output buffer
                 */
-               if (nfrontp - nbackp)
+               if (nfrontp - nbackp || pcc > 0)
                        obits |= (1 << f);
                else
                        ibits |= (1 << p);
                        obits |= (1 << f);
                else
                        ibits |= (1 << p);
-               if (pfrontp - pbackp)
+               if (pfrontp - pbackp || ncc > 0)
                        obits |= (1 << p);
                else
                        ibits |= (1 << f);
                if (ncc < 0 && pcc < 0)
                        break;
                        obits |= (1 << p);
                else
                        ibits |= (1 << f);
                if (ncc < 0 && pcc < 0)
                        break;
-               select(32, &ibits, &obits, INFINITY);
+               select(16, &ibits, &obits, 0, 0);
                if (ibits == 0 && obits == 0) {
                        sleep(5);
                        continue;
                if (ibits == 0 && obits == 0) {
                        sleep(5);
                        continue;
@@ -299,7 +330,8 @@ telrcv()
                         * Are You There?
                         */
                        case AYT:
                         * Are You There?
                         */
                        case AYT:
-                               *pfrontp++ = BELL;
+                               strcpy(nfrontp, "\r\n[Yes]\r\n");
+                               nfrontp += 9;
                                break;
 
                        /*
                                break;
 
                        /*
@@ -378,7 +410,7 @@ telrcv()
                        continue;
 
                default:
                        continue;
 
                default:
-                       printf("netser: panic state=%d\n", state);
+                       printf("telnetd: panic state=%d\n", state);
                        exit(1);
                }
        }
                        exit(1);
                }
        }
@@ -541,11 +573,10 @@ netflush()
 
 cleanup()
 {
 
 cleanup()
 {
-       int how = 2;
 
        rmut();
 
        rmut();
-       vhangup();
-       ioctl(net, SIOCDONE, &how);
+       vhangup();      /* XXX */
+       shutdown(net, 2);
        kill(0, SIGKILL);
        exit(1);
 }
        kill(0, SIGKILL);
        exit(1);
 }
@@ -563,13 +594,14 @@ rmut()
        register f;
        int found = 0;
 
        register f;
        int found = 0;
 
-       f = open(utmp, 2);
+       f = open(utmp, O_RDWR);
        if (f >= 0) {
                while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
                        if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
                                continue;
        if (f >= 0) {
                while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
                        if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
                                continue;
-                       lseek(f, -(long)sizeof (wtmp), 1);
+                       lseek(f, -(long)sizeof (wtmp), L_INCR);
                        SCPYN(wtmp.ut_name, "");
                        SCPYN(wtmp.ut_name, "");
+                       SCPYN(wtmp.ut_host, "");
                        time(&wtmp.ut_time);
                        write(f, (char *)&wtmp, sizeof (wtmp));
                        found++;
                        time(&wtmp.ut_time);
                        write(f, (char *)&wtmp, sizeof (wtmp));
                        found++;
@@ -577,12 +609,12 @@ rmut()
                close(f);
        }
        if (found) {
                close(f);
        }
        if (found) {
-               f = open(wtmpf, 1);
+               f = open(wtmpf, O_WRONLY|O_APPEND);
                if (f >= 0) {
                        SCPYN(wtmp.ut_line, line+5);
                        SCPYN(wtmp.ut_name, "");
                if (f >= 0) {
                        SCPYN(wtmp.ut_line, line+5);
                        SCPYN(wtmp.ut_name, "");
+                       SCPYN(wtmp.ut_host, "");
                        time(&wtmp.ut_time);
                        time(&wtmp.ut_time);
-                       lseek(f, (long)0, 2);
                        write(f, (char *)&wtmp, sizeof (wtmp));
                        close(f);
                }
                        write(f, (char *)&wtmp, sizeof (wtmp));
                        close(f);
                }