BSD 4_3_Net_2 release
[unix-history] / usr / src / libexec / rshd / rshd.c
index 86a76ed..f5203ae 100644 (file)
@@ -2,7 +2,33 @@
  * Copyright (c) 1988, 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1988, 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -12,7 +38,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)rshd.c     5.38 (Berkeley) %G%";
+static char sccsid[] = "@(#)rshd.c     5.38.1.1 (Berkeley) 8/20/91";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -43,7 +69,6 @@ static char sccsid[] = "@(#)rshd.c    5.38 (Berkeley) %G%";
 
 #include <pwd.h>
 #include <syslog.h>
 
 #include <pwd.h>
 #include <syslog.h>
-#include "pathnames.h"
 #include <unistd.h>
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdio.h>
@@ -53,12 +78,24 @@ static char sccsid[] = "@(#)rshd.c  5.38 (Berkeley) %G%";
 
 int    keepalive = 1;
 int    check_all = 0;
 
 int    keepalive = 1;
 int    check_all = 0;
-int    check_all = 0;
 char   *index(), *rindex(), *strncat();
 /*VARARGS1*/
 int    error();
 int    sent_null;
 char   *index(), *rindex(), *strncat();
 /*VARARGS1*/
 int    error();
 int    sent_null;
-int    sent_null;
+
+#ifdef KERBEROS
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#define        VERSION_SIZE    9
+#define SECURE_MESSAGE  "This rsh session is using DES encryption for all transmissions.\r\n"
+#define        OPTIONS         "alknvx"
+char   authbuf[sizeof(AUTH_DAT)];
+char   tickbuf[sizeof(KTEXT_ST)];
+int    doencrypt, use_kerberos, vacuous;
+Key_schedule   schedule;
+#else
+#define        OPTIONS "aln"
+#endif
 
 /*ARGSUSED*/
 main(argc, argv)
 
 /*ARGSUSED*/
 main(argc, argv)
@@ -74,6 +111,7 @@ main(argc, argv)
        openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
 
        opterr = 0;
        openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
 
        opterr = 0;
+       while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
                switch (ch) {
                case 'a':
                        check_all = 1;
                switch (ch) {
                case 'a':
                        check_all = 1;
@@ -84,6 +122,16 @@ main(argc, argv)
                case 'n':
                        keepalive = 0;
                        break;
                case 'n':
                        keepalive = 0;
                        break;
+#ifdef KERBEROS
+               case 'k':
+                       use_kerberos = 1;
+                       break;
+
+               case 'v':
+                       vacuous = 1;
+                       break;
+
+#endif
                case '?':
                default:
                        usage();
                case '?':
                default:
                        usage();
@@ -93,6 +141,13 @@ main(argc, argv)
        argc -= optind;
        argv += optind;
 
        argc -= optind;
        argv += optind;
 
+#ifdef KERBEROS
+       if (use_kerberos && vacuous) {
+               syslog(LOG_ERR, "only one of -k and -v allowed");
+               exit(2);
+       }
+#endif
+
        fromlen = sizeof (from);
        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
                syslog(LOG_ERR, "getpeername: %m");
        fromlen = sizeof (from);
        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
                syslog(LOG_ERR, "getpeername: %m");
@@ -135,6 +190,19 @@ doit(fromp)
        int one = 1;
        char remotehost[2 * MAXHOSTNAMELEN + 1];
 
        int one = 1;
        char remotehost[2 * MAXHOSTNAMELEN + 1];
 
+#ifdef KERBEROS
+       AUTH_DAT        *kdata = (AUTH_DAT *) NULL;
+       KTEXT           ticket = (KTEXT) NULL;
+       char            instance[INST_SZ], version[VERSION_SIZE];
+       struct          sockaddr_in     fromaddr;
+       int             rc;
+       long            authopts;
+       int             pv1[2], pv2[2];
+       fd_set          wready, writeto;
+
+       fromaddr = *fromp;
+#endif
+
        (void) signal(SIGINT, SIG_DFL);
        (void) signal(SIGQUIT, SIG_DFL);
        (void) signal(SIGTERM, SIG_DFL);
        (void) signal(SIGINT, SIG_DFL);
        (void) signal(SIGQUIT, SIG_DFL);
        (void) signal(SIGTERM, SIG_DFL);
@@ -152,12 +220,6 @@ doit(fromp)
                    fromp->sin_family);
                exit(1);
        }
                    fromp->sin_family);
                exit(1);
        }
-#ifdef IP_OPTIONS
-      {
-       u_char optbuf[BUFSIZ/3], *cp;
-       char lbuf[BUFSIZ], *lp;
-       int optsize = sizeof(optbuf), ipproto;
-       struct protoent *ip;
 #ifdef IP_OPTIONS
       {
        u_char optbuf[BUFSIZ/3], *cp;
 #ifdef IP_OPTIONS
       {
        u_char optbuf[BUFSIZ/3], *cp;
@@ -165,26 +227,6 @@ doit(fromp)
        int optsize = sizeof(optbuf), ipproto;
        struct protoent *ip;
 
        int optsize = sizeof(optbuf), ipproto;
        struct protoent *ip;
 
-       if ((ip = getprotobyname("ip")) != NULL)
-               ipproto = ip->p_proto;
-       else
-               ipproto = IPPROTO_IP;
-       if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 &&
-           optsize != 0) {
-               lp = lbuf;
-               for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
-                       sprintf(lp, " %2.2x", *cp);
-               syslog(LOG_NOTICE,
-                   "Connection received using IP options (ignored):%s", lbuf);
-               if (setsockopt(0, ipproto, IP_OPTIONS,
-                   (char *)NULL, &optsize) != 0) {
-                       syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
-                       exit(1);
-               }
-       }
-      }
-#endif
-
        if ((ip = getprotobyname("ip")) != NULL)
                ipproto = ip->p_proto;
        else
        if ((ip = getprotobyname("ip")) != NULL)
                ipproto = ip->p_proto;
        else
@@ -208,6 +250,14 @@ doit(fromp)
 
 #ifdef KERBEROS
        if (!use_kerberos)
 
 #ifdef KERBEROS
        if (!use_kerberos)
+#endif
+               if (fromp->sin_port >= IPPORT_RESERVED ||
+                   fromp->sin_port < IPPORT_RESERVED/2) {
+                       syslog(LOG_NOTICE|LOG_AUTH,
+                           "Connection from %s on illegal port",
+                           inet_ntoa(fromp->sin_addr));
+                       exit(1);
+               }
 
        (void) alarm(60);
        port = 0;
 
        (void) alarm(60);
        port = 0;
@@ -219,6 +269,8 @@ doit(fromp)
                        shutdown(0, 1+1);
                        exit(1);
                }
                        shutdown(0, 1+1);
                        exit(1);
                }
+               if (c== 0)
+                       break;
                port = port * 10 + c - '0';
        }
 
                port = port * 10 + c - '0';
        }
 
@@ -232,6 +284,11 @@ doit(fromp)
                }
 #ifdef KERBEROS
                if (!use_kerberos)
                }
 #ifdef KERBEROS
                if (!use_kerberos)
+#endif
+                       if (port >= IPPORT_RESERVED) {
+                               syslog(LOG_ERR, "2nd port not reserved\n");
+                               exit(1);
+                       }
                fromp->sin_port = htons(port);
                if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
                        syslog(LOG_INFO, "connect second port: %m");
                fromp->sin_port = htons(port);
                if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
                        syslog(LOG_INFO, "connect second port: %m");
@@ -239,6 +296,13 @@ doit(fromp)
                }
        }
 
                }
        }
 
+#ifdef KERBEROS
+       if (vacuous) {
+               error("rshd: remote host requires Kerberos authentication\n");
+               exit(1);
+       }
+#endif
+
 #ifdef notdef
        /* from inetd, socket is already on 0, 1, 2 */
        dup2(f, 0);
 #ifdef notdef
        /* from inetd, socket is already on 0, 1, 2 */
        dup2(f, 0);
@@ -270,9 +334,7 @@ doit(fromp)
                                errorstr =
                                "Couldn't look up address for your host (%s)\n";
                                hostname = inet_ntoa(fromp->sin_addr);
                                errorstr =
                                "Couldn't look up address for your host (%s)\n";
                                hostname = inet_ntoa(fromp->sin_addr);
-                       }
-#ifdef h_addr  /* 4.2 hack */
-                       for (; ; hp->h_addr_list++) {
+                       } else for (; ; hp->h_addr_list++) {
                                if (hp->h_addr_list[0] == NULL) {
                                        syslog(LOG_NOTICE,
                                          "Host addr %s not listed for host %s",
                                if (hp->h_addr_list[0] == NULL) {
                                        syslog(LOG_NOTICE,
                                          "Host addr %s not listed for host %s",
@@ -290,22 +352,30 @@ doit(fromp)
                                        break;
                                }
                        }
                                        break;
                                }
                        }
-#else
-                       if (bcmp(hp->h_addr, (caddr_t)&fromp->sin_addr,
-                           sizeof(fromp->sin_addr))) {
-                               syslog(LOG_NOTICE,
-                                 "Host addr %s not listed for host %s",
-                                   inet_ntoa(fromp->sin_addr),
-                                   hp->h_name);
-                               error("Host address mismatch\n");
-                               exit(1);
-                       }
-#endif
                }
        } else
                errorhost = hostname = inet_ntoa(fromp->sin_addr);
 
                }
        } else
                errorhost = hostname = inet_ntoa(fromp->sin_addr);
 
-       getstr(remuser, sizeof(remuser), "remuser");
+#ifdef KERBEROS
+       if (use_kerberos) {
+               kdata = (AUTH_DAT *) authbuf;
+               ticket = (KTEXT) tickbuf;
+               authopts = 0L;
+               strcpy(instance, "*");
+               version[VERSION_SIZE - 1] = '\0';
+                       rc = krb_recvauth(authopts, 0, ticket, "rcmd",
+                               instance, &fromaddr,
+                               (struct sockaddr_in *) 0,
+                               kdata, "", (bit_64 *) 0, version);
+               if (rc != KSUCCESS) {
+                       error("Kerberos authentication failure: %s\n",
+                                 krb_err_txt[rc]);
+                       exit(1);
+               }
+       } else
+#endif
+               getstr(remuser, sizeof(remuser), "remuser");
+
        getstr(locuser, sizeof(locuser), "locuser");
        getstr(cmdbuf, sizeof(cmdbuf), "command");
        setpwent();
        getstr(locuser, sizeof(locuser), "locuser");
        getstr(cmdbuf, sizeof(cmdbuf), "command");
        setpwent();
@@ -323,11 +393,29 @@ doit(fromp)
 #endif
        }
 
 #endif
        }
 
-       if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
-           ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
-               error("Permission denied.\n");
-               exit(1);
-       }
+#ifdef KERBEROS
+       if (use_kerberos) {
+               if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
+                       if (kuserok(kdata, locuser) != 0) {
+                               syslog(LOG_NOTICE|LOG_AUTH,
+                                   "Kerberos rsh denied to %s.%s@%s",
+                                   kdata->pname, kdata->pinst, kdata->prealm);
+                               error("Permission denied.\n");
+                               exit(1);
+                       }
+               }
+       } else
+#endif
+
+               if (errorstr ||
+                   pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
+                   ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
+fail:
+                       if (errorstr == NULL)
+                               errorstr = "Permission denied.\n";
+                       error(errorstr, errorhost);
+                       exit(1);
+               }
 
        if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
                error("Logins currently disabled.\n");
 
        if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
                error("Logins currently disabled.\n");
@@ -336,7 +424,6 @@ doit(fromp)
 
        (void) write(2, "\0", 1);
        sent_null = 1;
 
        (void) write(2, "\0", 1);
        sent_null = 1;
-       sent_null = 1;
 
        if (port) {
                if (pipe(pv) < 0) {
 
        if (port) {
                if (pipe(pv) < 0) {
@@ -398,7 +485,6 @@ doit(fromp)
                (void) close(s); (void) close(pv[0]);
                dup2(pv[1], 2);
                close(pv[1]);
                (void) close(s); (void) close(pv[0]);
                dup2(pv[1], 2);
                close(pv[1]);
-               close(pv[1]);
        }
        if (*pwd->pw_shell == '\0')
                pwd->pw_shell = _PATH_BSHELL;
        }
        if (*pwd->pw_shell == '\0')
                pwd->pw_shell = _PATH_BSHELL;
@@ -420,10 +506,6 @@ doit(fromp)
        else
                cp = pwd->pw_shell;
        endpwent();
        else
                cp = pwd->pw_shell;
        endpwent();
-       if (pwd->pw_uid == 0)
-               syslog(LOG_INFO|LOG_AUTH, "ROOT shell from %s@%s, comm: %s\n",
-                   remuser, hostname, cmdbuf);
-       endpwent();
        if (pwd->pw_uid == 0) {
 #ifdef KERBEROS
                if (use_kerberos)
        if (pwd->pw_uid == 0) {
 #ifdef KERBEROS
                if (use_kerberos)
@@ -442,12 +524,6 @@ doit(fromp)
        exit(1);
 }
 
        exit(1);
 }
 
-/*
- * Report error to client.
- * Note: can't be used until second socket has connected
- * to client, or older clients will hang waiting
- * for that connection first.
- */
 /*
  * Report error to client.
  * Note: can't be used until second socket has connected
 /*
  * Report error to client.
  * Note: can't be used until second socket has connected
@@ -499,7 +575,6 @@ local_domain(h)
        char localhost[MAXHOSTNAMELEN];
        char *p1, *p2, *topdomain();
 
        char localhost[MAXHOSTNAMELEN];
        char *p1, *p2, *topdomain();
 
-       localhost[0] = 0;
        localhost[0] = 0;
        (void) gethostname(localhost, sizeof(localhost));
        p1 = topdomain(localhost);
        localhost[0] = 0;
        (void) gethostname(localhost, sizeof(localhost));
        p1 = topdomain(localhost);
@@ -527,24 +602,6 @@ topdomain(h)
        return (maybe);
 }
 
        return (maybe);
 }
 
-char *
-topdomain(h)
-       char *h;
-{
-       register char *p;
-       char *maybe = NULL;
-       int dots = 0;
-
-       for (p = h + strlen(h); p >= h; p--) {
-               if (*p == '.') {
-                       if (++dots == 2)
-                               return (p);
-                       maybe = p;
-               }
-       }
-       return (maybe);
-}
-
 usage()
 {
        syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
 usage()
 {
        syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);