Page MenuHomeFreeBSD

D19218.id54030.diff
No OneTemporary

D19218.id54030.diff

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,9 @@
int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
pid_t slaves[MAXNFSUSERD];
+static struct sockaddr_in fromip;
+static struct sockaddr_in6 fromip6;
+static int use_inet6 = 0;
int
main(int argc, char *argv[])
@@ -105,13 +113,14 @@
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;
+ int s;
if (modfind("nfscommon") < 0) {
/* Not present in kernel, try loading it */
@@ -144,6 +153,32 @@
}
}
}
+
+ /*
+ * See if this server handles IPv4 or IPv6 and set up the default
+ * localhost address.
+ */
+ use_inet6 = 0;
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ use_inet6 = 1;
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ }
+ if (s < 0)
+ err(1, "Can't create a inet/inet6 socket");
+ close(s);
+
+ /*
+ * Hard wire the "localhost" address here, so that the startup
+ * of this deamon does not require a working DNS nor an accessible
+ * /etc/hosts file.
+ * Since these values are defined in RFCs, they should never change.
+ */
+ if (use_inet6 == 0)
+ fromip.sin_addr.s_addr = inet_addr("127.0.0.1");
+ else
+ inet_pton(AF_INET6, "::1", &fromip6.sin6_addr);
+
nid.nid_usermax = DEFUSERMAX;
nid.nid_usertimeout = defusertimeout;
@@ -245,11 +280,15 @@
for (i = 0; i < nfsuserdcnt; i++)
slaves[i] = (pid_t)-1;
+ if (use_inet6 != 0)
+ nargs.nuserd_family = AF_INET6;
+ else
+ nargs.nuserd_family = AF_INET;
/*
* Set up the service port to accept requests via UDP from
- * localhost (127.0.0.1).
+ * localhost (127.0.0.1 or ::1).
*/
- 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 +311,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");
@@ -460,24 +499,74 @@
u_short sport;
struct info info;
struct nfsd_idargs nid;
- u_int32_t saddr;
gid_t grps[NGROUPS];
int ngroup;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int ret;
+ char buf[INET6_ADDRSTRLEN];
/*
- * 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) {
+ if (use_inet6 == 0) {
+ 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;
+ 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 != fromip.sin_addr.s_addr)
+ ret = nfsbind_localhost();
+ if (ret == 0 || sin->sin_addr.s_addr !=
+ fromip.sin_addr.s_addr) {
+ syslog(LOG_ERR, "bad from ip %s",
+ inet_ntoa(sin->sin_addr));
+ svcerr_weakauth(transp);
+ return;
+ }
+ } else {
+ 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;
+ 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,
+ &fromip6.sin6_addr))
+ ret = nfsbind_localhost();
+ if (ret == 0 || !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &fromip6.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;
+ }
+ }
}
switch (rqstp->rq_proc) {
case NULLPROC:
@@ -718,6 +807,62 @@
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)
+{
+ struct sockaddr_in sad;
+ struct sockaddr_in6 sad6;
+ socklen_t slen;
+ int ret, s;
+
+ if (use_inet6 != 0) {
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+ memset(&sad6, 0, sizeof(sad6));
+ sad6.sin6_len = sizeof(sad6);
+ sad6.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, "::1", &sad6.sin6_addr);
+ sad6.sin6_port = 0;
+ ret = bind(s, (struct sockaddr *)&sad6, sizeof(sad6));
+ if (ret < 0) {
+ close(s);
+ return (0);
+ }
+ memset(&fromip6, 0, sizeof(fromip6));
+ slen = sizeof(fromip6);
+ ret = getsockname(s, (struct sockaddr *)&fromip6, &slen);
+ close(s);
+ if (ret < 0)
+ return (0);
+ } else {
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+ memset(&sad, 0, sizeof(sad));
+ sad.sin_len = sizeof(sad);
+ sad.sin_family = AF_INET;
+ sad.sin_addr.s_addr = inet_addr("127.0.0.1");
+ sad.sin_port = 0;
+ ret = bind(s, (struct sockaddr *)&sad, sizeof(sad));
+ if (ret < 0) {
+ close(s);
+ return (0);
+ }
+ 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
Wed, Jul 29, 4:36 PM (3 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35707550
Default Alt Text
D19218.id54030.diff (6 KB)

Event Timeline