summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>2000-01-13 15:09:48 +0000
committershin <shin@FreeBSD.org>2000-01-13 15:09:48 +0000
commit16085f42949d88bd0ba1801e6647b2c8777e30ba (patch)
tree3044ff81791eccd3209a757b144f64151f00275b /lib/libc
parent8813e718dc87a6dcf42bd2743686c7a74df222ca (diff)
downloadFreeBSD-src-16085f42949d88bd0ba1801e6647b2c8777e30ba.zip
FreeBSD-src-16085f42949d88bd0ba1801e6647b2c8777e30ba.tar.gz
libc rcmd update for IPv6.
A new function bindresvport2(), AF independent version of bindresvport() is also added. Reviewed by: sumikawa Obtained from: KAME project
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/net/rcmd.335
-rw-r--r--lib/libc/net/rcmd.c267
-rw-r--r--lib/libc/rpc/Makefile.inc3
-rw-r--r--lib/libc/rpc/bindresvport.32
-rw-r--r--lib/libc/rpc/bindresvport.c76
5 files changed, 295 insertions, 88 deletions
diff --git a/lib/libc/net/rcmd.3 b/lib/libc/net/rcmd.3
index 0154e82..b00f94a 100644
--- a/lib/libc/net/rcmd.3
+++ b/lib/libc/net/rcmd.3
@@ -39,7 +39,10 @@
.Nm rcmd ,
.Nm rresvport ,
.Nm iruserok ,
-.Nm ruserok
+.Nm ruserok ,
+.Nm rresvport_af ,
+.Nm iruserok_af ,
+.Nm ruserok_af
.Nd routines for returning a stream to a remote command
.Sh SYNOPSIS
.Fd #include <unistd.h>
@@ -51,6 +54,12 @@
.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
.Ft int
.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
+.Ft int
+.Fn rresvport_af "int *port" "int family"
+.Ft int
+.Fn iruserok_af "void *raddr" "int superuser" "const char *ruser" "const char *luser" "int af"
+.Ft int
+.Fn ruserok_af "const char *rhost" "int superuser" "const char *ruser" "const char *luser" "int af"
.Sh DESCRIPTION
The
.Fn rcmd
@@ -173,6 +182,19 @@ function is strongly preferred for security reasons.
It requires trusting the local DNS at most, while the
.Fn ruserok
function requires trusting the entire DNS, which can be spoofed.
+.Pp
+Functions with ``_af'' suffix, i.e.
+.Fn rresvport_af ,
+.Fn iruserok_af and
+.Fn ruserok_af ,
+works just as same as functions without ``_af'', and is capable of
+handling both IPv6 port and IPv4 port.
+To switch address family,
+.Fa af
+argument must be filled with
+.Dv AF_INET
+or
+.Dv AF_INET6 .
.Sh DIAGNOSTICS
The
.Fn rcmd
@@ -198,7 +220,18 @@ is overloaded to mean ``All network ports in use.''
.Xr rexecd 8 ,
.Xr rlogind 8 ,
.Xr rshd 8
+.Pp
+W. Stevens and M. Thomas, ``Advanced Socket API for IPv6,''
+RFC2292.
.Sh HISTORY
These
functions appeared in
.Bx 4.2 .
+.Fn rresvport_af
+appeared in RFC2292, and implemented by WIDE project
+for Hydrangea IPv6 protocol stack kit.
+.Fn iruserok_af
+and
+.Fn rusreok_af
+are proposed and implemented by WIDE project
+for Hydrangea IPv6 protocol stack kit.
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
index 7f68754..a1416ed 100644
--- a/lib/libc/net/rcmd.c
+++ b/lib/libc/net/rcmd.c
@@ -59,12 +59,19 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#include <rpcsvc/ypclnt.h>
#endif
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
extern int innetgr __P(( const char *, const char *, const char *, const char * ));
#define max(a, b) ((a > b) ? a : b)
int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
-static int __icheckhost __P((u_int32_t, char *));
+static int __icheckhost __P((void *, char *, int, int));
+
+char paddr[INET6_ADDRSTRLEN];
int
rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
@@ -73,24 +80,40 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
const char *locuser, *remuser, *cmd;
int *fd2p;
{
- struct hostent *hp;
- struct sockaddr_in sin, from;
+ struct addrinfo hints, *res, *ai;
+ struct sockaddr_storage from;
fd_set reads;
long oldmask;
pid_t pid;
- int s, lport, timo;
+ int s, aport, lport, timo, error;
char c;
+ int refused;
+ char num[8];
pid = getpid();
- hp = gethostbyname(*ahost);
- if (hp == NULL) {
- herror(*ahost);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ (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));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ strerror(errno));
return (-1);
}
- *ahost = hp->h_name;
+ if (res->ai_canonname)
+ *ahost = res->ai_canonname;
+ ai = res;
+ refused = 0;
oldmask = sigblock(sigmask(SIGURG));
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
- s = rresvport(&lport);
+ s = rresvport_af(&lport, ai->ai_family);
if (s < 0) {
if (errno == EAGAIN)
(void)fprintf(stderr,
@@ -99,40 +122,47 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
(void)fprintf(stderr, "rcmd: socket: %s\n",
strerror(errno));
sigsetmask(oldmask);
+ freeaddrinfo(res);
return (-1);
}
_libc_fcntl(s, F_SETOWN, pid);
- bzero(&sin, sizeof sin);
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = rport;
- bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr));
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
break;
(void)_libc_close(s);
if (errno == EADDRINUSE) {
lport--;
continue;
}
- if (errno == ECONNREFUSED && timo <= 16) {
- (void)_libc_sleep(timo);
- timo *= 2;
- continue;
- }
- if (hp->h_addr_list[1] != NULL) {
+ if (errno == ECONNREFUSED)
+ refused = 1;
+ if (ai->ai_next != NULL) {
int oerrno = errno;
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ paddr, sizeof(paddr),
+ NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
(void)fprintf(stderr, "connect to address %s: ",
- inet_ntoa(sin.sin_addr));
+ paddr);
errno = oerrno;
perror(0);
- hp->h_addr_list++;
- bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr));
- (void)fprintf(stderr, "Trying %s...\n",
- inet_ntoa(sin.sin_addr));
+ ai = ai->ai_next;
+ getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ paddr, sizeof(paddr),
+ NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ fprintf(stderr, "Trying %s...\n", paddr);
continue;
}
- (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
+ if (refused && timo <= 16) {
+ (void)_libc_sleep(timo);
+ timo *= 2;
+ ai = res;
+ refused = 0;
+ continue;
+ }
+ freeaddrinfo(res);
+ (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno));
sigsetmask(oldmask);
return (-1);
}
@@ -142,8 +172,8 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
lport = 0;
} else {
char num[8];
- int s2 = rresvport(&lport), s3;
- int len = sizeof(from);
+ int s2 = rresvport_af(&lport, ai->ai_family), s3;
+ int len = ai->ai_addrlen;
int nfds;
if (s2 < 0)
@@ -180,11 +210,24 @@ again:
goto bad;
}
s3 = accept(s2, (struct sockaddr *)&from, &len);
+ switch (from.ss_family) {
+ case AF_INET:
+ aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
+ break;
+#endif
+ default:
+ aport = 0; /* error */
+ break;
+ }
/*
* XXX careful for ftp bounce attacks. If discovered, shut them
* down and check for the real auxiliary channel to connect.
*/
- if (from.sin_family == AF_INET && from.sin_port == htons(20)) {
+ if (aport == 20) {
_libc_close(s3);
goto again;
}
@@ -196,10 +239,7 @@ again:
goto bad;
}
*fd2p = s3;
- from.sin_port = ntohs((u_short)from.sin_port);
- if (from.sin_family != AF_INET ||
- from.sin_port >= IPPORT_RESERVED ||
- from.sin_port < IPPORT_RESERVED / 2) {
+ if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
(void)fprintf(stderr,
"socket: protocol failure in circuit setup.\n");
goto bad2;
@@ -222,6 +262,7 @@ again:
goto bad2;
}
sigsetmask(oldmask);
+ freeaddrinfo(res);
return (s);
bad2:
if (lport)
@@ -229,21 +270,46 @@ bad2:
bad:
(void)_libc_close(s);
sigsetmask(oldmask);
+ freeaddrinfo(res);
return (-1);
}
int
-rresvport(alport)
- int *alport;
+rresvport(port)
+ int *port;
+{
+ return rresvport_af(port, AF_INET);
+}
+
+int
+rresvport_af(alport, family)
+ int *alport, family;
{
- struct sockaddr_in sin;
- int s;
-
- bzero(&sin, sizeof sin);
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- s = socket(AF_INET, SOCK_STREAM, 0);
+ int i, s, len, err;
+ struct sockaddr_storage ss;
+ u_short *sport;
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family;
+ switch (family) {
+ case AF_INET:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
+ sport = &((struct sockaddr_in *)&ss)->sin_port;
+ ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
+ sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ s = socket(ss.ss_family, SOCK_STREAM, 0);
if (s < 0)
return (-1);
#if 0 /* compat_exact_traditional_rresvport_semantics */
@@ -255,12 +321,13 @@ rresvport(alport)
return (-1);
}
#endif
- sin.sin_port = 0;
- if (bindresvport(s, &sin) == -1) {
+ *sport = 0;
+ if (bindresvport2(s, (struct sockaddr *)&ss,
+ ((struct sockaddr *)&ss)->sa_len) == -1) {
(void)_libc_close(s);
return (-1);
}
- *alport = (int)ntohs(sin.sin_port);
+ *alport = (int)ntohs(*sport);
return (s);
}
@@ -272,18 +339,34 @@ ruserok(rhost, superuser, ruser, luser)
const char *rhost, *ruser, *luser;
int superuser;
{
+ return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
+}
+
+int
+ruserok_af(rhost, superuser, ruser, luser, af)
+ const char *rhost, *ruser, *luser;
+ int superuser, af;
+{
struct hostent *hp;
- u_int32_t addr;
+ union {
+ struct in_addr addr_in;
+ struct in6_addr addr_in6;
+ } addr;
char **ap;
+ int ret, h_error;
- if ((hp = gethostbyname(rhost)) == NULL)
+ if ((hp = getipnodebyname(rhost, af, AI_DEFAULT, &h_error)) == NULL)
return (-1);
+ ret = -1;
for (ap = hp->h_addr_list; *ap; ++ap) {
- bcopy(*ap, &addr, sizeof(addr));
- if (iruserok(addr, superuser, ruser, luser) == 0)
- return (0);
+ bcopy(*ap, &addr, hp->h_length);
+ if (iruserok_af(&addr, superuser, ruser, luser, af) == 0) {
+ ret = 0;
+ break;
+ }
}
- return (-1);
+ freehostent(hp);
+ return (ret);
}
/*
@@ -301,6 +384,16 @@ iruserok(raddr, superuser, ruser, luser)
int superuser;
const char *ruser, *luser;
{
+ return iruserok_af(&raddr, superuser, ruser, luser, AF_INET);
+}
+
+int
+iruserok_af(raddr, superuser, ruser, luser, af)
+ void *raddr;
+ int superuser;
+ const char *ruser, *luser;
+ int af;
+{
register char *cp;
struct stat sbuf;
struct passwd *pwd;
@@ -308,12 +401,25 @@ iruserok(raddr, superuser, ruser, luser)
uid_t uid;
int first;
char pbuf[MAXPATHLEN];
+ int len = 0;
+
+ switch (af) {
+ case AF_INET:
+ len = sizeof(struct in_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ len = sizeof(struct in6_addr);
+ break;
+#endif
+ }
first = 1;
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
again:
if (hostf) {
- if (__ivaliduser(hostf, (u_int32_t)raddr, luser, ruser) == 0) {
+ if (__ivaliduser_af(hostf, raddr, luser, ruser, af, len)
+ == 0) {
(void)fclose(hostf);
return (0);
}
@@ -376,6 +482,17 @@ __ivaliduser(hostf, raddr, luser, ruser)
u_int32_t raddr;
const char *luser, *ruser;
{
+ return __ivaliduser_af(hostf, &raddr, luser, ruser, AF_INET,
+ sizeof(raddr));
+}
+
+int
+__ivaliduser_af(hostf, raddr, luser, ruser, af, len)
+ FILE *hostf;
+ void *raddr;
+ const char *luser, *ruser;
+ int af, len;
+{
register char *user, *p;
int ch;
char buf[MAXHOSTNAMELEN + 128]; /* host + login */
@@ -383,6 +500,7 @@ __ivaliduser(hostf, raddr, luser, ruser)
struct hostent *hp;
/* Presumed guilty until proven innocent. */
int userok = 0, hostok = 0;
+ int h_error;
#ifdef YP
char *ypdomain;
@@ -392,11 +510,11 @@ __ivaliduser(hostf, raddr, luser, ruser)
#define ypdomain NULL
#endif
/* We need to get the damn hostname back for netgroup matching. */
- if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_int32_t),
- AF_INET)) == NULL)
+ if ((hp = getipnodebyaddr((char *)raddr, len, af, &h_error)) == NULL)
return (-1);
strncpy(hname, hp->h_name, sizeof(hname));
hname[sizeof(hname) - 1] = '\0';
+ freehostent(hp);
while (fgets(buf, sizeof(buf), hostf)) {
p = buf;
@@ -438,7 +556,8 @@ __ivaliduser(hostf, raddr, luser, ruser)
hostok = innetgr((char *)&buf[2],
(char *)&hname, NULL, ypdomain);
else /* match a host by addr */
- hostok = __icheckhost(raddr,(char *)&buf[1]);
+ hostok = __icheckhost(raddr,(char *)&buf[1],
+ af, len);
break;
case '-': /* reject '-' hosts and all their users */
if (buf[1] == '@') {
@@ -446,12 +565,12 @@ __ivaliduser(hostf, raddr, luser, ruser)
(char *)&hname, NULL, ypdomain))
return(-1);
} else {
- if (__icheckhost(raddr,(char *)&buf[1]))
+ if (__icheckhost(raddr,(char *)&buf[1],af,len))
return(-1);
}
break;
default: /* if no '+' or '-', do a simple match */
- hostok = __icheckhost(raddr, buf);
+ hostok = __icheckhost(raddr, buf, af, len);
break;
}
switch(*user) {
@@ -494,27 +613,37 @@ __ivaliduser(hostf, raddr, luser, ruser)
* Returns "true" if match, 0 if no match.
*/
static int
-__icheckhost(raddr, lhost)
- u_int32_t raddr;
+__icheckhost(raddr, lhost, af, len)
+ void *raddr;
register char *lhost;
+ int af, len;
{
register struct hostent *hp;
- register u_int32_t laddr;
+ char laddr[BUFSIZ]; /* xxx */
register char **pp;
+ int h_error;
+ int match;
/* Try for raw ip address first. */
- if (isdigit((unsigned char)*lhost) && (u_int32_t)(laddr = inet_addr(lhost)) != -1)
- return (raddr == laddr);
+ if (inet_pton(af, lhost, laddr) == 1) {
+ if (memcmp(raddr, laddr, len) == 0)
+ return (1);
+ else
+ return (0);
+ }
/* Better be a hostname. */
- if ((hp = gethostbyname(lhost)) == NULL)
+ if ((hp = getipnodebyname(lhost, af, AI_DEFAULT, &h_error)) == NULL)
return (0);
/* Spin through ip addresses. */
+ match = 0;
for (pp = hp->h_addr_list; *pp; ++pp)
- if (!bcmp(&raddr, *pp, sizeof(u_int32_t)))
- return (1);
+ if (!bcmp(raddr, *pp, len)) {
+ match = 1;
+ break;
+ }
- /* No match. */
- return (0);
+ freehostent(hp);
+ return (match);
}
diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc
index 79103b3..472cea7 100644
--- a/lib/libc/rpc/Makefile.inc
+++ b/lib/libc/rpc/Makefile.inc
@@ -44,7 +44,8 @@ crypt.h: ${RPCDIR}/crypt.x
#
# MAN1+= rstat.1
-MAN3+= bindresvport.3 des_crypt.3 getrpcent.3 getrpcport.3 publickey.3 rpc.3 \
+MAN3+= bindresvport.3 bindresvport2.3 des_crypt.3 getrpcent.3 getrpcport.3 \
+ publickey.3 rpc.3 \
rpc_secure.3 rtime.3
MAN5+= publickey.5 rpc.5
# MAN8+= rstat_svc.8
diff --git a/lib/libc/rpc/bindresvport.3 b/lib/libc/rpc/bindresvport.3
index 9abdcb9..8d1f975 100644
--- a/lib/libc/rpc/bindresvport.3
+++ b/lib/libc/rpc/bindresvport.3
@@ -30,3 +30,5 @@ If the value of sin->sin_port is non-zero
.Fn bindresvport
will attempt to use that specific port. If it fails, it chooses another
privileged port automatically.
+.Sh "SEE ALSO"
+.Xr bindresvport2 3 \ No newline at end of file
diff --git a/lib/libc/rpc/bindresvport.c b/lib/libc/rpc/bindresvport.c
index 1a62efa..e8e8c15 100644
--- a/lib/libc/rpc/bindresvport.c
+++ b/lib/libc/rpc/bindresvport.c
@@ -55,7 +55,6 @@ bindresvport(sd, sin)
int sd;
struct sockaddr_in *sin;
{
- int on, old, error;
struct sockaddr_in myaddr;
int sinlen = sizeof(struct sockaddr_in);
@@ -69,39 +68,82 @@ bindresvport(sd, sin)
return (-1);
}
- if (sin->sin_port == 0) {
+ return (bindresvport2(sd, sin, sinlen));
+}
+
+int
+bindresvport2(sd, sa, addrlen)
+ int sd;
+ struct sockaddr *sa;
+ socklen_t addrlen;
+{
+ int on, old, error, level, optname;
+ u_short port;
+
+ if (sa == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ switch (sa->sa_family) {
+ case AF_INET:
+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ level = IPPROTO_IP;
+ optname = IP_PORTRANGE;
+ on = IP_PORTRANGE_LOW;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ level = IPPROTO_IPV6;
+ optname = IPV6_PORTRANGE;
+ on = IPV6_PORTRANGE_LOW;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+
+ if (port == 0) {
int oldlen = sizeof(old);
- error = getsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
- &old, &oldlen);
+ error = getsockopt(sd, level, optname, &old, &oldlen);
if (error < 0)
return(error);
- on = IP_PORTRANGE_LOW;
- error = setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
- &on, sizeof(on));
+ error = setsockopt(sd, level, optname, &on, sizeof(on));
if (error < 0)
return(error);
}
- error = bind(sd, (struct sockaddr *)sin, sinlen);
+ error = bind(sd, sa, addrlen);
- if (sin->sin_port == 0) {
+ switch (sa->sa_family) {
+ case AF_INET:
+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ break;
+#endif
+ default: /* shoud not match here */
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ if (port == 0) {
int saved_errno = errno;
if (error) {
- if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
+ if (setsockopt(sd, level, optname,
&old, sizeof(old)) < 0)
errno = saved_errno;
return (error);
}
- if (sin != &myaddr) {
- /* Hmm, what did the kernel assign... */
- if (getsockname(sd, (struct sockaddr *)sin,
- &sinlen) < 0)
- errno = saved_errno;
- return (error);
- }
+ /* Hmm, what did the kernel assign... */
+ if (getsockname(sd, (struct sockaddr *)sa, &addrlen) < 0)
+ errno = saved_errno;
+ return (error);
}
return (error);
}
OpenPOWER on IntegriCloud