mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-16 06:52:27 +00:00
libc rcmd update for IPv6.
A new function bindresvport2(), AF independent version of bindresvport() is also added. Reviewed by: sumikawa Obtained from: KAME project
This commit is contained in:
parent
5d60ed0e69
commit
42b4f28ebd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=55918
|
@ -87,6 +87,7 @@ extern void setrpcent __P((int));
|
||||||
extern void endrpcent __P((void));
|
extern void endrpcent __P((void));
|
||||||
|
|
||||||
extern int bindresvport __P((int, struct sockaddr_in *));
|
extern int bindresvport __P((int, struct sockaddr_in *));
|
||||||
|
extern int bindresvport2 __P((int, struct sockaddr *, int addrlen));
|
||||||
extern int get_myaddress __P((struct sockaddr_in *));
|
extern int get_myaddress __P((struct sockaddr_in *));
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,7 @@ char *getusershell __P((void));
|
||||||
char *getwd __P((char *)); /* obsoleted by getcwd() */
|
char *getwd __P((char *)); /* obsoleted by getcwd() */
|
||||||
int initgroups __P((const char *, int));
|
int initgroups __P((const char *, int));
|
||||||
int iruserok __P((unsigned long, int, const char *, const char *));
|
int iruserok __P((unsigned long, int, const char *, const char *));
|
||||||
|
int iruserok_af __P((void *, int, const char *, const char *, int));
|
||||||
int issetugid __P((void));
|
int issetugid __P((void));
|
||||||
int lchown __P((const char *, uid_t, gid_t));
|
int lchown __P((const char *, uid_t, gid_t));
|
||||||
int lockf __P((int, int, off_t));
|
int lockf __P((int, int, off_t));
|
||||||
|
@ -203,6 +204,9 @@ int unwhiteout __P((const char *));
|
||||||
int usleep __P((unsigned int));
|
int usleep __P((unsigned int));
|
||||||
void *valloc __P((size_t)); /* obsoleted by malloc() */
|
void *valloc __P((size_t)); /* obsoleted by malloc() */
|
||||||
pid_t vfork __P((void));
|
pid_t vfork __P((void));
|
||||||
|
int rresvport_af __P((int *, int));
|
||||||
|
int ruserok_af __P((const char *, int, const char *, const char *, int));
|
||||||
|
int iruserok_af __P((void *, int, const char *, const char *, int));
|
||||||
|
|
||||||
extern char *suboptarg; /* getsubopt(3) external variable */
|
extern char *suboptarg; /* getsubopt(3) external variable */
|
||||||
int getsubopt __P((char **, char * const *, char **));
|
int getsubopt __P((char **, char * const *, char **));
|
||||||
|
|
|
@ -39,7 +39,10 @@
|
||||||
.Nm rcmd ,
|
.Nm rcmd ,
|
||||||
.Nm rresvport ,
|
.Nm rresvport ,
|
||||||
.Nm iruserok ,
|
.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
|
.Nd routines for returning a stream to a remote command
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Fd #include <unistd.h>
|
.Fd #include <unistd.h>
|
||||||
|
@ -51,6 +54,12 @@
|
||||||
.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
|
.Fn iruserok "u_long raddr" "int superuser" "const char *ruser" "const char *luser"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
|
.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
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Fn rcmd
|
.Fn rcmd
|
||||||
|
@ -173,6 +182,19 @@ function is strongly preferred for security reasons.
|
||||||
It requires trusting the local DNS at most, while the
|
It requires trusting the local DNS at most, while the
|
||||||
.Fn ruserok
|
.Fn ruserok
|
||||||
function requires trusting the entire DNS, which can be spoofed.
|
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
|
.Sh DIAGNOSTICS
|
||||||
The
|
The
|
||||||
.Fn rcmd
|
.Fn rcmd
|
||||||
|
@ -198,7 +220,18 @@ is overloaded to mean ``All network ports in use.''
|
||||||
.Xr rexecd 8 ,
|
.Xr rexecd 8 ,
|
||||||
.Xr rlogind 8 ,
|
.Xr rlogind 8 ,
|
||||||
.Xr rshd 8
|
.Xr rshd 8
|
||||||
|
.Pp
|
||||||
|
W. Stevens and M. Thomas, ``Advanced Socket API for IPv6,''
|
||||||
|
RFC2292.
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
These
|
These
|
||||||
functions appeared in
|
functions appeared in
|
||||||
.Bx 4.2 .
|
.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.
|
||||||
|
|
|
@ -59,12 +59,19 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
|
||||||
#include <rpcsvc/ypclnt.h>
|
#include <rpcsvc/ypclnt.h>
|
||||||
#endif
|
#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 * ));
|
extern int innetgr __P(( const char *, const char *, const char *, const char * ));
|
||||||
|
|
||||||
#define max(a, b) ((a > b) ? a : b)
|
#define max(a, b) ((a > b) ? a : b)
|
||||||
|
|
||||||
int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
|
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
|
int
|
||||||
rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
|
@ -73,24 +80,40 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
const char *locuser, *remuser, *cmd;
|
const char *locuser, *remuser, *cmd;
|
||||||
int *fd2p;
|
int *fd2p;
|
||||||
{
|
{
|
||||||
struct hostent *hp;
|
struct addrinfo hints, *res, *ai;
|
||||||
struct sockaddr_in sin, from;
|
struct sockaddr_storage from;
|
||||||
fd_set reads;
|
fd_set reads;
|
||||||
long oldmask;
|
long oldmask;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int s, lport, timo;
|
int s, aport, lport, timo, error;
|
||||||
char c;
|
char c;
|
||||||
|
int refused;
|
||||||
|
char num[8];
|
||||||
|
|
||||||
pid = getpid();
|
pid = getpid();
|
||||||
hp = gethostbyname(*ahost);
|
|
||||||
if (hp == NULL) {
|
memset(&hints, 0, sizeof(hints));
|
||||||
herror(*ahost);
|
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);
|
return (-1);
|
||||||
}
|
}
|
||||||
*ahost = hp->h_name;
|
if (res->ai_canonname)
|
||||||
|
*ahost = res->ai_canonname;
|
||||||
|
ai = res;
|
||||||
|
refused = 0;
|
||||||
oldmask = sigblock(sigmask(SIGURG));
|
oldmask = sigblock(sigmask(SIGURG));
|
||||||
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
|
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
|
||||||
s = rresvport(&lport);
|
s = rresvport_af(&lport, ai->ai_family);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
(void)fprintf(stderr,
|
(void)fprintf(stderr,
|
||||||
|
@ -99,40 +122,47 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
(void)fprintf(stderr, "rcmd: socket: %s\n",
|
(void)fprintf(stderr, "rcmd: socket: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
sigsetmask(oldmask);
|
sigsetmask(oldmask);
|
||||||
|
freeaddrinfo(res);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
_libc_fcntl(s, F_SETOWN, pid);
|
_libc_fcntl(s, F_SETOWN, pid);
|
||||||
bzero(&sin, sizeof sin);
|
if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
|
||||||
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)
|
|
||||||
break;
|
break;
|
||||||
(void)_libc_close(s);
|
(void)_libc_close(s);
|
||||||
if (errno == EADDRINUSE) {
|
if (errno == EADDRINUSE) {
|
||||||
lport--;
|
lport--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (errno == ECONNREFUSED && timo <= 16) {
|
if (errno == ECONNREFUSED)
|
||||||
(void)_libc_sleep(timo);
|
refused = 1;
|
||||||
timo *= 2;
|
if (ai->ai_next != NULL) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (hp->h_addr_list[1] != NULL) {
|
|
||||||
int oerrno = errno;
|
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: ",
|
(void)fprintf(stderr, "connect to address %s: ",
|
||||||
inet_ntoa(sin.sin_addr));
|
paddr);
|
||||||
errno = oerrno;
|
errno = oerrno;
|
||||||
perror(0);
|
perror(0);
|
||||||
hp->h_addr_list++;
|
ai = ai->ai_next;
|
||||||
bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr));
|
getnameinfo(ai->ai_addr, ai->ai_addrlen,
|
||||||
(void)fprintf(stderr, "Trying %s...\n",
|
paddr, sizeof(paddr),
|
||||||
inet_ntoa(sin.sin_addr));
|
NULL, 0,
|
||||||
|
NI_NUMERICHOST|NI_WITHSCOPEID);
|
||||||
|
fprintf(stderr, "Trying %s...\n", paddr);
|
||||||
continue;
|
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);
|
sigsetmask(oldmask);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
@ -142,8 +172,8 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
lport = 0;
|
lport = 0;
|
||||||
} else {
|
} else {
|
||||||
char num[8];
|
char num[8];
|
||||||
int s2 = rresvport(&lport), s3;
|
int s2 = rresvport_af(&lport, ai->ai_family), s3;
|
||||||
int len = sizeof(from);
|
int len = ai->ai_addrlen;
|
||||||
int nfds;
|
int nfds;
|
||||||
|
|
||||||
if (s2 < 0)
|
if (s2 < 0)
|
||||||
|
@ -180,11 +210,24 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
s3 = accept(s2, (struct sockaddr *)&from, &len);
|
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
|
* XXX careful for ftp bounce attacks. If discovered, shut them
|
||||||
* down and check for the real auxiliary channel to connect.
|
* 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);
|
_libc_close(s3);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
@ -196,10 +239,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
*fd2p = s3;
|
*fd2p = s3;
|
||||||
from.sin_port = ntohs((u_short)from.sin_port);
|
if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
|
||||||
if (from.sin_family != AF_INET ||
|
|
||||||
from.sin_port >= IPPORT_RESERVED ||
|
|
||||||
from.sin_port < IPPORT_RESERVED / 2) {
|
|
||||||
(void)fprintf(stderr,
|
(void)fprintf(stderr,
|
||||||
"socket: protocol failure in circuit setup.\n");
|
"socket: protocol failure in circuit setup.\n");
|
||||||
goto bad2;
|
goto bad2;
|
||||||
|
@ -222,6 +262,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
goto bad2;
|
goto bad2;
|
||||||
}
|
}
|
||||||
sigsetmask(oldmask);
|
sigsetmask(oldmask);
|
||||||
|
freeaddrinfo(res);
|
||||||
return (s);
|
return (s);
|
||||||
bad2:
|
bad2:
|
||||||
if (lport)
|
if (lport)
|
||||||
|
@ -229,21 +270,46 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
|
||||||
bad:
|
bad:
|
||||||
(void)_libc_close(s);
|
(void)_libc_close(s);
|
||||||
sigsetmask(oldmask);
|
sigsetmask(oldmask);
|
||||||
|
freeaddrinfo(res);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rresvport(alport)
|
rresvport(port)
|
||||||
int *alport;
|
int *port;
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
return rresvport_af(port, AF_INET);
|
||||||
int s;
|
}
|
||||||
|
|
||||||
bzero(&sin, sizeof sin);
|
int
|
||||||
sin.sin_len = sizeof(struct sockaddr_in);
|
rresvport_af(alport, family)
|
||||||
sin.sin_family = AF_INET;
|
int *alport, family;
|
||||||
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)
|
if (s < 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
#if 0 /* compat_exact_traditional_rresvport_semantics */
|
#if 0 /* compat_exact_traditional_rresvport_semantics */
|
||||||
|
@ -255,12 +321,13 @@ rresvport(alport)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sin.sin_port = 0;
|
*sport = 0;
|
||||||
if (bindresvport(s, &sin) == -1) {
|
if (bindresvport2(s, (struct sockaddr *)&ss,
|
||||||
|
((struct sockaddr *)&ss)->sa_len) == -1) {
|
||||||
(void)_libc_close(s);
|
(void)_libc_close(s);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
*alport = (int)ntohs(sin.sin_port);
|
*alport = (int)ntohs(*sport);
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,18 +339,34 @@ ruserok(rhost, superuser, ruser, luser)
|
||||||
const char *rhost, *ruser, *luser;
|
const char *rhost, *ruser, *luser;
|
||||||
int superuser;
|
int superuser;
|
||||||
{
|
{
|
||||||
struct hostent *hp;
|
return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
|
||||||
u_int32_t addr;
|
}
|
||||||
char **ap;
|
|
||||||
|
|
||||||
if ((hp = gethostbyname(rhost)) == NULL)
|
int
|
||||||
|
ruserok_af(rhost, superuser, ruser, luser, af)
|
||||||
|
const char *rhost, *ruser, *luser;
|
||||||
|
int superuser, af;
|
||||||
|
{
|
||||||
|
struct hostent *hp;
|
||||||
|
union {
|
||||||
|
struct in_addr addr_in;
|
||||||
|
struct in6_addr addr_in6;
|
||||||
|
} addr;
|
||||||
|
char **ap;
|
||||||
|
int ret, h_error;
|
||||||
|
|
||||||
|
if ((hp = getipnodebyname(rhost, af, AI_DEFAULT, &h_error)) == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
ret = -1;
|
||||||
for (ap = hp->h_addr_list; *ap; ++ap) {
|
for (ap = hp->h_addr_list; *ap; ++ap) {
|
||||||
bcopy(*ap, &addr, sizeof(addr));
|
bcopy(*ap, &addr, hp->h_length);
|
||||||
if (iruserok(addr, superuser, ruser, luser) == 0)
|
if (iruserok_af(&addr, superuser, ruser, luser, af) == 0) {
|
||||||
return (0);
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (-1);
|
freehostent(hp);
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -300,6 +383,16 @@ iruserok(raddr, superuser, ruser, luser)
|
||||||
unsigned long raddr;
|
unsigned long raddr;
|
||||||
int superuser;
|
int superuser;
|
||||||
const char *ruser, *luser;
|
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;
|
register char *cp;
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
|
@ -308,12 +401,25 @@ iruserok(raddr, superuser, ruser, luser)
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
int first;
|
int first;
|
||||||
char pbuf[MAXPATHLEN];
|
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;
|
first = 1;
|
||||||
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
|
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
|
||||||
again:
|
again:
|
||||||
if (hostf) {
|
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);
|
(void)fclose(hostf);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -375,6 +481,17 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
FILE *hostf;
|
FILE *hostf;
|
||||||
u_int32_t raddr;
|
u_int32_t raddr;
|
||||||
const char *luser, *ruser;
|
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;
|
register char *user, *p;
|
||||||
int ch;
|
int ch;
|
||||||
|
@ -383,6 +500,7 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
/* Presumed guilty until proven innocent. */
|
/* Presumed guilty until proven innocent. */
|
||||||
int userok = 0, hostok = 0;
|
int userok = 0, hostok = 0;
|
||||||
|
int h_error;
|
||||||
#ifdef YP
|
#ifdef YP
|
||||||
char *ypdomain;
|
char *ypdomain;
|
||||||
|
|
||||||
|
@ -392,11 +510,11 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
#define ypdomain NULL
|
#define ypdomain NULL
|
||||||
#endif
|
#endif
|
||||||
/* We need to get the damn hostname back for netgroup matching. */
|
/* We need to get the damn hostname back for netgroup matching. */
|
||||||
if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_int32_t),
|
if ((hp = getipnodebyaddr((char *)raddr, len, af, &h_error)) == NULL)
|
||||||
AF_INET)) == NULL)
|
|
||||||
return (-1);
|
return (-1);
|
||||||
strncpy(hname, hp->h_name, sizeof(hname));
|
strncpy(hname, hp->h_name, sizeof(hname));
|
||||||
hname[sizeof(hname) - 1] = '\0';
|
hname[sizeof(hname) - 1] = '\0';
|
||||||
|
freehostent(hp);
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), hostf)) {
|
while (fgets(buf, sizeof(buf), hostf)) {
|
||||||
p = buf;
|
p = buf;
|
||||||
|
@ -438,7 +556,8 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
hostok = innetgr((char *)&buf[2],
|
hostok = innetgr((char *)&buf[2],
|
||||||
(char *)&hname, NULL, ypdomain);
|
(char *)&hname, NULL, ypdomain);
|
||||||
else /* match a host by addr */
|
else /* match a host by addr */
|
||||||
hostok = __icheckhost(raddr,(char *)&buf[1]);
|
hostok = __icheckhost(raddr,(char *)&buf[1],
|
||||||
|
af, len);
|
||||||
break;
|
break;
|
||||||
case '-': /* reject '-' hosts and all their users */
|
case '-': /* reject '-' hosts and all their users */
|
||||||
if (buf[1] == '@') {
|
if (buf[1] == '@') {
|
||||||
|
@ -446,12 +565,12 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
(char *)&hname, NULL, ypdomain))
|
(char *)&hname, NULL, ypdomain))
|
||||||
return(-1);
|
return(-1);
|
||||||
} else {
|
} else {
|
||||||
if (__icheckhost(raddr,(char *)&buf[1]))
|
if (__icheckhost(raddr,(char *)&buf[1],af,len))
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: /* if no '+' or '-', do a simple match */
|
default: /* if no '+' or '-', do a simple match */
|
||||||
hostok = __icheckhost(raddr, buf);
|
hostok = __icheckhost(raddr, buf, af, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch(*user) {
|
switch(*user) {
|
||||||
|
@ -494,27 +613,37 @@ __ivaliduser(hostf, raddr, luser, ruser)
|
||||||
* Returns "true" if match, 0 if no match.
|
* Returns "true" if match, 0 if no match.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
__icheckhost(raddr, lhost)
|
__icheckhost(raddr, lhost, af, len)
|
||||||
u_int32_t raddr;
|
void *raddr;
|
||||||
register char *lhost;
|
register char *lhost;
|
||||||
|
int af, len;
|
||||||
{
|
{
|
||||||
register struct hostent *hp;
|
register struct hostent *hp;
|
||||||
register u_int32_t laddr;
|
char laddr[BUFSIZ]; /* xxx */
|
||||||
register char **pp;
|
register char **pp;
|
||||||
|
int h_error;
|
||||||
|
int match;
|
||||||
|
|
||||||
/* Try for raw ip address first. */
|
/* Try for raw ip address first. */
|
||||||
if (isdigit((unsigned char)*lhost) && (u_int32_t)(laddr = inet_addr(lhost)) != -1)
|
if (inet_pton(af, lhost, laddr) == 1) {
|
||||||
return (raddr == laddr);
|
if (memcmp(raddr, laddr, len) == 0)
|
||||||
|
return (1);
|
||||||
|
else
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Better be a hostname. */
|
/* Better be a hostname. */
|
||||||
if ((hp = gethostbyname(lhost)) == NULL)
|
if ((hp = getipnodebyname(lhost, af, AI_DEFAULT, &h_error)) == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* Spin through ip addresses. */
|
/* Spin through ip addresses. */
|
||||||
|
match = 0;
|
||||||
for (pp = hp->h_addr_list; *pp; ++pp)
|
for (pp = hp->h_addr_list; *pp; ++pp)
|
||||||
if (!bcmp(&raddr, *pp, sizeof(u_int32_t)))
|
if (!bcmp(raddr, *pp, len)) {
|
||||||
return (1);
|
match = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* No match. */
|
freehostent(hp);
|
||||||
return (0);
|
return (match);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ crypt.h: ${RPCDIR}/crypt.x
|
||||||
#
|
#
|
||||||
|
|
||||||
# MAN1+= rstat.1
|
# 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
|
rpc_secure.3 rtime.3
|
||||||
MAN5+= publickey.5 rpc.5
|
MAN5+= publickey.5 rpc.5
|
||||||
# MAN8+= rstat_svc.8
|
# MAN8+= rstat_svc.8
|
||||||
|
|
|
@ -30,3 +30,5 @@ If the value of sin->sin_port is non-zero
|
||||||
.Fn bindresvport
|
.Fn bindresvport
|
||||||
will attempt to use that specific port. If it fails, it chooses another
|
will attempt to use that specific port. If it fails, it chooses another
|
||||||
privileged port automatically.
|
privileged port automatically.
|
||||||
|
.Sh "SEE ALSO"
|
||||||
|
.Xr bindresvport2 3
|
|
@ -55,7 +55,6 @@ bindresvport(sd, sin)
|
||||||
int sd;
|
int sd;
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
{
|
{
|
||||||
int on, old, error;
|
|
||||||
struct sockaddr_in myaddr;
|
struct sockaddr_in myaddr;
|
||||||
int sinlen = sizeof(struct sockaddr_in);
|
int sinlen = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
|
@ -69,39 +68,82 @@ bindresvport(sd, sin)
|
||||||
return (-1);
|
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);
|
int oldlen = sizeof(old);
|
||||||
error = getsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
|
error = getsockopt(sd, level, optname, &old, &oldlen);
|
||||||
&old, &oldlen);
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return(error);
|
return(error);
|
||||||
|
|
||||||
on = IP_PORTRANGE_LOW;
|
error = setsockopt(sd, level, optname, &on, sizeof(on));
|
||||||
error = setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
|
|
||||||
&on, sizeof(on));
|
|
||||||
if (error < 0)
|
if (error < 0)
|
||||||
return(error);
|
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;
|
int saved_errno = errno;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE,
|
if (setsockopt(sd, level, optname,
|
||||||
&old, sizeof(old)) < 0)
|
&old, sizeof(old)) < 0)
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sin != &myaddr) {
|
/* Hmm, what did the kernel assign... */
|
||||||
/* Hmm, what did the kernel assign... */
|
if (getsockname(sd, (struct sockaddr *)sa, &addrlen) < 0)
|
||||||
if (getsockname(sd, (struct sockaddr *)sin,
|
errno = saved_errno;
|
||||||
&sinlen) < 0)
|
return (error);
|
||||||
errno = saved_errno;
|
|
||||||
return (error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue