home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / ixemul-45.0-src.tgz / tar.out / contrib / ixemul / net / rcmd.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  519 lines

  1. /*    $NetBSD: rcmd.c,v 1.12 1995/06/03 22:33:34 mycroft Exp $    */
  2.  
  3. /*
  4.  * Copyright (c) 1983, 1993, 1994
  5.  *    The Regents of the University of California.  All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *    This product includes software developed by the University of
  18.  *    California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35.  
  36. #if defined(LIBC_SCCS) && !defined(lint)
  37. #if 0
  38. static char sccsid[] = "@(#)rcmd.c    8.3 (Berkeley) 3/26/94";
  39. #else
  40. static char *rcsid = "$NetBSD: rcmd.c,v 1.12 1995/06/03 22:33:34 mycroft Exp $";
  41. #endif
  42. #endif /* LIBC_SCCS and not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/socket.h>
  46. #include <sys/stat.h>
  47.  
  48. #include <netinet/in.h>
  49. #include <arpa/inet.h>
  50.  
  51. #include <netgroup.h>
  52. #include <signal.h>
  53. #include <fcntl.h>
  54. #include <netdb.h>
  55. #include <unistd.h>
  56. #include <pwd.h>
  57. #include <errno.h>
  58. #include <stdio.h>
  59. #include <ctype.h>
  60. #include <string.h>
  61.  
  62. int    __ivaliduser __P((FILE *, u_long, const char *, const char *));
  63. static int __icheckhost __P((u_long, const char *));
  64.  
  65. int
  66. rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
  67.     char **ahost;
  68.     u_short rport;
  69.     const char *locuser, *remuser, *cmd;
  70.     int *fd2p;
  71. {
  72.     struct hostent *hp;
  73.     struct sockaddr_in sin, from;
  74.     fd_set reads;
  75.     long oldmask;
  76.     pid_t pid;
  77.     int s, lport, timo;
  78.     char c;
  79.  
  80.     pid = getpid();
  81.     hp = gethostbyname(*ahost);
  82.     if (hp == NULL) {
  83.         herror(*ahost);
  84.         return (-1);
  85.     }
  86.     *ahost = hp->h_name;
  87.     oldmask = sigblock(sigmask(SIGURG));
  88.     for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
  89.         s = rresvport(&lport);
  90.         if (s < 0) {
  91.             if (errno == EAGAIN)
  92.                 (void)fprintf(stderr,
  93.                     "rcmd: socket: All ports in use\n");
  94.             else
  95.                 (void)fprintf(stderr, "rcmd: socket: %s\n",
  96.                     strerror(errno));
  97.             sigsetmask(oldmask);
  98.             return (-1);
  99.         }
  100.         fcntl(s, F_SETOWN, pid);
  101.         sin.sin_len = sizeof(struct sockaddr_in);
  102.         sin.sin_family = hp->h_addrtype;
  103.         sin.sin_port = rport;
  104.         bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
  105.         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  106.             break;
  107.         (void)close(s);
  108.         if (errno == EADDRINUSE) {
  109.             lport--;
  110.             continue;
  111.         }
  112.         if (errno == ECONNREFUSED && timo <= 16) {
  113.             (void)sleep(timo);
  114.             timo *= 2;
  115.             continue;
  116.         }
  117.         if (hp->h_addr_list[1] != NULL) {
  118.             int oerrno = errno;
  119.  
  120.             (void)fprintf(stderr, "connect to address %s: ",
  121.                 inet_ntoa(sin.sin_addr));
  122.             errno = oerrno;
  123.             perror(0);
  124.             hp->h_addr_list++;
  125.             bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
  126.             (void)fprintf(stderr, "Trying %s...\n",
  127.                 inet_ntoa(sin.sin_addr));
  128.             continue;
  129.         }
  130.         (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
  131.         sigsetmask(oldmask);
  132.         return (-1);
  133.     }
  134.     lport--;
  135.     if (fd2p == 0) {
  136.         write(s, "", 1);
  137.         lport = 0;
  138.     } else {
  139.         char num[8];
  140.         int s2 = rresvport(&lport), s3;
  141.         int len = sizeof(from);
  142.  
  143.         if (s2 < 0)
  144.             goto bad;
  145.         listen(s2, 1);
  146.         (void)snprintf(num, sizeof(num), "%d", lport);
  147.         if (write(s, num, strlen(num)+1) != strlen(num)+1) {
  148.             (void)fprintf(stderr,
  149.                 "rcmd: write (setting up stderr): %s\n",
  150.                 strerror(errno));
  151.             (void)close(s2);
  152.             goto bad;
  153.         }
  154.         FD_ZERO(&reads);
  155.         FD_SET(s, &reads);
  156.         FD_SET(s2, &reads);
  157.         errno = 0;
  158.         if (select(MAX(s, s2) + 1, &reads, 0, 0, 0) < 1 ||
  159.             !FD_ISSET(s2, &reads)) {
  160.             if (errno != 0)
  161.                 (void)fprintf(stderr,
  162.                     "rcmd: select (setting up stderr): %s\n",
  163.                     strerror(errno));
  164.             else
  165.                 (void)fprintf(stderr,
  166.                 "select: protocol failure in circuit setup\n");
  167.             (void)close(s2);
  168.             goto bad;
  169.         }
  170.         s3 = accept(s2, (struct sockaddr *)&from, &len);
  171.         (void)close(s2);
  172.         if (s3 < 0) {
  173.             (void)fprintf(stderr,
  174.                 "rcmd: accept: %s\n", strerror(errno));
  175.             lport = 0;
  176.             goto bad;
  177.         }
  178.         *fd2p = s3;
  179.         from.sin_port = ntohs(from.sin_port);
  180.         if (from.sin_family != AF_INET ||
  181.             from.sin_port >= IPPORT_RESERVED ||
  182.             from.sin_port < IPPORT_RESERVED / 2) {
  183.             (void)fprintf(stderr,
  184.                 "socket: protocol failure in circuit setup.\n");
  185.             goto bad2;
  186.         }
  187.     }
  188.     (void)write(s, locuser, strlen(locuser)+1);
  189.     (void)write(s, remuser, strlen(remuser)+1);
  190.     (void)write(s, cmd, strlen(cmd)+1);
  191.     if (read(s, &c, 1) != 1) {
  192.         (void)fprintf(stderr,
  193.             "rcmd: %s: %s\n", *ahost, strerror(errno));
  194.         goto bad2;
  195.     }
  196.     if (c != 0) {
  197.         while (read(s, &c, 1) == 1) {
  198.             (void)write(STDERR_FILENO, &c, 1);
  199.             if (c == '\n')
  200.                 break;
  201.         }
  202.         goto bad2;
  203.     }
  204.     sigsetmask(oldmask);
  205.     return (s);
  206. bad2:
  207.     if (lport)
  208.         (void)close(*fd2p);
  209. bad:
  210.     (void)close(s);
  211.     sigsetmask(oldmask);
  212.     return (-1);
  213. }
  214.  
  215. int
  216. rresvport(alport)
  217.     int *alport;
  218. {
  219.     struct sockaddr_in sin;
  220.     int s;
  221.  
  222.     sin.sin_len = sizeof(struct sockaddr_in);
  223.     sin.sin_family = AF_INET;
  224.     sin.sin_addr.s_addr = INADDR_ANY;
  225.     s = socket(AF_INET, SOCK_STREAM, 0);
  226.     if (s < 0)
  227.         return (-1);
  228.     for (;;) {
  229.         sin.sin_port = htons((u_short)*alport);
  230.         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  231.             return (s);
  232.         if (errno != EADDRINUSE) {
  233.             (void)close(s);
  234.             return (-1);
  235.         }
  236.         (*alport)--;
  237.         if (*alport == IPPORT_RESERVED/2) {
  238.             (void)close(s);
  239.             errno = EAGAIN;        /* close */
  240.             return (-1);
  241.         }
  242.     }
  243. }
  244.  
  245. int    __check_rhosts_file = 1;
  246. char    *__rcmd_errstr;
  247.  
  248. int
  249. ruserok(rhost, superuser, ruser, luser)
  250.     const char *rhost, *ruser, *luser;
  251.     int superuser;
  252. {
  253.     struct hostent *hp;
  254.     char **ap;
  255.     int i;
  256. #define MAXADDRS    35
  257.     u_long addrs[MAXADDRS + 1];
  258.  
  259.     if ((hp = gethostbyname(rhost)) == NULL)
  260.         return (-1);
  261.     for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i)
  262.         bcopy(*ap, &addrs[i], sizeof(addrs[i]));
  263.     addrs[i] = 0;
  264.  
  265.     for (i = 0; i < MAXADDRS && addrs[i]; i++)
  266.         if (iruserok(addrs[i], superuser, ruser, luser) == 0)
  267.             return (0);
  268.     return (-1);
  269. }
  270.  
  271. /*
  272.  * New .rhosts strategy: We are passed an ip address. We spin through
  273.  * hosts.equiv and .rhosts looking for a match. When the .rhosts only
  274.  * has ip addresses, we don't have to trust a nameserver.  When it
  275.  * contains hostnames, we spin through the list of addresses the nameserver
  276.  * gives us and look for a match.
  277.  *
  278.  * Returns 0 if ok, -1 if not ok.
  279.  */
  280. int
  281. iruserok(raddr, superuser, ruser, luser)
  282.     u_long raddr;
  283.     int superuser;
  284.     const char *ruser, *luser;
  285. {
  286.     register char *cp;
  287.     struct stat sbuf;
  288.     struct passwd *pwd;
  289.     FILE *hostf;
  290.     uid_t uid;
  291.     int first;
  292.     char pbuf[MAXPATHLEN];
  293.  
  294.     first = 1;
  295.     hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
  296. again:
  297.     if (hostf) {
  298.         if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
  299.             (void)fclose(hostf);
  300.             return (0);
  301.         }
  302.         (void)fclose(hostf);
  303.     }
  304.     if (first == 1 && (__check_rhosts_file || superuser)) {
  305.         first = 0;
  306.         if ((pwd = getpwnam(luser)) == NULL)
  307.             return (-1);
  308.         (void)strcpy(pbuf, pwd->pw_dir);
  309.         (void)strcat(pbuf, "/.rhosts");
  310.  
  311.         /*
  312.          * Change effective uid while opening .rhosts.  If root and
  313.          * reading an NFS mounted file system, can't read files that
  314.          * are protected read/write owner only.
  315.          */
  316.         uid = geteuid();
  317.         (void)seteuid(pwd->pw_uid);
  318.         hostf = fopen(pbuf, "r");
  319.         (void)seteuid(uid);
  320.  
  321.         if (hostf == NULL)
  322.             return (-1);
  323.         /*
  324.          * If not a regular file, or is owned by someone other than
  325.          * user or root or if writeable by anyone but the owner, quit.
  326.          */
  327.         cp = NULL;
  328.         if (lstat(pbuf, &sbuf) < 0)
  329.             cp = ".rhosts lstat failed";
  330.         else if (!S_ISREG(sbuf.st_mode))
  331.             cp = ".rhosts not regular file";
  332.         else if (fstat(fileno(hostf), &sbuf) < 0)
  333.             cp = ".rhosts fstat failed";
  334.         else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
  335.             cp = "bad .rhosts owner";
  336.         else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
  337.             cp = ".rhosts writeable by other than owner";
  338.         /* If there were any problems, quit. */
  339.         if (cp) {
  340.             __rcmd_errstr = cp;
  341.             (void)fclose(hostf);
  342.             return (-1);
  343.         }
  344.         goto again;
  345.     }
  346.     return (-1);
  347. }
  348.  
  349. /*
  350.  * XXX
  351.  * Don't make static, used by lpd(8).
  352.  *
  353.  * Returns 0 if ok, -1 if not ok.
  354.  */
  355. int
  356. __ivaliduser(hostf, raddr, luser, ruser)
  357.     FILE *hostf;
  358.     u_long raddr;
  359.     const char *luser, *ruser;
  360. {
  361.     register char *user, *p;
  362.     int ch;
  363.     char buf[MAXHOSTNAMELEN + 128];        /* host + login */
  364.     const char *auser, *ahost;
  365.     int hostok, userok;
  366.     char rhost[MAXHOSTNAMELEN];
  367.     struct hostent *hp;
  368.     char domain[MAXHOSTNAMELEN];
  369.  
  370.     getdomainname(domain, sizeof(domain));
  371.  
  372.     while (fgets(buf, sizeof(buf), hostf)) {
  373.         p = buf;
  374.         /* Skip lines that are too long. */
  375.         if (strchr(p, '\n') == NULL) {
  376.             while ((ch = getc(hostf)) != '\n' && ch != EOF);
  377.             continue;
  378.         }
  379.         while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
  380.             *p = isupper(*p) ? tolower(*p) : *p;
  381.             p++;
  382.         }
  383.         if (*p == ' ' || *p == '\t') {
  384.             *p++ = '\0';
  385.             while (*p == ' ' || *p == '\t')
  386.                 p++;
  387.             user = p;
  388.             while (*p != '\n' && *p != ' ' &&
  389.                 *p != '\t' && *p != '\0')
  390.                 p++;
  391.         } else
  392.             user = p;
  393.         *p = '\0';
  394.  
  395.         if (p == buf)
  396.             continue;
  397.  
  398.         auser = *user ? user : luser;
  399.         ahost = buf;
  400.  
  401.         if ((hp = gethostbyaddr((char *) &raddr,
  402.                     sizeof(raddr), AF_INET)) == NULL) {
  403.             abort();
  404.             return -1;
  405.         }
  406.         (void) strncpy(rhost, hp->h_name, sizeof(rhost));
  407.         rhost[sizeof(rhost) - 1] = '\0';
  408.  
  409.         if (ahost[0] == '+')
  410.             switch (ahost[1]) {
  411.             case '\0':
  412.                 hostok = 1;
  413.                 break;
  414.  
  415.             case '@':
  416.                 hostok = innetgr(&ahost[2], rhost, NULL,
  417.                          domain);
  418.                 break;
  419.  
  420.             default:
  421.                 hostok = __icheckhost(raddr, &ahost[1]);
  422.                 break;
  423.             }
  424.         else if (ahost[0] == '-')
  425.             switch (ahost[1]) {
  426.             case '\0':
  427.                 hostok = -1;
  428.                 break;
  429.  
  430.             case '@':
  431.                 hostok = -innetgr(&ahost[2], rhost, NULL,
  432.                           domain);
  433.                 break;
  434.  
  435.             default:
  436.                 hostok = -__icheckhost(raddr, &ahost[1]);
  437.                 break;
  438.             }
  439.         else
  440.             hostok = __icheckhost(raddr, ahost);
  441.  
  442.  
  443.         if (auser[0] == '+')
  444.             switch (auser[1]) {
  445.             case '\0':
  446.                 userok = 1;
  447.                 break;
  448.  
  449.             case '@':
  450.                 userok = innetgr(&auser[2], NULL, ruser,
  451.                          domain);
  452.                 break;
  453.  
  454.             default:
  455.                 userok = strcmp(ruser, &auser[1]) == 0;
  456.                 break;
  457.             }
  458.         else if (auser[0] == '-')
  459.             switch (auser[1]) {
  460.             case '\0':
  461.                 userok = -1;
  462.                 break;
  463.  
  464.             case '@':
  465.                 userok = -innetgr(&auser[2], NULL, ruser,
  466.                           domain);
  467.                 break;
  468.  
  469.             default:
  470.                 userok = -(strcmp(ruser, &auser[1]) == 0);
  471.                 break;
  472.             }
  473.         else
  474.             userok = strcmp(ruser, auser) == 0;
  475.  
  476.         /* Check if one component did not match */
  477.         if (hostok == 0 || userok == 0)
  478.             continue;
  479.  
  480.         /* Check if we got a forbidden pair */
  481.         if (userok == -1 || hostok == -1)
  482.             return -1;
  483.  
  484.         /* Check if we got a valid pair */
  485.         if (hostok == 1 && userok == 1)
  486.             return 0;
  487.     }
  488.     return -1;
  489. }
  490.  
  491. /*
  492.  * Returns "true" if match, 0 if no match.
  493.  */
  494. static int
  495. __icheckhost(raddr, lhost)
  496.     u_long raddr;
  497.     const char *lhost;
  498. {
  499.     register struct hostent *hp;
  500.     register u_long laddr;
  501.     register char **pp;
  502.  
  503.     /* Try for raw ip address first. */
  504.     if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
  505.         return (raddr == laddr);
  506.  
  507.     /* Better be a hostname. */
  508.     if ((hp = gethostbyname(lhost)) == NULL)
  509.         return (0);
  510.  
  511.     /* Spin through ip addresses. */
  512.     for (pp = hp->h_addr_list; *pp; ++pp)
  513.         if (!bcmp(&raddr, *pp, sizeof(u_long)))
  514.             return (1);
  515.  
  516.     /* No match. */
  517.     return (0);
  518. }
  519.