snmptrapd_handlers.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:35k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. #include <net-snmp/net-snmp-config.h>
  2. #if HAVE_STDLIB_H
  3. #include <stdlib.h>
  4. #endif
  5. #if HAVE_UNISTD_H
  6. #include <unistd.h>
  7. #endif
  8. #include <stdio.h>
  9. #if HAVE_STRING_H
  10. #include <string.h>
  11. #else
  12. #include <strings.h>
  13. #endif
  14. #include <ctype.h>
  15. #include <sys/types.h>
  16. #if HAVE_WINSOCK_H
  17. #include <winsock.h>
  18. #else
  19. #include <netinet/in.h>
  20. #include <netdb.h>
  21. #endif
  22. #if HAVE_SYS_WAIT_H
  23. #include <sys/wait.h>
  24. #endif
  25. #include <net-snmp/config_api.h>
  26. #include <net-snmp/output_api.h>
  27. #include <net-snmp/mib_api.h>
  28. #include <net-snmp/utilities.h>
  29. #include <net-snmp/net-snmp-includes.h>
  30. #include <net-snmp/agent/net-snmp-agent-includes.h>
  31. #include "utilities/execute.h"
  32. #include "snmptrapd_handlers.h"
  33. #include "snmptrapd_log.h"
  34. char *syslog_format1 = NULL;
  35. char *syslog_format2 = NULL;
  36. char *print_format1  = NULL;
  37. char *print_format2  = NULL;
  38. const char     *trap1_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b] (via %A [%a]): %Nnt%W Trap (%q) Uptime: %#Tn%vn";
  39. const char     *trap2_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:n%vn";
  40. void snmptrapd_free_traphandle(void);
  41. const char *
  42. trap_description(int trap)
  43. {
  44.     switch (trap) {
  45.     case SNMP_TRAP_COLDSTART:
  46.         return "Cold Start";
  47.     case SNMP_TRAP_WARMSTART:
  48.         return "Warm Start";
  49.     case SNMP_TRAP_LINKDOWN:
  50.         return "Link Down";
  51.     case SNMP_TRAP_LINKUP:
  52.         return "Link Up";
  53.     case SNMP_TRAP_AUTHFAIL:
  54.         return "Authentication Failure";
  55.     case SNMP_TRAP_EGPNEIGHBORLOSS:
  56.         return "EGP Neighbor Loss";
  57.     case SNMP_TRAP_ENTERPRISESPECIFIC:
  58.         return "Enterprise Specific";
  59.     default:
  60.         return "Unknown Type";
  61.     }
  62. }
  63. void
  64. snmptrapd_parse_traphandle(const char *token, char *line)
  65. {
  66.     char            buf[STRINGMAX];
  67.     oid             obuf[MAX_OID_LEN];
  68.     size_t          olen = MAX_OID_LEN;
  69.     char           *cptr;
  70.     netsnmp_trapd_handler *traph;
  71.     cptr = copy_nword(line, buf, sizeof(buf));
  72.     DEBUGMSGTL(("read_config:traphandle", "registering handler for: "));
  73.     if (!strcmp(buf, "default")) {
  74.         DEBUGMSG(("read_config:traphandle", "default"));
  75.         traph = netsnmp_add_default_traphandler( command_handler );
  76.     } else {
  77.         if (!read_objid(buf, obuf, &olen)) {
  78.             char            buf1[STRINGMAX];
  79.             snprintf(buf1,  sizeof(buf1),
  80.                     "Bad trap OID in traphandle directive: %s", buf);
  81.             buf1[ sizeof(buf1)-1 ] = 0;
  82.             config_perror(buf1);
  83.             return;
  84.         }
  85.         DEBUGMSGOID(("read_config:traphandle", obuf, olen));
  86.         traph = netsnmp_add_traphandler( command_handler, obuf, olen );
  87.     }
  88.     DEBUGMSG(("read_config:traphandle", "n"));
  89.     if (traph) {
  90.         traph->token = strdup(cptr);
  91.     }
  92. }
  93. static void
  94. parse_forward(const char *token, char *line)
  95. {
  96.     char            buf[STRINGMAX];
  97.     oid             obuf[MAX_OID_LEN];
  98.     size_t          olen = MAX_OID_LEN;
  99.     char           *cptr;
  100.     netsnmp_trapd_handler *traph;
  101.     cptr = copy_nword(line, buf, sizeof(buf));
  102.     DEBUGMSGTL(("read_config:forward", "registering forward for: "));
  103.     if (!strcmp(buf, "default")) {
  104.         DEBUGMSG(("read_config:forward", "default"));
  105.         traph = netsnmp_add_default_traphandler( forward_handler );
  106.     } else {
  107.         if (!read_objid(buf, obuf, &olen)) {
  108.             char            buf1[STRINGMAX];
  109.             snprintf(buf1,  sizeof(buf1),
  110.                     "Bad trap OID in forward directive: %s", buf);
  111.             buf1[ sizeof(buf1)-1 ] = 0;
  112.             config_perror(buf1);
  113.             return;
  114.         }
  115.         DEBUGMSGOID(("read_config:forward", obuf, olen));
  116.         traph = netsnmp_add_traphandler( forward_handler, obuf, olen );
  117.     }
  118.     DEBUGMSG(("read_config:forward", "n"));
  119.     if (traph) {
  120.         traph->token = strdup(cptr);
  121.     }
  122. }
  123. static void
  124. parse_format(const char *token, char *line)
  125. {
  126.     char *cp;
  127.     /*
  128.      * Extract the first token from the value
  129.      * which tells us which style of format this is
  130.      */
  131.     cp = line;
  132.     while (*cp && !isspace(*cp))
  133.         cp++;
  134.     if (!(*cp)) {
  135.         /*
  136.  * If we haven't got anything left,
  137.  * then this entry is malformed.
  138.  * So report this, and give up
  139.  */
  140.         return;
  141.     }
  142.     *cp = '';
  143.     cp++;
  144.     /*
  145.      * OK - now "line" contains the format type,
  146.      *      and cp points to the actual format string.
  147.      * So update the appropriate pointer(s).
  148.      *
  149.      * XXX - the previous values really need to be freed too
  150.      */
  151.     if (!strcmp( line, "print1"))
  152.         print_format1 = strdup(cp);
  153.     else if (!strcmp( line, "print2"))
  154.         print_format2 = strdup(cp);
  155.     else if (!strcmp( line, "print")) {
  156.         print_format1 = strdup(cp);
  157.         print_format2 = strdup(cp);
  158.     } else if (!strcmp( line, "syslog1"))
  159.         syslog_format1 = strdup(cp);
  160.     else if (!strcmp( line, "syslog2"))
  161.         syslog_format2 = strdup(cp);
  162.     else if (!strcmp( line, "syslog")) {
  163.         syslog_format1 = strdup(cp);
  164.         syslog_format2 = strdup(cp);
  165.     }
  166. }
  167. static void
  168. parse_trap1_fmt(const char *token, char *line)
  169. {
  170.     print_format1 = strdup(line);
  171. }
  172. void
  173. free_trap1_fmt(void)
  174. {
  175.     if (print_format1 && print_format1 != trap1_std_str)
  176.         free((char *) print_format1);
  177.     print_format1 = NULL;
  178. }
  179. static void
  180. parse_trap2_fmt(const char *token, char *line)
  181. {
  182.     print_format2 = strdup(line);
  183. }
  184. void
  185. free_trap2_fmt(void)
  186. {
  187.     if (print_format2 && print_format2 != trap2_std_str)
  188.         free((char *) print_format2);
  189.     print_format2 = NULL;
  190. }
  191. void
  192. snmptrapd_register_configs( void )
  193. {
  194.     register_config_handler("snmptrapd", "traphandle",
  195.                             snmptrapd_parse_traphandle,
  196.                             snmptrapd_free_traphandle,
  197.                             "oid|"default" program [args ...] ");
  198.     register_config_handler("snmptrapd", "format1",
  199.                             parse_trap1_fmt, free_trap1_fmt, "format");
  200.     register_config_handler("snmptrapd", "format2",
  201.                             parse_trap2_fmt, free_trap2_fmt, "format");
  202.     register_config_handler("snmptrapd", "format",
  203.                             parse_format, NULL,
  204.     "[print{,1,2}|syslog{,1,2}] format");
  205.     register_config_handler("snmptrapd", "forward",
  206.                             parse_forward, NULL, "OID|"default" destination");
  207. }
  208. /*-----------------------------
  209.  *
  210.  * Routines to implement a "registry" of trap handlers
  211.  *
  212.  *-----------------------------*/
  213. netsnmp_trapd_handler *netsnmp_auth_global_traphandlers   = NULL;
  214. netsnmp_trapd_handler *netsnmp_pre_global_traphandlers    = NULL;
  215. netsnmp_trapd_handler *netsnmp_post_global_traphandlers   = NULL;
  216. netsnmp_trapd_handler *netsnmp_default_traphandlers  = NULL;
  217. netsnmp_trapd_handler *netsnmp_specific_traphandlers = NULL;
  218. /*
  219.  * Register a new "global" traphandler,
  220.  * to be applied to *all* incoming traps
  221.  */
  222. netsnmp_trapd_handler *
  223. netsnmp_add_global_traphandler(int list, Netsnmp_Trap_Handler handler) {
  224.     netsnmp_trapd_handler *traph;
  225.     if ( !handler )
  226.         return NULL;
  227.     traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler);
  228.     if ( !traph )
  229.         return NULL;
  230.     /*
  231.      * Add this new handler to the front of the appropriate global list
  232.      *   (or should it go on the end?)
  233.      */
  234.     traph->handler = handler;
  235.     switch (list) {
  236.     case NETSNMPTRAPD_AUTH_HANDLER:
  237.         traph->nexth   = netsnmp_auth_global_traphandlers;
  238.         netsnmp_auth_global_traphandlers = traph;
  239.         break;
  240.     case NETSNMPTRAPD_PRE_HANDLER:
  241.         traph->nexth   = netsnmp_pre_global_traphandlers;
  242.         netsnmp_pre_global_traphandlers = traph;
  243.         break;
  244.     case NETSNMPTRAPD_POST_HANDLER:
  245.         traph->nexth   = netsnmp_post_global_traphandlers;
  246.         netsnmp_post_global_traphandlers = traph;
  247.         break;
  248.     default:
  249.         free( traph );
  250.         return NULL;
  251.     }
  252.     return traph;
  253. }
  254. /*
  255.  * Register a new "default" traphandler, to be applied to all
  256.  * traps with no specific trap handlers of their own.
  257.  */
  258. netsnmp_trapd_handler *
  259. netsnmp_add_default_traphandler( Netsnmp_Trap_Handler handler) {
  260.     netsnmp_trapd_handler *traph;
  261.     if ( !handler )
  262.         return NULL;
  263.     traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler);
  264.     if ( !traph )
  265.         return NULL;
  266.     /*
  267.      * Add this new handler to the front of the default list
  268.      *   (or should it go on the end?)
  269.      */
  270.     traph->handler = handler;
  271.     traph->nexth   = netsnmp_default_traphandlers;
  272.     netsnmp_default_traphandlers = traph;
  273.     return traph;
  274. }
  275. /*
  276.  * Register a new trap-specific traphandler
  277.  */
  278. netsnmp_trapd_handler *
  279. netsnmp_add_traphandler(Netsnmp_Trap_Handler handler,
  280.                         oid *trapOid, int trapOidLen ) {
  281.     netsnmp_trapd_handler *traph, *traph2;
  282.     if ( !handler )
  283.         return NULL;
  284.     traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler);
  285.     if ( !traph )
  286.         return NULL;
  287.     /*
  288.      * Populate this new handler with the trap information
  289.      *   (NB: the OID fields were not used in the default/global lists)
  290.      */
  291.     traph->handler     = handler;
  292.     traph->trapoid_len = trapOidLen;
  293.     memdup((u_char **)&(traph->trapoid), (u_char *)trapOid,
  294.     sizeof(oid) * trapOidLen);
  295.     /*
  296.      * Now try to find the appropriate place in the trap-specific
  297.      * list for this particular trap OID.  If there's a matching OID
  298.      * already, then find it.  Otherwise find the one that follows.
  299.      * If we run out of entried, the new one should be tacked onto the end.
  300.      */
  301.     for (traph2 = netsnmp_specific_traphandlers;
  302.          traph2; traph2 = traph2->nextt) {
  303.      /* XXX - check this! */
  304.         if (snmp_oid_compare(traph2->trapoid, traph2->trapoid_len,
  305.                              trapOid, trapOidLen) <= 0)
  306.     break;
  307.     }
  308.     if (traph2) {
  309.         /*
  310.          * OK - We've either got an exact match, or we've found the
  311.  *   entry *after* where the new one should go.
  312.          */
  313.         if (!snmp_oid_compare(traph->trapoid,  traph->trapoid_len,
  314.                               traph2->trapoid, traph2->trapoid_len)) {
  315.             /*
  316.              * Exact match, so find the end of the *handler* list
  317.              *   and tack on this new entry...
  318.              */
  319.             while (traph2->nexth)
  320.                 traph2 = traph2->nexth;
  321.             traph2->nexth = traph;
  322.             traph->nextt  = traph2->nextt;   /* Might as well... */
  323.             traph->prevt  = traph2->prevt;
  324.         } else {
  325.             /*
  326.              * .. or the following entry, so insert the new one before it.
  327.              */
  328.             traph->prevt  = traph2->prevt;
  329.             if (traph2->prevt)
  330.         traph2->prevt->nextt = traph;
  331.             else
  332.         netsnmp_specific_traphandlers = traph;
  333.             traph2->prevt = traph;
  334.             traph->nextt  = traph2;
  335.         }
  336.     } else {
  337.         /*
  338.          * If we've run out of entries without finding a suitable spot,
  339.  *   the new one should be tacked onto the end.....
  340.          */
  341. if (netsnmp_specific_traphandlers) {
  342.             traph2 = netsnmp_specific_traphandlers;
  343.             while (traph2->nextt)
  344.                 traph2 = traph2->nextt;
  345.             traph2->nextt = traph;
  346.             traph->prevt  = traph2;
  347. } else {
  348.             /*
  349.              * .... unless this is the very first entry, of course!
  350.              */
  351.             netsnmp_specific_traphandlers = traph;
  352.         }
  353.     }
  354.     return traph;
  355. }
  356. void
  357. snmptrapd_free_traphandle(void)
  358. {
  359.     netsnmp_trapd_handler *traph = NULL, *nextt = NULL, *nexth = NULL;
  360.     DEBUGMSGTL(("snmptrapd", "Freeing trap handler listsn"));
  361.     /*
  362.      * Free default trap handlers
  363.      */
  364.     traph = netsnmp_default_traphandlers;
  365.    /* loop over handlers */
  366.     while (traph) {
  367.        DEBUGMSG(("snmptrapd", "Freeing default trap handlern"));
  368. nexth = traph->nexth;
  369. SNMP_FREE(traph->token);
  370. SNMP_FREE(traph);
  371. traph = nexth;
  372.     }
  373.     netsnmp_default_traphandlers = NULL;
  374.     /* 
  375.      * Free specific trap handlers
  376.      */
  377.     traph = netsnmp_specific_traphandlers;
  378.     /* loop over traps */
  379.     while (traph) {
  380.         nextt = traph->nextt;
  381.         /* loop over handlers for this trap */
  382. while (traph) {
  383.     DEBUGMSG(("snmptrapd", "Freeing specific trap handlern"));
  384.     nexth = traph->nexth;
  385.     SNMP_FREE(traph->token);
  386.     SNMP_FREE(traph->trapoid);
  387.     SNMP_FREE(traph);
  388.     traph = nexth;
  389. }
  390. traph = nextt;
  391.     }
  392.     netsnmp_specific_traphandlers = NULL;
  393. }
  394. /*
  395.  * Locate the list of handlers for this particular Trap OID
  396.  * Returns NULL if there are no relevant traps
  397.  */
  398. netsnmp_trapd_handler *
  399. netsnmp_get_traphandler( oid *trapOid, int trapOidLen ) {
  400.     netsnmp_trapd_handler *traph;
  401.     
  402.     if (!trapOid || !trapOidLen)
  403.         return NULL;
  404.     /*
  405.      * Look for a matching OID, and return that list...
  406.      */
  407.     for (traph = netsnmp_specific_traphandlers;
  408.          traph; traph=traph->nextt ) {
  409.         if ( !snmp_oidtree_compare(traph->trapoid, traph->trapoid_len,
  410.                                    trapOid, trapOidLen)) {
  411.             DEBUGMSGTL(( "snmptrapd", "get_traphandler matched (%x)n", traph));
  412.     return traph;
  413. }
  414.     }
  415.     /*
  416.      * .... or failing that, return the "default" list (which may be NULL)
  417.      */
  418.     DEBUGMSGTL(( "snmptrapd", "get_traphandler default (%x)n",
  419.     netsnmp_default_traphandlers));
  420.     return netsnmp_default_traphandlers;
  421. }
  422. /*-----------------------------
  423.  *
  424.  * Standard traphandlers for the common requirements
  425.  *
  426.  *-----------------------------*/
  427. #define SYSLOG_V1_STANDARD_FORMAT      "%a: %W Trap (%q) Uptime: %#T%#vn"
  428. #define SYSLOG_V1_ENTERPRISE_FORMAT    "%a: %W Trap (%q) Uptime: %#T%#vn" /* XXX - (%q) become (.N) ??? */
  429. #define SYSLOG_V23_NOTIFICATION_FORMAT "%B [%b]: Trap %#vn"      /* XXX - introduces a leading " ," */
  430. /*
  431.  *  Trap handler for logging via syslog
  432.  */
  433. int   syslog_handler(  netsnmp_pdu           *pdu,
  434.                        netsnmp_transport     *transport,
  435.                        netsnmp_trapd_handler *handler)
  436. {
  437.     u_char         *rbuf = NULL;
  438.     size_t          r_len = 64, o_len = 0;
  439.     int             trunc = 0;
  440.     extern int      SyslogTrap;
  441.     DEBUGMSGTL(( "snmptrapd", "syslog_handlern"));
  442.     if (SyslogTrap)
  443.         return NETSNMPTRAPD_HANDLER_OK;
  444.     if ((rbuf = (u_char *) calloc(r_len, 1)) == NULL) {
  445.         snmp_log(LOG_ERR, "couldn't display trap -- malloc failedn");
  446.         return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
  447.     }
  448.     /*
  449.      *  If there's a format string registered for this trap, then use it.
  450.      */
  451.     if (handler && handler->format) {
  452.         DEBUGMSGTL(( "snmptrapd", "format = '%s'n", handler->format));
  453.         if (*handler->format) {
  454.             trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  455.                                      handler->format, pdu, transport);
  456.         } else {
  457.             free(rbuf);
  458.             return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
  459.         }
  460.     /*
  461.      *  Otherwise (i.e. a NULL handler format string),
  462.      *      use a standard output format setting
  463.      *      either configurable, or hardwired
  464.      *
  465.      *  XXX - v1 traps use a different hardwired formats for
  466.      *        standard and enterprise specific traps
  467.      *        Do we actually need this?
  468.      */
  469.     } else {
  470. if ( pdu->command == SNMP_MSG_TRAP ) {
  471.             if (syslog_format1) {
  472.                 DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'n", syslog_format1));
  473.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  474.                                              syslog_format1, pdu, transport);
  475.     } else if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
  476.                 DEBUGMSGTL(( "snmptrapd", "v1 enterprise formatn"));
  477.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  478.                                              SYSLOG_V1_ENTERPRISE_FORMAT,
  479.                                              pdu, transport);
  480.     } else {
  481.                 DEBUGMSGTL(( "snmptrapd", "v1 standard trap formatn"));
  482.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  483.                                              SYSLOG_V1_STANDARD_FORMAT,
  484.                                              pdu, transport);
  485.     }
  486. } else { /* SNMPv2/3 notifications */
  487.             if (syslog_format2) {
  488.                 DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'n", syslog_format2));
  489.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  490.                                              syslog_format2, pdu, transport);
  491.     } else {
  492.                 DEBUGMSGTL(( "snmptrapd", "v2/3 formatn"));
  493.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  494.                                              SYSLOG_V23_NOTIFICATION_FORMAT,
  495.                                              pdu, transport);
  496.     }
  497.         }
  498.     }
  499.     snmp_log(LOG_WARNING, "%s%s", rbuf, (trunc?" [TRUNCATED]n":""));
  500.     free(rbuf);
  501.     return NETSNMPTRAPD_HANDLER_OK;
  502. }
  503. #define PRINT_V23_NOTIFICATION_FORMAT "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:n%vn"
  504. /*
  505.  *  Trap handler for logging to a file
  506.  */
  507. int   print_handler(   netsnmp_pdu           *pdu,
  508.                        netsnmp_transport     *transport,
  509.                        netsnmp_trapd_handler *handler)
  510. {
  511.     u_char         *rbuf = NULL;
  512.     size_t          r_len = 64, o_len = 0;
  513.     int             trunc = 0;
  514.     extern int      dropauth;
  515.     DEBUGMSGTL(( "snmptrapd", "print_handlern"));
  516.     /*
  517.      *  Don't bother logging authentication failures
  518.      *  XXX - can we handle this via suitable handler entries instead?
  519.      */
  520.     if (pdu->trap_type == SNMP_TRAP_AUTHFAIL && dropauth)
  521.         return NETSNMPTRAPD_HANDLER_OK;
  522.     if ((rbuf = (u_char *) calloc(r_len, 1)) == NULL) {
  523.         snmp_log(LOG_ERR, "couldn't display trap -- malloc failedn");
  524.         return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
  525.     }
  526.     /*
  527.      *  If there's a format string registered for this trap, then use it.
  528.      */
  529.     if (handler && handler->format) {
  530.         DEBUGMSGTL(( "snmptrapd", "format = '%s'n", handler->format));
  531.         if (*handler->format) {
  532.             trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  533.                                      handler->format, pdu, transport);
  534.         } else {
  535.             free(rbuf);
  536.             return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
  537.         }
  538.     /*
  539.      *  Otherwise (i.e. a NULL handler format string),
  540.      *      use a standard output format setting
  541.      *      either configurable, or hardwired
  542.      *
  543.      *  XXX - v1 traps use a different routine for hardwired output
  544.      *        Do we actually need this separate v1 routine?
  545.      *        Or would a suitable format string be sufficient?
  546.      */
  547.     } else {
  548. if ( pdu->command == SNMP_MSG_TRAP ) {
  549.             if (print_format1) {
  550.                 DEBUGMSGTL(( "snmptrapd", "print_format v1 = '%s'n", print_format1));
  551.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  552.                                              print_format1, pdu, transport);
  553.     } else {
  554.                 DEBUGMSGTL(( "snmptrapd", "v1 formatn"));
  555.                 trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len, 1,
  556.                                                    pdu, transport);
  557.     }
  558. } else {
  559.             if (print_format2) {
  560.                 DEBUGMSGTL(( "snmptrapd", "print_format v2 = '%s'n", print_format2));
  561.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  562.                                              print_format2, pdu, transport);
  563.     } else {
  564.                 DEBUGMSGTL(( "snmptrapd", "v2/3 formatn"));
  565.                 trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  566.                                              PRINT_V23_NOTIFICATION_FORMAT,
  567.                                              pdu, transport);
  568.     }
  569.         }
  570.     }
  571.     snmp_log(LOG_INFO, "%s%s", rbuf, (trunc?" [TRUNCATED]n":""));
  572.     free(rbuf);
  573.     return NETSNMPTRAPD_HANDLER_OK;
  574. }
  575. /*
  576.  *  Trap handler for invoking a suitable script
  577.  */
  578. void
  579. send_handler_data(FILE * file, struct hostent *host,
  580.                   netsnmp_pdu *pdu, netsnmp_transport *transport)
  581. {
  582.     netsnmp_variable_list tmpvar, *vars;
  583.     static oid      trapoids[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5, 0 };
  584.     static oid      snmpsysuptime[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
  585.     static oid      snmptrapoid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
  586.     static oid      snmptrapent[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 3, 0 };
  587.     static oid      snmptrapaddr[] = { 1, 3, 6, 1, 6, 3, 18, 1, 3, 0 };
  588.     static oid      snmptrapcom[] = { 1, 3, 6, 1, 6, 3, 18, 1, 4, 0 };
  589.     oid             enttrapoid[MAX_OID_LEN];
  590.     int             enttraplen = pdu->enterprise_length;
  591.     if (transport != NULL && transport->f_fmtaddr != NULL) {
  592.         char *tstr = transport->f_fmtaddr(transport, pdu->transport_data,
  593.                                           pdu->transport_data_length);
  594.         if (tstr != NULL) {
  595.             fprintf(file, "%sn%sn", host ? host->h_name : tstr, tstr);
  596.             free(tstr);
  597.         }
  598.     } else {
  599.         fprintf(file, "%sn<UNKNOWN>n", host ? host->h_name : "<UNKNOWN>");
  600.     }
  601.     if (pdu->command == SNMP_MSG_TRAP) {
  602.         /*
  603.          * convert a v1 trap to a v2 variable binding list:
  604.          * The uptime and trapOID go first in the list. 
  605.          */
  606.         tmpvar.val.integer = (long *) &pdu->time;
  607.         tmpvar.val_len = sizeof(pdu->time);
  608.         tmpvar.type = ASN_TIMETICKS;
  609.         fprint_variable(file, snmpsysuptime,
  610.                         sizeof(snmpsysuptime) / sizeof(oid), &tmpvar);
  611.         tmpvar.type = ASN_OBJECT_ID;
  612.         if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
  613.             memcpy(enttrapoid, pdu->enterprise, sizeof(oid) * enttraplen);
  614.             if (enttrapoid[enttraplen - 1] != 0)
  615.                 enttrapoid[enttraplen++] = 0;
  616.             enttrapoid[enttraplen++] = pdu->specific_type;
  617.             tmpvar.val.objid = enttrapoid;
  618.             tmpvar.val_len = enttraplen * sizeof(oid);
  619.         } else {
  620.             trapoids[9] = pdu->trap_type + 1;
  621.             tmpvar.val.objid = trapoids;
  622.             tmpvar.val_len = 10 * sizeof(oid);
  623.         }
  624.         fprint_variable(file, snmptrapoid,
  625.                         sizeof(snmptrapoid) / sizeof(oid), &tmpvar);
  626.     }
  627.     /*
  628.      * do the variables in the pdu 
  629.      */
  630.     for (vars = pdu->variables; vars; vars = vars->next_variable) {
  631.         fprint_variable(file, vars->name, vars->name_length, vars);
  632.     }
  633.     if (pdu->command == SNMP_MSG_TRAP) {
  634.         /*
  635.          * convert a v1 trap to a v2 variable binding list:
  636.          * The enterprise goes last. 
  637.          */
  638.         tmpvar.val.string = pdu->agent_addr;
  639.         tmpvar.val_len = 4;
  640.         tmpvar.type = ASN_IPADDRESS;
  641.         fprint_variable(file, snmptrapaddr,
  642.                         sizeof(snmptrapaddr) / sizeof(oid), &tmpvar);
  643.         tmpvar.val.string = pdu->community;
  644.         tmpvar.val_len = pdu->community_len;
  645.         tmpvar.type = ASN_OCTET_STR;
  646.         fprint_variable(file, snmptrapcom,
  647.                         sizeof(snmptrapcom) / sizeof(oid), &tmpvar);
  648.         tmpvar.val.objid = pdu->enterprise;
  649.         tmpvar.val_len = pdu->enterprise_length * sizeof(oid);
  650.         tmpvar.type = ASN_OBJECT_ID;
  651.         fprint_variable(file, snmptrapent,
  652.                         sizeof(snmptrapent) / sizeof(oid), &tmpvar);
  653.     }
  654. }
  655. void
  656. do_external(char *cmd, struct hostent *host,
  657.             netsnmp_pdu *pdu, netsnmp_transport *transport)
  658. {
  659.     FILE           *file;
  660.     int             oldquick, result;
  661.     DEBUGMSGTL(("snmptrapd", "Running: %sn", cmd));
  662.     oldquick = snmp_get_quick_print();
  663.     snmp_set_quick_print(1);
  664.     if (cmd) {
  665. #ifndef WIN32
  666.         int             fd[2];
  667.         int             pid;
  668.         if (pipe(fd)) {
  669.             snmp_log_perror("pipe");
  670.         }
  671.         if ((pid = fork()) == 0) {
  672.             /*
  673.              * child 
  674.              */
  675.             close(0);
  676.             if (dup(fd[0]) != 0) {
  677.                 snmp_log_perror("dup");
  678.             }
  679.             close(fd[1]);
  680.             close(fd[0]);
  681.             system(cmd);
  682.             exit(0);
  683.         } else if (pid > 0) {
  684.             file = fdopen(fd[1], "w");
  685.             send_handler_data(file, host, pdu, transport);
  686.             fclose(file);
  687.             close(fd[0]);
  688.             close(fd[1]);
  689.             if (waitpid(pid, &result, 0) < 0) {
  690.                 snmp_log_perror("waitpid");
  691.             }
  692.         } else {
  693.             snmp_log_perror("fork");
  694.         }
  695. #else
  696.         char            command_buf[128];
  697.         char            file_buf[L_tmpnam];
  698.         tmpnam(file_buf);
  699.         file = fopen(file_buf, "w");
  700.         if (!file) {
  701.             fprintf(stderr, "fopen: %s: %sn", file_buf, strerror(errno));
  702.         } else {
  703.             send_handler_data(file, host, pdu, transport);
  704.             fclose(file);
  705.             snprintf(command_buf, sizeof(command_buf),
  706.                      "%s < %s", cmd, file_buf);
  707.             command_buf[ sizeof(command_buf)-1 ] = 0;
  708.             result = system(command_buf);
  709.             if (result == -1)
  710.                 fprintf(stderr, "system: %s: %sn", command_buf,
  711.                         strerror(errno));
  712.             else if (result)
  713.                 fprintf(stderr, "system: %s: %dn", command_buf, result);
  714.             remove(file_buf);
  715.         }
  716. #endif                          /* WIN32 */
  717.     }
  718.     snmp_set_quick_print(oldquick);
  719. }
  720. #define EXECUTE_FORMAT "%Bn%bn%Vn%vn"
  721. int   command_handler( netsnmp_pdu           *pdu,
  722.                        netsnmp_transport     *transport,
  723.                        netsnmp_trapd_handler *handler)
  724. {
  725.     u_char         *rbuf = NULL;
  726.     size_t          r_len = 64, o_len = 0;
  727.     int             oldquick;
  728.     DEBUGMSGTL(( "snmptrapd", "command_handlern"));
  729.     DEBUGMSGTL(( "snmptrapd", "token = '%s'n", handler->token));
  730.     if (handler && handler->token && *handler->token) {
  731. netsnmp_pdu    *v2_pdu = NULL;
  732. if (pdu->command == SNMP_MSG_TRAP)
  733.     v2_pdu = convert_v1pdu_to_v2(pdu);
  734. else
  735.     v2_pdu = pdu;
  736.         oldquick = snmp_get_quick_print();
  737.         snmp_set_quick_print(1);
  738.         /*
  739.  * Format the trap and pass this string to the external command
  740.  */
  741.         if ((rbuf = (u_char *) calloc(r_len, 1)) == NULL) {
  742.             snmp_log(LOG_ERR, "couldn't display trap -- malloc failedn");
  743.             return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
  744.         }
  745.         /*
  746.          *  If there's a format string registered for this trap, then use it.
  747.          *  Otherwise use the standard execution format setting.
  748.          */
  749.         if (handler && handler->format && *handler->format) {
  750.             DEBUGMSGTL(( "snmptrapd", "format = '%s'n", handler->format));
  751.             realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  752.                                              handler->format,
  753.                                              v2_pdu, transport);
  754.         } else {
  755.             DEBUGMSGTL(( "snmptrapd", "execute formatn"));
  756.             realloc_format_trap(&rbuf, &r_len, &o_len, 1,
  757.                                              EXECUTE_FORMAT,
  758.                                              v2_pdu, transport);
  759. }
  760.         /*
  761.          *  and pass this formatted string to the command specified
  762.          */
  763.         run_shell_command(handler->token, rbuf, NULL, 0);   /* Not interested in output */
  764.         snmp_set_quick_print(oldquick);
  765.         if (pdu->command == SNMP_MSG_TRAP)
  766.             snmp_free_pdu(v2_pdu);
  767.         free(rbuf);
  768.     }
  769.     return NETSNMPTRAPD_HANDLER_OK;
  770. }
  771. /*
  772.  *  Trap handler for doing something with "event" traps
  773.  *      (not entirely clear what this is about ???)
  774.  */
  775. /* XXX - in snmptrapd.c */
  776. void event_input(netsnmp_variable_list * vp);
  777. int   event_handler( netsnmp_pdu           *pdu,
  778.                      netsnmp_transport     *transport,
  779.                      netsnmp_trapd_handler *handler)
  780. {
  781.     DEBUGMSGTL(( "snmptrapd", "event_handlern"));
  782.     event_input(pdu->variables);
  783.     return NETSNMPTRAPD_HANDLER_OK;
  784. }
  785. /*
  786.  *  Trap handler for forwarding to another destination
  787.  */
  788. int   forward_handler( netsnmp_pdu           *pdu,
  789.                        netsnmp_transport     *transport,
  790.                        netsnmp_trapd_handler *handler)
  791. {
  792.     netsnmp_session session, *ss;
  793.     netsnmp_pdu *pdu2;
  794.     char buf[BUFSIZ], *cp;
  795.     DEBUGMSGTL(( "snmptrapd", "forward_handler (%s)n", handler->token));
  796.     snmp_sess_init( &session );
  797.     if (strchr( handler->token, ':') == NULL) {
  798.         snprintf( buf, BUFSIZ, "%s:%d", handler->token, SNMP_TRAP_PORT);
  799.         cp = buf;
  800.     } else {
  801.         cp = handler->token;
  802.     }
  803.     session.peername = cp;
  804.     session.version  = pdu->version;
  805.     ss = snmp_open( &session );
  806.     pdu2 = snmp_clone_pdu(pdu);
  807.     if (pdu2->transport_data) {
  808.         free(pdu2->transport_data);
  809.         pdu2->transport_data        = NULL;
  810.         pdu2->transport_data_length = 0;
  811.     }
  812.     if (!snmp_send( ss, pdu2 )) {
  813. snmp_sess_perror("Forward failed", ss);
  814. snmp_free_pdu(pdu2);
  815.     }
  816.     snmp_close( ss );
  817.     return NETSNMPTRAPD_HANDLER_OK;
  818. }
  819. /*-----------------------------
  820.  *
  821.  * Main driving code, to process an incoming trap
  822.  *
  823.  *-----------------------------*/
  824. int
  825. snmp_input(int op, netsnmp_session *session,
  826.            int reqid, netsnmp_pdu *pdu, void *magic)
  827. {
  828.     oid stdTrapOidRoot[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
  829.     oid snmpTrapOid[]    = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
  830.     oid trapOid[MAX_OID_LEN+2] = {0};
  831.     int trapOidLen;
  832.     netsnmp_variable_list *vars;
  833.     netsnmp_trapd_handler *traph;
  834.     netsnmp_transport *transport = (netsnmp_transport *) magic;
  835.     int ret;
  836.     extern netsnmp_trapd_handler *netsnmp_auth_global_traphandlers;
  837.     extern netsnmp_trapd_handler *netsnmp_pre_global_traphandlers;
  838.     extern netsnmp_trapd_handler *netsnmp_post_global_traphandlers;
  839.     switch (op) {
  840.     case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
  841.         /*
  842.          * Drops packets with reception problems
  843.          */
  844.         if (session->s_snmp_errno) {
  845.             /* drop problem packets */
  846.             return 1;
  847.         }
  848.         /*
  849.  * Determine the OID that identifies the trap being handled
  850.  */
  851.         DEBUGMSGTL(("snmptrapd", "input: %xn", pdu->command));
  852.         switch (pdu->command) {
  853.         case SNMP_MSG_TRAP:
  854.             /*
  855.      * Convert v1 traps into a v2-style trap OID
  856.      *    (following RFC 2576)
  857.      */
  858.             if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
  859.                 trapOidLen = pdu->enterprise_length;
  860.                 memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen);
  861.                 if (trapOid[trapOidLen - 1] != 0) {
  862.                     trapOid[trapOidLen++] = 0;
  863.                 }
  864.                 trapOid[trapOidLen++] = pdu->specific_type;
  865.             } else {
  866.                 memcpy(trapOid, stdTrapOidRoot, sizeof(stdTrapOidRoot));
  867.                 trapOidLen = OID_LENGTH(stdTrapOidRoot);  /* 9 */
  868.                 trapOid[trapOidLen++] = pdu->trap_type+1;
  869.             }
  870.             break;
  871.         case SNMP_MSG_TRAP2:
  872.         case SNMP_MSG_INFORM:
  873.             /*
  874.      * v2c/v3 notifications *should* have snmpTrapOID as the
  875.      *    second varbind, so we can go straight there.
  876.      *    But check, just to make sure
  877.      */
  878.             vars = pdu->variables;
  879.             if (vars)
  880.                 vars = vars->next_variable;
  881.             if (!vars || snmp_oid_compare(vars->name, vars->name_length,
  882.                                           snmpTrapOid, OID_LENGTH(snmpTrapOid))) {
  883.         /*
  884.  * Didn't find it!
  885.  * Let's look through the full list....
  886.  */
  887. for ( vars = pdu->variables; vars; vars=vars->next_variable) {
  888.                     if (!snmp_oid_compare(vars->name, vars->name_length,
  889.                                           snmpTrapOid, OID_LENGTH(snmpTrapOid)))
  890.                         break;
  891.                 }
  892.                 if (!vars) {
  893.             /*
  894.      * Still can't find it!  Give up.
  895.      */
  896.     snmp_log(LOG_ERR, "Cannot find TrapOID in TRAP2 PDUn");
  897.     return 1; /* ??? */
  898. }
  899.     }
  900.             memcpy(trapOid, vars->val.objid, vars->val_len);
  901.             trapOidLen = vars->val_len /sizeof(oid);
  902.             break;
  903.         default:
  904.             /* SHOULDN'T HAPPEN! */
  905.             return 1; /* ??? */
  906. }
  907.         DEBUGMSGTL(( "snmptrapd", "Trap OID: "));
  908.         DEBUGMSGOID(("snmptrapd", trapOid, trapOidLen));
  909.         DEBUGMSG(( "snmptrapd", "n"));
  910.         /*
  911.  *  OK - We've found the Trap OID used to identify this trap.
  912.          *  Call each of the various lists of handlers:
  913.          *     a) authentication-related handlers,
  914.          *     b) other handlers to be applied to all traps
  915.          * (*before* trap-specific handlers)
  916.          *     c) the handler(s) specific to this trap
  917. t        *     d) any other global handlers
  918.          *
  919.  *  In each case, a particular trap handler can abort further
  920.          *     processing - either just for that particular list,
  921.          *     or for the trap completely.
  922.          *
  923.  *  This is particularly designed for authentication-related
  924.  *     handlers, but can also be used elsewhere.
  925.          *
  926.          *  OK - Enough waffling, let's get to work.....
  927.  */
  928.         /*
  929.  *  a) authentication handlers
  930.  */
  931.         traph = netsnmp_auth_global_traphandlers;
  932. while (traph) {
  933.     ret = (*(traph->handler))(pdu, transport, traph);
  934.             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
  935.                 return 1;
  936.             if (ret == NETSNMPTRAPD_HANDLER_BREAK)
  937.                 break;
  938.     traph = traph->nexth;
  939. }
  940.         /*
  941.  *  b) pre-specific global handlers
  942.  */
  943.         traph = netsnmp_pre_global_traphandlers;
  944. while (traph) {
  945.     ret = (*(traph->handler))(pdu, transport, traph);
  946.             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
  947.                 return 1;
  948.             if (ret == NETSNMPTRAPD_HANDLER_BREAK)
  949.                 break;
  950.     traph = traph->nexth;
  951. }
  952.         /*
  953.  *  c) trap-specific handlers
  954.  */
  955.         traph = netsnmp_get_traphandler(trapOid, trapOidLen);
  956. while (traph) {
  957.     ret = (*(traph->handler))(pdu, transport, traph);
  958.             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
  959.                 return 1;
  960.             if (ret == NETSNMPTRAPD_HANDLER_BREAK)
  961.                 break;
  962.     traph = traph->nexth;
  963. }
  964.         /*
  965.  *  d) other global handlers
  966.  */
  967.         traph = netsnmp_post_global_traphandlers;
  968. while (traph) {
  969.     ret = (*(traph->handler))(pdu, transport, traph);
  970.             if (ret == NETSNMPTRAPD_HANDLER_FINISH)
  971.                 return 1;
  972.             if (ret == NETSNMPTRAPD_HANDLER_BREAK)
  973.                 break;
  974.     traph = traph->nexth;
  975. }
  976. if (pdu->command == SNMP_MSG_INFORM) {
  977.     netsnmp_pdu *reply = snmp_clone_pdu(pdu);
  978.     if (!reply) {
  979. snmp_log(LOG_ERR, "couldn't clone PDU for INFORM responsen");
  980.     } else {
  981. reply->command = SNMP_MSG_RESPONSE;
  982. reply->errstat = 0;
  983. reply->errindex = 0;
  984. if (!snmp_send(session, reply)) {
  985.     snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
  986.                                     session);
  987.     snmp_free_pdu(reply);
  988. }
  989.     }
  990. }
  991.         break;
  992.     case NETSNMP_CALLBACK_OP_TIMED_OUT:
  993.         snmp_log(LOG_ERR, "Timeout: This shouldn't happen!n");
  994.         break;
  995.     default:
  996.         snmp_log(LOG_ERR, "Unknown operation (%d): This shouldn't happen!n", op);
  997.         break;
  998.     }
  999.     return 0;
  1000. }