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