Blame inet/rcmd.c

Packit 6c4009
/*
Packit 6c4009
 * Copyright (C) 1998 WIDE Project.
Packit 6c4009
 * All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions
Packit 6c4009
 * are met:
Packit 6c4009
 * 1. Redistributions of source code must retain the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer.
Packit 6c4009
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer in the
Packit 6c4009
 *    documentation and/or other materials provided with the distribution.
Packit 6c4009
 * 3. Neither the name of the project nor the names of its contributors
Packit 6c4009
 *    may be used to endorse or promote products derived from this software
Packit 6c4009
 *    without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
Packit 6c4009
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 6c4009
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6c4009
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
Packit 6c4009
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 6c4009
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 6c4009
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 6c4009
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 6c4009
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 6c4009
 * SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
/*
Packit 6c4009
 * Copyright (c) 1983, 1993, 1994
Packit 6c4009
 *	The Regents of the University of California.  All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Redistribution and use in source and binary forms, with or without
Packit 6c4009
 * modification, are permitted provided that the following conditions
Packit 6c4009
 * are met:
Packit 6c4009
 * 1. Redistributions of source code must retain the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer.
Packit 6c4009
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 6c4009
 *    notice, this list of conditions and the following disclaimer in the
Packit 6c4009
 *    documentation and/or other materials provided with the distribution.
Packit 6c4009
 * 4. Neither the name of the University nor the names of its contributors
Packit 6c4009
 *    may be used to endorse or promote products derived from this software
Packit 6c4009
 *    without specific prior written permission.
Packit 6c4009
 *
Packit 6c4009
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
Packit 6c4009
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 6c4009
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 6c4009
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
Packit 6c4009
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 6c4009
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 6c4009
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 6c4009
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 6c4009
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 6c4009
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 6c4009
 * SUCH DAMAGE.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/poll.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <pwd.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <sigsetops.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
int __ivaliduser (FILE *, uint32_t, const char *, const char *);
Packit 6c4009
static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
Packit 6c4009
			    const char *, const char *, const char *);
Packit 6c4009
static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
Packit 6c4009
			int superuser, const char *ruser,
Packit 6c4009
			const char *luser, const char *rhost);
Packit 6c4009
static int ruserok_sa (struct sockaddr *ra, size_t ralen,
Packit 6c4009
			int superuser, const char *ruser,
Packit 6c4009
			const char *luser);
Packit 6c4009
int iruserok_af (const void *raddr, int superuser, const char *ruser,
Packit 6c4009
		 const char *luser, sa_family_t af);
Packit 6c4009
int iruserok (uint32_t raddr, int superuser, const char *ruser,
Packit 6c4009
	      const char *luser);
Packit 6c4009
Packit 6c4009
libc_hidden_proto (iruserok_af)
Packit 6c4009
Packit 6c4009
libc_freeres_ptr(static char *ahostbuf);
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
Packit 6c4009
	 const char *cmd, int *fd2p, sa_family_t af)
Packit 6c4009
{
Packit 6c4009
	char paddr[INET6_ADDRSTRLEN];
Packit 6c4009
	struct addrinfo hints, *res, *ai;
Packit 6c4009
	union
Packit 6c4009
	{
Packit 6c4009
		struct sockaddr sa;
Packit 6c4009
		struct sockaddr_storage ss;
Packit 6c4009
		struct sockaddr_in sin;
Packit 6c4009
		struct sockaddr_in6 sin6;
Packit 6c4009
	} from;
Packit 6c4009
	struct pollfd pfd[2];
Packit 6c4009
	sigset_t mask, omask;
Packit 6c4009
Packit 6c4009
	pid_t pid;
Packit 6c4009
	int s, lport, timo, error;
Packit 6c4009
	char c;
Packit 6c4009
	int refused;
Packit 6c4009
	char num[8];
Packit 6c4009
	ssize_t n;
Packit 6c4009
Packit 6c4009
	if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
Packit 6c4009
	  {
Packit 6c4009
	    __set_errno (EAFNOSUPPORT);
Packit 6c4009
	    return -1;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	pid = __getpid();
Packit 6c4009
Packit 6c4009
	memset(&hints, '\0', sizeof(hints));
Packit 6c4009
	hints.ai_flags = AI_CANONNAME;
Packit 6c4009
	hints.ai_family = af;
Packit 6c4009
	hints.ai_socktype = SOCK_STREAM;
Packit 6c4009
	(void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
Packit 6c4009
	error = getaddrinfo(*ahost, num, &hints, &res;;
Packit 6c4009
	if (error) {
Packit 6c4009
		if (error == EAI_NONAME && *ahost != NULL)
Packit 6c4009
			__fxprintf(NULL, "%s: Unknown host\n", *ahost);
Packit 6c4009
		else
Packit 6c4009
			__fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
Packit 6c4009
				   gai_strerror(error));
Packit 6c4009
Packit 6c4009
		return -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	pfd[0].events = POLLIN;
Packit 6c4009
	pfd[1].events = POLLIN;
Packit 6c4009
Packit 6c4009
	if (res->ai_canonname){
Packit 6c4009
		free (ahostbuf);
Packit 6c4009
		ahostbuf = __strdup (res->ai_canonname);
Packit 6c4009
		if (ahostbuf == NULL) {
Packit 6c4009
			__fxprintf(NULL, "%s",
Packit 6c4009
				   _("rcmd: Cannot allocate memory\n"));
Packit 6c4009
			return -1;
Packit 6c4009
		}
Packit 6c4009
		*ahost = ahostbuf;
Packit 6c4009
	} else
Packit 6c4009
		*ahost = NULL;
Packit 6c4009
	ai = res;
Packit 6c4009
	refused = 0;
Packit 6c4009
	__sigemptyset(&mask);
Packit 6c4009
	__sigaddset(&mask, SIGURG);
Packit 6c4009
	__sigprocmask (SIG_BLOCK, &mask, &omask);
Packit 6c4009
	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
Packit 6c4009
		char errbuf[200];
Packit 6c4009
Packit 6c4009
		s = rresvport_af(&lport, ai->ai_family);
Packit 6c4009
		if (s < 0) {
Packit 6c4009
			if (errno == EAGAIN)
Packit 6c4009
				__fxprintf(NULL, "%s", _("\
Packit 6c4009
rcmd: socket: All ports in use\n"));
Packit 6c4009
			else
Packit 6c4009
				__fxprintf(NULL, "rcmd: socket: %m\n");
Packit 6c4009
Packit 6c4009
			__sigprocmask (SIG_SETMASK, &omask, 0);
Packit 6c4009
			freeaddrinfo(res);
Packit 6c4009
			return -1;
Packit 6c4009
		}
Packit 6c4009
		__fcntl(s, F_SETOWN, pid);
Packit 6c4009
		if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
Packit 6c4009
			break;
Packit 6c4009
		(void)__close(s);
Packit 6c4009
		if (errno == EADDRINUSE) {
Packit 6c4009
			lport--;
Packit 6c4009
			continue;
Packit 6c4009
		}
Packit 6c4009
		if (errno == ECONNREFUSED)
Packit 6c4009
			refused = 1;
Packit 6c4009
		if (ai->ai_next != NULL) {
Packit 6c4009
			int oerrno = errno;
Packit 6c4009
			char *buf = NULL;
Packit 6c4009
Packit 6c4009
			getnameinfo(ai->ai_addr, ai->ai_addrlen,
Packit 6c4009
				    paddr, sizeof(paddr),
Packit 6c4009
				    NULL, 0,
Packit 6c4009
				    NI_NUMERICHOST);
Packit 6c4009
Packit 6c4009
			if (__asprintf (&buf, _("connect to address %s: "),
Packit 6c4009
					paddr) >= 0)
Packit 6c4009
			  {
Packit 6c4009
			    __fxprintf(NULL, "%s", buf);
Packit 6c4009
			    free (buf);
Packit 6c4009
			  }
Packit 6c4009
			__set_errno (oerrno);
Packit 6c4009
			perror(0);
Packit 6c4009
			ai = ai->ai_next;
Packit 6c4009
			getnameinfo(ai->ai_addr, ai->ai_addrlen,
Packit 6c4009
				    paddr, sizeof(paddr),
Packit 6c4009
				    NULL, 0,
Packit 6c4009
				    NI_NUMERICHOST);
Packit 6c4009
			if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
Packit 6c4009
			  {
Packit 6c4009
			    __fxprintf (NULL, "%s", buf);
Packit 6c4009
			    free (buf);
Packit 6c4009
			  }
Packit 6c4009
			continue;
Packit 6c4009
		}
Packit 6c4009
		if (refused && timo <= 16) {
Packit 6c4009
			(void)__sleep(timo);
Packit 6c4009
			timo *= 2;
Packit 6c4009
			ai = res;
Packit 6c4009
			refused = 0;
Packit 6c4009
			continue;
Packit 6c4009
		}
Packit 6c4009
		freeaddrinfo(res);
Packit 6c4009
		(void)__fxprintf(NULL, "%s: %s\n", *ahost,
Packit 6c4009
				 __strerror_r(errno, errbuf, sizeof (errbuf)));
Packit 6c4009
		__sigprocmask (SIG_SETMASK, &omask, 0);
Packit 6c4009
		return -1;
Packit 6c4009
	}
Packit 6c4009
	lport--;
Packit 6c4009
	if (fd2p == 0) {
Packit 6c4009
		__write(s, "", 1);
Packit 6c4009
		lport = 0;
Packit 6c4009
	} else {
Packit 6c4009
		char num[8];
Packit 6c4009
		int s2 = rresvport_af(&lport, ai->ai_family), s3;
Packit 6c4009
		socklen_t len = ai->ai_addrlen;
Packit 6c4009
Packit 6c4009
		if (s2 < 0)
Packit 6c4009
			goto bad;
Packit 6c4009
		__listen(s2, 1);
Packit 6c4009
		(void)__snprintf(num, sizeof(num), "%d", lport);
Packit 6c4009
		if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
Packit 6c4009
			char *buf = NULL;
Packit 6c4009
Packit 6c4009
			if (__asprintf (&buf, _("\
Packit 6c4009
rcmd: write (setting up stderr): %m\n")) >= 0)
Packit 6c4009
			  {
Packit 6c4009
			    __fxprintf(NULL, "%s", buf);
Packit 6c4009
			    free (buf);
Packit 6c4009
			  }
Packit 6c4009
			(void)__close(s2);
Packit 6c4009
			goto bad;
Packit 6c4009
		}
Packit 6c4009
		pfd[0].fd = s;
Packit 6c4009
		pfd[1].fd = s2;
Packit 6c4009
		__set_errno (0);
Packit 6c4009
		if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
Packit 6c4009
			char *buf = NULL;
Packit 6c4009
Packit 6c4009
			if ((errno != 0
Packit 6c4009
			     && __asprintf(&buf, _("\
Packit 6c4009
rcmd: poll (setting up stderr): %m\n")) >= 0)
Packit 6c4009
			    || (errno == 0
Packit 6c4009
				&& __asprintf(&buf, _("\
Packit 6c4009
poll: protocol failure in circuit setup\n")) >= 0))
Packit 6c4009
			  {
Packit 6c4009
			    __fxprintf (NULL, "%s", buf);
Packit 6c4009
			    free  (buf);
Packit 6c4009
			  }
Packit 6c4009
			(void)__close(s2);
Packit 6c4009
			goto bad;
Packit 6c4009
		}
Packit 6c4009
		s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
Packit 6c4009
		switch (from.sa.sa_family) {
Packit 6c4009
		case AF_INET:
Packit 6c4009
			rport = ntohs(from.sin.sin_port);
Packit 6c4009
			break;
Packit 6c4009
		case AF_INET6:
Packit 6c4009
			rport = ntohs(from.sin6.sin6_port);
Packit 6c4009
			break;
Packit 6c4009
		default:
Packit 6c4009
			rport = 0;
Packit 6c4009
			break;
Packit 6c4009
		}
Packit 6c4009
		(void)__close(s2);
Packit 6c4009
		if (s3 < 0) {
Packit 6c4009
			(void)__fxprintf(NULL, "rcmd: accept: %m\n");
Packit 6c4009
			lport = 0;
Packit 6c4009
			goto bad;
Packit 6c4009
		}
Packit 6c4009
		*fd2p = s3;
Packit 6c4009
Packit 6c4009
		if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
Packit 6c4009
			char *buf = NULL;
Packit 6c4009
Packit 6c4009
			if (__asprintf(&buf, _("\
Packit 6c4009
socket: protocol failure in circuit setup\n")) >= 0)
Packit 6c4009
			  {
Packit 6c4009
			    __fxprintf (NULL, "%s", buf);
Packit 6c4009
			    free (buf);
Packit 6c4009
			  }
Packit 6c4009
			goto bad2;
Packit 6c4009
		}
Packit 6c4009
	}
Packit 6c4009
	struct iovec iov[3] =
Packit 6c4009
	  {
Packit 6c4009
	    [0] = { .iov_base = (void *) locuser,
Packit 6c4009
		    .iov_len = strlen (locuser) + 1 },
Packit 6c4009
	    [1] = { .iov_base = (void *) remuser,
Packit 6c4009
		    .iov_len = strlen (remuser) + 1 },
Packit 6c4009
	    [2] = { .iov_base = (void *) cmd,
Packit 6c4009
		    .iov_len = strlen (cmd) + 1 }
Packit 6c4009
	  };
Packit 6c4009
	(void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
Packit 6c4009
	n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
Packit 6c4009
	if (n != 1) {
Packit 6c4009
		char *buf = NULL;
Packit 6c4009
Packit 6c4009
		if ((n == 0
Packit 6c4009
		     && __asprintf(&buf, _("rcmd: %s: short read"),
Packit 6c4009
				   *ahost) >= 0)
Packit 6c4009
		    || (n != 0
Packit 6c4009
			&& __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
Packit 6c4009
		  {
Packit 6c4009
		    __fxprintf (NULL, "%s", buf);
Packit 6c4009
		    free (buf);
Packit 6c4009
		  }
Packit 6c4009
		goto bad2;
Packit 6c4009
	}
Packit 6c4009
	if (c != 0) {
Packit 6c4009
		while (__read(s, &c, 1) == 1) {
Packit 6c4009
			(void)__write(STDERR_FILENO, &c, 1);
Packit 6c4009
			if (c == '\n')
Packit 6c4009
				break;
Packit 6c4009
		}
Packit 6c4009
		goto bad2;
Packit 6c4009
	}
Packit 6c4009
	__sigprocmask (SIG_SETMASK, &omask, 0);
Packit 6c4009
	freeaddrinfo(res);
Packit 6c4009
	return s;
Packit 6c4009
bad2:
Packit 6c4009
	if (lport)
Packit 6c4009
		(void)__close(*fd2p);
Packit 6c4009
bad:
Packit 6c4009
	(void)__close(s);
Packit 6c4009
	__sigprocmask (SIG_SETMASK, &omask, 0);
Packit 6c4009
	freeaddrinfo(res);
Packit 6c4009
	return -1;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (rcmd_af)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
Packit 6c4009
      const char *cmd, int *fd2p)
Packit 6c4009
{
Packit 6c4009
  return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
rresvport_af (int *alport, sa_family_t family)
Packit 6c4009
{
Packit 6c4009
	union {
Packit 6c4009
		struct sockaddr generic;
Packit 6c4009
		struct sockaddr_in in;
Packit 6c4009
		struct sockaddr_in6 in6;
Packit 6c4009
	} ss;
Packit 6c4009
	int s;
Packit 6c4009
	size_t len;
Packit 6c4009
	uint16_t *sport;
Packit 6c4009
Packit 6c4009
	switch(family){
Packit 6c4009
	case AF_INET:
Packit 6c4009
		len = sizeof(struct sockaddr_in);
Packit 6c4009
		sport = &ss.in.sin_port;
Packit 6c4009
		break;
Packit 6c4009
	case AF_INET6:
Packit 6c4009
		len = sizeof(struct sockaddr_in6);
Packit 6c4009
		sport = &ss.in6.sin6_port;
Packit 6c4009
		break;
Packit 6c4009
	default:
Packit 6c4009
		__set_errno (EAFNOSUPPORT);
Packit 6c4009
		return -1;
Packit 6c4009
	}
Packit 6c4009
	/* NB: No SOCK_CLOEXEC for backwards compatibility.  */
Packit 6c4009
	s = __socket(family, SOCK_STREAM, 0);
Packit 6c4009
	if (s < 0)
Packit 6c4009
		return -1;
Packit 6c4009
Packit 6c4009
	memset (&ss, '\0', sizeof(ss));
Packit 6c4009
#ifdef SALEN
Packit 6c4009
	ss.generic.__ss_len = len;
Packit 6c4009
#endif
Packit 6c4009
	ss.generic.sa_family = family;
Packit 6c4009
Packit 6c4009
	/* Ignore invalid values.  */
Packit 6c4009
	if (*alport < IPPORT_RESERVED / 2)
Packit 6c4009
		*alport = IPPORT_RESERVED / 2;
Packit 6c4009
	else if (*alport >= IPPORT_RESERVED)
Packit 6c4009
		*alport = IPPORT_RESERVED - 1;
Packit 6c4009
Packit 6c4009
	int start = *alport;
Packit 6c4009
	do {
Packit 6c4009
		*sport = htons((uint16_t) *alport);
Packit 6c4009
		if (__bind(s, &ss.generic, len) >= 0)
Packit 6c4009
			return s;
Packit 6c4009
		if (errno != EADDRINUSE) {
Packit 6c4009
			(void)__close(s);
Packit 6c4009
			return -1;
Packit 6c4009
		}
Packit 6c4009
		if ((*alport)-- == IPPORT_RESERVED/2)
Packit 6c4009
			*alport = IPPORT_RESERVED - 1;
Packit 6c4009
	} while (*alport != start);
Packit 6c4009
	(void)__close(s);
Packit 6c4009
	__set_errno (EAGAIN);
Packit 6c4009
	return -1;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (rresvport_af)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
rresvport (int *alport)
Packit 6c4009
{
Packit 6c4009
	return rresvport_af(alport, AF_INET);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int	__check_rhosts_file = 1;
Packit 6c4009
char	*__rcmd_errstr;
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
ruserok_af (const char *rhost, int superuser, const char *ruser,
Packit 6c4009
	    const char *luser, sa_family_t af)
Packit 6c4009
{
Packit 6c4009
	struct addrinfo hints, *res, *res0;
Packit 6c4009
	int gai;
Packit 6c4009
	int ret;
Packit 6c4009
Packit 6c4009
	memset (&hints, '\0', sizeof(hints));
Packit 6c4009
	hints.ai_family = af;
Packit 6c4009
	gai = getaddrinfo(rhost, NULL, &hints, &res0);
Packit 6c4009
	if (gai)
Packit 6c4009
		return -1;
Packit 6c4009
	ret = -1;
Packit 6c4009
	for (res=res0; res; res=res->ai_next)
Packit 6c4009
		if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
Packit 6c4009
				superuser, ruser, luser, rhost) == 0){
Packit 6c4009
			ret = 0;
Packit 6c4009
			break;
Packit 6c4009
		}
Packit 6c4009
	freeaddrinfo(res0);
Packit 6c4009
	return (ret);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (ruserok_af)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
ruserok (const char *rhost, int superuser, const char *ruser,
Packit 6c4009
	 const char *luser)
Packit 6c4009
{
Packit 6c4009
	return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Extremely paranoid file open function. */
Packit 6c4009
static FILE *
Packit 6c4009
iruserfopen (const char *file, uid_t okuser)
Packit 6c4009
{
Packit 6c4009
  struct stat64 st;
Packit 6c4009
  char *cp = NULL;
Packit 6c4009
  FILE *res = NULL;
Packit 6c4009
Packit 6c4009
  /* If not a regular file, if owned by someone other than user or
Packit 6c4009
     root, if writeable by anyone but the owner, or if hardlinked
Packit 6c4009
     anywhere, quit.  */
Packit 6c4009
  if (__lxstat64 (_STAT_VER, file, &st))
Packit 6c4009
    cp = _("lstat failed");
Packit 6c4009
  else if (!S_ISREG (st.st_mode))
Packit 6c4009
    cp = _("not regular file");
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      res = fopen (file, "rce");
Packit 6c4009
      if (!res)
Packit 6c4009
	cp = _("cannot open");
Packit 6c4009
      else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
Packit 6c4009
	cp = _("fstat failed");
Packit 6c4009
      else if (st.st_uid && st.st_uid != okuser)
Packit 6c4009
	cp = _("bad owner");
Packit 6c4009
      else if (st.st_mode & (S_IWGRP|S_IWOTH))
Packit 6c4009
	cp = _("writeable by other than owner");
Packit 6c4009
      else if (st.st_nlink > 1)
Packit 6c4009
	cp = _("hard linked somewhere");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If there were any problems, quit.  */
Packit 6c4009
  if (cp != NULL)
Packit 6c4009
    {
Packit 6c4009
      __rcmd_errstr = cp;
Packit 6c4009
      if (res)
Packit 6c4009
	fclose (res);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* No threads use this stream.  */
Packit 6c4009
  __fsetlocking (res, FSETLOCKING_BYCALLER);
Packit 6c4009
Packit 6c4009
  return res;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * New .rhosts strategy: We are passed an ip address. We spin through
Packit 6c4009
 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
Packit 6c4009
 * has ip addresses, we don't have to trust a nameserver.  When it
Packit 6c4009
 * contains hostnames, we spin through the list of addresses the nameserver
Packit 6c4009
 * gives us and look for a match.
Packit 6c4009
 *
Packit 6c4009
 * Returns 0 if ok, -1 if not ok.
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
ruserok2_sa (struct sockaddr *ra, size_t ralen, int superuser,
Packit 6c4009
	     const char *ruser, const char *luser, const char *rhost)
Packit 6c4009
{
Packit 6c4009
  FILE *hostf = NULL;
Packit 6c4009
  int isbad = -1;
Packit 6c4009
Packit 6c4009
  if (!superuser)
Packit 6c4009
    hostf = iruserfopen (_PATH_HEQUIV, 0);
Packit 6c4009
Packit 6c4009
  if (hostf)
Packit 6c4009
    {
Packit 6c4009
      isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
Packit 6c4009
      fclose (hostf);
Packit 6c4009
Packit 6c4009
      if (!isbad)
Packit 6c4009
	return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (__check_rhosts_file || superuser)
Packit 6c4009
    {
Packit 6c4009
      char *pbuf;
Packit 6c4009
      struct passwd pwdbuf, *pwd;
Packit 6c4009
      size_t dirlen;
Packit 6c4009
      size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
Packit 6c4009
      char *buffer = __alloca (buflen);
Packit 6c4009
      uid_t uid;
Packit 6c4009
Packit 6c4009
      if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
Packit 6c4009
	  || pwd == NULL)
Packit 6c4009
	return -1;
Packit 6c4009
Packit 6c4009
      dirlen = strlen (pwd->pw_dir);
Packit 6c4009
      pbuf = alloca (dirlen + sizeof "/.rhosts");
Packit 6c4009
      __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
Packit 6c4009
		 "/.rhosts", sizeof "/.rhosts");
Packit 6c4009
Packit 6c4009
       /* Change effective uid while reading .rhosts.  If root and
Packit 6c4009
	  reading an NFS mounted file system, can't read files that
Packit 6c4009
	  are protected read/write owner only.  */
Packit 6c4009
       uid = __geteuid ();
Packit 6c4009
       seteuid (pwd->pw_uid);
Packit 6c4009
       hostf = iruserfopen (pbuf, pwd->pw_uid);
Packit 6c4009
Packit 6c4009
       if (hostf != NULL)
Packit 6c4009
	 {
Packit 6c4009
	   isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
Packit 6c4009
	   fclose (hostf);
Packit 6c4009
	 }
Packit 6c4009
Packit 6c4009
       seteuid (uid);
Packit 6c4009
       return isbad;
Packit 6c4009
    }
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
/*
Packit 6c4009
 * ruserok_sa() is now discussed on ipng, so
Packit 6c4009
 * currently disabled for external use
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
Packit 6c4009
	    const char *ruser, const char *luser)
Packit 6c4009
{
Packit 6c4009
  return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This is the exported version.  */
Packit 6c4009
int
Packit 6c4009
iruserok_af (const void *raddr, int superuser, const char *ruser,
Packit 6c4009
	     const char *luser, sa_family_t af)
Packit 6c4009
{
Packit 6c4009
  union {
Packit 6c4009
    struct sockaddr generic;
Packit 6c4009
    struct sockaddr_in in;
Packit 6c4009
    struct sockaddr_in6 in6;
Packit 6c4009
  } ra;
Packit 6c4009
  size_t ralen;
Packit 6c4009
Packit 6c4009
  memset (&ra, '\0', sizeof(ra));
Packit 6c4009
  switch (af){
Packit 6c4009
  case AF_INET:
Packit 6c4009
    ra.in.sin_family = AF_INET;
Packit 6c4009
    memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
Packit 6c4009
    ralen = sizeof(struct sockaddr_in);
Packit 6c4009
    break;
Packit 6c4009
  case AF_INET6:
Packit 6c4009
    ra.in6.sin6_family = AF_INET6;
Packit 6c4009
    memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
Packit 6c4009
    ralen = sizeof(struct sockaddr_in6);
Packit 6c4009
    break;
Packit 6c4009
  default:
Packit 6c4009
    return 0;
Packit 6c4009
  }
Packit 6c4009
  return ruserok_sa (&ra.generic, ralen, superuser, ruser, luser);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (iruserok_af)
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
iruserok (uint32_t raddr, int superuser, const char *ruser, const char *luser)
Packit 6c4009
{
Packit 6c4009
  return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * XXX
Packit 6c4009
 * Don't make static, used by lpd(8).
Packit 6c4009
 *
Packit 6c4009
 * This function is not used anymore. It is only present because lpd(8)
Packit 6c4009
 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
Packit 6c4009
 * argument. This means that netgroups won't work in .rhost/hosts.equiv
Packit 6c4009
 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
Packit 6c4009
 * or PAM.
Packit 6c4009
 * Returns 0 if ok, -1 if not ok.
Packit 6c4009
 */
Packit 6c4009
int
Packit 6c4009
__ivaliduser (FILE *hostf, uint32_t raddr, const char *luser,
Packit 6c4009
	      const char *ruser)
Packit 6c4009
{
Packit 6c4009
	struct sockaddr_in ra;
Packit 6c4009
	memset(&ra, '\0', sizeof(ra));
Packit 6c4009
	ra.sin_family = AF_INET;
Packit 6c4009
	ra.sin_addr.s_addr = raddr;
Packit 6c4009
	return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
Packit 6c4009
			       luser, ruser, "-");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
Packit 6c4009
static int
Packit 6c4009
__checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
Packit 6c4009
		const char *rhost)
Packit 6c4009
{
Packit 6c4009
	struct addrinfo hints, *res0, *res;
Packit 6c4009
	char raddr[INET6_ADDRSTRLEN];
Packit 6c4009
	int match;
Packit 6c4009
	int negate=1;    /* Multiply return with this to get -1 instead of 1 */
Packit 6c4009
Packit 6c4009
	/* Check nis netgroup.  */
Packit 6c4009
	if (strncmp ("+@", lhost, 2) == 0)
Packit 6c4009
		return innetgr (&lhost[2], rhost, NULL, NULL);
Packit 6c4009
Packit 6c4009
	if (strncmp ("-@", lhost, 2) == 0)
Packit 6c4009
		return -innetgr (&lhost[2], rhost, NULL, NULL);
Packit 6c4009
Packit 6c4009
	/* -host */
Packit 6c4009
	if (strncmp ("-", lhost,1) == 0) {
Packit 6c4009
		negate = -1;
Packit 6c4009
		lhost++;
Packit 6c4009
	} else if (strcmp ("+",lhost) == 0) {
Packit 6c4009
		return 1;                    /* asking for trouble, but ok.. */
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	/* Try for raw ip address first. */
Packit 6c4009
	/* XXX */
Packit 6c4009
	if (getnameinfo(ra, ralen,
Packit 6c4009
			raddr, sizeof(raddr), NULL, 0,
Packit 6c4009
			NI_NUMERICHOST) == 0
Packit 6c4009
	    && strcmp(raddr, lhost) == 0)
Packit 6c4009
		return negate;
Packit 6c4009
Packit 6c4009
	/* Better be a hostname. */
Packit 6c4009
	match = 0;
Packit 6c4009
	memset(&hints, '\0', sizeof(hints));
Packit 6c4009
	hints.ai_family = ra->sa_family;
Packit 6c4009
	if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
Packit 6c4009
		/* Spin through ip addresses. */
Packit 6c4009
		for (res = res0; res; res = res->ai_next)
Packit 6c4009
		  {
Packit 6c4009
		    if (res->ai_family == ra->sa_family
Packit 6c4009
			&& !memcmp(res->ai_addr, ra, res->ai_addrlen))
Packit 6c4009
		      {
Packit 6c4009
			match = 1;
Packit 6c4009
			break;
Packit 6c4009
		      }
Packit 6c4009
		  }
Packit 6c4009
		freeaddrinfo (res0);
Packit 6c4009
	}
Packit 6c4009
	return negate * match;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Returns 1 on positive match, 0 on no match, -1 on negative match.  */
Packit 6c4009
static int
Packit 6c4009
__icheckuser (const char *luser, const char *ruser)
Packit 6c4009
{
Packit 6c4009
    /*
Packit 6c4009
      luser is user entry from .rhosts/hosts.equiv file
Packit 6c4009
      ruser is user id on remote host
Packit 6c4009
      */
Packit 6c4009
Packit 6c4009
    /* [-+]@netgroup */
Packit 6c4009
    if (strncmp ("+@", luser, 2) == 0)
Packit 6c4009
	return innetgr (&luser[2], NULL, ruser, NULL);
Packit 6c4009
Packit 6c4009
    if (strncmp ("-@", luser,2) == 0)
Packit 6c4009
	return -innetgr (&luser[2], NULL, ruser, NULL);
Packit 6c4009
Packit 6c4009
    /* -user */
Packit 6c4009
    if (strncmp ("-", luser, 1) == 0)
Packit 6c4009
	return -(strcmp (&luser[1], ruser) == 0);
Packit 6c4009
Packit 6c4009
    /* + */
Packit 6c4009
    if (strcmp ("+", luser) == 0)
Packit 6c4009
	return 1;
Packit 6c4009
Packit 6c4009
    /* simple string match */
Packit 6c4009
    return strcmp (ruser, luser) == 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
__isempty (char *p)
Packit 6c4009
{
Packit 6c4009
    while (*p && isspace (*p)) {
Packit 6c4009
	++p;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
    return (*p == '\0' || *p == '#') ? 1 : 0 ;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Returns 0 if positive match, -1 if _not_ ok.
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
__validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
Packit 6c4009
		 const char *luser, const char *ruser, const char *rhost)
Packit 6c4009
{
Packit 6c4009
    const char *user;
Packit 6c4009
    char *p;
Packit 6c4009
    int hcheck, ucheck;
Packit 6c4009
    char *buf = NULL;
Packit 6c4009
    size_t bufsize = 0;
Packit 6c4009
    int retval = -1;
Packit 6c4009
Packit 6c4009
    while (__getline (&buf, &bufsize, hostf) > 0) {
Packit 6c4009
	buf[bufsize - 1] = '\0'; /* Make sure it's terminated.  */
Packit 6c4009
	p = buf;
Packit 6c4009
Packit 6c4009
	/* Skip empty or comment lines */
Packit 6c4009
	if (__isempty (p)) {
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	for (;*p && !isspace(*p); ++p) {
Packit 6c4009
	    *p = _tolower (*p);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
	/* Next we want to find the permitted name for the remote user.  */
Packit 6c4009
	if (*p == ' ' || *p == '\t') {
Packit 6c4009
	    /* <nul> terminate hostname and skip spaces */
Packit 6c4009
	    for (*p++='\0'; *p && isspace (*p); ++p);
Packit 6c4009
Packit 6c4009
	    user = p;                   /* this is the user's name */
Packit 6c4009
	    while (*p && !isspace (*p))
Packit 6c4009
		++p;                    /* find end of user's name */
Packit 6c4009
	} else
Packit 6c4009
	    user = p;
Packit 6c4009
Packit 6c4009
	*p = '\0';              /* <nul> terminate username (+host?) */
Packit 6c4009
Packit 6c4009
	/* buf -> host(?) ; user -> username(?) */
Packit 6c4009
	if (*buf == '\0')
Packit 6c4009
	  break;
Packit 6c4009
	if (*user == '\0')
Packit 6c4009
	  user = luser;
Packit 6c4009
Packit 6c4009
	/* First check the user part.  In a naive implementation we
Packit 6c4009
	   would check the host part first, then the user.  However,
Packit 6c4009
	   if we check the user first and reject the entry we will
Packit 6c4009
	   have saved doing any host lookups to normalize the comparison
Packit 6c4009
	   and that likely saves several DNS queries.  Therefore we
Packit 6c4009
	   check the user first.  */
Packit 6c4009
	ucheck = __icheckuser (user, ruser);
Packit 6c4009
Packit 6c4009
	/* Either we found the user, or we didn't and this is a
Packit 6c4009
	   negative host check.  We must do the negative host lookup
Packit 6c4009
	   in order to preserve the semantics of stopping on this line
Packit 6c4009
	   before processing others.  */
Packit 6c4009
	if (ucheck != 0 || *buf == '-') {
Packit 6c4009
Packit 6c4009
	    /* Next check host part.  */
Packit 6c4009
	    hcheck = __checkhost_sa (ra, ralen, buf, rhost);
Packit 6c4009
Packit 6c4009
	    /* Negative '-host user(?)' match?  */
Packit 6c4009
	    if (hcheck < 0)
Packit 6c4009
		break;
Packit 6c4009
Packit 6c4009
	    /* Positive 'host user' match?  */
Packit 6c4009
	    if (hcheck > 0 && ucheck > 0) {
Packit 6c4009
		retval = 0;
Packit 6c4009
		break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	    /* Negative 'host -user' match?  */
Packit 6c4009
	    if (hcheck > 0 && ucheck < 0)
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    /* Neither, go on looking for match.  */
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
    free (buf);
Packit 6c4009
Packit 6c4009
    return retval;
Packit 6c4009
}