>>>>> 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;