Thanks. Modified (2).

Note:
> > +   if (argc >= 2)
> Is this `if' really needed?
No, this is only to suppress warning message: "warning: unused parameter 
‘argc’".


Patch:

Signed-off-by: Lukas Huba <[email protected]>
---
 networking/portmap.c |  247 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 247 insertions(+), 0 deletions(-)
 create mode 100644 networking/portmap.c

diff --git a/networking/portmap.c b/networking/portmap.c
new file mode 100644
index 0000000..6164d0b
--- /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.
+ */
+
+//applet: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.
+//config:
+
+//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 */
+#define FLAGS_ARG              "h:pr"
+#define FLAG_HOST              (1 << 0)
+#define FLAG_SPORT             (2 << 0)
+#define FLAG_SREMOTE   (4 << 0)
+
+struct globals {
+       int flags;      /* commanline flags */
+       int pn; /* count of items in portmap list */
+       struct pmaplist *pl;    /* portmap list */
+       int ifs;        /* default count of network interfaces (later it 
updates itself)
+                               it's for higher efficiency (re|m)alloc */
+} FIX_ALIASING;
+#define G (*(struct globals *)&bb_common_bufsiz1)
+
+static bool_t pmapproc_set(const struct pmap *pr)
+{
+       struct pmaplist *p, *pp = NULL, **n;
+       if (G.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 = G.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;
+       }
+       n = pp == NULL ? &G.pl : &pp->pml_next;
+       *n = xmalloc(sizeof(struct pmaplist));
+       (*n)->pml_map = *pr;
+       (*n)->pml_next = NULL;
+       G.pn++;
+       return TRUE;
+}
+
+static bool_t pmapproc_unset(const struct pmap *pr)
+{
+       bool_t res = FALSE;
+       struct pmaplist *p, *pp = NULL;
+       for (p = G.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) {
+                                       G.pl = NULL;
+                               } else {
+                                       pp->pml_next = NULL;
+                               }
+                       } else {
+                               if (pp == NULL) {
+                                       G.pl = p->pml_next;
+                               } else {
+                                       pp->pml_next = p->pml_next;
+                               }
+                       }
+                       free(p);
+                       G.pn--;
+               } else {
+                       pp = p;
+               }
+       }
+       return res;
+}
+
+static unsigned int pmapproc_getport(const struct pmap *pr)
+{
+       struct pmaplist *p;
+       for (p = G.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 (!(G.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 (!(G.flags & FLAG_SREMOTE)) {
+               /* secure mode
+                * SET and UNSET procs can be exec only from local machine */
+               bool_t res = FALSE;
+               struct ifconf ifc = {.ifc_req = NULL};
+               int s = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+               for (int cnt = 0; !cnt || ifc.ifc_len/sizeof(struct ifreq) == 
cnt;
+                       cnt += G.ifs) {
+                       ifc.ifc_len = (cnt+G.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;
+                       }
+               }
+               G.ifs = ifc.ifc_len/sizeof(struct ifreq)+1;
+               for (int i = 0; i < G.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)&G.pl);
+                       break;
+               default:
+                       svcerr_noproc(xprt);
+       }
+}
+
+int portmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int portmap_main(int argc, char **argv)
+{
+       const char *host = "0.0.0.0";
+       if (argc >= 2)
+               G.flags = getopt32(argv, FLAGS_ARG, &host);
+
+       G.ifs = 5;
+       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);
+               xprt = svcudp_create(sock);
+               if (xprt == (SVCXPRT *)NULL)
+                       bb_error_msg_and_die("cannot start portmap");
+               pmapproc_set(&pm);
+               if (svc_register(xprt, PMAPPROG, PMAPVERS, pmapproc, 0))
+                       G.pn++;
+
+               /* tcp listening */
+               sock = create_and_bind_stream_or_die(host, PMAPPORT);
+               xprt = svctcp_create(sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+               if (xprt == (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))
+                       G.pn++;
+       }
+
+       svc_run();
+
+       return EXIT_SUCCESS;
+}
-- 
1.7.4.rc1
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to