Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Mar 2004 21:10:30 +0000
From:      Bruce M Simpson <bms@spc.org>
To:        freebsd-security@FreeBSD.org
Subject:   [PATCH] Force mountd(8) to a specified port.
Message-ID:  <20040302211030.GJ7115@saboteur.dek.spc.org>

next in thread | raw e-mail | index | archive | help

--osDK9TLjxFScVI/L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,

I have a requirement to run NFS read-only in an Internet-facing colocation
environment. I am not happy with packet filters alone around rpcbind, call
me paranoid, so I just spent the last few minutes cutting this patch.

As you are aware, RPC applications can be forced to listen on a known port
through the sin/sa argument to bindresvport[_sa](). Why several Linux
distributions have this feature yet none of the BSDs do is beyond me...

Please let me know your thoughts. If there are no valid objections I plan
to commit it.

Regards,
BMS

--osDK9TLjxFScVI/L
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="mountd-force-port.diff"

Index: mountd.8
===================================================================
RCS file: /home/ncvs/src/usr.sbin/mountd/mountd.8,v
retrieving revision 1.24
diff -u -r1.24 mountd.8
--- mountd.8	12 Dec 2002 17:26:02 -0000	1.24
+++ mountd.8	2 Mar 2004 20:55:37 -0000
@@ -43,6 +43,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl 2dlnr
+.Op Fl p Ar port
 .Op Ar exportsfile
 .Sh DESCRIPTION
 The
@@ -77,6 +78,18 @@
 that require it.
 It will automatically clear the vfs.nfsrv.nfs_privport sysctl flag, which
 controls if the kernel will accept NFS requests from reserved ports only.
+.It Fl p Ar port
+Force
+.Nm
+to bind to the specified port, for both
+.Vt AF_INET
+and
+.Vt AF_INET6
+address families.
+If
+.Nm
+cannot bind to this port, an appropriate error will be recorded in
+the system log, and the daemon will then exit.
 .It Fl r
 Allow mount RPCs requests for regular files to be served.
 Although this seems to violate the mount protocol specification,
Index: mountd.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/mountd/mountd.c,v
retrieving revision 1.74
diff -u -r1.74 mountd.c
--- mountd.c	30 Oct 2003 22:57:43 -0000	1.74
+++ mountd.c	2 Mar 2004 21:08:17 -0000
@@ -272,11 +272,15 @@
 	fd_set readfds;
 	SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
 	struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
 	int udpsock, tcpsock, udp6sock, tcp6sock;
+	char *endptr;
+	in_port_t svcport = 0;
 	int xcreated = 0, s;
 	int maxrec = RPC_MAXDATASIZE;
 	int one = 1;
-	int c;
+	int c, r;
 
 	udp6conf = tcp6conf = NULL;
 	udp6sock = tcp6sock = NULL;
@@ -298,7 +302,7 @@
 			errx(1, "NFS server is not available or loadable");
 	}
 
-	while ((c = getopt(argc, argv, "2dlnr")) != -1)
+	while ((c = getopt(argc, argv, "2dlnp:r")) != -1)
 		switch (c) {
 		case '2':
 			force_v2 = 1;
@@ -315,6 +319,14 @@
 		case 'l':
 			dolog = 1;
 			break;
+		case 'p':
+			endptr = NULL;
+			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
+			if (endptr == NULL || *endptr != '\0' ||
+			    svcport < IPPORT_RESERVEDSTART ||
+			    svcport >= IPPORT_MAX)
+				usage();
+			break;
 		default:
 			usage();
 		};
@@ -390,8 +402,26 @@
 			exit(1);
 		}
 	}
+	if (svcport != 0) {
+		bzero(&sin, sizeof(struct sockaddr_in));
+		sin.sin_len = sizeof(struct sockaddr_in);
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(svcport);
+
+		bzero(&sin6, sizeof(struct sockaddr_in6));
+		sin6.sin6_len = sizeof(struct sockaddr_in6);
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_port = htons(svcport);
+	}
 	if (udpsock != -1 && udpconf != NULL) {
-		bindresvport(udpsock, NULL);
+		if (svcport != 0) {
+			r = bindresvport(udpsock, &sin);
+			if (r != 0) {
+				syslog(LOG_ERR, "bindresvport: %m");
+				exit(1);
+			}
+		} else
+			(void)bindresvport(udpsock, NULL);
 		udptransp = svc_dg_create(udpsock, 0, 0);
 		if (udptransp != NULL) {
 			if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1,
@@ -411,7 +441,14 @@
 
 	}
 	if (tcpsock != -1 && tcpconf != NULL) {
-		bindresvport(tcpsock, NULL);
+		if (svcport != 0) {
+			r = bindresvport(tcpsock, &sin);
+			if (r != 0) {
+				syslog(LOG_ERR, "bindresvport: %m");
+				exit(1);
+			}
+		} else
+			(void)bindresvport(tcpsock, NULL);
 		listen(tcpsock, SOMAXCONN);
 		tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
 		if (tcptransp != NULL) {
@@ -432,7 +469,15 @@
 
 	}
 	if (have_v6 && udp6sock != -1 && udp6conf != NULL) {
-		bindresvport(udp6sock, NULL);
+		if (svcport != 0) {
+			r = bindresvport_sa(udp6sock,
+			    (struct sockaddr *)&sin6);
+			if (r != 0) {
+				syslog(LOG_ERR, "bindresvport_sa: %m");
+				exit(1);
+			}
+		} else
+			(void)bindresvport_sa(udp6sock, NULL);
 		udp6transp = svc_dg_create(udp6sock, 0, 0);
 		if (udp6transp != NULL) {
 			if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1,
@@ -452,7 +497,15 @@
 
 	}
 	if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) {
-		bindresvport(tcp6sock, NULL);
+		if (svcport != 0) {
+			r = bindresvport_sa(tcp6sock,
+			    (struct sockaddr *)&sin6);
+			if (r != 0) {
+				syslog(LOG_ERR, "bindresvport_sa: %m");
+				exit(1);
+			}
+		} else
+			(void)bindresvport_sa(tcp6sock, NULL);
 		listen(tcp6sock, SOMAXCONN);
 		tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
 		if (tcp6transp != NULL) {
@@ -502,7 +555,8 @@
 usage()
 {
 	fprintf(stderr,
-		"usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n");
+		"usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] "
+		"[export_file]\n");
 	exit(1);
 }
 

--osDK9TLjxFScVI/L--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040302211030.GJ7115>