Subject: bin/9050: inet6 support for lpd(8) and ipv6 support for libc/net/rcmd.c
To: None <gnats-bugs@gnats.netbsd.org>
From: Feico Dillema <dillema@acm.org>
List: netbsd-bugs
Date: 12/24/1999 06:13:56
>Number:         9050
>Category:       bin
>Synopsis:       bugfix plus inet6 support for lpd(8) (and libc/net fix for ip6)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Dec 24 06:12:00 1999
>Last-Modified:
>Originator:     Feico Dillema
>Organization:
University of Tromsų, Norway.
>Release:        Wed Dec 22 1999
>Environment:
System: NetBSD drifter.dillema.net 1.4P NetBSD 1.4P (DRIFTER) #7: Wed Dec 15 15:09:31 CET 1999 dillema@drifter.dillema.net:/home/dillema/cvs/src/sys/arch/i386/compile /DRIFTER i386
>Description:
		lpd(8) debug option doesn't work and lpd has no
		ipv6 support. Also rcmd.c in libc/net/ has no inet6
		support (contains code lpd uses).
>How-To-Repeat:
		lpd -d produces syslogged-error
		network printing from and to ipv6-only machine does not work.

>Fix:
		a patch for usr.sbin/lpr is attached to this email. It
		makes lpd work with either INET and/or INET6 address
		families. The patch lpr6.diff depends on the next
		patch attached for rcmd6.diff.

		The rcmd6.diff patch is included to add ipv6 support to the
		libc rcmd.c routines. Only one of the routines is
		really used by lpd(8) but this patch also adds ipv6
		support to the other routines (so that rlogin and
		friends support IPv6 hosts too). It looked to me that
		rcmd.c has been `overlooked' when adding the ipv6
		support to the libc. I think I've seen kame snapshots
		with ipv6 capable rlogind and such, and there are
		already ipv6-ready prototypes defined in unistd.h
		(like ruserok_af). Not all of these functions are
		provided in rcmd.c and my patch fixes this. Note,
		that this patch doesn't change any existing
		interfaces, but does add some. 

		Browsing the kame CVS repository, I found rlogind.c 
		rshd.c for NetBSD/kame. I've compiled that rlogind.c
		with my patched libc (with rcmd6.diff) installed and
		tested it for IPv6 and IPv4. Compiles and runs just
		fine without further modification (also tested
		/etc/hsots.equiv and .rhost behaviour a bit for both
		v4 and v6; seems just fine). So, maybe (if there's no
		good reason why it hasn't been done yet) the IPv6
		capable rlogind and rshd could be added to
		NetBSd-current.

		bait for itojun: inet6 in6 ip6 ipv6 IPv6 INET6 ;)



--tMbDGjvJuJijemkf
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="lpr6.diff"

diff -r -u usr.sbin/lpr/common_source/common.c usr.sbin/lpr6/common_source/common.c
--- usr.sbin/lpr/common_source/common.c	Sun Dec  5 23:10:57 1999
+++ usr.sbin/lpr6/common_source/common.c	Wed Dec 22 11:43:04 1999
@@ -128,60 +128,51 @@
 	char *rhost;
 	int rport;
 {
-	struct hostent *hp;
-	struct servent *sp;
-	struct sockaddr_in sin;
+        struct addrinfo hints, *res, *r;
+	int lport = IPPORT_RESERVEDMAX;
+        int err, s;
 	u_int timo = 1;
-	int s, lport = IPPORT_RESERVED - 1;
-	int err;
 
-	/*
-	 * Get the host address and port number to connect to.
-	 */
 	if (rhost == NULL)
 		fatal("no remote host to connect to");
-	memset(&sin, 0, sizeof(sin));
-	if (inet_aton(rhost, &sin.sin_addr) == 1)
-		sin.sin_family = AF_INET;
-	else {
-		hp = gethostbyname(rhost);
-		if (hp == NULL)
-			fatal("unknown host %s", rhost);
-		memmove(&sin.sin_addr, hp->h_addr, (size_t)hp->h_length);
-		sin.sin_family = hp->h_addrtype;
-	}
-	if (rport == 0) {
-		sp = getservbyname("printer", "tcp");
-		if (sp == NULL)
-			fatal("printer/tcp: unknown service");
-		sin.sin_port = sp->s_port;
-	} else
-		sin.sin_port = htons(rport);
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_family = PF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        err = getaddrinfo(rhost, "printer", &hints, &res);
+        if (err)
+                fatal(gai_strerror(err));
 
 	/*
 	 * Try connecting to the server.
 	 */
+        for (r = res; r; r = r->ai_next) {
 retry:
-	seteuid(euid);
-	s = rresvport(&lport);
-	seteuid(uid);
-	if (s < 0)
-		return(-1);
-	if (connect(s, (const struct sockaddr *)&sin, sizeof(sin)) < 0) {
-		err = errno;
-		(void)close(s);
-		errno = err;
-		if (errno == EADDRINUSE) {
-			lport--;
-			goto retry;
-		}
-		if (errno == ECONNREFUSED && timo <= 16) {
-			sleep(timo);
-			timo *= 2;
-			goto retry;
+		seteuid(euid);
+		s = rresvport_af(&lport, r->ai_family);
+		seteuid(uid);
+		if (s < 0)
+			continue;	/* continue trying, another address/AF might work */
+		if (connect(s, r->ai_addr, r->ai_addrlen) < 0) {
+			err = errno;
+			(void)close(s);
+			errno = err;
+			if (errno == EADDRINUSE) {
+				lport--;
+				goto retry;
+			}
+			if (errno == ECONNREFUSED && timo <= 16) {
+				sleep(timo);
+				timo *= 2;
+				goto retry;
+			}
 		}
-		return(-1);
+		else
+			break;
 	}
+
+	if (res) freeaddrinfo(res);
+	if (s < 0)
+		return(-1);
 	return(s);
 }
 
@@ -303,41 +294,58 @@
 char *
 checkremote()
 {
+	struct addrinfo hints, *res = NULL;
 	char hname[MAXHOSTNAMELEN + 1];
-	struct hostent *hp;
 	static char errbuf[128];
+	int err;
 
 	remote = 0;	/* assume printer is local */
 	if (RM != NULL) {
 		/* get the official name of the local host */
 		gethostname(hname, sizeof(hname));
 		hname[sizeof(hname)-1] = '\0';
-		hp = gethostbyname(hname);
-		if (hp == (struct hostent *) NULL) {
-		    (void)snprintf(errbuf, sizeof(errbuf),
-			"unable to get official name for local machine %s",
-			hname);
-		    return errbuf;
+
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_CANONNAME;
+		hints.ai_family = AF_UNSPEC;
+		hints.ai_socktype = SOCK_STREAM;
+		err = getaddrinfo(hname, NULL, &hints, &res);
+		if (err) {
+			if (res)
+				freeaddrinfo(res);
+			(void)snprintf(errbuf, sizeof(errbuf),
+				"unable to get official name for local machine %s: %s",
+				hname, gai_strerror(err));
+			return errbuf;
 		} else {
-			(void)strncpy(hname, hp->h_name, sizeof(hname) - 1);
-			hname[sizeof(hname) - 1] = '\0';
+			if (res)
+				freeaddrinfo(res);
+			(void)strcpy(hname, res->ai_canonname);
 		}
 
 		/* get the official name of RM */
-		hp = gethostbyname(RM);
-		if (hp == (struct hostent *) NULL) {
-		    (void)snprintf(errbuf, sizeof(errbuf),
-			"unable to get official name for remote machine %s",
-			RM);
-		    return errbuf;
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_CANONNAME;
+		hints.ai_family = AF_UNSPEC;
+		hints.ai_socktype = SOCK_STREAM;
+		err = getaddrinfo(RM, NULL, &hints, &res);
+		if (err) {
+			if (res)
+				freeaddrinfo(res);
+			(void)snprintf(errbuf, sizeof(errbuf),
+				"unable to get official name for remote machine %s: %s",
+				RM, gai_strerror(err));
+		    	return errbuf;
 		}
 
 		/*
 		 * if the two hosts are not the same,
 		 * then the printer must be remote.
 		 */
-		if (strcasecmp(hname, hp->h_name) != 0)
+		if (strcasecmp(hname, res->ai_canonname) != 0)
 			remote = 1;
+		if (res)
+			freeaddrinfo(res);
 	}
 	return NULL;
 }
diff -r -u usr.sbin/lpr/lpd/extern.h usr.sbin/lpr6/lpd/extern.h
--- usr.sbin/lpr/lpd/extern.h	Sun Oct  5 17:12:12 1997
+++ usr.sbin/lpr6/lpd/extern.h	Wed Dec 22 11:43:05 1999
@@ -39,6 +39,7 @@
 #include <termios.h>
 #include <sys/ioctl.h>
 #include <stdio.h>
+#include <sys/socket.h>
 
 /*
  * from stty.h
@@ -64,4 +65,4 @@
 void       sttysetlflags __P((struct termios *tp, int flags));
 
 /* XXX from libc/net/rcmd.c */
-int        __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
+int        __ivaliduser2 __P((FILE *, struct sockaddr *, const char *, const char *));
diff -r -u usr.sbin/lpr/lpd/lpd.c usr.sbin/lpr6/lpd/lpd.c
--- usr.sbin/lpr/lpd/lpd.c	Tue Dec  7 15:54:46 1999
+++ usr.sbin/lpr6/lpd/lpd.c	Wed Dec 22 11:43:05 1999
@@ -116,9 +116,10 @@
 static void       mcleanup __P((int));
 static void       doit __P((void));
 static void       startup __P((void));
-static void       chkhost __P((struct sockaddr_in *));
+static void       chkhost __P((struct sockaddr_storage *));
 static int	  ckqueue __P((char *));
 static void	  usage __P((void));
+static int	  *socksetup __P((int, int));
 
 uid_t	uid, euid;
 int child_count;
@@ -128,10 +129,10 @@
 	int argc;
 	char **argv;
 {
-	int f, funix, finet, options, fromlen;
+	int f, funix, *finet, options, fromlen;
 	fd_set defreadfds;
 	struct sockaddr_un un, fromunix;
-	struct sockaddr_in sin, frominet;
+	struct sockaddr_storage frominet;
 	int omask, lfd, errs, i;
 	int child_max = 32;	/* more then enough to hose the system */
 
@@ -242,31 +243,15 @@
 	FD_SET(funix, &defreadfds);
 	listen(funix, 5);
 	if (!sflag)
-		finet = socket(AF_INET, SOCK_STREAM, 0);
+		finet = socksetup(PF_UNSPEC, options);
 	else
-		finet = -1;	/* pretend we couldn't open TCP socket. */
-	if (finet >= 0) {
-		struct servent *sp;
+		finet = NULL;	/* pretend we couldn't open TCP socket. */
 
-		if (options & SO_DEBUG)
-			if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) {
-				syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
-				mcleanup(0);
-			}
-		sp = getservbyname("printer", "tcp");
-		if (sp == NULL) {
-			syslog(LOG_ERR, "printer/tcp: unknown service");
-			mcleanup(0);
+	if (finet) {
+		for (i = 1; i <= *finet; i++) {
+			FD_SET(finet[i], &defreadfds);
+			listen(finet[i], 5);
 		}
-		memset(&sin, 0, sizeof(sin));
-		sin.sin_family = AF_INET;
-		sin.sin_port = sp->s_port;
-		if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
-			syslog(LOG_ERR, "bind: %m");
-			mcleanup(0);
-		}
-		FD_SET(finet, &defreadfds);
-		listen(finet, 5);
 	}
 	/*
 	 * Main loop: accept, do a request, continue.
@@ -302,10 +287,12 @@
 			domain = AF_LOCAL, fromlen = sizeof(fromunix);
 			s = accept(funix,
 			    (struct sockaddr *)&fromunix, &fromlen);
-		} else /* if (FD_ISSET(finet, &readfds)) */  {
-			domain = AF_INET, fromlen = sizeof(frominet);
-			s = accept(finet,
-			    (struct sockaddr *)&frominet, &fromlen);
+		} else {
+                        for (i = 1; i <= *finet; i++) 
+				if (FD_ISSET(finet[i], &readfds)) {
+					domain = AF_INET, fromlen = sizeof(frominet);
+					s = accept(finet[i], (struct sockaddr *)&frominet, &fromlen);
+				}
 		}
 		if (s < 0) {
 			if (errno != EINTR)
@@ -321,11 +308,13 @@
 			signal(SIGQUIT, SIG_IGN);
 			signal(SIGTERM, SIG_IGN);
 			(void)close(funix);
-			if (!sflag)
-				(void)close(finet);
+			if (!sflag && finet)
+                        	for (i = 1; i <= *finet; i++) 
+					(void)close(finet[i]);
 			dup2(s, 1);
 			(void)close(s);
 			if (domain == AF_INET) {
+				/* for both AF_INET and AF_INET6 */
 				from_remote = 1;
 				chkhost(&frominet);
 			} else
@@ -372,7 +361,7 @@
 int	requests;		/* # of spool requests */
 char	*person;		/* name of person doing lprm */
 
-char	fromb[MAXHOSTNAMELEN];	/* buffer for client's machine name */
+char	fromb[NI_MAXHOST];	/* buffer for client's machine name */
 char	cbuf[BUFSIZ];		/* command line buffer */
 char	*cmdnames[] = {
 	"null",
@@ -564,46 +553,59 @@
  */
 static void
 chkhost(f)
-	struct sockaddr_in *f;
+	struct sockaddr_storage *f;
 {
-	struct hostent *hp;
+        struct addrinfo *res, *r;
+	int first = 1, good = 0, error;
+	char host[NI_MAXHOST], ip[NI_MAXHOST];
 	FILE *hostf;
-	int first = 1, good = 0;
 
-	f->sin_port = ntohs(f->sin_port);
-	if (f->sin_family != AF_INET || f->sin_port >= IPPORT_RESERVED)
-		fatal("Malformed from address");
+	if ((((struct sockaddr_in *) f)->sin_family != AF_INET &&
+	      	((struct sockaddr_in6 *) f)->sin6_family != AF_INET6) || 
+		ntohs(((struct sockaddr_in *)f)->sin_port) >= IPPORT_RESERVED)
+		fatal("Malformed from address or non-reserved port");
 
 	/* Need real hostname for temporary filenames */
-	hp = gethostbyaddr((char *)&f->sin_addr,
-	    sizeof(struct in_addr), f->sin_family);
-	if (hp == NULL)
-		fatal("Host name for your address (%s) unknown",
-			inet_ntoa(f->sin_addr));
+	error = getnameinfo(((struct sockaddr *) f), 
+		((struct sockaddr *) f)->sa_len, host, NI_MAXHOST, 
+		NULL, 0, NI_NAMEREQD);
+	if (error)
+		fatal("Host name for your address (%s) unknown", host);
 
-	(void)strncpy(fromb, hp->h_name, sizeof(fromb) - 1);
+	(void)strncpy(fromb, host, sizeof(fromb) - 1);
 	from[sizeof(fromb) - 1] = '\0';
 	from = fromb;
 
+	/* need address in stringform for comparison (no DNS lookup here) */
+	error = getnameinfo(((struct sockaddr *) f), 
+			    ((struct sockaddr *) f)->sa_len, 
+			    host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+	if (error)
+		fatal("Cannot print address (%s)", host);
+
 	/* Check for spoof, ala rlogind */
-	hp = gethostbyname(fromb);
-	if (!hp)
-		fatal("hostname for your address (%s) unknown",
-		    inet_ntoa(f->sin_addr));
-	for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) {
-		if (!memcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr,
-		    sizeof(f->sin_addr)))
+        error = getaddrinfo(fromb, NULL, NULL, &res);
+        if (error)
+		fatal("hostname for your address (%s) unknown: %s", 
+			host, gai_strerror(error));
+
+        for (r = res; good == 0 && r; r = r->ai_next) {
+	        error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, NI_MAXHOST,
+ 				    NULL, 0, NI_NUMERICHOST);
+		if (!error && !strcmp(host, ip))
 			good = 1;
 	}
+	if (res)
+		freeaddrinfo(res);
+
 	if (good == 0)
-		fatal("address for your hostname (%s) not matched",
-		    inet_ntoa(f->sin_addr));
+		fatal("address for your hostname (%s) not matched in DNS", host);
+
 	setproctitle("serving %s", from);
 	hostf = fopen(_PATH_HOSTSEQUIV, "r");
 again:
 	if (hostf) {
-		if (__ivaliduser(hostf, f->sin_addr.s_addr,
-		    DUMMY, DUMMY) == 0) {
+		if (__ivaliduser2(hostf, (struct sockaddr *)f, DUMMY, DUMMY) == 0) {
 			(void)fclose(hostf);
 			return;
 		}
@@ -626,3 +628,67 @@
 	fprintf(stderr, "usage: %s [-d] [-l]\n", __progname);
 	exit(1);
 }
+
+/* setup server socket for specified address family */
+/* if af is PF_UNSPEC more than one socket may be returned */
+/* the returned list is dynamically allocated, so caller needs to free it */
+int *
+socksetup(af, options)
+        int af, options;
+{
+        struct addrinfo hints, *res, *r;
+        int error, maxs, *s, *socks;
+	const int on = 1;
+
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_PASSIVE;
+        hints.ai_family = af;
+        hints.ai_socktype = SOCK_STREAM;
+        error = getaddrinfo(NULL, "printer", &hints, &res);
+        if (error) {
+                syslog(LOG_ERR, (gai_strerror(error)));
+		mcleanup(0);
+	}
+
+        /* Count max number of sockets we may open */
+        for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
+        socks = malloc ((maxs+1) * sizeof(int));
+        if (!socks) {
+		syslog(LOG_ERR, "couldn't allocate memory for sockets");
+		mcleanup(0);
+	}
+ 
+        *socks = 0;   /* num of sockets counter at start of array */
+        s = socks+1;
+        for (r = res; r; r = r->ai_next) {
+                *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+                if (*s < 0) {
+        		syslog(LOG_DEBUG, "socket(): %m");
+                        continue;
+		}
+		if (options & SO_DEBUG)
+			if (setsockopt(*s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)) < 0) {
+				syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
+                        	close (*s);
+				continue;
+			}
+                if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
+        		syslog(LOG_DEBUG, "bind(): %m");
+                        close (*s);
+                        continue;
+                }
+                *socks = *socks + 1;
+                s++;
+        }
+
+        if (res)
+                freeaddrinfo(res);
+
+        if (*socks == 0) {
+                syslog(LOG_ERR, "Couldn't bind to any socket");
+                free (socks);
+		mcleanup(0);
+        }
+        return(socks);
+}
+

--tMbDGjvJuJijemkf
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="rcmd6.diff"

--- lib/libc/net/rcmd.c	Wed Dec 22 12:05:07 1999
+++ lib/libc/net/rcmd6.c	Wed Dec 22 12:15:07 1999
@@ -75,13 +75,14 @@
 
 int	orcmd __P((char **, u_int, const char *, const char *, const char *,
 	    int *));
-int	__ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
+int	iruserok2 __P((struct sockaddr *, int, const char *, const char *));
+int	__ivaliduser2 __P((FILE *, struct sockaddr *, const char *, const char *));
 static	int rshrcmd __P((char **, u_int32_t, const char *, const char *,
 	    const char *, int *, const char *));
-static	int hprcmd __P((struct hostent *, char **, u_int32_t, const char *,
+static	int hprcmd __P((struct addrinfo *, char **, u_int32_t, const char *,
 	    const char *, const char *, int *));
-static	int __icheckhost __P((u_int32_t, const char *));
-static	char *__gethostloop __P((u_int32_t));
+static	int __icheckhost __P((struct sockaddr *, const char *));
+static	int __gethostloop __P((struct sockaddr *, char *));
 
 int
 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
@@ -90,8 +91,10 @@
 	const char *locuser, *remuser, *cmd;
 	int *fd2p;
 {
-	struct hostent *hp;
+        struct addrinfo hints, *res, *ai;
+        char num[NI_MAXSERV];
 	struct servent *sp;
+	int error;
 
 	_DIAGASSERT(ahost != NULL);
 	_DIAGASSERT(locuser != NULL);
@@ -103,12 +106,23 @@
 	 * Canonicalise hostname.
 	 * XXX: Should we really do this?
 	 */
-	hp = gethostbyname(*ahost);
-	if (hp == NULL) {
-		herror(*ahost);
-		return (-1);
-	}
-	*ahost = hp->h_name;
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_CANONNAME;
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
+        error = getaddrinfo(*ahost, num, &hints, &res);
+        if (error) {
+                fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+                        gai_strerror(error));
+                return (-1);
+        }
+	ai = &hints;
+	(void)memcpy(ai, res, sizeof(*ai));
+        if (ai->ai_canonname)
+		*ahost = ai->ai_canonname;
+	if (res)
+		freeaddrinfo(res);
 
 	/*
 	 * Check if rport is the same as the shell port, and that the fd2p.  If
@@ -120,7 +134,7 @@
 		return (rshrcmd(ahost, (u_int32_t)rport,
 		    locuser, remuser, cmd, fd2p, getenv("RCMD_CMD")));
 	else
-		return (hprcmd(hp, ahost, (u_int32_t)rport,
+		return (hprcmd(ai, ahost, (u_int32_t)rport,
 		    locuser, remuser, cmd, fd2p));
 }
 
@@ -132,7 +146,9 @@
 	const char *locuser, *remuser, *cmd;
 	int *fd2p;
 {
-	struct hostent *hp;
+        struct addrinfo hints, *res, *ai;
+        char num[NI_MAXSERV];
+	int error;
 
 	_DIAGASSERT(ahost != NULL);
 	_DIAGASSERT(locuser != NULL);
@@ -140,29 +156,42 @@
 	_DIAGASSERT(cmd != NULL);
 	/* fd2p may be NULL */
 
-	hp = gethostbyname(*ahost);
-	if (hp == NULL) {
-		herror(*ahost);
-		return (-1);
-	}
-	*ahost = hp->h_name;
-	
-	return (hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p));
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_CANONNAME;
+        hints.ai_family = AF_UNSPEC;
+        hints.ai_socktype = SOCK_STREAM;
+        (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
+        error = getaddrinfo(*ahost, num, &hints, &res);
+        if (error) {
+                fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+                        gai_strerror(error));
+                return (-1);
+        }
+	ai = &hints;
+	(void)memcpy(ai, res, sizeof(*ai));
+        if (ai->ai_canonname)
+		*ahost = ai->ai_canonname;
+	if (res)
+		freeaddrinfo(res);
+
+	return (hprcmd(ai, ahost, rport, locuser, remuser, cmd, fd2p));
 }
 
 static int
-hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
-	struct hostent *hp;
+hprcmd(res, ahost, rport, locuser, remuser, cmd, fd2p)
+	struct addrinfo *res;
 	char **ahost;
 	u_int32_t rport;
 	const char *locuser, *remuser, *cmd;
 	int *fd2p;
 {
-	struct sockaddr_in sin, from;
+        struct sockaddr_storage from;
+	struct addrinfo *ai;
 	struct pollfd reads[2];
+	char addrstr[INET6_ADDRSTRLEN];
 	sigset_t nmask, omask;
 	pid_t pid;
-	int s, lport, timo;
+	int s, lport, timo, refused;
 	int pollr;
 	char c;
 
@@ -178,8 +207,10 @@
 	sigaddset(&nmask, SIGURG);
 	if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)
 		return -1;
+        ai = res;
+        refused = 0;
 	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
-		s = rresvport(&lport);
+		s = rresvport_af(&lport, ai->ai_family);
 		if (s < 0) {
 			if (errno == EAGAIN)
 				warnx("rcmd: socket: All ports in use");
@@ -189,40 +220,42 @@
 			return (-1);
 		}
 		fcntl(s, F_SETOWN, pid);
-#ifdef BSD4_4
-		sin.sin_len = sizeof(struct sockaddr_in);
-#endif
-		sin.sin_family = hp->h_addrtype;
-		sin.sin_port = rport;
-		memmove(&sin.sin_addr,
-		    hp->h_addr_list[0], (size_t)hp->h_length);
-		if (connect(s, (struct sockaddr *)(void *)&sin, sizeof(sin)) >= 0)
+		if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
 			break;
 		(void)close(s);
 		if (errno == EADDRINUSE) {
 			lport--;
 			continue;
 		}
-		if (errno == ECONNREFUSED && timo <= 16) {
+		if (errno == ECONNREFUSED) 
+			refused = 1;
+
+                if (ai->ai_next) {
+                        int oerrno = errno;
+                        getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                                    addrstr, sizeof(addrstr),
+                                    NULL, 0,
+                                    NI_NUMERICHOST);
+                        fprintf(stderr, "connect to address %s: ", addrstr);
+                        errno = oerrno;
+                        perror(0);
+                        ai = ai->ai_next;
+                        getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                                    addrstr, sizeof(addrstr),
+                                    NULL, 0,
+                                    NI_NUMERICHOST);
+                        fprintf(stderr, "Trying %s...\n", addrstr);
+                        continue;
+                }
+                if (refused && timo <= 16) {
 			(void)sleep((unsigned int)timo);
-			timo *= 2;
-			continue;
-		}
-		if (hp->h_addr_list[1] != NULL) {
-			int oerrno = errno;
+                        timo *= 2;
+                        ai = res;
+                        refused = 0;
+                        continue;
+                }
 
-			warnx("rcmd: connect to address %s",
-			    inet_ntoa(sin.sin_addr));
-			errno = oerrno;
-			perror(0);
-			hp->h_addr_list++;
-			memmove(&sin.sin_addr, hp->h_addr_list[0],
-			    (size_t)hp->h_length);
-			(void)fprintf(stderr, "Trying %s...\n",
-			    inet_ntoa(sin.sin_addr));
-			continue;
-		}
-		(void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
+                (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno));
 		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
 		return (-1);
 	}
@@ -232,8 +265,8 @@
 		lport = 0;
 	} else {
 		char num[8];
-		int s2 = rresvport(&lport), s3;
-		socklen_t len = sizeof(from);
+		int s2 = rresvport_af(&lport, ai->ai_family), s3;
+		socklen_t len = ai->ai_addrlen;
 
 		if (s2 < 0)
 			goto bad;
@@ -258,7 +291,19 @@
 			(void)close(s2);
 			goto bad;
 		}
-		s3 = accept(s2, (struct sockaddr *)(void *)&from, &len);
+		s3 = accept(s2, (struct sockaddr *)&from, &len);
+                switch (((struct sockaddr *)&from)->sa_family) {
+                case AF_INET:
+                        rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
+                        break;
+                case AF_INET6:
+                        rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
+                        break;
+                default:
+                        rport = 0;      /* error */
+                        break;
+                }
+
 		(void)close(s2);
 		if (s3 < 0) {
 			warn("rcmd: accept");
@@ -266,10 +311,8 @@
 			goto bad;
 		}
 		*fd2p = s3;
-		from.sin_port = ntohs(from.sin_port);
-		if (from.sin_family != AF_INET ||
-		    from.sin_port >= IPPORT_RESERVED ||
-		    from.sin_port < IPPORT_RESERVED / 2) {
+
+                if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2) {
 			warnx("rcmd: protocol failure in circuit setup.");
 			goto bad2;
 		}
@@ -502,30 +545,39 @@
 char	*__rcmd_errstr;
 
 int
-ruserok(rhost, superuser, ruser, luser)
+ruserok_af(rhost, superuser, ruser, luser, af)
 	const char *rhost, *ruser, *luser;
-	int superuser;
+	int superuser, af;
 {
-	struct hostent *hp;
-	char **ap;
-	int i;
-#define MAXADDRS	35
-	u_int32_t addrs[MAXADDRS + 1];
+        struct addrinfo hints, *res, *r;
+	int error, retval;
 
 	_DIAGASSERT(rhost != NULL);
 	_DIAGASSERT(ruser != NULL);
 	_DIAGASSERT(luser != NULL);
 
-	if ((hp = gethostbyname(rhost)) == NULL)
-		return (-1);
-	for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i)
-		memmove(&addrs[i], *ap, sizeof(addrs[i]));
-	addrs[i] = 0;
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_CANONNAME;
+        hints.ai_family = af;
+        hints.ai_socktype = SOCK_STREAM;
+        error = getaddrinfo(rhost, NULL, &hints, &res);
+        if (error) 
+                return (-1);
+
+        for (retval = -1, r = res; (retval == -1) && r; r = r->ai_next) 
+                if (iruserok2(r->ai_addr, superuser, ruser, luser) == 0) 
+			retval = 0;
+	if (res) 
+		freeaddrinfo(res);
+	return(retval);
+}
 
-	for (i = 0; i < MAXADDRS && addrs[i]; i++)
-		if (iruserok(addrs[i], superuser, ruser, luser) == 0)
-			return (0);
-	return (-1);
+int
+ruserok(rhost, superuser, ruser, luser)
+	const char *rhost, *ruser, *luser;
+	int superuser;
+{
+	return(ruserok_af(rhost, superuser, ruser, luser, AF_INET));
 }
 
 /*
@@ -538,8 +590,8 @@
  * Returns 0 if ok, -1 if not ok.
  */
 int
-iruserok(raddr, superuser, ruser, luser)
-	u_int32_t raddr;
+iruserok2(raddr, superuser, ruser, luser)
+	struct sockaddr *raddr;
 	int superuser;
 	const char *ruser, *luser;
 {
@@ -559,7 +611,7 @@
 	hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
 again:
 	if (hostf) {
-		if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
+		if (__ivaliduser2(hostf, raddr, luser, ruser) == 0) {
 			(void)fclose(hostf);
 			return (0);
 		}
@@ -614,6 +666,55 @@
 	return (-1);
 }
 
+/* 
+ * bit ugly stubs, just to avoid changing the interface of iruserok() 
+ * I'd prefer to replace all calls by __iruserok2() at all times.
+ * But, I have these here as that seems the more correct thing to
+ * do for now...
+ */
+int
+iruserok(raddr, superuser, ruser, luser)
+        u_int32_t raddr;
+        int superuser;
+        const char *ruser, *luser;
+{
+        struct sockaddr_in rem_addr;
+
+        rem_addr.sin_len = sizeof(struct sockaddr_in);
+        rem_addr.sin_family = AF_INET;
+        rem_addr.sin_port = 0;
+        rem_addr.sin_addr.s_addr = raddr;
+        return iruserok2((struct sockaddr *)&rem_addr, superuser, ruser, luser);
+}
+
+int
+iruserok_af(raddr, superuser, ruser, luser, af)
+        const void *raddr;
+        int superuser, af;
+        const char *ruser, *luser;
+{
+        struct sockaddr_storage rem_addr;
+
+        switch (af) {
+        case AF_INET:
+        	((struct sockaddr_in *) &rem_addr)->sin_len = sizeof(struct sockaddr_in);
+        	((struct sockaddr_in *) &rem_addr)->sin_family = af;
+        	((struct sockaddr_in *) &rem_addr)->sin_port = 0;
+		bcopy(raddr, &((struct sockaddr_in *) &rem_addr)->sin_addr, 
+			sizeof(struct in_addr)); 
+		break;
+        case AF_INET6:
+        	((struct sockaddr_in6 *) &rem_addr)->sin6_len = sizeof(struct sockaddr_in6);
+        	((struct sockaddr_in6 *) &rem_addr)->sin6_family = af;
+        	((struct sockaddr_in6 *) &rem_addr)->sin6_port = 0;
+		bcopy(raddr, &((struct sockaddr_in6 *) &rem_addr)->sin6_addr,
+			sizeof(struct in6_addr));
+		break;
+	}
+        return iruserok2((struct sockaddr *)&rem_addr, superuser, ruser, luser);
+}
+
+
 /*
  * XXX
  * Don't make static, used by lpd(8).
@@ -621,9 +722,9 @@
  * Returns 0 if ok, -1 if not ok.
  */
 int
-__ivaliduser(hostf, raddr, luser, ruser)
+__ivaliduser2(hostf, raddr, luser, ruser)
 	FILE *hostf;
-	u_int32_t raddr;
+	struct sockaddr *raddr;
 	const char *luser, *ruser;
 {
 	register char *user, *p;
@@ -631,7 +732,7 @@
 	char buf[MAXHOSTNAMELEN + 128];		/* host + login */
 	const char *auser, *ahost;
 	int hostok, userok;
-	char *rhost = NULL;
+	char rhost[MAXHOSTNAMELEN];
 	int firsttime = 1;
 	char domain[MAXHOSTNAMELEN];
 
@@ -679,10 +780,10 @@
 
 			case '@':
 				if (firsttime) {
-					rhost = __gethostloop(raddr);
+					hostok = __gethostloop(raddr, rhost);
 					firsttime = 0;
 				}
-				if (rhost)
+				if (hostok)
 					hostok = innetgr(&ahost[2], rhost,
 					    NULL, domain);
 				else
@@ -701,10 +802,10 @@
 
 			case '@':
 				if (firsttime) {
-					rhost = __gethostloop(raddr);
+					hostok = __gethostloop(raddr, rhost);
 					firsttime = 0;
 				}
-				if (rhost)
+				if (hostok)
 					hostok = -innetgr(&ahost[2], rhost,
 					    NULL, domain);
 				else
@@ -718,7 +819,6 @@
 		else
 			hostok = __icheckhost(raddr, ahost);
 
-
 		if (auser[0] == '+')
 			switch (auser[1]) {
 			case '\0':
@@ -768,35 +868,66 @@
 	return -1;
 }
 
+#if 0
+/* 
+ * bit ugly, just to avoid changing the interface of iruserok() 
+ * better use __invaliduser2() at all times. As lpd now uses
+ * __ivaliduser2() this one could be removed? I think so...
+ */
+static int
+__ivaliduser(hostf, raddr, luser, ruser)
+        FILE *hostf;
+        u_int32_t raddr;
+        const char *luser, *ruser;
+{
+	struct sockaddr_in rem_addr;
+
+	rem_addr.sin_len = sizeof(struct sockaddr_in);
+	rem_addr.sin_family = AF_INET;
+	rem_addr.sin_port = 0;
+	rem_addr.sin_addr.s_addr = raddr;
+	return __ivaliduser2(hostf, (struct sockaddr *) &rem_addr, luser, ruser);
+}
+#endif
+
 /*
  * Returns "true" if match, 0 if no match.
  */
 static int
 __icheckhost(raddr, lhost)
-	u_int32_t raddr;
+	struct sockaddr *raddr;
 	const char *lhost;
 {
-	struct hostent *hp;
-	struct in_addr laddr;
-	char **pp;
+	char laddr[NI_MAXHOST], ip[NI_MAXHOST];
+        struct addrinfo *res, *r;
+	int error, status = 0;
 
 	_DIAGASSERT(lhost != NULL);
 
-	/* Try for raw ip address first. */
-	if (isdigit((unsigned char)*lhost) && inet_aton(lhost, &laddr) != 0)
-		return (raddr == laddr.s_addr);
-
-	/* Better be a hostname. */
-	if ((hp = gethostbyname(lhost)) == NULL)
-		return (0);
-
+	/* Get ip address in string form first. */
+        error = getnameinfo(((struct sockaddr *) raddr),
+			((struct sockaddr *) raddr)->sa_len,
+			laddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+
+	/* Get list of addresses */
+        error = getaddrinfo(lhost, NULL, NULL, &res);
+        if (error)
+		return(0);	
+                        
 	/* Spin through ip addresses. */
-	for (pp = hp->h_addr_list; *pp; ++pp)
-		if (!memcmp(&raddr, *pp, sizeof(u_int32_t)))
-			return (1);
+        for (r = res; !status && r; r = r->ai_next) {
+		/* Get address to compare in string form */
+                error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, NI_MAXHOST,
+                                    NULL, 0, NI_NUMERICHOST);
+                if (!error && !strcmp(laddr, ip))
+			status = 1;
+        }               
+
+	if (res)
+		freeaddrinfo(res);
 
 	/* No match. */
-	return (0);
+	return (status);
 }
 
 /*
@@ -804,38 +935,50 @@
  * Do a reverse lookup as well for security. If a loop cannot
  * be found, pack the result of inet_ntoa() into the string.
  */
-static char *
-__gethostloop(raddr)
-	u_int32_t raddr;
-{
-	static char remotehost[MAXHOSTNAMELEN];
-	struct hostent *hp;
-	struct in_addr in;
-
-	hp = gethostbyaddr((char *)(void *)&raddr, sizeof(raddr), AF_INET);
-	if (hp == NULL)
-		return (NULL);
+static int
+__gethostloop(raddr, remotehost)
+	struct sockaddr *raddr;
+	char *remotehost;
+{
+	char rip[NI_MAXHOST], ip[NI_MAXHOST];
+        struct addrinfo *res, *r;
+	int error, status = 0;
+
+	/* get hostname for address */
+	if (getnameinfo(raddr, raddr->sa_len, remotehost, NI_MAXHOST, 
+		NULL, 0, NI_NAMEREQD))
+		return(-1);
 
 	/*
 	 * Look up the name and check that the supplied
 	 * address is in the list
 	 */
-	strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
-	remotehost[sizeof(remotehost) - 1] = '\0';
-	hp = gethostbyname(remotehost);
-	if (hp == NULL)
-		return (NULL);
-
-	for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++)
-		if (!memcmp(hp->h_addr_list[0], &raddr, sizeof(raddr)))
-			return (remotehost);
+        if (getaddrinfo(remotehost, NULL, NULL, &res))
+		return(-1);
+
+	/* we need ascii rep. of orig address for comparison */
+       if (getnameinfo(raddr, raddr->sa_len, rip, NI_MAXHOST, 
+			NULL, 0, NI_NUMERICHOST))
+		return(-1);
+
+        for (r = res; !status && r; r = r->ai_next) {
+                error = getnameinfo(r->ai_addr, r->ai_addrlen, ip, NI_MAXHOST,
+                                    NULL, 0, NI_NUMERICHOST);
+                if (!error && !strcmp(rip, ip))
+			status = 1;
+        }
+
+	if (res)
+		freeaddrinfo(res);
+
+	if (status) 
+		return(0); /* success */
 
 	/*
 	 * either the DNS adminstrator has made a configuration
 	 * mistake, or someone has attempted to spoof us
 	 */
-	in.s_addr = raddr;
 	syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s",
-	    inet_ntoa(in), hp->h_name);
-	return (NULL);
+	    rip, remotehost);
+	return (-1);
 }

--tMbDGjvJuJijemkf--
>Audit-Trail:
>Unformatted:
--tMbDGjvJuJijemkf
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit