Coverage Report

Created: 2026-01-10 06:37

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
void
521
snmptrapd_free_traphandle(void)
522
0
{
523
0
    netsnmp_trapd_handler *traph = NULL, *nextt = NULL, *nexth = NULL;
524
525
0
    DEBUGMSGTL(("snmptrapd", "Freeing trap handler lists\n"));
526
527
    /*
528
     * Free default trap handlers
529
     */
530
0
    traph = netsnmp_default_traphandlers;
531
   /* loop over handlers */
532
0
    while (traph) {
533
0
       DEBUGMSG(("snmptrapd", "Freeing default trap handler\n"));
534
0
  nexth = traph->nexth;
535
0
  SNMP_FREE(traph->token);
536
0
  SNMP_FREE(traph);
537
0
  traph = nexth;
538
0
    }
539
0
    netsnmp_default_traphandlers = NULL;
540
541
    /* 
542
     * Free specific trap handlers
543
     */
544
0
    traph = netsnmp_specific_traphandlers;
545
    /* loop over traps */
546
0
    while (traph) {
547
0
        nextt = traph->nextt;
548
        /* loop over handlers for this trap */
549
0
  while (traph) {
550
0
      DEBUGMSG(("snmptrapd", "Freeing specific trap handler\n"));
551
0
      nexth = traph->nexth;
552
0
      SNMP_FREE(traph->token);
553
0
      SNMP_FREE(traph->trapoid);
554
0
      SNMP_FREE(traph);
555
0
      traph = nexth;
556
0
  }
557
0
  traph = nextt;
558
0
    }
559
0
    netsnmp_specific_traphandlers = NULL;
560
0
}
561
562
/*
563
 * Locate the list of handlers for this particular Trap OID
564
 * Returns NULL if there are no relevant traps
565
 */
566
netsnmp_trapd_handler *
567
334
netsnmp_get_traphandler( oid *trapOid, int trapOidLen ) {
568
334
    netsnmp_trapd_handler *traph;
569
    
570
334
    if (!trapOid || !trapOidLen) {
571
10
        DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler no OID!\n"));
572
10
        return NULL;
573
10
    }
574
324
    DEBUGMSGTL(( "snmptrapd:lookup", "Looking up Trap OID: "));
575
324
    DEBUGMSGOID(("snmptrapd:lookup", trapOid, trapOidLen));
576
324
    DEBUGMSG(( "snmptrapd:lookup", "\n"));
577
578
    /*
579
     * Look for a matching OID, and return that list...
580
     */
581
324
    for (traph = netsnmp_specific_traphandlers;
582
324
         traph; traph=traph->nextt ) {
583
584
        /*
585
         * If the trap handler wasn't wildcarded, then the trapOID
586
         *   should match the registered OID exactly.
587
         */
588
0
        if (!(traph->flags & NETSNMP_TRAPHANDLER_FLAG_MATCH_TREE)) {
589
0
            if (snmp_oid_compare(traph->trapoid, traph->trapoid_len,
590
0
                                 trapOid, trapOidLen) == 0) {
591
0
                DEBUGMSGTL(( "snmptrapd:lookup",
592
0
                             "get_traphandler exact match (%p)\n", traph));
593
0
          return traph;
594
0
            }
595
0
  } else {
596
           /*
597
            * If the trap handler *was* wildcarded, then the trapOID
598
            *   should have the registered OID as a prefix...
599
            */
600
0
            if (snmp_oidsubtree_compare(traph->trapoid,
601
0
                                        traph->trapoid_len,
602
0
                                        trapOid, trapOidLen) == 0) {
603
0
                if (traph->flags & NETSNMP_TRAPHANDLER_FLAG_STRICT_SUBTREE) {
604
                    /*
605
                     * ... and (optionally) *strictly* as a prefix
606
                     *   i.e. not including an exact match.
607
                     */
608
0
                    if (snmp_oid_compare(traph->trapoid, traph->trapoid_len,
609
0
                                         trapOid, trapOidLen) != 0) {
610
0
                        DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler strict subtree match (%p)\n", traph));
611
0
                  return traph;
612
0
                    }
613
0
                } else {
614
0
                    DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler subtree match (%p)\n", traph));
615
0
              return traph;
616
0
                }
617
0
            }
618
0
  }
619
0
    }
620
621
    /*
622
     * .... or failing that, return the "default" list (which may be NULL)
623
     */
624
324
    DEBUGMSGTL(( "snmptrapd:lookup", "get_traphandler default (%p)\n",
625
324
          netsnmp_default_traphandlers));
626
324
    return netsnmp_default_traphandlers;
627
324
}
628
629
/*-----------------------------
630
 *
631
 * Standard traphandlers for the common requirements
632
 *
633
 *-----------------------------*/
634
635
0
#define SYSLOG_V1_STANDARD_FORMAT      "%a: %W Trap (%q) Uptime: %#T%#v\n"
636
0
#define SYSLOG_V1_ENTERPRISE_FORMAT    "%a: %W Trap (%q) Uptime: %#T%#v\n" /* XXX - (%q) become (.N) ??? */
637
0
#define SYSLOG_V23_NOTIFICATION_FORMAT "%B [%b]: Trap %#v\n"       /* XXX - introduces a leading " ," */
638
639
/*
640
 *  Trap handler for logging via syslog
641
 */
642
int   syslog_handler(  netsnmp_pdu           *pdu,
643
                       netsnmp_transport     *transport,
644
                       netsnmp_trapd_handler *handler)
645
0
{
646
0
    u_char         *rbuf = NULL;
647
0
    size_t          r_len = 64, o_len = 0;
648
0
    int             trunc = 0;
649
650
0
    DEBUGMSGTL(( "snmptrapd", "syslog_handler\n"));
651
652
0
    if (SyslogTrap)
653
0
        return NETSNMPTRAPD_HANDLER_OK;
654
655
0
    if ((rbuf = calloc(r_len, 1)) == NULL) {
656
0
        snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
657
0
        return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
658
0
    }
659
660
    /*
661
     *  If there's a format string registered for this trap, then use it.
662
     */
663
0
    if (handler && handler->format) {
664
0
        DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format));
665
0
        if (*handler->format) {
666
0
            trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
667
0
                                     handler->format, pdu, transport);
668
0
        } else {
669
0
            free(rbuf);
670
0
            return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
671
0
        }
672
673
    /*
674
     *  Otherwise (i.e. a NULL handler format string),
675
     *      use a standard output format setting
676
     *      either configurable, or hardwired
677
     *
678
     *  XXX - v1 traps use a different hardwired formats for
679
     *        standard and enterprise specific traps
680
     *        Do we actually need this?
681
     */
682
0
    } else {
683
0
  if ( pdu->command == SNMP_MSG_TRAP ) {
684
0
            if (syslog_format1) {
685
0
                DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'\n", syslog_format1));
686
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
687
0
                                             syslog_format1, pdu, transport);
688
689
0
      } else if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
690
0
                DEBUGMSGTL(( "snmptrapd", "v1 enterprise format\n"));
691
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
692
0
                                             SYSLOG_V1_ENTERPRISE_FORMAT,
693
0
                                             pdu, transport);
694
0
      } else {
695
0
                DEBUGMSGTL(( "snmptrapd", "v1 standard trap format\n"));
696
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
697
0
                                             SYSLOG_V1_STANDARD_FORMAT,
698
0
                                             pdu, transport);
699
0
      }
700
0
  } else { /* SNMPv2/3 notifications */
701
0
            if (syslog_format2) {
702
0
                DEBUGMSGTL(( "snmptrapd", "syslog_format v1 = '%s'\n", syslog_format2));
703
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
704
0
                                             syslog_format2, pdu, transport);
705
0
      } else {
706
0
                DEBUGMSGTL(( "snmptrapd", "v2/3 format\n"));
707
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
708
0
                                             SYSLOG_V23_NOTIFICATION_FORMAT,
709
0
                                             pdu, transport);
710
0
      }
711
0
        }
712
0
    }
713
0
    snmp_log(LOG_WARNING, "%s%s", rbuf, (trunc?" [TRUNCATED]\n":""));
714
0
    free(rbuf);
715
0
    return NETSNMPTRAPD_HANDLER_OK;
716
0
}
717
718
719
0
#define PRINT_V23_NOTIFICATION_FORMAT "%.4y-%.2m-%.2l %.2h:%.2j:%.2k %B [%b]:\n%v\n"
720
721
/*
722
 *  Trap handler for logging to a file
723
 */
724
int   print_handler(   netsnmp_pdu           *pdu,
725
                       netsnmp_transport     *transport,
726
                       netsnmp_trapd_handler *handler)
727
0
{
728
0
    u_char         *rbuf = NULL;
729
0
    size_t          r_len = 64, o_len = 0;
730
0
    int             trunc = 0;
731
732
0
    DEBUGMSGTL(( "snmptrapd", "print_handler\n"));
733
734
    /*
735
     *  Don't bother logging authentication failures
736
     *  XXX - can we handle this via suitable handler entries instead?
737
     */
738
0
    if (pdu->trap_type == SNMP_TRAP_AUTHFAIL && dropauth)
739
0
        return NETSNMPTRAPD_HANDLER_OK;
740
741
0
    if ((rbuf = calloc(r_len, 1)) == NULL) {
742
0
        snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
743
0
        return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
744
0
    }
745
746
    /*
747
     *  If there's a format string registered for this trap, then use it.
748
     */
749
0
    if (handler && handler->format) {
750
0
        DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format));
751
0
        if (*handler->format) {
752
0
            trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
753
0
                                     handler->format, pdu, transport);
754
0
        } else {
755
0
            free(rbuf);
756
0
            return NETSNMPTRAPD_HANDLER_OK;    /* A 0-length format string means don't log */
757
0
        }
758
759
    /*
760
     *  Otherwise (i.e. a NULL handler format string),
761
     *      use a standard output format setting
762
     *      either configurable, or hardwired
763
     *
764
     *  XXX - v1 traps use a different routine for hardwired output
765
     *        Do we actually need this separate v1 routine?
766
     *        Or would a suitable format string be sufficient?
767
     */
768
0
    } else {
769
0
  if ( pdu->command == SNMP_MSG_TRAP ) {
770
0
            if (print_format1) {
771
0
                DEBUGMSGTL(( "snmptrapd", "print_format v1 = '%s'\n", print_format1));
772
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
773
0
                                             print_format1, pdu, transport);
774
0
      } else {
775
0
                DEBUGMSGTL(( "snmptrapd", "v1 format\n"));
776
0
                trunc = !realloc_format_plain_trap(&rbuf, &r_len, &o_len, 1,
777
0
                                                   pdu, transport);
778
0
      }
779
0
  } else {
780
0
            if (print_format2) {
781
0
                DEBUGMSGTL(( "snmptrapd", "print_format v2 = '%s'\n", print_format2));
782
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
783
0
                                             print_format2, pdu, transport);
784
0
      } else {
785
0
                DEBUGMSGTL(( "snmptrapd", "v2/3 format\n"));
786
0
                trunc = !realloc_format_trap(&rbuf, &r_len, &o_len, 1,
787
0
                                             PRINT_V23_NOTIFICATION_FORMAT,
788
0
                                             pdu, transport);
789
0
      }
790
0
        }
791
0
    }
792
0
    snmp_log(LOG_INFO, "%s%s", rbuf, (trunc?" [TRUNCATED]\n":""));
793
0
    free(rbuf);
794
0
    return NETSNMPTRAPD_HANDLER_OK;
795
0
}
796
797
798
0
#define EXECUTE_FORMAT  "%B\n%b\n%V\n%v\n"
799
800
/*
801
 *  Trap handler for invoking a suitable script
802
 */
803
int   command_handler( netsnmp_pdu           *pdu,
804
                       netsnmp_transport     *transport,
805
                       netsnmp_trapd_handler *handler)
806
0
{
807
#ifndef USING_UTILITIES_EXECUTE_MODULE
808
    NETSNMP_LOGONCE((LOG_WARNING,
809
                     "support for run_shell_command not available\n"));
810
    return NETSNMPTRAPD_HANDLER_FAIL;
811
#else
812
0
    u_char         *rbuf = NULL;
813
0
    size_t          r_len = 64, o_len = 0;
814
0
    int             oldquick;
815
816
0
    netsnmp_assert(handler);
817
818
0
    DEBUGMSGTL(( "snmptrapd", "command_handler\n"));
819
0
    DEBUGMSGTL(( "snmptrapd", "token = '%s'\n", handler->token));
820
0
    if (handler->token && *handler->token) {
821
0
  netsnmp_pdu    *v2_pdu = NULL;
822
0
  if (pdu->command == SNMP_MSG_TRAP)
823
0
      v2_pdu = convert_v1pdu_to_v2(pdu);
824
0
  else
825
0
      v2_pdu = pdu;
826
0
        oldquick = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
827
0
                                          NETSNMP_DS_LIB_QUICK_PRINT);
828
0
        netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
829
0
                               NETSNMP_DS_LIB_QUICK_PRINT, 1);
830
831
        /*
832
   * Format the trap and pass this string to the external command
833
   */
834
0
        if ((rbuf = calloc(r_len, 1)) == NULL) {
835
0
            snmp_log(LOG_ERR, "couldn't display trap -- malloc failed\n");
836
0
            return NETSNMPTRAPD_HANDLER_FAIL; /* Failed but keep going */
837
0
        }
838
839
        /*
840
         *  If there's a format string registered for this trap, then use it.
841
         *  Otherwise use the standard execution format setting.
842
         */
843
0
        if (handler->format && *handler->format) {
844
0
            DEBUGMSGTL(( "snmptrapd", "format = '%s'\n", handler->format));
845
0
            realloc_format_trap(&rbuf, &r_len, &o_len, 1,
846
0
                                             handler->format,
847
0
                                             v2_pdu, transport);
848
0
        } else {
849
0
      if ( pdu->command == SNMP_MSG_TRAP && exec_format1 ) {
850
0
                DEBUGMSGTL(( "snmptrapd", "exec v1 = '%s'\n", exec_format1));
851
0
                realloc_format_trap(&rbuf, &r_len, &o_len, 1,
852
0
                                             exec_format1, pdu, transport);
853
0
      } else if ( pdu->command != SNMP_MSG_TRAP && exec_format2 ) {
854
0
                DEBUGMSGTL(( "snmptrapd", "exec v2/3 = '%s'\n", exec_format2));
855
0
                realloc_format_trap(&rbuf, &r_len, &o_len, 1,
856
0
                                             exec_format2, pdu, transport);
857
0
      } else {
858
0
                DEBUGMSGTL(( "snmptrapd", "execute format\n"));
859
0
                realloc_format_trap(&rbuf, &r_len, &o_len, 1, EXECUTE_FORMAT,
860
0
                                             v2_pdu, transport);
861
0
            }
862
0
  }
863
864
        /*
865
         *  and pass this formatted string to the command specified
866
         */
867
0
        run_shell_command(handler->token, (char*)rbuf, NULL, NULL);   /* Not interested in output */
868
0
        netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
869
0
                               NETSNMP_DS_LIB_QUICK_PRINT, oldquick);
870
0
        if (pdu->command == SNMP_MSG_TRAP)
871
0
            snmp_free_pdu(v2_pdu);
872
0
        free(rbuf);
873
0
    }
874
0
    return NETSNMPTRAPD_HANDLER_OK;
875
0
#endif /* !def USING_UTILITIES_EXECUTE_MODULE */
876
0
}
877
878
879
880
881
/*
882
 *  Trap handler for forwarding to the AgentX master agent
883
 */
884
int axforward_handler( netsnmp_pdu           *pdu,
885
                       netsnmp_transport     *transport,
886
                       netsnmp_trapd_handler *handler)
887
0
{
888
0
    send_v2trap( pdu->variables );
889
0
    return NETSNMPTRAPD_HANDLER_OK;
890
0
}
891
892
static int add_forwarder_info(netsnmp_pdu *pdu, netsnmp_pdu *pdu2)
893
0
{
894
0
    netsnmp_indexed_addr_pair *addr_pair1;
895
0
    struct sockaddr_in *to1 = NULL;
896
0
    struct sockaddr_in *to2 = NULL;
897
0
    int            last_snmpTrapAddress_index = -1;
898
    /* snmpTrapAddress_oid.0 is also defined as agentaddr_oid */
899
0
    const oid      snmpTrapAddress_oid[]   = { 1,3,6,1,6,3,18,1,3};
900
    /* each forwarder will add this OID with changed last index */
901
0
    oid            forwarder_oid[]   =       { 1,3,6,1,6,3,18,1,3,0};
902
0
    const size_t   snmpTrapAddress_oid_size = OID_LENGTH(snmpTrapAddress_oid);
903
0
    const size_t   forwarder_oid_len = OID_LENGTH(forwarder_oid);
904
0
    struct in_addr agent_addr;
905
0
    struct in_addr my_ip_addr;
906
907
0
    memset(&agent_addr, 0, sizeof(agent_addr));
908
0
    memset(&my_ip_addr, 0, sizeof(my_ip_addr));
909
910
0
    if (pdu && pdu->transport_data &&
911
0
        pdu->transport_data_length == sizeof(*addr_pair1)) {
912
0
        addr_pair1 = (netsnmp_indexed_addr_pair *)pdu->transport_data;
913
914
        /*
915
         * Get the IPv4 address of the host that this trap was sent from =
916
         * last forwarder's IP address.
917
         */
918
0
        if (addr_pair1->remote_addr.sa.sa_family == AF_INET) {
919
0
            to1 = (struct sockaddr_in *)&(addr_pair1->remote_addr);
920
0
            agent_addr = to1->sin_addr;
921
0
        }
922
        /*
923
         * Get the IPv4 address of the host that this trap was sent to =
924
         * this forwarder's IP address.
925
         */
926
0
        if (addr_pair1->local_addr.sa.sa_family == AF_INET) {
927
0
            to2 = (struct sockaddr_in *)&(addr_pair1->local_addr);
928
0
            my_ip_addr = to2->sin_addr;
929
0
        }
930
0
    }
931
932
0
    if (to1) {
933
0
        netsnmp_variable_list *vblist = NULL;
934
0
        netsnmp_variable_list *var = NULL;
935
936
0
        if (*(in_addr_t *)pdu2->agent_addr == INADDR_ANY) {
937
            /*
938
             * there was no agent address defined in PDU. copy the forwarding
939
             * agent IP address from the transport socket.
940
             */
941
0
            *(struct in_addr *)pdu2->agent_addr = agent_addr;
942
0
        }
943
944
0
        vblist = pdu2->variables;
945
946
        /*
947
         * Iterate over all varbinds in the PDU to see if it already has any
948
         * forwarder information.
949
         */
950
0
        for (var = vblist; var; var = var->next_variable) {
951
0
            if (snmp_oid_ncompare(var->name, var->name_length,
952
0
                                  snmpTrapAddress_oid,
953
0
                                  snmpTrapAddress_oid_size,
954
0
                                  snmpTrapAddress_oid_size) == 0) {
955
0
                int my_snmpTrapAddress_index =
956
0
                    var->name[var->name_length - 1];
957
958
0
                DEBUGMSGTL(("snmptrapd", "  my_snmpTrapAddress_index=%d, last_snmpTrapAddress_index=%d, my_ip_addr=%s\n",
959
0
                            my_snmpTrapAddress_index,
960
0
                            last_snmpTrapAddress_index,
961
0
                            inet_ntoa(my_ip_addr)));
962
963
0
                if (last_snmpTrapAddress_index < my_snmpTrapAddress_index)
964
0
                    last_snmpTrapAddress_index = my_snmpTrapAddress_index;
965
966
                /* Detect forwarding loop. */
967
0
                if (var->val_len < 4) {
968
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",
969
0
                             my_snmpTrapAddress_index, 4,
970
0
                             (int)var->val_len);
971
0
                } else {
972
0
                    if (to2 &&
973
0
                        memcmp(var->val.string, &my_ip_addr, 4) == 0) {
974
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",
975
0
                                 my_snmpTrapAddress_index,
976
0
                                 inet_ntoa(my_ip_addr));
977
0
                        return 0;
978
0
                    }
979
0
                    if (memcmp(var->val.string, &agent_addr, 4) == 0) {
980
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",
981
0
                                 my_snmpTrapAddress_index,
982
0
                                 inet_ntoa(agent_addr));
983
0
                        return 0;
984
0
                    }
985
0
                }
986
0
            }
987
0
        } /* for var in vblist */
988
989
0
        DEBUGMSGTL(("snmptrapd",
990
0
                    "  last_snmpTrapAddress_index=%d, adding index=%d\n",
991
0
                    last_snmpTrapAddress_index, last_snmpTrapAddress_index+1));
992
        /* Change the last index of this OID to the next available number. */
993
0
        forwarder_oid[forwarder_oid_len - 1] = last_snmpTrapAddress_index + 1;
994
995
        /*
996
         * Add forwarder IP address as OID to trap payload. Use the value
997
         * from the transport, so if a v1 PDU is sent, the same IP is not
998
         * duplicated you want every forwarder to add this OID with its
999
         * own IP address.
1000
         */
1001
0
        snmp_pdu_add_variable(pdu2, forwarder_oid, forwarder_oid_len,
1002
0
                              ASN_IPADDRESS, (u_char *)&agent_addr, 4);
1003
0
    }
1004
0
    return 1;
1005
0
}
1006
1007
/*
1008
 *  Trap handler for forwarding to another destination
1009
 */
1010
int   forward_handler( netsnmp_pdu           *pdu,
1011
                       netsnmp_transport     *transport,
1012
                       netsnmp_trapd_handler *handler)
1013
0
{
1014
0
    netsnmp_session session, *ss;
1015
0
    netsnmp_pdu *pdu2;
1016
0
    char buf[BUFSIZ], *cp;
1017
1018
0
    DEBUGMSGTL(( "snmptrapd", "forward_handler (%s)\n", handler->token));
1019
1020
0
    snmp_sess_init( &session );
1021
0
    if (strchr( handler->token, ':') == NULL) {
1022
0
        snprintf( buf, BUFSIZ, "%s:%d", handler->token, SNMP_TRAP_PORT);
1023
0
        cp = buf;
1024
0
    } else {
1025
0
        cp = handler->token;
1026
0
    }
1027
0
    session.peername = cp;
1028
0
    session.version  = pdu->version;
1029
0
    ss = snmp_open( &session );
1030
0
    if (!ss)
1031
0
        return NETSNMPTRAPD_HANDLER_FAIL;
1032
1033
    /* XXX: wjh we should be caching sessions here and not always
1034
       reopening a session.  It's very inefficient, especially with v3
1035
       INFORMS which may require engineID probing */
1036
1037
0
    pdu2 = snmp_clone_pdu(pdu);
1038
1039
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1040
0
                               NETSNMP_DS_LIB_ADD_FORWARDER_INFO) &&
1041
0
        !add_forwarder_info(pdu, pdu2)) {
1042
0
        snmp_close(ss);
1043
0
        return NETSNMPTRAPD_HANDLER_FAIL;
1044
0
    }
1045
1046
0
    if (pdu2->transport_data) {
1047
0
        free(pdu2->transport_data);
1048
0
        pdu2->transport_data        = NULL;
1049
0
        pdu2->transport_data_length = 0;
1050
0
    }
1051
1052
0
    ss->s_snmp_errno = SNMPERR_SUCCESS;
1053
0
    if (!snmp_send( ss, pdu2 ) &&
1054
0
            ss->s_snmp_errno != SNMPERR_SUCCESS) {
1055
0
        snmp_sess_perror("Forward failed", ss);
1056
0
        snmp_free_pdu(pdu2);
1057
0
    }
1058
0
    snmp_close( ss );
1059
0
    return NETSNMPTRAPD_HANDLER_OK;
1060
0
}
1061
1062
#if defined(USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE) && defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
1063
/*
1064
 *  "Notification" handler for implementing NOTIFICATION-MIB
1065
 *      (presumably)
1066
 */
1067
int   notification_handler(netsnmp_pdu           *pdu,
1068
                           netsnmp_transport     *transport,
1069
                           netsnmp_trapd_handler *handler)
1070
0
{
1071
0
    DEBUGMSGTL(( "snmptrapd", "notification_handler\n"));
1072
0
    log_notification(pdu, transport);
1073
0
    return NETSNMPTRAPD_HANDLER_OK;
1074
0
}
1075
#endif 
1076
1077
/*-----------------------------
1078
 *
1079
 * Main driving code, to process an incoming trap
1080
 *
1081
 *-----------------------------*/
1082
1083
1084
1085
int
1086
snmp_input(int op, netsnmp_session *session,
1087
           int reqid, netsnmp_pdu *pdu, void *magic)
1088
400
{
1089
400
    oid stdTrapOidRoot[] = { 1, 3, 6, 1, 6, 3, 1, 1, 5 };
1090
400
    oid snmpTrapOid[]    = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
1091
400
    oid trapOid[MAX_OID_LEN+2] = {0};
1092
400
    int trapOidLen;
1093
400
    netsnmp_variable_list *vars;
1094
400
    netsnmp_trapd_handler *traph;
1095
400
    netsnmp_transport *transport = (netsnmp_transport *) magic;
1096
400
    int ret, idx;
1097
1098
400
    switch (op) {
1099
400
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
1100
        /*
1101
         * Drops packets with reception problems
1102
         */
1103
400
        if (session->s_snmp_errno) {
1104
            /* drop problem packets */
1105
0
            return 1;
1106
0
        }
1107
1108
        /*
1109
   * Determine the OID that identifies the trap being handled
1110
   */
1111
400
        DEBUGMSGTL(("snmptrapd", "input: %x\n", pdu->command));
1112
400
        switch (pdu->command) {
1113
322
        case SNMP_MSG_TRAP:
1114
            /*
1115
       * Convert v1 traps into a v2-style trap OID
1116
       *    (following RFC 2576)
1117
       */
1118
322
            if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
1119
127
                trapOidLen = pdu->enterprise_length;
1120
                /*
1121
                 * Drop packets that would trigger an out-of-bounds trapOid[]
1122
                 * access.
1123
                 */
1124
127
                if (trapOidLen < 1 || trapOidLen > OID_LENGTH(trapOid) - 2)
1125
12
                    return 1;
1126
115
                memcpy(trapOid, pdu->enterprise, sizeof(oid) * trapOidLen);
1127
115
                if (trapOid[trapOidLen - 1] != 0) {
1128
113
                    trapOid[trapOidLen++] = 0;
1129
113
                }
1130
115
                trapOid[trapOidLen++] = pdu->specific_type;
1131
195
            } else {
1132
195
                memcpy(trapOid, stdTrapOidRoot, sizeof(stdTrapOidRoot));
1133
195
                trapOidLen = OID_LENGTH(stdTrapOidRoot);  /* 9 */
1134
                /* Drop packets with an invalid trap type. */
1135
195
                if (pdu->trap_type == LONG_MAX)
1136
3
                    return 1;
1137
192
                trapOid[trapOidLen++] = pdu->trap_type+1;
1138
192
            }
1139
307
            break;
1140
1141
307
        case SNMP_MSG_TRAP2:
1142
27
        case SNMP_MSG_INFORM:
1143
            /*
1144
       * v2c/v3 notifications *should* have snmpTrapOID as the
1145
       *    second varbind, so we can go straight there.
1146
       *    But check, just to make sure
1147
       */
1148
27
            vars = pdu->variables;
1149
27
            if (vars)
1150
27
                vars = vars->next_variable;
1151
27
            if (!vars || snmp_oid_compare(vars->name, vars->name_length,
1152
27
                                          snmpTrapOid, OID_LENGTH(snmpTrapOid))) {
1153
          /*
1154
     * Didn't find it!
1155
     * Let's look through the full list....
1156
     */
1157
0
    for ( vars = pdu->variables; vars; vars=vars->next_variable) {
1158
0
                    if (vars->type != ASN_OBJECT_ID)
1159
0
                        continue;
1160
0
                    if (!snmp_oid_compare(vars->name, vars->name_length,
1161
0
                                          snmpTrapOid, OID_LENGTH(snmpTrapOid)))
1162
0
                        break;
1163
0
                }
1164
0
                if (!vars) {
1165
              /*
1166
         * Still can't find it!  Give up.
1167
         */
1168
0
        snmp_log(LOG_ERR, "Cannot find TrapOID in TRAP2 PDU\n");
1169
0
        return 1;   /* ??? */
1170
0
    }
1171
0
      }
1172
27
            trapOidLen = SNMP_MIN(sizeof(trapOid), vars->val_len) / sizeof(oid);
1173
27
            memcpy(trapOid, vars->val.objid, trapOidLen * sizeof(oid));
1174
27
            break;
1175
1176
51
        default:
1177
            /* SHOULDN'T HAPPEN! */
1178
51
            return 1; /* ??? */
1179
400
  }
1180
334
        DEBUGMSGTL(( "snmptrapd", "Trap OID: "));
1181
334
        DEBUGMSGOID(("snmptrapd", trapOid, trapOidLen));
1182
334
        DEBUGMSG(( "snmptrapd", "\n"));
1183
1184
1185
        /*
1186
   *  OK - We've found the Trap OID used to identify this trap.
1187
         *  Call each of the various lists of handlers:
1188
         *     a) authentication-related handlers,
1189
         *     b) other handlers to be applied to all traps
1190
         *    (*before* trap-specific handlers)
1191
         *     c) the handler(s) specific to this trap
1192
t        *     d) any other global handlers
1193
         *
1194
   *  In each case, a particular trap handler can abort further
1195
         *     processing - either just for that particular list,
1196
         *     or for the trap completely.
1197
         *
1198
   *  This is particularly designed for authentication-related
1199
   *     handlers, but can also be used elsewhere.
1200
         *
1201
         *  OK - Enough waffling, let's get to work.....
1202
   */
1203
1204
1.67k
        for( idx = 0; handlers[idx].descr; ++idx ) {
1205
1.33k
            DEBUGMSGTL(("snmptrapd", "Running %s handlers\n",
1206
1.33k
                        handlers[idx].descr));
1207
1.33k
            if (NULL == handlers[idx].handler) /* specific */
1208
334
                traph = netsnmp_get_traphandler(trapOid, trapOidLen);
1209
1.00k
            else
1210
1.00k
                traph = *handlers[idx].handler;
1211
1212
1.33k
            for( ; traph; traph = traph->nexth) {
1213
0
                if (!netsnmp_trapd_check_auth(traph->authtypes))
1214
0
                    continue; /* we continue on and skip this one */
1215
1216
0
                ret = (*(traph->handler))(pdu, transport, traph);
1217
0
                if(NETSNMPTRAPD_HANDLER_FINISH == ret)
1218
0
                    return 1;
1219
0
                if (ret == NETSNMPTRAPD_HANDLER_BREAK)
1220
0
                    break; /* move on to next type */
1221
0
            } /* traph */
1222
1.33k
        } /* handlers */
1223
1224
1225
334
  if (pdu->command == SNMP_MSG_INFORM) {
1226
26
      netsnmp_pdu *reply = snmp_clone_pdu(pdu);
1227
26
      if (!reply) {
1228
0
    snmp_log(LOG_ERR, "couldn't clone PDU for INFORM response\n");
1229
26
      } else {
1230
26
    reply->command = SNMP_MSG_RESPONSE;
1231
26
    reply->errstat = 0;
1232
26
    reply->errindex = 0;
1233
26
    if (!snmp_send(session, reply)) {
1234
26
        snmp_sess_perror("snmptrapd: Couldn't respond to inform pdu",
1235
26
                                    session);
1236
26
        snmp_free_pdu(reply);
1237
26
    }
1238
26
      }
1239
26
  }
1240
1241
334
        break;
1242
1243
0
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
1244
0
        snmp_log(LOG_ERR, "Timeout: This shouldn't happen!\n");
1245
0
        break;
1246
1247
0
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
1248
0
        snmp_log(LOG_ERR, "Send Failed: This shouldn't happen either!\n");
1249
0
        break;
1250
1251
0
    case NETSNMP_CALLBACK_OP_CONNECT:
1252
0
    case NETSNMP_CALLBACK_OP_DISCONNECT:
1253
        /* Ignore silently */
1254
0
        break;
1255
1256
0
    default:
1257
0
        snmp_log(LOG_ERR, "Unknown operation (%d): This shouldn't happen!\n", op);
1258
0
        break;
1259
400
    }
1260
334
    return 0;
1261
400
}
1262