add IPv6 support to rcmd() and friends.

rcmd() and iruserok(): unchanged
	ruserok(): became address family independent
	rcmd_af(), iruesrok_sa(): address family independent
This commit is contained in:
itojun 2000-01-27 05:33:06 +00:00
parent 6e5a5cc306
commit 5b1aaa939e
5 changed files with 341 additions and 107 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.187 2000/01/26 13:20:26 itojun Exp $
# $NetBSD: mi,v 1.188 2000/01/27 05:33:07 itojun Exp $
./sys
./usr/bin/ar
./usr/bin/as
@ -1882,6 +1882,7 @@
./usr/share/man/cat3/ipsec_set_policy.0
./usr/share/man/cat3/ipsec_strerror.0
./usr/share/man/cat3/iruserok.0
./usr/share/man/cat3/iruserok_sa.0
./usr/share/man/cat3/isalnum.0
./usr/share/man/cat3/isalpha.0
./usr/share/man/cat3/isascii.0
@ -2040,6 +2041,7 @@
./usr/share/man/cat3/openlog.0
./usr/share/man/cat3/openpty.0
./usr/share/man/cat3/orcmd.0
./usr/share/man/cat3/orcmd_af.0
./usr/share/man/cat3/ossaudio.0
./usr/share/man/cat3/pause.0
./usr/share/man/cat3/pcap.0
@ -2083,6 +2085,7 @@
./usr/share/man/cat3/rand_r.0
./usr/share/man/cat3/random.0
./usr/share/man/cat3/rcmd.0
./usr/share/man/cat3/rcmd_af.0
./usr/share/man/cat3/re_comp.0
./usr/share/man/cat3/re_exec.0
./usr/share/man/cat3/readdir.0
@ -2118,6 +2121,7 @@
./usr/share/man/cat3/rpc.0
./usr/share/man/cat3/rpc_createerr.0
./usr/share/man/cat3/rresvport.0
./usr/share/man/cat3/rresvport_af.0
./usr/share/man/cat3/ruserok.0
./usr/share/man/cat3/scalb.0
./usr/share/man/cat3/scalbf.0
@ -2988,6 +2992,7 @@
./usr/share/man/man3/bcmp.3
./usr/share/man/man3/bcopy.3
./usr/share/man/man3/bindresvport.3
./usr/share/man/man3/bindresvport_sa.3
./usr/share/man/man3/bitstring.3
./usr/share/man/man3/bm.3
./usr/share/man/man3/bm_comp.3
@ -3357,6 +3362,7 @@
./usr/share/man/man3/ipsec_set_policy.3
./usr/share/man/man3/ipsec_strerror.3
./usr/share/man/man3/iruserok.3
./usr/share/man/man3/iruserok_sa.3
./usr/share/man/man3/isalnum.3
./usr/share/man/man3/isalpha.3
./usr/share/man/man3/isascii.3
@ -3515,6 +3521,7 @@
./usr/share/man/man3/openlog.3
./usr/share/man/man3/openpty.3
./usr/share/man/man3/orcmd.3
./usr/share/man/man3/orcmd_af.3
./usr/share/man/man3/ossaudio.3
./usr/share/man/man3/pause.3
./usr/share/man/man3/pcap.3
@ -3558,6 +3565,7 @@
./usr/share/man/man3/rand_r.3
./usr/share/man/man3/random.3
./usr/share/man/man3/rcmd.3
./usr/share/man/man3/rcmd_af.3
./usr/share/man/man3/re_comp.3
./usr/share/man/man3/re_exec.3
./usr/share/man/man3/readdir.3
@ -3593,6 +3601,7 @@
./usr/share/man/man3/rpc.3
./usr/share/man/man3/rpc_createerr.3
./usr/share/man/man3/rresvport.3
./usr/share/man/man3/rresvport_af.3
./usr/share/man/man3/ruserok.3
./usr/share/man/man3/scalb.3
./usr/share/man/man3/scalbf.3

View File

@ -1,4 +1,4 @@
/* $NetBSD: unistd.h,v 1.80 2000/01/10 16:58:38 kleink Exp $ */
/* $NetBSD: unistd.h,v 1.81 2000/01/27 05:33:07 itojun Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@ -331,9 +331,10 @@ quad_t __syscall __P((quad_t, ...));
int undelete __P((const char *));
#if 1 /*INET6*/
int rcmd_af __P((char **, int, const char *,
const char *, const char *, int *, int));
int rresvport_af __P((int *, int));
int ruserok_af __P((const char *, int, const char *, const char *, int));
int iruserok_af __P((const void *, int, const char *, const char *, int));
int iruserok_sa __P((const void *, int, int, const char *, const char *));
#endif
extern __const char *__const *sys_siglist __RENAME(__sys_siglist14);

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.inc,v 1.47 2000/01/26 02:46:36 itojun Exp $
# $NetBSD: Makefile.inc,v 1.48 2000/01/27 05:33:06 itojun Exp $
# @(#)Makefile.inc 8.2 (Berkeley) 9/5/93
# net sources
@ -19,7 +19,7 @@ CPPFLAGS+=-DRESOLVSORT -I.
# IPv6
SRCS+= getaddrinfo.c getnameinfo.c ifname.c ip6opt.c rthdr.c vars6.c
# need to revisit
#SRCS+= name6.c rresvport_af.c freehostent.c
#SRCS+= name6.c freehostent.c
#CPPFLAGS+= -DUSE_GETIPNODEBY
LPREFIX=_nsyy
@ -86,7 +86,9 @@ MLINKS+=getaddrinfo.3 freeaddrinfo.3 getaddrinfo.3 gai_strerror.3 \
inet6_rthdr_space.3 inet6_rthdr_reverse.3 \
inet6_rthdr_space.3 inet6_rthdr_segments.3 \
inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
inet6_rthdr_space.3 inet6_rthdr_getflags.3
inet6_rthdr_space.3 inet6_rthdr_getflags.3 \
rcmd.3 rcmd_af.3 rcmd.3 iruserok_sa.3 rcmd.3 rresvport_af.3 \
rcmd.3 orcmd_af.3
# need to revisit
#MAN+= getipnodebyname.3 rresvport_af.3
#MAN+= getipnodebyname.3
#MLINKS+=getipnodebyname.3 getipnodebyaddr.3 getipnodebyname.3 freehostent.3 \

View File

@ -1,4 +1,4 @@
.\" $NetBSD: rcmd.3,v 1.18 1999/07/04 00:43:44 itojun Exp $
.\" $NetBSD: rcmd.3,v 1.19 2000/01/27 05:33:06 itojun Exp $
.\"
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -38,11 +38,14 @@
.Os
.Sh NAME
.Nm rcmd ,
.Nm orcmd ,
.Nm rcmd_af ,
.Nm orcmd_af ,
.Nm rresvport ,
.Nm rresvport_af ,
.Nm iruserok ,
.Nm ruserok ,
.Nm orcmd
.Nm iruserok_sa
.Nd routines for returning a stream to a remote command
.Sh LIBRARY
.Lb libc
@ -53,6 +56,10 @@
.Ft int
.Fn orcmd "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p"
.Ft int
.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
.Ft int
.Fn orcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
.Ft int
.Fn rresvport "int *port"
.Ft int
.Fn rresvport_af "int *port" "int family"
@ -60,6 +67,8 @@
.Fn iruserok "u_int32_t 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 iruserok_sa "const void *raddr" "int rlen" "int superuser" "const char *ruser" "const char *luser"
.Sh DESCRIPTION
The
.Fn rcmd
@ -80,6 +89,15 @@ function
is used by the super-user to execute a command on
a remote machine using an authentication scheme based
on reserved port numbers.
While
.Fn rcmd
and
.Fn orcmd
can only handle IPv4 address in the first argument,
.Fn rcmd_af
and
.Fn orcmd_af
can handle other cases as well.
The
.Fn rresvport
function
@ -107,6 +125,9 @@ All six functions are present in the same file and are used
by the
.Xr rshd 8
server (among others).
.Fn iruserok_sa
is an address family independent variant of
.Fn iruserok .
.Pp
The
.Fn rcmd
@ -154,6 +175,16 @@ and no
provision is made for sending arbitrary signals to the remote process,
although you may be able to get its attention by using out-of-band data.
.Pp
.Fn rcmd_af
and
.Fn orcmd_af
take address family in the last argument.
If the last argument is
.Dv PF_UNSPEC ,
interpretation of
.Fa *ahost
will obey the underlying address resolution like DNS.
.Pp
The protocol is described in detail in
.Xr rshd 8 .
.Pp
@ -207,6 +238,22 @@ If the IP address of the remote host is known,
should be used in preference to
.Fn ruserok ,
as it does not require trusting the DNS server for the remote host's domain.
.Pp
While
.Fn iruserok
can handle IPv4 addresses only,
.Fn iruserok_sa
and
.Fn ruserok
can handle other address families as well, like IPv6.
The first argument of
.Fn iruserok_sa
is typed as
.Fa "void *"
to avoid dependency between
.Aq Li unistd.h
and
.Aq Li sys/socket.h .
.Sh DIAGNOSTICS
The
.Fn rcmd
@ -244,7 +291,7 @@ function, this variable is used as the program to run instead of
.Xr rhosts 5 ,
.Xr rexecd 8 ,
.Xr rlogind 8 ,
.Xr rshd 8 .
.Xr rshd 8
.Sh HISTORY
The
.Fn orcmd ,
@ -257,13 +304,15 @@ functions appeared in
where the
.Fn orcmd
function was called
.Fn rcmd.
.Fn rcmd .
The (newer)
.Fn rcmd
function appeared in
.Nx 1.3 .
.Fn rcmd_af
and
.Fn rresvport_af
was defined in RFC2292.
were defined in RFC2292.
.Sh BUGS
As the
.Nm

View File

@ -1,4 +1,4 @@
/* $NetBSD: rcmd.c,v 1.36 2000/01/22 23:36:17 mycroft Exp $ */
/* $NetBSD: rcmd.c,v 1.37 2000/01/27 05:33:06 itojun Exp $ */
/*
* Copyright (c) 1997 Matthew R. Green.
@ -39,7 +39,7 @@
#if 0
static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#else
__RCSID("$NetBSD: rcmd.c,v 1.36 2000/01/22 23:36:17 mycroft Exp $");
__RCSID("$NetBSD: rcmd.c,v 1.37 2000/01/27 05:33:06 itojun Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@ -75,13 +75,17 @@ __RCSID("$NetBSD: rcmd.c,v 1.36 2000/01/22 23:36:17 mycroft Exp $");
int orcmd __P((char **, u_int, const char *, const char *, const char *,
int *));
int orcmd_af __P((char **, u_int, const char *, const char *, const char *,
int *, int));
int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
int __ivaliduser_sa __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 resrcmd __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 char *__gethostloop __P((struct sockaddr *));
int
rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
@ -90,7 +94,22 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
const char *locuser, *remuser, *cmd;
int *fd2p;
{
struct hostent *hp;
return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
}
int
rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
char **ahost;
u_short rport;
const char *locuser, *remuser, *cmd;
int *fd2p;
int af;
{
static char hbuf[MAXHOSTNAMELEN];
char pbuf[NI_MAXSERV];
struct addrinfo hints, *res;
int error;
struct servent *sp;
_DIAGASSERT(ahost != NULL);
@ -99,16 +118,25 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
_DIAGASSERT(cmd != NULL);
/* fd2p may be NULL */
/*
* Canonicalise hostname.
* XXX: Should we really do this?
*/
hp = gethostbyname(*ahost);
if (hp == NULL) {
herror(*ahost);
snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(*ahost, pbuf, &hints, &res);
if (error) {
warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/
return (-1);
}
*ahost = hp->h_name;
if (res->ai_canonname) {
/*
* Canonicalise hostname.
* XXX: Should we really do this?
*/
strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1);
hbuf[sizeof(hbuf) - 1] = '\0';
*ahost = hbuf;
}
/*
* Check if rport is the same as the shell port, and that the fd2p. If
@ -117,11 +145,13 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
*/
sp = getservbyname("shell", "tcp");
if (sp != NULL && sp->s_port == rport)
return (rshrcmd(ahost, (u_int32_t)rport,
locuser, remuser, cmd, fd2p, getenv("RCMD_CMD")));
error = rshrcmd(ahost, (u_int32_t)rport,
locuser, remuser, cmd, fd2p, getenv("RCMD_CMD"));
else
return (hprcmd(hp, ahost, (u_int32_t)rport,
locuser, remuser, cmd, fd2p));
error = resrcmd(res, ahost, (u_int32_t)rport,
locuser, remuser, cmd, fd2p);
freeaddrinfo(res);
return (error);
}
/* this is simply a wrapper around hprcmd() that handles ahost first */
@ -132,7 +162,21 @@ orcmd(ahost, rport, locuser, remuser, cmd, fd2p)
const char *locuser, *remuser, *cmd;
int *fd2p;
{
struct hostent *hp;
return orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
}
int
orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
char **ahost;
u_int rport;
const char *locuser, *remuser, *cmd;
int *fd2p;
int af;
{
static char hbuf[MAXHOSTNAMELEN];
char pbuf[NI_MAXSERV];
struct addrinfo hints, *res;
int error;
_DIAGASSERT(ahost != NULL);
_DIAGASSERT(locuser != NULL);
@ -140,25 +184,37 @@ orcmd(ahost, rport, locuser, remuser, cmd, fd2p)
_DIAGASSERT(cmd != NULL);
/* fd2p may be NULL */
hp = gethostbyname(*ahost);
if (hp == NULL) {
herror(*ahost);
snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
error = getaddrinfo(*ahost, pbuf, &hints, &res);
if (error) {
warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/
return (-1);
}
*ahost = hp->h_name;
if (res->ai_canonname) {
strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1);
hbuf[sizeof(hbuf) - 1] = '\0';
*ahost = hbuf;
}
return (hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p));
error = resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p);
freeaddrinfo(res);
return (error);
}
static int
hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
struct hostent *hp;
resrcmd(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 addrinfo *r;
struct sockaddr_storage from;
struct pollfd reads[2];
sigset_t nmask, omask;
pid_t pid;
@ -166,20 +222,21 @@ hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
int pollr;
char c;
_DIAGASSERT(hp != NULL);
_DIAGASSERT(res != NULL);
_DIAGASSERT(ahost != NULL);
_DIAGASSERT(locuser != NULL);
_DIAGASSERT(remuser != NULL);
_DIAGASSERT(cmd != NULL);
/* fd2p may be NULL */
r = res;
pid = getpid();
sigemptyset(&nmask);
sigaddset(&nmask, SIGURG);
if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)
return -1;
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
s = rresvport(&lport);
s = rresvport_af(&lport, r->ai_family);
if (s < 0) {
if (errno == EAGAIN)
warnx("rcmd: socket: All ports in use");
@ -189,14 +246,7 @@ hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
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, r->ai_addr, r->ai_addrlen) >= 0)
break;
(void)close(s);
if (errno == EADDRINUSE) {
@ -208,21 +258,32 @@ hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
timo *= 2;
continue;
}
if (hp->h_addr_list[1] != NULL) {
if (r->ai_next) {
int oerrno = errno;
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
warnx("rcmd: connect to address %s",
inet_ntoa(sin.sin_addr));
hbuf[0] = '\0';
if (getnameinfo(r->ai_addr, r->ai_addrlen,
hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
strcpy(hbuf, "(invalid)");
warnx("rcmd: connect to address %s", hbuf);
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));
r = r->ai_next;
hbuf[0] = '\0';
if (getnameinfo(r->ai_addr, r->ai_addrlen,
hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
strcpy(hbuf, "(invalid)");
(void)fprintf(stderr, "Trying %s...\n", hbuf);
continue;
}
(void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
(void)fprintf(stderr, "%s: %s\n", res->ai_canonname,
strerror(errno));
(void)sigprocmask(SIG_SETMASK, &omask, NULL);
return (-1);
}
@ -232,7 +293,7 @@ hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
lport = 0;
} else {
char num[8];
int s2 = rresvport(&lport), s3;
int s2 = rresvport_af(&lport, r->ai_family), s3;
socklen_t len = sizeof(from);
if (s2 < 0)
@ -266,12 +327,21 @@ hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)
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) {
warnx("rcmd: protocol failure in circuit setup.");
goto bad2;
switch (((struct sockaddr *)&from)->sa_family) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
if (getnameinfo((struct sockaddr *)&from, len,
NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 ||
(atoi(num) >= IPPORT_RESERVED ||
atoi(num) < IPPORT_RESERVED / 2)) {
warnx("rcmd: protocol failure in circuit setup.");
goto bad2;
}
break;
default:
break;
}
}
@ -452,6 +522,7 @@ rresvport_af(alport, family)
salen = sizeof(struct sockaddr_in);
portp = &((struct sockaddr_in *)sa)->sin_port;
break;
#ifdef INET6
case AF_INET6:
#ifdef BSD4_4
sa->sa_len =
@ -459,6 +530,7 @@ rresvport_af(alport, family)
salen = sizeof(struct sockaddr_in6);
portp = &((struct sockaddr_in6 *)sa)->sin6_port;
break;
#endif
default:
portp = NULL;
return EAFNOSUPPORT;
@ -468,7 +540,9 @@ rresvport_af(alport, family)
if (s < 0)
return (-1);
#ifdef BSD4_4
if (family == AF_INET) {
switch (family) {
case AF_INET:
case AF_INET6:
*portp = 0;
if (bindresvport(s, (struct sockaddr_in *)sa) < 0) {
int sverr = errno;
@ -479,6 +553,9 @@ rresvport_af(alport, family)
}
*alport = (int)ntohs(*portp);
return (s);
default:
/* is it necessary to try keep code for other AFs? */
break;
}
#endif
for (;;) {
@ -506,25 +583,28 @@ ruserok(rhost, superuser, ruser, luser)
const char *rhost, *ruser, *luser;
int superuser;
{
struct hostent *hp;
char **ap;
int i;
#define MAXADDRS 35
u_int32_t addrs[MAXADDRS + 1];
struct addrinfo hints, *res, *r;
int error;
_DIAGASSERT(rhost != NULL);
_DIAGASSERT(ruser != NULL);
_DIAGASSERT(luser != NULL);
if ((hp = gethostbyname(rhost)) == NULL)
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
error = getaddrinfo(rhost, "0", &hints, &res);
if (error)
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;
for (i = 0; i < MAXADDRS && addrs[i]; i++)
if (iruserok(addrs[i], superuser, ruser, luser) == 0)
for (r = res; r; r = r->ai_next) {
if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
luser) == 0) {
freeaddrinfo(res);
return (0);
}
}
freeaddrinfo(res);
return (-1);
}
@ -543,6 +623,28 @@ iruserok(raddr, superuser, ruser, luser)
int superuser;
const char *ruser, *luser;
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(struct sockaddr_in);
memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
return iruserok_sa(&sin, sizeof(struct sockaddr_in), superuser, luser,
ruser);
}
/*
* 2nd and 3rd arguments are typed like this, to avoid dependency between
* unistd.h and sys/socket.h. There's no better way.
*/
int
iruserok_sa(raddr, rlen, superuser, ruser, luser)
const void *raddr;
int rlen;
int superuser;
const char *ruser, *luser;
{
struct sockaddr *sa;
register char *cp;
struct stat sbuf;
struct passwd *pwd;
@ -552,14 +654,20 @@ iruserok(raddr, superuser, ruser, luser)
int first;
char pbuf[MAXPATHLEN];
_DIAGASSERT(raddr != NULL);
_DIAGASSERT(ruser != NULL);
_DIAGASSERT(luser != NULL);
sa = (struct sockaddr *)raddr;
#ifdef lint
rlen = rlen;
#endif
first = 1;
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
again:
if (hostf) {
if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
if (__ivaliduser_sa(hostf, sa, luser, ruser) == 0) {
(void)fclose(hostf);
return (0);
}
@ -625,6 +733,21 @@ __ivaliduser(hostf, raddr, luser, ruser)
FILE *hostf;
u_int32_t raddr;
const char *luser, *ruser;
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(struct sockaddr_in);
memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, luser, ruser);
}
int
__ivaliduser_sa(hostf, raddr, luser, ruser)
FILE *hostf;
struct sockaddr *raddr;
const char *luser, *ruser;
{
register char *user, *p;
int ch;
@ -770,72 +893,122 @@ __ivaliduser(hostf, raddr, luser, ruser)
/*
* Returns "true" if match, 0 if no match.
*
* NI_WITHSCOPEID is useful for comparing sin6_scope_id portion
* if af == AF_INET6.
*/
static int
__icheckhost(raddr, lhost)
u_int32_t raddr;
struct sockaddr *raddr;
const char *lhost;
{
struct hostent *hp;
struct in_addr laddr;
char **pp;
struct addrinfo hints, *res, *r;
char h1[NI_MAXHOST], h2[NI_MAXHOST];
int error;
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
_DIAGASSERT(raddr != NULL);
_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)
h1[0] = '\0';
if (getnameinfo(raddr, raddr->sa_len, h1, sizeof(h1), NULL, 0,
niflags) != 0)
return (0);
/* Spin through ip addresses. */
for (pp = hp->h_addr_list; *pp; ++pp)
if (!memcmp(&raddr, *pp, sizeof(u_int32_t)))
/* Resolve laddr into sockaddr */
memset(&hints, 0, sizeof(hints));
hints.ai_family = raddr->sa_family;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
res = NULL;
error = getaddrinfo(lhost, "0", &hints, &res);
if (error)
return (0);
/*
* Try string comparisons between raddr and laddr.
*/
for (r = res; r; r = r->ai_next) {
h2[0] = '\0';
if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
NULL, 0, niflags) != 0)
continue;
if (strcmp(h1, h2) == 0) {
freeaddrinfo(res);
return (1);
}
}
/* No match. */
freeaddrinfo(res);
return (0);
}
/*
* Return the hostname associated with the supplied address.
* Do a reverse lookup as well for security. If a loop cannot
* be found, pack the result of inet_ntoa() into the string.
* be found, pack the numeric IP address into the string.
*
* NI_WITHSCOPEID is useful for comparing sin6_scope_id portion
* if af == AF_INET6.
*/
static char *
__gethostloop(raddr)
u_int32_t raddr;
struct sockaddr *raddr;
{
static char remotehost[MAXHOSTNAMELEN];
struct hostent *hp;
struct in_addr in;
static char remotehost[NI_MAXHOST];
char h1[NI_MAXHOST], h2[NI_MAXHOST];
struct addrinfo hints, *res, *r;
int error;
#ifdef NI_WITHSCOPEID
const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
#else
const int niflags = NI_NUMERICHOST;
#endif
hp = gethostbyaddr((char *)(void *)&raddr, sizeof(raddr), AF_INET);
if (hp == NULL)
_DIAGASSERT(raddr != NULL);
h1[0] = remotehost[0] = '\0';
if (getnameinfo(raddr, raddr->sa_len, remotehost, sizeof(remotehost),
NULL, 0, NI_NAMEREQD) != 0)
return (NULL);
if (getnameinfo(raddr, raddr->sa_len, h1, sizeof(h1), NULL, 0,
niflags) != 0)
return (NULL);
/*
* 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)
memset(&hints, 0, sizeof(hints));
hints.ai_family = raddr->sa_family;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_CANONNAME;
res = NULL;
error = getaddrinfo(remotehost, "0", &hints, &res);
if (error)
return (NULL);
for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++)
if (!memcmp(hp->h_addr_list[0], &raddr, sizeof(raddr)))
for (r = res; r; r = r->ai_next) {
h2[0] = '\0';
if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
NULL, 0, niflags) != 0)
continue;
if (strcmp(h1, h2) == 0) {
freeaddrinfo(res);
return (remotehost);
}
}
/*
* 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);
h1, res->ai_canonname ? res->ai_canonname : remotehost);
freeaddrinfo(res);
return (NULL);
}