/src/net-snmp/apps/snmptrapd_handlers.c
Line | Count | Source |
1 | | #include <net-snmp/net-snmp-config.h> |
2 | | #include <net-snmp/net-snmp-features.h> |
3 | | |
4 | | #ifdef HAVE_STDLIB_H |
5 | | #include <stdlib.h> |
6 | | #endif |
7 | | #ifdef HAVE_UNISTD_H |
8 | | #include <unistd.h> |
9 | | #endif |
10 | | #include <stdio.h> |
11 | | #ifdef HAVE_STRING_H |
12 | | #include <string.h> |
13 | | #else |
14 | | #include <strings.h> |
15 | | #endif |
16 | | #include <ctype.h> |
17 | | #include <sys/types.h> |
18 | | #ifdef HAVE_ARPA_INET_H |
19 | | #include <arpa/inet.h> |
20 | | #endif |
21 | | #ifdef HAVE_NETINET_IN_H |
22 | | #include <netinet/in.h> |
23 | | #endif |
24 | | #ifdef HAVE_NETDB_H |
25 | | #include <netdb.h> |
26 | | #endif |
27 | | #ifdef HAVE_SYS_WAIT_H |
28 | | #include <sys/wait.h> |
29 | | #endif |
30 | | #ifdef HAVE_LIMITS_H |
31 | | #include <limits.h> |
32 | | #endif |
33 | | |
34 | | #include <net-snmp/config_api.h> |
35 | | #include <net-snmp/output_api.h> |
36 | | #include <net-snmp/mib_api.h> |
37 | | #include <net-snmp/utilities.h> |
38 | | |
39 | | #include <net-snmp/net-snmp-includes.h> |
40 | | #include <net-snmp/agent/net-snmp-agent-includes.h> |
41 | | #include "utilities/execute.h" |
42 | | #include "snmptrapd_handlers.h" |
43 | | #include "snmptrapd_auth.h" |
44 | | #include "snmptrapd_log.h" |
45 | | #include "notification-log-mib/notification_log.h" |
46 | | |
47 | | netsnmp_feature_child_of(add_default_traphandler, snmptrapd); |
48 | | |
49 | | char *syslog_format1 = NULL; |
50 | | char *syslog_format2 = NULL; |
51 | | char *print_format1 = NULL; |
52 | | char *print_format2 = NULL; |
53 | | char *exec_format1 = NULL; |
54 | | char *exec_format2 = NULL; |
55 | | |
56 | | int SyslogTrap = 0; |
57 | | int dropauth = 0; |
58 | | |
59 | | const char *trap1_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b] (via %A [%a]): %N\n\t%W Trap (%q) Uptime: %#T\n%v\n"; |
60 | | const char *trap2_std_str = "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n"; |
61 | | |
62 | | void snmptrapd_free_traphandle(void); |
63 | | |
64 | | const char * |
65 | | trap_description(int trap) |
66 | 0 | { |
67 | 0 | switch (trap) { |
68 | 0 | case SNMP_TRAP_COLDSTART: |
69 | 0 | return "Cold Start"; |
70 | 0 | case SNMP_TRAP_WARMSTART: |
71 | 0 | return "Warm Start"; |
72 | 0 | case SNMP_TRAP_LINKDOWN: |
73 | 0 | return "Link Down"; |
74 | 0 | case SNMP_TRAP_LINKUP: |
75 | 0 | return "Link Up"; |
76 | 0 | case SNMP_TRAP_AUTHFAIL: |
77 | 0 | return "Authentication Failure"; |
78 | 0 | case SNMP_TRAP_EGPNEIGHBORLOSS: |
79 | 0 | return "EGP Neighbor Loss"; |
80 | 0 | case SNMP_TRAP_ENTERPRISESPECIFIC: |
81 | 0 | return "Enterprise Specific"; |
82 | 0 | default: |
83 | 0 | return "Unknown Type"; |
84 | 0 | } |
85 | 0 | } |
86 | | |
87 | | |
88 | | |
89 | | void |
90 | | snmptrapd_parse_traphandle(const char *token, char *line) |
91 | 0 | { |
92 | 0 | char buf[STRINGMAX]; |
93 | 0 | oid obuf[MAX_OID_LEN]; |
94 | 0 | size_t olen = MAX_OID_LEN; |
95 | 0 | char *cptr, *cp; |
96 | 0 | netsnmp_trapd_handler *traph; |
97 | 0 | int flags = 0; |
98 | 0 | char *format = NULL; |
99 | |
|
100 | 0 | memset( buf, 0, sizeof(buf)); |
101 | 0 | memset(obuf, 0, sizeof(obuf)); |
102 | 0 | cptr = copy_nword(line, buf, sizeof(buf)); |
103 | |
|
104 | 0 | if ( buf[0] == '-' && buf[1] == 'F' ) { |
105 | 0 | cptr = copy_nword(cptr, buf, sizeof(buf)); |
106 | 0 | format = strdup( buf ); |
107 | 0 | cptr = copy_nword(cptr, buf, sizeof(buf)); |
108 | 0 | } |
109 | 0 | if ( !cptr ) { |
110 | 0 | netsnmp_config_error("Missing traphandle command (%s)", buf); |
111 | 0 | free(format); |
112 | 0 | return; |
113 | 0 | } |
114 | | |
115 | 0 | DEBUGMSGTL(("read_config:traphandle", "registering handler for: ")); |
116 | 0 | if (!strcmp(buf, "default")) { |
117 | 0 | DEBUGMSG(("read_config:traphandle", "default")); |
118 | 0 | traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER, |
119 | 0 | command_handler ); |
120 | 0 | } else { |
121 | 0 | cp = buf+strlen(buf)-1; |
122 | 0 | if ( *cp == '*' ) { |
123 | 0 | flags |= NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE; |
124 | 0 | *(cp--) = '\0'; |
125 | 0 | if ( *cp == '.' ) { |
126 | | /* |
127 | | * Distinguish between 'oid.*' & 'oid*' |
128 | | */ |
129 | 0 | flags |= NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE; |
130 | 0 | *(cp--) = '\0'; |
131 | 0 | } |
132 | 0 | } |
133 | 0 | if (!read_objid(buf, obuf, &olen)) { |
134 | 0 | netsnmp_config_error("Bad trap OID in traphandle directive: %s", |
135 | 0 | buf); |
136 | 0 | free(format); |
137 | 0 | return; |
138 | 0 | } |
139 | 0 | DEBUGMSGOID(("read_config:traphandle", obuf, olen)); |
140 | 0 | traph = netsnmp_add_traphandler( command_handler, obuf, olen ); |
141 | 0 | } |
142 | | |
143 | 0 | DEBUGMSG(("read_config:traphandle", "\n")); |
144 | |
|
145 | 0 | if (traph) { |
146 | 0 | traph->flags = flags; |
147 | 0 | traph->authtypes = TRAP_AUTH_EXE; |
148 | 0 | traph->token = strdup(cptr); |
149 | 0 | if (format) { |
150 | 0 | traph->format = format; |
151 | 0 | format = NULL; |
152 | 0 | } |
153 | 0 | } |
154 | 0 | free(format); |
155 | 0 | } |
156 | | |
157 | | |
158 | | static void |
159 | | parse_forward(const char *token, char *line) |
160 | 0 | { |
161 | 0 | char buf[STRINGMAX]; |
162 | 0 | oid obuf[MAX_OID_LEN]; |
163 | 0 | size_t olen = MAX_OID_LEN; |
164 | 0 | char *cptr, *cp; |
165 | 0 | netsnmp_trapd_handler *traph; |
166 | 0 | int flags = 0; |
167 | 0 | char *format = NULL; |
168 | |
|
169 | 0 | memset( buf, 0, sizeof(buf)); |
170 | 0 | memset(obuf, 0, sizeof(obuf)); |
171 | 0 | cptr = copy_nword(line, buf, sizeof(buf)); |
172 | |
|
173 | 0 | if ( buf[0] == '-' && buf[1] == 'F' ) { |
174 | 0 | cptr = copy_nword(cptr, buf, sizeof(buf)); |
175 | 0 | format = strdup( buf ); |
176 | 0 | cptr = copy_nword(cptr, buf, sizeof(buf)); |
177 | 0 | } |
178 | 0 | DEBUGMSGTL(("read_config:forward", "registering forward for: ")); |
179 | 0 | if (!strcmp(buf, "default")) { |
180 | 0 | DEBUGMSG(("read_config:forward", "default")); |
181 | 0 | if ( !strcmp( cptr, "agentx" )) |
182 | 0 | traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER, |
183 | 0 | axforward_handler ); |
184 | 0 | else |
185 | 0 | traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER, |
186 | 0 | forward_handler ); |
187 | 0 | } else { |
188 | 0 | cp = buf+strlen(buf)-1; |
189 | 0 | if ( *cp == '*' ) { |
190 | 0 | flags |= NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE; |
191 | 0 | *(cp--) = '\0'; |
192 | 0 | if ( *cp == '.' ) { |
193 | | /* |
194 | | * Distinguish between 'oid.*' & 'oid*' |
195 | | */ |
196 | 0 | flags |= NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE; |
197 | 0 | *(cp--) = '\0'; |
198 | 0 | } |
199 | 0 | } |
200 | |
|
201 | 0 | if (!read_objid(buf, obuf, &olen)) { |
202 | 0 | netsnmp_config_error("Bad trap OID in forward directive: %s", buf); |
203 | 0 | free(format); |
204 | 0 | return; |
205 | 0 | } |
206 | 0 | DEBUGMSGOID(("read_config:forward", obuf, olen)); |
207 | 0 | if ( !strcmp( cptr, "agentx" )) |
208 | 0 | traph = netsnmp_add_traphandler( axforward_handler, obuf, olen ); |
209 | 0 | else |
210 | 0 | traph = netsnmp_add_traphandler( forward_handler, obuf, olen ); |
211 | 0 | } |
212 | | |
213 | 0 | DEBUGMSG(("read_config:forward", "\n")); |
214 | |
|
215 | 0 | if (traph) { |
216 | 0 | traph->flags = flags; |
217 | 0 | traph->authtypes = TRAP_AUTH_NET; |
218 | 0 | traph->token = strdup(cptr); |
219 | 0 | if (format) |
220 | 0 | traph->format = format; |
221 | 0 | } else { |
222 | 0 | free(format); |
223 | 0 | } |
224 | 0 | } |
225 | | |
226 | | |
227 | | void |
228 | | parse_format(const char *token, char *line) |
229 | 0 | { |
230 | 0 | char *cp, *sep; |
231 | | |
232 | | /* |
233 | | * Extract the first token from the value |
234 | | * which tells us which style of format this is |
235 | | */ |
236 | 0 | cp = line; |
237 | 0 | while (*cp && !isspace((unsigned char)(*cp))) |
238 | 0 | cp++; |
239 | 0 | if (!(*cp)) { |
240 | | /* |
241 | | * If we haven't got anything left, |
242 | | * then this entry is malformed. |
243 | | * So report this, and give up |
244 | | */ |
245 | 0 | return; |
246 | 0 | } |
247 | | |
248 | 0 | sep = cp; |
249 | 0 | *(cp++) = '\0'; |
250 | 0 | while (*cp && isspace((unsigned char)(*cp))) |
251 | 0 | cp++; |
252 | | |
253 | | /* |
254 | | * OK - now "line" contains the format type, |
255 | | * and cp points to the actual format string. |
256 | | * So update the appropriate pointer(s). |
257 | | */ |
258 | 0 | if (!strcmp( line, "print1")) { |
259 | 0 | SNMP_FREE( print_format1 ); |
260 | 0 | print_format1 = strdup(cp); |
261 | 0 | } else if (!strcmp( line, "print2")) { |
262 | 0 | SNMP_FREE( print_format2 ); |
263 | 0 | print_format2 = strdup(cp); |
264 | 0 | } else if (!strcmp( line, "print")) { |
265 | 0 | SNMP_FREE( print_format1 ); |
266 | 0 | SNMP_FREE( print_format2 ); |
267 | 0 | print_format1 = strdup(cp); |
268 | 0 | print_format2 = strdup(cp); |
269 | 0 | } else if (!strcmp( line, "syslog1")) { |
270 | 0 | SNMP_FREE( syslog_format1 ); |
271 | 0 | syslog_format1 = strdup(cp); |
272 | 0 | } else if (!strcmp( line, "syslog2")) { |
273 | 0 | SNMP_FREE( syslog_format2 ); |
274 | 0 | syslog_format2 = strdup(cp); |
275 | 0 | } else if (!strcmp( line, "syslog")) { |
276 | 0 | SNMP_FREE( syslog_format1 ); |
277 | 0 | SNMP_FREE( syslog_format2 ); |
278 | 0 | syslog_format1 = strdup(cp); |
279 | 0 | syslog_format2 = strdup(cp); |
280 | 0 | } else if (!strcmp( line, "execute1")) { |
281 | 0 | SNMP_FREE( exec_format1 ); |
282 | 0 | exec_format1 = strdup(cp); |
283 | 0 | } else if (!strcmp( line, "execute2")) { |
284 | 0 | SNMP_FREE( exec_format2 ); |
285 | 0 | exec_format2 = strdup(cp); |
286 | 0 | } else if (!strcmp( line, "execute")) { |
287 | 0 | SNMP_FREE( exec_format1 ); |
288 | 0 | SNMP_FREE( exec_format2 ); |
289 | 0 | exec_format1 = strdup(cp); |
290 | 0 | exec_format2 = strdup(cp); |
291 | 0 | } |
292 | |
|
293 | 0 | *sep = ' '; |
294 | 0 | } |
295 | | |
296 | | |
297 | | static void |
298 | | parse_trap1_fmt(const char *token, char *line) |
299 | 0 | { |
300 | 0 | print_format1 = strdup(line); |
301 | 0 | } |
302 | | |
303 | | |
304 | | void |
305 | | free_trap1_fmt(void) |
306 | 0 | { |
307 | 0 | if (print_format1 && print_format1 != trap1_std_str) |
308 | 0 | free(print_format1); |
309 | 0 | print_format1 = NULL; |
310 | 0 | } |
311 | | |
312 | | |
313 | | static void |
314 | | parse_trap2_fmt(const char *token, char *line) |
315 | 0 | { |
316 | 0 | print_format2 = strdup(line); |
317 | 0 | } |
318 | | |
319 | | |
320 | | void |
321 | | free_trap2_fmt(void) |
322 | 0 | { |
323 | 0 | if (print_format2 && print_format2 != trap2_std_str) |
324 | 0 | free(print_format2); |
325 | 0 | print_format2 = NULL; |
326 | 0 | } |
327 | | |
328 | | |
329 | | void |
330 | | snmptrapd_register_configs( void ) |
331 | 0 | { |
332 | 0 | register_config_handler("snmptrapd", "traphandle", |
333 | 0 | snmptrapd_parse_traphandle, |
334 | 0 | snmptrapd_free_traphandle, |
335 | 0 | "oid|\"default\" program [args ...] "); |
336 | 0 | register_config_handler("snmptrapd", "format1", |
337 | 0 | parse_trap1_fmt, free_trap1_fmt, "format"); |
338 | 0 | register_config_handler("snmptrapd", "format2", |
339 | 0 | parse_trap2_fmt, free_trap2_fmt, "format"); |
340 | 0 | register_config_handler("snmptrapd", "format", |
341 | 0 | parse_format, NULL, |
342 | 0 | "[print{,1,2}|syslog{,1,2}|execute{,1,2}] format"); |
343 | 0 | register_config_handler("snmptrapd", "forward", |
344 | 0 | parse_forward, NULL, "OID|\"default\" destination"); |
345 | 0 | } |
346 | | |
347 | | |
348 | | |
349 | | /*----------------------------- |
350 | | * |
351 | | * Routines to implement a "registry" of trap handlers |
352 | | * |
353 | | *-----------------------------*/ |
354 | | |
355 | | netsnmp_trapd_handler *netsnmp_auth_global_traphandlers = NULL; |
356 | | netsnmp_trapd_handler *netsnmp_pre_global_traphandlers = NULL; |
357 | | netsnmp_trapd_handler *netsnmp_post_global_traphandlers = NULL; |
358 | | netsnmp_trapd_handler *netsnmp_default_traphandlers = NULL; |
359 | | netsnmp_trapd_handler *netsnmp_specific_traphandlers = NULL; |
360 | | |
361 | | typedef struct netsnmp_handler_map_t { |
362 | | netsnmp_trapd_handler **handler; |
363 | | const char *descr; |
364 | | } netsnmp_handler_map; |
365 | | |
366 | | static netsnmp_handler_map handlers[] = { |
367 | | { &netsnmp_auth_global_traphandlers, "auth trap" }, |
368 | | { &netsnmp_pre_global_traphandlers, "pre-global trap" }, |
369 | | { NULL, "trap specific" }, |
370 | | { &netsnmp_post_global_traphandlers, "global" }, |
371 | | { NULL, NULL } |
372 | | }; |
373 | | |
374 | | /* |
375 | | * Register a new "global" traphandler, |
376 | | * to be applied to *all* incoming traps |
377 | | */ |
378 | | netsnmp_trapd_handler * |
379 | | netsnmp_add_global_traphandler(int list, Netsnmp_Trap_Handler *handler) |
380 | 0 | { |
381 | 0 | netsnmp_trapd_handler *traph; |
382 | |
|
383 | 0 | if ( !handler ) |
384 | 0 | return NULL; |
385 | | |
386 | 0 | traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler); |
387 | 0 | if ( !traph ) |
388 | 0 | return NULL; |
389 | | |
390 | | /* |
391 | | * Add this new handler to the front of the appropriate list |
392 | | * (or should it go on the end?) |
393 | | */ |
394 | 0 | traph->handler = handler; |
395 | 0 | traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */ |
396 | 0 | switch (list) { |
397 | 0 | case NETSNMPTRAPD_AUTH_HANDLER: |
398 | 0 | traph->nexth = netsnmp_auth_global_traphandlers; |
399 | 0 | netsnmp_auth_global_traphandlers = traph; |
400 | 0 | break; |
401 | 0 | case NETSNMPTRAPD_PRE_HANDLER: |
402 | 0 | traph->nexth = netsnmp_pre_global_traphandlers; |
403 | 0 | netsnmp_pre_global_traphandlers = traph; |
404 | 0 | break; |
405 | 0 | case NETSNMPTRAPD_POST_HANDLER: |
406 | 0 | traph->nexth = netsnmp_post_global_traphandlers; |
407 | 0 | netsnmp_post_global_traphandlers = traph; |
408 | 0 | break; |
409 | 0 | case NETSNMPTRAPD_DEFAULT_HANDLER: |
410 | 0 | traph->nexth = netsnmp_default_traphandlers; |
411 | 0 | netsnmp_default_traphandlers = traph; |
412 | 0 | break; |
413 | 0 | default: |
414 | 0 | free( traph ); |
415 | 0 | return NULL; |
416 | 0 | } |
417 | 0 | return traph; |
418 | 0 | } |
419 | | |
420 | | #ifndef NETSNMP_FEATURE_REMOVE_ADD_DEFAULT_TRAPHANDLER |
421 | | /* |
422 | | * Register a new "default" traphandler, to be applied to all |
423 | | * traps with no specific trap handlers of their own. |
424 | | */ |
425 | | netsnmp_trapd_handler * |
426 | 0 | netsnmp_add_default_traphandler(Netsnmp_Trap_Handler *handler) { |
427 | 0 | return netsnmp_add_global_traphandler(NETSNMPTRAPD_DEFAULT_HANDLER, |
428 | 0 | handler); |
429 | 0 | } |
430 | | #endif /* NETSNMP_FEATURE_REMOVE_ADD_DEFAULT_TRAPHANDLER */ |
431 | | |
432 | | |
433 | | /* |
434 | | * Register a new trap-specific traphandler |
435 | | */ |
436 | | netsnmp_trapd_handler * |
437 | | netsnmp_add_traphandler(Netsnmp_Trap_Handler* handler, |
438 | 0 | oid *trapOid, int trapOidLen ) { |
439 | 0 | netsnmp_trapd_handler *traph, *traph2; |
440 | |
|
441 | 0 | if ( !handler ) |
442 | 0 | return NULL; |
443 | | |
444 | 0 | traph = SNMP_MALLOC_TYPEDEF(netsnmp_trapd_handler); |
445 | 0 | if ( !traph ) |
446 | 0 | return NULL; |
447 | | |
448 | | /* |
449 | | * Populate this new handler with the trap information |
450 | | * (NB: the OID fields were not used in the default/global lists) |
451 | | */ |
452 | 0 | traph->authtypes = TRAP_AUTH_ALL; /* callers will likely change this */ |
453 | 0 | traph->handler = handler; |
454 | 0 | traph->trapoid_len = trapOidLen; |
455 | 0 | traph->trapoid = snmp_duplicate_objid(trapOid, trapOidLen); |
456 | | |
457 | | /* |
458 | | * Now try to find the appropriate place in the trap-specific |
459 | | * list for this particular trap OID. If there's a matching OID |
460 | | * already, then find it. Otherwise find the one that follows. |
461 | | * If we run out of entries, the new one should be tacked onto the end. |
462 | | */ |
463 | 0 | for (traph2 = netsnmp_specific_traphandlers; |
464 | 0 | traph2; traph2 = traph2->nextt) { |
465 | | /* XXX - check this! */ |
466 | 0 | if (snmp_oid_compare(traph2->trapoid, traph2->trapoid_len, |
467 | 0 | trapOid, trapOidLen) <= 0) |
468 | 0 | break; |
469 | 0 | } |
470 | 0 | if (traph2) { |
471 | | /* |
472 | | * OK - We've either got an exact match, or we've found the |
473 | | * entry *after* where the new one should go. |
474 | | */ |
475 | 0 | if (!snmp_oid_compare(traph->trapoid, traph->trapoid_len, |
476 | 0 | traph2->trapoid, traph2->trapoid_len)) { |
477 | | /* |
478 | | * Exact match, so find the end of the *handler* list |
479 | | * and tack on this new entry... |
480 | | */ |
481 | 0 | while (traph2->nexth) |
482 | 0 | traph2 = traph2->nexth; |
483 | 0 | traph2->nexth = traph; |
484 | 0 | traph->nextt = traph2->nextt; /* Might as well... */ |
485 | 0 | traph->prevt = traph2->prevt; |
486 | 0 | } else { |
487 | | /* |
488 | | * .. or the following entry, so insert the new one before it. |
489 | | */ |
490 | 0 | traph->prevt = traph2->prevt; |
491 | 0 | if (traph2->prevt) |
492 | 0 | traph2->prevt->nextt = traph; |
493 | 0 | else |
494 | 0 | netsnmp_specific_traphandlers = traph; |
495 | 0 | traph2->prevt = traph; |
496 | 0 | traph->nextt = traph2; |
497 | 0 | } |
498 | 0 | } else { |
499 | | /* |
500 | | * If we've run out of entries without finding a suitable spot, |
501 | | * the new one should be tacked onto the end..... |
502 | | */ |
503 | 0 | if (netsnmp_specific_traphandlers) { |
504 | 0 | traph2 = netsnmp_specific_traphandlers; |
505 | 0 | while (traph2->nextt) |
506 | 0 | traph2 = traph2->nextt; |
507 | 0 | traph2->nextt = traph; |
508 | 0 | traph->prevt = traph2; |
509 | 0 | } else { |
510 | | /* |
511 | | * .... unless this is the very first entry, of course! |
512 | | */ |
513 | 0 | netsnmp_specific_traphandlers = traph; |
514 | 0 | } |
515 | 0 | } |
516 | |
|
517 | 0 | return traph; |
518 | 0 | } |
519 | | |
520 | | static void |
521 | | free_non_builtin_handlers(netsnmp_trapd_handler **list_head) |
522 | 0 | { |
523 | 0 | netsnmp_trapd_handler *traph = *list_head; |
524 | 0 | netsnmp_trapd_handler *prev = NULL; |
525 | 0 | netsnmp_trapd_handler *next; |
526 | |
|
527 | 0 | while (traph) { |
528 | 0 | next = traph->nexth; |
529 | 0 | if (!(traph->flags & NETSNMP_TRAPHANDLER_FLAG_BUILTIN)) { |
530 | | /* Unlink */ |
531 | 0 | if (prev) |
532 | 0 | prev->nexth = next; |
533 | 0 | else |
534 | 0 | *list_head = next; |
535 | | |
536 | | /* Free */ |
537 | 0 | if (traph->free_handler_data) |
538 | 0 | traph->free_handler_data(traph->handler_data); |
539 | 0 | SNMP_FREE(traph->token); |
540 | 0 | SNMP_FREE(traph); |
541 | 0 | } else { |
542 | 0 | prev = traph; |
543 | 0 | } |
544 | 0 | traph = next; |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | void |
549 | | snmptrapd_free_traphandle(void) |
550 | 0 | { |
551 | 0 | netsnmp_trapd_handler *traph = NULL, *nextt = NULL, *nexth = NULL; |
552 | |
|
553 | 0 | DEBUGMSGTL(("snmptrapd", "Freeing trap handler lists\n")); |
554 | |
|
555 | 0 | free_non_builtin_handlers(&netsnmp_auth_global_traphandlers); |
556 | 0 | free_non_builtin_handlers(&netsnmp_pre_global_traphandlers); |
557 | 0 | free_non_builtin_handlers(&netsnmp_post_global_traphandlers); |
558 | 0 | free_non_builtin_handlers(&netsnmp_default_traphandlers); |
559 | | |
560 | | /* |
561 | | * Free specific trap handlers |
562 | | */ |
563 | 0 | traph = netsnmp_specific_traphandlers; |
564 | | /* loop over traps */ |
565 | 0 | while (traph) { |
566 | 0 | nextt = traph->nextt; |
567 | | /* loop over handlers for this trap */ |
568 | 0 | while (traph) { |
569 | 0 | DEBUGMSG(("snmptrapd", "Freeing specific trap handler\n")); |
570 | 0 | nexth = traph->nexth; |
571 | 0 | if (traph->free_handler_data) |
572 | 0 | traph->free_handler_data(traph->handler_data); |
573 | 0 | SNMP_FREE(traph->token); |
574 | 0 | SNMP_FREE(traph->trapoid); |
575 | 0 | SNMP_FREE(traph); |
576 | 0 | traph = nexth; |
577 | 0 | } |
578 | 0 | traph = nextt; |
579 | 0 | } |
580 | 0 | netsnmp_specific_traphandlers = NULL; |
581 | 0 | } |
582 | | |
583 | | void |
584 | | snmptrapd_free_all_traphandlers(void) |
585 | 0 | { |
586 | 0 | netsnmp_trapd_handler *traph; |
587 | |
|
588 | 0 | for (traph = netsnmp_auth_global_traphandlers; traph; traph = traph->nexth) |
589 | 0 | traph->flags &= ~NETSNMP_TRAPHANDLER_FLAG_BUILTIN; |
590 | 0 | for (traph = netsnmp_pre_global_traphandlers; traph; traph = traph->nexth) |
591 | 0 | traph->flags &= ~NETSNMP_TRAPHANDLER_FLAG_BUILTIN; |
592 | 0 | for (traph = netsnmp_post_global_traphandlers; traph; traph = traph->nexth) |
593 | 0 | traph->flags &= ~NETSNMP_TRAPHANDLER_FLAG_BUILTIN; |
594 | 0 | for (traph = netsnmp_default_traphandlers; traph; traph = traph->nexth) |
595 | 0 | traph->flags &= ~NETSNMP_TRAPHANDLER_FLAG_BUILTIN; |
596 | |
|
597 | 0 | snmptrapd_free_traphandle(); |
598 | 0 | } |
599 | | |
600 | | /* |
601 | | * Locate the list of handlers for this particular Trap OID |
602 | | * Returns NULL if there are no relevant traps |
603 | | */ |
604 | | netsnmp_trapd_handler * |
605 | 323 | netsnmp_get_traphandler( oid *trapOid, int trapOidLen ) { |
606 | 323 | netsnmp_trapd_handler *traph; |
607 | | |
608 | 323 | if (!trapOid || !trapOidLen) { |
609 | 11 | DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler no OID!\n")); |
610 | 11 | return NULL; |
611 | 11 | } |
612 | 312 | DEBUGMSGTL(( "snmptrapd:lookup", "Looking up Trap OID: ")); |
613 | 312 | DEBUGMSGOID(("snmptrapd:lookup", trapOid, trapOidLen)); |
614 | 312 | DEBUGMSG(( "snmptrapd:lookup", "\n")); |
615 | | |
616 | | /* |
617 | | * Look for a matching OID, and return that list... |
618 | | */ |
619 | 312 | for (traph = netsnmp_specific_traphandlers; |
620 | 312 | traph; traph=traph->nextt ) { |
621 | | |
622 | | /* |
623 | | * If the trap handler wasn't wildcarded, then the trapOID |
624 | | * should match the registered OID exactly. |
625 | | */ |
626 | 0 | if (!(traph->flags & NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE)) { |
627 | 0 | if (snmp_oid_compare(traph->trapoid, traph->trapoid_len, |
628 | 0 | trapOid, trapOidLen) == 0) { |
629 | 0 | DEBUGMSGTL(( "snmptrapd:lookup", |
630 | 0 | "get_traphandler exact match (%p)\n", traph)); |
631 | 0 | return traph; |
632 | 0 | } |
633 | 0 | } else { |
634 | | /* |
635 | | * If the trap handler *was* wildcarded, then the trapOID |
636 | | * should have the registered OID as a prefix... |
637 | | */ |
638 | 0 | if (snmp_oidsubtree_compare(traph->trapoid, |
639 | 0 | traph->trapoid_len, |
640 | 0 | trapOid, trapOidLen) == 0) { |
641 | 0 | if (traph->flags & NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE) { |
642 | | /* |
643 | | * ... and (optionally) *strictly* as a prefix |
644 | | * i.e. not including an exact match. |
645 | | */ |
646 | 0 | if (snmp_oid_compare(traph->trapoid, traph->trapoid_len, |
647 | 0 | trapOid, trapOidLen) != 0) { |
648 | 0 | DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler strict subtree match (%p)\n", traph)); |
649 | 0 | return traph; |
650 | 0 | } |
651 | 0 | } else { |
652 | 0 | DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler subtree match (%p)\n", traph)); |
653 | 0 | return traph; |
654 | 0 | } |
655 | 0 | } |
656 | 0 | } |
657 | 0 | } |
658 | | |
659 | | /* |
660 | | * .... or failing that, return the "default" list (which may be NULL) |
661 | | */ |
662 | 312 | DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler default (%p)\n", |
663 | 312 | netsnmp_default_traphandlers)); |
664 | 312 | return netsnmp_default_traphandlers; |
665 | 312 | } |
666 | | |
667 | | /*----------------------------- |
668 | | * |
669 | | * Standard traphandlers for the common requirements |
670 | | * |
671 | | *-----------------------------*/ |
672 | | |
673 | 0 | #define SYSLOG_V1_STANDARD_FORMAT "%a: %W Trap (%q) Uptime: %#T%#v\n" |
674 | 0 | #define SYSLOG_V1_ENTERPRISE_FORMAT "%a: %W Trap (%q) Uptime: %#T%#v\n" /* XXX - (%q) become (.N) ??? */ |
675 | 0 | #define SYSLOG_V23_NOTIFICATION_FORMAT "%B [%b]: Trap %#v\n" /* XXX - introduces a leading " ," */ |
676 | | |
677 | | /* |
678 | | * Trap handler for logging via syslog |
679 | | */ |
680 | | int syslog_handler( netsnmp_pdu *pdu, |
681 | | netsnmp_transport *transport, |
682 | | netsnmp_trapd_handler *handler) |
683 | 0 | { |
684 | 0 | u_char *rbuf = NULL; |
685 | 0 | size_t r_len = 64, o_len = 0; |
686 | 0 | int trunc = 0; |
687 | |
|
688 | 0 | DEBUGMSGTL(( "snmptrapd", "syslog_handler\n")); |
689 | |
|
690 | 0 | if (SyslogTrap) |
691 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
692 | | |
693 | 0 | if ((rbuf = calloc(r_len, 1)) == NULL) { |
694 | 0 | snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n"); |
695 | 0 | return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */ |
696 | 0 | } |
697 | | |
698 | | /* |
699 | | * If there's a format string registered for this trap, then use it. |
700 | | */ |
701 | 0 | if (handler && handler->format) { |
702 | 0 | DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format)); |
703 | 0 | if (*handler->format) { |
704 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
705 | 0 | handler->format, pdu, transport); |
706 | 0 | } else { |
707 | 0 | free(rbuf); |
708 | 0 | return NETSNMPTRAPD_HANDLER_OK; /* A 0-length format string means don't log */ |
709 | 0 | } |
710 | | |
711 | | /* |
712 | | * Otherwise (i.e. a NULL handler format string), |
713 | | * use a standard output format setting |
714 | | * either configurable, or hardwired |
715 | | * |
716 | | * XXX - v1 traps use a different hardwired formats for |
717 | | * standard and enterprise specific traps |
718 | | * Do we actually need this? |
719 | | */ |
720 | 0 | } else { |
721 | 0 | if ( pdu->command == SNMP_MSG_TRAP ) { |
722 | 0 | if (syslog_format1) { |
723 | 0 | DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'\n", syslog_format1)); |
724 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
725 | 0 | syslog_format1, pdu, transport); |
726 | |
|
727 | 0 | } else if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) { |
728 | 0 | DEBUGMSGTL(( "snmptrapd", "v1 enterprise format\n")); |
729 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
730 | 0 | SYSLOG_V1_ENTERPRISE_FORMAT, |
731 | 0 | pdu, transport); |
732 | 0 | } else { |
733 | 0 | DEBUGMSGTL(( "snmptrapd", "v1 standard trap format\n")); |
734 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
735 | 0 | SYSLOG_V1_STANDARD_FORMAT, |
736 | 0 | pdu, transport); |
737 | 0 | } |
738 | 0 | } else { /* SNMPv2/3 notifications */ |
739 | 0 | if (syslog_format2) { |
740 | 0 | DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'\n", syslog_format2)); |
741 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
742 | 0 | syslog_format2, pdu, transport); |
743 | 0 | } else { |
744 | 0 | DEBUGMSGTL(( "snmptrapd", "v2/3 format\n")); |
745 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
746 | 0 | SYSLOG_V23_NOTIFICATION_FORMAT, |
747 | 0 | pdu, transport); |
748 | 0 | } |
749 | 0 | } |
750 | 0 | } |
751 | 0 | snmp_log(LOG_WARNING, "%s%s", rbuf, (trunc?" [TRUNCATED]\n":"")); |
752 | 0 | free(rbuf); |
753 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
754 | 0 | } |
755 | | |
756 | | |
757 | 0 | #define PRINT_V23_NOTIFICATION_FORMAT "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n" |
758 | | |
759 | | /* |
760 | | * Trap handler for logging to a file |
761 | | */ |
762 | | int print_handler( netsnmp_pdu *pdu, |
763 | | netsnmp_transport *transport, |
764 | | netsnmp_trapd_handler *handler) |
765 | 0 | { |
766 | 0 | u_char *rbuf = NULL; |
767 | 0 | size_t r_len = 64, o_len = 0; |
768 | 0 | int trunc = 0; |
769 | |
|
770 | 0 | DEBUGMSGTL(( "snmptrapd", "print_handler\n")); |
771 | | |
772 | | /* |
773 | | * Don't bother logging authentication failures |
774 | | * XXX - can we handle this via suitable handler entries instead? |
775 | | */ |
776 | 0 | if (pdu->trap_type == SNMP_TRAP_AUTHFAIL && dropauth) |
777 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
778 | | |
779 | 0 | if ((rbuf = calloc(r_len, 1)) == NULL) { |
780 | 0 | snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n"); |
781 | 0 | return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */ |
782 | 0 | } |
783 | | |
784 | | /* |
785 | | * If there's a format string registered for this trap, then use it. |
786 | | */ |
787 | 0 | if (handler && handler->format) { |
788 | 0 | DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format)); |
789 | 0 | if (*handler->format) { |
790 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
791 | 0 | handler->format, pdu, transport); |
792 | 0 | } else { |
793 | 0 | free(rbuf); |
794 | 0 | return NETSNMPTRAPD_HANDLER_OK; /* A 0-length format string means don't log */ |
795 | 0 | } |
796 | | |
797 | | /* |
798 | | * Otherwise (i.e. a NULL handler format string), |
799 | | * use a standard output format setting |
800 | | * either configurable, or hardwired |
801 | | * |
802 | | * XXX - v1 traps use a different routine for hardwired output |
803 | | * Do we actually need this separate v1 routine? |
804 | | * Or would a suitable format string be sufficient? |
805 | | */ |
806 | 0 | } else { |
807 | 0 | if ( pdu->command == SNMP_MSG_TRAP ) { |
808 | 0 | if (print_format1) { |
809 | 0 | DEBUGMSGTL(( "snmptrapd", "print_format v1 = '%s'\n", print_format1)); |
810 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
811 | 0 | print_format1, pdu, transport); |
812 | 0 | } else { |
813 | 0 | DEBUGMSGTL(( "snmptrapd", "v1 format\n")); |
814 | 0 | trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len, 1, |
815 | 0 | pdu, transport); |
816 | 0 | } |
817 | 0 | } else { |
818 | 0 | if (print_format2) { |
819 | 0 | DEBUGMSGTL(( "snmptrapd", "print_format v2 = '%s'\n", print_format2)); |
820 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
821 | 0 | print_format2, pdu, transport); |
822 | 0 | } else { |
823 | 0 | DEBUGMSGTL(( "snmptrapd", "v2/3 format\n")); |
824 | 0 | trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
825 | 0 | PRINT_V23_NOTIFICATION_FORMAT, |
826 | 0 | pdu, transport); |
827 | 0 | } |
828 | 0 | } |
829 | 0 | } |
830 | 0 | snmp_log(LOG_INFO, "%s%s", rbuf, (trunc?" [TRUNCATED]\n":"")); |
831 | 0 | free(rbuf); |
832 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
833 | 0 | } |
834 | | |
835 | | |
836 | 0 | #define EXECUTE_FORMAT "%B\n%b\n%V\n%v\n" |
837 | | |
838 | | /* |
839 | | * Trap handler for invoking a suitable script |
840 | | */ |
841 | | int command_handler( netsnmp_pdu *pdu, |
842 | | netsnmp_transport *transport, |
843 | | netsnmp_trapd_handler *handler) |
844 | 0 | { |
845 | | #ifndef USING_UTILITIES_EXECUTE_MODULE |
846 | | NETSNMP_LOGONCE((LOG_WARNING, |
847 | | "support for run_shell_command not available\n")); |
848 | | return NETSNMPTRAPD_HANDLER_FAIL; |
849 | | #else |
850 | 0 | u_char *rbuf = NULL; |
851 | 0 | size_t r_len = 64, o_len = 0; |
852 | 0 | int oldquick; |
853 | |
|
854 | 0 | netsnmp_assert(handler); |
855 | |
|
856 | 0 | DEBUGMSGTL(( "snmptrapd", "command_handler\n")); |
857 | 0 | DEBUGMSGTL(( "snmptrapd", "token = '%s'\n", handler->token)); |
858 | 0 | if (handler->token && *handler->token) { |
859 | 0 | netsnmp_pdu *v2_pdu = NULL; |
860 | 0 | if (pdu->command == SNMP_MSG_TRAP) |
861 | 0 | v2_pdu = convert_v1pdu_to_v2(pdu); |
862 | 0 | else |
863 | 0 | v2_pdu = pdu; |
864 | 0 | oldquick = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, |
865 | 0 | NETSNMP_DS_LIB_QUICK_PRINT); |
866 | 0 | netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
867 | 0 | NETSNMP_DS_LIB_QUICK_PRINT, 1); |
868 | | |
869 | | /* |
870 | | * Format the trap and pass this string to the external command |
871 | | */ |
872 | 0 | if ((rbuf = calloc(r_len, 1)) == NULL) { |
873 | 0 | snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n"); |
874 | 0 | return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */ |
875 | 0 | } |
876 | | |
877 | | /* |
878 | | * If there's a format string registered for this trap, then use it. |
879 | | * Otherwise use the standard execution format setting. |
880 | | */ |
881 | 0 | if (handler->format && *handler->format) { |
882 | 0 | DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format)); |
883 | 0 | realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
884 | 0 | handler->format, |
885 | 0 | v2_pdu, transport); |
886 | 0 | } else { |
887 | 0 | if ( pdu->command == SNMP_MSG_TRAP && exec_format1 ) { |
888 | 0 | DEBUGMSGTL(( "snmptrapd", "exec v1 = '%s'\n", exec_format1)); |
889 | 0 | realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
890 | 0 | exec_format1, pdu, transport); |
891 | 0 | } else if ( pdu->command != SNMP_MSG_TRAP && exec_format2 ) { |
892 | 0 | DEBUGMSGTL(( "snmptrapd", "exec v2/3 = '%s'\n", exec_format2)); |
893 | 0 | realloc_format_trap(&rbuf, &r_len, &o_len, 1, |
894 | 0 | exec_format2, pdu, transport); |
895 | 0 | } else { |
896 | 0 | DEBUGMSGTL(( "snmptrapd", "execute format\n")); |
897 | 0 | realloc_format_trap(&rbuf, &r_len, &o_len, 1, EXECUTE_FORMAT, |
898 | 0 | v2_pdu, transport); |
899 | 0 | } |
900 | 0 | } |
901 | | |
902 | | /* |
903 | | * and pass this formatted string to the command specified |
904 | | */ |
905 | 0 | run_shell_command(handler->token, (char*)rbuf, NULL, NULL); /* Not interested in output */ |
906 | 0 | netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, |
907 | 0 | NETSNMP_DS_LIB_QUICK_PRINT, oldquick); |
908 | 0 | if (pdu->command == SNMP_MSG_TRAP) |
909 | 0 | snmp_free_pdu(v2_pdu); |
910 | 0 | free(rbuf); |
911 | 0 | } |
912 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
913 | 0 | #endif /* !def USING_UTILITIES_EXECUTE_MODULE */ |
914 | 0 | } |
915 | | |
916 | | |
917 | | |
918 | | |
919 | | /* |
920 | | * Trap handler for forwarding to the AgentX master agent |
921 | | */ |
922 | | int axforward_handler( netsnmp_pdu *pdu, |
923 | | netsnmp_transport *transport, |
924 | | netsnmp_trapd_handler *handler) |
925 | 0 | { |
926 | 0 | send_v2trap( pdu->variables ); |
927 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
928 | 0 | } |
929 | | |
930 | | static int add_forwarder_info(netsnmp_pdu *pdu, netsnmp_pdu *pdu2) |
931 | 0 | { |
932 | 0 | netsnmp_indexed_addr_pair *addr_pair1; |
933 | 0 | struct sockaddr_in *to1 = NULL; |
934 | 0 | struct sockaddr_in *to2 = NULL; |
935 | 0 | int last_snmpTrapAddress_index = -1; |
936 | | /* snmpTrapAddress_oid.0 is also defined as agentaddr_oid */ |
937 | 0 | const oid snmpTrapAddress_oid[] = { 1,3,6,1,6,3,18,1,3}; |
938 | | /* each forwarder will add this OID with changed last index */ |
939 | 0 | oid forwarder_oid[] = { 1,3,6,1,6,3,18,1,3,0}; |
940 | 0 | const size_t snmpTrapAddress_oid_size = OID_LENGTH(snmpTrapAddress_oid); |
941 | 0 | const size_t forwarder_oid_len = OID_LENGTH(forwarder_oid); |
942 | 0 | struct in_addr agent_addr; |
943 | 0 | struct in_addr my_ip_addr; |
944 | |
|
945 | 0 | memset(&agent_addr, 0, sizeof(agent_addr)); |
946 | 0 | memset(&my_ip_addr, 0, sizeof(my_ip_addr)); |
947 | |
|
948 | 0 | if (pdu && pdu->transport_data && |
949 | 0 | pdu->transport_data_length == sizeof(*addr_pair1)) { |
950 | 0 | addr_pair1 = (netsnmp_indexed_addr_pair *)pdu->transport_data; |
951 | | |
952 | | /* |
953 | | * Get the IPv4 address of the host that this trap was sent from = |
954 | | * last forwarder's IP address. |
955 | | */ |
956 | 0 | if (addr_pair1->remote_addr.sa.sa_family == AF_INET) { |
957 | 0 | to1 = (struct sockaddr_in *)&(addr_pair1->remote_addr); |
958 | 0 | agent_addr = to1->sin_addr; |
959 | 0 | } |
960 | | /* |
961 | | * Get the IPv4 address of the host that this trap was sent to = |
962 | | * this forwarder's IP address. |
963 | | */ |
964 | 0 | if (addr_pair1->local_addr.sa.sa_family == AF_INET) { |
965 | 0 | to2 = (struct sockaddr_in *)&(addr_pair1->local_addr); |
966 | 0 | my_ip_addr = to2->sin_addr; |
967 | 0 | } |
968 | 0 | } |
969 | |
|
970 | 0 | if (to1) { |
971 | 0 | netsnmp_variable_list *vblist = NULL; |
972 | 0 | netsnmp_variable_list *var = NULL; |
973 | |
|
974 | 0 | if (*(in_addr_t *)pdu2->agent_addr == INADDR_ANY) { |
975 | | /* |
976 | | * there was no agent address defined in PDU. copy the forwarding |
977 | | * agent IP address from the transport socket. |
978 | | */ |
979 | 0 | *(struct in_addr *)pdu2->agent_addr = agent_addr; |
980 | 0 | } |
981 | |
|
982 | 0 | vblist = pdu2->variables; |
983 | | |
984 | | /* |
985 | | * Iterate over all varbinds in the PDU to see if it already has any |
986 | | * forwarder information. |
987 | | */ |
988 | 0 | for (var = vblist; var; var = var->next_variable) { |
989 | 0 | if (snmp_oid_ncompare(var->name, var->name_length, |
990 | 0 | snmpTrapAddress_oid, |
991 | 0 | snmpTrapAddress_oid_size, |
992 | 0 | snmpTrapAddress_oid_size) == 0) { |
993 | 0 | int my_snmpTrapAddress_index = |
994 | 0 | var->name[var->name_length - 1]; |
995 | |
|
996 | 0 | DEBUGMSGTL(("snmptrapd", " my_snmpTrapAddress_index=%d, last_snmpTrapAddress_index=%d, my_ip_addr=%s\n", |
997 | 0 | my_snmpTrapAddress_index, |
998 | 0 | last_snmpTrapAddress_index, |
999 | 0 | inet_ntoa(my_ip_addr))); |
1000 | |
|
1001 | 0 | if (last_snmpTrapAddress_index < my_snmpTrapAddress_index) |
1002 | 0 | last_snmpTrapAddress_index = my_snmpTrapAddress_index; |
1003 | | |
1004 | | /* Detect forwarding loop. */ |
1005 | 0 | if (var->val_len < 4) { |
1006 | 0 | snmp_log(LOG_ERR, "Length of IP address of OID .1.3.6.1.6.3.18.1.3.%d in PDU is less than %d bytes = %d\n", |
1007 | 0 | my_snmpTrapAddress_index, 4, |
1008 | 0 | (int)var->val_len); |
1009 | 0 | } else { |
1010 | 0 | if (to2 && |
1011 | 0 | memcmp(var->val.string, &my_ip_addr, 4) == 0) { |
1012 | 0 | snmp_log(LOG_ERR, "Forwarding loop detected, OID .1.3.6.1.6.3.18.1.3.%d already has this forwarder's IP address=%s, not forwarding this trap\n", |
1013 | 0 | my_snmpTrapAddress_index, |
1014 | 0 | inet_ntoa(my_ip_addr)); |
1015 | 0 | return 0; |
1016 | 0 | } |
1017 | 0 | if (memcmp(var->val.string, &agent_addr, 4) == 0) { |
1018 | 0 | snmp_log(LOG_ERR, "Forwarding loop detected, OID .1.3.6.1.6.3.18.1.3.%d already has the sender's IP address=%s, not forwarding this trap\n", |
1019 | 0 | my_snmpTrapAddress_index, |
1020 | 0 | inet_ntoa(agent_addr)); |
1021 | 0 | return 0; |
1022 | 0 | } |
1023 | 0 | } |
1024 | 0 | } |
1025 | 0 | } /* for var in vblist */ |
1026 | | |
1027 | 0 | DEBUGMSGTL(("snmptrapd", |
1028 | 0 | " last_snmpTrapAddress_index=%d, adding index=%d\n", |
1029 | 0 | last_snmpTrapAddress_index, last_snmpTrapAddress_index+1)); |
1030 | | /* Change the last index of this OID to the next available number. */ |
1031 | 0 | forwarder_oid[forwarder_oid_len - 1] = last_snmpTrapAddress_index + 1; |
1032 | | |
1033 | | /* |
1034 | | * Add forwarder IP address as OID to trap payload. Use the value |
1035 | | * from the transport, so if a v1 PDU is sent, the same IP is not |
1036 | | * duplicated you want every forwarder to add this OID with its |
1037 | | * own IP address. |
1038 | | */ |
1039 | 0 | snmp_pdu_add_variable(pdu2, forwarder_oid, forwarder_oid_len, |
1040 | 0 | ASN_IPADDRESS, (u_char *)&agent_addr, 4); |
1041 | 0 | } |
1042 | 0 | return 1; |
1043 | 0 | } |
1044 | | |
1045 | | /* |
1046 | | * Trap handler for forwarding to another destination |
1047 | | */ |
1048 | | int forward_handler( netsnmp_pdu *pdu, |
1049 | | netsnmp_transport *transport, |
1050 | | netsnmp_trapd_handler *handler) |
1051 | 0 | { |
1052 | 0 | netsnmp_session session, *ss; |
1053 | 0 | netsnmp_pdu *pdu2; |
1054 | 0 | char buf[BUFSIZ], *cp; |
1055 | |
|
1056 | 0 | DEBUGMSGTL(( "snmptrapd", "forward_handler (%s)\n", handler->token)); |
1057 | |
|
1058 | 0 | snmp_sess_init( &session ); |
1059 | 0 | if (strchr( handler->token, ':') == NULL) { |
1060 | 0 | snprintf( buf, BUFSIZ, "%s:%d", handler->token, SNMP_TRAP_PORT); |
1061 | 0 | cp = buf; |
1062 | 0 | } else { |
1063 | 0 | cp = handler->token; |
1064 | 0 | } |
1065 | 0 | session.peername = cp; |
1066 | 0 | session.version = pdu->version; |
1067 | 0 | ss = snmp_open( &session ); |
1068 | 0 | if (!ss) |
1069 | 0 | return NETSNMPTRAPD_HANDLER_FAIL; |
1070 | | |
1071 | | /* XXX: wjh we should be caching sessions here and not always |
1072 | | reopening a session. It's very inefficient, especially with v3 |
1073 | | INFORMS which may require engineID probing */ |
1074 | | |
1075 | 0 | pdu2 = snmp_clone_pdu(pdu); |
1076 | |
|
1077 | 0 | if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, |
1078 | 0 | NETSNMP_DS_LIB_ADD_FORWARDER_INFO) && |
1079 | 0 | !add_forwarder_info(pdu, pdu2)) { |
1080 | 0 | snmp_close(ss); |
1081 | 0 | snmp_free_pdu(pdu2); |
1082 | 0 | return NETSNMPTRAPD_HANDLER_FAIL; |
1083 | 0 | } |
1084 | | |
1085 | 0 | if (pdu2->transport_data) { |
1086 | 0 | free(pdu2->transport_data); |
1087 | 0 | pdu2->transport_data = NULL; |
1088 | 0 | pdu2->transport_data_length = 0; |
1089 | 0 | } |
1090 | |
|
1091 | 0 | ss->s_snmp_errno = SNMPERR_SUCCESS; |
1092 | 0 | if (!snmp_send( ss, pdu2 )) { |
1093 | 0 | if (ss->s_snmp_errno != SNMPERR_SUCCESS) { |
1094 | 0 | snmp_sess_perror("Forward failed", ss); |
1095 | 0 | } |
1096 | 0 | snmp_free_pdu(pdu2); |
1097 | 0 | } |
1098 | 0 | snmp_close( ss ); |
1099 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
1100 | 0 | } |
1101 | | |
1102 | | #if defined(USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE) && defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) |
1103 | | /* |
1104 | | * "Notification" handler for implementing NOTIFICATION-MIB |
1105 | | * (presumably) |
1106 | | */ |
1107 | | int notification_handler(netsnmp_pdu *pdu, |
1108 | | netsnmp_transport *transport, |
1109 | | netsnmp_trapd_handler *handler) |
1110 | 0 | { |
1111 | 0 | DEBUGMSGTL(( "snmptrapd", "notification_handler\n")); |
1112 | 0 | log_notification(pdu, transport); |
1113 | 0 | return NETSNMPTRAPD_HANDLER_OK; |
1114 | 0 | } |
1115 | | #endif |
1116 | | |
1117 | | /*----------------------------- |
1118 | | * |
1119 | | * Main driving code, to process an incoming trap |
1120 | | * |
1121 | | *-----------------------------*/ |
1122 | | |
1123 | | |
1124 | | |
1125 | | int |
1126 | | snmp_input(int op, netsnmp_session *session, |
1127 | | int reqid, netsnmp_pdu *pdu, void *magic) |
1128 | 392 | { |
1129 | 392 | oid stdTrapOidRoot[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 }; |
1130 | 392 | oid snmpTrapOid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; |
1131 | 392 | oid trapOid[MAX_OID_LEN+2] = {0}; |
1132 | 392 | int trapOidLen; |
1133 | 392 | netsnmp_variable_list *vars; |
1134 | 392 | netsnmp_trapd_handler *traph; |
1135 | 392 | netsnmp_transport *transport = (netsnmp_transport *) magic; |
1136 | 392 | int ret, idx; |
1137 | | |
1138 | 392 | switch (op) { |
1139 | 392 | case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE: |
1140 | | /* |
1141 | | * Drops packets with reception problems |
1142 | | */ |
1143 | 392 | if (session->s_snmp_errno) { |
1144 | | /* drop problem packets */ |
1145 | 0 | return 1; |
1146 | 0 | } |
1147 | | |
1148 | | /* |
1149 | | * Determine the OID that identifies the trap being handled |
1150 | | */ |
1151 | 392 | DEBUGMSGTL(("snmptrapd", "input: %x\n", pdu->command)); |
1152 | 392 | switch (pdu->command) { |
1153 | 309 | case SNMP_MSG_TRAP: |
1154 | | /* |
1155 | | * Convert v1 traps into a v2-style trap OID |
1156 | | * (following RFC 2576) |
1157 | | */ |
1158 | 309 | if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) { |
1159 | 123 | trapOidLen = pdu->enterprise_length; |
1160 | | /* |
1161 | | * Drop packets that would trigger an out-of-bounds trapOid[] |
1162 | | * access. |
1163 | | */ |
1164 | 123 | if (trapOidLen < 1 || trapOidLen > OID_LENGTH(trapOid) - 2) |
1165 | 13 | return 1; |
1166 | 110 | memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen); |
1167 | 110 | if (trapOid[trapOidLen - 1] != 0) { |
1168 | 108 | trapOid[trapOidLen++] = 0; |
1169 | 108 | } |
1170 | 110 | trapOid[trapOidLen++] = pdu->specific_type; |
1171 | 186 | } else { |
1172 | 186 | memcpy(trapOid, stdTrapOidRoot, sizeof(stdTrapOidRoot)); |
1173 | 186 | trapOidLen = OID_LENGTH(stdTrapOidRoot); /* 9 */ |
1174 | | /* Drop packets with an invalid trap type. */ |
1175 | 186 | if (pdu->trap_type == LONG_MAX) |
1176 | 3 | return 1; |
1177 | 183 | trapOid[trapOidLen++] = pdu->trap_type+1; |
1178 | 183 | } |
1179 | 293 | break; |
1180 | | |
1181 | 293 | case SNMP_MSG_TRAP2: |
1182 | 30 | case SNMP_MSG_INFORM: |
1183 | | /* |
1184 | | * v2c/v3 notifications *should* have snmpTrapOID as the |
1185 | | * second varbind, so we can go straight there. |
1186 | | * But check, just to make sure |
1187 | | */ |
1188 | 30 | vars = pdu->variables; |
1189 | 30 | if (vars) |
1190 | 30 | vars = vars->next_variable; |
1191 | 30 | if (!vars || snmp_oid_compare(vars->name, vars->name_length, |
1192 | 30 | snmpTrapOid, OID_LENGTH(snmpTrapOid))) { |
1193 | | /* |
1194 | | * Didn't find it! |
1195 | | * Let's look through the full list.... |
1196 | | */ |
1197 | 0 | for ( vars = pdu->variables; vars; vars=vars->next_variable) { |
1198 | 0 | if (vars->type != ASN_OBJECT_ID) |
1199 | 0 | continue; |
1200 | 0 | if (!snmp_oid_compare(vars->name, vars->name_length, |
1201 | 0 | snmpTrapOid, OID_LENGTH(snmpTrapOid))) |
1202 | 0 | break; |
1203 | 0 | } |
1204 | 0 | if (!vars) { |
1205 | | /* |
1206 | | * Still can't find it! Give up. |
1207 | | */ |
1208 | 0 | snmp_log(LOG_ERR, "Cannot find TrapOID in TRAP2 PDU\n"); |
1209 | 0 | return 1; /* ??? */ |
1210 | 0 | } |
1211 | 0 | } |
1212 | 30 | trapOidLen = SNMP_MIN(sizeof(trapOid), vars->val_len) / sizeof(oid); |
1213 | 30 | memcpy(trapOid, vars->val.objid, trapOidLen * sizeof(oid)); |
1214 | 30 | break; |
1215 | | |
1216 | 53 | default: |
1217 | | /* SHOULDN'T HAPPEN! */ |
1218 | 53 | return 1; /* ??? */ |
1219 | 392 | } |
1220 | 323 | DEBUGMSGTL(( "snmptrapd", "Trap OID: ")); |
1221 | 323 | DEBUGMSGOID(("snmptrapd", trapOid, trapOidLen)); |
1222 | 323 | DEBUGMSG(( "snmptrapd", "\n")); |
1223 | | |
1224 | | |
1225 | | /* |
1226 | | * OK - We've found the Trap OID used to identify this trap. |
1227 | | * Call each of the various lists of handlers: |
1228 | | * a) authentication-related handlers, |
1229 | | * b) other handlers to be applied to all traps |
1230 | | * (*before* trap-specific handlers) |
1231 | | * c) the handler(s) specific to this trap |
1232 | | t * d) any other global handlers |
1233 | | * |
1234 | | * In each case, a particular trap handler can abort further |
1235 | | * processing - either just for that particular list, |
1236 | | * or for the trap completely. |
1237 | | * |
1238 | | * This is particularly designed for authentication-related |
1239 | | * handlers, but can also be used elsewhere. |
1240 | | * |
1241 | | * OK - Enough waffling, let's get to work..... |
1242 | | */ |
1243 | | |
1244 | 1.61k | for( idx = 0; handlers[idx].descr; ++idx ) { |
1245 | 1.29k | DEBUGMSGTL(("snmptrapd", "Running %s handlers\n", |
1246 | 1.29k | handlers[idx].descr)); |
1247 | 1.29k | if (NULL == handlers[idx].handler) /* specific */ |
1248 | 323 | traph = netsnmp_get_traphandler(trapOid, trapOidLen); |
1249 | 969 | else |
1250 | 969 | traph = *handlers[idx].handler; |
1251 | | |
1252 | 1.29k | for( ; traph; traph = traph->nexth) { |
1253 | 0 | if (!netsnmp_trapd_check_auth(traph->authtypes)) |
1254 | 0 | continue; /* we continue on and skip this one */ |
1255 | | |
1256 | 0 | ret = (*(traph->handler))(pdu, transport, traph); |
1257 | 0 | if(NETSNMPTRAPD_HANDLER_FINISH == ret) |
1258 | 0 | return 1; |
1259 | 0 | if (ret == NETSNMPTRAPD_HANDLER_BREAK) |
1260 | 0 | break; /* move on to next type */ |
1261 | 0 | } /* traph */ |
1262 | 1.29k | } /* handlers */ |
1263 | | |
1264 | | |
1265 | 323 | if (pdu->command == SNMP_MSG_INFORM) { |
1266 | 27 | netsnmp_pdu *reply = snmp_clone_pdu(pdu); |
1267 | 27 | if (!reply) { |
1268 | 0 | snmp_log(LOG_ERR, "couldn't clone PDU for INFORM response\n"); |
1269 | 27 | } else { |
1270 | 27 | reply->command = SNMP_MSG_RESPONSE; |
1271 | 27 | reply->errstat = 0; |
1272 | 27 | reply->errindex = 0; |
1273 | 27 | if (!snmp_send(session, reply)) { |
1274 | 27 | snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu", |
1275 | 27 | session); |
1276 | 27 | snmp_free_pdu(reply); |
1277 | 27 | } |
1278 | 27 | } |
1279 | 27 | } |
1280 | | |
1281 | 323 | break; |
1282 | | |
1283 | 0 | case NETSNMP_CALLBACK_OP_TIMED_OUT: |
1284 | 0 | snmp_log(LOG_ERR, "Timeout: This shouldn't happen!\n"); |
1285 | 0 | break; |
1286 | | |
1287 | 0 | case NETSNMP_CALLBACK_OP_SEND_FAILED: |
1288 | 0 | snmp_log(LOG_ERR, "Send Failed: This shouldn't happen either!\n"); |
1289 | 0 | break; |
1290 | | |
1291 | 0 | case NETSNMP_CALLBACK_OP_CONNECT: |
1292 | 0 | case NETSNMP_CALLBACK_OP_DISCONNECT: |
1293 | | /* Ignore silently */ |
1294 | 0 | break; |
1295 | | |
1296 | 0 | default: |
1297 | 0 | snmp_log(LOG_ERR, "Unknown operation (%d): This shouldn't happen!\n", op); |
1298 | 0 | break; |
1299 | 392 | } |
1300 | 323 | return 0; |
1301 | 392 | } |
1302 | | |