Coverage Report

Created: 2024-02-25 06:16

/src/net-snmp/agent/agent_trap.c
Line
Count
Source (jump to first uncovered line)
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.06k
{
147
3.06k
}
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
  sprintf(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
24.5k
{
476
24.5k
    struct trap_sink *sp = sinks;
477
24.5k
    DEBUGMSGTL(("trap", "freeing trap sessions\n"));
478
24.5k
    while (sp) {
479
0
        sinks = sinks->next;
480
0
        free_trap_session(sp);
481
0
        sp = sinks;
482
0
    }
483
24.5k
}
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
499
    /*
500
     * Make a copy of the v2 Trap PDU
501
     *   before starting to convert this
502
     *   into a v1 Trap PDU.
503
     */
504
0
    template_v1pdu = snmp_clone_pdu( template_v2pdu);
505
0
    if (!template_v1pdu) {
506
0
        snmp_log(LOG_WARNING,
507
0
                 "send_trap: failed to copy v1 template PDU\n");
508
0
        return NULL;
509
0
    }
510
0
    template_v1pdu->command = SNMP_MSG_TRAP;
511
0
    first_vb = template_v1pdu->variables;
512
0
    vblist   = template_v1pdu->variables;
513
514
    /*
515
     * The first varbind should be the system uptime.
516
     */
517
0
    if (!vblist ||
518
0
        snmp_oid_compare(vblist->name,  vblist->name_length,
519
0
                         sysuptime_oid, sysuptime_oid_len)) {
520
0
        snmp_log(LOG_WARNING,
521
0
                 "send_trap: no v2 sysUptime varbind to set from\n");
522
0
        snmp_free_pdu(template_v1pdu);
523
0
        return NULL;
524
0
    }
525
0
    template_v1pdu->time = *vblist->val.integer;
526
0
    vblist = vblist->next_variable;
527
            
528
    /*
529
     * The second varbind should be the snmpTrapOID.
530
     */
531
0
    if (!vblist ||
532
0
        snmp_oid_compare(vblist->name, vblist->name_length,
533
0
                         snmptrap_oid, snmptrap_oid_len)) {
534
0
        snmp_log(LOG_WARNING,
535
0
                 "send_trap: no v2 trapOID varbind to set from\n");
536
0
        snmp_free_pdu(template_v1pdu);
537
0
        return NULL;
538
0
    }
539
540
    /*
541
     * Check the v2 varbind list for any varbinds
542
     *  that are not valid in an SNMPv1 trap.
543
     *  This basically means Counter64 values.
544
     *
545
     * RFC 2089 said to omit such varbinds from the list.
546
     * RFC 2576/3584 say to drop the trap completely.
547
     */
548
0
    for (var = vblist->next_variable; var; var = var->next_variable) {
549
0
        if ( var->type == ASN_COUNTER64 ) {
550
0
            snmp_log(LOG_WARNING,
551
0
                     "send_trap: v1 traps can't carry Counter64 varbinds\n");
552
0
            snmp_free_pdu(template_v1pdu);
553
0
            return NULL;
554
0
        }
555
0
    }
556
557
    /*
558
     * Set the generic & specific trap types,
559
     *    and the enterprise field from the v2 varbind list.
560
     * If there's an agentIPAddress varbind, set the agent_addr too
561
     */
562
0
    if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix),
563
0
                          trap_prefix,       OID_LENGTH(trap_prefix))) {
564
        /*
565
         * For 'standard' traps, extract the generic trap type
566
         *   from the snmpTrapOID value, and take the enterprise
567
         *   value from the 'snmpEnterprise' varbind.
568
         */
569
0
        template_v1pdu->trap_type =
570
0
            vblist->val.objid[OID_LENGTH(trap_prefix)] - 1;
571
0
        template_v1pdu->specific_type = 0;
572
573
0
        var = find_varbind_in_list( vblist,
574
0
                             snmptrapenterprise_oid,
575
0
                             snmptrapenterprise_oid_len);
576
0
        if (var) {
577
0
            template_v1pdu->enterprise_length = var->val_len/sizeof(oid);
578
0
            template_v1pdu->enterprise =
579
0
                snmp_duplicate_objid(var->val.objid,
580
0
                                     template_v1pdu->enterprise_length);
581
0
        } else {
582
0
            template_v1pdu->enterprise        = NULL;
583
0
            template_v1pdu->enterprise_length = 0;    /* XXX ??? */
584
0
        }
585
0
    } else {
586
        /*
587
         * For enterprise-specific traps, split the snmpTrapOID value
588
         *   into enterprise and specific trap
589
         */
590
0
        size_t len = vblist->val_len / sizeof(oid);
591
0
        if ( len <= 2 ) {
592
0
            snmp_log(LOG_WARNING,
593
0
                     "send_trap: v2 trapOID too short (%d)\n", (int)len);
594
0
            snmp_free_pdu(template_v1pdu);
595
0
            return NULL;
596
0
        }
597
0
        template_v1pdu->trap_type     = SNMP_TRAP_ENTERPRISESPECIFIC;
598
0
        template_v1pdu->specific_type = vblist->val.objid[len - 1];
599
0
        len--;
600
0
        if (vblist->val.objid[len-1] == 0)
601
0
            len--;
602
0
        SNMP_FREE(template_v1pdu->enterprise);
603
0
        template_v1pdu->enterprise =
604
0
            snmp_duplicate_objid(vblist->val.objid, len);
605
0
        template_v1pdu->enterprise_length = len;
606
0
    }
607
0
    var = find_varbind_in_list( vblist, agentaddr_oid,
608
0
                                        agentaddr_oid_len);
609
0
    if (var) {
610
0
        memcpy(template_v1pdu->agent_addr,
611
0
               var->val.string, 4);
612
0
    }
613
614
    /*
615
     * The remainder of the v2 varbind list is kept
616
     * as the v2 varbind list.  Update the PDU and
617
     * free the two redundant varbinds.
618
     */
619
0
    template_v1pdu->variables = vblist->next_variable;
620
0
    vblist->next_variable = NULL;
621
0
    snmp_free_varbind( first_vb );
622
            
623
0
    return template_v1pdu;
624
0
}
625
626
/*
627
 * Set t_oid from the PDU enterprise & specific trap fields.
628
 */
629
int
630
netsnmp_build_trap_oid(netsnmp_pdu *pdu, oid *t_oid, size_t *t_oid_len)
631
0
{
632
0
    if (NULL == pdu || NULL == t_oid || NULL == t_oid_len)
633
0
        return SNMPERR_GENERR;
634
0
    if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
635
0
        if (*t_oid_len < (pdu->enterprise_length + 2))
636
0
            return SNMPERR_LONG_OID;
637
0
        memcpy(t_oid, pdu->enterprise, pdu->enterprise_length*sizeof(oid));
638
0
        *t_oid_len = pdu->enterprise_length;
639
0
        t_oid[(*t_oid_len)++] = 0;
640
0
        t_oid[(*t_oid_len)++] = pdu->specific_type;
641
0
    } else {
642
        /** use cold_start_oid as template */
643
0
        if (*t_oid_len < OID_LENGTH(cold_start_oid))
644
0
            return SNMPERR_LONG_OID;
645
0
        memcpy(t_oid, cold_start_oid, sizeof(cold_start_oid));
646
0
        t_oid[9]  = pdu->trap_type + 1; /* set actual trap type */
647
0
        *t_oid_len = OID_LENGTH(cold_start_oid);
648
0
    }
649
0
    return SNMPERR_SUCCESS;
650
0
}
651
652
netsnmp_pdu*
653
convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu )
654
0
{
655
0
    netsnmp_pdu           *template_v2pdu;
656
0
    netsnmp_variable_list *var;
657
0
    oid                    enterprise[MAX_OID_LEN];
658
0
    size_t                 enterprise_len;
659
660
    /*
661
     * Make a copy of the v1 Trap PDU
662
     *   before starting to convert this
663
     *   into a v2 Trap PDU.
664
     */
665
0
    template_v2pdu = snmp_clone_pdu( template_v1pdu);
666
0
    if (!template_v2pdu) {
667
0
        snmp_log(LOG_WARNING,
668
0
                 "send_trap: failed to copy v2 template PDU\n");
669
0
        return NULL;
670
0
    }
671
0
    template_v2pdu->command = SNMP_MSG_TRAP2;
672
673
    /*
674
     * Insert an snmpTrapOID varbind before the original v1 varbind list
675
     *   either using one of the standard defined trap OIDs,
676
     *   or constructing this from the PDU enterprise & specific trap fields
677
     */
678
0
    var = NULL;
679
0
    enterprise_len = OID_LENGTH(enterprise);
680
0
    if ((netsnmp_build_trap_oid(template_v1pdu, enterprise, &enterprise_len)
681
0
         != SNMPERR_SUCCESS) ||
682
0
        !snmp_varlist_add_variable( &var,
683
0
             snmptrap_oid, snmptrap_oid_len,
684
0
             ASN_OBJECT_ID,
685
0
             (u_char*)enterprise, enterprise_len*sizeof(oid))) {
686
0
        snmp_log(LOG_WARNING,
687
0
                 "send_trap: failed to insert copied snmpTrapOID varbind\n");
688
0
        snmp_free_pdu(template_v2pdu);
689
0
        return NULL;
690
0
    }
691
0
    var->next_variable        = template_v2pdu->variables;
692
0
    template_v2pdu->variables = var;
693
694
    /*
695
     * Insert a sysUptime varbind at the head of the v2 varbind list
696
     */
697
0
    var = NULL;
698
0
    if (!snmp_varlist_add_variable( &var,
699
0
             sysuptime_oid, sysuptime_oid_len,
700
0
             ASN_TIMETICKS,
701
0
             (u_char*)&(template_v1pdu->time), 
702
0
             sizeof(template_v1pdu->time))) {
703
0
        snmp_log(LOG_WARNING,
704
0
                 "send_trap: failed to insert copied sysUptime varbind\n");
705
0
        snmp_free_pdu(template_v2pdu);
706
0
        return NULL;
707
0
    }
708
0
    var->next_variable        = template_v2pdu->variables;
709
0
    template_v2pdu->variables = var;
710
711
    /*
712
     * Append the other three conversion varbinds,
713
     *  (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise)
714
     *  if they're not already present.
715
     *  But don't bomb out completely if there are problems.
716
     */
717
0
    var = find_varbind_in_list( template_v2pdu->variables,
718
0
                                agentaddr_oid, agentaddr_oid_len);
719
0
    if (!var && (template_v1pdu->agent_addr[0]
720
0
              || template_v1pdu->agent_addr[1]
721
0
              || template_v1pdu->agent_addr[2]
722
0
              || template_v1pdu->agent_addr[3])) {
723
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
724
0
                 agentaddr_oid, agentaddr_oid_len,
725
0
                 ASN_IPADDRESS,
726
0
                 (u_char*)&(template_v1pdu->agent_addr), 
727
0
                 sizeof(template_v1pdu->agent_addr)))
728
0
            snmp_log(LOG_WARNING,
729
0
                 "send_trap: failed to append snmpTrapAddr varbind\n");
730
0
    }
731
0
    var = find_varbind_in_list( template_v2pdu->variables,
732
0
                                community_oid, community_oid_len);
733
0
    if (!var && template_v1pdu->community) {
734
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
735
0
                 community_oid, community_oid_len,
736
0
                 ASN_OCTET_STR,
737
0
                 template_v1pdu->community, 
738
0
                 template_v1pdu->community_len))
739
0
            snmp_log(LOG_WARNING,
740
0
                 "send_trap: failed to append snmpTrapCommunity varbind\n");
741
0
    }
742
0
    var = find_varbind_in_list( template_v2pdu->variables,
743
0
                                snmptrapenterprise_oid,
744
0
                                snmptrapenterprise_oid_len);
745
0
    if (!var) {
746
0
        if (!snmp_varlist_add_variable( &(template_v2pdu->variables),
747
0
                 snmptrapenterprise_oid, snmptrapenterprise_oid_len,
748
0
                 ASN_OBJECT_ID,
749
0
                 (u_char*)template_v1pdu->enterprise, 
750
0
                 template_v1pdu->enterprise_length*sizeof(oid)))
751
0
            snmp_log(LOG_WARNING,
752
0
                 "send_trap: failed to append snmpEnterprise varbind\n");
753
0
    }
754
0
    return template_v2pdu;
755
0
}
756
757
/**
758
 * This function allows you to make a distinction between generic 
759
 * traps from different classes of equipment. For example, you may want 
760
 * to handle a SNMP_TRAP_LINKDOWN trap for a particular device in a 
761
 * different manner to a generic system SNMP_TRAP_LINKDOWN trap.
762
 *   
763
 *
764
 * @param trap is the generic trap type.  The trap types are:
765
 *    - SNMP_TRAP_COLDSTART:
766
 *      cold start
767
 *    - SNMP_TRAP_WARMSTART:
768
 *      warm start
769
 *    - SNMP_TRAP_LINKDOWN:
770
 *      link down
771
 *    - SNMP_TRAP_LINKUP:
772
 *      link up
773
 *    - SNMP_TRAP_AUTHFAIL:
774
 *      authentication failure
775
 *    - SNMP_TRAP_EGPNEIGHBORLOSS:
776
 *      egp neighbor loss
777
 *    - SNMP_TRAP_ENTERPRISESPECIFIC:
778
 *      enterprise specific
779
 *      
780
 * @param specific is the specific trap value.
781
 *
782
 * @param enterprise is an enterprise oid in which you want to send specific 
783
 *  traps from. 
784
 *
785
 * @param enterprise_length is the length of the enterprise oid, use macro,
786
 *  OID_LENGTH, to compute length.
787
 *
788
 * @param vars is used to supply list of variable bindings to form an SNMPv2 
789
 *  trap.
790
 *
791
 * @param context currently unused 
792
 *
793
 * @param flags currently unused 
794
 *
795
 * @return void
796
 *
797
 * @see send_easy_trap
798
 * @see send_v2trap
799
 */
800
int
801
netsnmp_send_traps(int trap, int specific,
802
                          const oid * enterprise, int enterprise_length,
803
                          netsnmp_variable_list * vars,
804
                          const char * context, int flags)
805
0
{
806
0
    netsnmp_pdu           *template_v1pdu;
807
0
    netsnmp_pdu           *template_v2pdu;
808
0
    netsnmp_variable_list *vblist = NULL;
809
0
    netsnmp_variable_list *trap_vb;
810
0
    netsnmp_variable_list *var;
811
0
    in_addr_t             *pdu_in_addr_t;
812
0
    u_long                 uptime;
813
0
    struct trap_sink *sink;
814
0
    const char            *v1trapaddress;
815
0
    int                    res = 0;
816
817
0
    DEBUGMSGTL(( "trap", "send_trap %d %d ", trap, specific));
818
0
    DEBUGMSGOID(("trap", enterprise, enterprise_length));
819
0
    DEBUGMSG(( "trap", "\n"));
820
821
0
    if (vars) {
822
0
        vblist = snmp_clone_varbind( vars );
823
0
        if (!vblist) {
824
0
            snmp_log(LOG_WARNING,
825
0
                     "send_trap: failed to clone varbind list\n");
826
0
            return -1;
827
0
        }
828
0
    }
829
830
0
    if ( trap == -1 ) {
831
        /*
832
         * Construct the SNMPv2-style notification PDU
833
         */
834
0
        if (!vblist) {
835
0
            snmp_log(LOG_WARNING,
836
0
                     "send_trap: called with NULL v2 information\n");
837
0
            return -1;
838
0
        }
839
0
        template_v2pdu = snmp_pdu_create(SNMP_MSG_TRAP2);
840
0
        if (!template_v2pdu) {
841
0
            snmp_log(LOG_WARNING,
842
0
                     "send_trap: failed to construct v2 template PDU\n");
843
0
            snmp_free_varbind(vblist);
844
0
            return -1;
845
0
        }
846
847
        /*
848
         * Check the varbind list we've been given.
849
         * If it starts with a 'sysUptime.0' varbind, then use that.
850
         * Otherwise, prepend a suitable 'sysUptime.0' varbind.
851
         */
852
0
        if (!snmp_oid_compare( vblist->name,    vblist->name_length,
853
0
                               sysuptime_oid, sysuptime_oid_len )) {
854
0
            template_v2pdu->variables = vblist;
855
0
            trap_vb  = vblist->next_variable;
856
0
        } else {
857
0
            uptime   = netsnmp_get_agent_uptime();
858
0
            var = NULL;
859
0
            snmp_varlist_add_variable( &var,
860
0
                           sysuptime_oid, sysuptime_oid_len,
861
0
                           ASN_TIMETICKS, (u_char*)&uptime, sizeof(uptime));
862
0
            if (!var) {
863
0
                snmp_log(LOG_WARNING,
864
0
                     "send_trap: failed to insert sysUptime varbind\n");
865
0
                snmp_free_pdu(template_v2pdu);
866
0
                snmp_free_varbind(vblist);
867
0
                return -1;
868
0
            }
869
0
            template_v2pdu->variables = var;
870
0
            var->next_variable        = vblist;
871
0
            trap_vb  = vblist;
872
0
        }
873
874
        /*
875
         * 'trap_vb' should point to the snmpTrapOID.0 varbind,
876
         *   identifying the requested trap.  If not then bomb out.
877
         * If it's a 'standard' trap, then we need to append an
878
         *   snmpEnterprise varbind (if there isn't already one).
879
         */
880
0
        if (!trap_vb ||
881
0
            snmp_oid_compare(trap_vb->name, trap_vb->name_length,
882
0
                             snmptrap_oid,  snmptrap_oid_len)) {
883
0
            snmp_log(LOG_WARNING,
884
0
                     "send_trap: no v2 trapOID varbind provided\n");
885
0
            snmp_free_pdu(template_v2pdu);
886
0
            return -1;
887
0
        }
888
0
        if (!snmp_oid_compare(vblist->val.objid, OID_LENGTH(trap_prefix),
889
0
                              trap_prefix,       OID_LENGTH(trap_prefix))) {
890
0
            var = find_varbind_in_list( template_v2pdu->variables,
891
0
                                        snmptrapenterprise_oid,
892
0
                                        snmptrapenterprise_oid_len);
893
0
            if (!var &&
894
0
                !snmp_varlist_add_variable( &(template_v2pdu->variables),
895
0
                     snmptrapenterprise_oid, snmptrapenterprise_oid_len,
896
0
                     ASN_OBJECT_ID,
897
0
                     enterprise, enterprise_length*sizeof(oid))) {
898
0
                snmp_log(LOG_WARNING,
899
0
                     "send_trap: failed to add snmpEnterprise to v2 trap\n");
900
0
                snmp_free_pdu(template_v2pdu);
901
0
                return -1;
902
0
            }
903
0
        }
904
            
905
906
        /*
907
         * If everything's OK, convert the v2 template into an SNMPv1 trap PDU.
908
         */
909
0
        template_v1pdu = convert_v2pdu_to_v1( template_v2pdu );
910
0
        if (!template_v1pdu) {
911
0
            snmp_log(LOG_WARNING,
912
0
                     "send_trap: failed to convert v2->v1 template PDU\n");
913
0
        }
914
915
0
    } else {
916
        /*
917
         * Construct the SNMPv1 trap PDU....
918
         */
919
0
        template_v1pdu = snmp_pdu_create(SNMP_MSG_TRAP);
920
0
        if (!template_v1pdu) {
921
0
            snmp_log(LOG_WARNING,
922
0
                     "send_trap: failed to construct v1 template PDU\n");
923
0
            snmp_free_varbind(vblist);
924
0
            return -1;
925
0
        }
926
0
        template_v1pdu->trap_type     = trap;
927
0
        template_v1pdu->specific_type = specific;
928
0
        template_v1pdu->time          = netsnmp_get_agent_uptime();
929
930
0
        if (snmp_clone_mem((void **) &template_v1pdu->enterprise,
931
0
                       enterprise, enterprise_length * sizeof(oid))) {
932
0
            snmp_log(LOG_WARNING,
933
0
                     "send_trap: failed to set v1 enterprise OID\n");
934
0
            snmp_free_varbind(vblist);
935
0
            snmp_free_pdu(template_v1pdu);
936
0
            return -1;
937
0
        }
938
0
        template_v1pdu->enterprise_length = enterprise_length;
939
940
0
        template_v1pdu->flags    |= UCD_MSG_FLAG_FORCE_PDU_COPY;
941
0
        template_v1pdu->variables = vblist;
942
943
        /*
944
         * ... and convert it into an SNMPv2-style notification PDU.
945
         */
946
947
0
        template_v2pdu = convert_v1pdu_to_v2( template_v1pdu );
948
0
        if (!template_v2pdu) {
949
0
            snmp_log(LOG_WARNING,
950
0
                     "send_trap: failed to convert v1->v2 template PDU\n");
951
0
        }
952
0
    }
953
954
    /*
955
     * Check whether we're ignoring authFail traps
956
     */
957
0
    if (template_v1pdu) {
958
0
      if (template_v1pdu->trap_type == SNMP_TRAP_AUTHFAIL &&
959
0
        snmp_enableauthentraps == SNMP_AUTHENTICATED_TRAPS_DISABLED) {
960
0
        snmp_free_pdu(template_v1pdu);
961
0
        snmp_free_pdu(template_v2pdu);
962
0
        return 0;
963
0
      }
964
965
    /*
966
     * Ensure that the v1 trap PDU includes the local IP address
967
     */
968
0
       pdu_in_addr_t = (in_addr_t *) template_v1pdu->agent_addr;
969
0
       v1trapaddress = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
970
0
                                             NETSNMP_DS_AGENT_TRAP_ADDR);
971
0
       if (v1trapaddress != NULL) {
972
           /* "v1trapaddress" was specified in config, try to resolve it */
973
0
           res = netsnmp_gethostbyname_v4(v1trapaddress, pdu_in_addr_t);
974
0
       }
975
0
       if (v1trapaddress == NULL || res < 0) {
976
           /* "v1trapaddress" was not specified in config or the resolution failed,
977
            * try any local address */
978
0
           *pdu_in_addr_t = get_myaddr();
979
0
       }
980
981
0
    }
982
983
0
    if (template_v2pdu) {
984
  /* A context name was provided, so copy it and its length to the v2 pdu
985
   * template. */
986
0
  if (context != NULL)
987
0
  {
988
0
    template_v2pdu->contextName    = strdup(context);
989
0
    template_v2pdu->contextNameLen = strlen(context);
990
0
  }
991
0
    }
992
993
    /*
994
     *  Now loop through the list of trap sinks
995
     *   and call the trap callback routines,
996
     *   providing an appropriately formatted PDU in each case
997
     */
998
0
    for (sink = sinks; sink; sink = sink->next) {
999
0
#ifndef NETSNMP_DISABLE_SNMPV1
1000
0
        if (sink->version == SNMP_VERSION_1) {
1001
0
            if (template_v1pdu &&
1002
0
                !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1003
0
                                        NETSNMP_DS_LIB_DISABLE_V1)) {
1004
0
                send_trap_to_sess(sink->sesp, template_v1pdu);
1005
0
            }
1006
0
        } else
1007
0
#endif
1008
0
        if (template_v2pdu) {
1009
0
            template_v2pdu->command = sink->pdutype;
1010
0
            send_trap_to_sess(sink->sesp, template_v2pdu);
1011
0
        }
1012
0
    }
1013
0
#ifndef NETSNMP_DISABLE_SNMPV1
1014
0
    if (template_v1pdu)
1015
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1016
0
                        SNMPD_CALLBACK_SEND_TRAP1, template_v1pdu);
1017
0
#endif
1018
0
    if (template_v2pdu)
1019
0
        snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
1020
0
                        SNMPD_CALLBACK_SEND_TRAP2, template_v2pdu);
1021
0
    snmp_free_pdu(template_v1pdu);
1022
0
    snmp_free_pdu(template_v2pdu);
1023
0
    return 0;
1024
0
}
1025
1026
1027
void
1028
send_enterprise_trap_vars(int trap,
1029
                          int specific,
1030
                          const oid * enterprise, int enterprise_length,
1031
                          netsnmp_variable_list * vars)
1032
0
{
1033
0
    netsnmp_send_traps(trap, specific,
1034
0
                       enterprise, enterprise_length,
1035
0
                       vars, NULL, 0);
1036
0
    return;
1037
0
}
1038
1039
/**
1040
 * Handles stats for basic traps (really just send failed
1041
*/
1042
int
1043
handle_trap_callback(int op, netsnmp_session * session, int reqid,
1044
                     netsnmp_pdu *pdu, void *magic)
1045
0
{
1046
0
    if (NULL == session)
1047
0
        return 0;
1048
1049
0
    DEBUGMSGTL(("trap", "handle_trap_callback for session %s\n",
1050
0
                session->paramName ? session->paramName : "UNKNOWN"));
1051
0
    switch (op) {
1052
1053
0
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
1054
0
        DEBUGMSGTL(("trap", "failed to send an inform for reqid=%d\n", reqid));
1055
0
#ifndef NETSNMP_NO_TRAP_STATS
1056
0
        if (session->trap_stats) {
1057
0
            session->trap_stats->sent_last_fail = netsnmp_get_agent_uptime();
1058
0
            ++session->trap_stats->sent_fail_count;
1059
0
        }
1060
0
#endif /* NETSNMP_NO_TRAP_STATS */
1061
0
        break;
1062
1063
0
    case NETSNMP_CALLBACK_OP_SEC_ERROR:
1064
0
        DEBUGMSGTL(("trap", "sec error sending a trap for reqid=%d\n",
1065
0
                    reqid));
1066
0
#ifndef NETSNMP_NO_TRAP_STATS
1067
0
        if (session->trap_stats) {
1068
0
            session->trap_stats->sec_err_last = netsnmp_get_agent_uptime();
1069
0
            ++session->trap_stats->sec_err_count;
1070
0
        }
1071
0
#endif /* NETSNMP_NO_TRAP_STATS */
1072
0
        break;
1073
1074
0
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
1075
0
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
1076
0
    case NETSNMP_CALLBACK_OP_RESEND:
1077
0
    default:
1078
0
        DEBUGMSGTL(("trap",
1079
0
                    "received op=%d for reqid=%d when trying to send a trap\n",
1080
0
                    op, reqid));
1081
0
    }
1082
0
#ifndef NETSNMP_NO_TRAP_STATS
1083
0
    if (session->trap_stats)
1084
0
        _dump_trap_stats(session);
1085
0
#endif /* NETSNMP_NO_TRAP_STATS */
1086
1087
0
    return 1;
1088
0
}
1089
1090
1091
/**
1092
 * Captures responses or the lack there of from INFORMs that were sent
1093
 * 1) a response is received from an INFORM
1094
 * 2) one isn't received and the retries/timeouts have failed
1095
*/
1096
int
1097
handle_inform_response(int op, netsnmp_session * session,
1098
                       int reqid, netsnmp_pdu *pdu,
1099
                       void *magic)
1100
0
{
1101
0
    if (NULL == session)
1102
0
        return 0;
1103
1104
0
    DEBUGMSGTL(("trap", "handle_inform_response for session %s\n",
1105
0
                session->paramName ? session->paramName : "UNKNOWN"));
1106
0
    switch (op) {
1107
1108
0
    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
1109
0
        snmp_increment_statistic(STAT_SNMPINPKTS);
1110
0
        if (pdu->command != SNMP_MSG_REPORT) {
1111
0
            DEBUGMSGTL(("trap", "received the inform response for reqid=%d\n",
1112
0
                        reqid));
1113
0
#ifndef NETSNMP_NO_TRAP_STATS
1114
0
            if (session->trap_stats) {
1115
0
                ++session->trap_stats->ack_count;
1116
0
                session->trap_stats->ack_last_rcvd = netsnmp_get_agent_uptime();
1117
0
            }
1118
0
#endif /* NETSNMP_NO_TRAP_STATS */
1119
0
            break;
1120
0
        } else {
1121
0
            int type = session->s_snmp_errno ? session->s_snmp_errno :
1122
0
                snmpv3_get_report_type(pdu);
1123
0
            DEBUGMSGTL(("trap", "received report %d for inform reqid=%d\n",
1124
0
                        type, reqid));
1125
            /*
1126
             * xxx-rks: what stats, if any, to bump for other report types?
1127
             * - ignore NOT_IN_TIME, as agent will sync and retry.
1128
             */
1129
0
            if (SNMPERR_AUTHENTICATION_FAILURE != type)
1130
0
                break;
1131
0
        }
1132
        /** AUTH failures fall through to sec error */
1133
0
  NETSNMP_FALLTHROUGH;
1134
1135
0
    case NETSNMP_CALLBACK_OP_SEC_ERROR:
1136
0
        DEBUGMSGTL(("trap", "sec error sending an inform for reqid=%d\n",
1137
0
                    reqid));
1138
0
#ifndef NETSNMP_NO_TRAP_STATS
1139
0
        if (session->trap_stats) {
1140
0
            session->trap_stats->sec_err_last = netsnmp_get_agent_uptime();
1141
0
            ++session->trap_stats->sec_err_count;
1142
0
        }
1143
0
#endif /* NETSNMP_NO_TRAP_STATS */
1144
0
        break;
1145
1146
0
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
1147
0
        DEBUGMSGTL(("trap",
1148
0
                    "received a timeout sending an inform for reqid=%d\n",
1149
0
                    reqid));
1150
0
#ifndef NETSNMP_NO_TRAP_STATS
1151
0
        if (session->trap_stats) {
1152
0
            ++session->trap_stats->timeouts;
1153
0
            session->trap_stats->sent_last_timeout =
1154
0
                netsnmp_get_agent_uptime();
1155
0
        }
1156
0
#endif /* NETSNMP_NO_TRAP_STATS */
1157
0
        break;
1158
1159
0
    case NETSNMP_CALLBACK_OP_RESEND:
1160
0
        DEBUGMSGTL(("trap", "resending an inform for reqid=%d\n", reqid));
1161
0
#ifndef NETSNMP_NO_TRAP_STATS
1162
0
        if (session->trap_stats)
1163
0
            session->trap_stats->sent_last_sent = netsnmp_get_agent_uptime();
1164
0
#endif /* NETSNMP_NO_TRAP_STATS */
1165
0
        break;
1166
1167
0
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
1168
0
        DEBUGMSGTL(("trap", "failed to send an inform for reqid=%d\n", reqid));
1169
0
#ifndef NETSNMP_NO_TRAP_STATS
1170
0
        if (session->trap_stats) {
1171
0
            session->trap_stats->sent_last_fail = netsnmp_get_agent_uptime();
1172
0
            ++session->trap_stats->sent_fail_count;
1173
0
        }
1174
0
#endif /* NETSNMP_NO_TRAP_STATS */
1175
0
        break;
1176
1177
0
    default:
1178
0
        DEBUGMSGTL(("trap", "received op=%d for reqid=%d when trying to send an inform\n", op, reqid));
1179
0
    }
1180
1181
0
#ifndef NETSNMP_NO_TRAP_STATS
1182
0
    if (session->trap_stats)
1183
0
        _dump_trap_stats(session);
1184
0
#endif /* NETSNMP_NO_TRAP_STATS */
1185
1186
0
    return 1;
1187
0
}
1188
1189
1190
/*
1191
 * send_trap_to_sess: sends a trap to a session but assumes that the
1192
 * pdu is constructed correctly for the session type. 
1193
 */
1194
void
1195
send_trap_to_sess(netsnmp_session * sess, netsnmp_pdu *template_pdu)
1196
0
{
1197
0
    netsnmp_pdu    *pdu;
1198
0
    int            result;
1199
1200
0
    if (!sess || !template_pdu)
1201
0
        return;
1202
1203
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(sess->version)) {
1204
0
        DEBUGMSGTL(("trap", "not sending trap type=%d, version %02lx disabled\n",
1205
0
                    template_pdu->command, sess->version));
1206
0
        return;
1207
0
    }
1208
0
    DEBUGIF("trap") {
1209
0
        struct session_list *sessp = snmp_sess_pointer(sess);
1210
0
        netsnmp_transport *t = sessp->transport;
1211
0
        const void *dst = template_pdu->transport_data;
1212
0
        const int dst_len = template_pdu->transport_data_length;
1213
0
        char *peer = NULL;
1214
1215
0
        if (t && t->f_fmtaddr)
1216
0
            peer = t->f_fmtaddr(t, dst, dst_len);
1217
0
        DEBUGMSGTL(("trap", "sending trap type=%d, version=%ld to %s\n",
1218
0
                    template_pdu->command, sess->version, peer ? peer : "(?)"));
1219
0
        free(peer);
1220
0
    }
1221
1222
0
#ifndef NETSNMP_DISABLE_SNMPV1
1223
0
    if (sess->version == SNMP_VERSION_1 &&
1224
0
        (template_pdu->command != SNMP_MSG_TRAP))
1225
0
        return;                 /* Skip v1 sinks for v2 only traps */
1226
0
    if (sess->version != SNMP_VERSION_1 &&
1227
0
        (template_pdu->command == SNMP_MSG_TRAP))
1228
0
        return;                 /* Skip v2+ sinks for v1 only traps */
1229
0
#endif
1230
0
    template_pdu->version = sess->version;
1231
0
    pdu = snmp_clone_pdu(template_pdu);
1232
0
    if(!pdu) {
1233
0
        snmp_log(LOG_WARNING, "send_trap: failed to clone PDU\n");
1234
0
        return;
1235
0
    }
1236
1237
0
    pdu->sessid = sess->sessid; /* AgentX only ? */
1238
    /*
1239
     * RFC 3414 sayeth:
1240
     *
1241
     * - If an SNMP engine uses a msgID for correlating Response messages to
1242
     *   outstanding Request messages, then it MUST use different msgIDs in
1243
     *   all such Request messages that it sends out during a Time Window
1244
     *   (150 seconds) period.
1245
     *
1246
     *   A Command Generator or Notification Originator Application MUST use
1247
     *   different request-ids in all Request PDUs that it sends out during
1248
     *   a TimeWindow (150 seconds) period.
1249
     */
1250
0
    pdu->reqid = snmp_get_next_reqid();
1251
0
    pdu->msgid = snmp_get_next_msgid();
1252
1253
0
#ifndef NETSNMP_NO_TRAP_STATS
1254
    /** allocate space for trap stats */
1255
0
    if (NULL == sess->trap_stats) {
1256
0
        sess->trap_stats = SNMP_MALLOC_TYPEDEF(netsnmp_trap_stats);
1257
0
        if (NULL == sess->trap_stats)
1258
0
            snmp_log(LOG_ERR, "malloc for %s trap stats failed\n",
1259
0
                     sess->paramName ? sess->paramName : "UNKNOWN");
1260
0
    }
1261
0
#endif /* NETSNMP_NO_TRAP_STATS */
1262
1263
0
    if ( template_pdu->command == SNMP_MSG_INFORM
1264
0
#ifdef USING_AGENTX_PROTOCOL_MODULE
1265
0
         || template_pdu->command == AGENTX_MSG_NOTIFY
1266
0
#endif
1267
0
       ) {
1268
0
        result =
1269
0
            snmp_async_send(sess, pdu, &handle_inform_response, NULL);
1270
0
    } else {
1271
0
        if ((sess->version == SNMP_VERSION_3) &&
1272
0
                (pdu->command == SNMP_MSG_TRAP2) &&
1273
0
                (sess->securityEngineIDLen == 0)) {
1274
0
            u_char          tmp[SPRINT_MAX_LEN];
1275
1276
0
            int len = snmpv3_get_engineID(tmp, sizeof(tmp));
1277
0
            pdu->securityEngineID = netsnmp_memdup(tmp, len);
1278
0
            pdu->securityEngineIDLen = len;
1279
0
        }
1280
1281
0
        result = snmp_async_send(sess, pdu, &handle_trap_callback, NULL);
1282
0
    }
1283
1284
0
    if (result == 0) {
1285
0
        snmp_sess_perror("snmpd: send_trap", sess);
1286
0
        snmp_free_pdu(pdu);
1287
        /** trap stats for failure handled in callback */
1288
0
    } else {
1289
0
        snmp_increment_statistic(STAT_SNMPOUTTRAPS);
1290
0
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
1291
0
#ifndef NETSNMP_NO_TRAP_STATS
1292
0
        if (sess->trap_stats) {
1293
0
            sess->trap_stats->sent_last_sent = netsnmp_get_agent_uptime();
1294
0
            ++sess->trap_stats->sent_count;
1295
0
            _dump_trap_stats(sess);
1296
0
        }
1297
0
#endif /* NETSNMP_NO_TRAP_STATS */
1298
0
    }
1299
0
}
1300
1301
void
1302
send_trap_vars(int trap, int specific, netsnmp_variable_list * vars)
1303
0
{
1304
0
    if (trap == SNMP_TRAP_ENTERPRISESPECIFIC)
1305
0
        send_enterprise_trap_vars(trap, specific, objid_enterprisetrap,
1306
0
                                  OID_LENGTH(objid_enterprisetrap), vars);
1307
0
    else
1308
0
        send_enterprise_trap_vars(trap, specific, trap_version_id,
1309
0
                                  OID_LENGTH(trap_version_id), vars);
1310
0
}
1311
1312
#ifndef NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT
1313
/* Send a trap under a context */
1314
void send_trap_vars_with_context(int trap, int specific, 
1315
              netsnmp_variable_list *vars, const char *context)
1316
0
{
1317
0
    if (trap == SNMP_TRAP_ENTERPRISESPECIFIC)
1318
0
        netsnmp_send_traps(trap, specific, objid_enterprisetrap,
1319
0
                                  OID_LENGTH(objid_enterprisetrap), vars,
1320
0
                  context, 0);
1321
0
    else
1322
0
        netsnmp_send_traps(trap, specific, trap_version_id,
1323
0
                                  OID_LENGTH(trap_version_id), vars, 
1324
0
                  context, 0);
1325
      
1326
0
}
1327
#endif /* NETSNMP_FEATURE_REMOVE_TRAP_VARS_WITH_CONTEXT */
1328
1329
/**
1330
 * Sends an SNMPv1 trap (or the SNMPv2 equivalent) to the list of  
1331
 * configured trap destinations (or "sinks"), using the provided 
1332
 * values for the generic trap type and specific trap value.
1333
 *
1334
 * This function eventually calls send_enterprise_trap_vars.  If the
1335
 * trap type is not set to SNMP_TRAP_ENTERPRISESPECIFIC the enterprise 
1336
 * and enterprise_length parameter is set to the pre defined NETSNMP_SYSTEM_MIB 
1337
 * oid and length respectively.  If the trap type is set to 
1338
 * SNMP_TRAP_ENTERPRISESPECIFIC the enterprise and enterprise_length 
1339
 * parameters are set to the pre-defined NETSNMP_NOTIFICATION_MIB oid and length 
1340
 * respectively.
1341
 *
1342
 * @param trap is the generic trap type.
1343
 *
1344
 * @param specific is the specific trap value.
1345
 *
1346
 * @return void
1347
 *
1348
 * @see send_enterprise_trap_vars
1349
 * @see send_v2trap
1350
 */
1351
        
1352
void
1353
send_easy_trap(int trap, int specific)
1354
0
{
1355
0
    send_trap_vars(trap, specific, NULL);
1356
0
}
1357
1358
/**
1359
 * Uses the supplied list of variable bindings to form an SNMPv2 trap, 
1360
 * which is sent to SNMPv2-capable sinks  on  the  configured  list.  
1361
 * An equivalent INFORM is sent to the configured list of inform sinks.  
1362
 * Sinks that can only handle SNMPv1 traps are skipped.
1363
 *
1364
 * This function eventually calls send_enterprise_trap_vars.  If the
1365
 * trap type is not set to SNMP_TRAP_ENTERPRISESPECIFIC the enterprise 
1366
 * and enterprise_length parameter is set to the pre defined NETSNMP_SYSTEM_MIB 
1367
 * oid and length respectively.  If the trap type is set to 
1368
 * SNMP_TRAP_ENTERPRISESPECIFIC the enterprise and enterprise_length 
1369
 * parameters are set to the pre-defined NETSNMP_NOTIFICATION_MIB oid and length 
1370
 * respectively.
1371
 *
1372
 * @param vars is used to supply list of variable bindings to form an SNMPv2 
1373
 *  trap.
1374
 *
1375
 * @return void
1376
 *
1377
 * @see send_easy_trap
1378
 * @see send_enterprise_trap_vars
1379
 */
1380
1381
void
1382
send_v2trap(netsnmp_variable_list * vars)
1383
0
{
1384
0
    send_trap_vars(-1, -1, vars);
1385
0
}
1386
1387
/**
1388
 * Similar to send_v2trap(), with the added ability to specify a context.  If
1389
 * the last parameter is NULL, then this call is equivalent to send_v2trap().
1390
 *
1391
 * @param vars is used to supply the list of variable bindings for the trap.
1392
 * 
1393
 * @param context is used to specify the context of the trap.
1394
 *
1395
 * @return void
1396
 *
1397
 * @see send_v2trap
1398
 */
1399
#ifndef NETSNMP_FEATURE_REMOVE_SEND_V3TRAP
1400
void send_v3trap(netsnmp_variable_list *vars, const char *context)
1401
0
{
1402
0
    netsnmp_send_traps(-1, -1, 
1403
0
                       trap_version_id, OID_LENGTH(trap_version_id),
1404
0
                       vars, context, 0);
1405
0
}
1406
#endif /* NETSNMP_FEATURE_REMOVE_SEND_V3TRAP */
1407
1408
#ifndef NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU
1409
void
1410
send_trap_pdu(netsnmp_pdu *pdu)
1411
0
{
1412
0
    send_trap_vars(-1, -1, pdu->variables);
1413
0
}
1414
#endif /* NETSNMP_FEATURE_REMOVE_SEND_TRAP_PDU */
1415
1416
1417
1418
        /*******************
1419
   *
1420
   * Config file handling
1421
   *
1422
   *******************/
1423
1424
void
1425
snmpd_parse_config_authtrap(const char *token, char *cptr)
1426
0
{
1427
0
    int             i;
1428
1429
0
    i = atoi(cptr);
1430
0
    if (i == 0) {
1431
0
        if (strcmp(cptr, "enable") == 0) {
1432
0
            i = SNMP_AUTHENTICATED_TRAPS_ENABLED;
1433
0
        } else if (strcmp(cptr, "disable") == 0) {
1434
0
            i = SNMP_AUTHENTICATED_TRAPS_DISABLED;
1435
0
        }
1436
0
    }
1437
0
    if (i < 1 || i > 2) {
1438
0
        config_perror("authtrapenable must be 1 or 2");
1439
0
    } else {
1440
0
        if (strcmp(token, "pauthtrapenable") == 0) {
1441
0
            if (snmp_enableauthentrapsset < 0) {
1442
                /*
1443
                 * This is bogus (and shouldn't happen anyway) -- the value
1444
                 * of snmpEnableAuthenTraps.0 is already configured
1445
                 * read-only.  
1446
                 */
1447
0
                snmp_log(LOG_WARNING,
1448
0
                         "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
1449
0
                return;
1450
0
            } else {
1451
0
                snmp_enableauthentrapsset++;
1452
0
            }
1453
0
        } else {
1454
0
            if (snmp_enableauthentrapsset > 0) {
1455
                /*
1456
                 * This is bogus (and shouldn't happen anyway) -- we already
1457
                 * read a persistent value of snmpEnableAuthenTraps.0, which
1458
                 * we should ignore in favour of this one.  
1459
                 */
1460
0
                snmp_log(LOG_WARNING,
1461
0
                         "ignoring attempted override of read-only snmpEnableAuthenTraps.0\n");
1462
                /*
1463
                 * Fall through and copy in this value.  
1464
                 */
1465
0
            }
1466
0
            snmp_enableauthentrapsset = -1;
1467
0
        }
1468
0
        snmp_enableauthentraps = i;
1469
0
    }
1470
0
}
1471
1472
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1473
static void
1474
_parse_config_sink(const char *token, char *cptr, int version, int type)
1475
0
{
1476
0
    char           *sp, *cp, *pp = NULL, *src = NULL;
1477
0
    char           *st, *name = NULL, *tag = NULL, *profile = NULL;
1478
0
    int            done = 0;
1479
1480
0
    if (!snmp_trapcommunity)
1481
0
        snmp_trapcommunity = strdup("public");
1482
0
    sp = strtok_r(cptr, " \t\n", &st);
1483
0
    if (!sp)
1484
0
        return;
1485
    /*
1486
     * check for optional arguments
1487
     */
1488
0
    do {
1489
0
        if (*sp != '-') {
1490
0
            done = 1;
1491
0
            continue;
1492
0
        }
1493
0
        if (strcmp(sp, "-name") == 0)
1494
0
            name = strtok_r(NULL, " \t\n", &st);
1495
0
        else if (strcmp(sp, "-tag") == 0)
1496
0
            tag = strtok_r(NULL, " \t\n", &st);
1497
0
        else if (strcmp(sp, "-profile") == 0)
1498
0
            profile = strtok_r(NULL, " \t\n", &st);
1499
0
        else if (strcmp(sp, "-s") == 0)
1500
0
            src = strtok_r(NULL, " \t\n", &st);
1501
0
        else
1502
0
            netsnmp_config_warn("ignoring unknown argument: %s", sp);
1503
0
        sp = strtok_r(NULL, " \t\n", &st);
1504
0
    } while (!done);
1505
0
    cp = strtok_r(NULL, " \t\n", &st);
1506
0
    if (cp)
1507
0
        pp = strtok_r(NULL, " \t\n", &st);
1508
0
    if (pp)
1509
0
        config_pwarn("The separate port argument for sinks is deprecated");
1510
0
    if (netsnmp_create_v1v2_notification_session(sp, pp,
1511
0
                                                 cp ? cp : snmp_trapcommunity,
1512
0
                                                 src, version, type, name, tag,
1513
0
                                                 profile) == NULL) {
1514
0
        netsnmp_config_error("cannot create sink: %s", cptr);
1515
0
    }
1516
0
}
1517
#endif
1518
1519
#ifndef NETSNMP_DISABLE_SNMPV1
1520
void
1521
snmpd_parse_config_trapsink(const char *token, char *cptr)
1522
0
{
1523
0
    _parse_config_sink(token, cptr, SNMP_VERSION_1, SNMP_MSG_TRAP);
1524
0
}
1525
#endif
1526
1527
#ifndef NETSNMP_DISABLE_SNMPV2C
1528
void
1529
snmpd_parse_config_trap2sink(const char *word, char *cptr)
1530
0
{
1531
0
    _parse_config_sink(word, cptr, SNMP_VERSION_2c, SNMP_MSG_TRAP2);
1532
0
}
1533
1534
void
1535
snmpd_parse_config_informsink(const char *word, char *cptr)
1536
0
{
1537
0
    _parse_config_sink(word, cptr, SNMP_VERSION_2c, SNMP_MSG_INFORM);
1538
0
}
1539
#endif
1540
1541
/*
1542
 * this must be standardized somewhere, right? 
1543
 */
1544
0
#define MAX_ARGS 128
1545
1546
static int      traptype;
1547
1548
static void
1549
trapOptProc(int argc, char *const *argv, int opt)
1550
0
{
1551
0
    switch (opt) {
1552
0
    case 'C':
1553
0
        while (*optarg) {
1554
0
            switch (*optarg++) {
1555
0
            case 'i':
1556
0
                traptype = SNMP_MSG_INFORM;
1557
0
                break;
1558
0
            default:
1559
0
                config_perror("unknown argument passed to -C");
1560
0
                break;
1561
0
            }
1562
0
        }
1563
0
        break;
1564
0
    }
1565
0
}
1566
1567
netsnmp_session *
1568
netsnmp_create_v3user_notification_session(const char *dest, const char *user,
1569
                                           int level, const char *context,
1570
                                           int pdutype, const u_char *engineId,
1571
                                           size_t engineId_len, const char *src,
1572
                                           const char *notif_name,
1573
                                           const char *notif_tag,
1574
                                           const char* notif_profile)
1575
0
{
1576
0
    netsnmp_session    session, *ss = NULL;
1577
0
    struct usmUser    *usmUser;
1578
0
    netsnmp_tdomain_spec tspec;
1579
0
    netsnmp_transport *transport;
1580
0
    u_char             tmp_engineId[SPRINT_MAX_LEN];
1581
0
    int                rc;
1582
1583
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1584
0
                               NETSNMP_DS_LIB_DISABLE_V3)) {
1585
0
        netsnmp_config_error("SNMPv3 disabled, cannot create notification session");
1586
0
        return NULL;
1587
0
    }
1588
0
    if (NULL == dest || NULL == user)
1589
0
        return NULL;
1590
1591
    /** authlevel */
1592
0
    if ((SNMP_SEC_LEVEL_AUTHPRIV != level) &&
1593
0
        (SNMP_SEC_LEVEL_AUTHNOPRIV != level) &&
1594
0
        (SNMP_SEC_LEVEL_NOAUTH != level)) {
1595
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "bad level %d\n", level));
1596
0
        return NULL;
1597
0
    }
1598
1599
    /** need engineId to look up users */
1600
0
    if (NULL == engineId) {
1601
0
        engineId_len = snmpv3_get_engineID( tmp_engineId, sizeof(tmp_engineId));
1602
0
        engineId = tmp_engineId;
1603
0
    }
1604
1605
0
    usmUser = usm_get_user(engineId, engineId_len, user);
1606
0
    if (NULL == usmUser) {
1607
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "usmUser %s not found\n", user));
1608
0
        return NULL;
1609
0
    }
1610
1611
0
    snmp_sess_init(&session);
1612
1613
0
    session.callback = handle_disconnect_packet;
1614
1615
0
    session.version = SNMP_VERSION_3;
1616
1617
0
    session.peername = strdup(dest);
1618
1619
0
    session.securityName = strdup(user);
1620
0
    session.securityNameLen = strlen(user);
1621
1622
0
    if (context) {
1623
0
        session.contextName = strdup(context);
1624
0
        session.contextNameLen = strlen(context);
1625
0
    }
1626
1627
0
    session.securityLevel = level;
1628
1629
    /** auth prot */
1630
0
    if (NULL != usmUser->authProtocol) {
1631
0
        session.securityAuthProto =
1632
0
            snmp_duplicate_objid(usmUser->authProtocol,
1633
0
                                 usmUser->authProtocolLen);
1634
0
        session.securityAuthProtoLen = usmUser->authProtocolLen;
1635
0
        if (NULL == session.securityAuthProto)
1636
0
            goto bail;
1637
0
    }
1638
1639
    /** authkey */
1640
0
    if (((SNMP_SEC_LEVEL_AUTHPRIV == level) ||
1641
0
         (SNMP_SEC_LEVEL_AUTHNOPRIV == level)) &&
1642
0
        (usmUser->flags & USMUSER_FLAG_KEEP_MASTER_KEY)) {
1643
0
        netsnmp_assert(usmUser->authKeyKuLen > 0);
1644
0
        memcpy(session.securityAuthKey, usmUser->authKeyKu,
1645
0
               usmUser->authKeyKuLen);
1646
0
        session.securityAuthKeyLen = usmUser->authKeyKuLen;
1647
0
    }
1648
1649
    /** priv prot */
1650
0
    if (NULL != usmUser->privProtocol) {
1651
0
        session.securityPrivProto =
1652
0
            snmp_duplicate_objid(usmUser->privProtocol,
1653
0
                                 usmUser->privProtocolLen);
1654
0
        session.securityPrivProtoLen = usmUser->privProtocolLen;
1655
0
        if (NULL == session.securityPrivProto)
1656
0
            goto bail;
1657
0
    }
1658
1659
    /** privkey */
1660
0
    if ((SNMP_SEC_LEVEL_AUTHPRIV == level)  &&
1661
0
        (usmUser->flags & USMUSER_FLAG_KEEP_MASTER_KEY)) {
1662
0
        netsnmp_assert(usmUser->privKeyKuLen > 0);
1663
0
        memcpy(session.securityPrivKey, usmUser->privKeyKu,
1664
0
               usmUser->privKeyKuLen);
1665
0
        session.securityPrivKeyLen = usmUser->privKeyKuLen;
1666
0
    }
1667
1668
    /** engineId */
1669
0
    session.contextEngineID = netsnmp_memdup(usmUser->engineID,
1670
0
                                             usmUser->engineIDLen);
1671
0
    session.contextEngineIDLen = usmUser->engineIDLen;
1672
1673
    /** open the tranport */
1674
1675
0
    memset(&tspec, 0, sizeof(netsnmp_tdomain_spec));
1676
0
    tspec.application = "snmptrap";
1677
0
    tspec.target = session.peername;
1678
0
    tspec.default_domain = NULL;
1679
0
    tspec.default_target = NULL;
1680
0
    tspec.source = src;
1681
0
    transport = netsnmp_tdomain_transport_tspec(&tspec);
1682
0
    if (transport == NULL) {
1683
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "could not create transport\n"));
1684
0
        goto bail;
1685
0
    }
1686
1687
0
    if ((rc = netsnmp_sess_config_and_open_transport(&session, transport))
1688
0
        != SNMPERR_SUCCESS) {
1689
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "config/open failed\n"));
1690
0
        goto bail;
1691
0
    }
1692
1693
0
    ss = snmp_add(&session, transport, NULL, NULL);
1694
0
    if (!ss) {
1695
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "snmp_add failed\n"));
1696
0
        goto bail;
1697
0
    }
1698
1699
0
    if (netsnmp_add_closable_notification_session(ss,
1700
0
                                                  !(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM),
1701
0
                                                  pdutype,
1702
0
                                                  (pdutype == SNMP_MSG_INFORM),
1703
0
                                                  ss->version, notif_name, notif_tag,
1704
0
                                                  notif_profile) != 1) {
1705
0
        DEBUGMSGTL(("trap:v3user_notif_sess", "add notification failed\n"));
1706
0
        snmp_close(ss);
1707
0
        return NULL;
1708
0
    }
1709
1710
0
  bail:
1711
    /** free any allocated mem in session */
1712
0
    netsnmp_cleanup_session(&session);
1713
1714
0
    return ss;
1715
0
}
1716
1717
void
1718
snmpd_parse_config_trapsess(const char *word, char *cptr)
1719
0
{
1720
0
    char           *argv[MAX_ARGS], *cp = cptr;
1721
0
    char           *profile = NULL, *name = NULL, *tag = NULL;
1722
0
    int             argn, rc;
1723
0
    netsnmp_session session, *ss;
1724
0
    netsnmp_transport *transport;
1725
0
    size_t          len;
1726
0
    char            tmp[SPRINT_MAX_LEN];
1727
0
    char           *clientaddr_save = NULL;
1728
1729
    /*
1730
     * inform or trap?  default to trap 
1731
     */
1732
0
    traptype = SNMP_MSG_TRAP2;
1733
1734
0
    do {
1735
0
        if (strncmp(cp, "-profile", 8) == 0) {
1736
0
            cp = skip_token(cp);
1737
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1738
0
            free(profile);
1739
0
            profile = strdup(tmp);
1740
0
        } else if (strncmp(cp, "-name", 5) == 0) {
1741
0
            cp = skip_token(cp);
1742
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1743
0
            free(name);
1744
0
            name = strdup(tmp);
1745
0
        } else if (strncmp(cp, "-tag", 4) == 0) {
1746
0
            cp = skip_token(cp);
1747
0
            cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1748
0
            free(tag);
1749
0
            tag = strdup(tmp);
1750
0
        } else
1751
0
            break;
1752
0
    } while(cp);
1753
1754
    /*
1755
     * create the argv[] like array 
1756
     */
1757
0
    argv[0] = strdup("snmpd-trapsess"); /* bogus entry for getopt() */
1758
0
    for (argn = 1; cp && argn < MAX_ARGS; argn++) {
1759
0
        cp = copy_nword(cp, tmp, SPRINT_MAX_LEN);
1760
0
        argv[argn] = strdup(tmp);
1761
0
    }
1762
1763
    /** parse args (also initializes session) */
1764
0
    netsnmp_parse_args(argn, argv, &session, "C:", trapOptProc,
1765
0
                       NETSNMP_PARSE_ARGS_NOLOGGING |
1766
0
                       NETSNMP_PARSE_ARGS_NOZERO);
1767
1768
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(session.version)) {
1769
0
        config_perror("snmpd: protocol version disabled at runtime");
1770
0
        for (; argn > 0; argn--)
1771
0
            free(argv[argn - 1]);
1772
0
        goto cleanup;
1773
0
    }
1774
1775
0
    if (NULL != session.localname) {
1776
0
        clientaddr_save = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1777
0
                                                NETSNMP_DS_LIB_CLIENT_ADDR);
1778
0
        if (clientaddr_save)
1779
0
            clientaddr_save = strdup(clientaddr_save);
1780
0
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1781
0
                              NETSNMP_DS_LIB_CLIENT_ADDR,
1782
0
                              session.localname);
1783
0
    }
1784
1785
0
    transport = netsnmp_transport_open_client("snmptrap", session.peername);
1786
1787
0
    if (NULL != session.localname)
1788
0
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1789
0
                              NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
1790
1791
0
    if (transport == NULL) {
1792
0
        config_perror("snmpd: failed to parse this line.");
1793
0
        for (; argn > 0; argn--)
1794
0
            free(argv[argn - 1]);
1795
0
        goto cleanup;
1796
0
    }
1797
0
    if ((rc = netsnmp_sess_config_and_open_transport(&session, transport))
1798
0
        != SNMPERR_SUCCESS) {
1799
0
        session.s_snmp_errno = rc;
1800
0
        session.s_errno = 0;
1801
0
        for (; argn > 0; argn--)
1802
0
            free(argv[argn - 1]);
1803
0
        goto cleanup;
1804
0
    }
1805
0
    session.callback = handle_disconnect_packet;
1806
0
    ss = snmp_add(&session, transport, NULL, NULL);
1807
0
    for (; argn > 0; argn--)
1808
0
        free(argv[argn - 1]);
1809
1810
0
    if (!ss) {
1811
0
        config_perror
1812
0
            ("snmpd: failed to parse this line or the remote trap receiver is down.  Possible cause:");
1813
0
        snmp_sess_perror("snmpd: snmpd_parse_config_trapsess()", &session);
1814
0
        goto cleanup;
1815
0
    }
1816
1817
    /*
1818
     * If this is an SNMPv3 TRAP session, then the agent is
1819
     *   the authoritative engine, so set the engineID accordingly
1820
     */
1821
0
    if (ss->version == SNMP_VERSION_3 &&
1822
0
        traptype != SNMP_MSG_INFORM   &&
1823
0
        ss->securityEngineIDLen == 0) {
1824
0
            u_char          tmp[SPRINT_MAX_LEN];
1825
1826
0
            len = snmpv3_get_engineID( tmp, sizeof(tmp));
1827
0
            ss->securityEngineID = netsnmp_memdup(tmp, len);
1828
0
            ss->securityEngineIDLen = len;
1829
0
    }
1830
1831
0
#ifndef NETSNMP_DISABLE_SNMPV1
1832
0
    if ((ss->version == SNMP_VERSION_1) &&
1833
0
        !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1834
0
                                NETSNMP_DS_LIB_DISABLE_V1))
1835
0
        traptype = SNMP_MSG_TRAP;
1836
0
#endif
1837
0
    netsnmp_add_closable_notification_session(ss,
1838
0
                                              !(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM),
1839
0
                                              traptype,
1840
0
                                              (traptype == SNMP_MSG_INFORM),
1841
0
                                              ss->version, name, tag, profile);
1842
1843
0
  cleanup:
1844
0
    netsnmp_cleanup_session(&session);
1845
0
    SNMP_FREE(clientaddr_save);
1846
0
    SNMP_FREE(profile);
1847
0
    SNMP_FREE(name);
1848
0
    SNMP_FREE(tag);
1849
0
}
1850
1851
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1852
void
1853
snmpd_parse_config_trapcommunity(const char *word, char *cptr)
1854
0
{
1855
0
    if (snmp_trapcommunity != NULL) {
1856
0
        free(snmp_trapcommunity);
1857
0
    }
1858
0
    snmp_trapcommunity = (char *) malloc(strlen(cptr) + 1);
1859
0
    if (snmp_trapcommunity != NULL) {
1860
0
        copy_nword(cptr, snmp_trapcommunity, strlen(cptr) + 1);
1861
0
    }
1862
0
}
1863
1864
void
1865
snmpd_free_trapcommunity(void)
1866
6.12k
{
1867
6.12k
    if (snmp_trapcommunity) {
1868
0
        free(snmp_trapcommunity);
1869
0
        snmp_trapcommunity = NULL;
1870
0
    }
1871
6.12k
}
1872
#endif
1873
/** @} */