(linenum→info "unix/slp.c:2238")

glibc/2.7/inet/rcmd.c

    1: /*
    2:  * Copyright (C) 1998 WIDE Project.
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. Neither the name of the project nor the names of its contributors
   14:  *    may be used to endorse or promote products derived from this software
   15:  *    without specific prior written permission.
   16:  *
   17:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27:  * SUCH DAMAGE.
   28:  */
   29: /*
   30:  * Copyright (c) 1983, 1993, 1994
   31:  *      The Regents of the University of California.  All rights reserved.
   32:  *
   33:  * Redistribution and use in source and binary forms, with or without
   34:  * modification, are permitted provided that the following conditions
   35:  * are met:
   36:  * 1. Redistributions of source code must retain the above copyright
   37:  *    notice, this list of conditions and the following disclaimer.
   38:  * 2. Redistributions in binary form must reproduce the above copyright
   39:  *    notice, this list of conditions and the following disclaimer in the
   40:  *    documentation and/or other materials provided with the distribution.
   41:  * 4. Neither the name of the University nor the names of its contributors
   42:  *    may be used to endorse or promote products derived from this software
   43:  *    without specific prior written permission.
   44:  *
   45:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   46:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   47:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   48:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   49:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   50:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   51:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   52:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   53:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   54:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   55:  * SUCH DAMAGE.
   56:  */
   57: 
   58: #if defined(LIBC_SCCS) && !defined(lint)
   59: static char sccsid[] = "@(#)rcmd.c      8.3 (Berkeley) 3/26/94";
   60: #endif /* LIBC_SCCS and not lint */
   61: 
   62: #include <sys/param.h>
   63: #include <sys/poll.h>
   64: #include <sys/socket.h>
   65: #include <sys/stat.h>
   66: 
   67: #include <netinet/in.h>
   68: #include <arpa/inet.h>
   69: 
   70: #include <alloca.h>
   71: #include <signal.h>
   72: #include <fcntl.h>
   73: #include <netdb.h>
   74: #include <unistd.h>
   75: #include <pwd.h>
   76: #include <errno.h>
   77: #include <stdio.h>
   78: #include <stdio_ext.h>
   79: #include <ctype.h>
   80: #include <string.h>
   81: #include <libintl.h>
   82: #include <stdlib.h>
   83: #include <wchar.h>
   84: #include <sys/uio.h>
   85: 
   86: 
   87: int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
   88: static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
   89:                             const char *, const char *, const char *);
   90: static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
   91:                         int superuser, const char *ruser,
   92:                         const char *luser, const char *rhost);
   93: static int ruserok_sa (struct sockaddr *ra, size_t ralen,
   94:                         int superuser, const char *ruser,
   95:                         const char *luser);
   96: int iruserok_af (const void *raddr, int superuser, const char *ruser,
   97:                  const char *luser, sa_family_t af);
   98: int iruserok (u_int32_t raddr, int superuser, const char *ruser,
   99:               const char *luser);
  100: 
  101: libc_hidden_proto (iruserok_af)
  102: 
  103: libc_freeres_ptr(static char *ahostbuf);
  104: 
  105: int
  106: rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
  107:         char **ahost;
  108:         u_short rport;
  109:         const char *locuser, *remuser, *cmd;
  110:         int *fd2p;
  111:         sa_family_t af;
  112: {
  113:         char paddr[INET6_ADDRSTRLEN];
  114:         struct addrinfo hints, *res, *ai;
  115:         struct sockaddr_storage from;
  116:         struct pollfd pfd[2];
  117:         int32_t oldmask;
  118:         pid_t pid;
  119:         int s, lport, timo, error;
  120:         char c;
  121:         int refused;
  122:         char num[8];
  123:         ssize_t n;
  124: 
  125:         if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
  126:           {
  127:             __set_errno (EAFNOSUPPORT);
  128:             return -1;
  129:           }
  130: 
  131:         pid = __getpid();
  132: 
  133:         memset(&hints, '\0', sizeof(hints));
  134:         hints.ai_flags = AI_CANONNAME;
  135:         hints.ai_family = af;
  136:         hints.ai_socktype = SOCK_STREAM;
  137:         (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
  138:         error = getaddrinfo(*ahost, num, &hints, &res);
  139:         if (error) {
  140:                 if (error == EAI_NONAME && *ahost != NULL)
  141:                         __fxprintf(NULL, "%s: Unknown host\n", *ahost);
  142:                 else
  143:                         __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
  144:                                    gai_strerror(error));
  145: 
  146:                 return -1;
  147:         }
  148: 
  149:         pfd[0].events = POLLIN;
  150:         pfd[1].events = POLLIN;
  151: 
  152:         if (res->ai_canonname){
  153:                 free (ahostbuf);
  154:                 ahostbuf = strdup (res->ai_canonname);
  155:                 if (ahostbuf == NULL) {
  156:                         __fxprintf(NULL, "%s",
  157:                                    _("rcmd: Cannot allocate memory\n"));
  158:                         return -1;
  159:                 }
  160:                 *ahost = ahostbuf;
  161:         } else
  162:                 *ahost = NULL;
  163:         ai = res;
  164:         refused = 0;
  165:         oldmask = __sigblock(sigmask(SIGURG));
  166:         for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
  167:                 char errbuf[200];
  168: 
  169:                 s = rresvport_af(&lport, ai->ai_family);
  170:                 if (s < 0) {
  171:                         if (errno == EAGAIN)
  172:                                 __fxprintf(NULL, "%s", _("\
  173: rcmd: socket: All ports in use\n"));
  174:                         else
  175:                                 __fxprintf(NULL, "rcmd: socket: %m\n");
  176: 
  177:                         __sigsetmask(oldmask);
  178:                         freeaddrinfo(res);
  179:                         return -1;
  180:                 }
  181:                 __fcntl(s, F_SETOWN, pid);
  182:                 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
  183:                         break;
  184:                 (void)__close(s);
  185:                 if (errno == EADDRINUSE) {
  186:                         lport--;
  187:                         continue;
  188:                 }
  189:                 if (errno == ECONNREFUSED)
  190:                         refused = 1;
  191:                 if (ai->ai_next != NULL) {
  192:                         int oerrno = errno;
  193:                         char *buf = NULL;
  194: 
  195:                         getnameinfo(ai->ai_addr, ai->ai_addrlen,
  196:                                     paddr, sizeof(paddr),
  197:                                     NULL, 0,
  198:                                     NI_NUMERICHOST);
  199: 
  200:                         if (__asprintf (&buf, _("connect to address %s: "),
  201:                                         paddr) >= 0)
  202:                           {
  203:                             __fxprintf(NULL, "%s", buf);
  204:                             free (buf);
  205:                           }
  206:                         __set_errno (oerrno);
  207:                         perror(0);
  208:                         ai = ai->ai_next;
  209:                         getnameinfo(ai->ai_addr, ai->ai_addrlen,
  210:                                     paddr, sizeof(paddr),
  211:                                     NULL, 0,
  212:                                     NI_NUMERICHOST);
  213:                         if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
  214:                           {
  215:                             __fxprintf (NULL, "%s", buf);
  216:                             free (buf);
  217:                           }
  218:                         continue;
  219:                 }
  220:                 if (refused && timo <= 16) {
  221:                         (void)__sleep(timo);
  222:                         timo *= 2;
  223:                         ai = res;
  224:                         refused = 0;
  225:                         continue;
  226:                 }
  227:                 freeaddrinfo(res);
  228:                 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
  229:                                  __strerror_r(errno, errbuf, sizeof (errbuf)));
  230:                 __sigsetmask(oldmask);
  231:                 return -1;
  232:         }
  233:         lport--;
  234:         if (fd2p == 0) {
  235:                 __write(s, "", 1);
  236:                 lport = 0;
  237:         } else {
  238:                 char num[8];
  239:                 int s2 = rresvport_af(&lport, ai->ai_family), s3;
  240:                 socklen_t len = ai->ai_addrlen;
  241: 
  242:                 if (s2 < 0)
  243:                         goto bad;
  244:                 __listen(s2, 1);
  245:                 (void)__snprintf(num, sizeof(num), "%d", lport);
  246:                 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
  247:                         char *buf = NULL;
  248: 
  249:                         if (__asprintf (&buf, _("\
  250: rcmd: write (setting up stderr): %m\n")) >= 0)
  251:                           {
  252:                             __fxprintf(NULL, "%s", buf);
  253:                             free (buf);
  254:                           }
  255:                         (void)__close(s2);
  256:                         goto bad;
  257:                 }
  258:                 pfd[0].fd = s;
  259:                 pfd[1].fd = s2;
  260:                 __set_errno (0);
  261:                 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
  262:                         char *buf = NULL;
  263: 
  264:                         if ((errno != 0
  265:                              && __asprintf(&buf, _("\
  266: rcmd: poll (setting up stderr): %m\n")) >= 0)
  267:                             || (errno == 0
  268:                                 && __asprintf(&buf, _("\
  269: poll: protocol failure in circuit setup\n")) >= 0))
  270:                           {
  271:                             __fxprintf (NULL, "%s", buf);
  272:                             free  (buf);
  273:                           }
  274:                         (void)__close(s2);
  275:                         goto bad;
  276:                 }
  277:                 s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
  278:                                                 &len));
  279:                 switch (from.ss_family) {
  280:                 case AF_INET:
  281:                         rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
  282:                         break;
  283:                 case AF_INET6:
  284:                         rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
  285:                         break;
  286:                 default:
  287:                         rport = 0;
  288:                         break;
  289:                 }
  290:                 (void)__close(s2);
  291:                 if (s3 < 0) {
  292:                         (void)__fxprintf(NULL, "rcmd: accept: %m\n");
  293:                         lport = 0;
  294:                         goto bad;
  295:                 }
  296:                 *fd2p = s3;
  297: 
  298:                 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
  299:                         char *buf = NULL;
  300: 
  301:                         if (__asprintf(&buf, _("\
  302: socket: protocol failure in circuit setup\n")) >= 0)
  303:                           {
  304:                             __fxprintf (NULL, "%s", buf);
  305:                             free (buf);
  306:                           }
  307:                         goto bad2;
  308:                 }
  309:         }
  310:         struct iovec iov[3] =
  311:           {
  312:             [0] = { .iov_base = (void *) locuser,
  313:                     .iov_len = strlen (locuser) + 1 },
  314:             [1] = { .iov_base = (void *) remuser,
  315:                     .iov_len = strlen (remuser) + 1 },
  316:             [2] = { .iov_base = (void *) cmd,
  317:                     .iov_len = strlen (cmd) + 1 }
  318:           };
  319:         (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
  320:         n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
  321:         if (n != 1) {
  322:                 char *buf = NULL;
  323: 
  324:                 if ((n == 0
  325:                      && __asprintf(&buf, _("rcmd: %s: short read"),
  326:                                    *ahost) >= 0)
  327:                     || (n != 0
  328:                         && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
  329:                   {
  330:                     __fxprintf (NULL, "%s", buf);
  331:                     free (buf);
  332:                   }
  333:                 goto bad2;
  334:         }
  335:         if (c != 0) {
  336:                 while (__read(s, &c, 1) == 1) {
  337:                         (void)__write(STDERR_FILENO, &c, 1);
  338:                         if (c == '\n')
  339:                                 break;
  340:                 }
  341:                 goto bad2;
  342:         }
  343:         __sigsetmask(oldmask);
  344:         freeaddrinfo(res);
  345:         return s;
  346: bad2:
  347:         if (lport)
  348:                 (void)__close(*fd2p);
  349: bad:
  350:         (void)__close(s);
  351:         __sigsetmask(oldmask);
  352:         freeaddrinfo(res);
  353:         return -1;
  354: }
  355: libc_hidden_def (rcmd_af)
  356: 
  357: int
  358: rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
  359:         char **ahost;
  360:         u_short rport;
  361:         const char *locuser, *remuser, *cmd;
  362:         int *fd2p;
  363: {
  364:   return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
  365: }
  366: 
  367: int
  368: rresvport_af(alport, family)
  369:         int *alport;
  370:         sa_family_t family;
  371: {
  372:         struct sockaddr_storage ss;
  373:         int s;
  374:         size_t len;
  375:         uint16_t *sport;
  376: 
  377:         switch(family){
  378:         case AF_INET:
  379:                 len = sizeof(struct sockaddr_in);
  380:                 sport = &((struct sockaddr_in *)&ss)->sin_port;
  381:                 break;
  382:         case AF_INET6:
  383:                 len = sizeof(struct sockaddr_in6);
  384:                 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
  385:                 break;
  386:         default:
  387:                 __set_errno (EAFNOSUPPORT);
  388:                 return -1;
  389:         }
  390:         s = __socket(family, SOCK_STREAM, 0);
  391:         if (s < 0)
  392:                 return -1;
  393: 
  394:         memset (&ss, '\0', sizeof(ss));
  395: #ifdef SALEN
  396:         ss.__ss_len = len;
  397: #endif
  398:         ss.ss_family = family;
  399: 
  400:         /* Ignore invalid values.  */
  401:         if (*alport < IPPORT_RESERVED / 2)
  402:                 *alport = IPPORT_RESERVED / 2;
  403:         else if (*alport >= IPPORT_RESERVED)
  404:                 *alport = IPPORT_RESERVED - 1;
  405: 
  406:         int start = *alport;
  407:         do {
  408:                 *sport = htons((uint16_t) *alport);
  409:                 if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
  410:                         return s;
  411:                 if (errno != EADDRINUSE) {
  412:                         (void)__close(s);
  413:                         return -1;
  414:                 }
  415:                 if ((*alport)-- == IPPORT_RESERVED/2)
  416:                         *alport = IPPORT_RESERVED - 1;
  417:         } while (*alport != start);
  418:         (void)__close(s);
  419:         __set_errno (EAGAIN);
  420:         return -1;
  421: }
  422: libc_hidden_def (rresvport_af)
  423: 
  424: int
  425: rresvport(alport)
  426:         int *alport;
  427: {
  428:         return rresvport_af(alport, AF_INET);
  429: }
  430: 
  431: int     __check_rhosts_file = 1;
  432: char    *__rcmd_errstr;
  433: 
  434: int
  435: ruserok_af(rhost, superuser, ruser, luser, af)
  436:         const char *rhost, *ruser, *luser;
  437:         int superuser;
  438:         sa_family_t af;
  439: {
  440:         struct addrinfo hints, *res, *res0;
  441:         int gai;
  442:         int ret;
  443: 
  444:         memset (&hints, '\0', sizeof(hints));
  445:         hints.ai_family = af;
  446:         gai = getaddrinfo(rhost, NULL, &hints, &res0);
  447:         if (gai)
  448:                 return -1;
  449:         ret = -1;
  450:         for (res=res0; res; res=res->ai_next)
  451:                 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
  452:                                 superuser, ruser, luser, rhost) == 0){
  453:                         ret = 0;
  454:                         break;
  455:                 }
  456:         freeaddrinfo(res0);
  457:         return (ret);
  458: }
  459: libc_hidden_def (ruserok_af)
  460: 
  461: int
  462: ruserok(rhost, superuser, ruser, luser)
  463:         const char *rhost, *ruser, *luser;
  464:         int superuser;
  465: {
  466:         return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
  467: }
  468: 
  469: /* Extremely paranoid file open function. */
  470: static FILE *
  471: iruserfopen (const char *file, uid_t okuser)
  472: {
  473:   struct stat64 st;
  474:   char *cp = NULL;
  475:   FILE *res = NULL;
  476: 
  477:   /* If not a regular file, if owned by someone other than user or
  478:      root, if writeable by anyone but the owner, or if hardlinked
  479:      anywhere, quit.  */
  480:   if (__lxstat64 (_STAT_VER, file, &st))
  481:     cp = _("lstat failed");
  482:   else if (!S_ISREG (st.st_mode))
  483:     cp = _("not regular file");
  484:   else
  485:     {
  486:       res = fopen (file, "rc");
  487:       if (!res)
  488:         cp = _("cannot open");
  489:       else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
  490:         cp = _("fstat failed");
  491:       else if (st.st_uid && st.st_uid != okuser)
  492:         cp = _("bad owner");
  493:       else if (st.st_mode & (S_IWGRP|S_IWOTH))
  494:         cp = _("writeable by other than owner");
  495:       else if (st.st_nlink > 1)
  496:         cp = _("hard linked somewhere");
  497:     }
  498: 
  499:   /* If there were any problems, quit.  */
  500:   if (cp != NULL)
  501:     {
  502:       __rcmd_errstr = cp;
  503:       if (res)
  504:         fclose (res);
  505:       return NULL;
  506:     }
  507: 
  508:   /* No threads use this stream.  */
  509:   __fsetlocking (res, FSETLOCKING_BYCALLER);
  510: 
  511:   return res;
  512: }
  513: 
  514: /*
  515:  * New .rhosts strategy: We are passed an ip address. We spin through
  516:  * hosts.equiv and .rhosts looking for a match. When the .rhosts only
  517:  * has ip addresses, we don't have to trust a nameserver.  When it
  518:  * contains hostnames, we spin through the list of addresses the nameserver
  519:  * gives us and look for a match.
  520:  *
  521:  * Returns 0 if ok, -1 if not ok.
  522:  */
  523: static int
  524: ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
  525:      struct sockaddr *ra;
  526:      size_t ralen;
  527:      int superuser;
  528:      const char *ruser, *luser, *rhost;
  529: {
  530:   FILE *hostf = NULL;
  531:   int isbad = -1;
  532: 
  533:   if (!superuser)
  534:     hostf = iruserfopen (_PATH_HEQUIV, 0);
  535: 
  536:   if (hostf)
  537:     {
  538:       isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
  539:       fclose (hostf);
  540: 
  541:       if (!isbad)
  542:         return 0;
  543:     }
  544: 
  545:   if (__check_rhosts_file || superuser)
  546:     {
  547:       char *pbuf;
  548:       struct passwd pwdbuf, *pwd;
  549:       size_t dirlen;
  550:       size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
  551:       char *buffer = __alloca (buflen);
  552:       uid_t uid;
  553: 
  554:       if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
  555:           || pwd == NULL)
  556:         return -1;
  557: 
  558:       dirlen = strlen (pwd->pw_dir);
  559:       pbuf = alloca (dirlen + sizeof "/.rhosts");
  560:       __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
  561:                  "/.rhosts", sizeof "/.rhosts");
  562: 
  563:        /* Change effective uid while reading .rhosts.  If root and
  564: