don't accept connections from ports below 512
[unix-history] / usr / src / libexec / rlogind / rlogind.c
index 0a82fff..eec0cb3 100644 (file)
+/*
+ * 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[] = "@(#)rlogind.c  4.9 83/01/18";
-#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[] = "@(#)rlogind.c  5.13 (Berkeley) %G%";
+#endif not lint
+
+/*
+ * remote login server:
+ *     remuser\0
+ *     locuser\0
+ *     terminal info\0
+ *     data
+ */
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/file.h>
 
 #include <netinet/in.h>
 
 #include <errno.h>
 #include <pwd.h>
 
 #include <netinet/in.h>
 
 #include <errno.h>
 #include <pwd.h>
-#include <wait.h>
 #include <signal.h>
 #include <sgtty.h>
 #include <stdio.h>
 #include <netdb.h>
 #include <signal.h>
 #include <sgtty.h>
 #include <stdio.h>
 #include <netdb.h>
+#include <syslog.h>
+#include <strings.h>
+
+# ifndef TIOCPKT_WINDOW
+# define TIOCPKT_WINDOW 0x80
+# endif TIOCPKT_WINDOW
 
 extern errno;
 int    reapchild();
 struct passwd *getpwnam();
 
 extern errno;
 int    reapchild();
 struct passwd *getpwnam();
-char   *crypt(), *rindex(), *index(), *malloc();
-struct sockaddr_in sin = { AF_INET };
-/*
- * remote login server:
- *     remuser\0
- *     locuser\0
- *     terminal type\0
- *     data
- */
+char   *malloc();
+
 main(argc, argv)
        int argc;
        char **argv;
 {
 main(argc, argv)
        int argc;
        char **argv;
 {
-       int f, options = SO_KEEPALIVE;
+       int on = 1, options = 0, fromlen;
        struct sockaddr_in from;
        struct sockaddr_in from;
-       struct servent *sp;
 
 
-       sp = getservbyname("login", "tcp");
-       if (sp == 0) {
-               fprintf(stderr, "rlogind: tcp/rlogin: unknown service\n");
-               exit(1);
+       openlog("rlogind", LOG_PID | LOG_AUTH, LOG_AUTH);
+       fromlen = sizeof (from);
+       if (getpeername(0, &from, &fromlen) < 0) {
+               fprintf(stderr, "%s: ", argv[0]);
+               perror("getpeername");
+               _exit(1);
        }
        }
-#ifndef DEBUG
-       if (fork())
-               exit(0);
-       for (f = 0; f < 10; f++)
-               (void) close(f);
-       (void) open("/", 0);
-       (void) dup2(0, 1);
-       (void) dup2(0, 2);
-       { int tt = open("/dev/tty", 2);
-         if (tt > 0) {
-               ioctl(tt, TIOCNOTTY, 0);
-               close(tt);
-         }
-       }
-#endif
-       sin.sin_port = sp->s_port;
-       argc--, argv++;
-       if (argc > 0 && !strcmp(argv[0], "-d")) {
-               options |= SO_DEBUG;
-               argc--, argv++;
+       if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
+               syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
        }
-       if (argc > 0) {
-               int port = atoi(argv[0]);
-
-               if (port < 0) {
-                       fprintf(stderr, "%s: bad port #\n", argv[0]);
-                       exit(1);
-               }
-               sin.sin_port = htons((u_short)port);
-               argv++, argc--;
-       }
-       f = socket(AF_INET, SOCK_STREAM, 0, 0);
-       if (f < 0) {
-               perror("rlogind: socket");
-               exit(1);
-       }
-       if (options & SO_DEBUG)
-               if (setsockopt(f, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
-                       perror("rlogind: setsockopt (SO_DEBUG)");
-#ifdef notdef
-       if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0)
-               perror("rlogind: setsocktopt (SO_KEEPALIVE)");
-#endif
-       if (bind(f, &sin, sizeof (sin), 0) < 0) {
-               perror("rlogind: bind");
-               exit(1);
-       }
-       signal(SIGCHLD, reapchild);
-       listen(f, 10);
-       for (;;) {
-               int s, len = sizeof (from);
-
-               s = accept(f, &from, &len, 0);
-               if (s < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       perror("rlogind: accept");
-                       continue;
-               }
-               if (fork() == 0)
-                       doit(s, &from);
-               close(s);
-       }
-}
-
-reapchild()
-{
-       union wait status;
-
-       while (wait3(&status, WNOHANG, 0) > 0)
-               ;
+       doit(0, &from);
 }
 
 }
 
-char   locuser[32], remuser[32];
-char   buf[BUFSIZ];
 int    child;
 int    cleanup();
 int    netf;
 extern errno;
 char   *line;
 int    child;
 int    cleanup();
 int    netf;
 extern errno;
 char   *line;
+extern char    *inet_ntoa();
+
+struct winsize win = { 0, 0, 0, 0 };
+
 
 doit(f, fromp)
        int f;
        struct sockaddr_in *fromp;
 {
 
 doit(f, fromp)
        int f;
        struct sockaddr_in *fromp;
 {
-       char c;
-       int i, p, cc, t, pid;
-       int stop = TIOCPKT_DOSTOP;
+       int i, p, t, pid, on = 1;
        register struct hostent *hp;
        register struct hostent *hp;
+       struct hostent hostent;
+       char c;
 
        alarm(60);
        read(f, &c, 1);
        if (c != 0)
                exit(1);
        alarm(0);
 
        alarm(60);
        read(f, &c, 1);
        if (c != 0)
                exit(1);
        alarm(0);
-       fromp->sin_port = htons((u_short)fromp->sin_port);
+       fromp->sin_port = ntohs((u_short)fromp->sin_port);
        hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
                fromp->sin_family);
        hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
                fromp->sin_family);
-       if (hp == 0)
-               fatal(f, "Host name for your address unknown");
+       if (hp == 0) {
+               /*
+                * Only the name is used below.
+                */
+               hp = &hostent;
+               hp->h_name = inet_ntoa(fromp->sin_addr);
+       }
        if (fromp->sin_family != AF_INET ||
            fromp->sin_port >= IPPORT_RESERVED ||
        if (fromp->sin_family != AF_INET ||
            fromp->sin_port >= IPPORT_RESERVED ||
-           hp == 0)
+           fromp->sin_port < IPPORT_RESERVED/2)
                fatal(f, "Permission denied");
        write(f, "", 1);
        for (c = 'p'; c <= 's'; c++) {
                fatal(f, "Permission denied");
        write(f, "", 1);
        for (c = 'p'; c <= 's'; c++) {
@@ -161,10 +122,11 @@ doit(f, fromp)
                                goto gotpty;
                }
        }
                                goto gotpty;
                }
        }
-       fatal(f, "All network ports in use");
+       fatal(f, "Out of ptys");
        /*NOTREACHED*/
 gotpty:
        /*NOTREACHED*/
 gotpty:
-       dup2(f, 0);
+       (void) ioctl(p, TIOCSWINSZ, &win);
+       netf = f;
        line[strlen("/dev/")] = 't';
 #ifdef DEBUG
        { int tt = open("/dev/tty", 2);
        line[strlen("/dev/")] = 't';
 #ifdef DEBUG
        { int tt = open("/dev/tty", 2);
@@ -183,103 +145,175 @@ gotpty:
        pid = fork();
        if (pid < 0)
                fatalperror(f, "", errno);
        pid = fork();
        if (pid < 0)
                fatalperror(f, "", errno);
-       if (pid) {
-               char pibuf[1024], fibuf[1024], *pbp, *fbp;
-               int pcc = 0, fcc = 0, on = 1;
-/* FILE *console = fopen("/dev/console", "w");  */
-/* setbuf(console, 0); */
-
-/* fprintf(console, "f %d p %d\r\n", f, p); */
-               ioctl(f, FIONBIO, &on);
-               ioctl(p, FIONBIO, &on);
-               ioctl(p, TIOCPKT, &on);
-               signal(SIGTSTP, SIG_IGN);
-               sigset(SIGCHLD, cleanup);
-               for (;;) {
-                       int ibits = 0, obits = 0;
-
-                       if (fcc)
-                               obits |= (1<<p);
+       if (pid == 0) {
+               close(f), close(p);
+               dup2(t, 0), dup2(t, 1), dup2(t, 2);
+               close(t);
+               execl("/bin/login", "login", "-r", hp->h_name, 0);
+               fatalperror(2, "/bin/login", errno);
+               /*NOTREACHED*/
+       }
+       close(t);
+       ioctl(f, FIONBIO, &on);
+       ioctl(p, FIONBIO, &on);
+       ioctl(p, TIOCPKT, &on);
+       signal(SIGTSTP, SIG_IGN);
+       signal(SIGCHLD, cleanup);
+       setpgrp(0, 0);
+       protocol(f, p);
+       signal(SIGCHLD, SIG_IGN);
+       cleanup();
+}
+
+char   magic[2] = { 0377, 0377 };
+char   oobdata[] = {TIOCPKT_WINDOW};
+
+/*
+ * Handle a "control" request (signaled by magic being present)
+ * in the data stream.  For now, we are only willing to handle
+ * window size changes.
+ */
+control(pty, cp, n)
+       int pty;
+       char *cp;
+       int n;
+{
+       struct winsize w;
+
+       if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
+               return (0);
+       oobdata[0] &= ~TIOCPKT_WINDOW;  /* we know he heard */
+       bcopy(cp+4, (char *)&w, sizeof(w));
+       w.ws_row = ntohs(w.ws_row);
+       w.ws_col = ntohs(w.ws_col);
+       w.ws_xpixel = ntohs(w.ws_xpixel);
+       w.ws_ypixel = ntohs(w.ws_ypixel);
+       (void)ioctl(pty, TIOCSWINSZ, &w);
+       return (4+sizeof (w));
+}
+
+/*
+ * rlogin "protocol" machine.
+ */
+protocol(f, p)
+       int f, p;
+{
+       char pibuf[1024], fibuf[1024], *pbp, *fbp;
+       register pcc = 0, fcc = 0;
+       int cc;
+       char cntl;
+
+       /*
+        * Must ignore SIGTTOU, otherwise we'll stop
+        * when we try and set slave pty's window shape
+        * (our controlling tty is the master pty).
+        */
+       (void) signal(SIGTTOU, SIG_IGN);
+       send(f, oobdata, 1, MSG_OOB);   /* indicate new rlogin */
+       for (;;) {
+               int ibits, obits, ebits;
+
+               ibits = 0;
+               obits = 0;
+               if (fcc)
+                       obits |= (1<<p);
+               else
+                       ibits |= (1<<f);
+               if (pcc >= 0)
+                       if (pcc)
+                               obits |= (1<<f);
                        else
                        else
-                               ibits |= (1<<f);
-                       if (pcc >= 0)
-                               if (pcc)
-                                       obits |= (1<<f);
-                               else
-                                       ibits |= (1<<p);
-                       if (fcc < 0 && pcc < 0)
-                               break;
-/* fprintf(console, "ibits from %d obits from %d\r\n", ibits, obits); */
-                       select(16, &ibits, &obits, 0, 0, 0);
-/* fprintf(console, "ibits %d obits %d\r\n", ibits, obits); */
-                       if (ibits == 0 && obits == 0) {
-                               sleep(5);
+                               ibits |= (1<<p);
+               ebits = (1<<p);
+               if (select(16, &ibits, &obits, &ebits, 0) < 0) {
+                       if (errno == EINTR)
                                continue;
                                continue;
-                       }
-                       if (ibits & (1<<f)) {
-                               fcc = read(f, fibuf, sizeof (fibuf));
-/* fprintf(console, "%d from f\r\n", fcc); */
-                               if (fcc < 0 && errno == EWOULDBLOCK)
-                                       fcc = 0;
-                               else {
-                                       if (fcc <= 0)
-                                               break;
-                                       fbp = fibuf;
+                       fatalperror(f, "select", errno);
+               }
+               if (ibits == 0 && obits == 0 && ebits == 0) {
+                       /* shouldn't happen... */
+                       sleep(5);
+                       continue;
+               }
+#define        pkcontrol(c)    ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
+               if (ebits & (1<<p)) {
+                       cc = read(p, &cntl, 1);
+                       if (cc == 1 && pkcontrol(cntl)) {
+                               cntl |= oobdata[0];
+                               send(f, &cntl, 1, MSG_OOB);
+                               if (cntl & TIOCPKT_FLUSHWRITE) {
+                                       pcc = 0;
+                                       ibits &= ~(1<<p);
                                }
                        }
                                }
                        }
-                       if (ibits & (1<<p)) {
-                               pcc = read(p, pibuf, sizeof (pibuf));
-/* fprintf(console, "%d from p, buf[0] %x, errno %d\r\n", pcc, buf[0], errno); */
-                               pbp = pibuf;
-                               if (pcc < 0 && errno == EWOULDBLOCK)
-                                       pcc = 0;
-                               else if (pcc <= 0)
-                                       pcc = -1;
-                               else if (pibuf[0] == 0)
-                                       pbp++, pcc--;
-                               else {
-                                       if (pibuf[0]&(TIOCPKT_FLUSHWRITE|
-                                                     TIOCPKT_NOSTOP|
-                                                     TIOCPKT_DOSTOP)) {
-                                               int nstop = pibuf[0] &
-                                                   (TIOCPKT_NOSTOP|
-                                                    TIOCPKT_DOSTOP);
-                                               if (nstop)
-                                                       stop = nstop;
-                                               pibuf[0] |= nstop;
-                                               send(f,&pibuf[0],1,SOF_OOB);
+               }
+               if (ibits & (1<<f)) {
+                       fcc = read(f, fibuf, sizeof (fibuf));
+                       if (fcc < 0 && errno == EWOULDBLOCK)
+                               fcc = 0;
+                       else {
+                               register char *cp;
+                               int left, n;
+
+                               if (fcc <= 0)
+                                       break;
+                               fbp = fibuf;
+
+                       top:
+                               for (cp = fibuf; cp < fibuf+fcc-1; cp++)
+                                       if (cp[0] == magic[0] &&
+                                           cp[1] == magic[1]) {
+                                               left = fcc - (cp-fibuf);
+                                               n = control(p, cp, left);
+                                               if (n) {
+                                                       left -= n;
+                                                       if (left > 0)
+                                                               bcopy(cp+n, cp, left);
+                                                       fcc -= n;
+                                                       goto top; /* n^2 */
+                                               }
                                        }
                                        }
-                                       pcc = 0;
-                               }
                        }
                        }
-                       if ((obits & (1<<f)) && pcc > 0) {
-                               cc = write(f, pbp, pcc);
-/* fprintf(console, "%d of %d to f\r\n", cc, pcc); */
-                               if (cc > 0) {
-                                       pcc -= cc;
-                                       pbp += cc;
-                               }
+               }
+
+               if ((obits & (1<<p)) && fcc > 0) {
+                       cc = write(p, fbp, fcc);
+                       if (cc > 0) {
+                               fcc -= cc;
+                               fbp += cc;
                        }
                        }
-                       if ((obits & (1<<p)) && fcc > 0) {
-                               cc = write(p, fbp, fcc);
-/* fprintf(console, "%d of %d to p\r\n", cc, fcc); */
-                               if (cc > 0) {
-                                       fcc -= cc;
-                                       fbp += cc;
+               }
+
+               if (ibits & (1<<p)) {
+                       pcc = read(p, pibuf, sizeof (pibuf));
+                       pbp = pibuf;
+                       if (pcc < 0 && errno == EWOULDBLOCK)
+                               pcc = 0;
+                       else if (pcc <= 0)
+                               break;
+                       else if (pibuf[0] == 0)
+                               pbp++, pcc--;
+                       else {
+                               if (pkcontrol(pibuf[0])) {
+                                       pibuf[0] |= oobdata[0];
+                                       send(f, &pibuf[0], 1, MSG_OOB);
                                }
                                }
+                               pcc = 0;
+                       }
+               }
+               if ((obits & (1<<f)) && pcc > 0) {
+                       cc = write(f, pbp, pcc);
+                       if (cc < 0 && errno == EWOULDBLOCK) {
+                               /* also shouldn't happen */
+                               sleep(5);
+                               continue;
+                       }
+                       if (cc > 0) {
+                               pcc -= cc;
+                               pbp += cc;
                        }
                }
                        }
                }
-               cleanup();
        }
        }
-       close(f);
-       close(p);
-       dup2(t, 0);
-       dup2(t, 1);
-       dup2(t, 2);
-       close(t);
-       execl("/bin/login", "login", "-r", hp->h_name, 0);
-       fatalperror(2, "/bin/login", errno);
-       /*NOTREACHED*/
 }
 
 cleanup()
 }
 
 cleanup()
@@ -288,7 +322,6 @@ cleanup()
        rmut();
        vhangup();              /* XXX */
        shutdown(netf, 2);
        rmut();
        vhangup();              /* XXX */
        shutdown(netf, 2);
-       kill(0, SIGKILL);
        exit(1);
 }
 
        exit(1);
 }
 
@@ -299,7 +332,7 @@ fatal(f, msg)
        char buf[BUFSIZ];
 
        buf[0] = '\01';         /* error indicator */
        char buf[BUFSIZ];
 
        buf[0] = '\01';         /* error indicator */
-       (void) sprintf(buf + 1, "rlogind: %s.\n", msg);
+       (void) sprintf(buf + 1, "rlogind: %s.\r\n", msg);
        (void) write(f, buf, strlen(buf));
        exit(1);
 }
        (void) write(f, buf, strlen(buf));
        exit(1);
 }
@@ -310,9 +343,13 @@ fatalperror(f, msg, errno)
        int errno;
 {
        char buf[BUFSIZ];
        int errno;
 {
        char buf[BUFSIZ];
+       extern int sys_nerr;
        extern char *sys_errlist[];
 
        extern char *sys_errlist[];
 
-       (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
+       if ((unsigned)errno < sys_nerr)
+               (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
+       else
+               (void) sprintf(buf, "%s: Error %d", msg, errno);
        fatal(f, buf);
 }
 
        fatal(f, buf);
 }
 
@@ -320,7 +357,7 @@ fatalperror(f, msg, errno)
 
 struct utmp wtmp;
 char   wtmpf[] = "/usr/adm/wtmp";
 
 struct utmp wtmp;
 char   wtmpf[] = "/usr/adm/wtmp";
-char   utmp[] = "/etc/utmp";
+char   utmpf[] = "/etc/utmp";
 #define SCPYN(a, b)    strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
 #define SCPYN(a, b)    strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
@@ -328,27 +365,41 @@ rmut()
 {
        register f;
        int found = 0;
 {
        register f;
        int found = 0;
+       struct utmp *u, *utmp;
+       int nutmp;
+       struct stat statbf;
 
 
-       f = open(utmp, 2);
+       f = open(utmpf, O_RDWR);
        if (f >= 0) {
        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);
-                       SCPYN(wtmp.ut_name, "");
-                       time(&wtmp.ut_time);
-                       write(f, (char *)&wtmp, sizeof(wtmp));
-                       found++;
+               fstat(f, &statbf);
+               utmp = (struct utmp *)malloc(statbf.st_size);
+               if (!utmp)
+                       syslog(LOG_ERR, "utmp malloc failed");
+               if (statbf.st_size && utmp) {
+                       nutmp = read(f, utmp, statbf.st_size);
+                       nutmp /= sizeof(struct utmp);
+               
+                       for (u = utmp ; u < &utmp[nutmp] ; u++) {
+                               if (SCMPN(u->ut_line, line+5) ||
+                                   u->ut_name[0]==0)
+                                       continue;
+                               lseek(f, ((long)u)-((long)utmp), L_SET);
+                               SCPYN(u->ut_name, "");
+                               SCPYN(u->ut_host, "");
+                               time(&u->ut_time);
+                               write(f, (char *)u, sizeof(wtmp));
+                               found++;
+                       }
                }
                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);
                }