NetBSD Problem Report #9050
Received: (qmail 6167 invoked from network); 24 Dec 1999 14:06:27 -0000
Message-Id: <19991224144252.G1036@acm.org>
Date: Fri, 24 Dec 1999 14:42:52 +0100
From: Feico Dillema <dillema@acm.org>
Reply-To: feico@pasta.cs.uit.no
To: gnats-bugs@gnats.netbsd.org
Subject: inet6 support for lpd(8) and ipv6 support for libc/net/rcmd.c
X-Send-Pr-Version: 3.95
>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: itojun
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Dec 24 06:12:00 +0000 1999
>Closed-Date: Sat Jan 29 04:50:25 +0000 2000
>Last-Modified: Sat Jan 29 04:50:38 +0000 2000
>Originator: Feico Dillema
>Release: Wed Dec 22 1999
>Organization:
University of Tromsų, Norway.
>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--
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: bin-bug-people->itojun
Responsible-Changed-By: itojun
Responsible-Changed-When: Fri Dec 24 18:17:52 PST 1999
Responsible-Changed-Why:
yup, i found it tihs time:-)
From: itojun@iijlab.net
To: feico@pasta.cs.uit.no
Cc: gnats-bugs@gnats.netbsd.org
Subject: Re: bin/9050: inet6 support for lpd(8) and ipv6 support for libc/net/rcmd.c
Date: Sun, 26 Dec 1999 00:52:34 +0900
> 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.
Another reason why I did not commit rsh/rlogin into NetBSD-current
is that I'm not very convinced about ruserok_af() interface.
ruserok_af() takes string hostname as argument, and it does not really
make sense to specify address family with it.
since iruserok() and ruserok() are local to BSD, there's no standard
document to rely upon. (draft-ietf-ipngwg-rfc2292bis-01.txt talks
about rresvport_af(), rcmd_af() and rexec_af())
itojun
Date: Fri, 14 Jan 2000 08:36:22 -0800
From: Jun-ichiro itojun Hagino <itojun@iijlab.net>
Subject: net/9050
ruserok_af, bindresvport_af and some others are not really
standardized (since they are BSD origin and not in posix?).
I'm now trying to get rough consensus among at least those who
are on IETF ipngwg mailing list. I'll commit those functions
after the discussion gets mature (I hope it to be by end of Jan)
itojun
State-Changed-From-To: open->feedback
State-Changed-By: itojun
State-Changed-When: Wed Jan 26 21:39:56 PST 2000
State-Changed-Why:
committed, with different rcmd-api due to standard document conformance
and *BSD synchronization. please check if it works for you.
State-Changed-From-To: feedback->closed
State-Changed-By: itojun
State-Changed-When: Fri Jan 28 20:50:25 PST 2000
State-Changed-Why:
submitter confirmed.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.49 2026/05/14 01:52:41 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.