Marek, thanks for notes. Modified patch:
Signed-off-by: Lukas Huba <[email protected]> --- 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 <[email protected]> + * + * 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 _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
