/src/net-snmp/agent/snmp_agent.c
Line | Count | Source |
1 | | /* |
2 | | * snmp_agent.c |
3 | | * |
4 | | * Simple Network Management Protocol (RFC 1067). |
5 | | */ |
6 | | /* Portions of this file are subject to the following copyrights. See |
7 | | * the Net-SNMP's COPYING file for more details and other copyrights |
8 | | * that may apply: |
9 | | */ |
10 | | /*********************************************************** |
11 | | Copyright 1988, 1989 by Carnegie Mellon University |
12 | | |
13 | | All Rights Reserved |
14 | | |
15 | | Permission to use, copy, modify, and distribute this software and its |
16 | | documentation for any purpose and without fee is hereby granted, |
17 | | provided that the above copyright notice appear in all copies and that |
18 | | both that copyright notice and this permission notice appear in |
19 | | supporting documentation, and that the name of CMU not be |
20 | | used in advertising or publicity pertaining to distribution of the |
21 | | software without specific, written prior permission. |
22 | | |
23 | | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
24 | | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
25 | | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
26 | | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
27 | | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
28 | | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
29 | | SOFTWARE. |
30 | | ******************************************************************/ |
31 | | /* |
32 | | * Portions of this file are copyrighted by: |
33 | | * Copyright © 2003 Sun Microsystems, Inc. All rights |
34 | | * reserved. Use is subject to license terms specified in the |
35 | | * COPYING file distributed with the Net-SNMP package. |
36 | | * |
37 | | * Portions of this file are copyrighted by: |
38 | | * Copyright (c) 2016 VMware, Inc. All rights reserved. |
39 | | * Use is subject to license terms specified in the COPYING file |
40 | | * distributed with the Net-SNMP package. |
41 | | */ |
42 | | /** @defgroup snmp_agent net-snmp agent related processing |
43 | | * @ingroup agent |
44 | | * |
45 | | * @{ |
46 | | */ |
47 | | #include <net-snmp/net-snmp-config.h> |
48 | | #include <net-snmp/net-snmp-features.h> |
49 | | |
50 | | #include <sys/types.h> |
51 | | #ifdef HAVE_LIMITS_H |
52 | | #include <limits.h> |
53 | | #endif |
54 | | #ifdef HAVE_STDLIB_H |
55 | | #include <stdlib.h> |
56 | | #endif |
57 | | #ifdef HAVE_UNISTD_H |
58 | | #include <unistd.h> |
59 | | #endif |
60 | | #ifdef HAVE_STRING_H |
61 | | #include <string.h> |
62 | | #endif |
63 | | #ifdef TIME_WITH_SYS_TIME |
64 | | # include <sys/time.h> |
65 | | # include <time.h> |
66 | | #else |
67 | | # ifdef HAVE_SYS_TIME_H |
68 | | # include <sys/time.h> |
69 | | # else |
70 | | # include <time.h> |
71 | | # endif |
72 | | #endif |
73 | | #ifdef HAVE_SYS_SELECT_H |
74 | | #include <sys/select.h> |
75 | | #endif |
76 | | #ifdef HAVE_NETDB_H |
77 | | #include <netdb.h> |
78 | | #endif |
79 | | #ifdef HAVE_NETINET_IN_H |
80 | | #include <netinet/in.h> |
81 | | #endif |
82 | | #ifdef HAVE_SYS_UN_H |
83 | | #include <sys/un.h> |
84 | | #endif |
85 | | #include <errno.h> |
86 | | |
87 | | #include <net-snmp/net-snmp-includes.h> |
88 | | #include <net-snmp/agent/net-snmp-agent-includes.h> |
89 | | #include <net-snmp/agent/agent_callbacks.h> |
90 | | #include <net-snmp/library/large_fd_set.h> |
91 | | #include <net-snmp/library/snmp_assert.h> |
92 | | #include "agent_global_vars.h" |
93 | | |
94 | | #ifdef HAVE_SYSLOG_H |
95 | | #include <syslog.h> |
96 | | #endif |
97 | | |
98 | | #ifdef NETSNMP_USE_LIBWRAP |
99 | | #include <tcpd.h> |
100 | | int allow_severity = LOG_INFO; |
101 | | int deny_severity = LOG_WARNING; |
102 | | #endif |
103 | | |
104 | | #include "snmpd.h" |
105 | | #include <net-snmp/agent/mib_module_config.h> |
106 | | #include <net-snmp/agent/mib_modules.h> |
107 | | |
108 | | #ifdef USING_AGENTX_PROTOCOL_MODULE |
109 | | #include "agentx/protocol.h" |
110 | | #endif |
111 | | |
112 | | #ifdef USING_AGENTX_MASTER_MODULE |
113 | | #include "agentx/master.h" |
114 | | #endif |
115 | | |
116 | | #ifdef USING_SMUX_MODULE |
117 | | #include "smux/smux.h" |
118 | | #endif |
119 | | |
120 | | netsnmp_feature_child_of(snmp_agent, libnetsnmpagent); |
121 | | netsnmp_feature_child_of(agent_debugging_utilities, libnetsnmpagent); |
122 | | |
123 | | netsnmp_feature_child_of(allocate_globalcacheid, snmp_agent); |
124 | | netsnmp_feature_child_of(free_agent_snmp_session_by_session, snmp_agent); |
125 | | netsnmp_feature_child_of(check_all_requests_error, snmp_agent); |
126 | | netsnmp_feature_child_of(check_requests_error, snmp_agent); |
127 | | netsnmp_feature_child_of(request_set_error_idx, snmp_agent); |
128 | | netsnmp_feature_child_of(set_agent_uptime, snmp_agent); |
129 | | netsnmp_feature_child_of(agent_check_and_process, snmp_agent); |
130 | | |
131 | | netsnmp_feature_child_of(agent_remove_list_data, netsnmp_unused); |
132 | | netsnmp_feature_child_of(set_all_requests_error, netsnmp_unused); |
133 | | netsnmp_feature_child_of(addrcache_age, netsnmp_unused); |
134 | | netsnmp_feature_child_of(delete_subtree_cache, netsnmp_unused); |
135 | | |
136 | | #ifndef NETSNMP_NO_PDU_STATS |
137 | | |
138 | | static netsnmp_container *_pdu_stats = NULL; |
139 | | static int _pdu_stats_max = 0; |
140 | | static u_long _pdu_stats_threshold = 0; |
141 | | static u_long _pdu_stats_current_lowest = 0; |
142 | | |
143 | | netsnmp_container * |
144 | | netsnmp_get_pdu_stats(void) |
145 | 0 | { |
146 | 0 | return _pdu_stats; |
147 | 0 | } |
148 | | |
149 | | int _pdu_stats_compare(const void *p, const void *q) |
150 | 0 | { |
151 | 0 | const netsnmp_pdu_stats *lhs = p, *rhs = q; |
152 | |
|
153 | 0 | if (NULL == lhs || NULL == rhs) { |
154 | 0 | snmp_log(LOG_WARNING, |
155 | 0 | "WARNING: results undefined for compares with NULL\n"); |
156 | 0 | return 0; |
157 | 0 | } |
158 | | |
159 | | /** we want list sorted in reverse order, so invert tests */ |
160 | 0 | if (lhs->processing_time > rhs->processing_time) |
161 | 0 | return -1; |
162 | 0 | else if (lhs->processing_time < rhs->processing_time) |
163 | 0 | return 1; |
164 | | |
165 | 0 | if (lhs->timestamp > rhs->timestamp) |
166 | 0 | return -1; |
167 | 0 | else if (lhs->timestamp < rhs->timestamp) |
168 | 0 | return 1; |
169 | | |
170 | 0 | return 0; |
171 | 0 | } |
172 | | |
173 | | |
174 | | static void |
175 | 3.34k | _pdu_stats_init(void) { |
176 | 3.34k | static int done = 0; |
177 | 3.34k | if ((NULL != _pdu_stats) || (++done != 1)) |
178 | 3.34k | return; |
179 | | |
180 | 1 | _pdu_stats = netsnmp_container_find("netsnmp_pdustats:binary_array"); |
181 | 1 | if (NULL == _pdu_stats) { |
182 | 0 | done = 0; |
183 | 0 | return; |
184 | 0 | } |
185 | | |
186 | 1 | _pdu_stats->compare = _pdu_stats_compare; |
187 | 1 | _pdu_stats->get_subset = NULL; /** subsets not supported */ |
188 | | |
189 | 1 | _pdu_stats_max = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
190 | 1 | NETSNMP_DS_AGENT_PDU_STATS_MAX); |
191 | 1 | _pdu_stats_threshold = |
192 | 1 | netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
193 | 1 | NETSNMP_DS_AGENT_PDU_STATS_THRESHOLD); |
194 | 1 | if (_pdu_stats_threshold < 100) |
195 | 1 | _pdu_stats_threshold = 100; |
196 | 1 | DEBUGMSGTL(("stats:pdu", "max: %d, threshold %ld ms\n", _pdu_stats_max, |
197 | 1 | _pdu_stats_threshold)); |
198 | 1 | } |
199 | | |
200 | | |
201 | | static void |
202 | | _pdu_stats_shutdown(void) |
203 | 3.34k | { |
204 | 3.34k | netsnmp_pdu_stats *entry; |
205 | 3.34k | int x = 0; |
206 | | |
207 | 3.34k | if (NULL == _pdu_stats) |
208 | 3.34k | return; |
209 | | |
210 | 1 | for( ; x < CONTAINER_SIZE(_pdu_stats); ++x) { |
211 | 0 | CONTAINER_GET_AT(_pdu_stats, x, (void**)&entry); |
212 | 0 | if (NULL == entry) |
213 | 0 | continue; |
214 | 0 | snmp_free_pdu(entry->pdu); |
215 | 0 | free(entry); |
216 | 0 | } |
217 | 1 | CONTAINER_FREE(_pdu_stats); |
218 | 1 | _pdu_stats = NULL; |
219 | 1 | } |
220 | | |
221 | | |
222 | | static void |
223 | | _dump_pdu_stats(void) |
224 | 0 | { |
225 | 0 | int x = 0; |
226 | 0 | struct tm *tm; |
227 | 0 | char timestr[40]; |
228 | 0 | netsnmp_pdu_stats *entry; |
229 | |
|
230 | 0 | for( ; x < CONTAINER_SIZE(_pdu_stats); ++x) { |
231 | 0 | netsnmp_pdu *response; |
232 | 0 | netsnmp_variable_list *vars; |
233 | 0 | CONTAINER_GET_AT(_pdu_stats, x, (void**)&entry); |
234 | 0 | if (NULL == entry) { |
235 | 0 | DEBUGMSGT_NC(("9:stats:pdu", "[%d] ERROR\n", x)); |
236 | 0 | continue; |
237 | 0 | } |
238 | 0 | tm = localtime(&entry->timestamp); |
239 | 0 | if (NULL == tm) |
240 | 0 | sprintf(timestr, "UNKNOWN"); |
241 | 0 | else if (strftime(timestr, sizeof(timestr), "%m/%d/%Y %H:%M:%S", |
242 | 0 | tm) == 0) |
243 | 0 | sprintf(timestr, "UNKNOWN"); |
244 | |
|
245 | 0 | DEBUGMSGT_NC(("9:stats:pdu", "[%d] %ld ms, %s\n", |
246 | 0 | x, entry->processing_time, timestr)); |
247 | 0 | response = entry->pdu; |
248 | 0 | if (response->errstat == SNMP_ERR_NOERROR) { |
249 | 0 | for (vars = response->variables; vars; |
250 | 0 | vars = vars->next_variable) { |
251 | 0 | DEBUGMSGT_NC(("9:stats:pdu", " vb ")); |
252 | 0 | DEBUGMSGVAR(("9:stats:pdu", vars)); |
253 | 0 | DEBUGMSG_NC(("9:stats:pdu", "\n")); |
254 | 0 | } |
255 | 0 | } else { |
256 | 0 | DEBUGMSGT_NC(("9:stats:pdu", "Error in packet: Reason: %s\n", |
257 | 0 | snmp_errstring(response->errstat))); |
258 | 0 | if (response->errindex != 0) { |
259 | 0 | int count; |
260 | 0 | DEBUGMSGT_NC(("9:stats:pdu", "Failed object: ")); |
261 | 0 | for (count = 1, vars = response->variables; |
262 | 0 | vars && count != response->errindex; |
263 | 0 | vars = vars->next_variable, count++) |
264 | 0 | /*EMPTY*/; |
265 | 0 | if (vars) { |
266 | 0 | DEBUGMSGOID(("9:stats:pdu", vars->name, |
267 | 0 | vars->name_length)); |
268 | 0 | } |
269 | 0 | DEBUGMSG_NC(("9:stats:pdu", "\n")); |
270 | 0 | } |
271 | 0 | } |
272 | 0 | } |
273 | 0 | } |
274 | | #endif /* NETSNMP_NO_PDU_STATS */ |
275 | | |
276 | | |
277 | | NETSNMP_INLINE void |
278 | | netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari, |
279 | | netsnmp_data_list *node) |
280 | 0 | { |
281 | 0 | if (ari) { |
282 | 0 | if (ari->agent_data) { |
283 | 0 | netsnmp_add_list_data(&ari->agent_data, node); |
284 | 0 | } else { |
285 | 0 | ari->agent_data = node; |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | #ifndef NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA |
291 | | NETSNMP_INLINE int |
292 | | netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari, |
293 | | const char * name) |
294 | 0 | { |
295 | 0 | if ((NULL == ari) || (NULL == ari->agent_data)) |
296 | 0 | return 1; |
297 | | |
298 | 0 | return netsnmp_remove_list_node(&ari->agent_data, name); |
299 | 0 | } |
300 | | #endif /* NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA */ |
301 | | |
302 | | NETSNMP_INLINE void * |
303 | | netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari, |
304 | | const char *name) |
305 | 0 | { |
306 | 0 | if (ari) { |
307 | 0 | return netsnmp_get_list_data(ari->agent_data, name); |
308 | 0 | } |
309 | 0 | return NULL; |
310 | 0 | } |
311 | | |
312 | | NETSNMP_INLINE void |
313 | | netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari) |
314 | 0 | { |
315 | 0 | if (ari) { |
316 | 0 | netsnmp_free_list_data(ari->agent_data); |
317 | 0 | } |
318 | 0 | } |
319 | | |
320 | | NETSNMP_INLINE void |
321 | | netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari) |
322 | 0 | { |
323 | 0 | if (ari) { |
324 | 0 | netsnmp_free_all_list_data(ari->agent_data); |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | | NETSNMP_INLINE void |
329 | | netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari) |
330 | 13.3k | { |
331 | 13.3k | if (ari) { |
332 | 13.3k | if (ari->agent_data) { |
333 | 0 | netsnmp_free_all_list_data(ari->agent_data); |
334 | 0 | } |
335 | 13.3k | SNMP_FREE(ari); |
336 | 13.3k | } |
337 | 13.3k | } |
338 | | |
339 | | const oid version_sysoid[] = { NETSNMP_SYSTEM_MIB }; |
340 | | const int version_sysoid_len = OID_LENGTH(version_sysoid); |
341 | | |
342 | 36.8k | #define SNMP_ADDRCACHE_SIZE 10 |
343 | 0 | #define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */ |
344 | | |
345 | | enum { |
346 | | SNMP_ADDRCACHE_UNUSED = 0, |
347 | | SNMP_ADDRCACHE_USED = 1 |
348 | | }; |
349 | | |
350 | | struct addrCache { |
351 | | char *addr; |
352 | | int status; |
353 | | struct timeval lastHitM; |
354 | | }; |
355 | | |
356 | | static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE]; |
357 | | int log_addresses = 0; |
358 | | |
359 | | |
360 | | |
361 | | typedef struct _agent_nsap { |
362 | | int handle; |
363 | | netsnmp_transport *t; |
364 | | void *s; /* Opaque internal session pointer. */ |
365 | | struct _agent_nsap *next; |
366 | | } agent_nsap; |
367 | | |
368 | | static agent_nsap *agent_nsap_list = NULL; |
369 | | netsnmp_agent_session *netsnmp_processing_set = NULL; |
370 | | netsnmp_agent_session *agent_delegated_list = NULL; |
371 | | netsnmp_agent_session *netsnmp_agent_queued_list = NULL; |
372 | | |
373 | | |
374 | | int handle_pdu(netsnmp_agent_session *asp); |
375 | | int netsnmp_handle_request(netsnmp_agent_session *asp, |
376 | | int status); |
377 | | int check_delayed_request(netsnmp_agent_session *asp); |
378 | | int handle_getnext_loop(netsnmp_agent_session *asp); |
379 | | int handle_set_loop(netsnmp_agent_session *asp); |
380 | | |
381 | | int netsnmp_remove_from_delegated(netsnmp_agent_session *asp); |
382 | | |
383 | | |
384 | | int netsnmp_running = 1; |
385 | | |
386 | | #ifndef NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID |
387 | | static int current_globalid = 0; |
388 | | |
389 | | int |
390 | | netsnmp_allocate_globalcacheid(void) |
391 | 0 | { |
392 | 0 | return ++current_globalid; |
393 | 0 | } |
394 | | #endif /* NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID */ |
395 | | |
396 | | int |
397 | | netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid) |
398 | 0 | { |
399 | 0 | while (cache_store != NULL) { |
400 | 0 | if (cache_store->globalid == globalid) |
401 | 0 | return cache_store->cacheid; |
402 | 0 | cache_store = cache_store->next; |
403 | 0 | } |
404 | 0 | return -1; |
405 | 0 | } |
406 | | |
407 | | netsnmp_cachemap * |
408 | | netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store, |
409 | | int globalid, int localid) |
410 | 0 | { |
411 | 0 | netsnmp_cachemap *tmpp; |
412 | |
|
413 | 0 | tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap); |
414 | 0 | if (tmpp != NULL) { |
415 | 0 | if (*cache_store) { |
416 | 0 | tmpp->next = *cache_store; |
417 | 0 | *cache_store = tmpp; |
418 | 0 | } else { |
419 | 0 | *cache_store = tmpp; |
420 | 0 | } |
421 | |
|
422 | 0 | tmpp->globalid = globalid; |
423 | 0 | tmpp->cacheid = localid; |
424 | 0 | } |
425 | 0 | return tmpp; |
426 | 0 | } |
427 | | |
428 | | void |
429 | | netsnmp_free_cachemap(netsnmp_cachemap *cache_store) |
430 | 0 | { |
431 | 0 | netsnmp_cachemap *tmpp; |
432 | 0 | while (cache_store) { |
433 | 0 | tmpp = cache_store; |
434 | 0 | cache_store = cache_store->next; |
435 | 0 | SNMP_FREE(tmpp); |
436 | 0 | } |
437 | 0 | } |
438 | | |
439 | | |
440 | | typedef struct agent_set_cache_s { |
441 | | /* |
442 | | * match on these 2 |
443 | | */ |
444 | | int transID; |
445 | | netsnmp_session *sess; |
446 | | |
447 | | /* |
448 | | * store this info |
449 | | */ |
450 | | netsnmp_tree_cache *treecache; |
451 | | int treecache_len; |
452 | | int treecache_num; |
453 | | |
454 | | int vbcount; |
455 | | netsnmp_request_info *requests; |
456 | | netsnmp_variable_list *saved_vars; |
457 | | netsnmp_data_list *agent_data; |
458 | | |
459 | | /* |
460 | | * list |
461 | | */ |
462 | | struct agent_set_cache_s *next; |
463 | | } agent_set_cache; |
464 | | |
465 | | static agent_set_cache *Sets = NULL; |
466 | | |
467 | | agent_set_cache * |
468 | | save_set_cache(netsnmp_agent_session *asp) |
469 | 9.27k | { |
470 | 9.27k | agent_set_cache *ptr; |
471 | | |
472 | 9.27k | if (!asp || !asp->reqinfo || !asp->pdu) |
473 | 0 | return NULL; |
474 | | |
475 | 9.27k | ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache); |
476 | 9.27k | if (ptr == NULL) |
477 | 0 | return NULL; |
478 | | |
479 | | /* |
480 | | * Save the important information |
481 | | */ |
482 | 9.27k | DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n", |
483 | 9.27k | asp, asp->reqinfo, asp->pdu->command)); |
484 | 9.27k | ptr->transID = asp->pdu->transid; |
485 | 9.27k | ptr->sess = asp->session; |
486 | 9.27k | ptr->treecache = asp->treecache; |
487 | 9.27k | ptr->treecache_len = asp->treecache_len; |
488 | 9.27k | ptr->treecache_num = asp->treecache_num; |
489 | 9.27k | ptr->agent_data = asp->reqinfo->agent_data; |
490 | 9.27k | ptr->requests = asp->requests; |
491 | 9.27k | ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */ |
492 | 9.27k | ptr->vbcount = asp->vbcount; |
493 | | |
494 | | /* |
495 | | * make the agent forget about what we've saved |
496 | | */ |
497 | 9.27k | asp->treecache = NULL; |
498 | 9.27k | asp->reqinfo->agent_data = NULL; |
499 | 9.27k | asp->pdu->variables = NULL; |
500 | 9.27k | asp->requests = NULL; |
501 | | |
502 | 9.27k | ptr->next = Sets; |
503 | 9.27k | Sets = ptr; |
504 | | |
505 | 9.27k | return ptr; |
506 | 9.27k | } |
507 | | |
508 | | int |
509 | | get_set_cache(netsnmp_agent_session *asp) |
510 | 617 | { |
511 | 617 | agent_set_cache *ptr, *prev = NULL; |
512 | | |
513 | 617 | for (ptr = Sets; ptr != NULL; ptr = ptr->next) { |
514 | 617 | if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) { |
515 | | /* |
516 | | * remove this item from list |
517 | | */ |
518 | 617 | if (prev) |
519 | 0 | prev->next = ptr->next; |
520 | 617 | else |
521 | 617 | Sets = ptr->next; |
522 | | |
523 | | /* |
524 | | * found it. Get the needed data |
525 | | */ |
526 | 617 | asp->treecache = ptr->treecache; |
527 | 617 | asp->treecache_len = ptr->treecache_len; |
528 | 617 | asp->treecache_num = ptr->treecache_num; |
529 | | |
530 | | /* |
531 | | * Free previously allocated requests before overwriting by |
532 | | * cached ones, otherwise memory leaks! |
533 | | */ |
534 | 617 | if (asp->requests) { |
535 | | /* |
536 | | * I don't think this case should ever happen. Please email |
537 | | * the net-snmp-coders@lists.sourceforge.net if you have |
538 | | * a test case that hits this condition. -- rstory |
539 | | */ |
540 | 0 | int i; |
541 | 0 | netsnmp_assert(NULL == asp->requests); /* see note above */ |
542 | 0 | for (i = 0; i < asp->vbcount; i++) { |
543 | 0 | netsnmp_free_request_data_sets(&asp->requests[i]); |
544 | 0 | } |
545 | 0 | free(asp->requests); |
546 | 0 | } |
547 | | /* |
548 | | * If we replace asp->requests with the info from the set cache, |
549 | | * we should replace asp->pdu->variables also with the cached |
550 | | * info, as asp->requests contains pointers to them. And we |
551 | | * should also free the current asp->pdu->variables list... |
552 | | */ |
553 | 617 | if (ptr->saved_vars) { |
554 | 0 | if (asp->pdu->variables) |
555 | 0 | snmp_free_varbind(asp->pdu->variables); |
556 | 0 | asp->pdu->variables = ptr->saved_vars; |
557 | 0 | asp->vbcount = ptr->vbcount; |
558 | 0 | } |
559 | 617 | asp->requests = ptr->requests; |
560 | | |
561 | 617 | netsnmp_assert(NULL != asp->reqinfo); |
562 | 617 | asp->reqinfo->asp = asp; |
563 | 617 | asp->reqinfo->agent_data = ptr->agent_data; |
564 | | |
565 | | /* |
566 | | * update request reqinfo, if it's out of date. |
567 | | * yyy-rks: investigate when/why sometimes they match, |
568 | | * sometimes they don't. |
569 | | */ |
570 | 617 | if(asp->requests && asp->requests->agent_req_info != asp->reqinfo) { |
571 | | /* |
572 | | * - one don't match case: agentx subagents. prev asp & reqinfo |
573 | | * freed, request reqinfo ptrs not cleared. |
574 | | */ |
575 | 602 | netsnmp_request_info *tmp = asp->requests; |
576 | 602 | DEBUGMSGTL(("verbose:asp", |
577 | 602 | " reqinfo %p doesn't match cached reqinfo %p\n", |
578 | 602 | asp->reqinfo, asp->requests->agent_req_info)); |
579 | 1.20k | for(; tmp; tmp = tmp->next) |
580 | 602 | tmp->agent_req_info = asp->reqinfo; |
581 | 602 | } else if (asp->requests) { |
582 | | /* |
583 | | * - match case: ? |
584 | | */ |
585 | 15 | DEBUGMSGTL(("verbose:asp", |
586 | 15 | " reqinfo %p matches cached reqinfo %p\n", |
587 | 15 | asp->reqinfo, asp->requests->agent_req_info)); |
588 | 15 | } else { |
589 | 0 | DEBUGMSGTL(("verbose:asp", " asp->requests is NULL\n")); |
590 | 0 | } |
591 | | |
592 | 617 | SNMP_FREE(ptr); |
593 | 617 | return SNMP_ERR_NOERROR; |
594 | 617 | } |
595 | 0 | prev = ptr; |
596 | 0 | } |
597 | 0 | return SNMP_ERR_GENERR; |
598 | 617 | } |
599 | | |
600 | | /* Bulkcache holds the values for the *repeating* varbinds (only), |
601 | | * but ordered "by column" - i.e. the repetitions for each |
602 | | * repeating varbind follow on immediately from one another, |
603 | | * rather than being interleaved, as required by the protocol. |
604 | | * |
605 | | * So we need to rearrange the varbind list so it's ordered "by row". |
606 | | * |
607 | | * In the following code chunk: |
608 | | * n = # non-repeating varbinds |
609 | | * r = # repeating varbinds |
610 | | * asp->vbcount = # varbinds in the incoming PDU |
611 | | * (So asp->vbcount = n+r) |
612 | | * |
613 | | * repeats = Desired # of repetitions (of 'r' varbinds) |
614 | | */ |
615 | | NETSNMP_STATIC_INLINE void |
616 | | _reorder_getbulk(netsnmp_agent_session *asp) |
617 | 622 | { |
618 | 622 | int i, n = 0, r = 0; |
619 | 622 | int repeats; |
620 | 622 | int j, k; |
621 | 622 | int all_eoMib; |
622 | 622 | netsnmp_variable_list *prev = NULL, *curr; |
623 | | |
624 | 622 | if (NULL == asp || NULL == asp->pdu || asp->vbcount == 0) |
625 | 384 | return; |
626 | | |
627 | 238 | if (asp->pdu->errstat < asp->vbcount) { |
628 | 141 | n = asp->pdu->errstat; |
629 | 141 | } else { |
630 | 97 | n = asp->vbcount; |
631 | 97 | } |
632 | 238 | if ((r = asp->vbcount - n) < 0) { |
633 | 0 | r = 0; |
634 | 0 | } |
635 | | |
636 | 238 | DEBUGMSGTL(("snmp_agent:bulk", "reorder n=%d, r=%d\n", n, r)); |
637 | | |
638 | | /* we do nothing if there is nothing repeated */ |
639 | 238 | if (r == 0) |
640 | 97 | return; |
641 | | |
642 | 141 | repeats = asp->pdu->errindex; |
643 | | /* Fix endOfMibView entries. */ |
644 | 389 | for (i = 0; i < r; i++) { |
645 | 248 | prev = NULL; |
646 | 9.24k | for (j = 0; j < repeats; j++) { |
647 | 8.99k | curr = asp->bulkcache[i * repeats + j]; |
648 | | /* |
649 | | * If we don't have a valid name for a given repetition |
650 | | * (and probably for all the ones that follow as well), |
651 | | * extend the previous result to indicate 'endOfMibView'. |
652 | | * Or if the repetition already has type endOfMibView make |
653 | | * sure it has the correct objid (i.e. that of the previous |
654 | | * entry or that of the original request). |
655 | | */ |
656 | 8.99k | if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) { |
657 | 8.99k | if (prev == NULL) { |
658 | | /* Use objid from original pdu. */ |
659 | 248 | prev = asp->orig_pdu->variables; |
660 | 422 | for (k = i; prev && k > 0; k--) |
661 | 174 | prev = prev->next_variable; |
662 | 248 | } |
663 | 8.99k | if (prev) { |
664 | 8.99k | snmp_set_var_objid(curr, prev->name, prev->name_length); |
665 | 8.99k | snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0); |
666 | 8.99k | } |
667 | 8.99k | } |
668 | 8.99k | prev = curr; |
669 | 8.99k | } |
670 | 248 | } |
671 | | |
672 | | /* |
673 | | * For each of the original repeating varbinds (except the last), |
674 | | * go through the block of results for that varbind, |
675 | | * and link each instance to the corresponding instance |
676 | | * in the next block. |
677 | | */ |
678 | 248 | for (i = 0; i < r - 1; i++) { |
679 | 1.90k | for (j = 0; j < repeats; j++) { |
680 | 1.79k | asp->bulkcache[i * repeats + j]->next_variable = |
681 | 1.79k | asp->bulkcache[(i + 1) * repeats + j]; |
682 | 1.79k | } |
683 | 107 | } |
684 | | |
685 | | /* |
686 | | * For the last of the original repeating varbinds, |
687 | | * go through that block of results, and link each |
688 | | * instance to the *next* instance in the *first* block. |
689 | | * |
690 | | * The very last instance of this block is left untouched |
691 | | * since it (correctly) points to the end of the list. |
692 | | */ |
693 | 7.19k | for (j = 0; j < repeats - 1; j++) { |
694 | 7.05k | asp->bulkcache[(r - 1) * repeats + j]->next_variable = |
695 | 7.05k | asp->bulkcache[j + 1]; |
696 | 7.05k | } |
697 | | |
698 | | /* |
699 | | * If we've got a full row of endOfMibViews, then we |
700 | | * can truncate the result varbind list after that. |
701 | | * |
702 | | * Look for endOfMibView exception values in the list of |
703 | | * repetitions for the first varbind, and check the |
704 | | * corresponding instances for the other varbinds |
705 | | * (following the next_variable links). |
706 | | * |
707 | | * If they're all endOfMibView too, then we can terminate |
708 | | * the linked list there, and free any redundant varbinds. |
709 | | */ |
710 | 141 | all_eoMib = 0; |
711 | 141 | for (i = 0; i < repeats; i++) { |
712 | 141 | if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) { |
713 | 141 | all_eoMib = 1; |
714 | 141 | for (j = 1, prev=asp->bulkcache[i]; |
715 | 248 | j < r; |
716 | 141 | j++, prev=prev->next_variable) { |
717 | 107 | if (prev->type != SNMP_ENDOFMIBVIEW) { |
718 | 0 | all_eoMib = 0; |
719 | 0 | break; /* Found a real value */ |
720 | 0 | } |
721 | 107 | } |
722 | 141 | if (all_eoMib) { |
723 | | /* |
724 | | * This is indeed a full endOfMibView row. |
725 | | * Terminate the list here & free the rest. |
726 | | */ |
727 | 141 | snmp_free_varbind( prev->next_variable ); |
728 | 141 | prev->next_variable = NULL; |
729 | 141 | break; |
730 | 141 | } |
731 | 141 | } |
732 | 141 | } |
733 | 141 | } |
734 | | |
735 | | |
736 | | /* EndOfMibView replies to a GETNEXT request should according to RFC3416 |
737 | | * have the object ID set to that of the request. Our tree search |
738 | | * algorithm will sometimes break that requirement. This function will |
739 | | * fix that. |
740 | | */ |
741 | | NETSNMP_STATIC_INLINE void |
742 | | _fix_endofmibview(netsnmp_agent_session *asp) |
743 | 109 | { |
744 | 109 | netsnmp_variable_list *vb, *ovb; |
745 | | |
746 | 109 | if (asp->vbcount == 0) /* Nothing to do! */ |
747 | 56 | return; |
748 | | |
749 | 53 | for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables; |
750 | 143 | vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) { |
751 | 90 | if (vb->type == SNMP_ENDOFMIBVIEW) |
752 | 90 | snmp_set_var_objid(vb, ovb->name, ovb->name_length); |
753 | 90 | } |
754 | 53 | } |
755 | | |
756 | | #ifndef NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS |
757 | | /** |
758 | | * This function checks for packets arriving on the SNMP port and |
759 | | * processes them(snmp_read) if some are found, using the select(). If block |
760 | | * is non zero, the function call blocks until a packet arrives |
761 | | * |
762 | | * @param block used to control blocking in the select() function, 1 = block |
763 | | * forever, and 0 = don't block |
764 | | * |
765 | | * @return Returns a positive integer if packets were processed, and -1 if an |
766 | | * error was found. |
767 | | * |
768 | | */ |
769 | | int |
770 | | agent_check_and_process(int block) |
771 | 0 | { |
772 | 0 | int numfds; |
773 | 0 | netsnmp_large_fd_set readfds; |
774 | 0 | netsnmp_large_fd_set writefds; |
775 | 0 | netsnmp_large_fd_set exceptfds; |
776 | 0 | struct timeval timeout = { LONG_MAX, 0 }, *tvp = &timeout; |
777 | 0 | int count; |
778 | 0 | int fakeblock = 0; |
779 | |
|
780 | 0 | snmp_poll(); |
781 | |
|
782 | 0 | numfds = 0; |
783 | 0 | netsnmp_large_fd_set_init(&readfds, FD_SETSIZE); |
784 | 0 | netsnmp_large_fd_set_init(&writefds, FD_SETSIZE); |
785 | 0 | netsnmp_large_fd_set_init(&exceptfds, FD_SETSIZE); |
786 | 0 | NETSNMP_LARGE_FD_ZERO(&readfds); |
787 | 0 | NETSNMP_LARGE_FD_ZERO(&writefds); |
788 | 0 | NETSNMP_LARGE_FD_ZERO(&exceptfds); |
789 | 0 | snmp_select_info2(&numfds, &readfds, tvp, &fakeblock); |
790 | 0 | if (block != 0 && fakeblock != 0) { |
791 | | /* |
792 | | * There are no alarms registered, and the caller asked for blocking, so |
793 | | * let select() block forever. |
794 | | */ |
795 | |
|
796 | 0 | tvp = NULL; |
797 | 0 | } else if (block != 0 && fakeblock == 0) { |
798 | | /* |
799 | | * The caller asked for blocking, but there is an alarm due sooner than |
800 | | * LONG_MAX seconds from now, so use the modified timeout returned by |
801 | | * snmp_select_info as the timeout for select(). |
802 | | */ |
803 | |
|
804 | 0 | } else if (block == 0) { |
805 | | /* |
806 | | * The caller does not want us to block at all. |
807 | | */ |
808 | |
|
809 | 0 | timerclear(tvp); |
810 | 0 | } |
811 | |
|
812 | 0 | #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER |
813 | 0 | netsnmp_external_event_info2(&numfds, &readfds, &writefds, &exceptfds); |
814 | 0 | #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */ |
815 | |
|
816 | 0 | count = netsnmp_large_fd_set_select(numfds, &readfds, &writefds, &exceptfds, tvp); |
817 | |
|
818 | 0 | if (count > 0) { |
819 | | /* |
820 | | * packets found, process them |
821 | | */ |
822 | 0 | #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER |
823 | 0 | netsnmp_dispatch_external_events2(&count, &readfds, &writefds, &exceptfds); |
824 | 0 | #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */ |
825 | |
|
826 | 0 | snmp_read2(&readfds); |
827 | 0 | } else |
828 | 0 | switch (count) { |
829 | 0 | case 0: |
830 | 0 | snmp_timeout(); |
831 | 0 | break; |
832 | 0 | case -1: |
833 | 0 | if (errno != EINTR) { |
834 | 0 | snmp_log_perror("select"); |
835 | 0 | } |
836 | 0 | count = -1; |
837 | 0 | goto exit; |
838 | 0 | default: |
839 | 0 | snmp_log(LOG_ERR, "select returned %d\n", count); |
840 | 0 | count = -1; |
841 | 0 | goto exit; |
842 | 0 | } /* endif -- count>0 */ |
843 | | |
844 | | /* |
845 | | * see if persistent store needs to be saved |
846 | | */ |
847 | 0 | snmp_store_if_needed(); |
848 | | |
849 | | /* |
850 | | * Run requested alarms. |
851 | | */ |
852 | 0 | run_alarms(); |
853 | |
|
854 | 0 | netsnmp_check_outstanding_agent_requests(); |
855 | |
|
856 | 0 | exit: |
857 | 0 | netsnmp_large_fd_set_cleanup(&readfds); |
858 | 0 | netsnmp_large_fd_set_cleanup(&writefds); |
859 | 0 | netsnmp_large_fd_set_cleanup(&exceptfds); |
860 | 0 | return count; |
861 | 0 | } |
862 | | #endif /* NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS */ |
863 | | |
864 | | /* |
865 | | * Set up the address cache. |
866 | | */ |
867 | | void |
868 | | netsnmp_addrcache_initialise(void) |
869 | 0 | { |
870 | 0 | int i = 0; |
871 | |
|
872 | 0 | for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) { |
873 | 0 | addrCache[i].addr = NULL; |
874 | 0 | addrCache[i].status = SNMP_ADDRCACHE_UNUSED; |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | | void netsnmp_addrcache_destroy(void) |
879 | 3.34k | { |
880 | 3.34k | int i = 0; |
881 | | |
882 | 36.8k | for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) { |
883 | 33.4k | if (addrCache[i].status == SNMP_ADDRCACHE_USED) { |
884 | 0 | free(addrCache[i].addr); |
885 | 0 | addrCache[i].status = SNMP_ADDRCACHE_UNUSED; |
886 | 0 | } |
887 | 33.4k | } |
888 | 3.34k | } |
889 | | |
890 | | /* |
891 | | * Adds a new entry to the cache of addresses that |
892 | | * have recently made connections to the agent. |
893 | | * Returns 0 if the entry already exists (but updates |
894 | | * the entry with a new timestamp) and 1 if the |
895 | | * entry did not previously exist. |
896 | | * |
897 | | * Implements a simple LRU cache replacement |
898 | | * policy. Uses a linear search, which should be |
899 | | * okay, as long as SNMP_ADDRCACHE_SIZE remains |
900 | | * relatively small. |
901 | | * |
902 | | * @retval 0 : updated existing entry |
903 | | * @retval 1 : added new entry |
904 | | */ |
905 | | int |
906 | | netsnmp_addrcache_add(const char *addr) |
907 | 0 | { |
908 | 0 | int oldest = -1; /* Index of the oldest cache entry */ |
909 | 0 | int unused = -1; /* Index of the first free cache entry */ |
910 | 0 | int i; /* Looping variable */ |
911 | 0 | int rc = -1; |
912 | 0 | struct timeval now; /* What time is it now? */ |
913 | 0 | struct timeval aged; /* Oldest allowable cache entry */ |
914 | | |
915 | | /* |
916 | | * First get the current and oldest allowable timestamps |
917 | | */ |
918 | 0 | netsnmp_get_monotonic_clock(&now); |
919 | 0 | aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE; |
920 | 0 | aged.tv_usec = now.tv_usec; |
921 | | |
922 | | /* |
923 | | * Now look for a place to put this thing |
924 | | */ |
925 | 0 | for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) { |
926 | 0 | if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */ |
927 | | /* |
928 | | * remember this location, in case addr isn't in the cache |
929 | | */ |
930 | 0 | if (unused < 0) |
931 | 0 | unused = i; |
932 | 0 | } |
933 | 0 | else { /* If used */ |
934 | 0 | if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) { |
935 | | /* |
936 | | * found a match |
937 | | */ |
938 | 0 | addrCache[i].lastHitM = now; |
939 | 0 | if (timercmp(&addrCache[i].lastHitM, &aged, <)) |
940 | 0 | rc = 1; /* should have expired, so is new */ |
941 | 0 | else |
942 | 0 | rc = 0; /* not expired, so is existing entry */ |
943 | 0 | break; |
944 | 0 | } |
945 | 0 | else { |
946 | | /* |
947 | | * Used, but not this address. check if it's stale. |
948 | | */ |
949 | 0 | if (timercmp(&addrCache[i].lastHitM, &aged, <)) { |
950 | | /* |
951 | | * Stale, reuse |
952 | | */ |
953 | 0 | SNMP_FREE(addrCache[i].addr); |
954 | 0 | addrCache[i].status = SNMP_ADDRCACHE_UNUSED; |
955 | | /* |
956 | | * remember this location, in case addr isn't in the cache |
957 | | */ |
958 | 0 | if (unused < 0) |
959 | 0 | unused = i; |
960 | 0 | } |
961 | 0 | else { |
962 | | /* |
963 | | * Still fresh, but a candidate for LRU replacement |
964 | | */ |
965 | 0 | if (oldest < 0) |
966 | 0 | oldest = i; |
967 | 0 | else if (timercmp(&addrCache[i].lastHitM, |
968 | 0 | &addrCache[oldest].lastHitM, <)) |
969 | 0 | oldest = i; |
970 | 0 | } /* fresh */ |
971 | 0 | } /* used, no match */ |
972 | 0 | } /* used */ |
973 | 0 | } /* for loop */ |
974 | |
|
975 | 0 | if ((-1 == rc) && (NULL != addr)) { |
976 | | /* |
977 | | * We didn't find the entry in the cache |
978 | | */ |
979 | 0 | if (unused >= 0) { |
980 | | /* |
981 | | * If we have a slot free anyway, use it |
982 | | */ |
983 | 0 | addrCache[unused].addr = strdup(addr); |
984 | 0 | addrCache[unused].status = SNMP_ADDRCACHE_USED; |
985 | 0 | addrCache[unused].lastHitM = now; |
986 | 0 | } |
987 | 0 | else { /* Otherwise, replace oldest entry */ |
988 | 0 | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
989 | 0 | NETSNMP_DS_AGENT_VERBOSE)) |
990 | 0 | snmp_log(LOG_INFO, "Purging address from address cache: %s", |
991 | 0 | addrCache[oldest].addr); |
992 | | |
993 | 0 | free(addrCache[oldest].addr); |
994 | 0 | addrCache[oldest].addr = strdup(addr); |
995 | 0 | addrCache[oldest].lastHitM = now; |
996 | 0 | } |
997 | 0 | rc = 1; |
998 | 0 | } |
999 | 0 | if ((log_addresses && (1 == rc)) || |
1000 | 0 | netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1001 | 0 | NETSNMP_DS_AGENT_VERBOSE)) { |
1002 | 0 | snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr); |
1003 | 0 | } |
1004 | |
|
1005 | 0 | return rc; |
1006 | 0 | } |
1007 | | |
1008 | | /* |
1009 | | * Age the entries in the address cache. |
1010 | | * |
1011 | | * backwards compatability; not used anywhere |
1012 | | */ |
1013 | | #ifndef NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE |
1014 | | void |
1015 | | netsnmp_addrcache_age(void) |
1016 | 0 | { |
1017 | 0 | (void)netsnmp_addrcache_add(NULL); |
1018 | 0 | } |
1019 | | #endif /* NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE */ |
1020 | | |
1021 | | /*******************************************************************-o-****** |
1022 | | * netsnmp_agent_check_packet |
1023 | | * |
1024 | | * Parameters: |
1025 | | * session, transport, transport_data, transport_data_length |
1026 | | * |
1027 | | * Returns: |
1028 | | * 1 On success. |
1029 | | * 0 On error. |
1030 | | * |
1031 | | * Handler for all incoming messages (a.k.a. packets) for the agent. If using |
1032 | | * the libwrap utility, log the connection and deny/allow the access. Print |
1033 | | * output when appropriate, and increment the incoming counter. |
1034 | | * |
1035 | | */ |
1036 | | |
1037 | | int |
1038 | | netsnmp_agent_check_packet(netsnmp_session * session, |
1039 | | netsnmp_transport *transport, |
1040 | | void *transport_data, int transport_data_length) |
1041 | 0 | { |
1042 | 0 | char *addr_string = NULL; |
1043 | | #ifdef NETSNMP_USE_LIBWRAP |
1044 | | char *tcpudpaddr = NULL, *name; |
1045 | | short not_log_connection; |
1046 | | |
1047 | | name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
1048 | | NETSNMP_DS_LIB_APPTYPE); |
1049 | | |
1050 | | /* not_log_connection will be 1 if we should skip the messages */ |
1051 | | not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1052 | | NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS); |
1053 | | |
1054 | | /* |
1055 | | * handle the error case |
1056 | | * default to logging the messages |
1057 | | */ |
1058 | | if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0; |
1059 | | #endif |
1060 | | |
1061 | | /* |
1062 | | * Log the message and/or dump the message. |
1063 | | * Optionally cache the network address of the sender. |
1064 | | */ |
1065 | |
|
1066 | 0 | if (transport != NULL && transport->f_fmtaddr != NULL) { |
1067 | | /* |
1068 | | * Okay I do know how to format this address for logging. |
1069 | | */ |
1070 | 0 | addr_string = transport->f_fmtaddr(transport, transport_data, |
1071 | 0 | transport_data_length); |
1072 | | /* |
1073 | | * Don't forget to free() it. |
1074 | | */ |
1075 | 0 | } |
1076 | | #ifdef NETSNMP_USE_LIBWRAP |
1077 | | /* Catch udp,udp6,tcp,tcp6 transports using "[" */ |
1078 | | if (addr_string) |
1079 | | tcpudpaddr = strstr(addr_string, "["); |
1080 | | if ( tcpudpaddr != 0 ) { |
1081 | | char sbuf[64]; |
1082 | | char *xp; |
1083 | | |
1084 | | strlcpy(sbuf, tcpudpaddr + 1, sizeof(sbuf)); |
1085 | | xp = strstr(sbuf, "]"); |
1086 | | if (xp) |
1087 | | *xp = '\0'; |
1088 | | |
1089 | | if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) { |
1090 | | if (!not_log_connection) { |
1091 | | snmp_log(allow_severity, "Connection from %s\n", addr_string); |
1092 | | } |
1093 | | } else { |
1094 | | snmp_log(deny_severity, "Connection from %s REFUSED\n", |
1095 | | addr_string); |
1096 | | SNMP_FREE(addr_string); |
1097 | | return 0; |
1098 | | } |
1099 | | } else { |
1100 | | /* |
1101 | | * don't log callback connections. |
1102 | | * What about 'Local IPC', 'IPX' and 'AAL5 PVC'? |
1103 | | */ |
1104 | | if (0 == strncmp(addr_string, "callback", 8)) |
1105 | | ; |
1106 | | else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){ |
1107 | | if (!not_log_connection) { |
1108 | | snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string); |
1109 | | }; |
1110 | | SNMP_FREE(addr_string); |
1111 | | addr_string = strdup("<UNKNOWN>"); |
1112 | | } else { |
1113 | | snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string); |
1114 | | SNMP_FREE(addr_string); |
1115 | | return 0; |
1116 | | } |
1117 | | } |
1118 | | #endif /*NETSNMP_USE_LIBWRAP */ |
1119 | |
|
1120 | 0 | snmp_increment_statistic(STAT_SNMPINPKTS); |
1121 | |
|
1122 | 0 | if (addr_string != NULL) { |
1123 | 0 | netsnmp_addrcache_add(addr_string); |
1124 | 0 | SNMP_FREE(addr_string); |
1125 | 0 | } |
1126 | 0 | return 1; |
1127 | 0 | } |
1128 | | |
1129 | | |
1130 | | int |
1131 | | netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu, |
1132 | | int result) |
1133 | 0 | { |
1134 | 0 | if (result == 0) { |
1135 | 0 | if (snmp_get_do_logging() && |
1136 | 0 | netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1137 | 0 | NETSNMP_DS_AGENT_VERBOSE)) { |
1138 | 0 | netsnmp_variable_list *var_ptr; |
1139 | |
|
1140 | 0 | switch (pdu->command) { |
1141 | 0 | case SNMP_MSG_GET: |
1142 | 0 | snmp_log(LOG_DEBUG, " GET message\n"); |
1143 | 0 | break; |
1144 | 0 | case SNMP_MSG_GETNEXT: |
1145 | 0 | snmp_log(LOG_DEBUG, " GETNEXT message\n"); |
1146 | 0 | break; |
1147 | 0 | case SNMP_MSG_RESPONSE: |
1148 | 0 | snmp_log(LOG_DEBUG, " RESPONSE message\n"); |
1149 | 0 | break; |
1150 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
1151 | 0 | case SNMP_MSG_SET: |
1152 | 0 | snmp_log(LOG_DEBUG, " SET message\n"); |
1153 | 0 | break; |
1154 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
1155 | 0 | case SNMP_MSG_TRAP: |
1156 | 0 | snmp_log(LOG_DEBUG, " TRAP message\n"); |
1157 | 0 | break; |
1158 | 0 | case SNMP_MSG_GETBULK: |
1159 | 0 | snmp_log(LOG_DEBUG, " GETBULK message, non-rep=%ld, max_rep=%ld\n", |
1160 | 0 | pdu->errstat, pdu->errindex); |
1161 | 0 | break; |
1162 | 0 | case SNMP_MSG_INFORM: |
1163 | 0 | snmp_log(LOG_DEBUG, " INFORM message\n"); |
1164 | 0 | break; |
1165 | 0 | case SNMP_MSG_TRAP2: |
1166 | 0 | snmp_log(LOG_DEBUG, " TRAP2 message\n"); |
1167 | 0 | break; |
1168 | 0 | case SNMP_MSG_REPORT: |
1169 | 0 | snmp_log(LOG_DEBUG, " REPORT message\n"); |
1170 | 0 | break; |
1171 | | |
1172 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
1173 | 0 | case SNMP_MSG_INTERNAL_SET_RESERVE1: |
1174 | 0 | snmp_log(LOG_DEBUG, " INTERNAL RESERVE1 message\n"); |
1175 | 0 | break; |
1176 | | |
1177 | 0 | case SNMP_MSG_INTERNAL_SET_RESERVE2: |
1178 | 0 | snmp_log(LOG_DEBUG, " INTERNAL RESERVE2 message\n"); |
1179 | 0 | break; |
1180 | | |
1181 | 0 | case SNMP_MSG_INTERNAL_SET_ACTION: |
1182 | 0 | snmp_log(LOG_DEBUG, " INTERNAL ACTION message\n"); |
1183 | 0 | break; |
1184 | | |
1185 | 0 | case SNMP_MSG_INTERNAL_SET_COMMIT: |
1186 | 0 | snmp_log(LOG_DEBUG, " INTERNAL COMMIT message\n"); |
1187 | 0 | break; |
1188 | | |
1189 | 0 | case SNMP_MSG_INTERNAL_SET_FREE: |
1190 | 0 | snmp_log(LOG_DEBUG, " INTERNAL FREE message\n"); |
1191 | 0 | break; |
1192 | | |
1193 | 0 | case SNMP_MSG_INTERNAL_SET_UNDO: |
1194 | 0 | snmp_log(LOG_DEBUG, " INTERNAL UNDO message\n"); |
1195 | 0 | break; |
1196 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
1197 | | |
1198 | 0 | default: |
1199 | 0 | snmp_log(LOG_DEBUG, " UNKNOWN message, type=%02X\n", |
1200 | 0 | pdu->command); |
1201 | 0 | snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); |
1202 | 0 | return 0; |
1203 | 0 | } |
1204 | | |
1205 | 0 | for (var_ptr = pdu->variables; var_ptr != NULL; |
1206 | 0 | var_ptr = var_ptr->next_variable) { |
1207 | 0 | size_t c_oidlen = 256, c_outlen = 0; |
1208 | 0 | u_char *c_oid = (u_char *) malloc(c_oidlen); |
1209 | |
|
1210 | 0 | if (c_oid) { |
1211 | 0 | if (!sprint_realloc_objid |
1212 | 0 | (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name, |
1213 | 0 | var_ptr->name_length)) { |
1214 | 0 | snmp_log(LOG_DEBUG, " -- %s [TRUNCATED]\n", |
1215 | 0 | c_oid); |
1216 | 0 | } else { |
1217 | 0 | snmp_log(LOG_DEBUG, " -- %s\n", c_oid); |
1218 | 0 | } |
1219 | 0 | SNMP_FREE(c_oid); |
1220 | 0 | } |
1221 | 0 | } |
1222 | 0 | } |
1223 | 0 | return 1; |
1224 | 0 | } |
1225 | 0 | return 0; /* XXX: does it matter what the return value |
1226 | | * is? Yes: if we return 0, then the PDU is |
1227 | | * dumped. */ |
1228 | 0 | } |
1229 | | |
1230 | | |
1231 | | /* |
1232 | | * Global access to the primary session structure for this agent. |
1233 | | * for Index Allocation use initially. |
1234 | | */ |
1235 | | |
1236 | | /* |
1237 | | * I don't understand what this is for at the moment. AFAICS as long as it |
1238 | | * gets set and points at a session, that's fine. ??? |
1239 | | */ |
1240 | | |
1241 | | netsnmp_session *main_session = NULL; |
1242 | | |
1243 | | |
1244 | | |
1245 | | /* |
1246 | | * Set up an agent session on the given transport. Return a handle |
1247 | | * which may later be used to de-register this transport. A return |
1248 | | * value of -1 indicates an error. |
1249 | | */ |
1250 | | |
1251 | | int |
1252 | | netsnmp_register_agent_nsap(netsnmp_transport *t) |
1253 | 3.34k | { |
1254 | 3.34k | netsnmp_session *s, *sp = NULL; |
1255 | 3.34k | agent_nsap *a = NULL, *n = NULL, **prevNext = &agent_nsap_list; |
1256 | 3.34k | int handle = 0; |
1257 | 3.34k | struct session_list *isp = NULL; |
1258 | | |
1259 | 3.34k | if (t == NULL) { |
1260 | 0 | return -1; |
1261 | 0 | } |
1262 | | |
1263 | 3.34k | DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %" NETSNMP_FMT_SKT "\n", |
1264 | 3.34k | t->sock)); |
1265 | | |
1266 | 3.34k | n = (agent_nsap *) malloc(sizeof(agent_nsap)); |
1267 | 3.34k | if (n == NULL) { |
1268 | 0 | return -1; |
1269 | 0 | } |
1270 | 3.34k | s = (netsnmp_session *) malloc(sizeof(netsnmp_session)); |
1271 | 3.34k | if (s == NULL) { |
1272 | 0 | SNMP_FREE(n); |
1273 | 0 | return -1; |
1274 | 0 | } |
1275 | 3.34k | snmp_sess_init(s); |
1276 | | |
1277 | | /* |
1278 | | * Set up the session appropriately for an agent. |
1279 | | */ |
1280 | | |
1281 | 3.34k | s->version = SNMP_DEFAULT_VERSION; |
1282 | 3.34k | s->callback = handle_snmp_packet; |
1283 | 3.34k | s->authenticator = NULL; |
1284 | 3.34k | s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
1285 | 3.34k | NETSNMP_DS_AGENT_FLAGS); |
1286 | 3.34k | s->isAuthoritative = SNMP_SESS_AUTHORITATIVE; |
1287 | | |
1288 | | /* Optional supplemental transport configuration information and |
1289 | | final call to actually open the transport */ |
1290 | 3.34k | if (netsnmp_sess_config_transport(s->transport_configuration, t) |
1291 | 3.34k | != SNMPERR_SUCCESS) { |
1292 | 0 | SNMP_FREE(s); |
1293 | 0 | SNMP_FREE(n); |
1294 | 0 | return -1; |
1295 | 0 | } |
1296 | | |
1297 | | |
1298 | 3.34k | if (t->f_open) |
1299 | 0 | t = t->f_open(t); |
1300 | | |
1301 | 3.34k | if (NULL == t) { |
1302 | 0 | SNMP_FREE(s); |
1303 | 0 | SNMP_FREE(n); |
1304 | 0 | return -1; |
1305 | 0 | } |
1306 | | |
1307 | 3.34k | t->flags |= NETSNMP_TRANSPORT_FLAG_OPENED; |
1308 | | |
1309 | 3.34k | sp = snmp_add(s, t, netsnmp_agent_check_packet, |
1310 | 3.34k | netsnmp_agent_check_parse); |
1311 | 3.34k | if (sp == NULL) { |
1312 | 0 | SNMP_FREE(s); |
1313 | 0 | SNMP_FREE(n); |
1314 | 0 | return -1; |
1315 | 0 | } |
1316 | | |
1317 | 3.34k | isp = snmp_sess_pointer(sp); |
1318 | 3.34k | if (isp == NULL) { /* over-cautious */ |
1319 | 0 | SNMP_FREE(s); |
1320 | 0 | SNMP_FREE(n); |
1321 | 0 | return -1; |
1322 | 0 | } |
1323 | | |
1324 | 3.34k | n->s = isp; |
1325 | 3.34k | n->t = t; |
1326 | | |
1327 | 3.34k | if (main_session == NULL) { |
1328 | 3.34k | main_session = snmp_sess_session(isp); |
1329 | 3.34k | } |
1330 | | |
1331 | 3.34k | for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle; |
1332 | 3.34k | a = a->next) { |
1333 | 0 | handle = a->handle; |
1334 | 0 | prevNext = &(a->next); |
1335 | 0 | } |
1336 | | |
1337 | 3.34k | if (handle < INT_MAX) { |
1338 | 3.34k | n->handle = handle + 1; |
1339 | 3.34k | n->next = a; |
1340 | 3.34k | *prevNext = n; |
1341 | 3.34k | SNMP_FREE(s); |
1342 | 3.34k | DEBUGMSGTL(("netsnmp_register_agent_nsap", "handle %d\n", n->handle)); |
1343 | 3.34k | return n->handle; |
1344 | 3.34k | } else { |
1345 | 0 | SNMP_FREE(s); |
1346 | 0 | SNMP_FREE(n); |
1347 | 0 | return -1; |
1348 | 0 | } |
1349 | 3.34k | } |
1350 | | |
1351 | | void |
1352 | | netsnmp_deregister_agent_nsap(int handle) |
1353 | 3.34k | { |
1354 | 3.34k | agent_nsap *a = NULL, **prevNext = &agent_nsap_list; |
1355 | 3.34k | int main_session_deregistered = 0; |
1356 | | |
1357 | 3.34k | DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle)); |
1358 | | |
1359 | 3.34k | for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) { |
1360 | 0 | prevNext = &(a->next); |
1361 | 0 | } |
1362 | | |
1363 | 3.34k | if (a != NULL && a->handle == handle) { |
1364 | 3.34k | *prevNext = a->next; |
1365 | 3.34k | if (snmp_sess_session_lookup(a->s)) { |
1366 | 3.34k | if (main_session == snmp_sess_session(a->s)) { |
1367 | 3.34k | main_session_deregistered = 1; |
1368 | 3.34k | } |
1369 | 3.34k | snmp_close(snmp_sess_session(a->s)); |
1370 | | /* |
1371 | | * The above free()s the transport and session pointers. |
1372 | | */ |
1373 | 3.34k | } |
1374 | 3.34k | SNMP_FREE(a); |
1375 | 3.34k | } |
1376 | | |
1377 | | /* |
1378 | | * If we've deregistered the session that main_session used to point to, |
1379 | | * then make it point to another one, or in the last resort, make it equal |
1380 | | * to NULL. Basically this shouldn't ever happen in normal operation |
1381 | | * because main_session starts off pointing at the first session added by |
1382 | | * init_master_agent(), which then discards the handle. |
1383 | | */ |
1384 | | |
1385 | 3.34k | if (main_session_deregistered) { |
1386 | 3.34k | if (agent_nsap_list != NULL) { |
1387 | 0 | DEBUGMSGTL(("snmp_agent", |
1388 | 0 | "WARNING: main_session ptr changed from %p to %p\n", |
1389 | 0 | main_session, snmp_sess_session(agent_nsap_list->s))); |
1390 | 0 | main_session = snmp_sess_session(agent_nsap_list->s); |
1391 | 3.34k | } else { |
1392 | 3.34k | DEBUGMSGTL(("snmp_agent", |
1393 | 3.34k | "WARNING: main_session ptr changed from %p to NULL\n", |
1394 | 3.34k | main_session)); |
1395 | 3.34k | main_session = NULL; |
1396 | 3.34k | } |
1397 | 3.34k | } |
1398 | 3.34k | } |
1399 | | |
1400 | | static void |
1401 | | log_agent_address(netsnmp_transport *transport) |
1402 | 3.34k | { |
1403 | 3.34k | struct sockaddr_storage sa; |
1404 | 3.34k | socklen_t len = sizeof(sa); |
1405 | 3.34k | char name[256], serv[16]; |
1406 | | |
1407 | 3.34k | if (getsockname(transport->sock, (void *)&sa, &len) < 0) |
1408 | 0 | return; |
1409 | | |
1410 | 3.34k | #if defined(AF_UNIX) && defined(HAVE_SYS_UN_H) |
1411 | 3.34k | if (sa.ss_family == AF_UNIX) { |
1412 | 0 | struct sockaddr_un *sun_addr = (struct sockaddr_un *)&sa; |
1413 | 0 | snmp_log(LOG_INFO, "Listening on address %s\n", |
1414 | 0 | sun_addr->sun_path[0] ? sun_addr->sun_path : "abstract"); |
1415 | 0 | return; |
1416 | 0 | } |
1417 | 3.34k | #endif |
1418 | | |
1419 | 3.34k | if (getnameinfo((void *)&sa, len, name, sizeof(name), serv, |
1420 | 3.34k | sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV) < 0) |
1421 | | |
1422 | 0 | return; |
1423 | | |
1424 | 3.34k | snmp_log(LOG_INFO, "Listening on address %s:%s\n", name, serv); |
1425 | 3.34k | } |
1426 | | |
1427 | | int |
1428 | | netsnmp_agent_listen_on(const char *port) |
1429 | 3.34k | { |
1430 | 3.34k | netsnmp_transport *transport; |
1431 | 3.34k | int handle; |
1432 | | |
1433 | 3.34k | if (NULL == port) |
1434 | 0 | return -1; |
1435 | | |
1436 | 3.34k | transport = netsnmp_transport_open_server("snmp", port); |
1437 | 3.34k | if (transport == NULL) { |
1438 | 0 | snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n", port); |
1439 | 0 | return -1; |
1440 | 0 | } |
1441 | | |
1442 | 3.34k | handle = netsnmp_register_agent_nsap(transport); |
1443 | 3.34k | if (handle < 0) { |
1444 | 0 | snmp_log(LOG_ERR, "Error registering specified transport \"%s\" as an " |
1445 | 0 | "agent NSAP\n", port); |
1446 | 0 | return -1; |
1447 | 3.34k | } else { |
1448 | 3.34k | DEBUGMSGTL(("snmp_agent", |
1449 | 3.34k | "init_master_agent; \"%s\" registered as an agent NSAP\n", |
1450 | 3.34k | port)); |
1451 | 3.34k | } |
1452 | | |
1453 | 3.34k | log_agent_address(transport); |
1454 | | |
1455 | 3.34k | return handle; |
1456 | 3.34k | } |
1457 | | |
1458 | | /* |
1459 | | * |
1460 | | * This function has been modified to use the experimental |
1461 | | * netsnmp_register_agent_nsap interface. The major responsibility of this |
1462 | | * function now is to interpret a string specified to the agent (via -p on the |
1463 | | * command line, or from a configuration file) as a list of agent NSAPs on |
1464 | | * which to listen for SNMP packets. Typically, when you add a new transport |
1465 | | * domain "foo", you add code here such that if the "foo" code is compiled |
1466 | | * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the |
1467 | | * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate |
1468 | | * transport descriptor. netsnmp_register_agent_nsap is then called with that |
1469 | | * transport descriptor and sets up a listening agent session on it. |
1470 | | * |
1471 | | * Everything then works much as normal: the agent runs in an infinite loop |
1472 | | * (in the snmpd.c/receive()routine), which calls snmp_read() when a request |
1473 | | * is readable on any of the given transports. This routine then traverses |
1474 | | * the library 'Sessions' list to identify the relevant session and eventually |
1475 | | * invokes '_sess_read'. This then processes the incoming packet, calling the |
1476 | | * pre_parse, parse, post_parse and callback routines in turn. |
1477 | | * |
1478 | | * JBPN 20001117 |
1479 | | */ |
1480 | | |
1481 | | int |
1482 | | init_master_agent(void) |
1483 | 3.34k | { |
1484 | 3.34k | char *cptr; |
1485 | 3.34k | char *buf = NULL; |
1486 | 3.34k | char *st; |
1487 | | |
1488 | | /* default to a default cache size */ |
1489 | 3.34k | netsnmp_set_lookup_cache_size(-1); |
1490 | | |
1491 | 3.34k | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1492 | 3.34k | NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { |
1493 | 0 | DEBUGMSGTL(("snmp_agent", |
1494 | 0 | "init_master_agent; not master agent\n")); |
1495 | |
|
1496 | 0 | netsnmp_assert("agent role !master && !sub_agent"); |
1497 | | |
1498 | 0 | return 0; /* No error if ! MASTER_AGENT */ |
1499 | 0 | } |
1500 | | |
1501 | 3.34k | #ifndef NETSNMP_NO_LISTEN_SUPPORT |
1502 | | /* |
1503 | | * Have specific agent ports been specified? |
1504 | | */ |
1505 | 3.34k | cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, |
1506 | 3.34k | NETSNMP_DS_AGENT_PORTS); |
1507 | | |
1508 | 3.34k | if (cptr) { |
1509 | 0 | buf = strdup(cptr); |
1510 | 3.34k | } else { |
1511 | | /* |
1512 | | * No, so just specify the default port. |
1513 | | */ |
1514 | 3.34k | buf = strdup(""); |
1515 | 3.34k | } |
1516 | 3.34k | if (!buf) { |
1517 | 0 | snmp_log(LOG_ERR, |
1518 | 0 | "Error processing transport \"%s\"\n", cptr ? cptr : "default"); |
1519 | 0 | return 1; |
1520 | 0 | } |
1521 | | |
1522 | 3.34k | DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf)); |
1523 | 3.34k | st = buf; |
1524 | 3.34k | do { |
1525 | | /* |
1526 | | * Specification format: |
1527 | | * |
1528 | | * NONE: (a pseudo-transport) |
1529 | | * UDP:[address:]port (also default if no transport is specified) |
1530 | | * TCP:[address:]port (if supported) |
1531 | | * Unix:pathname (if supported) |
1532 | | * AAL5PVC:itf.vpi.vci (if supported) |
1533 | | * IPX:[network]:node[/port] (if supported) |
1534 | | * |
1535 | | */ |
1536 | | |
1537 | 3.34k | cptr = st; |
1538 | 3.34k | st = strchr(st, ','); |
1539 | 3.34k | if (st) |
1540 | 0 | *st++ = '\0'; |
1541 | | |
1542 | 3.34k | DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n", |
1543 | 3.34k | cptr)); |
1544 | | |
1545 | 3.34k | if (strncasecmp(cptr, "none", 4) == 0) { |
1546 | 0 | DEBUGMSGTL(("snmp_agent", |
1547 | 0 | "init_master_agent; pseudo-transport \"none\" " |
1548 | 0 | "requested\n")); |
1549 | 0 | break; |
1550 | 0 | } |
1551 | 3.34k | if (-1 == netsnmp_agent_listen_on(cptr)) { |
1552 | 0 | SNMP_FREE(buf); |
1553 | 0 | return 1; |
1554 | 0 | } |
1555 | 3.34k | } while(st && *st != '\0'); |
1556 | 3.34k | SNMP_FREE(buf); |
1557 | 3.34k | #endif /* NETSNMP_NO_LISTEN_SUPPORT */ |
1558 | | |
1559 | 3.34k | #ifdef USING_AGENTX_MASTER_MODULE |
1560 | 3.34k | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1561 | 3.34k | NETSNMP_DS_AGENT_AGENTX_MASTER) == 1) |
1562 | 0 | real_init_master(); |
1563 | 3.34k | #endif |
1564 | 3.34k | #ifdef USING_SMUX_MODULE |
1565 | 3.34k | if(should_init("smux")) |
1566 | 0 | real_init_smux(); |
1567 | 3.34k | #endif |
1568 | | |
1569 | 3.34k | #ifndef NETSNMP_NO_PDU_STATS |
1570 | 3.34k | _pdu_stats_init(); |
1571 | 3.34k | #endif /* NETSNMP_NO_PDU_STATS */ |
1572 | | |
1573 | 3.34k | return 0; |
1574 | 3.34k | } |
1575 | | |
1576 | | void |
1577 | | clear_nsap_list(void) |
1578 | 3.34k | { |
1579 | 3.34k | DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n")); |
1580 | | |
1581 | 6.69k | while (agent_nsap_list != NULL) |
1582 | 3.34k | netsnmp_deregister_agent_nsap(agent_nsap_list->handle); |
1583 | 3.34k | } |
1584 | | |
1585 | | void |
1586 | | shutdown_master_agent(void) |
1587 | 3.34k | { |
1588 | 3.34k | clear_nsap_list(); |
1589 | | |
1590 | 3.34k | #ifndef NETSNMP_NO_PDU_STATS |
1591 | 3.34k | _pdu_stats_shutdown(); |
1592 | 3.34k | #endif /* NETSNMP_NO_PDU_STATS */ |
1593 | 3.34k | } |
1594 | | |
1595 | | |
1596 | | netsnmp_agent_session * |
1597 | | init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu) |
1598 | 13.3k | { |
1599 | 13.3k | netsnmp_agent_session *asp = calloc(1, sizeof(netsnmp_agent_session)); |
1600 | | |
1601 | 13.3k | if (asp == NULL) { |
1602 | 0 | return NULL; |
1603 | 0 | } |
1604 | | |
1605 | 13.3k | DEBUGMSGTL(("snmp_agent","agent_sesion %8p created\n", asp)); |
1606 | 13.3k | asp->session = session; |
1607 | 13.3k | asp->pdu = snmp_clone_pdu(pdu); |
1608 | 13.3k | if (!asp->pdu) |
1609 | 0 | goto err; |
1610 | 13.3k | asp->orig_pdu = snmp_clone_pdu(pdu); |
1611 | 13.3k | if (!asp->orig_pdu) |
1612 | 0 | goto err; |
1613 | 13.3k | asp->rw = READ; |
1614 | 13.3k | asp->exact = TRUE; |
1615 | 13.3k | asp->next = NULL; |
1616 | 13.3k | asp->mode = RESERVE1; |
1617 | 13.3k | asp->status = SNMP_ERR_NOERROR; |
1618 | 13.3k | asp->index = 0; |
1619 | 13.3k | asp->oldmode = 0; |
1620 | 13.3k | asp->treecache_num = -1; |
1621 | 13.3k | asp->treecache_len = 0; |
1622 | 13.3k | asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info); |
1623 | 13.3k | asp->flags = SNMP_AGENT_FLAGS_NONE; |
1624 | 13.3k | DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n", |
1625 | 13.3k | asp, asp->reqinfo)); |
1626 | | |
1627 | 13.3k | return asp; |
1628 | | |
1629 | 0 | err: |
1630 | 0 | snmp_free_pdu(asp->orig_pdu); |
1631 | 0 | snmp_free_pdu(asp->pdu); |
1632 | 0 | free(asp); |
1633 | 0 | return NULL; |
1634 | 13.3k | } |
1635 | | |
1636 | | void |
1637 | | free_agent_snmp_session(netsnmp_agent_session *asp) |
1638 | 26.0k | { |
1639 | 26.0k | if (!asp) |
1640 | 12.6k | return; |
1641 | | |
1642 | 13.3k | DEBUGMSGTL(("snmp_agent","agent_session %8p released\n", asp)); |
1643 | | |
1644 | 13.3k | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, SNMP_CALLBACK_FREE_SESSION, |
1645 | 13.3k | asp); |
1646 | | |
1647 | 13.3k | netsnmp_remove_from_delegated(asp); |
1648 | | |
1649 | 13.3k | DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n", |
1650 | 13.3k | asp, asp->reqinfo)); |
1651 | | |
1652 | 13.3k | if (asp->orig_pdu) |
1653 | 704 | snmp_free_pdu(asp->orig_pdu); |
1654 | 13.3k | if (asp->pdu) |
1655 | 704 | snmp_free_pdu(asp->pdu); |
1656 | 13.3k | if (asp->reqinfo) |
1657 | 13.3k | netsnmp_free_agent_request_info(asp->reqinfo); |
1658 | 13.3k | SNMP_FREE(asp->treecache); |
1659 | 13.3k | SNMP_FREE(asp->bulkcache); |
1660 | 13.3k | if (asp->requests) { |
1661 | 3.40k | int i; |
1662 | 4.41k | for (i = 0; i < asp->vbcount; i++) { |
1663 | 1.01k | netsnmp_free_request_data_sets(&asp->requests[i]); |
1664 | 1.01k | } |
1665 | 3.40k | SNMP_FREE(asp->requests); |
1666 | 3.40k | } |
1667 | 13.3k | if (asp->cache_store) { |
1668 | 0 | netsnmp_free_cachemap(asp->cache_store); |
1669 | 0 | asp->cache_store = NULL; |
1670 | 0 | } |
1671 | 13.3k | SNMP_FREE(asp); |
1672 | 13.3k | } |
1673 | | |
1674 | | int |
1675 | | netsnmp_check_for_delegated(netsnmp_agent_session *asp) |
1676 | 24.2k | { |
1677 | 24.2k | int i; |
1678 | 24.2k | netsnmp_request_info *request; |
1679 | | |
1680 | 24.2k | if (NULL == asp->treecache) |
1681 | 10 | return 0; |
1682 | | |
1683 | 24.2k | if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) |
1684 | 0 | return 0; |
1685 | | |
1686 | 25.1k | for (i = 0; i <= asp->treecache_num; i++) { |
1687 | 1.98k | for (request = asp->treecache[i].requests_begin; request; |
1688 | 1.06k | request = request->next) { |
1689 | 1.06k | if (request->delegated) |
1690 | 0 | return 1; |
1691 | 1.06k | } |
1692 | 926 | } |
1693 | 24.2k | return 0; |
1694 | 24.2k | } |
1695 | | |
1696 | | int |
1697 | | netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp) |
1698 | 12.6k | { |
1699 | 12.6k | netsnmp_agent_session *asptmp; |
1700 | 12.6k | for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) { |
1701 | 0 | if (asptmp == asp) |
1702 | 0 | return 1; |
1703 | 0 | } |
1704 | 12.6k | return 0; |
1705 | 12.6k | } |
1706 | | |
1707 | | int |
1708 | | netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp) |
1709 | 12.6k | { |
1710 | 12.6k | if (netsnmp_check_for_delegated(asp)) { |
1711 | 0 | if (!netsnmp_check_delegated_chain_for(asp)) { |
1712 | | /* |
1713 | | * add to delegated request chain |
1714 | | */ |
1715 | 0 | asp->next = agent_delegated_list; |
1716 | 0 | agent_delegated_list = asp; |
1717 | 0 | DEBUGMSGTL(("snmp_agent", "delegate session == %8p\n", asp)); |
1718 | 0 | } |
1719 | 0 | return 1; |
1720 | 0 | } |
1721 | 12.6k | return 0; |
1722 | 12.6k | } |
1723 | | |
1724 | | int |
1725 | | netsnmp_remove_from_delegated(netsnmp_agent_session *asp) |
1726 | 13.3k | { |
1727 | 13.3k | netsnmp_agent_session *curr, *prev = NULL; |
1728 | | |
1729 | 13.3k | for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) { |
1730 | | /* |
1731 | | * is this us? |
1732 | | */ |
1733 | 0 | if (curr != asp) |
1734 | 0 | continue; |
1735 | | |
1736 | | /* |
1737 | | * remove from queue |
1738 | | */ |
1739 | 0 | if (prev != NULL) |
1740 | 0 | prev->next = asp->next; |
1741 | 0 | else |
1742 | 0 | agent_delegated_list = asp->next; |
1743 | |
|
1744 | 0 | DEBUGMSGTL(("snmp_agent", "remove delegated session == %8p\n", asp)); |
1745 | |
|
1746 | 0 | return 1; |
1747 | 0 | } |
1748 | | |
1749 | 13.3k | return 0; |
1750 | 13.3k | } |
1751 | | |
1752 | | /* |
1753 | | * netsnmp_remove_delegated_requests_for_session |
1754 | | * |
1755 | | * called when a session is being closed. Check all delegated requests to |
1756 | | * see if the are waiting on this session, and if set, set the status for |
1757 | | * that request to GENERR. |
1758 | | */ |
1759 | | int |
1760 | | netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess) |
1761 | 0 | { |
1762 | 0 | netsnmp_agent_session *asp; |
1763 | 0 | int total_count = 0; |
1764 | | |
1765 | 0 | for (asp = agent_delegated_list; asp; asp = asp->next) { |
1766 | | /* |
1767 | | * check each request |
1768 | | */ |
1769 | 0 | int i; |
1770 | 0 | int count = 0; |
1771 | 0 | netsnmp_request_info *request; |
1772 | 0 | for (i = 0; i <= asp->treecache_num; i++) { |
1773 | 0 | for (request = asp->treecache[i].requests_begin; request; |
1774 | 0 | request = request->next) { |
1775 | | /* |
1776 | | * check session |
1777 | | */ |
1778 | 0 | netsnmp_assert(NULL!=request->subtree); |
1779 | 0 | if(request->subtree->session != sess) |
1780 | 0 | continue; |
1781 | | |
1782 | | /* |
1783 | | * matched! mark request as done |
1784 | | */ |
1785 | 0 | netsnmp_request_set_error(request, SNMP_ERR_GENERR); |
1786 | 0 | ++count; |
1787 | 0 | } |
1788 | 0 | } |
1789 | 0 | if (count) { |
1790 | 0 | asp->flags |= SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS; |
1791 | 0 | total_count += count; |
1792 | 0 | } |
1793 | 0 | } |
1794 | | |
1795 | | /* |
1796 | | * if we found any, that request may be finished now |
1797 | | */ |
1798 | 0 | if(total_count) { |
1799 | 0 | DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session " |
1800 | 0 | "%8p\n", total_count, sess)); |
1801 | 0 | netsnmp_check_delegated_requests(); |
1802 | 0 | } |
1803 | | |
1804 | 0 | return total_count; |
1805 | 0 | } |
1806 | | |
1807 | | #if 0 |
1808 | | int |
1809 | | netsnmp_check_queued_chain_for(netsnmp_agent_session *asp) |
1810 | | { |
1811 | | netsnmp_agent_session *asptmp; |
1812 | | for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) { |
1813 | | if (asptmp == asp) |
1814 | | return 1; |
1815 | | } |
1816 | | return 0; |
1817 | | } |
1818 | | #endif |
1819 | | |
1820 | | int |
1821 | | netsnmp_add_queued(netsnmp_agent_session *asp) |
1822 | 0 | { |
1823 | 0 | netsnmp_agent_session *asp_tmp; |
1824 | | |
1825 | | /* |
1826 | | * first item? |
1827 | | */ |
1828 | 0 | if (NULL == netsnmp_agent_queued_list) { |
1829 | 0 | netsnmp_agent_queued_list = asp; |
1830 | 0 | return 1; |
1831 | 0 | } |
1832 | | |
1833 | | |
1834 | | /* |
1835 | | * add to end of queued request chain |
1836 | | */ |
1837 | 0 | asp_tmp = netsnmp_agent_queued_list; |
1838 | 0 | for (; asp_tmp; asp_tmp = asp_tmp->next) { |
1839 | | /* |
1840 | | * already in queue? |
1841 | | */ |
1842 | 0 | if (asp_tmp == asp) |
1843 | 0 | break; |
1844 | | |
1845 | | /* |
1846 | | * end of queue? |
1847 | | */ |
1848 | 0 | if (NULL == asp_tmp->next) |
1849 | 0 | asp_tmp->next = asp; |
1850 | 0 | } |
1851 | 0 | return 1; |
1852 | 0 | } |
1853 | | |
1854 | | #ifndef NETSNMP_NO_PDU_STATS |
1855 | | /* |
1856 | | * netsnmp_pdu_stats_process: record time for pdu processing |
1857 | | */ |
1858 | | int |
1859 | | netsnmp_pdu_stats_process(netsnmp_agent_session *asp) |
1860 | 0 | { |
1861 | 0 | netsnmp_pdu_stats *new_entry, *old = NULL; |
1862 | 0 | struct timeval tv_end; |
1863 | 0 | marker_t start, end = &tv_end; |
1864 | 0 | u_long msec; |
1865 | |
|
1866 | 0 | if (NULL == asp) { |
1867 | 0 | DEBUGMSGTL(("stats:pdu", "netsnmp_pdu_stats_process bad params\n")); |
1868 | 0 | return -1; |
1869 | 0 | } |
1870 | | |
1871 | | /** get start/end time */ |
1872 | 0 | netsnmp_set_monotonic_marker(&end); |
1873 | 0 | start = (marker_t)netsnmp_agent_get_list_data(asp->reqinfo, |
1874 | 0 | "netsnmp_pdu_stats"); |
1875 | 0 | if (NULL == start) { |
1876 | 0 | DEBUGMSGTL(("stats:pdu:stop", "start time not found!\n")); |
1877 | 0 | return -1; |
1878 | 0 | } |
1879 | | |
1880 | 0 | msec = uatime_diff(start, end); |
1881 | 0 | DEBUGMSGTL(("stats:pdu:stop", "pdu processing took %ld msec\n", msec)); |
1882 | | |
1883 | | /** bail if below threshold or less than current low time */ |
1884 | 0 | if (msec <= _pdu_stats_threshold || msec < _pdu_stats_current_lowest) { |
1885 | 0 | DEBUGMSGTL(("9:stats:pdu", |
1886 | 0 | "time below thresholds (%ld/%ld); ignoring\n", |
1887 | 0 | _pdu_stats_threshold, _pdu_stats_current_lowest)); |
1888 | 0 | return 0; |
1889 | 0 | } |
1890 | | |
1891 | | /** insert in list. if list goes over max size, truncate last entry. */ |
1892 | 0 | new_entry = SNMP_MALLOC_TYPEDEF(netsnmp_pdu_stats); |
1893 | 0 | if (NULL == new_entry) { |
1894 | 0 | snmp_log(LOG_ERR, "malloc failed for pdu stats entry\n"); |
1895 | 0 | return -1; |
1896 | 0 | } |
1897 | 0 | new_entry->processing_time = msec; |
1898 | 0 | time(&new_entry->timestamp); |
1899 | 0 | new_entry->pdu = snmp_clone_pdu(asp->pdu); |
1900 | |
|
1901 | 0 | CONTAINER_INSERT(_pdu_stats, new_entry); |
1902 | |
|
1903 | 0 | if (CONTAINER_SIZE(_pdu_stats) > _pdu_stats_max) { |
1904 | 0 | DEBUGMSGTL(("9:stats:pdu", "dropping old/low stat\n")); |
1905 | 0 | CONTAINER_REMOVE_AT(_pdu_stats, _pdu_stats_max, (void**)&old); |
1906 | 0 | if (old) { |
1907 | 0 | snmp_free_pdu(old->pdu); |
1908 | 0 | free(old); |
1909 | 0 | } |
1910 | 0 | } |
1911 | |
|
1912 | 0 | if (CONTAINER_SIZE(_pdu_stats) < _pdu_stats_max) |
1913 | 0 | _pdu_stats_current_lowest = 0; /* take anything over threshold */ |
1914 | 0 | else { |
1915 | 0 | CONTAINER_GET_AT(_pdu_stats, _pdu_stats_max - 1, (void**)&old); |
1916 | 0 | if (old) |
1917 | 0 | _pdu_stats_current_lowest = old->processing_time; |
1918 | 0 | } |
1919 | |
|
1920 | 0 | DEBUGIF("9:stats:pdu") { |
1921 | 0 | _dump_pdu_stats(); |
1922 | 0 | } |
1923 | |
|
1924 | 0 | return 1; |
1925 | |
|
1926 | 0 | } |
1927 | | #endif /* NETSNMP_NO_PDU_STATS */ |
1928 | | |
1929 | | int |
1930 | | netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status) |
1931 | 12.6k | { |
1932 | 12.6k | #ifndef NETSNMP_NO_PDU_STATS |
1933 | 12.6k | if (_pdu_stats_max > 0) |
1934 | 0 | netsnmp_pdu_stats_process(asp); |
1935 | 12.6k | #endif /* NETSNMP_NO_PDU_STATS */ |
1936 | | |
1937 | | /* |
1938 | | * if this request was a set, clear the global now that we are |
1939 | | * done. |
1940 | | */ |
1941 | 12.6k | if (asp == netsnmp_processing_set) { |
1942 | 333 | DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %8p\n", |
1943 | 333 | asp)); |
1944 | 333 | netsnmp_processing_set = NULL; |
1945 | 333 | } |
1946 | | |
1947 | 12.6k | if (asp->pdu) { |
1948 | 12.6k | const int command = asp->pdu->command; |
1949 | | |
1950 | | /* |
1951 | | * If we've got an error status, then this needs to be |
1952 | | * passed back up to the higher levels.... |
1953 | | */ |
1954 | 12.6k | if ( status != 0 && asp->status == 0 ) |
1955 | 1.84k | asp->status = status; |
1956 | | |
1957 | 12.6k | switch (asp->pdu->command) { |
1958 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
1959 | 0 | case SNMP_MSG_INTERNAL_SET_BEGIN: |
1960 | 8.88k | case SNMP_MSG_INTERNAL_SET_RESERVE1: |
1961 | 8.99k | case SNMP_MSG_INTERNAL_SET_RESERVE2: |
1962 | 9.27k | case SNMP_MSG_INTERNAL_SET_ACTION: |
1963 | | /* |
1964 | | * some stuff needs to be saved in special subagent cases |
1965 | | */ |
1966 | 9.27k | save_set_cache(asp); |
1967 | 9.27k | break; |
1968 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
1969 | | |
1970 | 109 | case SNMP_MSG_GETNEXT: |
1971 | 109 | _fix_endofmibview(asp); |
1972 | 109 | break; |
1973 | | |
1974 | 622 | case SNMP_MSG_GETBULK: |
1975 | | /* |
1976 | | * for a GETBULK response we need to rearrange the varbinds |
1977 | | */ |
1978 | 622 | _reorder_getbulk(asp); |
1979 | 622 | break; |
1980 | 12.6k | } |
1981 | | |
1982 | | /* |
1983 | | * May need to "dumb down" a SET error status for a |
1984 | | * v1 query. See RFC2576 - section 4.3 |
1985 | | */ |
1986 | 12.6k | #ifndef NETSNMP_DISABLE_SNMPV1 |
1987 | 12.6k | #ifndef NETSNMP_NO_WRITE_SUPPORT |
1988 | 12.6k | if ((asp->pdu->command == SNMP_MSG_SET) && |
1989 | 333 | (asp->pdu->version == SNMP_VERSION_1)) { |
1990 | 333 | switch (asp->status) { |
1991 | 0 | case SNMP_ERR_WRONGVALUE: |
1992 | 0 | case SNMP_ERR_WRONGENCODING: |
1993 | 10 | case SNMP_ERR_WRONGTYPE: |
1994 | 10 | case SNMP_ERR_WRONGLENGTH: |
1995 | 10 | case SNMP_ERR_INCONSISTENTVALUE: |
1996 | 10 | status = SNMP_ERR_BADVALUE; |
1997 | 10 | asp->status = SNMP_ERR_BADVALUE; |
1998 | 10 | break; |
1999 | 0 | case SNMP_ERR_NOACCESS: |
2000 | 130 | case SNMP_ERR_NOTWRITABLE: |
2001 | 130 | case SNMP_ERR_NOCREATION: |
2002 | 130 | case SNMP_ERR_INCONSISTENTNAME: |
2003 | 130 | case SNMP_ERR_AUTHORIZATIONERROR: |
2004 | 130 | status = SNMP_ERR_NOSUCHNAME; |
2005 | 130 | asp->status = SNMP_ERR_NOSUCHNAME; |
2006 | 130 | break; |
2007 | 0 | case SNMP_ERR_RESOURCEUNAVAILABLE: |
2008 | 0 | case SNMP_ERR_COMMITFAILED: |
2009 | 0 | case SNMP_ERR_UNDOFAILED: |
2010 | 0 | status = SNMP_ERR_GENERR; |
2011 | 0 | asp->status = SNMP_ERR_GENERR; |
2012 | 0 | break; |
2013 | 333 | } |
2014 | 333 | } |
2015 | 12.6k | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2016 | | /* |
2017 | | * Similarly we may need to "dumb down" v2 exception |
2018 | | * types to throw an error for a v1 query. |
2019 | | * See RFC2576 - section 4.1.2.3 |
2020 | | */ |
2021 | 12.6k | if ( |
2022 | 12.6k | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2023 | 12.6k | (asp->pdu->command != SNMP_MSG_SET) && |
2024 | 12.3k | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2025 | 12.3k | (asp->pdu->version == SNMP_VERSION_1) && asp->index < 1) { |
2026 | 12.3k | netsnmp_variable_list *var_ptr = asp->pdu->variables; |
2027 | 12.3k | int i = 1; |
2028 | | |
2029 | 13.1k | while (var_ptr != NULL) { |
2030 | 829 | switch (var_ptr->type) { |
2031 | 251 | case SNMP_NOSUCHOBJECT: |
2032 | 251 | case SNMP_NOSUCHINSTANCE: |
2033 | 758 | case SNMP_ENDOFMIBVIEW: |
2034 | 758 | case ASN_COUNTER64: |
2035 | 758 | status = SNMP_ERR_NOSUCHNAME; |
2036 | 758 | asp->status = SNMP_ERR_NOSUCHNAME; |
2037 | 758 | asp->index = i; |
2038 | 758 | break; |
2039 | 829 | } |
2040 | 829 | var_ptr = var_ptr->next_variable; |
2041 | 829 | ++i; |
2042 | 829 | } |
2043 | 12.3k | } |
2044 | | |
2045 | 333 | else |
2046 | 333 | { |
2047 | 333 | status = asp->status ; |
2048 | 333 | } |
2049 | 12.6k | #endif /* snmpv1 support */ |
2050 | | |
2051 | | /** so far so good? try and build packet */ |
2052 | 12.6k | if (status == SNMP_ERR_NOERROR) { |
2053 | 10.2k | struct session_list *slp = snmp_sess_pointer(asp->session); |
2054 | | |
2055 | | /** build packet to send */ |
2056 | 10.2k | asp->pdu->command = SNMP_MSG_RESPONSE; |
2057 | 10.2k | asp->pdu->errstat = asp->status; |
2058 | 10.2k | asp->pdu->errindex = asp->index; |
2059 | 10.2k | status = _build_initial_pdu_packet(slp, asp->pdu, |
2060 | 10.2k | SNMP_MSG_GETBULK == asp->orig_pdu->command); |
2061 | 10.2k | if (SNMPERR_SUCCESS != status){ |
2062 | 10.2k | if (SNMPERR_TOO_LONG == asp->session->s_snmp_errno) |
2063 | 0 | status = asp->status = SNMP_ERR_TOOBIG; |
2064 | 10.2k | else |
2065 | 10.2k | status = asp->status = SNMP_ERR_GENERR; |
2066 | 10.2k | } |
2067 | 10.2k | } |
2068 | | |
2069 | 12.6k | if (status == SNMP_ERR_NOERROR) |
2070 | 0 | snmp_increment_statistic_by( |
2071 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2072 | 0 | (command == SNMP_MSG_SET ? |
2073 | 0 | STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS), |
2074 | | #else |
2075 | | STAT_SNMPINTOTALREQVARS, |
2076 | | #endif |
2077 | 0 | count_varbinds(asp->pdu->variables)); |
2078 | 12.6k | } /** if asp->pdu */ |
2079 | | |
2080 | | /* |
2081 | | * Update the snmp error-count statistics |
2082 | | * XXX - should we include the V2 errors in this or not? |
2083 | | */ |
2084 | 12.6k | #define INCLUDE_V2ERRORS_IN_V1STATS |
2085 | | |
2086 | 12.6k | switch (status) { |
2087 | 0 | #ifdef INCLUDE_V2ERRORS_IN_V1STATS |
2088 | 0 | case SNMP_ERR_WRONGVALUE: |
2089 | 0 | case SNMP_ERR_WRONGENCODING: |
2090 | 0 | case SNMP_ERR_WRONGTYPE: |
2091 | 0 | case SNMP_ERR_WRONGLENGTH: |
2092 | 0 | case SNMP_ERR_INCONSISTENTVALUE: |
2093 | 0 | #endif |
2094 | 10 | case SNMP_ERR_BADVALUE: |
2095 | 10 | snmp_increment_statistic(STAT_SNMPOUTBADVALUES); |
2096 | 10 | break; |
2097 | 0 | #ifdef INCLUDE_V2ERRORS_IN_V1STATS |
2098 | 0 | case SNMP_ERR_NOACCESS: |
2099 | 0 | case SNMP_ERR_NOTWRITABLE: |
2100 | 0 | case SNMP_ERR_NOCREATION: |
2101 | 0 | case SNMP_ERR_INCONSISTENTNAME: |
2102 | 0 | case SNMP_ERR_AUTHORIZATIONERROR: |
2103 | 0 | #endif |
2104 | 562 | case SNMP_ERR_NOSUCHNAME: |
2105 | 562 | snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES); |
2106 | 562 | break; |
2107 | 0 | #ifdef INCLUDE_V2ERRORS_IN_V1STATS |
2108 | 0 | case SNMP_ERR_RESOURCEUNAVAILABLE: |
2109 | 0 | case SNMP_ERR_COMMITFAILED: |
2110 | 0 | case SNMP_ERR_UNDOFAILED: |
2111 | 0 | #endif |
2112 | 10.2k | case SNMP_ERR_GENERR: |
2113 | 10.2k | snmp_increment_statistic(STAT_SNMPOUTGENERRS); |
2114 | 10.2k | break; |
2115 | | |
2116 | 0 | case SNMP_ERR_TOOBIG: |
2117 | 0 | snmp_increment_statistic(STAT_SNMPOUTTOOBIGS); |
2118 | 0 | break; |
2119 | 12.6k | } |
2120 | | |
2121 | 12.6k | if ((status != SNMP_ERR_NOERROR) || (NULL == asp->pdu)) { |
2122 | | /** Use a copy of the original request to report failures. */ |
2123 | 12.6k | snmp_free_pdu(asp->pdu); |
2124 | 12.6k | asp->pdu = asp->orig_pdu; |
2125 | 12.6k | asp->orig_pdu = NULL; |
2126 | 12.6k | } |
2127 | 12.6k | if (asp->pdu) { |
2128 | 12.6k | int rc; |
2129 | | |
2130 | 12.6k | asp->pdu->command = SNMP_MSG_RESPONSE; |
2131 | 12.6k | asp->pdu->errstat = asp->status; |
2132 | 12.6k | asp->pdu->errindex = asp->index; |
2133 | 12.6k | rc = snmp_send(asp->session, asp->pdu); |
2134 | 12.6k | if (rc == 0 && asp->session->s_snmp_errno != SNMPERR_SUCCESS) { |
2135 | 0 | netsnmp_variable_list *var_ptr; |
2136 | 0 | snmp_perror("send response"); |
2137 | 0 | for (var_ptr = asp->pdu->variables; var_ptr != NULL; |
2138 | 0 | var_ptr = var_ptr->next_variable) { |
2139 | 0 | size_t c_oidlen = 256, c_outlen = 0; |
2140 | 0 | u_char *c_oid = (u_char *) malloc(c_oidlen); |
2141 | |
|
2142 | 0 | if (c_oid) { |
2143 | 0 | if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1, |
2144 | 0 | var_ptr->name, |
2145 | 0 | var_ptr->name_length)) { |
2146 | 0 | snmp_log(LOG_ERR, " -- %s [TRUNCATED]\n", c_oid); |
2147 | 0 | } else { |
2148 | 0 | snmp_log(LOG_ERR, " -- %s\n", c_oid); |
2149 | 0 | } |
2150 | 0 | SNMP_FREE(c_oid); |
2151 | 0 | } |
2152 | 0 | } |
2153 | 0 | } |
2154 | 12.6k | if (rc == 0) |
2155 | 12.6k | snmp_free_pdu(asp->pdu); |
2156 | 12.6k | snmp_increment_statistic(STAT_SNMPOUTPKTS); |
2157 | 12.6k | snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES); |
2158 | 12.6k | asp->pdu = NULL; |
2159 | 12.6k | free_agent_snmp_session(asp); |
2160 | 12.6k | } |
2161 | 12.6k | return 1; |
2162 | 12.6k | } |
2163 | | |
2164 | | /** handles an incoming SNMP packet into the agent */ |
2165 | | int |
2166 | | handle_snmp_packet(int op, netsnmp_session * session, int reqid, |
2167 | | netsnmp_pdu *pdu, void *magic) |
2168 | 13.3k | { |
2169 | 13.3k | netsnmp_agent_session *asp; |
2170 | 13.3k | int status, access_ret, rc; |
2171 | | |
2172 | | /* |
2173 | | * We only support receiving here. |
2174 | | */ |
2175 | 13.3k | if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) { |
2176 | 0 | return 1; |
2177 | 0 | } |
2178 | | |
2179 | | /* |
2180 | | * RESPONSE messages won't get this far, but TRAP-like messages |
2181 | | * might. |
2182 | | */ |
2183 | 13.3k | if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM || |
2184 | 12.7k | pdu->command == SNMP_MSG_TRAP2) { |
2185 | 704 | DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n", |
2186 | 704 | pdu->command)); |
2187 | 704 | pdu->command = SNMP_MSG_TRAP2; |
2188 | 704 | snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS); |
2189 | 704 | return 1; |
2190 | 704 | } |
2191 | | |
2192 | | /* |
2193 | | * send snmpv3 authfail trap. |
2194 | | */ |
2195 | 12.6k | if (pdu->version == SNMP_VERSION_3 && |
2196 | 0 | session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) { |
2197 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2198 | 0 | SNMPD_CALLBACK_AUTH_FAILURE, pdu); |
2199 | 0 | send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); |
2200 | 0 | return 1; |
2201 | 0 | } |
2202 | | |
2203 | 12.6k | if (magic == NULL) { |
2204 | 0 | asp = init_agent_snmp_session(session, pdu); |
2205 | 0 | status = SNMP_ERR_NOERROR; |
2206 | 0 | if (asp == NULL) |
2207 | 0 | return 1; |
2208 | 12.6k | } else { |
2209 | 12.6k | asp = (netsnmp_agent_session *) magic; |
2210 | 12.6k | status = asp->status; |
2211 | 12.6k | } |
2212 | | |
2213 | | #if defined(NETSNMP_DISABLE_SET_SUPPORT) && !defined(NETSNMP_NO_WRITE_SUPPORT) |
2214 | | if (pdu->command == SNMP_MSG_SET) { |
2215 | | /** Silvercreek protocol tests send set with 0 varbinds */ |
2216 | | if (NULL == pdu->variables) |
2217 | | return netsnmp_wrap_up_request(asp, SNMP_ERR_NOERROR); |
2218 | | asp->index = 1; |
2219 | | return netsnmp_wrap_up_request(asp, SNMP_ERR_NOTWRITABLE); |
2220 | | } |
2221 | | #endif /* NETSNMP_DISABLE_SET_SUPPORT && !NETSNMP_NO_WRITE_SUPPORT */ |
2222 | | |
2223 | 12.6k | if ((access_ret = check_access(asp->pdu)) != 0) { |
2224 | 0 | if (access_ret == VACM_NOSUCHCONTEXT) { |
2225 | | /* |
2226 | | * rfc3413 section 3.2, step 5 says that we increment the |
2227 | | * counter but don't return a response of any kind |
2228 | | */ |
2229 | | |
2230 | | /* |
2231 | | * we currently don't support unavailable contexts, as |
2232 | | * there is no reason to that I currently know of |
2233 | | */ |
2234 | 0 | snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS); |
2235 | | |
2236 | | /* |
2237 | | * drop the request |
2238 | | */ |
2239 | 0 | free_agent_snmp_session(asp); |
2240 | 0 | return 0; |
2241 | 0 | } else { |
2242 | | /* |
2243 | | * access control setup is incorrect |
2244 | | */ |
2245 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2246 | 0 | SNMPD_CALLBACK_AUTH_FAILURE, pdu); |
2247 | 0 | send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); |
2248 | 0 | #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) |
2249 | | #if defined(NETSNMP_DISABLE_SNMPV1) |
2250 | | if (asp->pdu->version != SNMP_VERSION_2c) { |
2251 | | #else |
2252 | | #if defined(NETSNMP_DISABLE_SNMPV2C) |
2253 | | if (asp->pdu->version != SNMP_VERSION_1) { |
2254 | | #else |
2255 | 0 | if (asp->pdu->version != SNMP_VERSION_1 |
2256 | 0 | && asp->pdu->version != SNMP_VERSION_2c) { |
2257 | 0 | #endif |
2258 | 0 | #endif |
2259 | 0 | asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR; |
2260 | 0 | asp->pdu->command = SNMP_MSG_RESPONSE; |
2261 | 0 | snmp_increment_statistic(STAT_SNMPOUTPKTS); |
2262 | 0 | if (!snmp_send(asp->session, asp->pdu)) |
2263 | 0 | snmp_free_pdu(asp->pdu); |
2264 | 0 | asp->pdu = NULL; |
2265 | 0 | free_agent_snmp_session(asp); |
2266 | 0 | return 1; |
2267 | 0 | } else { |
2268 | 0 | #endif /* support for community based SNMP */ |
2269 | | /* |
2270 | | * drop the request |
2271 | | */ |
2272 | 0 | free_agent_snmp_session(asp); |
2273 | 0 | return 0; |
2274 | 0 | #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) |
2275 | 0 | } |
2276 | 0 | #endif /* support for community based SNMP */ |
2277 | 0 | } |
2278 | 0 | } |
2279 | | |
2280 | 12.6k | rc = netsnmp_handle_request(asp, status); |
2281 | | |
2282 | | /* |
2283 | | * done |
2284 | | */ |
2285 | 12.6k | DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %8p\n", |
2286 | 12.6k | asp)); |
2287 | 12.6k | return rc; |
2288 | 12.6k | } |
2289 | | |
2290 | | netsnmp_request_info * |
2291 | | netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount, |
2292 | | netsnmp_variable_list * varbind_ptr, |
2293 | | netsnmp_subtree *tp) |
2294 | 1.01k | { |
2295 | 1.01k | netsnmp_request_info *request = NULL; |
2296 | | |
2297 | 1.01k | DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount)); |
2298 | 1.01k | DEBUGMSGOID(("snmp_agent", varbind_ptr->name, |
2299 | 1.01k | varbind_ptr->name_length)); |
2300 | 1.01k | DEBUGMSG(("snmp_agent", ", %8p)\n", tp)); |
2301 | | |
2302 | 1.01k | if (tp && |
2303 | 1.01k | (asp->pdu->command == SNMP_MSG_GETNEXT || |
2304 | 924 | asp->pdu->command == SNMP_MSG_GETBULK)) { |
2305 | 507 | int result; |
2306 | 507 | int prefix_len; |
2307 | | |
2308 | 507 | prefix_len = netsnmp_oid_find_prefix(tp->start_a, |
2309 | 507 | tp->start_len, |
2310 | 507 | tp->end_a, tp->end_len); |
2311 | 507 | if (prefix_len < 1) { |
2312 | 507 | result = VACM_NOTINVIEW; /* ack... bad bad thing happened */ |
2313 | 507 | } else { |
2314 | 0 | result = |
2315 | 0 | netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len); |
2316 | 0 | } |
2317 | | |
2318 | 1.15k | while (result == VACM_NOTINVIEW) { |
2319 | | /* the entire subtree is not in view. Skip it. */ |
2320 | | /** @todo make this be more intelligent about ranges. |
2321 | | Right now we merely take the highest level |
2322 | | commonality of a registration range and use that. |
2323 | | At times we might be able to be smarter about |
2324 | | checking the range itself as opposed to the node |
2325 | | above where the range exists, but I doubt this will |
2326 | | come up all that frequently. */ |
2327 | 1.15k | tp = tp->next; |
2328 | 1.15k | if (tp) { |
2329 | 650 | prefix_len = netsnmp_oid_find_prefix(tp->start_a, |
2330 | 650 | tp->start_len, |
2331 | 650 | tp->end_a, |
2332 | 650 | tp->end_len); |
2333 | 650 | if (prefix_len < 1) { |
2334 | | /* ack... bad bad thing happened */ |
2335 | 650 | result = VACM_NOTINVIEW; |
2336 | 650 | } else { |
2337 | 0 | result = |
2338 | 0 | netsnmp_acm_check_subtree(asp->pdu, |
2339 | 0 | tp->start_a, prefix_len); |
2340 | 0 | } |
2341 | 650 | } |
2342 | 507 | else |
2343 | 507 | break; |
2344 | 1.15k | } |
2345 | 507 | } |
2346 | 1.01k | if (tp == NULL) { |
2347 | | /* |
2348 | | * no appropriate registration found |
2349 | | */ |
2350 | | /* |
2351 | | * make up the response ourselves |
2352 | | */ |
2353 | 507 | switch (asp->pdu->command) { |
2354 | 90 | case SNMP_MSG_GETNEXT: |
2355 | 507 | case SNMP_MSG_GETBULK: |
2356 | 507 | varbind_ptr->type = SNMP_ENDOFMIBVIEW; |
2357 | 507 | break; |
2358 | | |
2359 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2360 | 0 | case SNMP_MSG_SET: |
2361 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2362 | 0 | case SNMP_MSG_GET: |
2363 | 0 | varbind_ptr->type = SNMP_NOSUCHOBJECT; |
2364 | 0 | break; |
2365 | | |
2366 | 0 | default: |
2367 | 0 | return NULL; /* shouldn't get here */ |
2368 | 507 | } |
2369 | 507 | } else { |
2370 | 507 | int cacheid; |
2371 | | |
2372 | 507 | DEBUGMSGTL(("snmp_agent", "tp->start ")); |
2373 | 507 | DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len)); |
2374 | 507 | DEBUGMSG(("snmp_agent", ", tp->end ")); |
2375 | 507 | DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len)); |
2376 | 507 | DEBUGMSG(("snmp_agent", ", \n")); |
2377 | | |
2378 | | /* |
2379 | | * malloc the request structure |
2380 | | */ |
2381 | 507 | request = &(asp->requests[vbcount - 1]); |
2382 | 507 | request->index = vbcount; |
2383 | 507 | request->delegated = 0; |
2384 | 507 | request->processed = 0; |
2385 | 507 | request->status = 0; |
2386 | 507 | request->subtree = tp; |
2387 | 507 | request->agent_req_info = asp->reqinfo; |
2388 | 507 | if (request->parent_data) { |
2389 | 0 | netsnmp_free_request_data_sets(request); |
2390 | 0 | } |
2391 | 507 | DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", |
2392 | 507 | asp, asp->reqinfo)); |
2393 | | |
2394 | | /* |
2395 | | * for non-SET modes, set the type to NULL |
2396 | | */ |
2397 | 507 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2398 | 507 | if (!MODE_IS_SET(asp->pdu->command)) { |
2399 | 322 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2400 | 322 | DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", |
2401 | 322 | asp, asp->reqinfo)); |
2402 | 322 | if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) { |
2403 | 0 | DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n", |
2404 | 0 | request->index)); |
2405 | 0 | request->inclusive = 1; |
2406 | 0 | } |
2407 | 322 | varbind_ptr->type = ASN_NULL; |
2408 | 322 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2409 | 322 | } |
2410 | 507 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2411 | | |
2412 | | /* |
2413 | | * place them in a cache |
2414 | | */ |
2415 | 507 | if (tp->global_cacheid) { |
2416 | | /* |
2417 | | * we need to merge all marked subtrees together |
2418 | | */ |
2419 | 0 | if (asp->cache_store && -1 != |
2420 | 0 | (cacheid = netsnmp_get_local_cachid(asp->cache_store, |
2421 | 0 | tp->global_cacheid))) { |
2422 | 0 | } else { |
2423 | 0 | cacheid = ++(asp->treecache_num); |
2424 | 0 | netsnmp_get_or_add_local_cachid(&asp->cache_store, |
2425 | 0 | tp->global_cacheid, |
2426 | 0 | cacheid); |
2427 | 0 | goto mallocslot; /* XXX: ick */ |
2428 | 0 | } |
2429 | 507 | } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num && |
2430 | 152 | asp->treecache[tp->cacheid].subtree == tp) { |
2431 | | /* |
2432 | | * we have already added a request to this tree |
2433 | | * pointer before |
2434 | | */ |
2435 | 67 | cacheid = tp->cacheid; |
2436 | 440 | } else { |
2437 | 440 | cacheid = ++(asp->treecache_num); |
2438 | 440 | mallocslot: |
2439 | | /* |
2440 | | * new slot needed |
2441 | | */ |
2442 | 440 | if (asp->treecache_num >= asp->treecache_len) { |
2443 | | /* |
2444 | | * expand cache array |
2445 | | */ |
2446 | | /* |
2447 | | * WWW: non-linear expansion needed (with cap) |
2448 | | */ |
2449 | 0 | #define CACHE_GROW_SIZE 16 |
2450 | 0 | asp->treecache_len = |
2451 | 0 | (asp->treecache_len + CACHE_GROW_SIZE); |
2452 | 0 | asp->treecache = |
2453 | 0 | (netsnmp_tree_cache *)realloc(asp->treecache, |
2454 | 0 | sizeof(netsnmp_tree_cache) * |
2455 | 0 | asp->treecache_len); |
2456 | 0 | if (asp->treecache == NULL) |
2457 | 0 | return NULL; |
2458 | 0 | memset(asp->treecache + cacheid, 0, |
2459 | 0 | sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE)); |
2460 | 0 | } |
2461 | 440 | asp->treecache[cacheid].subtree = tp; |
2462 | 440 | asp->treecache[cacheid].requests_begin = request; |
2463 | 440 | tp->cacheid = cacheid; |
2464 | 440 | } |
2465 | | |
2466 | | /* |
2467 | | * if this is a search type, get the ending range oid as well |
2468 | | */ |
2469 | 507 | if (asp->pdu->command == SNMP_MSG_GETNEXT || |
2470 | 507 | asp->pdu->command == SNMP_MSG_GETBULK) { |
2471 | 0 | request->range_end = tp->end_a; |
2472 | 0 | request->range_end_len = tp->end_len; |
2473 | 507 | } else { |
2474 | 507 | request->range_end = NULL; |
2475 | 507 | request->range_end_len = 0; |
2476 | 507 | } |
2477 | | |
2478 | | /* |
2479 | | * link into chain |
2480 | | */ |
2481 | 507 | if (asp->treecache[cacheid].requests_end) |
2482 | 67 | asp->treecache[cacheid].requests_end->next = request; |
2483 | 507 | request->next = NULL; |
2484 | 507 | request->prev = asp->treecache[cacheid].requests_end; |
2485 | 507 | asp->treecache[cacheid].requests_end = request; |
2486 | | |
2487 | | /* |
2488 | | * add the given request to the list of requests they need |
2489 | | * to handle results for |
2490 | | */ |
2491 | 507 | request->requestvb = request->requestvb_start = varbind_ptr; |
2492 | 507 | } |
2493 | 1.01k | return request; |
2494 | 1.01k | } |
2495 | | |
2496 | | /* |
2497 | | * check the ACM(s) for the results on each of the varbinds. |
2498 | | * If ACM disallows it, replace the value with type |
2499 | | * |
2500 | | * Returns number of varbinds with ACM errors |
2501 | | */ |
2502 | | int |
2503 | | check_acm(netsnmp_agent_session *asp, u_char type) |
2504 | 1.25k | { |
2505 | 1.25k | int view; |
2506 | 1.25k | int i, j, k; |
2507 | 1.25k | netsnmp_request_info *request; |
2508 | 1.25k | int ret = 0; |
2509 | 1.25k | netsnmp_variable_list *vb, *vb2, *vbc; |
2510 | 1.25k | int earliest = 0; |
2511 | | |
2512 | 1.63k | for (i = 0; i <= asp->treecache_num; i++) { |
2513 | 375 | for (request = asp->treecache[i].requests_begin; |
2514 | 811 | request; request = request->next) { |
2515 | | /* |
2516 | | * for each request, run it through in_a_view() |
2517 | | */ |
2518 | 436 | earliest = 0; |
2519 | 436 | for(j = request->repeat, vb = request->requestvb_start; |
2520 | 872 | vb && j > -1; |
2521 | 436 | j--, vb = vb->next_variable) { |
2522 | 436 | if (vb->type != ASN_NULL && |
2523 | 185 | vb->type != ASN_PRIV_RETRY) { /* not yet processed */ |
2524 | 185 | view = |
2525 | 185 | in_a_view(vb->name, &vb->name_length, |
2526 | 185 | asp->pdu, vb->type); |
2527 | | |
2528 | | /* |
2529 | | * if a ACM error occurs, mark it as type passed in |
2530 | | */ |
2531 | 185 | if (view != VACM_SUCCESS) { |
2532 | 0 | ret++; |
2533 | 0 | if (request->repeat < request->orig_repeat) { |
2534 | | /* basically this means a GETBULK */ |
2535 | 0 | request->repeat++; |
2536 | 0 | if (!earliest) { |
2537 | 0 | request->requestvb = vb; |
2538 | 0 | earliest = 1; |
2539 | 0 | } |
2540 | | |
2541 | | /* ugh. if a whole now exists, we need to |
2542 | | move the contents up the chain and fill |
2543 | | in at the end else we won't end up |
2544 | | lexographically sorted properly */ |
2545 | 0 | if (j > -1 && vb->next_variable && |
2546 | 0 | vb->next_variable->type != ASN_NULL && |
2547 | 0 | vb->next_variable->type != ASN_PRIV_RETRY) { |
2548 | 0 | for(k = j, vbc = vb, vb2 = vb->next_variable; |
2549 | 0 | k > -2 && vbc && vb2; |
2550 | 0 | k--, vbc = vb2, vb2 = vb2->next_variable) { |
2551 | | /* clone next into the current */ |
2552 | 0 | snmp_clone_var(vb2, vbc); |
2553 | 0 | vbc->next_variable = vb2; |
2554 | 0 | } |
2555 | 0 | } |
2556 | 0 | } |
2557 | 0 | snmp_set_var_typed_value(vb, type, NULL, 0); |
2558 | 0 | if (ASN_PRIV_RETRY == type) |
2559 | 0 | request->inclusive = 0; |
2560 | 0 | } |
2561 | 185 | } |
2562 | 436 | } |
2563 | 436 | } |
2564 | 375 | } |
2565 | 1.25k | return ret; |
2566 | 1.25k | } |
2567 | | |
2568 | | |
2569 | | int |
2570 | | netsnmp_create_subtree_cache(netsnmp_agent_session *asp) |
2571 | 12.0k | { |
2572 | 12.0k | netsnmp_subtree *tp; |
2573 | 12.0k | netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext; |
2574 | 12.0k | int view; |
2575 | 12.0k | int vbcount = 0; |
2576 | 12.0k | int bulkcount = 0, bulkrep = 0; |
2577 | 12.0k | int i = 0, n = 0, r = 0; |
2578 | 12.0k | netsnmp_request_info *request; |
2579 | | |
2580 | 12.0k | if (NULL == asp || NULL == asp->pdu) |
2581 | 0 | return SNMP_ERR_GENERR; |
2582 | | |
2583 | 12.0k | if (asp->pdu->msgMaxSize == 0) |
2584 | 12.0k | asp->pdu->msgMaxSize = netsnmp_max_send_msg_size(); |
2585 | 12.0k | DEBUGMSGTL(("msgMaxSize", "pdu max size %lu\n", asp->pdu->msgMaxSize)); |
2586 | | |
2587 | 12.0k | if (asp->treecache == NULL && asp->treecache_len == 0) { |
2588 | 12.0k | asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16); |
2589 | 12.0k | asp->treecache = calloc(asp->treecache_len, sizeof(netsnmp_tree_cache)); |
2590 | 12.0k | if (asp->treecache == NULL) |
2591 | 0 | return SNMP_ERR_GENERR; |
2592 | 12.0k | } |
2593 | 12.0k | asp->treecache_num = -1; |
2594 | | |
2595 | 12.0k | if (asp->pdu->command == SNMP_MSG_GETBULK) { |
2596 | | /* |
2597 | | * getbulk prep |
2598 | | */ |
2599 | 622 | int count = count_varbinds(asp->pdu->variables); |
2600 | 622 | if (asp->pdu->errstat < 0) { |
2601 | 302 | asp->pdu->errstat = 0; |
2602 | 302 | } |
2603 | 622 | if (asp->pdu->errindex < 0) { |
2604 | 111 | asp->pdu->errindex = 0; |
2605 | 111 | } |
2606 | | |
2607 | 622 | if (asp->pdu->errstat < count) { |
2608 | 154 | n = asp->pdu->errstat; |
2609 | 468 | } else { |
2610 | 468 | n = count; |
2611 | 468 | } |
2612 | 622 | if ((r = count - n) <= 0) { |
2613 | 468 | r = 0; |
2614 | 468 | asp->bulkcache = NULL; |
2615 | 468 | } else { |
2616 | 154 | int maxbulk = |
2617 | 154 | netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
2618 | 154 | NETSNMP_DS_AGENT_MAX_GETBULKREPEATS); |
2619 | 154 | int maxresponses = |
2620 | 154 | netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
2621 | 154 | NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES); |
2622 | 154 | int avgvarbind = |
2623 | 154 | netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
2624 | 154 | NETSNMP_DS_AGENT_AVG_BULKVARBINDSIZE); |
2625 | | |
2626 | 154 | if (maxresponses == 0) |
2627 | 154 | maxresponses = 100; /* more than reasonable default */ |
2628 | | |
2629 | | /* ensure that the total number of responses fits in a mallocable |
2630 | | * result vector |
2631 | | */ |
2632 | 154 | if (maxresponses < 0 || |
2633 | 154 | maxresponses > (int)(INT_MAX / sizeof(struct varbind_list *))) |
2634 | 0 | maxresponses = (int)(INT_MAX / sizeof(struct varbind_list *)); |
2635 | 154 | DEBUGMSGTL(("snmp_agent:bulk", "maxresponse %d\n", maxresponses)); |
2636 | | |
2637 | | /* reduce maxresponses by dividing the sessions max size by a |
2638 | | * (very) rough approximation of the size of an average |
2639 | | * varbind. 15 seems to be a reasonable balance between getting |
2640 | | * enough varbinds to fill the packet vs retrieving varbinds |
2641 | | * that will be discarded to make the response fit the packet size. |
2642 | | */ |
2643 | 154 | if (avgvarbind <= 0) |
2644 | 154 | avgvarbind = 15; |
2645 | | |
2646 | 154 | if (maxresponses > (asp->pdu->msgMaxSize / avgvarbind)) { |
2647 | 0 | maxresponses = asp->pdu->msgMaxSize / avgvarbind; |
2648 | 0 | DEBUGMSGTL(("snmp_agent:bulk", |
2649 | 0 | "lowering maxresponse to %d based pdusession msgMaxSize %ld and avgBulkVarbindSize %d\n", |
2650 | 0 | maxresponses, asp->pdu->msgMaxSize, avgvarbind)); |
2651 | 0 | } |
2652 | | |
2653 | | /* ensure that the maximum number of repetitions will fit in the |
2654 | | * result vector |
2655 | | */ |
2656 | 154 | if (maxbulk <= 0 || maxbulk > maxresponses / r) |
2657 | 154 | maxbulk = maxresponses / r; |
2658 | | |
2659 | | /* limit getbulk number of repeats to a configured size */ |
2660 | 154 | if (asp->pdu->errindex > maxbulk) { |
2661 | 68 | asp->pdu->errindex = maxbulk; |
2662 | 68 | DEBUGMSGTL(("snmp_agent:bulk", |
2663 | 68 | "lowering requested getbulk repeats to %ld\n", |
2664 | 68 | asp->pdu->errindex)); |
2665 | 68 | } |
2666 | | |
2667 | 154 | asp->bulkcache = |
2668 | 154 | (netsnmp_variable_list **) malloc( |
2669 | 154 | (n + asp->pdu->errindex * r) * sizeof(struct varbind_list *)); |
2670 | | |
2671 | 154 | if (!asp->bulkcache) { |
2672 | 0 | DEBUGMSGTL(("snmp_agent:bulk", "Bulkcache malloc failed\n")); |
2673 | 0 | return SNMP_ERR_GENERR; |
2674 | 0 | } |
2675 | 154 | } |
2676 | 622 | DEBUGMSGTL(("snmp_agent:bulk", "GETBULK N = %d, M = %ld, R = %d\n", |
2677 | 622 | n, asp->pdu->errindex, r)); |
2678 | 622 | } |
2679 | | |
2680 | | /* |
2681 | | * collect varbinds into their registered trees |
2682 | | */ |
2683 | 12.0k | prevNext = &(asp->pdu->variables); |
2684 | 13.1k | for (varbind_ptr = asp->pdu->variables; varbind_ptr; |
2685 | 12.0k | varbind_ptr = vbsave) { |
2686 | | |
2687 | | /* |
2688 | | * getbulk mess with this pointer, so save it |
2689 | | */ |
2690 | 1.04k | vbsave = varbind_ptr->next_variable; |
2691 | | |
2692 | 1.04k | if (asp->pdu->command == SNMP_MSG_GETBULK) { |
2693 | 450 | if (n > 0) { |
2694 | 169 | n--; |
2695 | 281 | } else { |
2696 | | /* |
2697 | | * repeat request varbinds on GETBULK. These will |
2698 | | * have to be properly rearranged later though as |
2699 | | * responses are supposed to actually be interlaced |
2700 | | * with each other. This is done with the asp->bulkcache. |
2701 | | */ |
2702 | 281 | bulkrep = asp->pdu->errindex - 1; |
2703 | 281 | if (asp->pdu->errindex > 0) { |
2704 | 248 | vbptr = varbind_ptr; |
2705 | 248 | asp->bulkcache[bulkcount++] = vbptr; |
2706 | | |
2707 | 8.99k | for (i = 1; i < asp->pdu->errindex; i++) { |
2708 | 8.74k | vbptr->next_variable = |
2709 | 8.74k | SNMP_MALLOC_STRUCT(variable_list); |
2710 | | /* |
2711 | | * don't clone the oid as it's got to be |
2712 | | * overwritten anyway |
2713 | | */ |
2714 | 8.74k | if (!vbptr->next_variable) { |
2715 | | /* |
2716 | | * XXXWWW: ack!!! |
2717 | | */ |
2718 | 0 | DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n")); |
2719 | 8.74k | } else { |
2720 | 8.74k | vbptr = vbptr->next_variable; |
2721 | 8.74k | vbptr->name_length = 0; |
2722 | 8.74k | vbptr->type = ASN_NULL; |
2723 | 8.74k | asp->bulkcache[bulkcount++] = vbptr; |
2724 | 8.74k | } |
2725 | 8.74k | } |
2726 | 248 | vbptr->next_variable = vbsave; |
2727 | 248 | } else { |
2728 | | /* |
2729 | | * 0 repeats requested for this varbind, so take it off |
2730 | | * the list. |
2731 | | */ |
2732 | 33 | vbptr = varbind_ptr; |
2733 | 33 | *prevNext = vbptr->next_variable; |
2734 | 33 | vbptr->next_variable = NULL; |
2735 | 33 | snmp_free_varbind(vbptr); |
2736 | 33 | asp->vbcount--; |
2737 | 33 | continue; |
2738 | 33 | } |
2739 | 281 | } |
2740 | 450 | } |
2741 | | |
2742 | | /* |
2743 | | * count the varbinds |
2744 | | */ |
2745 | 1.01k | ++vbcount; |
2746 | | |
2747 | | /* |
2748 | | * find the owning tree |
2749 | | */ |
2750 | 1.01k | tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length, |
2751 | 1.01k | NULL, asp->pdu->contextName); |
2752 | | |
2753 | | /* |
2754 | | * check access control |
2755 | | */ |
2756 | 1.01k | switch (asp->pdu->command) { |
2757 | 251 | case SNMP_MSG_GET: |
2758 | 251 | view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, |
2759 | 251 | asp->pdu, varbind_ptr->type); |
2760 | 251 | if (view != VACM_SUCCESS) |
2761 | 0 | snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT, |
2762 | 0 | NULL, 0); |
2763 | 251 | break; |
2764 | | |
2765 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
2766 | 185 | case SNMP_MSG_SET: |
2767 | 185 | view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, |
2768 | 185 | asp->pdu, varbind_ptr->type); |
2769 | 185 | if (view != VACM_SUCCESS) { |
2770 | 0 | asp->index = vbcount; |
2771 | 0 | return SNMP_ERR_NOACCESS; |
2772 | 0 | } |
2773 | 185 | break; |
2774 | 185 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
2775 | | |
2776 | 185 | case SNMP_MSG_GETNEXT: |
2777 | 507 | case SNMP_MSG_GETBULK: |
2778 | 578 | default: |
2779 | 578 | view = VACM_SUCCESS; |
2780 | | /* |
2781 | | * XXXWWW: check VACM here to see if "tp" is even worthwhile |
2782 | | */ |
2783 | 1.01k | } |
2784 | 1.01k | if (view == VACM_SUCCESS) { |
2785 | 1.01k | request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr, |
2786 | 1.01k | tp); |
2787 | 1.01k | if (request && asp->pdu->command == SNMP_MSG_GETBULK) { |
2788 | 0 | request->repeat = request->orig_repeat = bulkrep; |
2789 | 0 | } |
2790 | 1.01k | } |
2791 | | |
2792 | 1.01k | prevNext = &(varbind_ptr->next_variable); |
2793 | 1.01k | } |
2794 | | |
2795 | 12.0k | return SNMPERR_SUCCESS; |
2796 | 12.0k | } |
2797 | | |
2798 | | /* |
2799 | | * this function is only applicable in getnext like contexts |
2800 | | */ |
2801 | | int |
2802 | | netsnmp_reassign_requests(netsnmp_agent_session *asp) |
2803 | 0 | { |
2804 | | /* |
2805 | | * assume all the requests have been filled or rejected by the |
2806 | | * subtrees, so reassign the rejected ones to the next subtree in |
2807 | | * the chain |
2808 | | */ |
2809 | |
|
2810 | 0 | int i; |
2811 | | |
2812 | | /* |
2813 | | * get old info |
2814 | | */ |
2815 | 0 | netsnmp_tree_cache *old_treecache = asp->treecache; |
2816 | | |
2817 | | /* |
2818 | | * malloc new space |
2819 | | */ |
2820 | 0 | asp->treecache = calloc(asp->treecache_len, sizeof(netsnmp_tree_cache)); |
2821 | |
|
2822 | 0 | if (asp->treecache == NULL) |
2823 | 0 | return SNMP_ERR_GENERR; |
2824 | | |
2825 | 0 | asp->treecache_num = -1; |
2826 | 0 | if (asp->cache_store) { |
2827 | 0 | netsnmp_free_cachemap(asp->cache_store); |
2828 | 0 | asp->cache_store = NULL; |
2829 | 0 | } |
2830 | |
|
2831 | 0 | for (i = 0; i < asp->vbcount; i++) { |
2832 | 0 | if (asp->requests[i].requestvb == NULL) { |
2833 | | /* |
2834 | | * Occurs when there's a mixture of still active |
2835 | | * and "endOfMibView" repetitions |
2836 | | */ |
2837 | 0 | continue; |
2838 | 0 | } |
2839 | 0 | if (asp->requests[i].requestvb->type == ASN_NULL) { |
2840 | 0 | if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index, |
2841 | 0 | asp->requests[i].requestvb, |
2842 | 0 | asp->requests[i].subtree->next)) { |
2843 | 0 | SNMP_FREE(old_treecache); |
2844 | 0 | } |
2845 | 0 | } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) { |
2846 | | /* |
2847 | | * re-add the same subtree |
2848 | | */ |
2849 | 0 | asp->requests[i].requestvb->type = ASN_NULL; |
2850 | 0 | if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index, |
2851 | 0 | asp->requests[i].requestvb, |
2852 | 0 | asp->requests[i].subtree)) { |
2853 | 0 | SNMP_FREE(old_treecache); |
2854 | 0 | } |
2855 | 0 | } |
2856 | 0 | } |
2857 | |
|
2858 | 0 | SNMP_FREE(old_treecache); |
2859 | 0 | return SNMP_ERR_NOERROR; |
2860 | 0 | } |
2861 | | |
2862 | | void |
2863 | | netsnmp_delete_request_infos(netsnmp_request_info *reqlist) |
2864 | 0 | { |
2865 | 0 | while (reqlist) { |
2866 | 0 | netsnmp_free_request_data_sets(reqlist); |
2867 | 0 | reqlist = reqlist->next; |
2868 | 0 | } |
2869 | 0 | } |
2870 | | |
2871 | | #ifndef NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE |
2872 | | void |
2873 | | netsnmp_delete_subtree_cache(netsnmp_agent_session *asp) |
2874 | 0 | { |
2875 | 0 | while (asp->treecache_num >= 0) { |
2876 | | /* |
2877 | | * don't delete subtrees |
2878 | | */ |
2879 | 0 | netsnmp_delete_request_infos(asp->treecache[asp->treecache_num]. |
2880 | 0 | requests_begin); |
2881 | 0 | asp->treecache_num--; |
2882 | 0 | } |
2883 | 0 | } |
2884 | | #endif /* NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE */ |
2885 | | |
2886 | | #ifndef NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR |
2887 | | /* |
2888 | | * check all requests for errors |
2889 | | * |
2890 | | * @Note: |
2891 | | * This function is a little different from the others in that |
2892 | | * it does not use any linked lists, instead using the original |
2893 | | * asp requests array. This is of particular importance for |
2894 | | * cases where the linked lists are unreliable. One known instance |
2895 | | * of this scenario occurs when the row_merge helper is used, which |
2896 | | * may temporarily disrupts linked lists during its (and its children's) |
2897 | | * handling of requests. |
2898 | | */ |
2899 | | int |
2900 | | netsnmp_check_all_requests_error(netsnmp_agent_session *asp, |
2901 | | int look_for_specific) |
2902 | 0 | { |
2903 | 0 | int i; |
2904 | | |
2905 | | /* |
2906 | | * find any errors marked in the requests |
2907 | | */ |
2908 | 0 | for( i = 0; i < asp->vbcount; ++i ) { |
2909 | 0 | if ((SNMP_ERR_NOERROR != asp->requests[i].status) && |
2910 | 0 | (!look_for_specific || |
2911 | 0 | asp->requests[i].status == look_for_specific)) |
2912 | 0 | return asp->requests[i].status; |
2913 | 0 | } |
2914 | | |
2915 | 0 | return SNMP_ERR_NOERROR; |
2916 | 0 | } |
2917 | | #endif /* NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR */ |
2918 | | |
2919 | | #ifndef NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR |
2920 | | int |
2921 | | netsnmp_check_requests_error(netsnmp_request_info *requests) |
2922 | 0 | { |
2923 | | /* |
2924 | | * find any errors marked in the requests |
2925 | | */ |
2926 | 0 | for (;requests;requests = requests->next) { |
2927 | 0 | if (requests->status != SNMP_ERR_NOERROR) |
2928 | 0 | return requests->status; |
2929 | 0 | } |
2930 | 0 | return SNMP_ERR_NOERROR; |
2931 | 0 | } |
2932 | | #endif /* NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR */ |
2933 | | |
2934 | | int |
2935 | | netsnmp_check_requests_status(netsnmp_agent_session *asp, |
2936 | | netsnmp_request_info *requests, |
2937 | | int look_for_specific) |
2938 | 537 | { |
2939 | | /* |
2940 | | * find any errors marked in the requests |
2941 | | */ |
2942 | 1.15k | while (requests) { |
2943 | 621 | if(requests->agent_req_info != asp->reqinfo) { |
2944 | 0 | DEBUGMSGTL(("verbose:asp", |
2945 | 0 | "**reqinfo %p doesn't match cached reqinfo %p\n", |
2946 | 0 | asp->reqinfo, requests->agent_req_info)); |
2947 | 0 | } |
2948 | 621 | if (requests->status != SNMP_ERR_NOERROR && |
2949 | 370 | (!look_for_specific || requests->status == look_for_specific) |
2950 | 370 | && (look_for_specific || asp->index == 0 |
2951 | 260 | || requests->index <= asp->index)) { |
2952 | 260 | asp->index = requests->index; |
2953 | 260 | asp->status = requests->status; |
2954 | 260 | } |
2955 | 621 | requests = requests->next; |
2956 | 621 | } |
2957 | 537 | return asp->status; |
2958 | 537 | } |
2959 | | |
2960 | | int |
2961 | | netsnmp_check_all_requests_status(netsnmp_agent_session *asp, |
2962 | | int look_for_specific) |
2963 | 0 | { |
2964 | 0 | int i; |
2965 | 0 | for (i = 0; i <= asp->treecache_num; i++) { |
2966 | 0 | netsnmp_check_requests_status(asp, |
2967 | 0 | asp->treecache[i].requests_begin, |
2968 | 0 | look_for_specific); |
2969 | 0 | } |
2970 | 0 | return asp->status; |
2971 | 0 | } |
2972 | | |
2973 | | int |
2974 | | handle_var_requests(netsnmp_agent_session *asp) |
2975 | 11.4k | { |
2976 | 11.4k | int i, retstatus = SNMP_ERR_NOERROR, |
2977 | 11.4k | status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR; |
2978 | 11.4k | netsnmp_handler_registration *reginfo; |
2979 | | |
2980 | 11.4k | asp->reqinfo->asp = asp; |
2981 | 11.4k | asp->reqinfo->mode = asp->mode; |
2982 | | |
2983 | | /* |
2984 | | * now, have the subtrees in the cache go search for their results |
2985 | | */ |
2986 | 12.0k | for (i = 0; i <= asp->treecache_num; i++) { |
2987 | | /* |
2988 | | * don't call handlers w/null reginfo. |
2989 | | * - when is this? sub agent disconnected while request processing? |
2990 | | * - should this case encompass more of this subroutine? |
2991 | | * - does check_request_status make send if handlers weren't called? |
2992 | | */ |
2993 | 537 | if(NULL != asp->treecache[i].subtree->reginfo) { |
2994 | 537 | reginfo = asp->treecache[i].subtree->reginfo; |
2995 | 537 | status = netsnmp_call_handlers(reginfo, asp->reqinfo, |
2996 | 537 | asp->treecache[i].requests_begin); |
2997 | 537 | } |
2998 | 0 | else |
2999 | 0 | status = SNMP_ERR_GENERR; |
3000 | | |
3001 | | /* |
3002 | | * find any errors marked in the requests. For later parts of |
3003 | | * SET processing, only check for new errors specific to that |
3004 | | * set processing directive (which must supersede the previous |
3005 | | * errors). |
3006 | | */ |
3007 | 537 | switch (asp->mode) { |
3008 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3009 | 0 | case MODE_SET_COMMIT: |
3010 | 0 | retstatus = netsnmp_check_requests_status(asp, |
3011 | 0 | asp->treecache[i]. |
3012 | 0 | requests_begin, |
3013 | 0 | SNMP_ERR_COMMITFAILED); |
3014 | 0 | break; |
3015 | | |
3016 | 0 | case MODE_SET_UNDO: |
3017 | 0 | retstatus = netsnmp_check_requests_status(asp, |
3018 | 0 | asp->treecache[i]. |
3019 | 0 | requests_begin, |
3020 | 0 | SNMP_ERR_UNDOFAILED); |
3021 | 0 | break; |
3022 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3023 | | |
3024 | 537 | default: |
3025 | 537 | retstatus = netsnmp_check_requests_status(asp, |
3026 | 537 | asp->treecache[i]. |
3027 | 537 | requests_begin, 0); |
3028 | 537 | break; |
3029 | 537 | } |
3030 | | |
3031 | | /* |
3032 | | * always take lowest varbind if possible |
3033 | | */ |
3034 | 537 | if (retstatus != SNMP_ERR_NOERROR) { |
3035 | 324 | status = retstatus; |
3036 | 324 | } |
3037 | | |
3038 | | /* |
3039 | | * other things we know less about (no index) |
3040 | | */ |
3041 | | /* |
3042 | | * WWW: drop support for this? |
3043 | | */ |
3044 | 537 | if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) { |
3045 | | /* |
3046 | | * we can't break here, since some processing needs to be |
3047 | | * done for all requests anyway (IE, SET handling for UNDO |
3048 | | * needs to be called regardless of previous status |
3049 | | * results. |
3050 | | * WWW: This should be predictable though and |
3051 | | * breaking should be possible in some cases (eg GET, |
3052 | | * GETNEXT, ...) |
3053 | | */ |
3054 | 260 | final_status = status; |
3055 | 260 | } |
3056 | 537 | } |
3057 | | |
3058 | 11.4k | return final_status; |
3059 | 11.4k | } |
3060 | | |
3061 | | void |
3062 | | netsnmp_check_delegated_requests(void) |
3063 | 0 | { |
3064 | 0 | netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL; |
3065 | |
|
3066 | 0 | for (asp = agent_delegated_list; asp; asp = next_asp) { |
3067 | 0 | next_asp = asp->next; /* save in case we clean up asp */ |
3068 | 0 | if (!netsnmp_check_for_delegated(asp)) { |
3069 | 0 | netsnmp_agent_session *old_head; |
3070 | | |
3071 | | /* |
3072 | | * we're done with this one, remove from queue |
3073 | | */ |
3074 | 0 | if (prev_asp != NULL) |
3075 | 0 | prev_asp->next = asp->next; |
3076 | 0 | else |
3077 | 0 | agent_delegated_list = asp->next; |
3078 | 0 | asp->next = NULL; |
3079 | | |
3080 | | /* |
3081 | | * check request status |
3082 | | */ |
3083 | 0 | netsnmp_check_all_requests_status(asp, 0); |
3084 | | |
3085 | 0 | old_head = agent_delegated_list; |
3086 | | |
3087 | | /* |
3088 | | * continue processing or finish up |
3089 | | */ |
3090 | 0 | check_delayed_request(asp); |
3091 | | |
3092 | | /* |
3093 | | * if head was removed, don't drop it if it |
3094 | | * was it re-queued |
3095 | | */ |
3096 | 0 | if ((prev_asp == NULL) && (agent_delegated_list != old_head)) { |
3097 | 0 | prev_asp = agent_delegated_list; |
3098 | 0 | } |
3099 | 0 | } else { |
3100 | | |
3101 | | /* |
3102 | | * asp is still on the queue |
3103 | | */ |
3104 | 0 | prev_asp = asp; |
3105 | 0 | } |
3106 | 0 | } |
3107 | 0 | } |
3108 | | |
3109 | | /* |
3110 | | * loop through our sessions known delegated sessions and check to see |
3111 | | * if they've completed yet. If there are no more delegated sessions, |
3112 | | * check for and process any queued requests |
3113 | | */ |
3114 | | void |
3115 | | netsnmp_check_outstanding_agent_requests(void) |
3116 | 0 | { |
3117 | 0 | netsnmp_agent_session *asp; |
3118 | | |
3119 | | /* |
3120 | | * deal with delegated requests |
3121 | | */ |
3122 | 0 | netsnmp_check_delegated_requests(); |
3123 | | |
3124 | | /* |
3125 | | * if we are processing a set and there are more delegated |
3126 | | * requests, keep waiting before getting to queued requests. |
3127 | | */ |
3128 | 0 | if (netsnmp_processing_set && (NULL != agent_delegated_list)) |
3129 | 0 | return; |
3130 | | |
3131 | 0 | while (netsnmp_agent_queued_list) { |
3132 | | |
3133 | | /* |
3134 | | * if we are processing a set, the first item better be |
3135 | | * the set being (or waiting to be) processed. |
3136 | | */ |
3137 | 0 | netsnmp_assert((!netsnmp_processing_set) || |
3138 | 0 | (netsnmp_processing_set == netsnmp_agent_queued_list)); |
3139 | | |
3140 | | /* |
3141 | | * if the top request is a set, don't pop it |
3142 | | * off if there are delegated requests |
3143 | | */ |
3144 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3145 | 0 | if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) && |
3146 | 0 | (agent_delegated_list)) { |
3147 | |
|
3148 | 0 | netsnmp_assert(netsnmp_processing_set == NULL); |
3149 | |
|
3150 | 0 | netsnmp_processing_set = netsnmp_agent_queued_list; |
3151 | 0 | DEBUGMSGTL(("snmp_agent", "SET request remains queued while " |
3152 | 0 | "delegated requests finish, asp = %8p\n", |
3153 | 0 | agent_delegated_list)); |
3154 | 0 | break; |
3155 | 0 | } |
3156 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3157 | | |
3158 | | /* |
3159 | | * pop the first request and process it |
3160 | | */ |
3161 | 0 | asp = netsnmp_agent_queued_list; |
3162 | 0 | netsnmp_agent_queued_list = asp->next; |
3163 | 0 | DEBUGMSGTL(("snmp_agent", |
3164 | 0 | "processing queued request, asp = %8p\n", asp)); |
3165 | |
|
3166 | 0 | netsnmp_handle_request(asp, asp->status); |
3167 | | |
3168 | | /* |
3169 | | * if we hit a set, stop |
3170 | | */ |
3171 | 0 | if (NULL != netsnmp_processing_set) |
3172 | 0 | break; |
3173 | 0 | } |
3174 | 0 | } |
3175 | | |
3176 | | /** Decide if the requested transaction_id is still being processed |
3177 | | within the agent. This is used to validate whether a delayed cache |
3178 | | (containing possibly freed pointers) is still usable. |
3179 | | |
3180 | | returns SNMPERR_SUCCESS if it's still valid, or SNMPERR_GENERR if not. */ |
3181 | | int |
3182 | | netsnmp_check_transaction_id(int transaction_id) |
3183 | 0 | { |
3184 | 0 | netsnmp_agent_session *asp; |
3185 | |
|
3186 | 0 | for (asp = agent_delegated_list; asp; asp = asp->next) { |
3187 | 0 | if (asp->pdu->transid == transaction_id) |
3188 | 0 | return SNMPERR_SUCCESS; |
3189 | 0 | } |
3190 | 0 | return SNMPERR_GENERR; |
3191 | 0 | } |
3192 | | |
3193 | | |
3194 | | /* |
3195 | | * check_delayed_request(asp) |
3196 | | * |
3197 | | * Called to reexamine a set of requests and continue processing them |
3198 | | * once all the previous (delayed) requests have been handled one way |
3199 | | * or another. |
3200 | | */ |
3201 | | |
3202 | | int |
3203 | | check_delayed_request(netsnmp_agent_session *asp) |
3204 | 0 | { |
3205 | 0 | int status = SNMP_ERR_NOERROR; |
3206 | |
|
3207 | 0 | DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %8p\n", |
3208 | 0 | asp)); |
3209 | |
|
3210 | 0 | switch (asp->mode) { |
3211 | 0 | case SNMP_MSG_GETBULK: |
3212 | 0 | case SNMP_MSG_GETNEXT: |
3213 | 0 | netsnmp_check_all_requests_status(asp, 0); |
3214 | 0 | if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) { |
3215 | 0 | DEBUGMSGTL(("snmp_agent","canceling next walk for asp %p\n", asp)); |
3216 | 0 | break; |
3217 | 0 | } |
3218 | 0 | handle_getnext_loop(asp); |
3219 | 0 | if (netsnmp_check_for_delegated(asp) && |
3220 | 0 | netsnmp_check_transaction_id(asp->pdu->transid) != |
3221 | 0 | SNMPERR_SUCCESS) { |
3222 | | /* |
3223 | | * add to delegated request chain |
3224 | | */ |
3225 | 0 | if (!netsnmp_check_delegated_chain_for(asp)) { |
3226 | 0 | asp->next = agent_delegated_list; |
3227 | 0 | agent_delegated_list = asp; |
3228 | 0 | } |
3229 | 0 | } |
3230 | 0 | break; |
3231 | | |
3232 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3233 | 0 | case MODE_SET_COMMIT: |
3234 | 0 | netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED); |
3235 | 0 | goto settop; |
3236 | | |
3237 | 0 | case MODE_SET_UNDO: |
3238 | 0 | netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED); |
3239 | 0 | goto settop; |
3240 | | |
3241 | 0 | case MODE_SET_BEGIN: |
3242 | 0 | case MODE_SET_RESERVE1: |
3243 | 0 | case MODE_SET_RESERVE2: |
3244 | 0 | case MODE_SET_ACTION: |
3245 | 0 | case MODE_SET_FREE: |
3246 | 0 | settop: |
3247 | | /* If we should do only one pass, this mean we */ |
3248 | | /* should not reenter this function */ |
3249 | 0 | if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { |
3250 | | /* We should have finished the processing after the first */ |
3251 | | /* handle_set_loop, so just wrap up */ |
3252 | 0 | break; |
3253 | 0 | } |
3254 | 0 | handle_set_loop(asp); |
3255 | 0 | if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { |
3256 | |
|
3257 | 0 | if (netsnmp_check_for_delegated_and_add(asp)) { |
3258 | | /* |
3259 | | * add to delegated request chain |
3260 | | */ |
3261 | 0 | if (!asp->status) |
3262 | 0 | asp->status = status; |
3263 | 0 | } |
3264 | |
|
3265 | 0 | return SNMP_ERR_NOERROR; |
3266 | 0 | } |
3267 | 0 | break; |
3268 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3269 | | |
3270 | 0 | default: |
3271 | 0 | break; |
3272 | 0 | } |
3273 | | |
3274 | | /* |
3275 | | * if we don't have anything outstanding (delegated), wrap up |
3276 | | */ |
3277 | 0 | if (!netsnmp_check_for_delegated(asp)) |
3278 | 0 | return netsnmp_wrap_up_request(asp, status); |
3279 | | |
3280 | 0 | return 1; |
3281 | 0 | } |
3282 | | |
3283 | | /** returns 1 if there are valid GETNEXT requests left. Returns 0 if not. */ |
3284 | | int |
3285 | | check_getnext_results(netsnmp_agent_session *asp) |
3286 | 731 | { |
3287 | | /* |
3288 | | * get old info |
3289 | | */ |
3290 | 731 | netsnmp_tree_cache *old_treecache = asp->treecache; |
3291 | 731 | int old_treecache_num = asp->treecache_num; |
3292 | 731 | int count = 0; |
3293 | 731 | int i, special = 0; |
3294 | 731 | netsnmp_request_info *request; |
3295 | | |
3296 | 731 | if (asp->mode == SNMP_MSG_GET) { |
3297 | | /* |
3298 | | * Special case for doing INCLUSIVE getNext operations in |
3299 | | * AgentX subagents. |
3300 | | */ |
3301 | 0 | DEBUGMSGTL(("snmp_agent", |
3302 | 0 | "asp->mode == SNMP_MSG_GET in ch_getnext\n")); |
3303 | 0 | asp->mode = asp->oldmode; |
3304 | 0 | special = 1; |
3305 | 0 | } |
3306 | | |
3307 | 731 | for (i = 0; i <= old_treecache_num; i++) { |
3308 | 0 | for (request = old_treecache[i].requests_begin; request; |
3309 | 0 | request = request->next) { |
3310 | | |
3311 | | /* |
3312 | | * If we have just done the special case AgentX GET, then any |
3313 | | * requests which were not INCLUSIVE will now have a wrong |
3314 | | * response, so junk them and retry from the same place (except |
3315 | | * that this time the handler will be called in "inexact" |
3316 | | * mode). |
3317 | | */ |
3318 | |
|
3319 | 0 | if (special) { |
3320 | 0 | if (!request->inclusive) { |
3321 | 0 | DEBUGMSGTL(("snmp_agent", |
3322 | 0 | "request %d wasn't inclusive\n", |
3323 | 0 | request->index)); |
3324 | 0 | snmp_set_var_typed_value(request->requestvb, |
3325 | 0 | ASN_PRIV_RETRY, NULL, 0); |
3326 | 0 | } else if (request->requestvb->type == ASN_NULL || |
3327 | 0 | request->requestvb->type == SNMP_NOSUCHINSTANCE || |
3328 | 0 | request->requestvb->type == SNMP_NOSUCHOBJECT) { |
3329 | | /* |
3330 | | * it was inclusive, but no results. Still retry this |
3331 | | * search. |
3332 | | */ |
3333 | 0 | snmp_set_var_typed_value(request->requestvb, |
3334 | 0 | ASN_PRIV_RETRY, NULL, 0); |
3335 | 0 | } |
3336 | 0 | } |
3337 | | |
3338 | | /* |
3339 | | * out of range? |
3340 | | */ |
3341 | 0 | if (snmp_oid_compare(request->requestvb->name, |
3342 | 0 | request->requestvb->name_length, |
3343 | 0 | request->range_end, |
3344 | 0 | request->range_end_len) >= 0) { |
3345 | | /* |
3346 | | * ack, it's beyond the accepted end of range. |
3347 | | */ |
3348 | | /* |
3349 | | * fix it by setting the oid to the end of range oid instead |
3350 | | */ |
3351 | 0 | DEBUGMSGTL(("check_getnext_results", |
3352 | 0 | "request response %d out of range\n", |
3353 | 0 | request->index)); |
3354 | | /* |
3355 | | * I'm not sure why inclusive is set unconditionally here (see |
3356 | | * comments for revision 1.161), but it causes a problem for |
3357 | | * GETBULK over an overridden variable. The bulk-to-next |
3358 | | * handler re-uses the same request for multiple varbinds, |
3359 | | * and once inclusive was set, it was never cleared. So, a |
3360 | | * hack. Instead of setting it to 1, set it to 2, so bulk-to |
3361 | | * next can clear it later. As of the time of this hack, all |
3362 | | * checks of this var are boolean checks (not == 1), so this |
3363 | | * should be safe. Cross your fingers. |
3364 | | */ |
3365 | 0 | request->inclusive = 2; |
3366 | | /* |
3367 | | * XXX: should set this to the original OID? |
3368 | | */ |
3369 | 0 | snmp_set_var_objid(request->requestvb, |
3370 | 0 | request->range_end, |
3371 | 0 | request->range_end_len); |
3372 | 0 | snmp_set_var_typed_value(request->requestvb, ASN_NULL, |
3373 | 0 | NULL, 0); |
3374 | 0 | } |
3375 | | |
3376 | | /* |
3377 | | * mark any existent requests with illegal results as NULL |
3378 | | */ |
3379 | 0 | if (request->requestvb->type == SNMP_ENDOFMIBVIEW) { |
3380 | | /* |
3381 | | * illegal response from a subagent. Change it back to NULL |
3382 | | * xxx-rks: err, how do we know this is a subagent? |
3383 | | */ |
3384 | 0 | request->requestvb->type = ASN_NULL; |
3385 | 0 | request->inclusive = 1; |
3386 | 0 | } |
3387 | |
|
3388 | 0 | if (request->requestvb->type == ASN_NULL || |
3389 | 0 | request->requestvb->type == ASN_PRIV_RETRY || |
3390 | 0 | (asp->reqinfo->mode == MODE_GETBULK |
3391 | 0 | && request->repeat > 0)) |
3392 | 0 | count++; |
3393 | 0 | } |
3394 | 0 | } |
3395 | 731 | return count; |
3396 | 731 | } |
3397 | | |
3398 | | /** repeatedly calls getnext handlers looking for an answer till all |
3399 | | requests are satisfied. It's expected that one pass has been made |
3400 | | before entering this function */ |
3401 | | int |
3402 | | handle_getnext_loop(netsnmp_agent_session *asp) |
3403 | 731 | { |
3404 | 731 | int status, rough_size, count = 0, total, val_len; |
3405 | 731 | netsnmp_variable_list *var_ptr, *last_var = NULL; |
3406 | | |
3407 | 731 | if (NULL == asp || NULL == asp->pdu) |
3408 | 0 | return SNMP_ERR_GENERR; |
3409 | | |
3410 | 731 | total = count_varbinds(asp->pdu->variables); |
3411 | | |
3412 | | /* |
3413 | | * loop |
3414 | | */ |
3415 | 731 | while (netsnmp_running) { |
3416 | | |
3417 | | /* |
3418 | | * bail for now if anything is delegated. |
3419 | | */ |
3420 | 731 | if (netsnmp_check_for_delegated(asp)) { |
3421 | 0 | return SNMP_ERR_NOERROR; |
3422 | 0 | } |
3423 | | |
3424 | | /* |
3425 | | * check vacm against results |
3426 | | */ |
3427 | 731 | check_acm(asp, ASN_PRIV_RETRY); |
3428 | | |
3429 | | /* |
3430 | | * need to keep going we're not done yet. |
3431 | | */ |
3432 | 731 | if (!check_getnext_results(asp)) |
3433 | | /* |
3434 | | * nothing left, quit now |
3435 | | */ |
3436 | 731 | break; |
3437 | | |
3438 | 0 | count = rough_size = 0; |
3439 | 0 | DEBUGMSGTL(("results:intermediate", |
3440 | 0 | "getnext results, before next pass:\n")); |
3441 | 0 | for (var_ptr = asp->pdu->variables; var_ptr; |
3442 | 0 | var_ptr = var_ptr->next_variable) { |
3443 | 0 | if ((var_ptr->type == ASN_NULL && 0 == var_ptr->name_length) || |
3444 | 0 | (var_ptr->type == ASN_PRIV_RETRY)) { |
3445 | 0 | continue; |
3446 | 0 | } |
3447 | 0 | ++count; |
3448 | 0 | DEBUGIF("results:intermediate") { |
3449 | 0 | DEBUGMSGTL(("results:intermediate", "\t")); |
3450 | 0 | DEBUGMSGVAR(("results:intermediate", var_ptr)); |
3451 | 0 | DEBUGMSG(("results:intermediate", "\n")); |
3452 | 0 | } |
3453 | | /* |
3454 | | * make a very rough guesstimate of the encoded varbind size by |
3455 | | * adding the name and val lengths. If these rough sizes add up |
3456 | | * to more than the msgMaxSize, stop gathering new varbinds. |
3457 | | * |
3458 | | * [Increasing the accuracy of this estimate would allow us to |
3459 | | * do better at filling packets and collecting fewer varbinds that |
3460 | | * we'll later have to trim. This is left as an exercise for the |
3461 | | * reader.] |
3462 | | */ |
3463 | 0 | rough_size += var_ptr->name_length; |
3464 | | /** sizeof(oid) is 8 on 64bit systems :-( Hardcode for 4 */ |
3465 | 0 | if (var_ptr->type == ASN_OBJECT_ID && sizeof(long) == 8) |
3466 | 0 | val_len = (var_ptr->val_len / 2); |
3467 | 0 | else |
3468 | 0 | val_len = var_ptr->val_len; |
3469 | |
|
3470 | 0 | DEBUGMSGTL(("results:intermediate", "\t+ %" NETSNMP_PRIz "d %d = %d\n", |
3471 | 0 | var_ptr->name_length, val_len, rough_size)); |
3472 | 0 | if (rough_size > asp->pdu->msgMaxSize) { |
3473 | 0 | DEBUGMSGTL(("results", |
3474 | 0 | "estimating packet too big; stop gathering\n")); |
3475 | 0 | asp->pdu->flags |= UCD_MSG_FLAG_BULK_TOOBIG | |
3476 | 0 | UCD_MSG_FLAG_FORWARD_ENCODE; |
3477 | 0 | var_ptr->type = ASN_PRIV_STOP; |
3478 | 0 | if (NULL != last_var) |
3479 | 0 | last_var->next_variable = NULL; |
3480 | 0 | break; |
3481 | 0 | } |
3482 | 0 | last_var = var_ptr; |
3483 | 0 | } |
3484 | 0 | if (rough_size > asp->pdu->msgMaxSize) |
3485 | 0 | break; |
3486 | | |
3487 | 0 | netsnmp_reassign_requests(asp); |
3488 | 0 | status = handle_var_requests(asp); |
3489 | 0 | if (status != SNMP_ERR_NOERROR) { |
3490 | 0 | return status; /* should never really happen */ |
3491 | 0 | } |
3492 | 0 | } |
3493 | 731 | DEBUGMSGTL(("results:summary", "gathered %d/%d varbinds\n", count, |
3494 | 731 | total)); |
3495 | 731 | if (!netsnmp_running) { |
3496 | 0 | return SNMP_ERR_GENERR; |
3497 | 0 | } |
3498 | 731 | return SNMP_ERR_NOERROR; |
3499 | 731 | } |
3500 | | |
3501 | | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3502 | | int |
3503 | | handle_set(netsnmp_agent_session *asp) |
3504 | 10.8k | { |
3505 | 10.8k | int status; |
3506 | | /* |
3507 | | * SETS require 3-4 passes through the var_op_list. |
3508 | | * The first two |
3509 | | * passes verify that all types, lengths, and values are valid |
3510 | | * and may reserve resources and the third does the set and a |
3511 | | * fourth executes any actions. Then the identical GET RESPONSE |
3512 | | * packet is returned. |
3513 | | * If either of the first two passes returns an error, another |
3514 | | * pass is made so that any reserved resources can be freed. |
3515 | | * If the third pass returns an error, another pass is |
3516 | | * made so that |
3517 | | * any changes can be reversed. |
3518 | | * If the fourth pass (or any of the error handling passes) |
3519 | | * return an error, we'd rather not know about it! |
3520 | | */ |
3521 | 10.8k | if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { |
3522 | 1.35k | switch (asp->mode) { |
3523 | 323 | case MODE_SET_BEGIN: |
3524 | 323 | snmp_increment_statistic(STAT_SNMPINSETREQUESTS); |
3525 | 323 | asp->rw = WRITE; /* WWW: still needed? */ |
3526 | 323 | asp->mode = MODE_SET_RESERVE1; |
3527 | 323 | asp->status = SNMP_ERR_NOERROR; |
3528 | 323 | break; |
3529 | | |
3530 | 323 | case MODE_SET_RESERVE1: |
3531 | | |
3532 | 323 | if (asp->status != SNMP_ERR_NOERROR) |
3533 | 130 | asp->mode = MODE_SET_FREE; |
3534 | 193 | else |
3535 | 193 | asp->mode = MODE_SET_RESERVE2; |
3536 | 323 | break; |
3537 | | |
3538 | 193 | case MODE_SET_RESERVE2: |
3539 | 193 | if (asp->status != SNMP_ERR_NOERROR) |
3540 | 0 | asp->mode = MODE_SET_FREE; |
3541 | 193 | else |
3542 | 193 | asp->mode = MODE_SET_ACTION; |
3543 | 193 | break; |
3544 | | |
3545 | 193 | case MODE_SET_ACTION: |
3546 | 193 | if (asp->status != SNMP_ERR_NOERROR) |
3547 | 0 | asp->mode = MODE_SET_UNDO; |
3548 | 193 | else |
3549 | 193 | asp->mode = MODE_SET_COMMIT; |
3550 | 193 | break; |
3551 | | |
3552 | 193 | case MODE_SET_COMMIT: |
3553 | 193 | if (asp->status != SNMP_ERR_NOERROR) { |
3554 | 0 | asp->mode = FINISHED_FAILURE; |
3555 | 193 | } else { |
3556 | 193 | asp->mode = FINISHED_SUCCESS; |
3557 | 193 | } |
3558 | 193 | break; |
3559 | | |
3560 | 0 | case MODE_SET_UNDO: |
3561 | 0 | asp->mode = FINISHED_FAILURE; |
3562 | 0 | break; |
3563 | | |
3564 | 130 | case MODE_SET_FREE: |
3565 | 130 | asp->mode = FINISHED_FAILURE; |
3566 | 130 | break; |
3567 | 1.35k | } |
3568 | 1.35k | } |
3569 | | |
3570 | 10.8k | if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { |
3571 | 10.5k | DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode, |
3572 | 10.5k | se_find_label_in_slist("agent_mode", asp->mode))); |
3573 | 10.5k | status = handle_var_requests(asp); |
3574 | 10.5k | DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n", |
3575 | 10.5k | asp->mode, status)); |
3576 | 10.5k | if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) || |
3577 | 10.5k | status == SNMP_ERR_COMMITFAILED || |
3578 | 10.5k | status == SNMP_ERR_UNDOFAILED) { |
3579 | 0 | asp->status = status; |
3580 | 0 | } |
3581 | 10.5k | } |
3582 | 10.8k | return asp->status; |
3583 | 10.8k | } |
3584 | | |
3585 | | int |
3586 | | handle_set_loop(netsnmp_agent_session *asp) |
3587 | 9.82k | { |
3588 | 11.1k | while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) { |
3589 | 10.8k | handle_set(asp); |
3590 | 10.8k | if (netsnmp_check_for_delegated(asp)) { |
3591 | 0 | return SNMP_ERR_NOERROR; |
3592 | 0 | } |
3593 | 10.8k | if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) { |
3594 | 9.50k | return asp->status; |
3595 | 9.50k | } |
3596 | 10.8k | } |
3597 | 323 | return asp->status; |
3598 | 9.82k | } |
3599 | | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3600 | | |
3601 | | int |
3602 | | netsnmp_handle_request(netsnmp_agent_session *asp, int status) |
3603 | 12.6k | { |
3604 | 12.6k | #ifndef NETSNMP_NO_PDU_STATS |
3605 | 12.6k | if (_pdu_stats_max > 0) { |
3606 | | /** tag new pdus with a start time */ |
3607 | 0 | marker_t start; |
3608 | 0 | start = (marker_t)netsnmp_agent_get_list_data(asp->reqinfo, |
3609 | 0 | "netsnmp_pdu_stats"); |
3610 | 0 | if (NULL == start) { |
3611 | 0 | netsnmp_data_list *data_list; |
3612 | 0 | DEBUGMSGTL(("stats:pdu:start", "starting pdu processing\n")); |
3613 | |
|
3614 | 0 | netsnmp_set_monotonic_marker(&start); /* will alloc space */ |
3615 | 0 | data_list = netsnmp_create_data_list("netsnmp_pdu_stats", start, |
3616 | 0 | free); |
3617 | 0 | if (NULL == data_list) { |
3618 | 0 | free(start); |
3619 | 0 | snmp_log(LOG_WARNING, "error creating data list for stats\n"); |
3620 | 0 | } else |
3621 | 0 | netsnmp_agent_add_list_data(asp->reqinfo, data_list); |
3622 | 0 | } |
3623 | 0 | } |
3624 | 12.6k | #endif /* NETSNMP_NO_PDU_STATS */ |
3625 | | |
3626 | | /* |
3627 | | * if this isn't a delegated request trying to finish, |
3628 | | * processing of a set request should not start until all |
3629 | | * delegated requests have completed, and no other new requests |
3630 | | * should be processed until the set request completes. |
3631 | | */ |
3632 | 12.6k | if ((0 == netsnmp_check_delegated_chain_for(asp)) && |
3633 | 12.6k | (asp != netsnmp_processing_set)) { |
3634 | | /* |
3635 | | * if we are processing a set and this is not a delegated |
3636 | | * request, queue the request |
3637 | | */ |
3638 | 12.6k | if (netsnmp_processing_set) { |
3639 | 0 | netsnmp_add_queued(asp); |
3640 | 0 | DEBUGMSGTL(("snmp_agent", |
3641 | 0 | "request queued while processing set, " |
3642 | 0 | "asp = %8p\n", asp)); |
3643 | 0 | return 1; |
3644 | 0 | } |
3645 | | |
3646 | | /* |
3647 | | * check for set request |
3648 | | */ |
3649 | 12.6k | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3650 | 12.6k | if (asp->pdu->command == SNMP_MSG_SET) { |
3651 | 333 | netsnmp_processing_set = asp; |
3652 | | |
3653 | | /* |
3654 | | * if there are delegated requests, we must wait for them |
3655 | | * to finish. |
3656 | | */ |
3657 | 333 | if (agent_delegated_list) { |
3658 | 0 | DEBUGMSGTL(("snmp_agent", "SET request queued while " |
3659 | 0 | "delegated requests finish, asp = %8p\n", |
3660 | 0 | asp)); |
3661 | 0 | netsnmp_add_queued(asp); |
3662 | 0 | return 1; |
3663 | 0 | } |
3664 | 333 | } |
3665 | 12.6k | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3666 | 12.6k | } |
3667 | | |
3668 | | /* |
3669 | | * process the request |
3670 | | */ |
3671 | 12.6k | status = handle_pdu(asp); |
3672 | | |
3673 | | /* |
3674 | | * print the results in appropriate debugging mode |
3675 | | */ |
3676 | 12.6k | DEBUGIF("results") { |
3677 | 0 | netsnmp_variable_list *var_ptr; |
3678 | 0 | DEBUGMSGTL(("results", "request results (status = %d):\n", |
3679 | 0 | status)); |
3680 | 0 | for (var_ptr = asp->pdu->variables; var_ptr; |
3681 | 0 | var_ptr = var_ptr->next_variable) { |
3682 | 0 | DEBUGMSGTL(("results", "\t")); |
3683 | 0 | DEBUGMSGVAR(("results", var_ptr)); |
3684 | 0 | DEBUGMSG(("results", "\n")); |
3685 | 0 | } |
3686 | 0 | } |
3687 | | |
3688 | | /* |
3689 | | * check for uncompleted requests |
3690 | | */ |
3691 | 12.6k | if (netsnmp_check_for_delegated_and_add(asp)) { |
3692 | | /* |
3693 | | * add to delegated request chain |
3694 | | */ |
3695 | 0 | asp->status = status; |
3696 | 12.6k | } else { |
3697 | | /* |
3698 | | * if we don't have anything outstanding (delegated), wrap up |
3699 | | */ |
3700 | 12.6k | return netsnmp_wrap_up_request(asp, status); |
3701 | 12.6k | } |
3702 | | |
3703 | 0 | return 1; |
3704 | 12.6k | } |
3705 | | |
3706 | | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3707 | | static int |
3708 | | check_set_pdu_for_null_varbind(netsnmp_agent_session *asp) |
3709 | 333 | { |
3710 | 333 | int i; |
3711 | 333 | netsnmp_variable_list *v = NULL; |
3712 | | |
3713 | 520 | for (i = 1, v = asp->pdu->variables; v != NULL; i++, v = v->next_variable) { |
3714 | 197 | if (v->type == ASN_NULL) { |
3715 | | /* |
3716 | | * Protect SET implementations that do not protect themselves |
3717 | | * against wrong type. |
3718 | | */ |
3719 | 10 | DEBUGMSGTL(("snmp_agent", "disallowing SET with NULL var for varbind %d\n", i)); |
3720 | 10 | asp->index = i; |
3721 | 10 | return SNMP_ERR_WRONGTYPE; |
3722 | 10 | } |
3723 | 197 | } |
3724 | 323 | return SNMP_ERR_NOERROR; |
3725 | 333 | } |
3726 | | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3727 | | |
3728 | | int |
3729 | | handle_pdu(netsnmp_agent_session *asp) |
3730 | 12.6k | { |
3731 | 12.6k | int status, inclusives = 0; |
3732 | 12.6k | netsnmp_variable_list *v = NULL; |
3733 | | |
3734 | 12.6k | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3735 | | /* |
3736 | | * Check for ASN_NULL in SET request |
3737 | | */ |
3738 | 12.6k | if (asp->pdu->command == SNMP_MSG_SET) { |
3739 | 333 | status = check_set_pdu_for_null_varbind(asp); |
3740 | 333 | if (status != SNMP_ERR_NOERROR) { |
3741 | 10 | return status; |
3742 | 10 | } |
3743 | 333 | } |
3744 | 12.6k | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3745 | | |
3746 | | /* |
3747 | | * for illegal requests, mark all nodes as ASN_NULL |
3748 | | */ |
3749 | 12.6k | switch (asp->pdu->command) { |
3750 | | |
3751 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3752 | 108 | case SNMP_MSG_INTERNAL_SET_RESERVE2: |
3753 | 383 | case SNMP_MSG_INTERNAL_SET_ACTION: |
3754 | 465 | case SNMP_MSG_INTERNAL_SET_COMMIT: |
3755 | 560 | case SNMP_MSG_INTERNAL_SET_FREE: |
3756 | 617 | case SNMP_MSG_INTERNAL_SET_UNDO: |
3757 | 617 | status = get_set_cache(asp); |
3758 | 617 | if (status != SNMP_ERR_NOERROR) |
3759 | 0 | return status; |
3760 | 617 | break; |
3761 | 617 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3762 | | |
3763 | 617 | case SNMP_MSG_GET: |
3764 | 313 | case SNMP_MSG_GETNEXT: |
3765 | 935 | case SNMP_MSG_GETBULK: |
3766 | 1.72k | for (v = asp->pdu->variables; v != NULL; v = v->next_variable) { |
3767 | 791 | if (v->type == ASN_PRIV_INCL_RANGE) { |
3768 | | /* |
3769 | | * Leave the type for now (it gets set to |
3770 | | * ASN_NULL in netsnmp_add_varbind_to_cache, |
3771 | | * called by netsnmp_create_subtree_cache below). |
3772 | | * If we set it to ASN_NULL now, we wouldn't be |
3773 | | * able to distinguish INCLUSIVE search |
3774 | | * ranges. |
3775 | | */ |
3776 | 0 | inclusives++; |
3777 | 791 | } else { |
3778 | 791 | snmp_set_var_typed_value(v, ASN_NULL, NULL, 0); |
3779 | 791 | } |
3780 | 791 | } |
3781 | 935 | NETSNMP_FALLTHROUGH; |
3782 | | |
3783 | 3.16k | default: |
3784 | 3.16k | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3785 | 3.16k | case SNMP_MSG_INTERNAL_SET_BEGIN: |
3786 | 12.0k | case SNMP_MSG_INTERNAL_SET_RESERVE1: |
3787 | 12.0k | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3788 | 12.0k | asp->vbcount = count_varbinds(asp->pdu->variables); |
3789 | 12.0k | asp->requests = |
3790 | 12.0k | calloc(asp->vbcount ? asp->vbcount : 1, |
3791 | 12.0k | sizeof(netsnmp_request_info)); |
3792 | | /* |
3793 | | * collect varbinds |
3794 | | */ |
3795 | 12.0k | status = netsnmp_create_subtree_cache(asp); |
3796 | 12.0k | if (status != SNMP_ERR_NOERROR) |
3797 | 0 | return status; |
3798 | 12.6k | } |
3799 | | |
3800 | 12.6k | asp->mode = asp->pdu->command; |
3801 | 12.6k | switch (asp->mode) { |
3802 | 204 | case SNMP_MSG_GET: |
3803 | | /* |
3804 | | * increment the message type counter |
3805 | | */ |
3806 | 204 | snmp_increment_statistic(STAT_SNMPINGETREQUESTS); |
3807 | | |
3808 | | /* |
3809 | | * check vacm ahead of time |
3810 | | */ |
3811 | 204 | check_acm(asp, SNMP_NOSUCHOBJECT); |
3812 | | |
3813 | | /* |
3814 | | * get the results |
3815 | | */ |
3816 | 204 | status = handle_var_requests(asp); |
3817 | | |
3818 | | /* |
3819 | | * Deal with unhandled results -> noSuchInstance (rather |
3820 | | * than noSuchObject -- in that case, the type will |
3821 | | * already have been set to noSuchObject when we realised |
3822 | | * we couldn't find an appropriate tree). |
3823 | | */ |
3824 | 204 | if (status == SNMP_ERR_NOERROR) |
3825 | 204 | snmp_replace_var_types(asp->pdu->variables, ASN_NULL, |
3826 | 204 | SNMP_NOSUCHINSTANCE); |
3827 | 204 | break; |
3828 | | |
3829 | 109 | case SNMP_MSG_GETNEXT: |
3830 | 109 | snmp_increment_statistic(STAT_SNMPINGETNEXTS); |
3831 | 109 | NETSNMP_FALLTHROUGH; |
3832 | | |
3833 | 731 | case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */ |
3834 | | /* |
3835 | | * loop through our mib tree till we find an |
3836 | | * appropriate response to return to the caller. |
3837 | | */ |
3838 | | |
3839 | 731 | if (inclusives) { |
3840 | | /* |
3841 | | * This is a special case for AgentX INCLUSIVE getNext |
3842 | | * requests where a result lexi-equal to the request is okay |
3843 | | * but if such a result does not exist, we still want the |
3844 | | * lexi-next one. So basically we do a GET first, and if any |
3845 | | * of the INCLUSIVE requests are satisfied, we use that |
3846 | | * value. Then, unsatisfied INCLUSIVE requests, and |
3847 | | * non-INCLUSIVE requests get done as normal. |
3848 | | */ |
3849 | |
|
3850 | 0 | DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n")); |
3851 | 0 | asp->oldmode = asp->mode; |
3852 | 0 | asp->mode = SNMP_MSG_GET; |
3853 | 0 | } |
3854 | | |
3855 | | /* |
3856 | | * first pass |
3857 | | */ |
3858 | 731 | status = handle_var_requests(asp); |
3859 | 731 | if (status != SNMP_ERR_NOERROR) { |
3860 | 0 | if (!inclusives) |
3861 | 0 | return status; /* should never really happen */ |
3862 | 0 | else |
3863 | 0 | asp->status = SNMP_ERR_NOERROR; |
3864 | 0 | } |
3865 | | |
3866 | | /* |
3867 | | * loop through our mib tree till we find an |
3868 | | * appropriate response to return to the caller. |
3869 | | */ |
3870 | | |
3871 | 731 | status = handle_getnext_loop(asp); |
3872 | 731 | break; |
3873 | | |
3874 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3875 | 323 | case SNMP_MSG_SET: |
3876 | | #ifdef NETSNMP_DISABLE_SET_SUPPORT |
3877 | | return SNMP_ERR_NOTWRITABLE; |
3878 | | #else |
3879 | | /* |
3880 | | * check access permissions first |
3881 | | */ |
3882 | 323 | if (check_acm(asp, SNMP_NOSUCHOBJECT)) |
3883 | 0 | return SNMP_ERR_NOTWRITABLE; |
3884 | | |
3885 | 323 | asp->mode = MODE_SET_BEGIN; |
3886 | 323 | status = handle_set_loop(asp); |
3887 | 323 | #endif |
3888 | 323 | break; |
3889 | | |
3890 | 0 | case SNMP_MSG_INTERNAL_SET_BEGIN: |
3891 | 8.88k | case SNMP_MSG_INTERNAL_SET_RESERVE1: |
3892 | 8.99k | case SNMP_MSG_INTERNAL_SET_RESERVE2: |
3893 | 9.27k | case SNMP_MSG_INTERNAL_SET_ACTION: |
3894 | 9.35k | case SNMP_MSG_INTERNAL_SET_COMMIT: |
3895 | 9.44k | case SNMP_MSG_INTERNAL_SET_FREE: |
3896 | 9.50k | case SNMP_MSG_INTERNAL_SET_UNDO: |
3897 | 9.50k | asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY; |
3898 | 9.50k | status = handle_set_loop(asp); |
3899 | | /* |
3900 | | * asp related cache is saved in cleanup |
3901 | | */ |
3902 | 9.50k | break; |
3903 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3904 | | |
3905 | 69 | case SNMP_MSG_RESPONSE: |
3906 | 69 | snmp_increment_statistic(STAT_SNMPINGETRESPONSES); |
3907 | 69 | return SNMP_ERR_NOERROR; |
3908 | | |
3909 | 0 | case SNMP_MSG_TRAP: |
3910 | 0 | case SNMP_MSG_TRAP2: |
3911 | 0 | snmp_increment_statistic(STAT_SNMPINTRAPS); |
3912 | 0 | return SNMP_ERR_NOERROR; |
3913 | | |
3914 | 1.83k | default: |
3915 | | /* |
3916 | | * WWW: are reports counted somewhere ? |
3917 | | */ |
3918 | 1.83k | snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); |
3919 | 1.83k | return SNMPERR_GENERR; /* shouldn't get here */ |
3920 | | /* |
3921 | | * WWW |
3922 | | */ |
3923 | 12.6k | } |
3924 | 10.7k | return status; |
3925 | 12.6k | } |
3926 | | |
3927 | | /** set error for a request |
3928 | | * \internal external interface: netsnmp_request_set_error |
3929 | | */ |
3930 | | NETSNMP_STATIC_INLINE int |
3931 | | _request_set_error(netsnmp_request_info *request, int mode, int error_value) |
3932 | 621 | { |
3933 | 621 | if (!request) |
3934 | 0 | return SNMPERR_NO_VARS; |
3935 | | |
3936 | 621 | request->processed = 1; |
3937 | 621 | request->delegated = REQUEST_IS_NOT_DELEGATED; |
3938 | | |
3939 | 621 | switch (error_value) { |
3940 | 251 | case SNMP_NOSUCHOBJECT: |
3941 | 251 | case SNMP_NOSUCHINSTANCE: |
3942 | 251 | case SNMP_ENDOFMIBVIEW: |
3943 | | /* |
3944 | | * these are exceptions that should be put in the varbind |
3945 | | * in the case of a GET but should be translated for a SET |
3946 | | * into a real error status code and put in the request |
3947 | | */ |
3948 | 251 | switch (mode) { |
3949 | 251 | case MODE_GET: |
3950 | 251 | case MODE_GETNEXT: |
3951 | 251 | case MODE_GETBULK: |
3952 | 251 | request->requestvb->type = error_value; |
3953 | 251 | break; |
3954 | | |
3955 | | /* |
3956 | | * These are technically illegal to set by the |
3957 | | * client APIs for these modes. But accepting |
3958 | | * them here allows the 'sparse_table' helper to |
3959 | | * provide some common table handling processing |
3960 | | * |
3961 | | snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n", |
3962 | | error_value, mode); |
3963 | | return SNMPERR_VALUE; |
3964 | | */ |
3965 | | |
3966 | 0 | #ifndef NETSNMP_NO_WRITE_SUPPORT |
3967 | 0 | case SNMP_MSG_INTERNAL_SET_RESERVE1: |
3968 | 0 | request->status = SNMP_ERR_NOCREATION; |
3969 | 0 | break; |
3970 | 0 | #endif /* NETSNMP_NO_WRITE_SUPPORT */ |
3971 | | |
3972 | 0 | default: |
3973 | 0 | request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */ |
3974 | 0 | break; |
3975 | 251 | } |
3976 | 251 | break; /* never get here */ |
3977 | | |
3978 | 370 | default: |
3979 | 370 | if (error_value < 0) { |
3980 | | /* |
3981 | | * illegal local error code. translate to generr |
3982 | | */ |
3983 | | /* |
3984 | | * WWW: full translation map? |
3985 | | */ |
3986 | 0 | snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n", |
3987 | 0 | error_value, SNMP_ERR_GENERR); |
3988 | 0 | request->status = SNMP_ERR_GENERR; |
3989 | 370 | } else { |
3990 | | /* |
3991 | | * WWW: translations and mode checking? |
3992 | | */ |
3993 | 370 | request->status = error_value; |
3994 | 370 | } |
3995 | 370 | break; |
3996 | 621 | } |
3997 | 621 | return SNMPERR_SUCCESS; |
3998 | 621 | } |
3999 | | |
4000 | | /** set error for a request |
4001 | | * @param request request which has error |
4002 | | * @param error_value error value for request |
4003 | | */ |
4004 | | int |
4005 | | netsnmp_request_set_error(netsnmp_request_info *request, int error_value) |
4006 | 0 | { |
4007 | 0 | if (!request || !request->agent_req_info) |
4008 | 0 | return SNMPERR_NO_VARS; |
4009 | | |
4010 | 0 | return _request_set_error(request, request->agent_req_info->mode, |
4011 | 0 | error_value); |
4012 | 0 | } |
4013 | | |
4014 | | #ifndef NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX |
4015 | | /** set error for a request within a request list |
4016 | | * @param request head of the request list |
4017 | | * @param error_value error value for request |
4018 | | * @param idx index of the request which has the error |
4019 | | */ |
4020 | | int |
4021 | | netsnmp_request_set_error_idx(netsnmp_request_info *request, |
4022 | | int error_value, int idx) |
4023 | 0 | { |
4024 | 0 | int i; |
4025 | 0 | netsnmp_request_info *req = request; |
4026 | |
|
4027 | 0 | if (!request || !request->agent_req_info) |
4028 | 0 | return SNMPERR_NO_VARS; |
4029 | | |
4030 | | /* |
4031 | | * Skip to the indicated varbind |
4032 | | */ |
4033 | 0 | for ( i=2; i<=idx; i++) { |
4034 | 0 | req = req->next; |
4035 | 0 | if (!req) |
4036 | 0 | return SNMPERR_NO_VARS; |
4037 | 0 | } |
4038 | | |
4039 | 0 | return _request_set_error(req, request->agent_req_info->mode, |
4040 | 0 | error_value); |
4041 | 0 | } |
4042 | | #endif /* NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX */ |
4043 | | |
4044 | | /** set error for all requests |
4045 | | * @param requests request list |
4046 | | * @param error error value for requests |
4047 | | * @return SNMPERR_SUCCESS, or an error code |
4048 | | */ |
4049 | | NETSNMP_INLINE int |
4050 | | netsnmp_request_set_error_all( netsnmp_request_info *requests, int error) |
4051 | 213 | { |
4052 | 213 | int mode, rc, result = SNMPERR_SUCCESS; |
4053 | | |
4054 | 213 | if((NULL == requests) || (NULL == requests->agent_req_info)) |
4055 | 0 | return SNMPERR_NO_VARS; |
4056 | | |
4057 | 213 | mode = requests->agent_req_info->mode; /* every req has same mode */ |
4058 | | |
4059 | 464 | for(; requests ; requests = requests->next) { |
4060 | | |
4061 | | /** paranoid sanity checks */ |
4062 | 251 | netsnmp_assert(NULL != requests->agent_req_info); |
4063 | 251 | netsnmp_assert(mode == requests->agent_req_info->mode); |
4064 | | |
4065 | | /* |
4066 | | * set error for this request. Log any errors, save the last |
4067 | | * to return to the user. |
4068 | | */ |
4069 | 251 | if((rc = _request_set_error(requests, mode, error))) { |
4070 | 0 | snmp_log(LOG_WARNING,"got %d while setting request error\n", rc); |
4071 | 0 | result = rc; |
4072 | 0 | } |
4073 | 251 | } |
4074 | 213 | return result; |
4075 | 213 | } |
4076 | | |
4077 | | /** |
4078 | | * Return the difference between pm and the agent start time in hundredths of |
4079 | | * a second. |
4080 | | * \deprecated Don't use in new code. |
4081 | | * |
4082 | | * @param[in] pm An absolute time as e.g. reported by gettimeofday(). |
4083 | | */ |
4084 | | u_long |
4085 | | netsnmp_marker_uptime(marker_t pm) |
4086 | 0 | { |
4087 | 0 | u_long res; |
4088 | 0 | const_marker_t start = netsnmp_get_agent_starttime(); |
4089 | |
|
4090 | 0 | res = uatime_hdiff(start, pm); |
4091 | 0 | return res; |
4092 | 0 | } |
4093 | | |
4094 | | /** |
4095 | | * Return the difference between tv and the agent start time in hundredths of |
4096 | | * a second. |
4097 | | * |
4098 | | * \deprecated Use netsnmp_get_agent_uptime() instead. |
4099 | | * |
4100 | | * @param[in] tv An absolute time as e.g. reported by gettimeofday(). |
4101 | | */ |
4102 | | u_long |
4103 | | netsnmp_timeval_uptime(struct timeval * tv) |
4104 | 0 | { |
4105 | 0 | return netsnmp_marker_uptime((marker_t) tv); |
4106 | 0 | } |
4107 | | |
4108 | | |
4109 | | struct timeval starttime; |
4110 | | static struct timeval starttimeM; |
4111 | | |
4112 | | /** |
4113 | | * Return a pointer to the variable in which the Net-SNMP start time has |
4114 | | * been stored. |
4115 | | * |
4116 | | * @note Use netsnmp_get_agent_runtime() instead of this function if you need |
4117 | | * to know how much time elapsed since netsnmp_set_agent_starttime() has been |
4118 | | * called. |
4119 | | */ |
4120 | | const_marker_t |
4121 | | netsnmp_get_agent_starttime(void) |
4122 | 0 | { |
4123 | 0 | return &starttime; |
4124 | 0 | } |
4125 | | |
4126 | | /** |
4127 | | * Report the time that elapsed since the agent start time in hundredths of a |
4128 | | * second. |
4129 | | * |
4130 | | * @see See also netsnmp_set_agent_starttime(). |
4131 | | */ |
4132 | | uint64_t |
4133 | | netsnmp_get_agent_runtime(void) |
4134 | 0 | { |
4135 | 0 | struct timeval now, delta; |
4136 | |
|
4137 | 0 | netsnmp_get_monotonic_clock(&now); |
4138 | 0 | NETSNMP_TIMERSUB(&now, &starttimeM, &delta); |
4139 | 0 | return (uint64_t)(delta.tv_sec * (uint64_t)100 + delta.tv_usec / 10000); |
4140 | 0 | } |
4141 | | |
4142 | | /** |
4143 | | * Set the time at which Net-SNMP started either to the current time |
4144 | | * (if s == NULL) or to *s (if s is not NULL). |
4145 | | * |
4146 | | * @see See also netsnmp_set_agent_uptime(). |
4147 | | */ |
4148 | | void |
4149 | | netsnmp_set_agent_starttime(marker_t s) |
4150 | 3.34k | { |
4151 | 3.34k | if (s) { |
4152 | 0 | struct timeval nowA, nowM; |
4153 | |
|
4154 | 0 | starttime = *(struct timeval*)s; |
4155 | 0 | gettimeofday(&nowA, NULL); |
4156 | 0 | netsnmp_get_monotonic_clock(&nowM); |
4157 | 0 | NETSNMP_TIMERSUB(&starttime, &nowA, &starttimeM); |
4158 | 0 | NETSNMP_TIMERADD(&starttimeM, &nowM, &starttimeM); |
4159 | 3.34k | } else { |
4160 | 3.34k | gettimeofday(&starttime, NULL); |
4161 | 3.34k | netsnmp_get_monotonic_clock(&starttimeM); |
4162 | 3.34k | } |
4163 | 3.34k | } |
4164 | | |
4165 | | |
4166 | | /** |
4167 | | * Return the current value of 'sysUpTime' |
4168 | | */ |
4169 | | u_long |
4170 | | netsnmp_get_agent_uptime(void) |
4171 | 0 | { |
4172 | 0 | struct timeval now, delta; |
4173 | |
|
4174 | 0 | netsnmp_get_monotonic_clock(&now); |
4175 | 0 | NETSNMP_TIMERSUB(&now, &starttimeM, &delta); |
4176 | 0 | return (u_long)(delta.tv_sec * 100UL + delta.tv_usec / 10000); |
4177 | 0 | } |
4178 | | |
4179 | | #ifndef NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME |
4180 | | /** |
4181 | | * Set the start time from which 'sysUpTime' is computed. |
4182 | | * |
4183 | | * @param[in] hsec New sysUpTime in hundredths of a second. |
4184 | | * |
4185 | | * @see See also netsnmp_set_agent_starttime(). |
4186 | | */ |
4187 | | void |
4188 | | netsnmp_set_agent_uptime(u_long hsec) |
4189 | 0 | { |
4190 | 0 | struct timeval nowA, nowM; |
4191 | 0 | struct timeval new_uptime; |
4192 | |
|
4193 | 0 | gettimeofday(&nowA, NULL); |
4194 | 0 | netsnmp_get_monotonic_clock(&nowM); |
4195 | 0 | new_uptime.tv_sec = hsec / 100; |
4196 | 0 | new_uptime.tv_usec = (uint32_t)(hsec - new_uptime.tv_sec * 100) * 10000L; |
4197 | 0 | NETSNMP_TIMERSUB(&nowA, &new_uptime, &starttime); |
4198 | 0 | NETSNMP_TIMERSUB(&nowM, &new_uptime, &starttimeM); |
4199 | 0 | } |
4200 | | #endif /* NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME */ |
4201 | | |
4202 | | |
4203 | | /************************************************************************* |
4204 | | * |
4205 | | * deprecated functions |
4206 | | * |
4207 | | */ |
4208 | | |
4209 | | /** set error for a request |
4210 | | * \deprecated, use netsnmp_request_set_error instead |
4211 | | * @param reqinfo agent_request_info pointer for request |
4212 | | * @param request request_info pointer |
4213 | | * @param error_value error value for requests |
4214 | | * @return error_value |
4215 | | */ |
4216 | | int |
4217 | | netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo, |
4218 | | netsnmp_request_info *request, int error_value) |
4219 | 370 | { |
4220 | 370 | if (!request || !reqinfo) |
4221 | 0 | return error_value; |
4222 | | |
4223 | 370 | _request_set_error(request, reqinfo->mode, error_value); |
4224 | | |
4225 | 370 | return error_value; |
4226 | 370 | } |
4227 | | |
4228 | | /** set error for a request |
4229 | | * \deprecated, use netsnmp_request_set_error instead |
4230 | | * @param mode Net-SNMP agent processing mode |
4231 | | * @param request request_info pointer |
4232 | | * @param error_value error value for requests |
4233 | | * @return error_value |
4234 | | */ |
4235 | | int |
4236 | | netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request, |
4237 | | int error_value) |
4238 | 0 | { |
4239 | 0 | _request_set_error(request, mode, error_value); |
4240 | | |
4241 | 0 | return error_value; |
4242 | 0 | } |
4243 | | |
4244 | | /** set error for all request |
4245 | | * \deprecated use netsnmp_request_set_error_all |
4246 | | * @param reqinfo agent_request_info pointer for requests |
4247 | | * @param requests request list |
4248 | | * @param error_value error value for requests |
4249 | | * @return error_value |
4250 | | */ |
4251 | | #ifndef NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR |
4252 | | int |
4253 | | netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo, |
4254 | | netsnmp_request_info *requests, |
4255 | | int error_value) |
4256 | 0 | { |
4257 | 0 | netsnmp_request_set_error_all(requests, error_value); |
4258 | 0 | return error_value; |
4259 | 0 | } |
4260 | | #endif /* NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR */ |
4261 | | /** @} */ |