Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/agent/agent_trap.c
Line
Count
Source
1
/*
2
 * agent_trap.c
3
 */
4
/* Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 */
8
/*
9
 * Portions of this file are copyrighted by:
10
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
11
 * Use is subject to license terms specified in the COPYING file
12
 * distributed with the Net-SNMP package.
13
 *
14
 * Portions of this file are copyrighted by:
15
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
16
 * Use is subject to license terms specified in the COPYING file
17
 * distributed with the Net-SNMP package.
18
 */
19
/** @defgroup agent_trap Trap generation routines for mib modules to use
20
 *  @ingroup agent
21
 *
22
 * @{
23
 */
24
25
#include <net-snmp/net-snmp-config.h>
26
#include <net-snmp/net-snmp-features.h>
27
28
#ifdef HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
#ifdef HAVE_NETDB_H
32
#include <netdb.h>
33
#endif
34
#ifdef HAVE_STDLIB_H
35
#include <stdlib.h>
36
#endif
37
#ifdef HAVE_STRING_H
38
#include <string.h>
39
#else
40
#include <strings.h>
41
#endif
42
#ifdef TIME_WITH_SYS_TIME
43
# include <sys/time.h>
44
# include <time.h>
45
#else
46
# ifdef HAVE_SYS_TIME_H
47
#  include <sys/time.h>
48
# else
49
#  include <time.h>
50
# endif
51
#endif
52
#ifdef HAVE_SYS_SOCKET_H
53
#include <sys/socket.h>
54
#endif
55
#ifdef HAVE_NETINET_IN_H
56
#include <netinet/in.h>
57
#endif
58
#include <net-snmp/utilities.h>
59
60
#include <net-snmp/net-snmp-includes.h>
61
#include <net-snmp/agent/net-snmp-agent-includes.h>
62
#include <net-snmp/agent/agent_trap.h>
63
#include <net-snmp/agent/snmp_agent.h>
64
#include <net-snmp/agent/agent_callbacks.h>
65
#include "agent_global_vars.h"
66
67
#include <net-snmp/agent/agent_module_config.h>
68
#include <net-snmp/agent/mib_module_config.h>
69
70
#ifdef USING_AGENTX_PROTOCOL_MODULE
71
#include "agentx/protocol.h"
72
#endif
73
74
#ifdef USING_NOTIFICATION_SNMPNOTIFYTABLE_DATA_MODULE
75
#include "mibgroup/notification/snmpNotifyTable_data.h"
76
#endif
77
78
netsnmp_feature_child_of(agent_trap_all, libnetsnmpagent);
79
80
netsnmp_feature_child_of(trap_vars_with_context, agent_trap_all);
81
netsnmp_feature_child_of(remove_trap_session, agent_trap_all);
82
83
netsnmp_feature_child_of(send_v3trap,netsnmp_unused);
84
netsnmp_feature_child_of(send_trap_pdu,netsnmp_unused);
85
86
struct trap_sink {
87
    netsnmp_session *sesp;
88
    struct trap_sink *next;
89
    int             pdutype;
90
    int             version;
91
};
92
93
struct trap_sink *sinks = NULL;
94
95
const oid       objid_enterprisetrap[] = { NETSNMP_NOTIFICATION_MIB };
96
const oid       trap_version_id[] = { NETSNMP_SYSTEM_MIB };
97
const int       enterprisetrap_len = OID_LENGTH(objid_enterprisetrap);
98
const int       trap_version_id_len = OID_LENGTH(trap_version_id);
99
100
#define SNMPV2_TRAPS_PREFIX SNMP_OID_SNMPMODULES,1,1,5
101
const oid       trap_prefix[]    = { SNMPV2_TRAPS_PREFIX };
102
const oid       cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 };  /* SNMPv2-MIB */
103
104
#define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4
105
const oid       snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 };
106
const oid       snmptrapenterprise_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 };
107
const oid       sysuptime_oid[] = { SNMP_OID_MIB2, 1, 3, 0 };
108
const size_t    snmptrap_oid_len = OID_LENGTH(snmptrap_oid);
109
const size_t    snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid);
110
const size_t    sysuptime_oid_len = OID_LENGTH(sysuptime_oid);
111
112
#define SNMPV2_COMM_OBJS_PREFIX SNMP_OID_SNMPMODULES,18,1
113
const oid       agentaddr_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 3, 0 };
114
const size_t    agentaddr_oid_len = OID_LENGTH(agentaddr_oid);
115
const oid       community_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 4, 0 };
116
const size_t    community_oid_len = OID_LENGTH(community_oid);
117
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
118
char           *snmp_trapcommunity = NULL;
119
#endif
120
121
122
0
#define SNMP_AUTHENTICATED_TRAPS_ENABLED  1
123
0
#define SNMP_AUTHENTICATED_TRAPS_DISABLED 2
124
125
long            snmp_enableauthentraps = SNMP_AUTHENTICATED_TRAPS_DISABLED;
126
int             snmp_enableauthentrapsset = 0;
127
128
/*
129
 * Prototypes 
130
 */
131
 /*
132
  * static void free_trap_session (struct trap_sink *sp);
133
  * static void send_v1_trap (netsnmp_session *, int, int);
134
  * static void send_v2_trap (netsnmp_session *, int, int, int);
135
  */
136
137
138
        /*******************
139
   *
140
   * Trap session handling
141
   *
142
   *******************/
143
144
void
145
init_traps(void)
146
3.36k
{
147
3.36k
}
148
149
static void
150
free_trap_session(struct trap_sink *sp)
151
0
{
152
0
    DEBUGMSGTL(("trap", "freeing callback trap session (%p, %p)\n", sp, sp->sesp));
153
0
    snmp_close(sp->sesp);
154
0
    free(sp);
155
0
}
156
157
#ifndef NETSNMP_NO_TRAP_STATS
158
static void
159
_dump_trap_stats(netsnmp_session *sess)
160
0
{
161
0
    if (NULL == sess || NULL == sess->trap_stats)
162
0
        return;
163
164
0
    DEBUGIF("stats:notif") {
165
0
        DEBUGMSGT_NC(("stats:notif", "%s inform stats\n", sess->paramName));
166
0
        DEBUGMSGT_NC(("stats:notif", "    %ld sends, last @ %ld\n",
167
0
                      sess->trap_stats->sent_count,
168
0
                      sess->trap_stats->sent_last_sent));
169
0
        DEBUGMSGT_NC(("stats:notif", "    %ld acks, last @ %ld\n",
170
0
                      sess->trap_stats->ack_count,
171
0
                      sess->trap_stats->ack_last_rcvd));
172
0
        DEBUGMSGT_NC(("stats:notif", "    %ld failed sends, last @ %ld\n",
173
0
                      sess->trap_stats->sent_fail_count,
174
0
                      sess->trap_stats->sent_last_fail));
175
0
        DEBUGMSGT_NC(("stats:notif", "    %ld timeouts, last @ %ld\n",
176
0
                      sess->trap_stats->timeouts,
177
0
                      sess->trap_stats->sent_last_timeout));
178
0
        DEBUGMSGT_NC(("stats:notif", "    %ld v3 errs, last @ %ld\n",
179
0
                      sess->trap_stats->sec_err_count,
180
0
                      sess->trap_stats->sec_err_last));
181
0
    }
182
0
}
183
#endif /* NETSNMP_NO_TRAP_STATS */
184
185
int
186
netsnmp_add_closable_notification_session(netsnmp_session *ss, int close_sess, int pdutype,
187
                                          int confirm, int version, const char *name,
188
                                          const char *tag, const char* profile)
189
0
{
190
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(version)) {
191
0
        DEBUGMSGTL(("trap", "skipping trap sink (version 0x%02x disabled)\n",
192
0
                    version));
193
0
        return 0;
194
0
    }
195
0
    if (snmp_callback_available(SNMP_CALLBACK_APPLICATION,
196
0
                                SNMPD_CALLBACK_REGISTER_NOTIFICATIONS) ==
197
0
        SNMPERR_SUCCESS) {
198
        /*
199
         * something else wants to handle notification registrations 
200
         */
201
0
        struct agent_add_trap_args args;
202
0
        DEBUGMSGTL(("trap", "adding callback trap sink (%p)\n", ss));
203
0
        args.ss = ss;
204
0
        args.close_sess = close_sess;
205
0
        args.confirm = confirm;
206
0
        args.nameData = name;
207
0
        args.nameLen = (NULL == name) ? 0 : strlen(name);
208
0
        args.tagData = tag;
209
0
        args.tagLen = (NULL == tag) ? 0 : strlen(tag);
210
0
        args.profileData = profile;
211
0
        args.profileLen = (NULL == profile) ? 0: strlen(profile);
212
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
213
0
                            SNMPD_CALLBACK_REGISTER_NOTIFICATIONS,
214
0
                            (void *) &args);
215
0
        if (args.rc != SNMPERR_SUCCESS)
216
0
            return 0;
217
0
    } else {
218
        /*
219
         * no other support exists, handle it ourselves. 
220
         */
221
0
        struct trap_sink *new_sink;
222
223
0
        DEBUGMSGTL(("trap", "adding internal trap sink\n"));
224
0
        new_sink = (struct trap_sink *) malloc(sizeof(*new_sink));
225
0
        if (new_sink == NULL)
226
0
            return 0;
227
228
0
        new_sink->sesp = ss;
229
0
        new_sink->pdutype = pdutype;
230
0
        new_sink->version = version;
231
0
        new_sink->next = sinks;
232
0
        sinks = new_sink;
233
0
    }
234
235
0
    return 1;
236
0
}
237
238
/* This is a wrapper to netsnmp_add_closable_notification_session
239
   for backward compatibility
240
 */
241
int
242
netsnmp_add_notification_session(netsnmp_session *ss, int pdutype,
243
                                 int confirm, int version, const char *name,
244
                                 const char *tag, const char* profile)
245
0
{
246
0
    return netsnmp_add_closable_notification_session(ss, 1, pdutype, confirm,
247
0
                                                     version, name,
248
0
                                                     tag, profile);
249
0
}
250
251
/*
252
 * xxx needs update to support embedded NUL.
253
 * xxx should probably also be using and unregister callback, similar to
254
 *     how registration is done.
255
 */
256
void
257
netsnmp_unregister_notification(const char *name, u_char len)
258
0
{
259
0
    if (snmp_callback_available(SNMP_CALLBACK_APPLICATION,
260
0
                                SNMPD_CALLBACK_UNREGISTER_NOTIFICATIONS) ==
261
0
        SNMPERR_SUCCESS) {
262
        /*
263
         * something else wants to handle notification registrations 
264
         */
265
0
        struct agent_add_trap_args args;
266
0
        DEBUGMSGTL(("trap", "removing callback trap sink\n"));
267
0
        args.nameData = name;
268
0
        args.nameLen = len;
269
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
270
0
                            SNMPD_CALLBACK_UNREGISTER_NOTIFICATIONS,
271
0
                            (void *) &args);
272
0
    } else
273
0
        NETSNMP_LOGONCE((LOG_WARNING,
274
0
                         "netsnmp_unregister_notification not supported\n"));
275
0
}
276
277
int
278
handle_disconnect_packet(int operation, netsnmp_session *session, int reqid,
279
                            netsnmp_pdu *pdu, void *magic)
280
0
{
281
0
    if (NETSNMP_CALLBACK_OP_DISCONNECT == operation) {
282
0
        netsnmp_transport *t = snmp_sess_transport(snmp_sess_pointer(session));
283
0
        char *addr_string = NULL;
284
285
0
        if (t && (addr_string = netsnmp_transport_peer_string(t, t->remote, t->remote_length))) {
286
0
            snmp_log(LOG_WARNING,
287
0
                        "send_trap: session closed by snmptrap (%s)\n", addr_string);
288
0
            free(addr_string);
289
0
        } else {
290
0
            snmp_log(LOG_WARNING,
291
0
                        "send_trap: session %8p closed by snmptrap\n", session);
292
0
        }
293
0
        snmp_log(LOG_WARNING,
294
0
                    "send_trap: re-opening of TCP connection is not supported.\n");
295
296
0
        netsnmp_unregister_notification(session->paramName, strlen(session->paramName));
297
0
    }
298
0
    return 1;
299
0
}
300
301
int
302
add_trap_session(netsnmp_session * ss, int pdutype, int confirm,
303
                         int version)
304
0
{
305
0
    return netsnmp_add_closable_notification_session(ss, 0, pdutype, confirm, version,
306
0
                                                     NULL, NULL, NULL);
307
0
}
308
309
#ifndef NETSNMP_FEATURE_REMOVE_REMOVE_TRAP_SESSION
310
int
311
remove_trap_session(netsnmp_session * ss)
312
0
{
313
0
    struct trap_sink *sp = sinks, *prev = NULL;
314
315
0
    DEBUGMSGTL(("trap", "removing trap sessions\n"));
316
0
    while (sp) {
317
0
        if (sp->sesp == ss) {
318
0
            if (prev) {
319
0
                prev->next = sp->next;
320
0
            } else {
321
0
                sinks = sp->next;
322
0
            }
323
            /*
324
             * I don't believe you *really* want to close the session here;
325
             * it may still be in use for other purposes.  In particular this
326
             * is awkward for AgentX, since we want to call this function
327
             * from the session's callback.  Let's just free the trapsink
328
             * data structure.  [jbpn]  
329
             */
330
            /*
331
             * free_trap_session(sp);  
332
             */
333
0
            DEBUGMSGTL(("trap", "removing trap session (%p, %p)\n", sp, sp->sesp));
334
0
            free(sp);
335
0
            return 1;
336
0
        }
337
0
        prev = sp;
338
0
        sp = sp->next;
339
0
    }
340
0
    return 0;
341
0
}
342
#endif /* NETSNMP_FEATURE_REMOVE_REMOVE_TRAP_SESSION */
343
344
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
345
netsnmp_session *
346
netsnmp_create_v1v2_notification_session(const char *sink, const char* sinkport,
347
                                         const char *com, const char *src,
348
                                         int version, int pdutype,
349
                                         const char *name, const char *tag,
350
                                         const char* profile)
351
0
{
352
0
    netsnmp_transport *t;
353
0
    netsnmp_session session, *sesp;
354
0
    netsnmp_tdomain_spec tspec;
355
0
    char                 tmp[SPRINT_MAX_LEN];
356
0
    int                  rc;
357
0
    const char          *client_addr = NULL;
358
359
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(version)) {
360
0
        config_perror("SNMP version disabled");
361
0
        DEBUGMSGTL(("trap", "skipping trap sink (version 0x%02x disabled)\n",
362
0
                    version));
363
0
        return NULL;
364
0
    }
365
366
0
    snmp_sess_init(&session);
367
0
    session.callback = handle_disconnect_packet;
368
0
    session.version = version;
369
0
    if (com) {
370
0
        session.community = (u_char *)strdup(com);
371
0
        session.community_len = strlen(com);
372
0
    }
373
374
    /*
375
     * for informs, set retries to default
376
     */
377
0
    if (SNMP_MSG_INFORM == pdutype) {
378
0
        session.timeout = SNMP_DEFAULT_TIMEOUT;
379
0
        session.retries = SNMP_DEFAULT_RETRIES;
380
0
    }
381
382
0
    memset(&tspec, 0, sizeof(netsnmp_tdomain_spec));
383
384
    /*
385
     * use specified source or client addr, if available. If no, and
386
     * if the sink is localhost, bind to localhost, to reduce open ports.
387
     */
388
0
    if (NULL != src)
389
0
        tspec.source = src;
390
0
    else {
391
0
        client_addr = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
392
0
                                            NETSNMP_DS_LIB_CLIENT_ADDR);
393
0
        if ((NULL == client_addr) &&
394
0
            ((0 == strcmp("localhost",sink)) ||
395
0
             (0 == strcmp("127.0.0.1",sink))))
396
0
            client_addr = "localhost";
397
0
        tspec.source = client_addr;
398
0
    }
399
0
    session.localname = tspec.source ? strdup(tspec.source) : NULL;
400
401
0
    tspec.application = "snmptrap";
402
0
    if (NULL == sinkport)
403
0
        tspec.target = sink;
404
0
    else {
405
0
        snprintf(tmp, sizeof(tmp)-1,"%s:%s", sink, sinkport);
406
0
        tspec.target = tmp;
407
0
    }
408
0
    tspec.default_domain = NULL;
409
0
    tspec.default_target = sinkport;
410
0
    t = netsnmp_tdomain_transport_tspec(&tspec);
411
0
    if ((NULL == t) ||
412
0
        ((sesp = snmp_add(&session, t, NULL, NULL)) == NULL)) {
413
        /** diagnose snmp_open errors with the input netsnmp_session pointer */
414
0
        snmp_sess_perror("snmpd: netsnmp_create_notification_session",
415
0
                         &session);
416
0
        netsnmp_cleanup_session(&session);
417
        /* transport freed by snmp_add */
418
0
        return NULL;
419
0
    }
420
421
0
    netsnmp_cleanup_session(&session);
422
423
0
    rc = netsnmp_add_closable_notification_session(sesp,
424
0
                                                   !(t->flags & NETSNMP_TRANSPORT_FLAG_STREAM),
425
0
                                                   pdutype,
426
0
                                                   (pdutype == SNMP_MSG_INFORM),
427
0
                                                   version, name, tag, profile);
428
0
    if (0 == rc)
429
0
        return NULL;
430
431
0
    return sesp;
432
0
}
433
434
int
435
create_trap_session_with_src(const char *sink, const char* sinkport,
436
                             const char *com, const char *src, int version,
437
                             int pdutype)
438
0
{
439
0
    void *ss = netsnmp_create_v1v2_notification_session(sink, sinkport, com,
440
0
                                                        src, version, pdutype,
441
0
                                                        NULL, NULL, NULL);
442
0
    return (ss != NULL);
443
0
}
444
445
int
446
create_trap_session2(const char *sink, const char* sinkport,
447
                     char *com, int version, int pdutype)
448
0
{
449
0
    return create_trap_session_with_src(sink, sinkport, com, NULL, version,
450
0
                                        pdutype);
451
0
}
452
453
int
454
create_trap_session(char *sink, u_short sinkport,
455
        char *com, int version, int pdutype)
456
0
{
457
0
    void *ss;
458
0
    char buf[sizeof(sinkport) * 3 + 2];
459
0
    if (sinkport != 0) {
460
0
  snprintf(buf, sizeof(buf), ":%hu", sinkport);
461
0
  snmp_log(LOG_NOTICE,
462
0
     "Using a separate port number is deprecated, please correct "
463
0
     "the sink specification instead");
464
0
    }
465
0
    ss = netsnmp_create_v1v2_notification_session(sink, sinkport ? buf : NULL,
466
0
                                                  com, NULL, version, pdutype,
467
0
                                                  NULL, NULL, NULL);
468
0
    return (ss != NULL);
469
0
}
470
471
#endif /* support for community based SNMP */
472
473
void
474
snmpd_free_trapsinks(void)
475
26.8k
{
476
26.8k
    struct trap_sink *sp = sinks;
477
26.8k
    DEBUGMSGTL(("trap", "freeing trap sessions\n"));
478
26.8k
    while (sp) {
479
0
        sinks = sinks->next;
480
0
        free_trap_session(sp);
481
0
        sp = sinks;
482
0
    }
483
26.8k
}
484
485
        /*******************
486
   *
487
   * Trap handling
488
   *
489
   *******************/
490
491
492
netsnmp_pdu*
493
convert_v2pdu_to_v1( netsnmp_pdu* template_v2pdu )
494
0
{
495
0
    netsnmp_pdu           *template_v1pdu;
496
0
    netsnmp_variable_list *first_vb, *vblist;
497
0
    netsnmp_variable_list *var;
498
0
    size_t                 trap_oid_len;
499
500
0
    if (!template_v2pdu)
501
0
        return NULL;
502
503
    /*
504
     * Make a copy of the v2 Trap PDU
505
     *   before starting to convert this
506
     *   into a v1 Trap PDU.
507
     */
508
0
    template_v1pdu = snmp_clone_pdu( template_v2pdu);
509
0
    if (!template_v1pdu) {
510
0
        snmp_log(LOG_WARNING,
511
0
                 "send_trap: failed to copy v1 template PDU\n");
512
0
        return NULL;
513
0
    }
514
0
    template_v1pdu->command = SNMP_MSG_TRAP;
515
0
    first_vb = template_v1pdu->variables;
516
0
    vblist   = template_v1pdu->variables;
517
518
    /*
519
     * The first varbind should be the system uptime.
520
     */
521
0
    if (!vblist ||
522
0
        snmp_oid_compare(vblist->name,  vblist->name_length,
523
0
                         sysuptime_oid, sysuptime_oid_len) ||
524
0
        !vblist->val.integer ||
525
0
        vblist->val_len < sizeof(u_long) ||
526
0
        (vblist->type != ASN_TIMETICKS && vblist->type != ASN_INTEGER &&
527
0
         vblist->type != ASN_UINTEGER)) {
528
0
        snmp_log(LOG_WARNING,
529
0
                 "send_trap: no v2 sysUptime varbind to set from\n");
530
0
        snmp_free_pdu(template_v1pdu);
531
0
        return NULL;
532
0
    }
533
0
    template_v1pdu->time = *vblist->val.integer;
534
0
    vblist = vblist->next_variable;
535
            
536
    /*
537
     * The second varbind should be the snmpTrapOID.
538
     */
539
0
    if (!vblist ||
540
0
        snmp_oid_compare(vblist->name, vblist->name_length,
541
0
                         snmptrap_oid, snmptrap_oid_len) ||
542
0
        vblist->type != ASN_OBJECT_ID ||
543
0
        !vblist->val.objid ||
544
0
        vblist->val_len < sizeof(oid)) {
545
0
        snmp_log(LOG_WARNING,
546
0
                 "send_trap: no v2 trapOID varbind to set from\n");
547
0
        snmp_free_pdu(template_v1pdu);
548
0
        return NULL;
549
0
    }
550
551
0
    trap_oid_len = vblist->val_len / sizeof(oid);
552
0
    if (trap_oid_len > MAX_OID_LEN) {
553
0
        snmp_log(LOG_WARNING,
554
0
                 "send_trap: v2 trapOID too long (%" NETSNMP_PRIz "u)\n",
555
0
                 trap_oid_len);
556
0
        snmp_free_pdu(template_v1pdu);
557
0
        return NULL;
558
0
    }
559
560
    /*
561
     * Check the v2 varbind list for any varbinds
562
     *  that are not valid in an SNMPv1 trap.
563
     *  This basically means Counter64 values.
564
     *
565
     * RFC 2089 said to omit such varbinds from the list.
566
     * RFC 2576/3584 say to drop the trap completely.
567
     */
568
0
    for (var = vblist->next_variable; var; var = var->next_variable) {
569
0
        if ( var->type == ASN_COUNTER64 ) {
570
0
            snmp_log(LOG_WARNING,
571
0
                     "send_trap: v1 traps can't carry Counter64 varbinds\n");
572
0
            snmp_free_pdu(template_v1pdu);
573
0
            return NULL;
574
0
        }
575
0
    }
576
577
    /*
578
     * Set the generic & specific trap types,
579
     *    and the enterprise field from the v2 varbind list.
580
     * If there's an agentIPAddress varbind, set the agent_addr too
581
     */
582
0
    if (trap_oid_len == OID_LENGTH(trap_prefix) + 1 &&
583
0
        snmp_oid_ncompare(vblist->val.objid, trap_oid_len,
584
0
                          trap_prefix, OID_LENGTH(trap_prefix),
585
0
                          OID_LENGTH(trap_prefix)) == 0 &&
586
0
        vblist->val.objid[OID_LENGTH(trap_prefix)] >= 1 &&
587
0
        vblist->val.objid[OID_LENGTH(trap_prefix)] <= 6) {
588
        /*
589
         * For 'standard' traps, extract the generic trap type
590
         *   from the snmpTrapOID value, and take the enterprise
591
         *   value from the 'snmpEnterprise' varbind.
592
         */
593
0
        template_v1pdu->trap_type =
594
0
            vblist->val.objid[OID_LENGTH(trap_prefix)] - 1;
595
0
        template_v1pdu->specific_type = 0;
596
597
0
        var = find_varbind_in_list( vblist,
598
0
                             snmptrapenterprise_oid,
599
0
                             snmptrapenterprise_oid_len);
600
0
        SNMP_FREE(template_v1pdu->enterprise);
601
0
        if (var && var->type == ASN_OBJECT_ID && var->val.objid &&
602
0
            var->val_len >= sizeof(oid) &&
603
0
            (var->val_len / sizeof(oid)) <= MAX_OID_LEN) {
604
0
            template_v1pdu->enterprise_length = var->val_len/sizeof(oid);
605
0
            template_v1pdu->enterprise =
606
0
                snmp_duplicate_objid(var->val.objid,
607
0
                                     template_v1pdu->enterprise_length);
608
0
            if (!template_v1pdu->enterprise)
609
0
                template_v1pdu->enterprise_length = 0;
610
0
        } else {
611
0
            template_v1pdu->enterprise =
612
0
                snmp_duplicate_objid(trap_prefix, OID_LENGTH(trap_prefix));
613
0
            template_v1pdu->enterprise_length =
614
0
                template_v1pdu->enterprise ? OID_LENGTH(trap_prefix) : 0;
615
0
        }
616
0
    } else {
617
        /*
618
         * For enterprise-specific traps, split the snmpTrapOID value
619
         *   into enterprise and specific trap
620
         */
621
0
        size_t len = trap_oid_len;
622
0
        if ( len < 2 || (len == 2 && vblist->val.objid[0] == 0) ) {
623
0
            snmp_log(LOG_WARNING,
624
0
                     "send_trap: v2 trapOID too short (%" NETSNMP_PRIz "u)\n",
625
0
                     len);
626
0
            snmp_free_pdu(template_v1pdu);
627
0
            return NULL;
628
0
        }
629
0
        template_v1pdu->trap_type     = SNMP_TRAP_ENTERPRISESPECIFIC;
630
0
        template_v1pdu->specific_type = vblist->val.objid[len - 1];
631
0
        len--;
632
0
        if (vblist->val.objid[len-1] == 0)
633
0
            len--;
634
0
        SNMP_FREE(template_v1pdu->enterprise);
635
0
        template_v1pdu->enterprise =
636
0
            snmp_duplicate_objid(vblist->val.objid, len);
637
0
        template_v1pdu->enterprise_length =
638
0
            template_v1pdu->enterprise ? len : 0;
639
0
    }
640
0
    var = find_varbind_in_list( vblist, agentaddr_oid,
641
0
                                        agentaddr_oid_len);
642
0
    if (var && var->val.string &&
643
0
        var->val_len == sizeof(template_v1pdu->agent_addr)) {
644
0
        memcpy(template_v1pdu->agent_addr,
645
0
               var->val.string, sizeof(template_v1pdu->agent_addr));
646
0
    }
647
648
    /*
649
     * The remainder of the v2 varbind list is kept
650
     * as the v2 varbind list.  Update the PDU and
651
     * free the two redundant varbinds.
652
     */
653
0
    template_v1pdu->variables = vblist->next_variable;
654
0
    vblist->next_variable = NULL;
655
0
    snmp_free_varbind( first_vb );
656
            
657
0
    return template_v1pdu;
658
0
}
659
660
/*
661
 * Set t_oid from the PDU enterprise & specific trap fields.
662
 */
663
int
664
netsnmp_build_trap_oid(netsnmp_pdu *pdu, oid *t_oid, size_t *t_oid_len)
665
0
{
666
0
    if (NULL == pdu || NULL == t_oid || NULL == t_oid_len)
667
0
        return SNMPERR_GENERR;
668
0
    if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
669
0
        if (pdu->enterprise == NULL ||
670
0
            pdu->enterprise_length == 0 ||
671
0
            pdu->enterprise_length > MAX_OID_LEN ||
672
0
            *t_oid_len < (pdu->enterprise_length + 2))
673
0
            return SNMPERR_LONG_OID;
674
0
        memcpy(t_oid, pdu->enterprise, pdu->enterprise_length*sizeof(oid));
675
0
        *t_oid_len = pdu->enterprise_length;
676
0
        t_oid[(*t_oid_len)++] = 0;
677
0
        t_oid[(*t_oid_len)++] = pdu->specific_type;
678
0
    } else {
679
        /** use cold_start_oid as template */
680
0
        if (*t_oid_len < OID_LENGTH(cold_start_oid))
681
0
            return SNMPERR_LONG_OID;
682
0
        if (pdu->trap_type < 0 || pdu->trap_type > 5)
683
0
            return SNMPERR_GENERR;
684
0
        memcpy(t_oid, cold_start_oid, sizeof(cold_start_oid));
685
0
        t_oid[OID_LENGTH(cold_start_oid) - 1]  = pdu->trap_type + 1; /* set actual trap type */
686
0
        *t_oid_len = OID_LENGTH(cold_start_oid);
687
0
    }
688
0
    return SNMPERR_SUCCESS;
689
0
}
690
691
netsnmp_pdu*
692
convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu )
693
0
{
694
0
    netsnmp_pdu           *template_v2pdu;
695
0
    netsnmp_variable_list *var;
696
0
    oid                    enterprise[MAX_OID_LEN];
697
0
    size_t                 enterprise_len;
698
699
    /*
700
     * Make a copy of the v1 Trap PDU
701
     *   before starting to convert this
702
     *   into a v2 Trap PDU.
703
     */
704
0
    template_v2pdu = snmp_clone_pdu( template_v1pdu);
705
0
    if (!template_v2pdu) {
706
0
        snmp_log(LOG_WARNING,
707
0
                 "send_trap: failed to copy v2 template PDU\n");
708
0
        return NULL;
709
0
    }
710
0
    template_v2pdu->command = SNMP_MSG_TRAP2;
711
712
    /*
713
     * Insert an snmpTrapOID varbind before the original v1 varbind list
714
     *   either using one of the standard defined trap OIDs,
715
     *   or constructing this from the PDU enterprise & specific trap fields
716
     */
717
0
    var = NULL;
718
0
    enterprise_len = OID_LENGTH(enterprise);
719
0
    if ((netsnmp_build_trap_oid(template_v1pdu, enterprise, &enterprise_len)
720
0
         != SNMPERR_SUCCESS) ||
721
0
        !snmp_varlist_add_variable( &var,
722
0
             snmptrap_oid, snmptrap_oid_len,
723
0
             ASN_OBJECT_ID,
724
0
             (u_char*)enterprise, enterprise_len*sizeof(oid))) {
725
0
        snmp_log(LOG_WARNING,
726
0
                 "send_trap: failed to insert copied snmpTrapOID varbind\n");
727
0
        snmp_free_pdu(template_v2pdu);
728
0
        return NULL;
729
0
    }
730
0
    var->next_variable        = template_v2pdu->variables;
731
0
    template_v2pdu->variables = var;
732
733
    /*
734
     * Insert a sysUptime varbind at the head of the v2 varbind list
735
     */
736
0
    var = NULL;
737
0
    if (!snmp_varlist_add_variable( &var,
738
0
             sysuptime_oid, sysuptime_oid_len,
739
0
             ASN_TIMETICKS,
740
0
             (u_char*)&(template_v1pdu->time), 
741
0
             sizeof(template_v1pdu->time))) {
742
0
        snmp_log(LOG_WARNING,
743
0
                 "send_trap: failed to insert copied sysUptime varbind\n");
744
0
        snmp_free_pdu(template_v2pdu);
745
0
        return NULL;
746
0
    }
747
0
    var->next_variable        = template_v2pdu->variables;
748
0
    template_v2pdu->variables = var;
749
750
    /*
751
     * Append the other three conversion varbinds,
752
     *  (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise)
753
     *  if they're not already present.
754
     *  But don't bomb out completely if there are problems.
755
     */
756
0
    var = find_varbind_in_list( template_v2pdu->variables,
757
0
                                agentaddr_oid, agentaddr_oid_len);
758
0
    if (!var && (template_v1pdu->agent_addr[0]
759
0
              || template_v1pdu->agent_addr[1]
760
0
              || template_v1pdu->agent_addr[2]
761
0
              || template_v1pdu->agent_addr[3])) {
762
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
763
0
                 agentaddr_oid, agentaddr_oid_len,
764
0
                 ASN_IPADDRESS,
765
0
                 (u_char*)&(template_v1pdu->agent_addr), 
766
0
                 sizeof(template_v1pdu->agent_addr)))
767
0
            snmp_log(LOG_WARNING,
768
0
                 "send_trap: failed to append snmpTrapAddr varbind\n");
769
0
    }
770
0
    var = find_varbind_in_list( template_v2pdu->variables,
771
0
                                community_oid, community_oid_len);
772
0
    if (!var && template_v1pdu->community) {
773
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
774
0
                 community_oid, community_oid_len,
775
0
                 ASN_OCTET_STR,
776
0
                 template_v1pdu->community, 
777
0
                 template_v1pdu->community_len))
778
0
            snmp_log(LOG_WARNING,
779
0
                 "send_trap: failed to append snmpTrapCommunity varbind\n");
780
0
    }
781
0
    var = find_varbind_in_list( template_v2pdu->variables,
782
0
                                snmptrapenterprise_oid,
783
0
                                snmptrapenterprise_oid_len);
784
0
    if (!var && template_v1pdu->enterprise && template_v1pdu->enterprise_length > 0) {
785
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
786
0
                 snmptrapenterprise_oid, snmptrapenterprise_oid_len,
787
0
                 ASN_OBJECT_ID,
788
0
                 (u_char*)template_v1pdu->enterprise, 
789
0
                 template_v1pdu->enterprise_length*sizeof(oid)))
790
0
            snmp_log(LOG_WARNING,
791
0
                 "send_trap: failed to append snmpEnterprise varbind\n");
792
0
    }
793
0
    return template_v2pdu;
794
0
}
795
796
/**
797
 * This function allows you to make a distinction between generic 
798
 * traps from different classes of equipment. For example, you may want 
799
 * to handle a SNMP_TRAP_LINKDOWN trap for a particular device in a 
800
 * different manner to a generic system SNMP_TRAP_LINKDOWN trap.
801
 *   
802
 *
803
 * @param trap is the generic trap type.  The trap types are:
804
 *    - SNMP_TRAP_COLDSTART:
805
 *      cold start
806
 *    - SNMP_TRAP_WARMSTART:
807
 *      warm start
808
 *    - SNMP_TRAP_LINKDOWN:
809
 *      link down
810
 *    - SNMP_TRAP_LINKUP:
811
 *      link up
812
 *    - SNMP_TRAP_AUTHFAIL:
813
 *      authentication failure
814
 *    - SNMP_TRAP_EGPNEIGHBORLOSS:
815
 *      egp neighbor loss
816
 *    - SNMP_TRAP_ENTERPRISESPECIFIC:
817
 *      enterprise specific
818
 *      
819
 * @param specific is the specific trap value.
820
 *
821
 * @param enterprise is an enterprise oid in which you want to send specific 
822
 *  traps from. 
823
 *
824
 * @param enterprise_length is the length of the enterprise oid, use macro,
825
 *  OID_LENGTH, to compute length.
826
 *
827
 * @param vars is used to supply list of variable bindings to form an SNMPv2 
828
 *  trap.
829
 *
830
 * @param context currently unused 
831
 *
832
 * @param flags currently unused 
833
 *
834
 * @return void
835
 *
836
 * @see send_easy_trap
837
 * @see send_v2trap
838
 */
839
int
840
netsnmp_send_traps(int trap, int specific,
841
                          const oid * enterprise, int enterprise_length,
842
                          netsnmp_variable_list * vars,
843
                          const char * context, int flags)
844
0
{
845
0
    netsnmp_pdu           *template_v1pdu;
846
0
    netsnmp_pdu           *template_v2pdu;
847
0
    netsnmp_variable_list *vblist = NULL;
848
0
    netsnmp_variable_list *trap_vb;
849
0
    netsnmp_variable_list *var;
850
0
    in_addr_t             *pdu_in_addr_t;
851
0
    u_long                 uptime;
852
0
    struct trap_sink *sink;
853
0
    const char            *v1trapaddress;
854
0
    int                    res = 0;
855
856
0
    DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific));
857
0
    DEBUGMSGOID(("trap", enterprise, enterprise_length));
858
0
    DEBUGMSG(( "trap", "\n"));
859
860
0
    if (vars) {
861
0
        vblist = snmp_clone_varbind( vars );
862
0
        if (!vblist) {
863
0
            snmp_log(LOG_WARNING,
864
0
                     "send_trap: failed to clone varbind list\n");
865
0
            return -1;
866
0
        }
867
0
    }
868
869
0
    if ( trap == -1 ) {
870
        /*
871
         * Construct the SNMPv2-style notification PDU
872
         */
873
0
        if (!vblist) {
874
0
            snmp_log(LOG_WARNING,
875
0
                     "send_trap: called with NULL v2 information\n");
876
0
            return -1;
877
0
        }
878
0
        template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
879
0
        if (!template_v2pdu) {
880
0
            snmp_log(LOG_WARNING,
881
0
                     "send_trap: failed to construct v2 template PDU\n");
882
0
            snmp_free_varbind(vblist);
883
0
            return -1;
884
0
        }
885
886
        /*
887
         * Check the varbind list we've been given.
888
         * If it starts with a 'sysUptime.0' varbind, then use that.
889
         * Otherwise, prepend a suitable 'sysUptime.0' varbind.
890
         */
891
0
        if (!snmp_oid_compare( vblist->name,    vblist->name_length,
892
0
                               sysuptime_oid, sysuptime_oid_len )) {
893
0
            template_v2pdu->variables = vblist;
894
0
            trap_vb  = vblist->next_variable;
895
0
        } else {
896
0
            uptime   = netsnmp_get_agent_uptime();
897
0
            var = NULL;
898
0
            snmp_varlist_add_variable( &var,
899
0
                           sysuptime_oid, sysuptime_oid_len,
900
0
                           ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime));
901
0
            if (!var) {
902
0
                snmp_log(LOG_WARNING,
903
0
                     "send_trap: failed to insert sysUptime varbind\n");
904
0
                snmp_free_pdu(template_v2pdu);
905
0
                snmp_free_varbind(vblist);
906
0
                return -1;
907
0
            }
908
0
            template_v2pdu->variables = var;
909
0
            var->next_variable        = vblist;
910
0
            trap_vb  = vblist;
911
0
        }
912
913
        /*
914
         * 'trap_vb' should point to the snmpTrapOID.0 varbind,
915
         *   identifying the requested trap.  If not then bomb out.
916
         * If it's a 'standard' trap, then we need to append an
917
         *   snmpEnterprise varbind (if there isn't already one).
918
         */
919
0
        if (!trap_vb ||
920
0
            snmp_oid_compare(trap_vb->name, trap_vb->name_length,
921
0
                             snmptrap_oid,  snmptrap_oid_len)) {
922
0
            snmp_log(LOG_WARNING,
923
0
                     "send_trap: no v2 trapOID varbind provided\n");
924
0
            snmp_free_pdu(template_v2pdu);
925
0
            return -1;
926
0
        }
927
0
        if (trap_vb->type == ASN_OBJECT_ID && trap_vb->val.objid &&
928
0
            trap_vb->val_len == (OID_LENGTH(trap_prefix) + 1) * sizeof(oid) &&
929
0
            snmp_oid_ncompare(trap_vb->val.objid, OID_LENGTH(trap_prefix) + 1,
930
0
                              trap_prefix, OID_LENGTH(trap_prefix),
931
0
                              OID_LENGTH(trap_prefix)) == 0 &&
932
0
            trap_vb->val.objid[OID_LENGTH(trap_prefix)] >= 1 &&
933
0
            trap_vb->val.objid[OID_LENGTH(trap_prefix)] <= 6) {
934
0
            var = find_varbind_in_list( template_v2pdu->variables,
935
0
                                        snmptrapenterprise_oid,
936
0
                                        snmptrapenterprise_oid_len);
937
0
            if (!var && enterprise && enterprise_length > 0 &&
938
0
                !snmp_varlist_add_variable( &(template_v2pdu->variables),
939
0
                     snmptrapenterprise_oid, snmptrapenterprise_oid_len,
940
0
                     ASN_OBJECT_ID,
941
0
                     enterprise, enterprise_length*sizeof(oid))) {
942
0
                snmp_log(LOG_WARNING,
943
0
                     "send_trap: failed to add snmpEnterprise to v2 trap\n");
944
0
                snmp_free_pdu(template_v2pdu);
945
0
                return -1;
946
0
            }
947
0
        }
948
            
949
950
        /*
951
         * If everything's OK, convert the v2 template into an SNMPv1 trap PDU.
952
         */
953
0
        template_v1pdu = convert_v2pdu_to_v1( template_v2pdu );
954
0
        if (!template_v1pdu) {
955
0
            snmp_log(LOG_WARNING,
956
0
                     "send_trap: failed to convert v2->v1 template PDU\n");
957
0
        }
958
959
0
    } else {
960
        /*
961
         * Construct the SNMPv1 trap PDU....
962
         */
963
0
        template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP);
964
0
        if (!template_v1pdu) {
965
0
            snmp_log(LOG_WARNING,
966
0
                     "send_trap: failed to construct v1 template PDU\n");
967
0
            snmp_free_varbind(vblist);
968
0
            return -1;
969
0
        }
970
0
        template_v1pdu->trap_type     = trap;
971
0
        template_v1pdu->specific_type = specific;
972
0
        template_v1pdu->time          = netsnmp_get_agent_uptime();
973
974
0
        if (snmp_clone_mem((void **) &template_v1pdu->enterprise,
975
0
                       enterprise, enterprise_length * sizeof(oid))) {
976
0
            snmp_log(LOG_WARNING,
977
0
                     "send_trap: failed to set v1 enterprise OID\n");
978
0
            snmp_free_varbind(vblist);
979
0
            snmp_free_pdu(template_v1pdu);
980
0
            return -1;
981
0
        }
982
0
        template_v1pdu->enterprise_length = enterprise_length;
983
984
0
        template_v1pdu->flags    |= UCD_MSG_FLAG_FORCE_PDU_COPY;
985
0
        template_v1pdu->variables = vblist;
986
987
        /*
988
         * ... and convert it into an SNMPv2-style notification PDU.
989
         */
990
991
0
        template_v2pdu = convert_v1pdu_to_v2( template_v1pdu );
992
0
        if (!template_v2pdu) {
993
0
            snmp_log(LOG_WARNING,
994
0
                     "send_trap: failed to convert v1->v2 template PDU\n");
995
0
        }
996
0
    }
997
998
    /*
999
     * Check whether we're ignoring authFail traps
1000
     */
1001
0
    if (template_v1pdu) {
1002
0
      if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL &&
1003
0
        snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) {
1004
0
        snmp_free_pdu(template_v1pdu);
1005
0
        snmp_free_pdu(template_v2pdu);
1006
0
        return 0;
1007
0
      }
1008
1009
    /*
1010
     * Ensure that the v1 trap PDU includes the local IP address
1011
     */
1012
0
       pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr;
1013
0
       v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
1014
0
                                             NETSNMP_DS_AGENT_TRAP_ADDR);
1015
0
       if (v1trapaddress != NULL) {
1016
           /* "v1trapaddress" was specified in config, try to resolve it */
1017
0
           res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t);
1018
0
       }
1019
0
       if (v1trapaddress == NULL || res < 0) {
1020
           /* "v1trapaddress" was not specified in config or the resolution failed,
1021
            * try any local address */
1022
0
           *pdu_in_addr_t = get_myaddr();
1023
0
       }
1024
1025
0
    }
1026
1027
0
    if (template_v2pdu) {
1028
  /* A context name was provided, so copy it and its length to the v2 pdu
1029
   * template. */
1030
0
  if (context != NULL)
1031
0
  {
1032
0
    template_v2pdu->contextName    = strdup(context);
1033
0
    template_v2pdu->contextNameLen = strlen(context);
1034
0
  }
1035
0
    }
1036
1037
    /*
1038
     *  Now loop through the list of trap sinks
1039
     *   and call the trap callback routines,
1040
     *   providing an appropriately formatted PDU in each case
1041
     */
1042
0
    for (sink = sinks; sink; sink = sink->next) {
1043
0
#ifndef NETSNMP_DISABLE_SNMPV1
1044
0
        if (sink->version == SNMP_VERSION_1) {
1045
0
            if (template_v1pdu &&
1046
0
                !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1047
0
                                        NETSNMP_DS_LIB_DISABLE_V1)) {
1048
0
                send_trap_to_sess(sink->sesp, template_v1pdu);
1049
0
            }
1050
0
        } else
1051
0
#endif
1052
0
        if (template_v2pdu) {
1053
0
            template_v2pdu->command = sink->pdutype;
1054
0
            send_trap_to_sess(sink->sesp, template_v2pdu);
1055
0
        }
1056
0
    }
1057
0
#ifndef NETSNMP_DISABLE_SNMPV1
1058
0
    if (template_v1pdu)
1059
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1060
0
                        SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu);
1061
0
#endif
1062
0
    if (template_v2pdu)
1063
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1064
0
                        SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu);
1065
0
    snmp_free_pdu(template_v1pdu);
1066
0
    snmp_free_pdu(template_v2pdu);
1067
0
    return 0;
1068
0
}
1069
1070
1071
void
1072
send_enterprise_trap_vars(int trap,
1073
                          int specific,
1074
                          const oid * enterprise, int enterprise_length,
1075
                          netsnmp_variable_list * vars)
1076
0
{
1077
0
    netsnmp_send_traps(trap, specific,
1078
0
                       enterprise, enterprise_length,
1079
0
                       vars, NULL, 0);
1080
0
    return;
1081
0
}
1082
1083
/**
1084
 * Handles stats for basic traps (really just send failed
1085
*/
1086
int
1087
handle_trap_callback(int op, netsnmp_session * session, int reqid,
1088
                     netsnmp_pdu *pdu, void *magic)
1089
0
{
1090
0
    if (NULL == session)
1091
0
        return 0;
1092
1093
0
    DEBUGMSGTL(("trap", "handle_trap_callback for session %s\n",
1094
0
                session->paramName ? session->paramName : "UNKNOWN"));
1095
0
    switch (op) {
1096
1097
0
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
1098
0
        DEBUGMSGTL(("trap", "failed to send an inform for reqid=%d\n", reqid));
1099
0
#ifndef NETSNMP_NO_TRAP_STATS
1100
0
        if (session->trap_stats) {
1101
0
            session->trap_stats->sent_last_fail = netsnmp_get_agent_uptime();
1102
0
            ++session->trap_stats->sent_fail_count;
1103
0
        }
1104
0
#endif /* NETSNMP_NO_TRAP_STATS */
1105
0
        break;
1106
1107
0
    case NETSNMP_CALLBACK_OP_SEC_ERROR:
1108
0
        DEBUGMSGTL(("trap", "sec error sending a trap for reqid=%d\n",
1109
0
                    reqid));
1110
0
#ifndef NETSNMP_NO_TRAP_STATS
1111
0
        if (session->trap_stats) {
1112
0
            session->trap_stats->sec_err_last = netsnmp_get_agent_uptime();
1113
0
            ++session->trap_stats->sec_err_count;
1114
0
        }
1115
0
#endif /* NETSNMP_NO_TRAP_STATS */
1116
0
        break;
1117
1118
0
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
1119
0
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
1120
0
    case NETSNMP_CALLBACK_OP_RESEND:
1121
0
    default:
1122
0
        DEBUGMSGTL(("trap",
1123
0
                    "received op=%d for reqid=%d when trying to send a trap\n",
1124
0
                    op, reqid));
1125
0
    }
1126
0
#ifndef NETSNMP_NO_TRAP_STATS
1127
0
    if (session->trap_stats)
1128
0
        _dump_trap_stats(session);
1129
0
#endif /* NETSNMP_NO_TRAP_STATS */
1130
1131
0
    return 1;
1132
0
}
1133
1134
1135
/**
1136
 * Captures responses or the lack there of from INFORMs that were sent
1137
 * 1) a response is received from an INFORM
1138
 * 2) one isn't received and the retries/timeouts have failed
1139
*/
1140
int
1141
handle_inform_response(int op, netsnmp_session * session,
1142
                       int reqid, netsnmp_pdu *pdu,
1143
                       void *magic)
1144
0
{
1145
0
    if (NULL == session)
1146
0
        return 0;
1147
1148
0
    DEBUGMSGTL(("trap", "handle_inform_response for session %s\n",
1149
0
                session->paramName ? session->paramName : "UNKNOWN"));
1150
0
    switch (op) {
1151
1152
0
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
1153
0
        snmp_increment_statistic(STAT_SNMPINPKTS);
1154
0
        if (pdu->command != SNMP_MSG_REPORT) {
1155
0
            DEBUGMSGTL(("trap", "received the inform response for reqid=%d\n",
1156
0
                        reqid));
1157
0
#ifndef NETSNMP_NO_TRAP_STATS
1158
0
            if (session->trap_stats) {
1159
0
                ++session->trap_stats->ack_count;
1160
0
                session->trap_stats->ack_last_rcvd = netsnmp_get_agent_uptime();
1161
0
            }
1162
0
#endif /* NETSNMP_NO_TRAP_STATS */
1163
0
            break;
1164
0
        } else {
1165
0
            int type = session->s_snmp_errno ? session->s_snmp_errno :
1166
0
                snmpv3_get_report_type(pdu);
1167
0
            DEBUGMSGTL(("trap", "received report %d for inform reqid=%d\n",
1168
0
                        type, reqid));
1169
            /*
1170
             * xxx-rks: what stats, if any, to bump for other report types?
1171
             * - ignore NOT_IN_TIME, as agent will sync and retry.
1172
             */
1173
0
            if (SNMPERR_AUTHENTICATION_FAILURE != type)
1174
0
                break;
1175
0
        }
1176
        /** AUTH failures fall through to sec error */
1177
0
  NETSNMP_FALLTHROUGH;
1178
1179
0
    case NETSNMP_CALLBACK_OP_SEC_ERROR:
1180
0
        DEBUGMSGTL(("trap", "sec error sending an inform for reqid=%d\n",
1181
0
                    reqid));
1182
0
#ifndef NETSNMP_NO_TRAP_STATS
1183
0
        if (session->trap_stats) {
1184
0
            session->trap_stats->sec_err_last = netsnmp_get_agent_uptime();
1185
0
            ++session->trap_stats->sec_err_count;
1186
0
        }
1187
0
#endif /* NETSNMP_NO_TRAP_STATS */
1188
0
        break;
1189
1190
0
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
1191
0
        DEBUGMSGTL(("trap",
1192
0
                    "received a timeout sending an inform for reqid=%d\n",
1193
0
                    reqid));
1194
0
#ifndef NETSNMP_NO_TRAP_STATS
1195
0
        if (session->trap_stats) {
1196
0
            ++session->trap_stats->timeouts;
1197
0
            session->trap_stats->sent_last_timeout =
1198
0
                netsnmp_get_agent_uptime();
1199
0
        }
1200
0
#endif /* NETSNMP_NO_TRAP_STATS */
1201
0
        break;
1202
1203
0
    case NETSNMP_CALLBACK_OP_RESEND:
1204
0
        DEBUGMSGTL(("trap", "resending an inform for reqid=%d\n", reqid));
1205
0
#ifndef NETSNMP_NO_TRAP_STATS
1206
0
        if (session->trap_stats)
1207
0
            session->trap_stats->sent_last_sent = netsnmp_get_agent_uptime();
1208
0
#endif /* NETSNMP_NO_TRAP_STATS */
1209
0
        break;
1210
1211
0
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
1212
0
        DEBUGMSGTL(("trap", "failed to send an inform for reqid=%d\n", reqid));
1213
0
#ifndef NETSNMP_NO_TRAP_STATS
1214
0
        if (session->trap_stats) {
1215
0
            session->trap_stats->sent_last_fail = netsnmp_get_agent_uptime();
1216
0
            ++session->trap_stats->sent_fail_count;
1217
0
        }
1218
0
#endif /* NETSNMP_NO_TRAP_STATS */
1219
0
        break;
1220
1221
0
    default:
1222
0
        DEBUGMSGTL(("trap", "received op=%d for reqid=%d when trying to send an inform\n", op, reqid));
1223
0
    }
1224
1225
0
#ifndef NETSNMP_NO_TRAP_STATS
1226
0
    if (session->trap_stats)
1227
0
        _dump_trap_stats(session);
1228
0
#endif /* NETSNMP_NO_TRAP_STATS */
1229
1230
0
    return 1;
1231
0
}
1232
1233
1234
/*
1235
 * send_trap_to_sess: sends a trap to a session but assumes that the
1236
 * pdu is constructed correctly for the session type. 
1237
 */
1238
void
1239
send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
1240
0
{
1241
0
    netsnmp_pdu    *pdu;
1242
0
    int            result;
1243
1244
0
    if (!sess || !template_pdu)
1245
0
        return;
1246
1247
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(sess->version)) {
1248
0
        DEBUGMSGTL(("trap", "not sending trap type=%d, version %02lx disabled\n",
1249
0
                    template_pdu->command, sess->version));
1250
0
        return;
1251
0
    }
1252
0
    DEBUGIF("trap") {
1253
0
        struct session_list *sessp = snmp_sess_pointer(sess);
1254
0
        netsnmp_transport *t = sessp->transport;
1255
0
        const void *dst = template_pdu->transport_data;
1256
0
        const int dst_len = template_pdu->transport_data_length;
1257
0
        char *peer = NULL;
1258
1259
0
        if (t && t->f_fmtaddr)
1260
0
            peer = t->f_fmtaddr(t, dst, dst_len);
1261
0
        DEBUGMSGTL(("trap", "sending trap type=%d, version=%ld to %s\n",
1262
0
                    template_pdu->command, sess->version, peer ? peer : "(?)"));
1263
0
        free(peer);
1264
0
    }
1265
1266
0
#ifndef NETSNMP_DISABLE_SNMPV1
1267
0
    if (sess->version == SNMP_VERSION_1 &&
1268
0
        (template_pdu->command != SNMP_MSG_TRAP))
1269
0
        return;                 /* Skip v1 sinks for v2 only traps */
1270
0
    if (sess->version != SNMP_VERSION_1 &&
1271
0
        (template_pdu->command == SNMP_MSG_TRAP))
1272
0
        return;                 /* Skip v2+ sinks for v1 only traps */
1273
0
#endif
1274
0
    template_pdu->version = sess->version;
1275
0
    pdu = snmp_clone_pdu(template_pdu);
1276
0
    if(!pdu) {
1277
0
        snmp_log(LOG_WARNING, "send_trap: failed to clone PDU\n");
1278
0
        return;
1279
0
    }
1280
1281
0
    pdu->sessid = sess->sessid; /* AgentX only ? */
1282
    /*
1283
     * RFC 3414 sayeth:
1284
     *
1285
     * - If an SNMP engine uses a msgID for correlating Response messages to
1286
     *   outstanding Request messages, then it MUST use different msgIDs in
1287
     *   all such Request messages that it sends out during a Time Window
1288
     *   (150 seconds) period.
1289
     *
1290
     *   A Command Generator or Notification Originator Application MUST use
1291
     *   different request-ids in all Request PDUs that it sends out during
1292
     *   a TimeWindow (150 seconds) period.
1293
     */
1294
0
    pdu->reqid = snmp_get_next_reqid();
1295
0
    pdu->msgid = snmp_get_next_msgid();
1296
1297
0
#ifndef NETSNMP_NO_TRAP_STATS
1298
    /** allocate space for trap stats */
1299
0
    if (NULL == sess->trap_stats) {
1300
0
        sess->trap_stats = SNMP_MALLOC_TYPEDEF(netsnmp_trap_stats);
1301
0
        if (NULL == sess->trap_stats)
1302
0
            snmp_log(LOG_ERR, "malloc for %s trap stats failed\n",
1303
0
                     sess->paramName ? sess->paramName : "UNKNOWN");
1304
0
    }
1305
0
#endif /* NETSNMP_NO_TRAP_STATS */
1306
1307
0
    if ( template_pdu->command == SNMP_MSG_INFORM
1308
0
#ifdef USING_AGENTX_PROTOCOL_MODULE
1309
0
         || template_pdu->command == AGENTX_MSG_NOTIFY
1310
0
#endif
1311
0
       ) {
1312
0
        result =
1313
0
            snmp_async_send(sess, pdu, &handle_inform_response, NULL);
1314
0
    } else {
1315
0
        if ((sess->version == SNMP_VERSION_3) &&
1316
0
                (pdu->command == SNMP_MSG_TRAP2) &&
1317
0
                (sess->securityEngineIDLen == 0)) {
1318
0
            u_char          tmp[SPRINT_MAX_LEN];
1319
1320
0
            int len = snmpv3_get_engineID(tmp, sizeof(tmp));
1321
0
            pdu->securityEngineID = netsnmp_memdup(tmp, len);
1322
0
            pdu->securityEngineIDLen = len;
1323
0
        }
1324
1325
0
        result = snmp_async_send(sess, pdu, &handle_trap_callback, NULL);
1326
0
    }
1327
1328
0
    if (result == 0) {
1329
0
        snmp_sess_perror("snmpd: send_trap", sess);
1330
0
        snmp_free_pdu(pdu);
1331
        /** trap stats for failure handled in callback */
1332
0
    } else {
1333
0
        snmp_increment_statistic(STAT_SNMPOUTTRAPS);
1334
0
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
1335
0
#ifndef NETSNMP_NO_TRAP_STATS
1336
0
        if (sess->trap_stats) {
1337
0
            sess->trap_stats->sent_last_sent = netsnmp_get_agent_uptime();
1338
0
            ++sess->trap_stats->sent_count;
1339
0
            _dump_trap_stats(sess);
1340
0
        }
1341
0
#endif /* NETSNMP_NO_TRAP_STATS */
1342
0
    }
1343
0
}
1344
1345
void
1346
send_trap_vars(int trap, int specific, netsnmp_variable_list * vars)
1347
0
{
1348
0
    if (trap == SNMP_TRAP_ENTERPRISESPECIFIC)
1349
0
        send_enterprise_trap_vars(trap, specific, objid_enterprisetrap,
1350
0
                                  OID_LENGTH(objid_enterprisetrap), vars);
1351
0
    else
1352
0
        send_enterprise_trap_vars(trap, specific, trap_version_id,
1353
0
                                  OID_LENGTH(trap_version_id), vars);
1354
0
}
1355
1356
#ifndef NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT
1357
/* Send a trap under a context */
1358
void send_trap_vars_with_context(int trap, int specific, 
1359
              netsnmp_variable_list *vars, const char *context)
1360
0
{
1361
0
    if (trap == SNMP_TRAP_ENTERPRISESPECIFIC)
1362
0
        netsnmp_send_traps(trap, specific, objid_enterprisetrap,
1363
0
                                  OID_LENGTH(objid_enterprisetrap), vars,
1364
0
                  context, 0);
1365
0
    else
1366
0
        netsnmp_send_traps(trap, specific, trap_version_id,
1367
0
                                  OID_LENGTH(trap_version_id), vars, 
1368
0
                  context, 0);
1369
      
1370
0
}
1371
#endif /* NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT */
1372
1373
/**
1374
 * Sends an SNMPv1 trap (or the SNMPv2 equivalent) to the list of  
1375
 * configured trap destinations (or "sinks"), using the provided 
1376
 * values for the generic trap type and specific trap value.
1377
 *
1378
 * This function eventually calls send_enterprise_trap_vars.  If the
1379
 * trap type is not set to SNMP_TRAP_ENTERPRISESPECIFIC the enterprise 
1380
 * and enterprise_length parameter is set to the pre defined NETSNMP_SYSTEM_MIB 
1381
 * oid and length respectively.  If the trap type is set to 
1382
 * SNMP_TRAP_ENTERPRISESPECIFIC the enterprise and enterprise_length 
1383
 * parameters are set to the pre-defined NETSNMP_NOTIFICATION_MIB oid and length 
1384
 * respectively.
1385
 *
1386
 * @param trap is the generic trap type.
1387
 *
1388
 * @param specific is the specific trap value.
1389
 *
1390
 * @return void
1391
 *
1392
 * @see send_enterprise_trap_vars
1393
 * @see send_v2trap
1394
 */
1395
        
1396
void
1397
send_easy_trap(int trap, int specific)
1398
0
{
1399
0
    send_trap_vars(trap, specific, NULL);
1400
0
}
1401
1402
/**
1403
 * Uses the supplied list of variable bindings to form an SNMPv2 trap, 
1404
 * which is sent to SNMPv2-capable sinks  on  the  configured  list.  
1405
 * An equivalent INFORM is sent to the configured list of inform sinks.  
1406
 * Sinks that can only handle SNMPv1 traps are skipped.
1407
 *
1408
 * This function eventually calls send_enterprise_trap_vars.  If the
1409
 * trap type is not set to SNMP_TRAP_ENTERPRISESPECIFIC the enterprise 
1410
 * and enterprise_length parameter is set to the pre defined NETSNMP_SYSTEM_MIB 
1411
 * oid and length respectively.  If the trap type is set to 
1412
 * SNMP_TRAP_ENTERPRISESPECIFIC the enterprise and enterprise_length 
1413
 * parameters are set to the pre-defined NETSNMP_NOTIFICATION_MIB oid and length 
1414
 * respectively.
1415
 *
1416
 * @param vars is used to supply list of variable bindings to form an SNMPv2 
1417
 *  trap.
1418
 *
1419
 * @return void
1420
 *
1421
 * @see send_easy_trap
1422
 * @see send_enterprise_trap_vars
1423
 */
1424
1425
void
1426
send_v2trap(netsnmp_variable_list * vars)
1427
0
{
1428
0
    send_trap_vars(-1, -1, vars);
1429
0
}
1430
1431
/**
1432
 * Similar to send_v2trap(), with the added ability to specify a context.  If
1433
 * the last parameter is NULL, then this call is equivalent to send_v2trap().
1434
 *
1435
 * @param vars is used to supply the list of variable bindings for the trap.
1436
 * 
1437
 * @param context is used to specify the context of the trap.
1438
 *
1439
 * @return void
1440
 *
1441
 * @see send_v2trap
1442
 */
1443
#ifndef NETSNMP_FEATURE_REMOVE_SEND_V3TRAP
1444
void send_v3trap(netsnmp_variable_list *vars, const char *context)
1445
0
{
1446
0
    netsnmp_send_traps(-1, -1, 
1447
0
                       trap_version_id, OID_LENGTH(trap_version_id),
1448
0
                       vars, context, 0);
1449
0
}
1450
#endif /* NETSNMP_FEATURE_REMOVE_SEND_V3TRAP */
1451
1452
#ifndef NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU
1453
void
1454
send_trap_pdu(netsnmp_pdu *pdu)
1455
0
{
1456
0
    send_trap_vars(-1, -1, pdu->variables);
1457
0
}
1458
#endif /* NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU */
1459
1460
1461
1462
        /*******************
1463
   *
1464
   * Config file handling
1465
   *
1466
   *******************/
1467
1468
void
1469
snmpd_parse_config_authtrap(const char *token, char *cptr)
1470
0
{
1471
0
    int             i;
1472
1473
0
    i = atoi(cptr);
1474
0
    if (i == 0) {
1475
0
        if (strcmp(cptr, "enable") == 0) {
1476
0
            i = SNMP_AUTHENTICATED_TRAPS_ENABLED;
1477
0
        } else if (strcmp(cptr, "disable") == 0) {
1478
0
            i = SNMP_AUTHENTICATED_TRAPS_DISABLED;
1479
0
        }
1480
0
    }
1481
0
    if (i < 1 || i > 2) {
1482
0
        config_perror("authtrapenable must be 1 or 2");
1483
0
    } else {
1484
0
        if (strcmp(token, "pauthtrapenable") == 0) {
1485
0
            if (snmp_enableauthentrapsset < 0) {
1486
                /*
1487
                 * This is bogus (and shouldn't happen anyway) -- the value
1488
                 * of snmpEnableAuthenTraps.0 is already configured
1489
                 * read-only.  
1490
                 */
1491
0
                snmp_log(LOG_WARNING,
1492
0
                         "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
1493
0
                return;
1494
0
            } else {
1495
0
                snmp_enableauthentrapsset++;
1496
0
            }
1497
0
        } else {
1498
0
            if (snmp_enableauthentrapsset > 0) {
1499
                /*
1500
                 * This is bogus (and shouldn't happen anyway) -- we already
1501
                 * read a persistent value of snmpEnableAuthenTraps.0, which
1502
                 * we should ignore in favour of this one.  
1503
                 */
1504
0
                snmp_log(LOG_WARNING,
1505
0
                         "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
1506
                /*
1507
                 * Fall through and copy in this value.  
1508
                 */
1509
0
            }
1510
0
            snmp_enableauthentrapsset = -1;
1511
0
        }
1512
0
        snmp_enableauthentraps = i;
1513
0
    }
1514
0
}
1515
1516
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1517
static void
1518
_parse_config_sink(const char *token, char *cptr, int version, int type)
1519
0
{
1520
0
    char           *sp, *cp, *pp = NULL, *src = NULL;
1521
0
    char           *st, *name = NULL, *tag = NULL, *profile = NULL;
1522
1523
0
    if (!snmp_trapcommunity)
1524
0
        snmp_trapcommunity = strdup("public");
1525
0
    sp = strtok_r(cptr, " \t\n", &st);
1526
0
    if (!sp)
1527
0
        return;
1528
    /*
1529
     * check for optional arguments
1530
     */
1531
0
    for (;;) {
1532
0
        if (!sp) {
1533
0
            netsnmp_config_error("missing trapsink: %s", cptr);
1534
0
            return;
1535
0
        }
1536
0
        if (*sp != '-')
1537
0
            break;
1538
0
        if (strcmp(sp, "-name") == 0)
1539
0
            name = strtok_r(NULL, " \t\n", &st);
1540
0
        else if (strcmp(sp, "-tag") == 0)
1541
0
            tag = strtok_r(NULL, " \t\n", &st);
1542
0
        else if (strcmp(sp, "-profile") == 0)
1543
0
            profile = strtok_r(NULL, " \t\n", &st);
1544
0
        else if (strcmp(sp, "-s") == 0)
1545
0
            src = strtok_r(NULL, " \t\n", &st);
1546
0
        else
1547
0
            netsnmp_config_warn("ignoring unknown argument: %s", sp);
1548
0
        sp = strtok_r(NULL, " \t\n", &st);
1549
0
    }
1550
0
    cp = strtok_r(NULL, " \t\n", &st);
1551
0
    if (cp)
1552
0
        pp = strtok_r(NULL, " \t\n", &st);
1553
0
    if (pp)
1554
0
        config_pwarn("The separate port argument for sinks is deprecated");
1555
0
    if (netsnmp_create_v1v2_notification_session(sp, pp,
1556
0
                                                 cp ? cp : snmp_trapcommunity,
1557
0
                                                 src, version, type, name, tag,
1558
0
                                                 profile) == NULL) {
1559
0
        netsnmp_config_error("cannot create sink: %s", cptr);
1560
0
    }
1561
0
}
1562
#endif
1563
1564
#ifndef NETSNMP_DISABLE_SNMPV1
1565
void
1566
snmpd_parse_config_trapsink(const char *token, char *cptr)
1567
0
{
1568
0
    _parse_config_sink(token, cptr, SNMP_VERSION_1, SNMP_MSG_TRAP);
1569
0
}
1570
#endif
1571
1572
#ifndef NETSNMP_DISABLE_SNMPV2C
1573
void
1574
snmpd_parse_config_trap2sink(const char *word, char *cptr)
1575
0
{
1576
0
    _parse_config_sink(word, cptr, SNMP_VERSION_2c, SNMP_MSG_TRAP2);
1577
0
}
1578
1579
void
1580
snmpd_parse_config_informsink(const char *word, char *cptr)
1581
0
{
1582
0
    _parse_config_sink(word, cptr, SNMP_VERSION_2c, SNMP_MSG_INFORM);
1583
0
}
1584
#endif
1585
1586
/*
1587
 * this must be standardized somewhere, right? 
1588
 */
1589
0
#define MAX_ARGS 128
1590
1591
static int      traptype;
1592
1593
static void
1594
trapOptProc(int argc, char *const *argv, int opt)
1595
0
{
1596
0
    switch (opt) {
1597
0
    case 'C':
1598
0
        while (*optarg) {
1599
0
            switch (*optarg++) {
1600
0
            case 'i':
1601
0
                traptype = SNMP_MSG_INFORM;
1602
0
                break;
1603
0
            default:
1604
0
                config_perror("unknown argument passed to -C");
1605
0
                break;
1606
0
            }
1607
0
        }
1608
0
        break;
1609
0
    }
1610
0
}
1611
1612
netsnmp_session *
1613
netsnmp_create_v3user_notification_session(const char *dest, const char *user,
1614
                                           int level, const char *context,
1615
                                           int pdutype, const u_char *engineId,
1616
                                           size_t engineId_len, const char *src,
1617
                                           const char *notif_name,
1618
                                           const char *notif_tag,
1619
                                           const char* notif_profile)
1620
0
{
1621
0
    netsnmp_session    session, *ss = NULL;
1622
0
    struct usmUser    *usmUser;
1623
0
    netsnmp_tdomain_spec tspec;
1624
0
    netsnmp_transport *transport;
1625
0
    u_char             tmp_engineId[SPRINT_MAX_LEN];
1626
0
    int                rc;
1627
1628
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1629
0
                               NETSNMP_DS_LIB_DISABLE_V3)) {
1630
0
        netsnmp_config_error("SNMPv3 disabled, cannot create notification session");
1631
0
        return NULL;
1632
0
    }
1633
0
    if (NULL == dest || NULL == user)
1634
0
        return NULL;
1635
1636
    /** authlevel */
1637
0
    if ((SNMP_SEC_LEVEL_AUTHPRIV != level) &&
1638
0
        (SNMP_SEC_LEVEL_AUTHNOPRIV != level) &&
1639
0
        (SNMP_SEC_LEVEL_NOAUTH != level)) {
1640
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "bad level %d\n", level));
1641
0
        return NULL;
1642
0
    }
1643
1644
    /** need engineId to look up users */
1645
0
    if (NULL == engineId) {
1646
0
        engineId_len = snmpv3_get_engineID( tmp_engineId, sizeof(tmp_engineId));
1647
0
        engineId = tmp_engineId;
1648
0
    }
1649
1650
0
    usmUser = usm_get_user(engineId, engineId_len, user);
1651
0
    if (NULL == usmUser) {
1652
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "usmUser %s not found\n", user));
1653
0
        return NULL;
1654
0
    }
1655
1656
0
    snmp_sess_init(&session);
1657
1658
0
    session.callback = handle_disconnect_packet;
1659
1660
0
    session.version = SNMP_VERSION_3;
1661
1662
0
    session.peername = strdup(dest);
1663
1664
0
    session.securityName = strdup(user);
1665
0
    session.securityNameLen = strlen(user);
1666
1667
0
    if (context) {
1668
0
        session.contextName = strdup(context);
1669
0
        session.contextNameLen = strlen(context);
1670
0
    }
1671
1672
0
    session.securityLevel = level;
1673
1674
    /** auth prot */
1675
0
    if (NULL != usmUser->authProtocol) {
1676
0
        session.securityAuthProto =
1677
0
            snmp_duplicate_objid(usmUser->authProtocol,
1678
0
                                 usmUser->authProtocolLen);
1679
0
        session.securityAuthProtoLen = usmUser->authProtocolLen;
1680
0
        if (NULL == session.securityAuthProto)
1681
0
            goto bail;
1682
0
    }
1683
1684
    /** authkey */
1685
0
    if (((SNMP_SEC_LEVEL_AUTHPRIV == level) ||
1686
0
         (SNMP_SEC_LEVEL_AUTHNOPRIV == level)) &&
1687
0
        (usmUser->flags & USMUSER_FLAG_KEEP_MASTER_KEY)) {
1688
0
        netsnmp_assert(usmUser->authKeyKuLen > 0);
1689
0
        memcpy(session.securityAuthKey, usmUser->authKeyKu,
1690
0
               usmUser->authKeyKuLen);
1691
0
        session.securityAuthKeyLen = usmUser->authKeyKuLen;
1692
0
    }
1693
1694
    /** priv prot */
1695
0
    if (NULL != usmUser->privProtocol) {
1696
0
        session.securityPrivProto =
1697
0
            snmp_duplicate_objid(usmUser->privProtocol,
1698
0
                                 usmUser->privProtocolLen);
1699
0
        session.securityPrivProtoLen = usmUser->privProtocolLen;
1700
0
        if (NULL == session.securityPrivProto)
1701
0
            goto bail;
1702
0
    }
1703
1704
    /** privkey */
1705
0
    if ((SNMP_SEC_LEVEL_AUTHPRIV == level)  &&
1706
0
        (usmUser->flags & USMUSER_FLAG_KEEP_MASTER_KEY)) {
1707
0
        netsnmp_assert(usmUser->privKeyKuLen > 0);
1708
0
        memcpy(session.securityPrivKey, usmUser->privKeyKu,
1709
0
               usmUser->privKeyKuLen);
1710
0
        session.securityPrivKeyLen = usmUser->privKeyKuLen;
1711
0
    }
1712
1713
    /** engineId */
1714
0
    session.contextEngineID = netsnmp_memdup(usmUser->engineID,
1715
0
                                             usmUser->engineIDLen);
1716
0
    session.contextEngineIDLen = usmUser->engineIDLen;
1717
1718
    /** open the tranport */
1719
1720
0
    memset(&tspec, 0, sizeof(netsnmp_tdomain_spec));
1721
0
    tspec.application = "snmptrap";
1722
0
    tspec.target = session.peername;
1723
0
    tspec.default_domain = NULL;
1724
0
    tspec.default_target = NULL;
1725
0
    tspec.source = src;
1726
0
    transport = netsnmp_tdomain_transport_tspec(&tspec);
1727
0
    if (transport == NULL) {
1728
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "could not create transport\n"));
1729
0
        goto bail;
1730
0
    }
1731
1732
0
    if ((rc = netsnmp_sess_config_and_open_transport(&session, transport))
1733
0
        != SNMPERR_SUCCESS) {
1734
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "config/open failed\n"));
1735
0
        goto bail;
1736
0
    }
1737
1738
0
    ss = snmp_add(&session, transport, NULL, NULL);
1739
0
    if (!ss) {
1740
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "snmp_add failed\n"));
1741
0
        goto bail;
1742
0
    }
1743
1744
0
    if (netsnmp_add_closable_notification_session(ss,
1745
0
                                                  !(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM),
1746
0
                                                  pdutype,
1747
0
                                                  (pdutype == SNMP_MSG_INFORM),
1748
0
                                                  ss->version, notif_name, notif_tag,
1749
0
                                                  notif_profile) != 1) {
1750
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "add notification failed\n"));
1751
0
        snmp_close(ss);
1752
0
        return NULL;
1753
0
    }
1754
1755
0
  bail:
1756
    /** free any allocated mem in session */
1757
0
    netsnmp_cleanup_session(&session);
1758
1759
0
    return ss;
1760
0
}
1761
1762
void
1763
snmpd_parse_config_trapsess(const char *word, char *cptr)
1764
0
{
1765
0
    char           *argv[MAX_ARGS], *cp = cptr;
1766
0
    char           *profile = NULL, *name = NULL, *tag = NULL;
1767
0
    int             argn, rc;
1768
0
    netsnmp_session session, *ss;
1769
0
    netsnmp_transport *transport;
1770
0
    size_t          len;
1771
0
    char            tmp[SPRINT_MAX_LEN];
1772
0
    char           *clientaddr_save = NULL;
1773
1774
    /*
1775
     * inform or trap?  default to trap 
1776
     */
1777
0
    traptype = SNMP_MSG_TRAP2;
1778
1779
0
    do {
1780
0
        if (strncmp(cp, "-profile", 8) == 0) {
1781
0
            cp = skip_token(cp);
1782
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1783
0
            free(profile);
1784
0
            profile = strdup(tmp);
1785
0
        } else if (strncmp(cp, "-name", 5) == 0) {
1786
0
            cp = skip_token(cp);
1787
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1788
0
            free(name);
1789
0
            name = strdup(tmp);
1790
0
        } else if (strncmp(cp, "-tag", 4) == 0) {
1791
0
            cp = skip_token(cp);
1792
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1793
0
            free(tag);
1794
0
            tag = strdup(tmp);
1795
0
        } else
1796
0
            break;
1797
0
    } while(cp);
1798
1799
    /*
1800
     * create the argv[] like array 
1801
     */
1802
0
    argv[0] = strdup("snmpd-trapsess"); /* bogus entry for getopt() */
1803
0
    for (argn = 1; cp && argn < MAX_ARGS; argn++) {
1804
0
        cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1805
0
        argv[argn] = strdup(tmp);
1806
0
    }
1807
1808
    /** parse args (also initializes session) */
1809
0
    netsnmp_parse_args(argn, argv, &session, "C:", trapOptProc,
1810
0
                       NETSNMP_PARSE_ARGS_NOLOGGING |
1811
0
                       NETSNMP_PARSE_ARGS_NOZERO);
1812
1813
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(session.version)) {
1814
0
        config_perror("snmpd: protocol version disabled at runtime");
1815
0
        for (; argn > 0; argn--)
1816
0
            free(argv[argn - 1]);
1817
0
        goto cleanup;
1818
0
    }
1819
1820
0
    if (NULL != session.localname) {
1821
0
        clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1822
0
                                                NETSNMP_DS_LIB_CLIENT_ADDR);
1823
0
        if (clientaddr_save)
1824
0
            clientaddr_save = strdup(clientaddr_save);
1825
0
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1826
0
                              NETSNMP_DS_LIB_CLIENT_ADDR,
1827
0
                              session.localname);
1828
0
    }
1829
1830
0
    transport = netsnmp_transport_open_client("snmptrap", session.peername);
1831
1832
0
    if (NULL != session.localname)
1833
0
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1834
0
                              NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
1835
1836
0
    if (transport == NULL) {
1837
0
        config_perror("snmpd: failed to parse this line.");
1838
0
        for (; argn > 0; argn--)
1839
0
            free(argv[argn - 1]);
1840
0
        goto cleanup;
1841
0
    }
1842
0
    if ((rc = netsnmp_sess_config_and_open_transport(&session, transport))
1843
0
        != SNMPERR_SUCCESS) {
1844
0
        session.s_snmp_errno = rc;
1845
0
        session.s_errno = 0;
1846
0
        for (; argn > 0; argn--)
1847
0
            free(argv[argn - 1]);
1848
0
        goto cleanup;
1849
0
    }
1850
0
    session.callback = handle_disconnect_packet;
1851
0
    ss = snmp_add(&session, transport, NULL, NULL);
1852
0
    for (; argn > 0; argn--)
1853
0
        free(argv[argn - 1]);
1854
1855
0
    if (!ss) {
1856
0
        config_perror
1857
0
            ("snmpd: failed to parse this line or the remote trap receiver is down.  Possible cause:");
1858
0
        snmp_sess_perror("snmpd: snmpd_parse_config_trapsess()", &session);
1859
0
        goto cleanup;
1860
0
    }
1861
1862
    /*
1863
     * If this is an SNMPv3 TRAP session, then the agent is
1864
     *   the authoritative engine, so set the engineID accordingly
1865
     */
1866
0
    if (ss->version == SNMP_VERSION_3 &&
1867
0
        traptype != SNMP_MSG_INFORM   &&
1868
0
        ss->securityEngineIDLen == 0) {
1869
0
            u_char          tmp[SPRINT_MAX_LEN];
1870
1871
0
            len = snmpv3_get_engineID( tmp, sizeof(tmp));
1872
0
            ss->securityEngineID = netsnmp_memdup(tmp, len);
1873
0
            ss->securityEngineIDLen = len;
1874
0
    }
1875
1876
0
#ifndef NETSNMP_DISABLE_SNMPV1
1877
0
    if ((ss->version == SNMP_VERSION_1) &&
1878
0
        !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1879
0
                                NETSNMP_DS_LIB_DISABLE_V1))
1880
0
        traptype = SNMP_MSG_TRAP;
1881
0
#endif
1882
0
    netsnmp_add_closable_notification_session(ss,
1883
0
                                              !(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM),
1884
0
                                              traptype,
1885
0
                                              (traptype == SNMP_MSG_INFORM),
1886
0
                                              ss->version, name, tag, profile);
1887
1888
0
  cleanup:
1889
0
    netsnmp_cleanup_session(&session);
1890
0
    SNMP_FREE(clientaddr_save);
1891
0
    SNMP_FREE(profile);
1892
0
    SNMP_FREE(name);
1893
0
    SNMP_FREE(tag);
1894
0
}
1895
1896
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1897
void
1898
snmpd_parse_config_trapcommunity(const char *word, char *cptr)
1899
0
{
1900
0
    if (snmp_trapcommunity != NULL) {
1901
0
        free(snmp_trapcommunity);
1902
0
    }
1903
0
    snmp_trapcommunity = (char *) malloc(strlen(cptr) + 1);
1904
0
    if (snmp_trapcommunity != NULL) {
1905
0
        copy_nword(cptr, snmp_trapcommunity, strlen(cptr) + 1);
1906
0
    }
1907
0
}
1908
1909
void
1910
snmpd_free_trapcommunity(void)
1911
6.72k
{
1912
6.72k
    if (snmp_trapcommunity) {
1913
0
        free(snmp_trapcommunity);
1914
        snmp_trapcommunity = NULL;
1915
0
    }
1916
6.72k
}
1917
#endif
1918
/** @} */