add iruserok; from Van and Craig
authorCraig Leres <leres@ucbvax.Berkeley.EDU>
Wed, 1 Jul 1992 07:38:35 +0000 (23:38 -0800)
committerCraig Leres <leres@ucbvax.Berkeley.EDU>
Wed, 1 Jul 1992 07:38:35 +0000 (23:38 -0800)
SCCS-vsn: lib/libc/net/rcmd.c 5.25

usr/src/lib/libc/net/rcmd.c

index bb37f15..4c1f3c4 100644 (file)
@@ -6,87 +6,93 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)rcmd.c     5.24 (Berkeley) %G%";
+static char sccsid[] = "@(#)rcmd.c     5.25 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+
 #include <signal.h>
 #include <fcntl.h>
 #include <netdb.h>
 #include <signal.h>
 #include <fcntl.h>
 #include <netdb.h>
+#include <unistd.h>
 #include <pwd.h>
 #include <errno.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <pwd.h>
 #include <errno.h>
 #include <stdio.h>
 #include <ctype.h>
-#include <unistd.h>
 #include <string.h>
 
 #include <string.h>
 
+int    __ivaliduser __P((FILE *, u_long, const char *, const char *));
+static int __icheckhost __P((u_long, char *));
+
+int
 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
        char **ahost;
        u_short rport;
        const char *locuser, *remuser, *cmd;
        int *fd2p;
 {
 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
        char **ahost;
        u_short rport;
        const char *locuser, *remuser, *cmd;
        int *fd2p;
 {
-       int s, timo = 1, pid;
-       long oldmask;
-       struct sockaddr_in sin, sin2, from;
-       char c;
-       int lport = IPPORT_RESERVED - 1;
        struct hostent *hp;
        struct hostent *hp;
+       struct sockaddr_in sin, from;
        fd_set reads;
        fd_set reads;
+       long oldmask;
+       int s, lport, pid, timo;
+       char c;
 
        pid = getpid();
        hp = gethostbyname(*ahost);
 
        pid = getpid();
        hp = gethostbyname(*ahost);
-       if (hp == 0) {
+       if (hp == NULL) {
                herror(*ahost);
                return (-1);
        }
        *ahost = hp->h_name;
        oldmask = sigblock(sigmask(SIGURG));
                herror(*ahost);
                return (-1);
        }
        *ahost = hp->h_name;
        oldmask = sigblock(sigmask(SIGURG));
-       for (;;) {
+       for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
                s = rresvport(&lport);
                if (s < 0) {
                        if (errno == EAGAIN)
                s = rresvport(&lport);
                if (s < 0) {
                        if (errno == EAGAIN)
-                               fprintf(stderr, "socket: All ports in use\n");
+                               (void)fprintf(stderr,
+                                   "rcmd: socket: All ports in use\n");
                        else
                        else
-                               perror("rcmd: socket");
+                               (void)fprintf(stderr, "rcmd: socket: %s\n",
+                                   strerror(errno));
                        sigsetmask(oldmask);
                        return (-1);
                }
                fcntl(s, F_SETOWN, pid);
                sin.sin_family = hp->h_addrtype;
                        sigsetmask(oldmask);
                        return (-1);
                }
                fcntl(s, F_SETOWN, pid);
                sin.sin_family = hp->h_addrtype;
-               bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
+               bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
                sin.sin_port = rport;
                if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
                        break;
                sin.sin_port = rport;
                if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
                        break;
-               (void) close(s);
+               (void)close(s);
                if (errno == EADDRINUSE) {
                        lport--;
                        continue;
                }
                if (errno == ECONNREFUSED && timo <= 16) {
                if (errno == EADDRINUSE) {
                        lport--;
                        continue;
                }
                if (errno == ECONNREFUSED && timo <= 16) {
-                       sleep(timo);
+                       (void)sleep(timo);
                        timo *= 2;
                        continue;
                }
                if (hp->h_addr_list[1] != NULL) {
                        int oerrno = errno;
 
                        timo *= 2;
                        continue;
                }
                if (hp->h_addr_list[1] != NULL) {
                        int oerrno = errno;
 
-                       fprintf(stderr,
-                           "connect to address %s: ", inet_ntoa(sin.sin_addr));
+                       (void)fprintf(stderr, "connect to address %s: ",
+                           inet_ntoa(sin.sin_addr));
                        errno = oerrno;
                        perror(0);
                        hp->h_addr_list++;
                        errno = oerrno;
                        perror(0);
                        hp->h_addr_list++;
-                       bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
-                           hp->h_length);
-                       fprintf(stderr, "Trying %s...\n",
-                               inet_ntoa(sin.sin_addr));
+                       bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
+                       (void)fprintf(stderr, "Trying %s...\n",
+                           inet_ntoa(sin.sin_addr));
                        continue;
                }
                        continue;
                }
-               perror(hp->h_name);
+               (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
                sigsetmask(oldmask);
                return (-1);
        }
                sigsetmask(oldmask);
                return (-1);
        }
@@ -97,35 +103,39 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
        } else {
                char num[8];
                int s2 = rresvport(&lport), s3;
        } else {
                char num[8];
                int s2 = rresvport(&lport), s3;
-               int len = sizeof (from);
+               int len = sizeof(from);
 
                if (s2 < 0)
                        goto bad;
                listen(s2, 1);
 
                if (s2 < 0)
                        goto bad;
                listen(s2, 1);
-               (void) sprintf(num, "%d", lport);
+               (void)snprintf(num, sizeof(num), "%d", lport);
                if (write(s, num, strlen(num)+1) != strlen(num)+1) {
                if (write(s, num, strlen(num)+1) != strlen(num)+1) {
-                       perror("write: setting up stderr");
-                       (void) close(s2);
+                       (void)fprintf(stderr,
+                           "rcmd: write (setting up stderr): %s\n",
+                           strerror(errno));
+                       (void)close(s2);
                        goto bad;
                }
                FD_ZERO(&reads);
                FD_SET(s, &reads);
                FD_SET(s2, &reads);
                errno = 0;
                        goto bad;
                }
                FD_ZERO(&reads);
                FD_SET(s, &reads);
                FD_SET(s2, &reads);
                errno = 0;
-               if (select(32, &reads, 0, 0, 0) < 1 ||
-                   !FD_ISSET(s2, &reads)) {
+               if (select(32, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
                        if (errno != 0)
                        if (errno != 0)
-                               perror("select: setting up stderr");
+                               (void)fprintf(stderr,
+                                   "rcmd: select (setting up stderr): %s\n",
+                                   strerror(errno));
                        else
                        else
-                           fprintf(stderr,
-                               "select: protocol failure in circuit setup.\n");
-                       (void) close(s2);
+                               (void)fprintf(stderr,
+                               "select: protocol failure in circuit setup\n");
+                       (void)close(s2);
                        goto bad;
                }
                s3 = accept(s2, (struct sockaddr *)&from, &len);
                        goto bad;
                }
                s3 = accept(s2, (struct sockaddr *)&from, &len);
-               (void) close(s2);
+               (void)close(s2);
                if (s3 < 0) {
                if (s3 < 0) {
-                       perror("accept");
+                       (void)fprintf(stderr,
+                           "rcmd: accept: %s\n", strerror(errno));
                        lport = 0;
                        goto bad;
                }
                        lport = 0;
                        goto bad;
                }
@@ -134,16 +144,17 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
                if (from.sin_family != AF_INET ||
                    from.sin_port >= IPPORT_RESERVED ||
                    from.sin_port < IPPORT_RESERVED / 2) {
                if (from.sin_family != AF_INET ||
                    from.sin_port >= IPPORT_RESERVED ||
                    from.sin_port < IPPORT_RESERVED / 2) {
-                       fprintf(stderr,
+                       (void)fprintf(stderr,
                            "socket: protocol failure in circuit setup.\n");
                        goto bad2;
                }
        }
                            "socket: protocol failure in circuit setup.\n");
                        goto bad2;
                }
        }
-       (void) write(s, locuser, strlen(locuser)+1);
-       (void) write(s, remuser, strlen(remuser)+1);
-       (void) write(s, cmd, strlen(cmd)+1);
+       (void)write(s, locuser, strlen(locuser)+1);
+       (void)write(s, remuser, strlen(remuser)+1);
+       (void)write(s, cmd, strlen(cmd)+1);
        if (read(s, &c, 1) != 1) {
        if (read(s, &c, 1) != 1) {
-               perror(*ahost);
+               (void)fprintf(stderr,
+                   "rcmd: %s: %s\n", *ahost, strerror(errno));
                goto bad2;
        }
        if (c != 0) {
                goto bad2;
        }
        if (c != 0) {
@@ -158,13 +169,14 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
        return (s);
 bad2:
        if (lport)
        return (s);
 bad2:
        if (lport)
-               (void) close(*fd2p);
+               (void)close(*fd2p);
 bad:
 bad:
-       (void) close(s);
+       (void)close(s);
        sigsetmask(oldmask);
        return (-1);
 }
 
        sigsetmask(oldmask);
        return (-1);
 }
 
+int
 rresvport(alport)
        int *alport;
 {
 rresvport(alport)
        int *alport;
 {
@@ -181,89 +193,132 @@ rresvport(alport)
                if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
                        return (s);
                if (errno != EADDRINUSE) {
                if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
                        return (s);
                if (errno != EADDRINUSE) {
-                       (void) close(s);
+                       (void)close(s);
                        return (-1);
                }
                (*alport)--;
                if (*alport == IPPORT_RESERVED/2) {
                        return (-1);
                }
                (*alport)--;
                if (*alport == IPPORT_RESERVED/2) {
-                       (void) close(s);
+                       (void)close(s);
                        errno = EAGAIN;         /* close */
                        return (-1);
                }
        }
 }
 
                        errno = EAGAIN;         /* close */
                        return (-1);
                }
        }
 }
 
-int    _check_rhosts_file = 1;
+int    __check_rhosts_file = 1;
+char   *__rcmd_errstr;
 
 
+int
 ruserok(rhost, superuser, ruser, luser)
        const char *rhost, *ruser, *luser;
        int superuser;
 {
 ruserok(rhost, superuser, ruser, luser)
        const char *rhost, *ruser, *luser;
        int superuser;
 {
-       FILE *hostf;
-       char fhost[MAXHOSTNAMELEN];
-       int first = 1;
-       register char *sp, *p;
-       int baselen = -1;
+       struct hostent *hp;
+       u_long addr;
+       char **ap;
 
 
-       sp = (char *)rhost;
-       p = fhost;
-       while (*sp) {
-               if (*sp == '.') {
-                       if (baselen == -1)
-                               baselen = sp - rhost;
-                       *p++ = *sp++;
-               } else {
-                       *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
-               }
+       if ((hp = gethostbyname(rhost)) == NULL)
+               return (-1);
+       for (ap = hp->h_addr_list; *ap; ++ap) {
+               bcopy(*ap, &addr, sizeof(addr));
+               if (iruserok(addr, superuser, ruser, luser) == 0)
+                       return (0);
        }
        }
-       *p = '\0';
-       hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r");
+       return (-1);
+}
+
+/*
+ * New .rhosts strategy: We are passed an ip address. We spin through
+ * hosts.equiv and .rhosts looking for a match. When the .rhosts only
+ * has ip addresses, we don't have to trust a nameserver.  When it
+ * contains hostnames, we spin through the list of addresses the nameserver
+ * gives us and look for a match.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+iruserok(raddr, superuser, ruser, luser)
+       u_long raddr;
+       int superuser;
+       const char *ruser, *luser;
+{
+       FILE *hostf;
+       uid_t uid;
+       int first;
+
+       first = 1;
+       hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
 again:
        if (hostf) {
 again:
        if (hostf) {
-               if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
-                       (void) fclose(hostf);
-                       return(0);
+               if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
+                       (void)fclose(hostf);
+                       return (0);
                }
                }
-               (void) fclose(hostf);
+               (void)fclose(hostf);
        }
        }
-       if (first == 1 && (_check_rhosts_file || superuser)) {
+       if (first == 1 && (__check_rhosts_file || superuser)) {
                struct stat sbuf;
                struct passwd *pwd;
                char pbuf[MAXPATHLEN];
 
                first = 0;
                if ((pwd = getpwnam(luser)) == NULL)
                struct stat sbuf;
                struct passwd *pwd;
                char pbuf[MAXPATHLEN];
 
                first = 0;
                if ((pwd = getpwnam(luser)) == NULL)
-                       return(-1);
+                       return (-1);
                (void)strcpy(pbuf, pwd->pw_dir);
                (void)strcat(pbuf, "/.rhosts");
                (void)strcpy(pbuf, pwd->pw_dir);
                (void)strcat(pbuf, "/.rhosts");
-               if ((hostf = fopen(pbuf, "r")) == NULL)
-                       return(-1);
+
                /*
                /*
-                * if owned by someone other than user or root or if
-                * writeable by anyone but the owner, quit
+                * Change effective uid while opening .rhosts.  If root and
+                * reading an NFS mounted file system, can't read files that
+                * are protected read/write owner only.
                 */
                 */
-               if (fstat(fileno(hostf), &sbuf) ||
-                   sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
-                   sbuf.st_mode&022) {
-                       fclose(hostf);
-                       return(-1);
+               uid = geteuid();
+               (void)seteuid(pwd->pw_uid);
+               hostf = fopen(pbuf, "r");
+               (void)seteuid(uid);
+
+               if (hostf == NULL)
+                       return (-1);
+               /*
+                * If not a regular file, or is owned by someone other than
+                * user or root or if writeable by anyone but the owner, quit.
+                */
+               if (lstat(pbuf, &sbuf) < 0)
+                       __rcmd_errstr = ".rhosts lstat failed";
+               else if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+                       __rcmd_errstr = ".rhosts not regular file";
+               else if (fstat(fileno(hostf), &sbuf) < 0)
+                       __rcmd_errstr = ".rhosts fstat failed";
+               else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
+                       __rcmd_errstr = "bad .rhosts owner";
+               else if (sbuf.st_mode & 022)
+                       __rcmd_errstr = "bad .rhosts permissions";
+               /* If there were any problems, quit. */
+               if (__rcmd_errstr) {
+                       (void)fclose(hostf);
+                       return (-1);
                }
                goto again;
        }
        return (-1);
 }
 
                }
                goto again;
        }
        return (-1);
 }
 
-/* don't make static, used by lpd(8) */
-_validuser(hostf, rhost, luser, ruser, baselen)
-       char *rhost, *luser, *ruser;
+/*
+ * XXX
+ * Don't make static, used by lpd(8).
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+int
+__ivaliduser(hostf, raddr, luser, ruser)
        FILE *hostf;
        FILE *hostf;
-       int baselen;
+       u_long raddr;
+       const char *luser, *ruser;
 {
 {
-       register char *p;
-       char *user, ahost[MAXHOSTNAMELEN];
-       static int _checkhost();
+       register char *user, *p;
+       char ahost[MAXHOSTNAMELEN];
 
 
-       while (fgets(ahost, sizeof (ahost), hostf)) {
+       while (fgets(ahost, sizeof(ahost), hostf)) {
                p = ahost;
                while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
                        *p = isupper(*p) ? tolower(*p) : *p;
                p = ahost;
                while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
                        *p = isupper(*p) ? tolower(*p) : *p;
@@ -274,52 +329,45 @@ _validuser(hostf, rhost, luser, ruser, baselen)
                        while (*p == ' ' || *p == '\t')
                                p++;
                        user = p;
                        while (*p == ' ' || *p == '\t')
                                p++;
                        user = p;
-                       while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
+                       while (*p != '\n' && *p != ' ' &&
+                           *p != '\t' && *p != '\0')
                                p++;
                } else
                        user = p;
                *p = '\0';
                                p++;
                } else
                        user = p;
                *p = '\0';
-               if (_checkhost(rhost, ahost, baselen) &&
-                   !strcmp(ruser, *user ? user : luser)) {
+               if (__icheckhost(raddr, ahost) &&
+                   strcmp(ruser, *user ? user : luser) == 0) {
                        return (0);
                }
        }
        return (-1);
 }
 
                        return (0);
                }
        }
        return (-1);
 }
 
-static
-_checkhost(rhost, lhost, len)
-       char *rhost, *lhost;
-       int len;
+/*
+ * Returns "true" if match, 0 if no match.
+ */
+static int
+__icheckhost(raddr, lhost)
+       u_long raddr;
+       register char *lhost;
 {
 {
-       static char ldomain[MAXHOSTNAMELEN + 1];
-       static char *domainp = NULL;
-       static int nodomain = 0;
-       register char *cp;
+       register struct hostent *hp;
+       register u_long laddr;
+       register char **pp;
 
 
-       if (len == -1)
-               return(!strcmp(rhost, lhost));
-       if (strncmp(rhost, lhost, len))
-               return(0);
-       if (!strcmp(rhost, lhost))
-               return(1);
-       if (*(lhost + len) != '\0')
-               return(0);
-       if (nodomain)
-               return(0);
-       if (!domainp) {
-               if (gethostname(ldomain, sizeof(ldomain)) == -1) {
-                       nodomain = 1;
-                       return(0);
-               }
-               ldomain[MAXHOSTNAMELEN] = NULL;
-               if ((domainp = index(ldomain, '.')) == (char *)NULL) {
-                       nodomain = 1;
-                       return(0);
-               }
-               for (cp = ++domainp; *cp; ++cp)
-                       if (isupper(*cp))
-                               *cp = tolower(*cp);
-       }
-       return(!strcmp(domainp, rhost + len +1));
+       /* Try for raw ip address first. */
+       if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
+               return (raddr == laddr);
+
+       /* Better be a hostname. */
+       if ((hp = gethostbyname(lhost)) == NULL)
+               return (0);
+
+       /* Spin through ip addresses. */
+       for (pp = hp->h_addr_list; *pp; ++pp)
+               if (!bcmp(&raddr, *pp, sizeof(u_long)))
+                       return (1);
+
+       /* No match. */
+       return (0);
 }
 }