Coverage Report

Created: 2026-08-13 09:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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