Page MenuHomeFreeBSD

D19218.id54318.diff
No OneTemporary

D19218.id54318.diff

Index: sys/fs/nfs/nfs.h
===================================================================
--- sys/fs/nfs/nfs.h
+++ sys/fs/nfs/nfs.h
@@ -252,6 +252,11 @@
int nid_namelen; /* and its length */
};
+struct nfsuserd_args {
+ sa_family_t nuserd_family; /* Address family to use */
+ u_short nuserd_port; /* Port# */
+};
+
struct nfsd_clid {
int nclid_idlen; /* Length of client id */
u_char nclid_id[NFSV4_OPAQUELIMIT]; /* and name */
Index: sys/fs/nfs/nfs_commonport.c
===================================================================
--- sys/fs/nfs/nfs_commonport.c
+++ sys/fs/nfs/nfs_commonport.c
@@ -631,30 +631,24 @@
goto out;
} else if (uap->flag & NFSSVC_NFSUSERDPORT) {
u_short sockport;
- struct sockaddr *sad;
- struct sockaddr_un *sun;
+ struct nfsuserd_args nargs;
if ((uap->flag & NFSSVC_NEWSTRUCT) != 0) {
- /* New nfsuserd using an AF_LOCAL socket. */
- sun = malloc(sizeof(struct sockaddr_un), M_SONAME,
- M_WAITOK | M_ZERO);
- error = copyinstr(uap->argp, sun->sun_path,
- sizeof(sun->sun_path), NULL);
- if (error != 0) {
- free(sun, M_SONAME);
- return (error);
- }
- sun->sun_family = AF_LOCAL;
- sun->sun_len = SUN_LEN(sun);
- sockport = 0;
- sad = (struct sockaddr *)sun;
+ /*
+ * New nfsuserd_args structure, which indicates
+ * which IP version to use along with the port#.
+ */
+ error = copyin(uap->argp, &nargs, sizeof(nargs));
} else {
error = copyin(uap->argp, (caddr_t)&sockport,
sizeof (u_short));
- sad = NULL;
+ if (error == 0) {
+ nargs.nuserd_family = AF_INET;
+ nargs.nuserd_port = sockport;
+ }
}
if (error == 0)
- error = nfsrv_nfsuserdport(sad, sockport, p);
+ error = nfsrv_nfsuserdport(&nargs, p);
} else if (uap->flag & NFSSVC_NFSUSERDDELPORT) {
nfsrv_nfsuserddelport();
error = 0;
Index: sys/fs/nfs/nfs_commonsubs.c
===================================================================
--- sys/fs/nfs/nfs_commonsubs.c
+++ sys/fs/nfs/nfs_commonsubs.c
@@ -3531,17 +3531,18 @@
* Set the port for the nfsuserd.
*/
APPLESTATIC int
-nfsrv_nfsuserdport(struct sockaddr *sad, u_short port, NFSPROC_T *p)
+nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
{
struct nfssockreq *rp;
struct sockaddr_in *ad;
+ struct sockaddr_in6 *ad6;
+ const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
int error;
NFSLOCKNAMEID();
if (nfsrv_nfsuserd) {
NFSUNLOCKNAMEID();
error = EPERM;
- free(sad, M_SONAME);
goto out;
}
nfsrv_nfsuserd = 1;
@@ -3553,22 +3554,25 @@
rp->nr_client = NULL;
rp->nr_cred = NULL;
rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
- if (sad != NULL) {
- /* Use the AF_LOCAL socket address passed in. */
- rp->nr_sotype = SOCK_STREAM;
- rp->nr_soproto = 0;
- rp->nr_nam = sad;
- } else {
- /* Use the port# for a UDP socket (old nfsuserd). */
- rp->nr_sotype = SOCK_DGRAM;
- rp->nr_soproto = IPPROTO_UDP;
+ /* Use the port# for a UDP socket. */
+ rp->nr_sotype = SOCK_DGRAM;
+ rp->nr_soproto = IPPROTO_UDP;
+ if (nargs->nuserd_family == AF_INET) {
rp->nr_nam = malloc(sizeof(*rp->nr_nam), M_SONAME, M_WAITOK |
M_ZERO);
NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
ad->sin_family = AF_INET;
- ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);
- ad->sin_port = port;
+ ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ ad->sin_port = nargs->nuserd_port;
+ } else {
+ rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
+ M_WAITOK | M_ZERO);
+ NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in6));
+ ad6 = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in6 *);
+ ad6->sin6_family = AF_INET6;
+ ad6->sin6_addr = in6loopback;
+ ad6->sin6_port = nargs->nuserd_port;
}
rp->nr_prog = RPCPROG_NFSUSERD;
rp->nr_vers = RPCNFSUSERD_VERS;
Index: sys/fs/nfs/nfs_var.h
===================================================================
--- sys/fs/nfs/nfs_var.h
+++ sys/fs/nfs/nfs_var.h
@@ -136,7 +136,7 @@
NFSPROC_T *);
int nfsrv_checkgetattr(struct nfsrv_descript *, vnode_t,
struct nfsvattr *, nfsattrbit_t *, NFSPROC_T *);
-int nfsrv_nfsuserdport(struct sockaddr *, u_short, NFSPROC_T *);
+int nfsrv_nfsuserdport(struct nfsuserd_args *, NFSPROC_T *);
void nfsrv_nfsuserddelport(void);
void nfsrv_throwawayallstate(NFSPROC_T *);
int nfsrv_checksequence(struct nfsrv_descript *, uint32_t, uint32_t *,
Index: usr.sbin/nfsuserd/Makefile
===================================================================
--- usr.sbin/nfsuserd/Makefile
+++ usr.sbin/nfsuserd/Makefile
@@ -1,7 +1,16 @@
# $FreeBSD: head/usr.sbin/nfsuserd/Makefile 193070 2009-05-29 22:19:45Z delphij $
+.include <src.opts.mk>
+
PROG= nfsuserd
MAN= nfsuserd.8
WARNS?= 3
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DINET
+.endif
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DINET6
+.endif
+
.include <bsd.prog.mk>
Index: usr.sbin/nfsuserd/nfsuserd.c
===================================================================
--- usr.sbin/nfsuserd/nfsuserd.c
+++ usr.sbin/nfsuserd/nfsuserd.c
@@ -40,6 +40,10 @@
#include <sys/vnode.h>
#include <sys/wait.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
#include <nfs/nfssvc.h>
#include <rpc/rpc.h>
@@ -72,6 +76,7 @@
static bool_t xdr_getid(XDR *, caddr_t);
static bool_t xdr_getname(XDR *, caddr_t);
static bool_t xdr_retval(XDR *, caddr_t);
+static int nfsbind_localhost(void);
#define MAXNAME 1024
#define MAXNFSUSERD 20
@@ -94,6 +99,10 @@
int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
pid_t slaves[MAXNFSUSERD];
+static struct sockaddr_storage fromip;
+#ifdef INET6
+static struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
+#endif
int
main(int argc, char *argv[])
@@ -105,13 +114,20 @@
struct group *grp;
int sock, one = 1;
SVCXPRT *udptransp;
- u_short portnum;
+ struct nfsuserd_args nargs;
sigset_t signew;
char hostname[MAXHOSTNAMELEN + 1], *cp;
struct addrinfo *aip, hints;
static uid_t check_dups[MAXUSERMAX];
gid_t grps[NGROUPS];
int ngroup;
+#ifdef INET
+ struct sockaddr_in *sin;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ int s;
if (modfind("nfscommon") < 0) {
/* Not present in kernel, try loading it */
@@ -144,6 +160,37 @@
}
}
}
+
+ /*
+ * See if this server handles IPv4 or IPv6 and set up the default
+ * localhost address.
+ */
+ s = -1;
+#ifdef INET6
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ fromip.ss_family = AF_INET6;
+ fromip.ss_len = sizeof(struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *)&fromip;
+ sin6->sin6_addr = in6loopback;
+ close(s);
+ }
+#endif /* INET6 */
+#ifdef INET
+ if (s < 0) {
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ fromip.ss_family = AF_INET;
+ fromip.ss_len = sizeof(struct sockaddr_in);
+ sin = (struct sockaddr_in *)&fromip;
+ sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ close(s);
+ }
+ }
+#endif /* INET */
+ if (s < 0)
+ err(1, "Can't create a inet/inet6 socket");
+
nid.nid_usermax = DEFUSERMAX;
nid.nid_usertimeout = defusertimeout;
@@ -245,11 +292,12 @@
for (i = 0; i < nfsuserdcnt; i++)
slaves[i] = (pid_t)-1;
+ nargs.nuserd_family = fromip.ss_family;
/*
* Set up the service port to accept requests via UDP from
- * localhost (127.0.0.1).
+ * localhost (INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT).
*/
- if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ if ((sock = socket(nargs.nuserd_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
err(1, "cannot create udp socket");
/*
@@ -272,11 +320,11 @@
/*
* Tell the kernel what my port# is.
*/
- portnum = htons(udptransp->xp_port);
+ nargs.nuserd_port = htons(udptransp->xp_port);
#ifdef DEBUG
- printf("portnum=0x%x\n", portnum);
+ printf("portnum=0x%x\n", nargs.nuserd_port);
#else
- if (nfssvc(NFSSVC_NFSUSERDPORT, (caddr_t)&portnum) < 0) {
+ if (nfssvc(NFSSVC_NFSUSERDPORT | NFSSVC_NEWSTRUCT, &nargs) < 0) {
if (errno == EPERM) {
fprintf(stderr,
"Can't start nfsuserd when already running");
@@ -457,27 +505,92 @@
struct passwd *pwd;
struct group *grp;
int error;
+#if defined(INET) || defined(INET6)
u_short sport;
+ int ret;
+#endif
struct info info;
struct nfsd_idargs nid;
- u_int32_t saddr;
gid_t grps[NGROUPS];
int ngroup;
+#ifdef INET
+ struct sockaddr_in *fromsin, *sin;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 *fromsin6, *sin6;
+ char buf[INET6_ADDRSTRLEN];
+#endif
/*
- * Only handle requests from 127.0.0.1 on a reserved port number.
+ * Only handle requests from localhost on a reserved port number.
+ * If the upcall is from a different address, call nfsbind_localhost()
+ * to check for a remapping of localhost, due to jails.
* (Since a reserved port # at localhost implies a client with
* local root, there won't be a security breach. This is about
* the only case I can think of where a reserved port # means
* something.)
*/
- sport = ntohs(transp->xp_raddr.sin_port);
- saddr = ntohl(transp->xp_raddr.sin_addr.s_addr);
- if ((rqstp->rq_proc != NULLPROC && sport >= IPPORT_RESERVED) ||
- saddr != 0x7f000001) {
- syslog(LOG_ERR, "req from ip=0x%x port=%d\n", saddr, sport);
- svcerr_weakauth(transp);
- return;
+ if (rqstp->rq_proc != NULLPROC) {
+ switch (fromip.ss_family) {
+#ifdef INET
+ case AF_INET:
+ if (transp->xp_rtaddr.len < sizeof(*sin)) {
+ syslog(LOG_ERR, "xp_rtaddr too small");
+ svcerr_weakauth(transp);
+ return;
+ }
+ sin = (struct sockaddr_in *)transp->xp_rtaddr.buf;
+ fromsin = (struct sockaddr_in *)&fromip;
+ sport = ntohs(sin->sin_port);
+ if (sport >= IPPORT_RESERVED) {
+ syslog(LOG_ERR, "not a reserved port#");
+ svcerr_weakauth(transp);
+ return;
+ }
+ ret = 1;
+ if (sin->sin_addr.s_addr != fromsin->sin_addr.s_addr)
+ ret = nfsbind_localhost();
+ if (ret == 0 || sin->sin_addr.s_addr !=
+ fromsin->sin_addr.s_addr) {
+ syslog(LOG_ERR, "bad from ip %s",
+ inet_ntoa(sin->sin_addr));
+ svcerr_weakauth(transp);
+ return;
+ }
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ if (transp->xp_rtaddr.len < sizeof(*sin6)) {
+ syslog(LOG_ERR, "xp_rtaddr too small");
+ svcerr_weakauth(transp);
+ return;
+ }
+ sin6 = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
+ fromsin6 = (struct sockaddr_in6 *)&fromip;
+ sport = ntohs(sin6->sin6_port);
+ if (sport >= IPV6PORT_RESERVED) {
+ syslog(LOG_ERR, "not a reserved port#");
+ svcerr_weakauth(transp);
+ return;
+ }
+ ret = 1;
+ if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &fromsin6->sin6_addr))
+ ret = nfsbind_localhost();
+ if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &fromsin6->sin6_addr)) {
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
+ INET6_ADDRSTRLEN) != NULL)
+ syslog(LOG_ERR, "bad from ip %s", buf);
+ else
+ syslog(LOG_ERR, "bad from ip6 addr");
+ svcerr_weakauth(transp);
+ return;
+ }
+ break;
+#endif /* INET6 */
+ }
}
switch (rqstp->rq_proc) {
case NULLPROC:
@@ -718,6 +831,67 @@
exit(0);
}
+/*
+ * Get the IP address that the localhost address maps to.
+ * This is needed when jails map localhost to another IP address.
+ */
+static int
+nfsbind_localhost(void)
+{
+#ifdef INET
+ struct sockaddr_in sin;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+ socklen_t slen;
+ int ret, s;
+
+ switch (fromip.ss_family) {
+#ifdef INET6
+ case AF_INET6:
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6loopback;
+ sin6.sin6_port = 0;
+ ret = bind(s, (struct sockaddr *)&sin6, sizeof(sin6));
+ if (ret < 0) {
+ close(s);
+ return (0);
+ }
+ break;
+#endif /* INET6 */
+#ifdef INET
+ case AF_INET:
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sin.sin_port = 0;
+ ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
+ if (ret < 0) {
+ close(s);
+ return (0);
+ }
+ break;
+#endif /* INET */
+ }
+ memset(&fromip, 0, sizeof(fromip));
+ slen = sizeof(fromip);
+ ret = getsockname(s, (struct sockaddr *)&fromip, &slen);
+ close(s);
+ if (ret < 0)
+ return (0);
+ return (1);
+}
+
static void
usage(void)
{

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 8, 4:45 PM (9 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28475167
Default Alt Text
D19218.id54318.diff (12 KB)

Event Timeline