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