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