[PATCH] portmap: new applet

Lukas Huba huba.lukas at centrum.cz
Sun May 1 17:12:05 UTC 2011


Marek, thanks for notes.

Modified patch:

Signed-off-by: Lukas Huba <huba.lukas at centrum.cz>
---
 include/applets.src.h |    1 +
 include/usage.src.h   |    8 ++
 networking/Config.src |   16 +++
 networking/Kbuild.src |    1 +
 networking/portmap.c  |  247 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 273 insertions(+), 0 deletions(-)
 create mode 100644 networking/portmap.c

diff --git a/include/applets.src.h b/include/applets.src.h
index 133f376..e92f215 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -283,6 +283,7 @@ IF_PIPE_PROGRESS(APPLET(pipe_progress, BB_DIR_BIN, BB_SUID_DROP))
 IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP))
 IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
 IF_POPMAILDIR(APPLET(popmaildir, BB_DIR_USR_SBIN, BB_SUID_DROP))
+IF_PORTMAP(APPLET(portmap, BB_DIR_SBIN, BB_SUID_DROP))
 IF_PRINTENV(APPLET_NOFORK(printenv, printenv, BB_DIR_BIN, BB_SUID_DROP, printenv))
 IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf))
 IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP))
diff --git a/include/usage.src.h b/include/usage.src.h
index d836093..a94df3c 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -1834,6 +1834,14 @@ INSERT
        "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [<password_file]\n" \
        "$ popmaildir ~/Maildir -- openssl s_client -quiet -connect pop.gmail.com:995 [<password_file]\n"
 
+#define portmap_trivial_usage \
+       "[hpr]"
+#define portmap_full_usage "\n\n" \
+       "RPC program, version to DARPA port mapper\n" \
+     "\nOptions:" \
+     "\n	-h	Specify specific IP addresses to bind to for requests" \
+     "\n	-p	Insecure mode. Allow calls to SET and UNSET from any port (allow port > 1024)" \
+     "\n	-r	Insecure mode. Allow calls to SET and UNSET from any host" \
 
 #if ENABLE_DESKTOP
 
diff --git a/networking/Config.src b/networking/Config.src
index 8aeba0e..37866ac 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -656,6 +656,22 @@ config FEATURE_NTPD_SERVER
 	  Make ntpd usable as a NTP server. If you disable this option
 	  ntpd will be usable only as a NTP client.
 
+config PORTMAP
+	bool "portmap"
+	default n
+	select PLATFORM_LINUX
+	select FEATURE_SYSLOG
+	help
+	  RPC program, version to DARPA port mapper.
+
+config PORTMAP_ITEMS_MAX
+	int "Maximum RPC services"
+	default 32
+	depends on PORTMAP
+	help
+	  Maximum RPC services which portmap is able to store.
+	  That's for better security.
+
 config PSCAN
 	bool "pscan"
 	default y
diff --git a/networking/Kbuild.src b/networking/Kbuild.src
index 944f27b..3f1d026 100644
--- a/networking/Kbuild.src
+++ b/networking/Kbuild.src
@@ -30,6 +30,7 @@ lib-$(CONFIG_NC)           += nc.o
 lib-$(CONFIG_NETSTAT)      += netstat.o
 lib-$(CONFIG_NSLOOKUP)     += nslookup.o
 lib-$(CONFIG_NTPD)         += ntpd.o
+lib-$(CONFIG_PORTMAP)      += portmap.o
 lib-$(CONFIG_PSCAN)        += pscan.o
 lib-$(CONFIG_ROUTE)        += route.o
 lib-$(CONFIG_SLATTACH)     += slattach.o
diff --git a/networking/portmap.c b/networking/portmap.c
new file mode 100644
index 0000000..e288a15
--- /dev/null
+++ b/networking/portmap.c
@@ -0,0 +1,247 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * mini portmap implementation for busybox
+ *
+ * Copyright (C) 2011 by Lukas Huba <huba.lukas at centrum.cz>
+ *
+ * Licensed under GPLv2, see file LICENSE in this source tree.
+ */
+
+//applets: IF_PORTMAP(APPLET(portmap, BB_DIR_SBIN, BB_SUID_DROP))
+
+//Kbuild: lib-$(CONFIG_PORTMAP) += portmap.o
+
+//config: config PORTMAP
+//config: 	bool "portmap"
+//config: 	default n
+//config: 	select PLATFORM_LINUX
+//config: 	select FEATURE_SYSLOG
+//config: 	help
+//config: 	  RPC program, version to DARPA port mapper.
+//config: 
+//config: config PORTMAP_ITEMS_MAX
+//config: 	int "Maximum RPC services"
+//config: 	default 32
+//config: 	depends on PORTMAP
+//config: 	help
+//config: 	  Maximum RPC services which portmap is able to store.
+//config: 	  That's for better security.
+
+//usage: #define portmap_trivial_usage
+//usage:        "[hpr]"
+//usage: #define portmap_full_usage "\n\n"
+//usage:        "RPC program, version to DARPA port mapper\n"
+//usage:      "\nOptions:"
+//usage:      "\n	-h	Specify specific IP addresses to bind to for requests"
+//usage:      "\n	-p	Insecure mode. Allow calls to SET and UNSET from any
+//usage:                port (allow port > 1024)"
+//usage:      "\n	-r	Insecure mode. Allow calls to SET and UNSET from any
+//usage:                host"
+
+#include "libbb.h"
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+
+/* commandline parameters */
+static int flags;
+#define FLAGS_ARG		"h:pr"
+#define FLAG_HOST		(1 << 0)
+#define FLAG_SPORT		(2 << 0)
+#define FLAG_SREMOTE	(4 << 0)
+
+/* portmap items */
+static int pn;
+static struct pmaplist *pl;
+
+/* default count of network interfaces (later it updates itself)
+ * it's for higher efficiency (re|m)alloc */
+static int ifs = 5;
+
+static bool_t pmapproc_set(const struct pmap *pr)
+{
+	struct pmaplist *p, *pp = NULL, **n;
+	if (pn >= CONFIG_PORTMAP_ITEMS_MAX) {
+		bb_error_msg("All available resources are used! Count of registered "\
+					"RPC services is limited to %i.", CONFIG_PORTMAP_ITEMS_MAX);
+		return FALSE;
+	}
+	for (p = pl; p != NULL; p = p->pml_next) {
+		if (p->pml_map.pm_prog == pr->pm_prog
+			&& p->pml_map.pm_vers == pr->pm_vers
+			&& p->pml_map.pm_prot == pr->pm_prot) {
+			return FALSE;
+		}
+		pp = p;
+	}
+	if (pp == NULL)
+		n = &pl;
+	else
+		n = &pp->pml_next;
+	*n = xmalloc(sizeof(struct pmaplist));
+	(*n)->pml_map = *pr;
+	(*n)->pml_next = NULL;
+	pn++;
+	return TRUE;
+}
+
+static bool_t pmapproc_unset(const struct pmap *pr)
+{
+	bool_t res = FALSE;
+	struct pmaplist *p, *pp = NULL;
+	for (p=pl; p!=NULL; p=p->pml_next) {
+		if (p->pml_map.pm_prog == pr->pm_prog &&
+			p->pml_map.pm_vers == pr->pm_vers) {
+			res = TRUE;
+			if (p->pml_next == NULL) {
+				if (pp == NULL) {
+					pl = NULL;
+				} else {
+					pp->pml_next = NULL;
+				}
+			} else {
+				if (pp == NULL) {
+					pl = p->pml_next;
+				} else {
+					pp->pml_next = p->pml_next;
+				}
+			}
+			free(p);
+			pn--;
+		} else {
+			pp=p;
+		}
+	}
+	return res;
+}
+
+static unsigned int pmapproc_getport(const struct pmap *pr)
+{
+	struct pmaplist *p;
+	for (p=pl; p!=NULL; p=p->pml_next) {
+		if (p->pml_map.pm_prog == pr->pm_prog &&
+			p->pml_map.pm_vers == pr->pm_vers) {
+			return p->pml_map.pm_port;
+		}
+	}
+	return 0;
+}
+
+static bool_t check_security(SVCXPRT *xprt)
+{
+	if (!(flags & FLAG_SPORT))
+		/* secure mode
+		 * SET and UNSET procs can be exec only from port <= 1024 */
+		if (htons(svc_getcaller(xprt)->sin_port) > 1024)
+			return FALSE;
+	if (!(flags & FLAG_SREMOTE)) {
+		/* secure mode
+		 * SET and UNSET procs can be exec only from local machine */
+		bool_t res = FALSE;
+		struct ifconf ifc;
+		int s = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		for (int cnt = 0; !cnt || ifc.ifc_len/sizeof(struct ifreq) == cnt;
+			cnt += ifs) {
+			ifc.ifc_len = (cnt+ifs)*sizeof(struct ifreq);
+			ifc.ifc_req = xrealloc(ifc.ifc_req, ifc.ifc_len);
+			if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+				bb_error_msg("ioctl(SIOCGIFCONF) error");
+				goto out;
+			}
+		}
+		ifs = ifc.ifc_len/sizeof(struct ifreq)+1;
+		for (int i = 0; i < ifs-1; i++) {
+			if (((struct sockaddr_in *)&ifc.ifc_req[i].ifr_addr)->
+				sin_addr.s_addr == svc_getcaller(xprt)->sin_addr.s_addr) {
+				res = TRUE;
+				goto out;
+			}
+		}
+out:
+		free(ifc.ifc_req);
+		return res;
+	}
+	return TRUE;
+}
+
+static void pmapproc(struct svc_req *rqstp, SVCXPRT *xprt)
+{
+	unsigned int res;
+	struct pmap pmap;
+
+	if (rqstp->rq_proc == PMAPPROC_SET || rqstp->rq_proc == PMAPPROC_UNSET)
+		if (check_security(xprt) == FALSE) {
+			svcerr_weakauth(xprt);
+			return;
+		}
+
+	if (rqstp->rq_proc > PMAPPROC_NULL && rqstp->rq_proc < PMAPPROC_DUMP)
+		if (!svc_getargs(xprt, (xdrproc_t)xdr_pmap, (caddr_t)&pmap))
+			return;
+
+	switch(rqstp->rq_proc) {
+		case PMAPPROC_NULL:
+			svc_sendreply(xprt, (xdrproc_t)xdr_void, (caddr_t)NULL);
+			break;
+		case PMAPPROC_SET:
+			res = (unsigned int)pmapproc_set(&pmap);
+			svc_sendreply(xprt, (xdrproc_t)xdr_bool, (caddr_t)&res);
+			break;
+		case PMAPPROC_UNSET:
+			res = (unsigned int)pmapproc_unset(&pmap);
+			svc_sendreply(xprt, (xdrproc_t)xdr_bool, (caddr_t)&res);
+			break;
+		case PMAPPROC_GETPORT:
+			res = pmapproc_getport(&pmap);
+			svc_sendreply(xprt, (xdrproc_t)xdr_u_int, (caddr_t)&res);
+			break;
+		case PMAPPROC_DUMP:
+			svc_sendreply(xprt, (xdrproc_t)xdr_pmaplist, (caddr_t)&pl);
+			break;
+		default:
+			svcerr_noproc(xprt);
+	}
+}
+
+int portmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int portmap_main(int argc, char **argv)
+{
+	char *host = (char *)"0.0.0.0";
+	if (argc >= 2)
+		flags = getopt32(argv, FLAGS_ARG, &host);
+
+	bb_daemonize(DAEMON_CHDIR_ROOT);
+
+	openlog(applet_name, LOG_PID | LOG_ERR, LOG_DAEMON);
+	logmode |= LOGMODE_SYSLOG;
+
+	{
+		int sock;
+		SVCXPRT *xprt;
+		struct pmap pm = {PMAPPROG, PMAPVERS, IPPROTO_UDP, PMAPPORT};
+
+		/* udp listening */
+		sock = create_and_bind_dgram_or_die(host, PMAPPORT);
+		if ((xprt = svcudp_create(sock)) == (SVCXPRT *)NULL)
+			bb_error_msg_and_die("cannot start portmap");
+		pmapproc_set(&pm);
+		if (svc_register(xprt, PMAPPROG, PMAPVERS, pmapproc, 0))
+			pn++;
+
+		/* tcp listening */
+		sock = create_and_bind_stream_or_die(host, PMAPPORT);
+		if ((xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE))
+			== (SVCXPRT *)NULL)
+			bb_error_msg_and_die("cannot start portmap");
+		pm.pm_prot = IPPROTO_TCP;
+		pmapproc_set(&pm);
+		if (svc_register(xprt, PMAPPROG, PMAPVERS, pmapproc, 0))
+			pn++;
+	}
+
+	svc_run();
+
+	return EXIT_SUCCESS;
+}
-- 
1.7.4.rc1


More information about the busybox mailing list