(root)/
glibc-2.38/
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  #include <sys/param.h>
      59  #include <sys/poll.h>
      60  #include <sys/socket.h>
      61  #include <sys/stat.h>
      62  
      63  #include <netinet/in.h>
      64  #include <arpa/inet.h>
      65  
      66  #include <alloca.h>
      67  #include <signal.h>
      68  #include <fcntl.h>
      69  #include <netdb.h>
      70  #include <unistd.h>
      71  #include <pwd.h>
      72  #include <errno.h>
      73  #include <stdio.h>
      74  #include <stdio_ext.h>
      75  #include <ctype.h>
      76  #include <string.h>
      77  #include <libintl.h>
      78  #include <stdlib.h>
      79  #include <wchar.h>
      80  #include <sys/uio.h>
      81  #include <sigsetops.h>
      82  #include <shlib-compat.h>
      83  #include <set-freeres.h>
      84  
      85  
      86  int __ivaliduser (FILE *, uint32_t, const char *, const char *);
      87  static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
      88  			    const char *, const char *, const char *);
      89  static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
      90  			int superuser, const char *ruser,
      91  			const char *luser, const char *rhost);
      92  static int ruserok_sa (struct sockaddr *ra, size_t ralen,
      93  			int superuser, const char *ruser,
      94  			const char *luser);
      95  int iruserok_af (const void *raddr, int superuser, const char *ruser,
      96  		 const char *luser, sa_family_t af);
      97  int iruserok (uint32_t raddr, int superuser, const char *ruser,
      98  	      const char *luser);
      99  
     100  libc_hidden_proto (iruserok_af)
     101  
     102  static char *ahostbuf;
     103  
     104  int
     105  rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
     106  	 const char *cmd, int *fd2p, sa_family_t af)
     107  {
     108  	char paddr[INET6_ADDRSTRLEN];
     109  	struct addrinfo hints, *res, *ai;
     110  	union
     111  	{
     112  		struct sockaddr sa;
     113  		struct sockaddr_storage ss;
     114  		struct sockaddr_in sin;
     115  		struct sockaddr_in6 sin6;
     116  	} from;
     117  	struct pollfd pfd[2];
     118  	sigset_t mask, omask;
     119  
     120  	pid_t pid;
     121  	int s, lport, timo, error;
     122  	char c;
     123  	int refused;
     124  	char num[8];
     125  	ssize_t n;
     126  
     127  	if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
     128  	  {
     129  	    __set_errno (EAFNOSUPPORT);
     130  	    return -1;
     131  	  }
     132  
     133  	pid = __getpid();
     134  
     135  	memset(&hints, '\0', sizeof(hints));
     136  	hints.ai_flags = AI_CANONNAME;
     137  	hints.ai_family = af;
     138  	hints.ai_socktype = SOCK_STREAM;
     139  	(void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
     140  	error = getaddrinfo(*ahost, num, &hints, &res);
     141  	if (error) {
     142  		if (error == EAI_NONAME && *ahost != NULL)
     143  			__fxprintf(NULL, "%s: Unknown host\n", *ahost);
     144  		else
     145  			__fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
     146  				   gai_strerror(error));
     147  
     148  		return -1;
     149  	}
     150  
     151  	pfd[0].events = POLLIN;
     152  	pfd[1].events = POLLIN;
     153  
     154  	if (res->ai_canonname){
     155  		free (ahostbuf);
     156  		ahostbuf = __strdup (res->ai_canonname);
     157  		if (ahostbuf == NULL) {
     158  			freeaddrinfo (res);
     159  			__fxprintf(NULL, "%s",
     160  				   _("rcmd: Cannot allocate memory\n"));
     161  			return -1;
     162  		}
     163  		*ahost = ahostbuf;
     164  	} else
     165  		*ahost = NULL;
     166  	ai = res;
     167  	refused = 0;
     168  	__sigemptyset(&mask);
     169  	__sigaddset(&mask, SIGURG);
     170  	__sigprocmask (SIG_BLOCK, &mask, &omask);
     171  	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
     172  		char errbuf[200];
     173  
     174  		s = rresvport_af(&lport, ai->ai_family);
     175  		if (s < 0) {
     176  			if (errno == EAGAIN)
     177  				__fxprintf(NULL, "%s", _("\
     178  rcmd: socket: All ports in use\n"));
     179  			else
     180  				__fxprintf(NULL, "rcmd: socket: %m\n");
     181  
     182  			__sigprocmask (SIG_SETMASK, &omask, 0);
     183  			freeaddrinfo(res);
     184  			return -1;
     185  		}
     186  		__fcntl(s, F_SETOWN, pid);
     187  		if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
     188  			break;
     189  		(void)__close(s);
     190  		if (errno == EADDRINUSE) {
     191  			lport--;
     192  			continue;
     193  		}
     194  		if (errno == ECONNREFUSED)
     195  			refused = 1;
     196  		if (ai->ai_next != NULL) {
     197  			int oerrno = errno;
     198  			char *buf = NULL;
     199  
     200  			getnameinfo(ai->ai_addr, ai->ai_addrlen,
     201  				    paddr, sizeof(paddr),
     202  				    NULL, 0,
     203  				    NI_NUMERICHOST);
     204  
     205  			if (__asprintf (&buf, _("connect to address %s: "),
     206  					paddr) >= 0)
     207  			  {
     208  			    __fxprintf(NULL, "%s", buf);
     209  			    free (buf);
     210  			  }
     211  			__set_errno (oerrno);
     212  			perror(0);
     213  			ai = ai->ai_next;
     214  			getnameinfo(ai->ai_addr, ai->ai_addrlen,
     215  				    paddr, sizeof(paddr),
     216  				    NULL, 0,
     217  				    NI_NUMERICHOST);
     218  			if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
     219  			  {
     220  			    __fxprintf (NULL, "%s", buf);
     221  			    free (buf);
     222  			  }
     223  			continue;
     224  		}
     225  		if (refused && timo <= 16) {
     226  			(void)__sleep(timo);
     227  			timo *= 2;
     228  			ai = res;
     229  			refused = 0;
     230  			continue;
     231  		}
     232  		freeaddrinfo(res);
     233  		(void)__fxprintf(NULL, "%s: %s\n", *ahost,
     234  				 __strerror_r(errno, errbuf, sizeof (errbuf)));
     235  		__sigprocmask (SIG_SETMASK, &omask, 0);
     236  		return -1;
     237  	}
     238  	lport--;
     239  	if (fd2p == 0) {
     240  		__write(s, "", 1);
     241  		lport = 0;
     242  	} else {
     243  		char num[8];
     244  		int s2 = rresvport_af(&lport, ai->ai_family), s3;
     245  		socklen_t len = ai->ai_addrlen;
     246  
     247  		if (s2 < 0)
     248  			goto bad;
     249  		__listen(s2, 1);
     250  		(void)__snprintf(num, sizeof(num), "%d", lport);
     251  		if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
     252  			char *buf = NULL;
     253  
     254  			if (__asprintf (&buf, _("\
     255  rcmd: write (setting up stderr): %m\n")) >= 0)
     256  			  {
     257  			    __fxprintf(NULL, "%s", buf);
     258  			    free (buf);
     259  			  }
     260  			(void)__close(s2);
     261  			goto bad;
     262  		}
     263  		pfd[0].fd = s;
     264  		pfd[1].fd = s2;
     265  		__set_errno (0);
     266  		if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
     267  			char *buf = NULL;
     268  
     269  			if ((errno != 0
     270  			     && __asprintf(&buf, _("\
     271  rcmd: poll (setting up stderr): %m\n")) >= 0)
     272  			    || (errno == 0
     273  				&& __asprintf(&buf, _("\
     274  poll: protocol failure in circuit setup\n")) >= 0))
     275  			  {
     276  			    __fxprintf (NULL, "%s", buf);
     277  			    free  (buf);
     278  			  }
     279  			(void)__close(s2);
     280  			goto bad;
     281  		}
     282  		s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
     283  		switch (from.sa.sa_family) {
     284  		case AF_INET:
     285  			rport = ntohs(from.sin.sin_port);
     286  			break;
     287  		case AF_INET6:
     288  			rport = ntohs(from.sin6.sin6_port);
     289  			break;
     290  		default:
     291  			rport = 0;
     292  			break;
     293  		}
     294  		(void)__close(s2);
     295  		if (s3 < 0) {
     296  			(void)__fxprintf(NULL, "rcmd: accept: %m\n");
     297  			lport = 0;
     298  			goto bad;
     299  		}
     300  		*fd2p = s3;
     301  
     302  		if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
     303  			char *buf = NULL;
     304  
     305  			if (__asprintf(&buf, _("\
     306  socket: protocol failure in circuit setup\n")) >= 0)
     307  			  {
     308  			    __fxprintf (NULL, "%s", buf);
     309  			    free (buf);
     310  			  }
     311  			goto bad2;
     312  		}
     313  	}
     314  	struct iovec iov[3] =
     315  	  {
     316  	    [0] = { .iov_base = (void *) locuser,
     317  		    .iov_len = strlen (locuser) + 1 },
     318  	    [1] = { .iov_base = (void *) remuser,
     319  		    .iov_len = strlen (remuser) + 1 },
     320  	    [2] = { .iov_base = (void *) cmd,
     321  		    .iov_len = strlen (cmd) + 1 }
     322  	  };
     323  	(void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
     324  	n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
     325  	if (n != 1) {
     326  		char *buf = NULL;
     327  
     328  		if ((n == 0
     329  		     && __asprintf(&buf, _("rcmd: %s: short read"),
     330  				   *ahost) >= 0)
     331  		    || (n != 0
     332  			&& __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
     333  		  {
     334  		    __fxprintf (NULL, "%s", buf);
     335  		    free (buf);
     336  		  }
     337  		goto bad2;
     338  	}
     339  	if (c != 0) {
     340  		while (__read(s, &c, 1) == 1) {
     341  			(void)__write(STDERR_FILENO, &c, 1);
     342  			if (c == '\n')
     343  				break;
     344  		}
     345  		goto bad2;
     346  	}
     347  	__sigprocmask (SIG_SETMASK, &omask, 0);
     348  	freeaddrinfo(res);
     349  	return s;
     350  bad2:
     351  	if (lport)
     352  		(void)__close(*fd2p);
     353  bad:
     354  	(void)__close(s);
     355  	__sigprocmask (SIG_SETMASK, &omask, 0);
     356  	freeaddrinfo(res);
     357  	return -1;
     358  }
     359  libc_hidden_def (rcmd_af)
     360  
     361  int
     362  rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
     363        const char *cmd, int *fd2p)
     364  {
     365    return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
     366  }
     367  
     368  int
     369  rresvport_af (int *alport, sa_family_t family)
     370  {
     371  	union {
     372  		struct sockaddr generic;
     373  		struct sockaddr_in in;
     374  		struct sockaddr_in6 in6;
     375  	} ss;
     376  	int s;
     377  	size_t len;
     378  	uint16_t *sport;
     379  
     380  	switch(family){
     381  	case AF_INET:
     382  		len = sizeof(struct sockaddr_in);
     383  		sport = &ss.in.sin_port;
     384  		break;
     385  	case AF_INET6:
     386  		len = sizeof(struct sockaddr_in6);
     387  		sport = &ss.in6.sin6_port;
     388  		break;
     389  	default:
     390  		__set_errno (EAFNOSUPPORT);
     391  		return -1;
     392  	}
     393  	/* NB: No SOCK_CLOEXEC for backwards compatibility.  */
     394  	s = __socket(family, SOCK_STREAM, 0);
     395  	if (s < 0)
     396  		return -1;
     397  
     398  	memset (&ss, '\0', sizeof(ss));
     399  #ifdef SALEN
     400  	ss.generic.__ss_len = len;
     401  #endif
     402  	ss.generic.sa_family = family;
     403  
     404  	/* Ignore invalid values.  */
     405  	if (*alport < IPPORT_RESERVED / 2)
     406  		*alport = IPPORT_RESERVED / 2;
     407  	else if (*alport >= IPPORT_RESERVED)
     408  		*alport = IPPORT_RESERVED - 1;
     409  
     410  	int start = *alport;
     411  	do {
     412  		*sport = htons((uint16_t) *alport);
     413  		if (__bind(s, &ss.generic, len) >= 0)
     414  			return s;
     415  		if (errno != EADDRINUSE) {
     416  			(void)__close(s);
     417  			return -1;
     418  		}
     419  		if ((*alport)-- == IPPORT_RESERVED/2)
     420  			*alport = IPPORT_RESERVED - 1;
     421  	} while (*alport != start);
     422  	(void)__close(s);
     423  	__set_errno (EAGAIN);
     424  	return -1;
     425  }
     426  libc_hidden_def (rresvport_af)
     427  
     428  int
     429  rresvport (int *alport)
     430  {
     431  	return rresvport_af(alport, AF_INET);
     432  }
     433  
     434  int	__check_rhosts_file = 1;
     435  char	*__rcmd_errstr;
     436  
     437  int
     438  ruserok_af (const char *rhost, int superuser, const char *ruser,
     439  	    const char *luser, sa_family_t af)
     440  {
     441  	struct addrinfo hints, *res, *res0;
     442  	int gai;
     443  	int ret;
     444  
     445  	memset (&hints, '\0', sizeof(hints));
     446  	hints.ai_family = af;
     447  	gai = getaddrinfo(rhost, NULL, &hints, &res0);
     448  	if (gai)
     449  		return -1;
     450  	ret = -1;
     451  	for (res=res0; res; res=res->ai_next)
     452  		if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
     453  				superuser, ruser, luser, rhost) == 0){
     454  			ret = 0;
     455  			break;
     456  		}
     457  	freeaddrinfo(res0);
     458  	return (ret);
     459  }
     460  libc_hidden_def (ruserok_af)
     461  
     462  int
     463  ruserok (const char *rhost, int superuser, const char *ruser,
     464  	 const char *luser)
     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_t64 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 (__lstat64_time64 (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, "rce");
     487        if (!res)
     488  	cp = _("cannot open");
     489        else if (__fstat64_time64 (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 (struct sockaddr *ra, size_t ralen, int superuser,
     525  	     const char *ruser, const char *luser, const char *rhost)
     526  {
     527    FILE *hostf = NULL;
     528    int isbad = -1;
     529  
     530    if (!superuser)
     531      hostf = iruserfopen (_PATH_HEQUIV, 0);
     532  
     533    if (hostf)
     534      {
     535        isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
     536        fclose (hostf);
     537  
     538        if (!isbad)
     539  	return 0;
     540      }
     541  
     542    if (__check_rhosts_file || superuser)
     543      {
     544        char *pbuf;
     545        struct passwd pwdbuf, *pwd;
     546        size_t dirlen;
     547        size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
     548        char *buffer = __alloca (buflen);
     549        uid_t uid;
     550  
     551        if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
     552  	  || pwd == NULL)
     553  	return -1;
     554  
     555        dirlen = strlen (pwd->pw_dir);
     556        pbuf = alloca (dirlen + sizeof "/.rhosts");
     557        __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
     558  		 "/.rhosts", sizeof "/.rhosts");
     559  
     560         /* Change effective uid while reading .rhosts.  If root and
     561  	  reading an NFS mounted file system, can't read files that
     562  	  are protected read/write owner only.  */
     563         uid = __geteuid ();
     564         if (seteuid (pwd->pw_uid) < 0)
     565  	 return -1;
     566  
     567         hostf = iruserfopen (pbuf, pwd->pw_uid);
     568  
     569         if (hostf != NULL)
     570  	 {
     571  	   isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
     572  	   fclose (hostf);
     573  	 }
     574  
     575         if (seteuid (uid) < 0)
     576  	 return -1;
     577         return isbad;
     578      }
     579    return -1;
     580  }
     581  /*
     582   * ruserok_sa() is now discussed on ipng, so
     583   * currently disabled for external use
     584   */
     585  static int
     586  ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
     587  	    const char *ruser, const char *luser)
     588  {
     589    return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
     590  }
     591  
     592  /* This is the exported version.  */
     593  int
     594  iruserok_af (const void *raddr, int superuser, const char *ruser,
     595  	     const char *luser, sa_family_t af)
     596  {
     597    union {
     598      struct sockaddr generic;
     599      struct sockaddr_in in;
     600      struct sockaddr_in6 in6;
     601    } ra;
     602    size_t ralen;
     603  
     604    memset (&ra, '\0', sizeof(ra));
     605    switch (af){
     606    case AF_INET:
     607      ra.in.sin_family = AF_INET;
     608      memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
     609      ralen = sizeof(struct sockaddr_in);
     610      break;
     611    case AF_INET6:
     612      ra.in6.sin6_family = AF_INET6;
     613      memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
     614      ralen = sizeof(struct sockaddr_in6);
     615      break;
     616    default:
     617      return 0;
     618    }
     619    return ruserok_sa (&ra.generic, ralen, superuser, ruser, luser);
     620  }
     621  libc_hidden_def (iruserok_af)
     622  
     623  int
     624  iruserok (uint32_t raddr, int superuser, const char *ruser, const char *luser)
     625  {
     626    return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
     627  }
     628  
     629  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_37)
     630  /* Previously used by lpd.  Current lpd versions have their own copy.  */
     631  int attribute_compat_text_section
     632  __ivaliduser (FILE *hostf, uint32_t raddr, const char *luser,
     633  	      const char *ruser)
     634  {
     635  	struct sockaddr_in ra;
     636  	memset(&ra, '\0', sizeof(ra));
     637  	ra.sin_family = AF_INET;
     638  	ra.sin_addr.s_addr = raddr;
     639  	return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
     640  			       luser, ruser, "-");
     641  }
     642  compat_symbol (libc, __ivaliduser, __ivaliduser, GLIBC_2_0);
     643  #endif
     644  
     645  /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
     646  static int
     647  __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
     648  		const char *rhost)
     649  {
     650  	struct addrinfo hints, *res0, *res;
     651  	char raddr[INET6_ADDRSTRLEN];
     652  	int match;
     653  	int negate=1;    /* Multiply return with this to get -1 instead of 1 */
     654  
     655  	/* Check nis netgroup.  */
     656  	if (strncmp ("+@", lhost, 2) == 0)
     657  		return innetgr (&lhost[2], rhost, NULL, NULL);
     658  
     659  	if (strncmp ("-@", lhost, 2) == 0)
     660  		return -innetgr (&lhost[2], rhost, NULL, NULL);
     661  
     662  	/* -host */
     663  	if (strncmp ("-", lhost,1) == 0) {
     664  		negate = -1;
     665  		lhost++;
     666  	} else if (strcmp ("+",lhost) == 0) {
     667  		return 1;                    /* asking for trouble, but ok.. */
     668  	}
     669  
     670  	/* Try for raw ip address first. */
     671  	/* XXX */
     672  	if (getnameinfo(ra, ralen,
     673  			raddr, sizeof(raddr), NULL, 0,
     674  			NI_NUMERICHOST) == 0
     675  	    && strcmp(raddr, lhost) == 0)
     676  		return negate;
     677  
     678  	/* Better be a hostname. */
     679  	match = 0;
     680  	memset(&hints, '\0', sizeof(hints));
     681  	hints.ai_family = ra->sa_family;
     682  	if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
     683  		/* Spin through ip addresses. */
     684  		for (res = res0; res; res = res->ai_next)
     685  		  {
     686  		    if (res->ai_family == ra->sa_family
     687  			&& !memcmp(res->ai_addr, ra, res->ai_addrlen))
     688  		      {
     689  			match = 1;
     690  			break;
     691  		      }
     692  		  }
     693  		freeaddrinfo (res0);
     694  	}
     695  	return negate * match;
     696  }
     697  
     698  /* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
     699  static int
     700  __icheckuser (const char *luser, const char *ruser)
     701  {
     702      /*
     703        luser is user entry from .rhosts/hosts.equiv file
     704        ruser is user id on remote host
     705        */
     706  
     707      /* [-+]@netgroup */
     708      if (strncmp ("+@", luser, 2) == 0)
     709  	return innetgr (&luser[2], NULL, ruser, NULL);
     710  
     711      if (strncmp ("-@", luser,2) == 0)
     712  	return -innetgr (&luser[2], NULL, ruser, NULL);
     713  
     714      /* -user */
     715      if (strncmp ("-", luser, 1) == 0)
     716  	return -(strcmp (&luser[1], ruser) == 0);
     717  
     718      /* + */
     719      if (strcmp ("+", luser) == 0)
     720  	return 1;
     721  
     722      /* simple string match */
     723      return strcmp (ruser, luser) == 0;
     724  }
     725  
     726  /*
     727   * Returns 1 for blank lines (or only comment lines) and 0 otherwise
     728   */
     729  static int
     730  __isempty (char *p)
     731  {
     732      while (*p && isspace (*p)) {
     733  	++p;
     734      }
     735  
     736      return (*p == '\0' || *p == '#') ? 1 : 0 ;
     737  }
     738  
     739  /*
     740   * Returns 0 if positive match, -1 if _not_ ok.
     741   */
     742  static int
     743  __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
     744  		 const char *luser, const char *ruser, const char *rhost)
     745  {
     746      const char *user;
     747      char *p;
     748      int hcheck, ucheck;
     749      char *buf = NULL;
     750      size_t bufsize = 0;
     751      int retval = -1;
     752  
     753      while (__getline (&buf, &bufsize, hostf) > 0) {
     754  	buf[bufsize - 1] = '\0'; /* Make sure it's terminated.  */
     755  	p = buf;
     756  
     757  	/* Skip empty or comment lines */
     758  	if (__isempty (p)) {
     759  	    continue;
     760  	}
     761  
     762  	for (;*p && !isspace(*p); ++p) {
     763  	    *p = _tolower (*p);
     764  	}
     765  
     766  	/* Next we want to find the permitted name for the remote user.  */
     767  	if (*p == ' ' || *p == '\t') {
     768  	    /* <nul> terminate hostname and skip spaces */
     769  	    for (*p++='\0'; *p && isspace (*p); ++p);
     770  
     771  	    user = p;                   /* this is the user's name */
     772  	    while (*p && !isspace (*p))
     773  		++p;                    /* find end of user's name */
     774  	} else
     775  	    user = p;
     776  
     777  	*p = '\0';              /* <nul> terminate username (+host?) */
     778  
     779  	/* buf -> host(?) ; user -> username(?) */
     780  	if (*buf == '\0')
     781  	  break;
     782  	if (*user == '\0')
     783  	  user = luser;
     784  
     785  	/* First check the user part.  In a naive implementation we
     786  	   would check the host part first, then the user.  However,
     787  	   if we check the user first and reject the entry we will
     788  	   have saved doing any host lookups to normalize the comparison
     789  	   and that likely saves several DNS queries.  Therefore we
     790  	   check the user first.  */
     791  	ucheck = __icheckuser (user, ruser);
     792  
     793  	/* Either we found the user, or we didn't and this is a
     794  	   negative host check.  We must do the negative host lookup
     795  	   in order to preserve the semantics of stopping on this line
     796  	   before processing others.  */
     797  	if (ucheck != 0 || *buf == '-') {
     798  
     799  	    /* Next check host part.  */
     800  	    hcheck = __checkhost_sa (ra, ralen, buf, rhost);
     801  
     802  	    /* Negative '-host user(?)' match?  */
     803  	    if (hcheck < 0)
     804  		break;
     805  
     806  	    /* Positive 'host user' match?  */
     807  	    if (hcheck > 0 && ucheck > 0) {
     808  		retval = 0;
     809  		break;
     810  	    }
     811  
     812  	    /* Negative 'host -user' match?  */
     813  	    if (hcheck > 0 && ucheck < 0)
     814  	      break;
     815  
     816  	    /* Neither, go on looking for match.  */
     817  	}
     818      }
     819  
     820      free (buf);
     821  
     822      return retval;
     823  }
     824  
     825  weak_alias (ahostbuf, __libc_rcmd_freemem_ptr)