>>>>> On Fri, 02 Sep 2005 16:25:04 -0700, Wes Hardaker <[EMAIL PROTECTED]> said:

Wes> /me wonders how much of the VACM code could be leveraged to apply
Wes> here...  Much of the requirements are actually similar.

/me puts his fingers where his mouth is.

I'd like to propose something like the following.  It works already
and I've successfully set up authorization such that I can say
"community xyz is only allowed to log" and "community abc is allowed
to execute", etc.  What's better is that it's not a lot of now code
because I'm completely reusing the VACM code base but in sort of a new
way.  My wife is telling me that I'm over-due for finishing working
for the day, which means I can't tinker with it more.  What I wanted
to do was change the user visibility more such that the tokens for
read/write/notify in the acm settings would be different for trapd
such that they'd say something like log/execute/network or something
like that.

In short summary, I'm overriding the access methods within the VACM
stuff so that read becomes "ability to log", and write becomes
"ability to execute" and notify becomes "ability to froward".  Each
trap handler is then forced to register which abilities it requires
permission for (IE, you can require multiple permissions).  Thus, the
forwarding handler gets the vacm 'notify' group.  The traphandle (and
eventually perl) will get the 'write' group.  And the logging handlers
(syslog, ...) get the 'read' group.  To the eventual user visibility,
this should be modified a bit, of course, so that documentation will
say "log" instead of "read"...

Patch attached to main line CVS code (this patches a file checked in a
few hours ago, btw)

To test, here's the most simple thing you can do in your
snmptrapd.conf file:

rocommunity xyz
rwcommunity abc
traphandle default /bin/cat

Then run snmptrapd and send a trap with community xyz and you'll see
it can log stuff, but the /bin/cat isn't executed.  send it with
community abc, however, and both logging and /bin/cat get done.

The nice thing about this is that suddenly we'd get the remote
configuration with it as well, if we registered the VACM tables
underneath the snmptrapd v3 context as we do for the usm table (and
notification logging tables if enabled).  All for very very little
code.

What this does *not* do, however, is make setting up v3 traps
simpler.  We should still work on that, and we should probably work on
wildcarding augmentation in the VACM as well.

What this does do is finally plug a security issue I've had nagging me
for way way too long.

Notes:
  1) by default traphandlers that don't change the defaults will
     require all three r/w/n permissions to be on.
  2) perl handler not changed yet
  3) I'll be out of serious contact till Wednesday most likely, but I
     promise not to commit this without listening to complaints first ;-)

-- 
Wes Hardaker
Sparta, Inc.
? .gdb.auto.prog
? Blah
? Perl_snmptrapd
? blah
? blah.h
? blah.ps
? dump.txt
? invoke
? log
? patch
? perl_snmptrapd.h
? snmpget-special
? snmpget-special.c
? snmptrapd_handlers.c.agentx
Index: Makefile.in
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/Makefile.in,v
retrieving revision 5.13
diff -u -p -r5.13 Makefile.in
--- Makefile.in	22 Jul 2005 01:47:04 -0000	5.13
+++ Makefile.in	3 Sep 2005 05:45:55 -0000
@@ -67,8 +67,10 @@ CPPFLAGS	= $(TOP_INCLUDES) -I. $(AGENT_I
 
 OSUFFIX		= lo
 TRAPD_OBJECTS   = snmptrapd.$(OSUFFIX) @other_trapd_objects@
-LIBTRAPD_OBJS   = snmptrapd_handlers.o  snmptrapd_log.o
-LLIBTRAPD_OBJS  = snmptrapd_handlers.lo snmptrapd_log.lo
+LIBTRAPD_OBJS   = snmptrapd_handlers.o  snmptrapd_log.o \
+		  snmptrapd_auth.o
+LLIBTRAPD_OBJS  = snmptrapd_handlers.lo snmptrapd_log.lo \
+		  snmptrapd_auth.lo
 OBJS  = *.o
 LOBJS = *.lo
 
Index: snmptrapd.c
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/snmptrapd.c,v
retrieving revision 5.56
diff -u -p -r5.56 snmptrapd.c
--- snmptrapd.c	23 Aug 2005 13:52:58 -0000	5.56
+++ snmptrapd.c	3 Sep 2005 05:45:56 -0000
@@ -95,6 +95,7 @@ SOFTWARE.
 #include <net-snmp/library/fd_event_manager.h>
 #include "snmptrapd_handlers.h"
 #include "snmptrapd_log.h"
+#include "snmptrapd_auth.h"
 #include "notification-log-mib/notification_log.h"
 
 /*
@@ -596,6 +597,7 @@ main(int argc, char *argv[])
 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(SNMPTRAPD_DISABLE_AGENTX)
     int             agentx_subagent = 1;
 #endif
+    netsnmp_trapd_handler *traph;
 
 #ifdef SIGTERM
     signal(SIGTERM, term_handler);
@@ -940,18 +942,27 @@ main(int argc, char *argv[])
      */
     if (!Log && !Print) {
         Syslog = 1;
-        netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler);
+        traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
+                                               syslog_handler);
+        traph->authtypes = TRAP_AUTH_LOG;
     } else {
-        netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler);
+        traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
+                                               print_handler);
+        traph->authtypes = TRAP_AUTH_LOG;
     }
 
     if (Event) {
-        netsnmp_add_traphandler(event_handler, risingAlarm,
-                                    OID_LENGTH(risingAlarm));
-        netsnmp_add_traphandler(event_handler, fallingAlarm,
-                                    OID_LENGTH(fallingAlarm));
-        netsnmp_add_traphandler(event_handler, unavailableAlarm,
-                                    OID_LENGTH(unavailableAlarm));
+        traph = netsnmp_add_traphandler(event_handler, risingAlarm,
+                                        OID_LENGTH(risingAlarm));
+        traph->authtypes = TRAP_AUTH_LOG;
+
+        traph = netsnmp_add_traphandler(event_handler, fallingAlarm,
+                                        OID_LENGTH(fallingAlarm));
+        traph->authtypes = TRAP_AUTH_LOG;
+
+        traph = netsnmp_add_traphandler(event_handler, unavailableAlarm,
+                                        OID_LENGTH(unavailableAlarm));
+        traph->authtypes = TRAP_AUTH_LOG;
 	/* XXX - might be worth setting some "magic data"
 	 * in the traphandler structure that 'event_handler'
 	 * can use to avoid checking the trap OID values.
@@ -1000,11 +1011,15 @@ main(int argc, char *argv[])
             netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
                               NETSNMP_DS_NOTIF_LOG_CTX,
                               "snmptrapd");
-            netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER,
-                                           notification_handler);
+            traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER,
+                                                   notification_handler);
+            traph->authtypes = TRAP_AUTH_LOG;
             init_notification_log();
         }
 #endif
+        /* register our authorization handler */
+        init_netsnmp_trapd_auth();
+
         /* register ourselves as having a USM user database */
         init_register_usmUser_context("snmptrapd");
     }
Index: snmptrapd_auth.c
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/snmptrapd_auth.c,v
retrieving revision 1.1
diff -u -p -r1.1 snmptrapd_auth.c
--- snmptrapd_auth.c	3 Sep 2005 00:33:37 -0000	1.1
+++ snmptrapd_auth.c	3 Sep 2005 05:45:56 -0000
@@ -15,22 +15,82 @@
 void
 init_netsnmp_trapd_auth(void)
 {
+    /* register our function as a authorization handler */
     netsnmp_trapd_handler *traph;
     traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_AUTH_HANDLER,
                                            netsnmp_trapd_auth);
+    traph->authtypes = TRAP_AUTH_NONE;
+
+    /* register our configuration tokens for VACM configs */
+    init_vacm_config_tokens();
 }
 
+/* XXX: store somewhere in the PDU instead */
+static int lastlookup;
 
 /**
- * authorizes incoming notifications for further processing
+ * Authorizes incoming notifications for further processing
  */
 int
 netsnmp_trapd_auth(netsnmp_pdu           *pdu,
                    netsnmp_transport     *transport,
                    netsnmp_trapd_handler *handler)
 {
+    int ret = 0;
+    oid name[] = {1,3,6,1,4,8072};
+    size_t namelen = 6;
+    int oldcommand;
+    int views[] = { SNMP_MSG_GET, SNMP_MSG_SET, SNMP_MSG_TRAP };
+    int i;
+
+    /* bail early if called illegally */
+    if (!pdu || !transport || !handler)
+        return NETSNMPTRAPD_HANDLER_FINISH;
+    
+    /* XXX: pull name from PDU TRAP OID */
+
+    /* here we hack the VACM data to check for different cases:
+       READ     =>  allowed to display the results   (eg log)
+       WRITE    =>  allowed to EXECUTE               (eg traphandle)
+       NOTIFY   =>  allowed to access NETWORK        (eg forward)
+    */
+    oldcommand = pdu->command; /* save original PDU command */
+    for(i = 0; i <= 2; i++) {
+        /* pass the PDU to the VACM routine for handling authorization */
+        DEBUGMSGTL(("snmptrapd:auth", "Calling VACM for checking phase %d\n",
+                    i));
+        pdu->command = views[i];
+        if (vacm_in_view(pdu, name, namelen, 0) == VACM_SUCCESS) {
+            DEBUGMSGTL(("snmptrapd:auth", "  result: authorized\n"));
+            ret |= 1 << i;
+        } else {
+            DEBUGMSGTL(("snmptrapd:auth", "  result: not authorized\n"));
+        }
+    }
+    pdu->command = oldcommand; /* restore original PDU command */
+
+    if (ret) {
+        /* we have policy to at least do "something".  Remember and continue. */
+        lastlookup = ret;
+        return NETSNMPTRAPD_HANDLER_OK;
+    }
 
     /* No policy was met, so we drop the PDU from further processing */
     DEBUGMSGTL(("snmptrapd:auth", "Dropping unauthorized message\n"));
     return NETSNMPTRAPD_HANDLER_FINISH;
 }
+
+/**
+ * Checks to see if the pdu is authorized for a set of given action types.
+ * @returns 1 if authorized, 0 if not.
+ */
+int
+netsnmp_trapd_check_auth(int authtypes, netsnmp_pdu *pdu)
+{
+    int i;
+    DEBUGMSGTL(("snmptrapd:auth",
+                "Comparing auth types: result=%d, request=%d, result=%d\n",
+                lastlookup, authtypes,
+                ((authtypes & lastlookup) == authtypes)));
+    return ((authtypes & lastlookup) == authtypes);
+}
Index: snmptrapd_auth.h
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/snmptrapd_auth.h,v
retrieving revision 1.1
diff -u -p -r1.1 snmptrapd_auth.h
--- snmptrapd_auth.h	3 Sep 2005 00:33:37 -0000	1.1
+++ snmptrapd_auth.h	3 Sep 2005 05:45:56 -0000
@@ -6,4 +6,11 @@ int netsnmp_trapd_auth(netsnmp_pdu *pdu,
                        netsnmp_trapd_handler *handler);
 
 
+#define TRAP_AUTH_LOG 1  /* displaying and logging */
+#define TRAP_AUTH_EXE 2  /* executing code or binaries */
+#define TRAP_AUTH_NET 4  /* forwarding and net access */
+
+#define TRAP_AUTH_ALL (TRAP_AUTH_LOG | TRAP_AUTH_EXE | TRAP_AUTH_NET)
+#define TRAP_AUTH_NONE 0
+
 #endif /* SNMPTRAPD_AUTH_H */
Index: snmptrapd_handlers.c
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/snmptrapd_handlers.c,v
retrieving revision 5.25
diff -u -p -r5.25 snmptrapd_handlers.c
--- snmptrapd_handlers.c	25 Jul 2005 19:55:58 -0000	5.25
+++ snmptrapd_handlers.c	3 Sep 2005 05:45:56 -0000
@@ -33,6 +33,7 @@
 #include <net-snmp/agent/net-snmp-agent-includes.h>
 #include "utilities/execute.h"
 #include "snmptrapd_handlers.h"
+#include "snmptrapd_auth.h"
 #include "snmptrapd_log.h"
 #include "notification-log-mib/notification_log.h"
 
@@ -102,6 +103,7 @@ snmptrapd_parse_traphandle(const char *t
     DEBUGMSG(("read_config:traphandle", "\n"));
 
     if (traph) {
+        traph->authtypes = TRAP_AUTH_EXE;
         traph->token = strdup(cptr);
     }
 }
@@ -138,6 +140,7 @@ parse_forward(const char *token, char *l
     DEBUGMSG(("read_config:forward", "\n"));
 
     if (traph) {
+        traph->authtypes = TRAP_AUTH_NET;
         traph->token = strdup(cptr);
     }
 }
@@ -276,6 +279,7 @@ netsnmp_add_global_traphandler(int list,
      *   (or should it go on the end?)
      */
     traph->handler = handler;
+    traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */
     switch (list) {
     case NETSNMPTRAPD_AUTH_HANDLER:
         traph->nexth   = netsnmp_auth_global_traphandlers;
@@ -316,6 +320,7 @@ netsnmp_add_default_traphandler( Netsnmp
      * Add this new handler to the front of the default list
      *   (or should it go on the end?)
      */
+    traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */
     traph->handler = handler;
     traph->nexth   = netsnmp_default_traphandlers;
     netsnmp_default_traphandlers = traph;
@@ -342,6 +347,7 @@ netsnmp_add_traphandler(Netsnmp_Trap_Han
      * Populate this new handler with the trap information
      *   (NB: the OID fields were not used in the default/global lists)
      */
+    traph->authtypes   = TRAP_AUTH_ALL; /* callers will likely change this */
     traph->handler     = handler;
     traph->trapoid_len = trapOidLen;
     memdup((u_char **)&(traph->trapoid), (u_char *)trapOid,
@@ -1052,7 +1058,12 @@ t        *     d) any other global handl
 	 *  a) authentication handlers
 	 */
         traph = netsnmp_auth_global_traphandlers;
+        DEBUGMSGTL(("snmptrapd", "Running auth trap handlers\n"));
 	while (traph) {
+            if (!netsnmp_trapd_check_auth(traph->authtypes, pdu)) {
+                traph = traph->nexth;
+                continue; /* we continue on and skip this one */
+            }
 	    ret = (*(traph->handler))(pdu, transport, traph);
             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
                 return 1;
@@ -1065,7 +1076,12 @@ t        *     d) any other global handl
 	 *  b) pre-specific global handlers
 	 */
         traph = netsnmp_pre_global_traphandlers;
+        DEBUGMSGTL(("snmptrapd", "Running pre-global trap handlers\n"));
 	while (traph) {
+            if (!netsnmp_trapd_check_auth(traph->authtypes, pdu)) {
+                traph = traph->nexth;
+                continue; /* we continue on and skip this one */
+            }
 	    ret = (*(traph->handler))(pdu, transport, traph);
             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
                 return 1;
@@ -1077,8 +1093,13 @@ t        *     d) any other global handl
         /*
 	 *  c) trap-specific handlers
 	 */
+        DEBUGMSGTL(("snmptrapd", "Running trap specific handlers\n"));
         traph = netsnmp_get_traphandler(trapOid, trapOidLen);
 	while (traph) {
+            if (!netsnmp_trapd_check_auth(traph->authtypes, pdu)) {
+                traph = traph->nexth;
+                continue; /* we continue on and skip this one */
+            }
 	    ret = (*(traph->handler))(pdu, transport, traph);
             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
                 return 1;
@@ -1090,8 +1111,13 @@ t        *     d) any other global handl
         /*
 	 *  d) other global handlers
 	 */
+        DEBUGMSGTL(("snmptrapd", "Running global handlers\n"));
         traph = netsnmp_post_global_traphandlers;
 	while (traph) {
+            if (!netsnmp_trapd_check_auth(traph->authtypes, pdu)) {
+                traph = traph->nexth;
+                continue; /* we continue on and skip this one */
+            }
 	    ret = (*(traph->handler))(pdu, transport, traph);
             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
                 return 1;
Index: snmptrapd_handlers.h
===================================================================
RCS file: /cvsroot/net-snmp/net-snmp/apps/snmptrapd_handlers.h,v
retrieving revision 5.6
diff -u -p -r5.6 snmptrapd_handlers.h
--- snmptrapd_handlers.h	22 Jul 2005 01:47:55 -0000	5.6
+++ snmptrapd_handlers.h	3 Sep 2005 05:45:56 -0000
@@ -14,6 +14,7 @@ struct netsnmp_trapd_handler_s {
      char *token;		/* Or an array of tokens? */
      char *format;		/* Formatting string */
      int   version;		/* ??? */
+     int   authtypes;
      Netsnmp_Trap_Handler *handler;
      void *handler_data;
 

Reply via email to