Back to index

glibc  2.9
rcmd.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 1998 WIDE Project.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the project nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 /*
00030  * Copyright (c) 1983, 1993, 1994
00031  *     The Regents of the University of California.  All rights reserved.
00032  *
00033  * Redistribution and use in source and binary forms, with or without
00034  * modification, are permitted provided that the following conditions
00035  * are met:
00036  * 1. Redistributions of source code must retain the above copyright
00037  *    notice, this list of conditions and the following disclaimer.
00038  * 2. Redistributions in binary form must reproduce the above copyright
00039  *    notice, this list of conditions and the following disclaimer in the
00040  *    documentation and/or other materials provided with the distribution.
00041  * 4. Neither the name of the University nor the names of its contributors
00042  *    may be used to endorse or promote products derived from this software
00043  *    without specific prior written permission.
00044  *
00045  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00046  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00047  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00048  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00049  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00050  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00051  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00052  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00053  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00054  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00055  * SUCH DAMAGE.
00056  */
00057 
00058 #if defined(LIBC_SCCS) && !defined(lint)
00059 static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
00060 #endif /* LIBC_SCCS and not lint */
00061 
00062 #include <sys/param.h>
00063 #include <sys/poll.h>
00064 #include <sys/socket.h>
00065 #include <sys/stat.h>
00066 
00067 #include <netinet/in.h>
00068 #include <arpa/inet.h>
00069 
00070 #include <alloca.h>
00071 #include <signal.h>
00072 #include <fcntl.h>
00073 #include <netdb.h>
00074 #include <unistd.h>
00075 #include <pwd.h>
00076 #include <errno.h>
00077 #include <stdio.h>
00078 #include <stdio_ext.h>
00079 #include <ctype.h>
00080 #include <string.h>
00081 #include <libintl.h>
00082 #include <stdlib.h>
00083 #include <wchar.h>
00084 #include <sys/uio.h>
00085 
00086 
00087 int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
00088 static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
00089                          const char *, const char *, const char *);
00090 static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
00091                      int superuser, const char *ruser,
00092                      const char *luser, const char *rhost);
00093 static int ruserok_sa (struct sockaddr *ra, size_t ralen,
00094                      int superuser, const char *ruser,
00095                      const char *luser);
00096 int iruserok_af (const void *raddr, int superuser, const char *ruser,
00097                const char *luser, sa_family_t af);
00098 int iruserok (u_int32_t raddr, int superuser, const char *ruser,
00099              const char *luser);
00100 
00101 libc_hidden_proto (iruserok_af)
00102 
00103 libc_freeres_ptr(static char *ahostbuf);
00104 
00105 int
00106 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
00107        char **ahost;
00108        u_short rport;
00109        const char *locuser, *remuser, *cmd;
00110        int *fd2p;
00111        sa_family_t af;
00112 {
00113        char paddr[INET6_ADDRSTRLEN];
00114        struct addrinfo hints, *res, *ai;
00115        struct sockaddr_storage from;
00116        struct pollfd pfd[2];
00117        int32_t oldmask;
00118        pid_t pid;
00119        int s, lport, timo, error;
00120        char c;
00121        int refused;
00122        char num[8];
00123        ssize_t n;
00124 
00125        if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
00126          {
00127            __set_errno (EAFNOSUPPORT);
00128            return -1;
00129          }
00130 
00131        pid = __getpid();
00132 
00133        memset(&hints, '\0', sizeof(hints));
00134        hints.ai_flags = AI_CANONNAME;
00135        hints.ai_family = af;
00136        hints.ai_socktype = SOCK_STREAM;
00137        (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
00138        error = getaddrinfo(*ahost, num, &hints, &res);
00139        if (error) {
00140               if (error == EAI_NONAME && *ahost != NULL)
00141                      __fxprintf(NULL, "%s: Unknown host\n", *ahost);
00142               else
00143                      __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
00144                                gai_strerror(error));
00145 
00146                 return -1;
00147        }
00148 
00149        pfd[0].events = POLLIN;
00150        pfd[1].events = POLLIN;
00151 
00152        if (res->ai_canonname){
00153               free (ahostbuf);
00154               ahostbuf = strdup (res->ai_canonname);
00155               if (ahostbuf == NULL) {
00156                      __fxprintf(NULL, "%s",
00157                                _("rcmd: Cannot allocate memory\n"));
00158                      return -1;
00159               }
00160               *ahost = ahostbuf;
00161        } else
00162               *ahost = NULL;
00163        ai = res;
00164        refused = 0;
00165        oldmask = __sigblock(sigmask(SIGURG));
00166        for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
00167               char errbuf[200];
00168 
00169               s = rresvport_af(&lport, ai->ai_family);
00170               if (s < 0) {
00171                      if (errno == EAGAIN)
00172                             __fxprintf(NULL, "%s", _("\
00173 rcmd: socket: All ports in use\n"));
00174                      else
00175                             __fxprintf(NULL, "rcmd: socket: %m\n");
00176 
00177                      __sigsetmask(oldmask);
00178                      freeaddrinfo(res);
00179                      return -1;
00180               }
00181               __fcntl(s, F_SETOWN, pid);
00182               if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
00183                      break;
00184               (void)__close(s);
00185               if (errno == EADDRINUSE) {
00186                      lport--;
00187                      continue;
00188               }
00189               if (errno == ECONNREFUSED)
00190                      refused = 1;
00191               if (ai->ai_next != NULL) {
00192                      int oerrno = errno;
00193                      char *buf = NULL;
00194 
00195                      getnameinfo(ai->ai_addr, ai->ai_addrlen,
00196                                 paddr, sizeof(paddr),
00197                                 NULL, 0,
00198                                 NI_NUMERICHOST);
00199 
00200                      if (__asprintf (&buf, _("connect to address %s: "),
00201                                    paddr) >= 0)
00202                        {
00203                          __fxprintf(NULL, "%s", buf);
00204                          free (buf);
00205                        }
00206                      __set_errno (oerrno);
00207                      perror(0);
00208                      ai = ai->ai_next;
00209                      getnameinfo(ai->ai_addr, ai->ai_addrlen,
00210                                 paddr, sizeof(paddr),
00211                                 NULL, 0,
00212                                 NI_NUMERICHOST);
00213                      if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
00214                        {
00215                          __fxprintf (NULL, "%s", buf);
00216                          free (buf);
00217                        }
00218                      continue;
00219               }
00220               if (refused && timo <= 16) {
00221                      (void)__sleep(timo);
00222                      timo *= 2;
00223                      ai = res;
00224                      refused = 0;
00225                      continue;
00226               }
00227               freeaddrinfo(res);
00228               (void)__fxprintf(NULL, "%s: %s\n", *ahost,
00229                              __strerror_r(errno, errbuf, sizeof (errbuf)));
00230               __sigsetmask(oldmask);
00231               return -1;
00232        }
00233        lport--;
00234        if (fd2p == 0) {
00235               __write(s, "", 1);
00236               lport = 0;
00237        } else {
00238               char num[8];
00239               int s2 = rresvport_af(&lport, ai->ai_family), s3;
00240               socklen_t len = ai->ai_addrlen;
00241 
00242               if (s2 < 0)
00243                      goto bad;
00244               __listen(s2, 1);
00245               (void)__snprintf(num, sizeof(num), "%d", lport);
00246               if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
00247                      char *buf = NULL;
00248 
00249                      if (__asprintf (&buf, _("\
00250 rcmd: write (setting up stderr): %m\n")) >= 0)
00251                        {
00252                          __fxprintf(NULL, "%s", buf);
00253                          free (buf);
00254                        }
00255                      (void)__close(s2);
00256                      goto bad;
00257               }
00258               pfd[0].fd = s;
00259               pfd[1].fd = s2;
00260               __set_errno (0);
00261               if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
00262                      char *buf = NULL;
00263 
00264                      if ((errno != 0
00265                           && __asprintf(&buf, _("\
00266 rcmd: poll (setting up stderr): %m\n")) >= 0)
00267                          || (errno == 0
00268                             && __asprintf(&buf, _("\
00269 poll: protocol failure in circuit setup\n")) >= 0))
00270                        {
00271                          __fxprintf (NULL, "%s", buf);
00272                          free  (buf);
00273                        }
00274                      (void)__close(s2);
00275                      goto bad;
00276               }
00277               s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
00278                                           &len));
00279               switch (from.ss_family) {
00280               case AF_INET:
00281                      rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
00282                      break;
00283               case AF_INET6:
00284                      rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
00285                      break;
00286               default:
00287                      rport = 0;
00288                      break;
00289               }
00290               (void)__close(s2);
00291               if (s3 < 0) {
00292                      (void)__fxprintf(NULL, "rcmd: accept: %m\n");
00293                      lport = 0;
00294                      goto bad;
00295               }
00296               *fd2p = s3;
00297 
00298               if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
00299                      char *buf = NULL;
00300 
00301                      if (__asprintf(&buf, _("\
00302 socket: protocol failure in circuit setup\n")) >= 0)
00303                        {
00304                          __fxprintf (NULL, "%s", buf);
00305                          free (buf);
00306                        }
00307                      goto bad2;
00308               }
00309        }
00310        struct iovec iov[3] =
00311          {
00312            [0] = { .iov_base = (void *) locuser,
00313                   .iov_len = strlen (locuser) + 1 },
00314            [1] = { .iov_base = (void *) remuser,
00315                   .iov_len = strlen (remuser) + 1 },
00316            [2] = { .iov_base = (void *) cmd,
00317                   .iov_len = strlen (cmd) + 1 }
00318          };
00319        (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
00320        n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
00321        if (n != 1) {
00322               char *buf = NULL;
00323 
00324               if ((n == 0
00325                    && __asprintf(&buf, _("rcmd: %s: short read"),
00326                                *ahost) >= 0)
00327                   || (n != 0
00328                      && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
00329                 {
00330                   __fxprintf (NULL, "%s", buf);
00331                   free (buf);
00332                 }
00333               goto bad2;
00334        }
00335        if (c != 0) {
00336               while (__read(s, &c, 1) == 1) {
00337                      (void)__write(STDERR_FILENO, &c, 1);
00338                      if (c == '\n')
00339                             break;
00340               }
00341               goto bad2;
00342        }
00343        __sigsetmask(oldmask);
00344        freeaddrinfo(res);
00345        return s;
00346 bad2:
00347        if (lport)
00348               (void)__close(*fd2p);
00349 bad:
00350        (void)__close(s);
00351        __sigsetmask(oldmask);
00352        freeaddrinfo(res);
00353        return -1;
00354 }
00355 libc_hidden_def (rcmd_af)
00356 
00357 int
00358 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
00359        char **ahost;
00360        u_short rport;
00361        const char *locuser, *remuser, *cmd;
00362        int *fd2p;
00363 {
00364   return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
00365 }
00366 
00367 int
00368 rresvport_af(alport, family)
00369        int *alport;
00370        sa_family_t family;
00371 {
00372        struct sockaddr_storage ss;
00373        int s;
00374        size_t len;
00375        uint16_t *sport;
00376 
00377        switch(family){
00378        case AF_INET:
00379               len = sizeof(struct sockaddr_in);
00380               sport = &((struct sockaddr_in *)&ss)->sin_port;
00381               break;
00382        case AF_INET6:
00383               len = sizeof(struct sockaddr_in6);
00384               sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
00385               break;
00386        default:
00387               __set_errno (EAFNOSUPPORT);
00388               return -1;
00389        }
00390        s = __socket(family, SOCK_STREAM, 0);
00391        if (s < 0)
00392               return -1;
00393 
00394        memset (&ss, '\0', sizeof(ss));
00395 #ifdef SALEN
00396        ss.__ss_len = len;
00397 #endif
00398        ss.ss_family = family;
00399 
00400        /* Ignore invalid values.  */
00401        if (*alport < IPPORT_RESERVED / 2)
00402               *alport = IPPORT_RESERVED / 2;
00403        else if (*alport >= IPPORT_RESERVED)
00404               *alport = IPPORT_RESERVED - 1;
00405 
00406        int start = *alport;
00407        do {
00408               *sport = htons((uint16_t) *alport);
00409               if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
00410                      return s;
00411               if (errno != EADDRINUSE) {
00412                      (void)__close(s);
00413                      return -1;
00414               }
00415               if ((*alport)-- == IPPORT_RESERVED/2)
00416                      *alport = IPPORT_RESERVED - 1;
00417        } while (*alport != start);
00418        (void)__close(s);
00419        __set_errno (EAGAIN);
00420        return -1;
00421 }
00422 libc_hidden_def (rresvport_af)
00423 
00424 int
00425 rresvport(alport)
00426        int *alport;
00427 {
00428        return rresvport_af(alport, AF_INET);
00429 }
00430 
00431 int    __check_rhosts_file = 1;
00432 char   *__rcmd_errstr;
00433 
00434 int
00435 ruserok_af(rhost, superuser, ruser, luser, af)
00436        const char *rhost, *ruser, *luser;
00437        int superuser;
00438        sa_family_t af;
00439 {
00440        struct addrinfo hints, *res, *res0;
00441        int gai;
00442        int ret;
00443 
00444        memset (&hints, '\0', sizeof(hints));
00445        hints.ai_family = af;
00446        gai = getaddrinfo(rhost, NULL, &hints, &res0);
00447        if (gai)
00448               return -1;
00449        ret = -1;
00450        for (res=res0; res; res=res->ai_next)
00451               if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
00452                             superuser, ruser, luser, rhost) == 0){
00453                      ret = 0;
00454                      break;
00455               }
00456        freeaddrinfo(res0);
00457        return (ret);
00458 }
00459 libc_hidden_def (ruserok_af)
00460 
00461 int
00462 ruserok(rhost, superuser, ruser, luser)
00463        const char *rhost, *ruser, *luser;
00464        int superuser;
00465 {
00466        return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
00467 }
00468 
00469 /* Extremely paranoid file open function. */
00470 static FILE *
00471 iruserfopen (const char *file, uid_t okuser)
00472 {
00473   struct stat64 st;
00474   char *cp = NULL;
00475   FILE *res = NULL;
00476 
00477   /* If not a regular file, if owned by someone other than user or
00478      root, if writeable by anyone but the owner, or if hardlinked
00479      anywhere, quit.  */
00480   if (__lxstat64 (_STAT_VER, file, &st))
00481     cp = _("lstat failed");
00482   else if (!S_ISREG (st.st_mode))
00483     cp = _("not regular file");
00484   else
00485     {
00486       res = fopen (file, "rc");
00487       if (!res)
00488        cp = _("cannot open");
00489       else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
00490        cp = _("fstat failed");
00491       else if (st.st_uid && st.st_uid != okuser)
00492        cp = _("bad owner");
00493       else if (st.st_mode & (S_IWGRP|S_IWOTH))
00494        cp = _("writeable by other than owner");
00495       else if (st.st_nlink > 1)
00496        cp = _("hard linked somewhere");
00497     }
00498 
00499   /* If there were any problems, quit.  */
00500   if (cp != NULL)
00501     {
00502       __rcmd_errstr = cp;
00503       if (res)
00504        fclose (res);
00505       return NULL;
00506     }
00507 
00508   /* No threads use this stream.  */
00509   __fsetlocking (res, FSETLOCKING_BYCALLER);
00510 
00511   return res;
00512 }
00513 
00514 /*
00515  * New .rhosts strategy: We are passed an ip address. We spin through
00516  * hosts.equiv and .rhosts looking for a match. When the .rhosts only
00517  * has ip addresses, we don't have to trust a nameserver.  When it
00518  * contains hostnames, we spin through the list of addresses the nameserver
00519  * gives us and look for a match.
00520  *
00521  * Returns 0 if ok, -1 if not ok.
00522  */
00523 static int
00524 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
00525      struct sockaddr *ra;
00526      size_t ralen;
00527      int superuser;
00528      const char *ruser, *luser, *rhost;
00529 {
00530   FILE *hostf = NULL;
00531   int isbad = -1;
00532 
00533   if (!superuser)
00534     hostf = iruserfopen (_PATH_HEQUIV, 0);
00535 
00536   if (hostf)
00537     {
00538       isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
00539       fclose (hostf);
00540 
00541       if (!isbad)
00542        return 0;
00543     }
00544 
00545   if (__check_rhosts_file || superuser)
00546     {
00547       char *pbuf;
00548       struct passwd pwdbuf, *pwd;
00549       size_t dirlen;
00550       size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
00551       char *buffer = __alloca (buflen);
00552       uid_t uid;
00553 
00554       if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
00555          || pwd == NULL)
00556        return -1;
00557 
00558       dirlen = strlen (pwd->pw_dir);
00559       pbuf = alloca (dirlen + sizeof "/.rhosts");
00560       __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
00561                "/.rhosts", sizeof "/.rhosts");
00562 
00563        /* Change effective uid while reading .rhosts.  If root and
00564          reading an NFS mounted file system, can't read files that
00565          are protected read/write owner only.  */
00566        uid = __geteuid ();
00567        seteuid (pwd->pw_uid);
00568        hostf = iruserfopen (pbuf, pwd->pw_uid);
00569 
00570        if (hostf != NULL)
00571         {
00572            isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
00573            fclose (hostf);
00574         }
00575 
00576        seteuid (uid);
00577        return isbad;
00578     }
00579   return -1;
00580 }
00581 /*
00582  * ruserok_sa() is now discussed on ipng, so
00583  * currently disabled for external use
00584  */
00585 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
00586      struct sockaddr *ra;
00587      size_t ralen;
00588      int superuser;
00589      const char *ruser, *luser;
00590 {
00591   return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
00592 }
00593 
00594 /* This is the exported version.  */
00595 int
00596 iruserok_af (raddr, superuser, ruser, luser, af)
00597      const void *raddr;
00598      int superuser;
00599      const char *ruser, *luser;
00600      sa_family_t af;
00601 {
00602   struct sockaddr_storage ra;
00603   size_t ralen;
00604 
00605   memset (&ra, '\0', sizeof(ra));
00606   switch (af){
00607   case AF_INET:
00608     ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
00609     memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
00610            sizeof(struct in_addr));
00611     ralen = sizeof(struct sockaddr_in);
00612     break;
00613   case AF_INET6:
00614     ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
00615     memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
00616             sizeof(struct in6_addr));
00617     ralen = sizeof(struct sockaddr_in6);
00618     break;
00619   default:
00620     return 0;
00621   }
00622   return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
00623 }
00624 libc_hidden_def (iruserok_af)
00625 
00626 int
00627 iruserok (raddr, superuser, ruser, luser)
00628      u_int32_t raddr;
00629      int superuser;
00630      const char *ruser, *luser;
00631 {
00632   return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
00633 }
00634 
00635 /*
00636  * XXX
00637  * Don't make static, used by lpd(8).
00638  *
00639  * This function is not used anymore. It is only present because lpd(8)
00640  * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
00641  * argument. This means that netgroups won't work in .rhost/hosts.equiv
00642  * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
00643  * or PAM.
00644  * Returns 0 if ok, -1 if not ok.
00645  */
00646 int
00647 __ivaliduser(hostf, raddr, luser, ruser)
00648        FILE *hostf;
00649        u_int32_t raddr;
00650        const char *luser, *ruser;
00651 {
00652        struct sockaddr_in ra;
00653        memset(&ra, '\0', sizeof(ra));
00654        ra.sin_family = AF_INET;
00655        ra.sin_addr.s_addr = raddr;
00656        return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
00657                             luser, ruser, "-");
00658 }
00659 
00660 
00661 /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
00662 static int
00663 internal_function
00664 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
00665               const char *rhost)
00666 {
00667        struct addrinfo hints, *res0, *res;
00668        char raddr[INET6_ADDRSTRLEN];
00669        int match;
00670        int negate=1;    /* Multiply return with this to get -1 instead of 1 */
00671 
00672        /* Check nis netgroup.  */
00673        if (strncmp ("+@", lhost, 2) == 0)
00674               return innetgr (&lhost[2], rhost, NULL, NULL);
00675 
00676        if (strncmp ("-@", lhost, 2) == 0)
00677               return -innetgr (&lhost[2], rhost, NULL, NULL);
00678 
00679        /* -host */
00680        if (strncmp ("-", lhost,1) == 0) {
00681               negate = -1;
00682               lhost++;
00683        } else if (strcmp ("+",lhost) == 0) {
00684               return 1;                    /* asking for trouble, but ok.. */
00685        }
00686 
00687        /* Try for raw ip address first. */
00688        /* XXX */
00689        if (getnameinfo(ra, ralen,
00690                      raddr, sizeof(raddr), NULL, 0,
00691                      NI_NUMERICHOST) == 0
00692            && strcmp(raddr, lhost) == 0)
00693               return negate;
00694 
00695        /* Better be a hostname. */
00696        match = 0;
00697        memset(&hints, '\0', sizeof(hints));
00698        hints.ai_family = ra->sa_family;
00699        if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
00700               /* Spin through ip addresses. */
00701               for (res = res0; res; res = res->ai_next)
00702                 {
00703                   if (res->ai_family == ra->sa_family
00704                      && !memcmp(res->ai_addr, ra, res->ai_addrlen))
00705                     {
00706                      match = 1;
00707                      break;
00708                     }
00709                 }
00710               freeaddrinfo (res0);
00711        }
00712        return negate * match;
00713 }
00714 
00715 /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
00716 static int
00717 internal_function
00718 __icheckuser (const char *luser, const char *ruser)
00719 {
00720     /*
00721       luser is user entry from .rhosts/hosts.equiv file
00722       ruser is user id on remote host
00723       */
00724 
00725     /* [-+]@netgroup */
00726     if (strncmp ("+@", luser, 2) == 0)
00727        return innetgr (&luser[2], NULL, ruser, NULL);
00728 
00729     if (strncmp ("-@", luser,2) == 0)
00730        return -innetgr (&luser[2], NULL, ruser, NULL);
00731 
00732     /* -user */
00733     if (strncmp ("-", luser, 1) == 0)
00734        return -(strcmp (&luser[1], ruser) == 0);
00735 
00736     /* + */
00737     if (strcmp ("+", luser) == 0)
00738        return 1;
00739 
00740     /* simple string match */
00741     return strcmp (ruser, luser) == 0;
00742 }
00743 
00744 /*
00745  * Returns 1 for blank lines (or only comment lines) and 0 otherwise
00746  */
00747 static int
00748 __isempty (char *p)
00749 {
00750     while (*p && isspace (*p)) {
00751        ++p;
00752     }
00753 
00754     return (*p == '\0' || *p == '#') ? 1 : 0 ;
00755 }
00756 
00757 /*
00758  * Returns 0 if positive match, -1 if _not_ ok.
00759  */
00760 static int
00761 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
00762        FILE *hostf;
00763        struct sockaddr *ra;
00764        size_t ralen;
00765        const char *luser, *ruser, *rhost;
00766 {
00767     register const char *user;
00768     register char *p;
00769     int hcheck, ucheck;
00770     char *buf = NULL;
00771     size_t bufsize = 0;
00772     int retval = -1;
00773 
00774     while (__getline (&buf, &bufsize, hostf) > 0) {
00775        buf[bufsize - 1] = '\0'; /* Make sure it's terminated.  */
00776         p = buf;
00777 
00778        /* Skip empty or comment lines */
00779        if (__isempty (p)) {
00780            continue;
00781        }
00782 
00783        for (;*p && !isspace(*p); ++p) {
00784            *p = _tolower (*p);
00785        }
00786 
00787        /* Next we want to find the permitted name for the remote user.  */
00788        if (*p == ' ' || *p == '\t') {
00789            /* <nul> terminate hostname and skip spaces */
00790            for (*p++='\0'; *p && isspace (*p); ++p);
00791 
00792            user = p;                   /* this is the user's name */
00793            while (*p && !isspace (*p))
00794               ++p;                    /* find end of user's name */
00795        } else
00796            user = p;
00797 
00798        *p = '\0';              /* <nul> terminate username (+host?) */
00799 
00800        /* buf -> host(?) ; user -> username(?) */
00801 
00802        /* First check host part */
00803        hcheck = __checkhost_sa (ra, ralen, buf, rhost);
00804 
00805        if (hcheck < 0)
00806            break;
00807 
00808        if (hcheck) {
00809            /* Then check user part */
00810            if (! (*user))
00811               user = luser;
00812 
00813            ucheck = __icheckuser (user, ruser);
00814 
00815            /* Positive 'host user' match? */
00816            if (ucheck > 0) {
00817               retval = 0;
00818               break;
00819            }
00820 
00821            /* Negative 'host -user' match? */
00822            if (ucheck < 0)
00823               break;
00824 
00825            /* Neither, go on looking for match */
00826        }
00827     }
00828 
00829     free (buf);
00830 
00831     return retval;
00832 }