/src/net-snmp/agent/agent_registry.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * agent_registry.c |
3 | | */ |
4 | | /* Portions of this file are subject to the following copyright(s). See |
5 | | * the Net-SNMP's COPYING file for more details and other copyrights |
6 | | * that may apply: |
7 | | */ |
8 | | /* |
9 | | * Portions of this file are copyrighted by: |
10 | | * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. |
11 | | * Use is subject to license terms specified in the COPYING file |
12 | | * distributed with the Net-SNMP package. |
13 | | * |
14 | | * Portions of this file are copyrighted by: |
15 | | * Copyright (c) 2016 VMware, Inc. All rights reserved. |
16 | | * Use is subject to license terms specified in the COPYING file |
17 | | * distributed with the Net-SNMP package. |
18 | | */ |
19 | | /** @defgroup agent_registry Registry of MIB subtrees, modules, sessions, etc |
20 | | * Maintain a registry of MIB subtrees, together with related information |
21 | | * regarding MIB modules, sessions, etc |
22 | | * @ingroup agent |
23 | | * |
24 | | * @{ |
25 | | */ |
26 | | |
27 | | #define IN_SNMP_VARS_C |
28 | | |
29 | | #include <net-snmp/net-snmp-config.h> |
30 | | #include <net-snmp/net-snmp-features.h> |
31 | | |
32 | | #include <signal.h> |
33 | | #ifdef HAVE_STRING_H |
34 | | #include <string.h> |
35 | | #endif |
36 | | #ifdef HAVE_STDLIB_H |
37 | | #include <stdlib.h> |
38 | | #endif |
39 | | #include <sys/types.h> |
40 | | #include <stdio.h> |
41 | | #include <fcntl.h> |
42 | | #ifdef TIME_WITH_SYS_TIME |
43 | | # include <sys/time.h> |
44 | | # include <time.h> |
45 | | #else |
46 | | # ifdef HAVE_SYS_TIME_H |
47 | | # include <sys/time.h> |
48 | | # else |
49 | | # include <time.h> |
50 | | # endif |
51 | | #endif |
52 | | #ifdef HAVE_NETINET_IN_H |
53 | | #include <netinet/in.h> |
54 | | #endif |
55 | | |
56 | | #include <net-snmp/net-snmp-includes.h> |
57 | | #include <net-snmp/library/snmp_assert.h> |
58 | | #include <net-snmp/agent/net-snmp-agent-includes.h> |
59 | | #include <net-snmp/agent/agent_callbacks.h> |
60 | | |
61 | | #include "snmpd.h" |
62 | | #include "agent_global_vars.h" |
63 | | #include "mibgroup/struct.h" |
64 | | #include <net-snmp/agent/old_api.h> |
65 | | #include <net-snmp/agent/null.h> |
66 | | #include <net-snmp/agent/table.h> |
67 | | #include <net-snmp/agent/table_iterator.h> |
68 | | #include <net-snmp/agent/agent_index.h> |
69 | | #include <net-snmp/agent/agent_registry.h> |
70 | | |
71 | | #ifdef USING_AGENTX_SUBAGENT_MODULE |
72 | | #include "agentx/subagent.h" |
73 | | #include "agentx/client.h" |
74 | | #endif |
75 | | |
76 | | netsnmp_feature_child_of(agent_registry_all, libnetsnmpagent); |
77 | | |
78 | | netsnmp_feature_child_of(unregister_mib_table_row, agent_registry_all); |
79 | | |
80 | | /** @defgroup agent_lookup_cache Lookup cache, storing the registered OIDs. |
81 | | * Maintain the cache used for locating sub-trees and OIDs. |
82 | | * @ingroup agent_registry |
83 | | * |
84 | | * @{ |
85 | | */ |
86 | | |
87 | | /** Lookup cache - default size.*/ |
88 | 2.61k | #define SUBTREE_DEFAULT_CACHE_SIZE 8 |
89 | | /** Lookup cache - max acceptable size.*/ |
90 | 47.1k | #define SUBTREE_MAX_CACHE_SIZE 32 |
91 | | int lookup_cache_size = 0; /*enabled later after registrations are loaded */ |
92 | | |
93 | | typedef struct lookup_cache_s { |
94 | | netsnmp_subtree *next; |
95 | | netsnmp_subtree *previous; |
96 | | } lookup_cache; |
97 | | |
98 | | typedef struct lookup_cache_context_s { |
99 | | char *context; |
100 | | struct lookup_cache_context_s *next; |
101 | | int thecachecount; |
102 | | int currentpos; |
103 | | lookup_cache cache[SUBTREE_MAX_CACHE_SIZE]; |
104 | | } lookup_cache_context; |
105 | | |
106 | | static lookup_cache_context *thecontextcache = NULL; |
107 | | |
108 | | /** Set the lookup cache size for optimized agent registration performance. |
109 | | * Note that it is only used by master agent - sub-agent doesn't need the cache. |
110 | | * The rough guide is that the cache size should be equal to the maximum |
111 | | * number of simultaneous managers you expect to talk to the agent (M) times 80% |
112 | | * (or so, he says randomly) the average number (N) of varbinds you |
113 | | * expect to receive in a given request for a manager. ie, M times N. |
114 | | * Bigger does NOT necessarily mean better. Certainly 16 should be an |
115 | | * upper limit. 32 is the hard coded limit. |
116 | | * |
117 | | * @param newsize set to the maximum size of a cache for a given |
118 | | * context. Set to 0 to completely disable caching, or to -1 to set |
119 | | * to the default cache size (8), or to a number of your chosing. The |
120 | | */ |
121 | | void |
122 | 49.7k | netsnmp_set_lookup_cache_size(int newsize) { |
123 | 49.7k | if (newsize < 0) |
124 | 2.61k | lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE; |
125 | 47.1k | else if (newsize < SUBTREE_MAX_CACHE_SIZE) |
126 | 47.1k | lookup_cache_size = newsize; |
127 | 0 | else |
128 | 0 | lookup_cache_size = SUBTREE_MAX_CACHE_SIZE; |
129 | 49.7k | } |
130 | | |
131 | | /** Retrieves the current value of the lookup cache size |
132 | | * Should be called from master agent only - sub-agent doesn't need the cache. |
133 | | * |
134 | | * @return the current lookup cache size |
135 | | */ |
136 | | int |
137 | 23.5k | netsnmp_get_lookup_cache_size(void) { |
138 | 23.5k | return lookup_cache_size; |
139 | 23.5k | } |
140 | | |
141 | | /** Returns lookup cache entry for the context of given name. |
142 | | * |
143 | | * @param context Name of the context. Name is case sensitive. |
144 | | * |
145 | | * @return the lookup cache context |
146 | | */ |
147 | | NETSNMP_STATIC_INLINE lookup_cache_context * |
148 | 40.4k | get_context_lookup_cache(const char *context) { |
149 | 40.4k | lookup_cache_context *ptr; |
150 | 40.4k | if (!context) |
151 | 16.8k | context = ""; |
152 | | |
153 | 40.4k | for(ptr = thecontextcache; ptr; ptr = ptr->next) { |
154 | 37.7k | if (strcmp(ptr->context, context) == 0) |
155 | 37.7k | break; |
156 | 37.7k | } |
157 | 40.4k | if (!ptr) { |
158 | 2.61k | if (netsnmp_subtree_find_first(context)) { |
159 | 2.61k | ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context); |
160 | 2.61k | if (!ptr) |
161 | 0 | return NULL; |
162 | 2.61k | ptr->next = thecontextcache; |
163 | 2.61k | ptr->context = strdup(context); |
164 | 2.61k | if (!ptr->context) { |
165 | 0 | free(ptr); |
166 | 0 | return NULL; |
167 | 0 | } |
168 | 2.61k | thecontextcache = ptr; |
169 | 2.61k | } else { |
170 | 0 | return NULL; |
171 | 0 | } |
172 | 2.61k | } |
173 | 40.4k | return ptr; |
174 | 40.4k | } |
175 | | |
176 | | /** Adds an entry to the Lookup Cache under specified context name. |
177 | | * |
178 | | * @param context Name of the context. Name is case sensitive. |
179 | | * |
180 | | * @param next Next subtree item. |
181 | | * |
182 | | * @param previous Previous subtree item. |
183 | | */ |
184 | | NETSNMP_STATIC_INLINE void |
185 | | lookup_cache_add(const char *context, |
186 | 296 | netsnmp_subtree *next, netsnmp_subtree *previous) { |
187 | 296 | lookup_cache_context *cptr; |
188 | | |
189 | 296 | if ((cptr = get_context_lookup_cache(context)) == NULL) |
190 | 0 | return; |
191 | | |
192 | 296 | if (cptr->thecachecount < lookup_cache_size) |
193 | 296 | cptr->thecachecount++; |
194 | | |
195 | 296 | cptr->cache[cptr->currentpos].next = next; |
196 | 296 | cptr->cache[cptr->currentpos].previous = previous; |
197 | | |
198 | 296 | if (++cptr->currentpos >= lookup_cache_size) |
199 | 0 | cptr->currentpos = 0; |
200 | 296 | } |
201 | | |
202 | | /** @private |
203 | | * Replaces next and previous pointer in given Lookup Cache. |
204 | | * |
205 | | * @param ptr Lookup Cache pointer. |
206 | | * |
207 | | * @param next Next subtree item. |
208 | | * |
209 | | * @param previous Previous subtree item. |
210 | | */ |
211 | | NETSNMP_STATIC_INLINE void |
212 | | lookup_cache_replace(lookup_cache *ptr, |
213 | 335 | netsnmp_subtree *next, netsnmp_subtree *previous) { |
214 | | |
215 | 335 | ptr->next = next; |
216 | 335 | ptr->previous = previous; |
217 | 335 | } |
218 | | |
219 | | /** Finds an entry in the Lookup Cache. |
220 | | * |
221 | | * @param context Case sensitive name of the context. |
222 | | * |
223 | | * @param name The OID we're searching for. |
224 | | * |
225 | | * @param name_len Number of sub-ids (single integers) in the OID. |
226 | | * |
227 | | * @param retcmp Value set to snmp_oid_compare() call result. |
228 | | * The value, if set, is always nonnegative. |
229 | | * |
230 | | * @return gives Lookup Cache entry, or NULL if not found. |
231 | | * |
232 | | * @see snmp_oid_compare() |
233 | | */ |
234 | | NETSNMP_STATIC_INLINE lookup_cache * |
235 | | lookup_cache_find(const char *context, const oid *name, size_t name_len, |
236 | 8.69k | int *retcmp) { |
237 | 8.69k | lookup_cache_context *cptr; |
238 | 8.69k | lookup_cache *ret = NULL; |
239 | 8.69k | int cmp; |
240 | 8.69k | int i; |
241 | | |
242 | 8.69k | if ((cptr = get_context_lookup_cache(context)) == NULL) |
243 | 0 | return NULL; |
244 | | |
245 | 9.67k | for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) { |
246 | 986 | if (cptr->cache[i].previous->start_a) |
247 | 986 | cmp = snmp_oid_compare(name, name_len, |
248 | 986 | cptr->cache[i].previous->start_a, |
249 | 986 | cptr->cache[i].previous->start_len); |
250 | 0 | else |
251 | 0 | cmp = 1; |
252 | 986 | if (cmp >= 0) { |
253 | 808 | *retcmp = cmp; |
254 | 808 | ret = &(cptr->cache[i]); |
255 | 808 | } |
256 | 986 | } |
257 | 8.69k | return ret; |
258 | 8.69k | } |
259 | | |
260 | | /** @private |
261 | | * Clears cache count and position in Lookup Cache. |
262 | | */ |
263 | | NETSNMP_STATIC_INLINE void |
264 | 31.4k | invalidate_lookup_cache(const char *context) { |
265 | 31.4k | lookup_cache_context *cptr; |
266 | 31.4k | if ((cptr = get_context_lookup_cache(context)) != NULL) { |
267 | 31.4k | cptr->thecachecount = 0; |
268 | 31.4k | cptr->currentpos = 0; |
269 | 31.4k | } |
270 | 31.4k | } |
271 | | |
272 | | void |
273 | 2.61k | clear_lookup_cache(void) { |
274 | | |
275 | 2.61k | lookup_cache_context *ptr = NULL, *next = NULL; |
276 | | |
277 | 2.61k | ptr = thecontextcache; |
278 | 5.23k | while (ptr) { |
279 | 2.61k | next = ptr->next; |
280 | 2.61k | SNMP_FREE(ptr->context); |
281 | 2.61k | SNMP_FREE(ptr); |
282 | 2.61k | ptr = next; |
283 | 2.61k | } |
284 | 2.61k | thecontextcache = NULL; /* !!! */ |
285 | 2.61k | } |
286 | | |
287 | | /** @} */ |
288 | | /* End of Lookup cache code */ |
289 | | |
290 | | /** @defgroup agent_context_cache Context cache, storing the OIDs under their contexts. |
291 | | * Maintain the cache used for locating sub-trees registered under different contexts. |
292 | | * @ingroup agent_registry |
293 | | * |
294 | | * @{ |
295 | | */ |
296 | | subtree_context_cache *context_subtrees = NULL; |
297 | | |
298 | | /** Returns the top element of context subtrees cache. |
299 | | * Use it if you wish to sweep through the cache elements. |
300 | | * Note that the return may be NULL (cache may be empty). |
301 | | * |
302 | | * @return pointer to topmost context subtree cache element. |
303 | | */ |
304 | | subtree_context_cache * |
305 | | get_top_context_cache(void) |
306 | 2.61k | { |
307 | 2.61k | return context_subtrees; |
308 | 2.61k | } |
309 | | |
310 | | /** Finds the first subtree registered under given context. |
311 | | * |
312 | | * @param context_name Text name of the context we're searching for. |
313 | | * |
314 | | * @return pointer to the first subtree element, or NULL if not found. |
315 | | */ |
316 | | netsnmp_subtree * |
317 | | netsnmp_subtree_find_first(const char *context_name) |
318 | 65.6k | { |
319 | 65.6k | subtree_context_cache *ptr; |
320 | | |
321 | 65.6k | if (!context_name) { |
322 | 47.5k | context_name = ""; |
323 | 47.5k | } |
324 | | |
325 | 65.6k | DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", |
326 | 65.6k | context_name)); |
327 | 65.6k | for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { |
328 | 52.5k | if (ptr->context_name != NULL && |
329 | 52.5k | strcmp(ptr->context_name, context_name) == 0) { |
330 | 52.5k | DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name)); |
331 | 52.5k | return ptr->first_subtree; |
332 | 52.5k | } |
333 | 52.5k | } |
334 | 13.0k | DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", |
335 | 13.0k | context_name)); |
336 | 13.0k | return NULL; |
337 | 65.6k | } |
338 | | |
339 | | /** Adds the subtree to Context Cache under given context name. |
340 | | * |
341 | | * @param context_name Text name of the context we're adding. |
342 | | * |
343 | | * @param new_tree The subtree to be added. |
344 | | * |
345 | | * @return copy of the new_tree pointer, or NULL if cannot add. |
346 | | */ |
347 | | netsnmp_subtree * |
348 | | add_subtree(netsnmp_subtree *new_tree, const char *context_name) |
349 | 2.61k | { |
350 | 2.61k | subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache); |
351 | | |
352 | 2.61k | if (!context_name) { |
353 | 0 | context_name = ""; |
354 | 0 | } |
355 | | |
356 | 2.61k | if (!ptr) { |
357 | 0 | return NULL; |
358 | 0 | } |
359 | | |
360 | 2.61k | DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n", |
361 | 2.61k | context_name)); |
362 | | |
363 | 2.61k | ptr->next = context_subtrees; |
364 | 2.61k | ptr->first_subtree = new_tree; |
365 | 2.61k | ptr->context_name = strdup(context_name); |
366 | 2.61k | if (!ptr->context_name) { |
367 | 0 | free(ptr); |
368 | 0 | return NULL; |
369 | 0 | } |
370 | | |
371 | 2.61k | context_subtrees = ptr; |
372 | | |
373 | 2.61k | return ptr->first_subtree; |
374 | 2.61k | } |
375 | | |
376 | | void |
377 | | netsnmp_remove_subtree(netsnmp_subtree *tree) |
378 | 0 | { |
379 | 0 | subtree_context_cache *ptr; |
380 | |
|
381 | 0 | if (!tree->prev) { |
382 | 0 | for (ptr = context_subtrees; ptr; ptr = ptr->next) |
383 | 0 | if (ptr->first_subtree == tree) |
384 | 0 | break; |
385 | 0 | netsnmp_assert(ptr); |
386 | 0 | if (ptr) |
387 | 0 | ptr->first_subtree = tree->next; |
388 | 0 | } else |
389 | 0 | tree->prev->next = tree->next; |
390 | |
|
391 | 0 | if (tree->next) |
392 | 0 | tree->next->prev = tree->prev; |
393 | 0 | } |
394 | | |
395 | | /** Replaces first subtree registered under given context name. |
396 | | * Overwrites a subtree pointer in Context Cache for the context name. |
397 | | * The previous subtree pointer is lost. If there's no subtree |
398 | | * under the supplied name, then a new cache item is created. |
399 | | * |
400 | | * @param new_tree The new subtree to be set. |
401 | | * |
402 | | * @param context_name Text name of the context we're replacing. |
403 | | * It is case sensitive. |
404 | | * |
405 | | * @return copy of the new_tree pointer, or NULL on error. |
406 | | */ |
407 | | netsnmp_subtree * |
408 | | netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, |
409 | | const char *context_name) |
410 | 5.23k | { |
411 | 5.23k | subtree_context_cache *ptr; |
412 | 5.23k | if (!context_name) { |
413 | 2.61k | context_name = ""; |
414 | 2.61k | } |
415 | 5.23k | for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { |
416 | 2.61k | if (ptr->context_name != NULL && |
417 | 2.61k | strcmp(ptr->context_name, context_name) == 0) { |
418 | 2.61k | ptr->first_subtree = new_tree; |
419 | 2.61k | return ptr->first_subtree; |
420 | 2.61k | } |
421 | 2.61k | } |
422 | 2.61k | return add_subtree(new_tree, context_name); |
423 | 5.23k | } |
424 | | |
425 | | |
426 | | void clear_subtree (netsnmp_subtree *sub); |
427 | | |
428 | | /** Completely clears both the Context cache and the Lookup cache. |
429 | | */ |
430 | | void |
431 | 2.61k | clear_context(void) { |
432 | | |
433 | 2.61k | subtree_context_cache *ptr = NULL, *next = NULL; |
434 | 2.61k | netsnmp_subtree *t, *u; |
435 | | |
436 | 2.61k | DEBUGMSGTL(("agent_registry", "clear context\n")); |
437 | | |
438 | 2.61k | ptr = get_top_context_cache(); |
439 | 5.23k | while (ptr) { |
440 | 2.61k | next = ptr->next; |
441 | | |
442 | 2.61k | for (t = ptr->first_subtree; t; t = u) { |
443 | 0 | u = t->next; |
444 | 0 | clear_subtree(t); |
445 | 0 | } |
446 | | |
447 | 2.61k | free(NETSNMP_REMOVE_CONST(char*, ptr->context_name)); |
448 | 2.61k | SNMP_FREE(ptr); |
449 | | |
450 | 2.61k | ptr = next; |
451 | 2.61k | } |
452 | 2.61k | context_subtrees = NULL; /* !!! */ |
453 | 2.61k | clear_lookup_cache(); |
454 | 2.61k | } |
455 | | |
456 | | /** @} */ |
457 | | /* End of Context cache code */ |
458 | | |
459 | | /** @defgroup agent_mib_subtree Maintaining MIB subtrees. |
460 | | * Maintaining MIB nodes and subtrees. |
461 | | * @ingroup agent_registry |
462 | | * |
463 | | * @{ |
464 | | */ |
465 | | |
466 | | static void register_mib_detach_node(netsnmp_subtree *s); |
467 | | |
468 | | /** Frees single subtree item. |
469 | | * Deallocated memory for given netsnmp_subtree item, including |
470 | | * Handle Registration structure stored inside this item. |
471 | | * After calling this function, the pointer is invalid |
472 | | * and should be set to NULL. |
473 | | * |
474 | | * @param a The subtree item to dispose. |
475 | | */ |
476 | | void |
477 | | netsnmp_subtree_free(netsnmp_subtree *a) |
478 | 15.7k | { |
479 | 15.7k | if (a != NULL) { |
480 | 15.7k | if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, |
481 | 0 | a->start_a, a->start_len) == 0) { |
482 | 0 | SNMP_FREE(a->variables); |
483 | 0 | } |
484 | 15.7k | SNMP_FREE(a->name_a); |
485 | 15.7k | a->namelen = 0; |
486 | 15.7k | SNMP_FREE(a->start_a); |
487 | 15.7k | a->start_len = 0; |
488 | 15.7k | SNMP_FREE(a->end_a); |
489 | 15.7k | a->end_len = 0; |
490 | 15.7k | SNMP_FREE(a->label_a); |
491 | 15.7k | netsnmp_handler_registration_free(a->reginfo); |
492 | 15.7k | a->reginfo = NULL; |
493 | 15.7k | SNMP_FREE(a); |
494 | 15.7k | } |
495 | 15.7k | } |
496 | | |
497 | | /** Creates deep copy of a subtree item. |
498 | | * Duplicates all properties stored in the structure, including |
499 | | * Handle Registration structure stored inside the item. |
500 | | * |
501 | | * @param a The subtree item to copy. |
502 | | * |
503 | | * @return deep copy of the subtree item, or NULL on error. |
504 | | */ |
505 | | netsnmp_subtree * |
506 | | netsnmp_subtree_deepcopy(netsnmp_subtree *a) |
507 | 0 | { |
508 | 0 | netsnmp_subtree *b = calloc(1, sizeof(netsnmp_subtree)); |
509 | |
|
510 | 0 | if (b != NULL) { |
511 | 0 | memcpy(b, a, sizeof(netsnmp_subtree)); |
512 | 0 | b->name_a = snmp_duplicate_objid(a->name_a, a->namelen); |
513 | 0 | b->start_a = snmp_duplicate_objid(a->start_a, a->start_len); |
514 | 0 | b->end_a = snmp_duplicate_objid(a->end_a, a->end_len); |
515 | 0 | b->label_a = strdup(a->label_a); |
516 | | |
517 | 0 | if (b->name_a == NULL || b->start_a == NULL || |
518 | 0 | b->end_a == NULL || b->label_a == NULL) { |
519 | 0 | netsnmp_subtree_free(b); |
520 | 0 | return NULL; |
521 | 0 | } |
522 | | |
523 | 0 | if (a->variables != NULL) { |
524 | 0 | b->variables = (struct variable *)malloc(a->variables_len * |
525 | 0 | a->variables_width); |
526 | 0 | if (b->variables != NULL) { |
527 | 0 | memcpy(b->variables, a->variables,a->variables_len*a->variables_width); |
528 | 0 | } else { |
529 | 0 | netsnmp_subtree_free(b); |
530 | 0 | return NULL; |
531 | 0 | } |
532 | 0 | } |
533 | | |
534 | 0 | if (a->reginfo != NULL) { |
535 | 0 | b->reginfo = netsnmp_handler_registration_dup(a->reginfo); |
536 | 0 | if (b->reginfo == NULL) { |
537 | 0 | netsnmp_subtree_free(b); |
538 | 0 | return NULL; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | } |
542 | 0 | return b; |
543 | 0 | } |
544 | | |
545 | | /** @private |
546 | | * Replaces next subtree pointer in given subtree. |
547 | | */ |
548 | | NETSNMP_STATIC_INLINE void |
549 | | netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext) |
550 | 18.3k | { |
551 | 18.3k | ptr->next = thenext; |
552 | 18.3k | if (thenext) |
553 | 5.23k | netsnmp_oid_compare_ll(ptr->start_a, |
554 | 5.23k | ptr->start_len, |
555 | 5.23k | thenext->start_a, |
556 | 5.23k | thenext->start_len, |
557 | 5.23k | &thenext->oid_off); |
558 | 18.3k | } |
559 | | |
560 | | /** @private |
561 | | * Replaces previous subtree pointer in given subtree. |
562 | | */ |
563 | | NETSNMP_STATIC_INLINE void |
564 | | netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev) |
565 | 7.85k | { |
566 | 7.85k | ptr->prev = theprev; |
567 | 7.85k | if (theprev) |
568 | 5.23k | netsnmp_oid_compare_ll(theprev->start_a, |
569 | 5.23k | theprev->start_len, |
570 | 5.23k | ptr->start_a, |
571 | 5.23k | ptr->start_len, |
572 | 5.23k | &ptr->oid_off); |
573 | 7.85k | } |
574 | | |
575 | | netsnmp_feature_child_of(netsnmp_subtree_compare,netsnmp_unused); |
576 | | #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE |
577 | | /** Compares OIDs of given subtrees. |
578 | | * |
579 | | * @param ap,bp Pointers to the subtrees to be compared. |
580 | | * |
581 | | * @return OIDs lexicographical comparison result. |
582 | | * |
583 | | * @see snmp_oid_compare() |
584 | | */ |
585 | | int |
586 | | netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp) |
587 | 0 | { |
588 | 0 | return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen); |
589 | 0 | } |
590 | | #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_SUBTREE_COMPARE */ |
591 | | |
592 | | /** Joins the given subtree with the current tree. |
593 | | * Trees are joined and the one supplied as parameter is freed. |
594 | | * |
595 | | * @param root The subtree to be merged with current subtree. |
596 | | * Do not use the pointer after joining - it may be invalid. |
597 | | */ |
598 | | void |
599 | | netsnmp_subtree_join(netsnmp_subtree *root) |
600 | 0 | { |
601 | 0 | netsnmp_subtree *s, *tmp, *c, *d; |
602 | |
|
603 | 0 | while (root != NULL) { |
604 | 0 | s = root->next; |
605 | 0 | while (s != NULL && root->reginfo == s->reginfo) { |
606 | 0 | tmp = s->next; |
607 | 0 | DEBUGMSGTL(("subtree", "root start ")); |
608 | 0 | DEBUGMSGOID(("subtree", root->start_a, root->start_len)); |
609 | 0 | DEBUGMSG(("subtree", " (original end ")); |
610 | 0 | DEBUGMSGOID(("subtree", root->end_a, root->end_len)); |
611 | 0 | DEBUGMSG(("subtree", ")\n")); |
612 | 0 | DEBUGMSGTL(("subtree", " JOINING to ")); |
613 | 0 | DEBUGMSGOID(("subtree", s->start_a, s->start_len)); |
614 | |
|
615 | 0 | SNMP_FREE(root->end_a); |
616 | 0 | root->end_a = s->end_a; |
617 | 0 | root->end_len = s->end_len; |
618 | 0 | s->end_a = NULL; |
619 | |
|
620 | 0 | for (c = root; c != NULL; c = c->children) { |
621 | 0 | netsnmp_subtree_change_next(c, s->next); |
622 | 0 | } |
623 | 0 | for (c = s; c != NULL; c = c->children) { |
624 | 0 | netsnmp_subtree_change_prev(c, root); |
625 | 0 | } |
626 | 0 | DEBUGMSG(("subtree", " so new end ")); |
627 | 0 | DEBUGMSGOID(("subtree", root->end_a, root->end_len)); |
628 | 0 | DEBUGMSG(("subtree", "\n")); |
629 | | /* |
630 | | * Probably need to free children too? |
631 | | */ |
632 | 0 | for (c = s->children; c != NULL; c = d) { |
633 | 0 | d = c->children; |
634 | 0 | netsnmp_subtree_free(c); |
635 | 0 | } |
636 | 0 | netsnmp_subtree_free(s); |
637 | 0 | s = tmp; |
638 | 0 | } |
639 | 0 | root = root->next; |
640 | 0 | } |
641 | 0 | } |
642 | | |
643 | | |
644 | | /** Split the subtree into two at the specified point. |
645 | | * Subtrees of the given OID and separated and formed into the |
646 | | * returned subtree. |
647 | | * |
648 | | * @param current The element at which splitting is started. |
649 | | * |
650 | | * @param name The OID we'd like to split. |
651 | | * |
652 | | * @param name_len Length of the OID. |
653 | | * |
654 | | * @return head of the new (second) subtree. |
655 | | */ |
656 | | netsnmp_subtree * |
657 | | netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len) |
658 | 0 | { |
659 | 0 | struct variable *vp = NULL; |
660 | 0 | netsnmp_subtree *new_sub, *ptr; |
661 | 0 | int i = 0, rc = 0, rc2 = 0; |
662 | 0 | size_t common_len = 0; |
663 | 0 | char *cp; |
664 | 0 | oid *tmp_a, *tmp_b; |
665 | |
|
666 | 0 | if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) { |
667 | | /* Split comes after the end of this subtree */ |
668 | 0 | return NULL; |
669 | 0 | } |
670 | | |
671 | 0 | new_sub = netsnmp_subtree_deepcopy(current); |
672 | 0 | if (new_sub == NULL) { |
673 | 0 | return NULL; |
674 | 0 | } |
675 | | |
676 | | /* Set up the point of division. */ |
677 | 0 | tmp_a = snmp_duplicate_objid(name, name_len); |
678 | 0 | if (tmp_a == NULL) { |
679 | 0 | netsnmp_subtree_free(new_sub); |
680 | 0 | return NULL; |
681 | 0 | } |
682 | 0 | tmp_b = snmp_duplicate_objid(name, name_len); |
683 | 0 | if (tmp_b == NULL) { |
684 | 0 | netsnmp_subtree_free(new_sub); |
685 | 0 | SNMP_FREE(tmp_a); |
686 | 0 | return NULL; |
687 | 0 | } |
688 | | |
689 | 0 | SNMP_FREE(current->end_a); |
690 | 0 | current->end_a = tmp_a; |
691 | 0 | current->end_len = name_len; |
692 | 0 | if (new_sub->start_a != NULL) { |
693 | 0 | SNMP_FREE(new_sub->start_a); |
694 | 0 | } |
695 | 0 | new_sub->start_a = tmp_b; |
696 | 0 | new_sub->start_len = name_len; |
697 | | |
698 | | /* Split the variables between the two new subtrees. */ |
699 | 0 | i = current->variables_len; |
700 | 0 | current->variables_len = 0; |
701 | |
|
702 | 0 | for (vp = current->variables; i > 0; i--) { |
703 | | /* Note that the variable "name" field omits the prefix common to the |
704 | | whole registration, hence the strange comparison here. */ |
705 | |
|
706 | 0 | rc = snmp_oid_compare(vp->name, vp->namelen, |
707 | 0 | name + current->namelen, |
708 | 0 | name_len - current->namelen); |
709 | |
|
710 | 0 | if (name_len - current->namelen > vp->namelen) { |
711 | 0 | common_len = vp->namelen; |
712 | 0 | } else { |
713 | 0 | common_len = name_len - current->namelen; |
714 | 0 | } |
715 | |
|
716 | 0 | rc2 = snmp_oid_compare(vp->name, common_len, |
717 | 0 | name + current->namelen, common_len); |
718 | |
|
719 | 0 | if (rc >= 0) { |
720 | 0 | break; /* All following variables belong to the second subtree */ |
721 | 0 | } |
722 | | |
723 | 0 | current->variables_len++; |
724 | 0 | if (rc2 < 0) { |
725 | 0 | new_sub->variables_len--; |
726 | 0 | cp = (char *) new_sub->variables; |
727 | 0 | new_sub->variables = (struct variable *)(cp + |
728 | 0 | new_sub->variables_width); |
729 | 0 | } |
730 | 0 | vp = (struct variable *) ((char *) vp + current->variables_width); |
731 | 0 | } |
732 | | |
733 | | /* Delegated trees should retain their variables regardless */ |
734 | 0 | if (current->variables_len > 0 && |
735 | 0 | IS_DELEGATED((u_char) current->variables[0].type)) { |
736 | 0 | new_sub->variables_len = 1; |
737 | 0 | new_sub->variables = current->variables; |
738 | 0 | } |
739 | | |
740 | | /* Propogate this split down through any children */ |
741 | 0 | if (current->children) { |
742 | 0 | new_sub->children = netsnmp_subtree_split(current->children, |
743 | 0 | name, name_len); |
744 | 0 | } |
745 | | |
746 | | /* Retain the correct linking of the list */ |
747 | 0 | for (ptr = current; ptr != NULL; ptr = ptr->children) { |
748 | 0 | netsnmp_subtree_change_next(ptr, new_sub); |
749 | 0 | } |
750 | 0 | for (ptr = new_sub; ptr != NULL; ptr = ptr->children) { |
751 | 0 | netsnmp_subtree_change_prev(ptr, current); |
752 | 0 | } |
753 | 0 | for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) { |
754 | 0 | netsnmp_subtree_change_prev(ptr, new_sub); |
755 | 0 | } |
756 | |
|
757 | 0 | return new_sub; |
758 | 0 | } |
759 | | |
760 | | /** Loads the subtree under given context name. |
761 | | * |
762 | | * @param new_sub The subtree to be loaded into current subtree. |
763 | | * |
764 | | * @param context_name Text name of the context we're searching for. |
765 | | * |
766 | | * @return gives MIB_REGISTERED_OK on success, error code otherwise. |
767 | | */ |
768 | | int |
769 | | netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name) |
770 | 15.7k | { |
771 | 15.7k | netsnmp_subtree *tree1, *tree2; |
772 | 15.7k | netsnmp_subtree *prev, *next; |
773 | | |
774 | 15.7k | if (new_sub == NULL) { |
775 | 0 | return MIB_REGISTERED_OK; /* Degenerate case */ |
776 | 0 | } |
777 | | |
778 | 15.7k | if (!netsnmp_subtree_find_first(context_name)) { |
779 | 5.23k | static int inloop = 0; |
780 | 5.23k | if (!inloop) { |
781 | 2.61k | oid ccitt[1] = { 0 }; |
782 | 2.61k | oid iso[1] = { 1 }; |
783 | 2.61k | oid joint_ccitt_iso[1] = { 2 }; |
784 | 2.61k | inloop = 1; |
785 | 2.61k | netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1, |
786 | 2.61k | context_name); |
787 | 2.61k | netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1, |
788 | 2.61k | context_name); |
789 | 2.61k | netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1), |
790 | 2.61k | 1, context_name); |
791 | 2.61k | inloop = 0; |
792 | 2.61k | } |
793 | 5.23k | } |
794 | | |
795 | | /* Find the subtree that contains the start of the new subtree (if |
796 | | any)...*/ |
797 | | |
798 | 15.7k | tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, |
799 | 15.7k | NULL, context_name); |
800 | | |
801 | | /* ... and the subtree that follows the new one (NULL implies this is the |
802 | | final region covered). */ |
803 | | |
804 | 15.7k | if (tree1 == NULL) { |
805 | 7.85k | tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len, |
806 | 7.85k | NULL, context_name); |
807 | 7.85k | } else { |
808 | 7.85k | tree2 = tree1->next; |
809 | 7.85k | } |
810 | | |
811 | | /* Handle new subtrees that start in virgin territory. */ |
812 | | |
813 | 15.7k | if (tree1 == NULL) { |
814 | | /*netsnmp_subtree *new2 = NULL;*/ |
815 | | /* Is there any overlap with later subtrees? */ |
816 | 7.85k | if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len, |
817 | 0 | tree2->start_a, tree2->start_len) > 0) { |
818 | | /*new2 =*/ |
819 | 0 | netsnmp_subtree_split(new_sub, tree2->start_a, tree2->start_len); |
820 | 0 | } |
821 | | |
822 | | /* Link the new subtree (less any overlapping region) with the list of |
823 | | existing registrations. */ |
824 | | |
825 | 7.85k | if (tree2) { |
826 | 0 | netsnmp_subtree_change_prev(new_sub, tree2->prev); |
827 | 0 | netsnmp_subtree_change_prev(tree2, new_sub); |
828 | 7.85k | } else { |
829 | 7.85k | netsnmp_subtree_change_prev(new_sub, |
830 | 7.85k | netsnmp_subtree_find_prev(new_sub->start_a, |
831 | 7.85k | new_sub->start_len, NULL, context_name)); |
832 | | |
833 | 7.85k | if (new_sub->prev) { |
834 | 5.23k | netsnmp_subtree_change_next(new_sub->prev, new_sub); |
835 | 5.23k | } else { |
836 | 2.61k | netsnmp_subtree_replace_first(new_sub, context_name); |
837 | 2.61k | } |
838 | | |
839 | 7.85k | netsnmp_subtree_change_next(new_sub, tree2); |
840 | | |
841 | | #if 0 |
842 | | /* The code below cannot be reached which is why it has been |
843 | | surrounded with #if 0 / #endif. */ |
844 | | /* If there was any overlap, recurse to merge in the overlapping |
845 | | region (including anything that may follow the overlap). */ |
846 | | if (new2) { |
847 | | return netsnmp_subtree_load(new2, context_name); |
848 | | } |
849 | | #endif |
850 | 7.85k | } |
851 | 7.85k | } else { |
852 | | /* If the new subtree starts *within* an existing registration |
853 | | (rather than at the same point as it), then split the existing |
854 | | subtree at this point. */ |
855 | | |
856 | 7.85k | if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, |
857 | 7.85k | tree1->start_a, tree1->start_len) != 0) { |
858 | 0 | tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, |
859 | 0 | new_sub->start_len); |
860 | 0 | } |
861 | | |
862 | 7.85k | if (tree1 == NULL) { |
863 | 0 | return MIB_REGISTRATION_FAILED; |
864 | 0 | } |
865 | | |
866 | | /* Now consider the end of this existing subtree: |
867 | | |
868 | | If it matches the new subtree precisely, |
869 | | simply merge the new one into the list of children |
870 | | |
871 | | If it includes the whole of the new subtree, |
872 | | split it at the appropriate point, and merge again |
873 | | |
874 | | If the new subtree extends beyond this existing region, |
875 | | split it, and recurse to merge the two parts. */ |
876 | | |
877 | 7.85k | switch (snmp_oid_compare(new_sub->end_a, new_sub->end_len, |
878 | 7.85k | tree1->end_a, tree1->end_len)) { |
879 | | |
880 | 0 | case -1: |
881 | | /* Existing subtree contains new one. */ |
882 | 0 | netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len); |
883 | 0 | NETSNMP_FALLTHROUGH; |
884 | |
|
885 | 7.85k | case 0: |
886 | | /* The two trees match precisely. */ |
887 | | |
888 | | /* Note: This is the only point where the original registration |
889 | | OID ("name") is used. */ |
890 | | |
891 | 7.85k | prev = NULL; |
892 | 7.85k | next = tree1; |
893 | | |
894 | 7.85k | while (next && next->namelen > new_sub->namelen) { |
895 | 0 | prev = next; |
896 | 0 | next = next->children; |
897 | 0 | } |
898 | | |
899 | 7.85k | while (next && next->namelen == new_sub->namelen && |
900 | 7.85k | next->priority < new_sub->priority ) { |
901 | 0 | prev = next; |
902 | 0 | next = next->children; |
903 | 0 | } |
904 | | |
905 | 7.85k | if (next && (next->namelen == new_sub->namelen) && |
906 | 7.85k | (next->priority == new_sub->priority)) { |
907 | 7.85k | if (new_sub->namelen != 1) { /* ignore root OID dups */ |
908 | 0 | size_t out_len = 0; |
909 | 0 | size_t buf_len = 0; |
910 | 0 | char *buf = NULL; |
911 | 0 | int buf_overflow = 0; |
912 | |
|
913 | 0 | netsnmp_sprint_realloc_objid((u_char **) &buf, &buf_len, &out_len, |
914 | 0 | 1, &buf_overflow, |
915 | 0 | new_sub->start_a, |
916 | 0 | new_sub->start_len); |
917 | 0 | snmp_log(LOG_ERR, |
918 | 0 | "duplicate registration: MIB modules %s and %s (oid %s%s).\n", |
919 | 0 | next->label_a, new_sub->label_a, |
920 | 0 | buf ? buf : "", |
921 | 0 | buf_overflow ? " [TRUNCATED]" : ""); |
922 | 0 | free(buf); |
923 | 0 | } |
924 | 7.85k | return MIB_DUPLICATE_REGISTRATION; |
925 | 7.85k | } |
926 | | |
927 | 0 | if (prev) { |
928 | 0 | prev->children = new_sub; |
929 | 0 | new_sub->children = next; |
930 | 0 | netsnmp_subtree_change_prev(new_sub, prev->prev); |
931 | 0 | netsnmp_subtree_change_next(new_sub, prev->next); |
932 | 0 | } else { |
933 | 0 | new_sub->children = next; |
934 | 0 | netsnmp_subtree_change_prev(new_sub, next->prev); |
935 | 0 | netsnmp_subtree_change_next(new_sub, next->next); |
936 | | |
937 | 0 | for (next = new_sub->next; next != NULL;next = next->children){ |
938 | 0 | netsnmp_subtree_change_prev(next, new_sub); |
939 | 0 | } |
940 | |
|
941 | 0 | for (prev = new_sub->prev; prev != NULL;prev = prev->children){ |
942 | 0 | netsnmp_subtree_change_next(prev, new_sub); |
943 | 0 | } |
944 | 0 | } |
945 | 0 | break; |
946 | | |
947 | 0 | case 1: |
948 | | /* New subtree contains the existing one. */ |
949 | 0 | { |
950 | 0 | netsnmp_subtree *new2 = |
951 | 0 | netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len); |
952 | 0 | int res = netsnmp_subtree_load(new_sub, context_name); |
953 | 0 | if (res != MIB_REGISTERED_OK) { |
954 | 0 | netsnmp_remove_subtree(new2); |
955 | 0 | netsnmp_subtree_free(new2); |
956 | 0 | return res; |
957 | 0 | } |
958 | 0 | return netsnmp_subtree_load(new2, context_name); |
959 | 0 | } |
960 | 7.85k | } |
961 | 7.85k | } |
962 | 7.85k | return 0; |
963 | 15.7k | } |
964 | | |
965 | | /** Free the given subtree and all its children. |
966 | | * |
967 | | * @param sub Subtree branch to be cleared and freed. |
968 | | * After the call, this pointer is invalid |
969 | | * and should be set to NULL. |
970 | | */ |
971 | | void |
972 | 0 | clear_subtree (netsnmp_subtree *sub) { |
973 | |
|
974 | 0 | netsnmp_subtree *c; |
975 | | |
976 | 0 | if (sub == NULL) |
977 | 0 | return; |
978 | | |
979 | 0 | for(c = sub; c;) { |
980 | 0 | sub = c; |
981 | 0 | c = c->children; |
982 | 0 | netsnmp_subtree_free(sub); |
983 | 0 | } |
984 | |
|
985 | 0 | } |
986 | | |
987 | | netsnmp_subtree * |
988 | | netsnmp_subtree_find_prev(const oid *name, size_t len, netsnmp_subtree *subtree, |
989 | | const char *context_name) |
990 | 47.9k | { |
991 | 47.9k | lookup_cache *lookup_cache = NULL; |
992 | 47.9k | netsnmp_subtree *myptr = NULL, *previous = NULL; |
993 | 47.9k | int cmp = 1; |
994 | 47.9k | size_t ll_off = 0; |
995 | | |
996 | 47.9k | if (subtree) { |
997 | 7.85k | myptr = subtree; |
998 | 40.1k | } else { |
999 | | /* look through everything */ |
1000 | 40.1k | if (lookup_cache_size) { |
1001 | 8.69k | lookup_cache = lookup_cache_find(context_name, name, len, &cmp); |
1002 | 8.69k | if (lookup_cache) { |
1003 | 628 | myptr = lookup_cache->next; |
1004 | 628 | previous = lookup_cache->previous; |
1005 | 628 | } |
1006 | 8.69k | if (!myptr) |
1007 | 8.06k | myptr = netsnmp_subtree_find_first(context_name); |
1008 | 31.4k | } else { |
1009 | 31.4k | myptr = netsnmp_subtree_find_first(context_name); |
1010 | 31.4k | } |
1011 | 40.1k | } |
1012 | | |
1013 | | /* |
1014 | | * this optimization causes a segfault on sf cf alpha-linux1. |
1015 | | * ifdef out until someone figures out why and fixes it. xxx-rks 20051117 |
1016 | | */ |
1017 | 47.9k | #ifndef __alpha |
1018 | 47.9k | #define WTEST_OPTIMIZATION 1 |
1019 | 47.9k | #endif |
1020 | 47.9k | #ifdef WTEST_OPTIMIZATION |
1021 | 47.9k | DEBUGMSGTL(("wtest","oid in: ")); |
1022 | 47.9k | DEBUGMSGOID(("wtest", name, len)); |
1023 | 47.9k | DEBUGMSG(("wtest","\n")); |
1024 | 47.9k | #endif |
1025 | 119k | for (; myptr != NULL; previous = myptr, myptr = myptr->next) { |
1026 | 77.2k | #ifdef WTEST_OPTIMIZATION |
1027 | | /* Compare the incoming oid with the linked list. If we have |
1028 | | results of previous compares, its faster to make sure the |
1029 | | length we differed in the last check is greater than the |
1030 | | length between this pointer and the last then we don't need |
1031 | | to actually perform a comparison */ |
1032 | 77.2k | DEBUGMSGTL(("wtest","oid cmp: ")); |
1033 | 77.2k | DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len)); |
1034 | 77.2k | DEBUGMSG(("wtest"," --- off = %lu, in off = %lu test = %d\n", |
1035 | 77.2k | (unsigned long)myptr->oid_off, (unsigned long)ll_off, |
1036 | 77.2k | !(ll_off && myptr->oid_off && |
1037 | 77.2k | myptr->oid_off > ll_off))); |
1038 | 77.2k | if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) && |
1039 | 77.2k | netsnmp_oid_compare_ll(name, len, |
1040 | 77.2k | myptr->start_a, myptr->start_len, |
1041 | 77.2k | &ll_off) < 0) { |
1042 | | #else |
1043 | | if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) { |
1044 | | #endif |
1045 | 5.86k | if (lookup_cache_size && previous && cmp) { |
1046 | 631 | if (lookup_cache) { |
1047 | 335 | lookup_cache_replace(lookup_cache, myptr, previous); |
1048 | 335 | } else { |
1049 | 296 | lookup_cache_add(context_name, myptr, previous); |
1050 | 296 | } |
1051 | 631 | } |
1052 | 5.86k | return previous; |
1053 | 5.86k | } |
1054 | 77.2k | } |
1055 | 42.0k | return previous; |
1056 | 47.9k | } |
1057 | | |
1058 | | netsnmp_subtree * |
1059 | | netsnmp_subtree_find_next(const oid *name, size_t len, |
1060 | | netsnmp_subtree *subtree, const char *context_name) |
1061 | 7.85k | { |
1062 | 7.85k | netsnmp_subtree *myptr = NULL; |
1063 | | |
1064 | 7.85k | myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); |
1065 | | |
1066 | 7.85k | if (myptr != NULL) { |
1067 | 5.23k | myptr = myptr->next; |
1068 | 5.23k | while (myptr != NULL && (myptr->variables == NULL || |
1069 | 0 | myptr->variables_len == 0)) { |
1070 | 0 | myptr = myptr->next; |
1071 | 0 | } |
1072 | 5.23k | return myptr; |
1073 | 5.23k | } else if (subtree != NULL && snmp_oid_compare(name, len, |
1074 | 0 | subtree->start_a, subtree->start_len) < 0) { |
1075 | 0 | return subtree; |
1076 | 2.61k | } else { |
1077 | 2.61k | return NULL; |
1078 | 2.61k | } |
1079 | 7.85k | } |
1080 | | |
1081 | | netsnmp_subtree * |
1082 | | netsnmp_subtree_find(const oid *name, size_t len, netsnmp_subtree *subtree, |
1083 | | const char *context_name) |
1084 | 32.2k | { |
1085 | 32.2k | netsnmp_subtree *myptr; |
1086 | | |
1087 | 32.2k | myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); |
1088 | 32.2k | if (myptr && myptr->end_a && |
1089 | 32.2k | snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) { |
1090 | 24.4k | return myptr; |
1091 | 24.4k | } |
1092 | | |
1093 | 7.85k | return NULL; |
1094 | 32.2k | } |
1095 | | |
1096 | | /** @} */ |
1097 | | /* End of Subtrees maintaining code */ |
1098 | | |
1099 | | /** @defgroup agent_mib_registering Registering and unregistering MIB subtrees. |
1100 | | * Adding and removing MIB nodes to the database under their contexts. |
1101 | | * @ingroup agent_registry |
1102 | | * |
1103 | | * @{ |
1104 | | */ |
1105 | | |
1106 | | |
1107 | | /** Registers a MIB handler. |
1108 | | * |
1109 | | * @param moduleName |
1110 | | * @param var |
1111 | | * @param varsize |
1112 | | * @param numvars |
1113 | | * @param mibloc |
1114 | | * @param mibloclen |
1115 | | * @param priority |
1116 | | * @param range_subid |
1117 | | * @param range_ubound |
1118 | | * @param ss |
1119 | | * @param context |
1120 | | * @param timeout |
1121 | | * @param flags |
1122 | | * @param reginfo Registration handler structure. |
1123 | | * In a case of failure, it will be freed. |
1124 | | * @param perform_callback |
1125 | | * |
1126 | | * @return gives MIB_REGISTERED_OK or MIB_* error code. |
1127 | | * |
1128 | | * @see netsnmp_register_handler() |
1129 | | * @see register_agentx_list() |
1130 | | * @see netsnmp_handler_registration_free() |
1131 | | */ |
1132 | | int |
1133 | | netsnmp_register_mib(const char *moduleName, |
1134 | | struct variable *var, |
1135 | | size_t varsize, |
1136 | | size_t numvars, |
1137 | | oid * mibloc, |
1138 | | size_t mibloclen, |
1139 | | int priority, |
1140 | | int range_subid, |
1141 | | oid range_ubound, |
1142 | | netsnmp_session * ss, |
1143 | | const char *context, |
1144 | | int timeout, |
1145 | | int flags, |
1146 | | netsnmp_handler_registration *reginfo, |
1147 | | int perform_callback) |
1148 | 15.7k | { |
1149 | 15.7k | netsnmp_subtree *subtree, *sub2; |
1150 | 15.7k | int res; |
1151 | 15.7k | struct register_parameters reg_parms; |
1152 | 15.7k | int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); |
1153 | | |
1154 | 15.7k | if (moduleName == NULL || |
1155 | 15.7k | mibloc == NULL) { |
1156 | | /* Shouldn't happen ??? */ |
1157 | 0 | netsnmp_handler_registration_free(reginfo); |
1158 | 0 | return MIB_REGISTRATION_FAILED; |
1159 | 0 | } |
1160 | 15.7k | subtree = calloc(1, sizeof(netsnmp_subtree)); |
1161 | 15.7k | if (subtree == NULL) { |
1162 | 0 | netsnmp_handler_registration_free(reginfo); |
1163 | 0 | return MIB_REGISTRATION_FAILED; |
1164 | 0 | } |
1165 | | |
1166 | 15.7k | DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); |
1167 | 15.7k | DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid, |
1168 | 15.7k | range_ubound)); |
1169 | 15.7k | DEBUGMSG(("register_mib", " with context \"%s\"\n", |
1170 | 15.7k | SNMP_STRORNULL(context))); |
1171 | | |
1172 | | /* |
1173 | | * verify that the passed context is equal to the context |
1174 | | * in the reginfo. |
1175 | | * (which begs the question, why do we have both? It appears that the |
1176 | | * reginfo item didn't appear til 5.2) |
1177 | | */ |
1178 | 15.7k | if( ((NULL == context) && (NULL != reginfo->contextName)) || |
1179 | 15.7k | ((NULL != context) && (NULL == reginfo->contextName)) || |
1180 | 15.7k | ( ((NULL != context) && (NULL != reginfo->contextName)) && |
1181 | 15.7k | (0 != strcmp(context, reginfo->contextName))) ) { |
1182 | 0 | snmp_log(LOG_WARNING,"context passed during registration does not " |
1183 | 0 | "equal the reginfo contextName! ('%s' != '%s')\n", |
1184 | 0 | context, reginfo->contextName); |
1185 | 0 | netsnmp_assert(!"register context == reginfo->contextName"); /* always false */ |
1186 | 0 | } |
1187 | | |
1188 | | /* Create the new subtree node being registered. */ |
1189 | | |
1190 | 15.7k | subtree->reginfo = reginfo; |
1191 | 15.7k | subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen); |
1192 | 15.7k | subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen); |
1193 | 15.7k | subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen); |
1194 | 15.7k | subtree->label_a = strdup(moduleName); |
1195 | 15.7k | if (subtree->name_a == NULL || subtree->start_a == NULL || |
1196 | 15.7k | subtree->end_a == NULL || subtree->label_a == NULL) { |
1197 | 0 | netsnmp_subtree_free(subtree); /* also frees reginfo */ |
1198 | 0 | return MIB_REGISTRATION_FAILED; |
1199 | 0 | } |
1200 | 15.7k | subtree->namelen = (u_char)mibloclen; |
1201 | 15.7k | subtree->start_len = (u_char)mibloclen; |
1202 | 15.7k | subtree->end_len = (u_char)mibloclen; |
1203 | 15.7k | subtree->end_a[mibloclen - 1]++; |
1204 | | |
1205 | 15.7k | if (var != NULL) { |
1206 | 0 | subtree->variables = (struct variable *)malloc(varsize*numvars); |
1207 | 0 | if (subtree->variables == NULL) { |
1208 | 0 | netsnmp_subtree_free(subtree); /* also frees reginfo */ |
1209 | 0 | return MIB_REGISTRATION_FAILED; |
1210 | 0 | } |
1211 | 0 | memcpy(subtree->variables, var, numvars*varsize); |
1212 | 0 | subtree->variables_len = numvars; |
1213 | 0 | subtree->variables_width = varsize; |
1214 | 0 | } |
1215 | 15.7k | subtree->priority = priority; |
1216 | 15.7k | subtree->timeout = timeout; |
1217 | 15.7k | subtree->range_subid = range_subid; |
1218 | 15.7k | subtree->range_ubound = range_ubound; |
1219 | 15.7k | subtree->session = ss; |
1220 | 15.7k | subtree->flags = (u_char)flags; /* used to identify instance oids */ |
1221 | 15.7k | subtree->flags |= SUBTREE_ATTACHED; |
1222 | 15.7k | subtree->global_cacheid = reginfo->global_cacheid; |
1223 | | |
1224 | 15.7k | netsnmp_set_lookup_cache_size(0); |
1225 | 15.7k | res = netsnmp_subtree_load(subtree, context); |
1226 | | |
1227 | | /* If registering a range, use the first subtree as a template for the |
1228 | | rest of the range. */ |
1229 | | |
1230 | 15.7k | if (res == MIB_REGISTERED_OK && range_subid != 0) { |
1231 | 0 | int i; |
1232 | 0 | for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) { |
1233 | 0 | sub2 = netsnmp_subtree_deepcopy(subtree); |
1234 | |
|
1235 | 0 | if (sub2 == NULL) { |
1236 | 0 | unregister_mib_context(mibloc, mibloclen, priority, |
1237 | 0 | range_subid, range_ubound, context); |
1238 | 0 | netsnmp_set_lookup_cache_size(old_lookup_cache_val); |
1239 | 0 | invalidate_lookup_cache(context); |
1240 | 0 | return MIB_REGISTRATION_FAILED; |
1241 | 0 | } |
1242 | | |
1243 | 0 | sub2->name_a[range_subid - 1] = i; |
1244 | 0 | sub2->start_a[range_subid - 1] = i; |
1245 | 0 | sub2->end_a[range_subid - 1] = i; /* XXX - ???? */ |
1246 | 0 | if (range_subid == (int)mibloclen) { |
1247 | 0 | ++sub2->end_a[range_subid - 1]; |
1248 | 0 | } |
1249 | 0 | sub2->flags |= SUBTREE_ATTACHED; |
1250 | 0 | sub2->global_cacheid = reginfo->global_cacheid; |
1251 | | /* FRQ This is essential for requests to succeed! */ |
1252 | 0 | sub2->reginfo->rootoid[range_subid - 1] = i; |
1253 | |
|
1254 | 0 | res = netsnmp_subtree_load(sub2, context); |
1255 | 0 | if (res != MIB_REGISTERED_OK) { |
1256 | 0 | unregister_mib_context(mibloc, mibloclen, priority, |
1257 | 0 | range_subid, range_ubound, context); |
1258 | 0 | netsnmp_remove_subtree(sub2); |
1259 | 0 | netsnmp_subtree_free(sub2); |
1260 | 0 | netsnmp_set_lookup_cache_size(old_lookup_cache_val); |
1261 | 0 | invalidate_lookup_cache(context); |
1262 | 0 | return res; |
1263 | 0 | } |
1264 | 0 | } |
1265 | 15.7k | } else if (res == MIB_DUPLICATE_REGISTRATION || |
1266 | 15.7k | res == MIB_REGISTRATION_FAILED) { |
1267 | 7.85k | netsnmp_set_lookup_cache_size(old_lookup_cache_val); |
1268 | 7.85k | invalidate_lookup_cache(context); |
1269 | 7.85k | netsnmp_subtree_free(subtree); |
1270 | 7.85k | return res; |
1271 | 7.85k | } |
1272 | | |
1273 | | /* |
1274 | | * mark the MIB as detached, if there's no master agent present as of now |
1275 | | */ |
1276 | 7.85k | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
1277 | 7.85k | NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { |
1278 | 0 | if (main_session == NULL) { |
1279 | 0 | register_mib_detach_node(subtree); |
1280 | 0 | } |
1281 | 0 | } |
1282 | | |
1283 | 7.85k | if (res == MIB_REGISTERED_OK && perform_callback) { |
1284 | 7.85k | memset(®_parms, 0x0, sizeof(reg_parms)); |
1285 | 7.85k | reg_parms.name = mibloc; |
1286 | 7.85k | reg_parms.namelen = mibloclen; |
1287 | 7.85k | reg_parms.priority = priority; |
1288 | 7.85k | reg_parms.range_subid = range_subid; |
1289 | 7.85k | reg_parms.range_ubound = range_ubound; |
1290 | 7.85k | reg_parms.timeout = timeout; |
1291 | 7.85k | reg_parms.flags = (u_char) flags; |
1292 | 7.85k | reg_parms.session = ss; |
1293 | 7.85k | reg_parms.reginfo = reginfo; |
1294 | 7.85k | reg_parms.contextName = context; |
1295 | 7.85k | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
1296 | 7.85k | SNMPD_CALLBACK_REGISTER_OID, ®_parms); |
1297 | 7.85k | } |
1298 | | |
1299 | 7.85k | netsnmp_set_lookup_cache_size(old_lookup_cache_val); |
1300 | 7.85k | invalidate_lookup_cache(context); |
1301 | 7.85k | return res; |
1302 | 15.7k | } |
1303 | | |
1304 | | /** @private |
1305 | | * Reattach a particular node. |
1306 | | */ |
1307 | | static void |
1308 | | register_mib_reattach_node(netsnmp_subtree *s) |
1309 | 0 | { |
1310 | 0 | if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) { |
1311 | 0 | struct register_parameters reg_parms; |
1312 | | /* |
1313 | | * only do registrations that are not the top level nodes |
1314 | | */ |
1315 | 0 | memset(®_parms, 0x0, sizeof(reg_parms)); |
1316 | | |
1317 | | /* |
1318 | | * XXX: do this better |
1319 | | */ |
1320 | 0 | reg_parms.name = s->name_a; |
1321 | 0 | reg_parms.namelen = s->namelen; |
1322 | 0 | reg_parms.priority = s->priority; |
1323 | 0 | reg_parms.range_subid = s->range_subid; |
1324 | 0 | reg_parms.range_ubound = s->range_ubound; |
1325 | 0 | reg_parms.timeout = s->timeout; |
1326 | 0 | reg_parms.flags = s->flags; |
1327 | 0 | reg_parms.session = s->session; |
1328 | 0 | reg_parms.reginfo = s->reginfo; |
1329 | | /* XXX: missing in subtree: reg_parms.contextName = s->context; */ |
1330 | 0 | if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName)) |
1331 | 0 | reg_parms.contextName = s->reginfo->contextName; |
1332 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
1333 | 0 | SNMPD_CALLBACK_REGISTER_OID, ®_parms); |
1334 | 0 | s->flags |= SUBTREE_ATTACHED; |
1335 | 0 | } |
1336 | 0 | } |
1337 | | |
1338 | | /** Call callbacks to reattach all our nodes. |
1339 | | */ |
1340 | | void |
1341 | | register_mib_reattach(void) |
1342 | 0 | { |
1343 | 0 | netsnmp_subtree *s, *t; |
1344 | 0 | subtree_context_cache *ptr; |
1345 | |
|
1346 | 0 | for (ptr = context_subtrees; ptr; ptr = ptr->next) { |
1347 | 0 | for (s = ptr->first_subtree; s != NULL; s = s->next) { |
1348 | 0 | register_mib_reattach_node(s); |
1349 | 0 | for (t = s->children; t != NULL; t = t->children) { |
1350 | 0 | register_mib_reattach_node(t); |
1351 | 0 | } |
1352 | 0 | } |
1353 | 0 | } |
1354 | 0 | } |
1355 | | |
1356 | | /** @private |
1357 | | * Mark a node as detached. |
1358 | | * |
1359 | | * @param s The note to be marked |
1360 | | */ |
1361 | | static void |
1362 | | register_mib_detach_node(netsnmp_subtree *s) |
1363 | 0 | { |
1364 | 0 | if (s != NULL) { |
1365 | 0 | s->flags = s->flags & ~SUBTREE_ATTACHED; |
1366 | 0 | } |
1367 | 0 | } |
1368 | | |
1369 | | /** Mark all our registered OIDs as detached. |
1370 | | * This is only really useful for subagent protocols, when |
1371 | | * a connection is lost or the subagent is being shut down. |
1372 | | */ |
1373 | | void |
1374 | | register_mib_detach(void) |
1375 | 0 | { |
1376 | 0 | netsnmp_subtree *s, *t; |
1377 | 0 | subtree_context_cache *ptr; |
1378 | 0 | for (ptr = context_subtrees; ptr; ptr = ptr->next) { |
1379 | 0 | for (s = ptr->first_subtree; s != NULL; s = s->next) { |
1380 | 0 | register_mib_detach_node(s); |
1381 | 0 | for (t = s->children; t != NULL; t = t->children) { |
1382 | 0 | register_mib_detach_node(t); |
1383 | 0 | } |
1384 | 0 | } |
1385 | 0 | } |
1386 | 0 | } |
1387 | | |
1388 | | /** Register a new module into the MIB database, with all possible custom options |
1389 | | * |
1390 | | * @param moduleName Text name of the module. |
1391 | | * The given name will be used to identify the module |
1392 | | * inside the agent. |
1393 | | * |
1394 | | * @param var Array of variables to be registered in the module. |
1395 | | * |
1396 | | * @param varsize Size of a single variable in var array. |
1397 | | * The size is normally equal to sizeof(struct variable), |
1398 | | * but if we wish to use shorter (or longer) OIDs, then we |
1399 | | * could use different variant of the variable structure. |
1400 | | * |
1401 | | * @param numvars Number of variables in the var array. |
1402 | | * This is how many variables the function will try to register. |
1403 | | * |
1404 | | * @param mibloc Base OID of the module. |
1405 | | * All OIDs in var array should be sub-oids of the base OID. |
1406 | | * |
1407 | | * @param mibloclen Length of the base OID. |
1408 | | * Number of integers making up the base OID. |
1409 | | * |
1410 | | * @param priority Registration priority. |
1411 | | * Used to achieve a desired configuration when different |
1412 | | * sessions register identical or overlapping regions. |
1413 | | * Primarily used with AgentX subagent registrations. |
1414 | | * |
1415 | | * @param range_subid If non-zero, the module is registered against a range |
1416 | | * of OIDs, with this parameter identifying the relevant |
1417 | | * subidentifier - see RFC 2741 for details. |
1418 | | * Typically used to register a single row of a table. |
1419 | | * If zero, then register the module against the full OID subtree. |
1420 | | * |
1421 | | * @param range_ubound The end of the range being registered (see RFC 2741) |
1422 | | * If range_subid is zero, then this parameter is ignored. |
1423 | | * |
1424 | | * @param ss |
1425 | | * @param context |
1426 | | * @param timeout |
1427 | | * @param flags |
1428 | | * |
1429 | | * @return gives SNMPERR_SUCCESS or SNMPERR_* error code. |
1430 | | * |
1431 | | * @see register_mib() |
1432 | | * @see register_mib_priority() |
1433 | | * @see register_mib_range() |
1434 | | * @see unregister_mib() |
1435 | | */ |
1436 | | int |
1437 | | register_mib_context(const char *moduleName, |
1438 | | const struct variable *var, |
1439 | | size_t varsize, |
1440 | | size_t numvars, |
1441 | | const oid * mibloc, |
1442 | | size_t mibloclen, |
1443 | | int priority, |
1444 | | int range_subid, |
1445 | | oid range_ubound, |
1446 | | netsnmp_session * ss, |
1447 | | const char *context, int timeout, int flags) |
1448 | 0 | { |
1449 | 0 | return netsnmp_register_old_api(moduleName, var, varsize, numvars, |
1450 | 0 | mibloc, mibloclen, priority, |
1451 | 0 | range_subid, range_ubound, ss, context, |
1452 | 0 | timeout, flags); |
1453 | 0 | } |
1454 | | |
1455 | | /** Register a new module into the MIB database, as being responsible |
1456 | | * for a range of OIDs (typically a single row of a table). |
1457 | | * |
1458 | | * @param moduleName Text name of the module. |
1459 | | * The given name will be used to identify the module |
1460 | | * inside the agent. |
1461 | | * |
1462 | | * @param var Array of variables to be registered in the module. |
1463 | | * |
1464 | | * @param varsize Size of a single variable in var array. |
1465 | | * The size is normally equal to sizeof(struct variable), |
1466 | | * but if we wish to use shorter (or longer) OIDs, then we |
1467 | | * could use different variant of the variable structure. |
1468 | | * |
1469 | | * @param numvars Number of variables in the var array. |
1470 | | * This is how many variables the function will try to register. |
1471 | | * |
1472 | | * @param mibloc Base OID of the module. |
1473 | | * All OIDs in var array should be sub-oids of the base OID. |
1474 | | * |
1475 | | * @param mibloclen Length of the base OID. |
1476 | | * Number of integers making up the base OID. |
1477 | | * |
1478 | | * @param priority Registration priority. |
1479 | | * Used to achieve a desired configuration when different |
1480 | | * sessions register identical or overlapping regions. |
1481 | | * Primarily used with AgentX subagent registrations. |
1482 | | * |
1483 | | * @param range_subid If non-zero, the module is registered against a range |
1484 | | * of OIDs, with this parameter identifying the relevant |
1485 | | * subidentifier - see RFC 2741 for details. |
1486 | | * Typically used to register a single row of a table. |
1487 | | * If zero, then register the module against the full OID subtree. |
1488 | | * |
1489 | | * @param range_ubound The end of the range being registered (see RFC 2741) |
1490 | | * If range_subid is zero, then this parameter is ignored. |
1491 | | * |
1492 | | * @param ss |
1493 | | * |
1494 | | * @return gives SNMPERR_SUCCESS or SNMPERR_* error code. |
1495 | | * |
1496 | | * @see register_mib() |
1497 | | * @see register_mib_priority() |
1498 | | * @see register_mib_context() |
1499 | | * @see unregister_mib() |
1500 | | */ |
1501 | | int |
1502 | | register_mib_range(const char *moduleName, |
1503 | | const struct variable *var, |
1504 | | size_t varsize, |
1505 | | size_t numvars, |
1506 | | const oid * mibloc, |
1507 | | size_t mibloclen, |
1508 | | int priority, |
1509 | | int range_subid, oid range_ubound, netsnmp_session * ss) |
1510 | 0 | { |
1511 | 0 | return register_mib_context(moduleName, var, varsize, numvars, |
1512 | 0 | mibloc, mibloclen, priority, |
1513 | 0 | range_subid, range_ubound, ss, "", -1, 0); |
1514 | 0 | } |
1515 | | |
1516 | | /** Register a new module into the MIB database, with a non-default priority |
1517 | | * |
1518 | | * @param moduleName Text name of the module. |
1519 | | * The given name will be used to identify the module |
1520 | | * inside the agent. |
1521 | | * |
1522 | | * @param var Array of variables to be registered in the module. |
1523 | | * |
1524 | | * @param varsize Size of a single variable in var array. |
1525 | | * The size is normally equal to sizeof(struct variable), |
1526 | | * but if we wish to use shorter (or longer) OIDs, then we |
1527 | | * could use different variant of the variable structure. |
1528 | | * |
1529 | | * @param numvars Number of variables in the var array. |
1530 | | * This is how many variables the function will try to register. |
1531 | | * |
1532 | | * @param mibloc Base OID of the module. |
1533 | | * All OIDs in var array should be sub-oids of the base OID. |
1534 | | * |
1535 | | * @param mibloclen Length of the base OID. |
1536 | | * Number of integers making up the base OID. |
1537 | | * |
1538 | | * @param priority Registration priority. |
1539 | | * Used to achieve a desired configuration when different |
1540 | | * sessions register identical or overlapping regions. |
1541 | | * Primarily used with AgentX subagent registrations. |
1542 | | * |
1543 | | * @return gives SNMPERR_SUCCESS or SNMPERR_* error code. |
1544 | | * |
1545 | | * @see register_mib() |
1546 | | * @see register_mib_range() |
1547 | | * @see register_mib_context() |
1548 | | * @see unregister_mib() |
1549 | | */ |
1550 | | int |
1551 | | register_mib_priority(const char *moduleName, |
1552 | | const struct variable *var, |
1553 | | size_t varsize, |
1554 | | size_t numvars, |
1555 | | const oid * mibloc, size_t mibloclen, int priority) |
1556 | 0 | { |
1557 | 0 | return register_mib_range(moduleName, var, varsize, numvars, |
1558 | 0 | mibloc, mibloclen, priority, 0, 0, NULL); |
1559 | 0 | } |
1560 | | |
1561 | | /** Register a new module into the MIB database, using default priority and context |
1562 | | * |
1563 | | * @param moduleName Text name of the module. |
1564 | | * The given name will be used to identify the module |
1565 | | * inside the agent. |
1566 | | * |
1567 | | * @param var Array of variables to be registered in the module. |
1568 | | * |
1569 | | * @param varsize Size of a single variable in var array. |
1570 | | * The size is normally equal to sizeof(struct variable), |
1571 | | * but if we wish to use shorter (or longer) OIDs, then we |
1572 | | * could use different variant of the variable structure. |
1573 | | * |
1574 | | * @param numvars Number of variables in the var array. |
1575 | | * This is how many variables the function will try to register. |
1576 | | * |
1577 | | * @param mibloc Base OID of the module. |
1578 | | * All OIDs in var array should be sub-oids of the base OID. |
1579 | | * |
1580 | | * @param mibloclen Length of the base OID. |
1581 | | * Number of integers making up the base OID. |
1582 | | * |
1583 | | * @return gives SNMPERR_SUCCESS or SNMPERR_* error code. |
1584 | | * |
1585 | | * @see register_mib_priority() |
1586 | | * @see register_mib_range() |
1587 | | * @see register_mib_context() |
1588 | | * @see unregister_mib() |
1589 | | */ |
1590 | | int |
1591 | | register_mib(const char *moduleName, |
1592 | | const struct variable *var, |
1593 | | size_t varsize, |
1594 | | size_t numvars, const oid * mibloc, size_t mibloclen) |
1595 | 0 | { |
1596 | 0 | return register_mib_priority(moduleName, var, varsize, numvars, |
1597 | 0 | mibloc, mibloclen, DEFAULT_MIB_PRIORITY); |
1598 | 0 | } |
1599 | | |
1600 | | /** @private |
1601 | | * Unloads a subtree from MIB tree. |
1602 | | * |
1603 | | * @param sub The sub-tree which is being removed. |
1604 | | * |
1605 | | * @param prev Previous entry, before the unloaded one. |
1606 | | * |
1607 | | * @param context Name of the context which is being removed. |
1608 | | * |
1609 | | * @see unregister_mib_context() |
1610 | | */ |
1611 | | void |
1612 | | netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context) |
1613 | 7.85k | { |
1614 | 7.85k | netsnmp_subtree *ptr; |
1615 | | |
1616 | 7.85k | DEBUGMSGTL(("register_mib", "unload(")); |
1617 | 7.85k | if (sub != NULL) { |
1618 | 7.85k | DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len)); |
1619 | 7.85k | } else { |
1620 | 0 | DEBUGMSG(("register_mib", "[NIL]")); |
1621 | 0 | return; |
1622 | 0 | } |
1623 | 7.85k | DEBUGMSG(("register_mib", ", ")); |
1624 | 7.85k | if (prev != NULL) { |
1625 | 0 | DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len)); |
1626 | 7.85k | } else { |
1627 | 7.85k | DEBUGMSG(("register_mib", "[NIL]")); |
1628 | 7.85k | } |
1629 | 7.85k | DEBUGMSG(("register_mib", ")\n")); |
1630 | | |
1631 | 7.85k | if (prev != NULL) { /* non-leading entries are easy */ |
1632 | 0 | prev->children = sub->children; |
1633 | 0 | invalidate_lookup_cache(context); |
1634 | 0 | return; |
1635 | 0 | } |
1636 | | /* |
1637 | | * otherwise, we need to amend our neighbours as well |
1638 | | */ |
1639 | | |
1640 | 7.85k | if (sub->children == NULL) { /* just remove this node completely */ |
1641 | 13.0k | for (ptr = sub->prev; ptr; ptr = ptr->children) { |
1642 | 5.23k | netsnmp_subtree_change_next(ptr, sub->next); |
1643 | 5.23k | } |
1644 | 7.85k | for (ptr = sub->next; ptr; ptr = ptr->children) { |
1645 | 0 | netsnmp_subtree_change_prev(ptr, sub->prev); |
1646 | 0 | } |
1647 | | |
1648 | 7.85k | if (sub->prev == NULL) { |
1649 | 2.61k | netsnmp_subtree_replace_first(sub->next, context); |
1650 | 2.61k | } |
1651 | | |
1652 | 7.85k | } else { |
1653 | 0 | for (ptr = sub->prev; ptr; ptr = ptr->children) |
1654 | 0 | netsnmp_subtree_change_next(ptr, sub->children); |
1655 | 0 | for (ptr = sub->next; ptr; ptr = ptr->children) |
1656 | 0 | netsnmp_subtree_change_prev(ptr, sub->children); |
1657 | |
|
1658 | 0 | if (sub->prev == NULL) { |
1659 | 0 | netsnmp_subtree_replace_first(sub->children, context); |
1660 | 0 | } |
1661 | 0 | } |
1662 | 7.85k | invalidate_lookup_cache(context); |
1663 | 7.85k | } |
1664 | | |
1665 | | /** |
1666 | | * Unregisters a module registered against a given OID (or range) in a specified context. |
1667 | | * Typically used when a module has multiple contexts defined. |
1668 | | * The parameters priority, range_subid, range_ubound and context |
1669 | | * should match those used to register the module originally. |
1670 | | * |
1671 | | * @param name the specific OID to unregister if it conatins the associated |
1672 | | * context. |
1673 | | * |
1674 | | * @param len the length of the OID, use OID_LENGTH macro. |
1675 | | * |
1676 | | * @param priority a value between 1 and 255, used to achieve a desired |
1677 | | * configuration when different sessions register identical or |
1678 | | * overlapping regions. Subagents with no particular |
1679 | | * knowledge of priority should register with the default |
1680 | | * value of 127. |
1681 | | * |
1682 | | * @param range_subid permits specifying a range in place of one of a subtree |
1683 | | * sub-identifiers. When this value is zero, no range is |
1684 | | * being specified. |
1685 | | * |
1686 | | * @param range_ubound the upper bound of a sub-identifier's range. |
1687 | | * This field is present only if range_subid is not 0. |
1688 | | * |
1689 | | * @param context a context name that has been created |
1690 | | * |
1691 | | * @return gives MIB_UNREGISTERED_OK or MIB_* error code. |
1692 | | * |
1693 | | * @see unregister_mib() |
1694 | | * @see unregister_mib_priority() |
1695 | | * @see unregister_mib_range() |
1696 | | */ |
1697 | | int |
1698 | | unregister_mib_context(oid * name, size_t len, int priority, |
1699 | | int range_subid, oid range_ubound, |
1700 | | const char *context) |
1701 | 7.85k | { |
1702 | 7.85k | netsnmp_subtree *list, *myptr = NULL; |
1703 | 7.85k | netsnmp_subtree *prev, *child, *next; /* loop through children */ |
1704 | 7.85k | struct register_parameters reg_parms; |
1705 | 7.85k | int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); |
1706 | 7.85k | int unregistering = 1; |
1707 | 7.85k | int orig_subid_val = -1; |
1708 | | |
1709 | 7.85k | netsnmp_set_lookup_cache_size(0); |
1710 | | |
1711 | 7.85k | if ((range_subid > 0) && ((size_t)range_subid <= len)) |
1712 | 0 | orig_subid_val = name[range_subid-1]; |
1713 | | |
1714 | 15.7k | while(unregistering){ |
1715 | 7.85k | DEBUGMSGTL(("register_mib", "unregistering ")); |
1716 | 7.85k | DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound)); |
1717 | 7.85k | DEBUGMSG(("register_mib", "\n")); |
1718 | | |
1719 | 7.85k | list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context), |
1720 | 7.85k | context); |
1721 | 7.85k | if (list == NULL) { |
1722 | 0 | return MIB_NO_SUCH_REGISTRATION; |
1723 | 0 | } |
1724 | | |
1725 | 7.85k | for (child = list, prev = NULL; child != NULL; |
1726 | 7.85k | prev = child, child = child->children) { |
1727 | 7.85k | if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 && |
1728 | 7.85k | child->priority == priority) { |
1729 | 7.85k | break; /* found it */ |
1730 | 7.85k | } |
1731 | 7.85k | } |
1732 | | |
1733 | 7.85k | if (child == NULL) { |
1734 | 0 | return MIB_NO_SUCH_REGISTRATION; |
1735 | 0 | } |
1736 | | |
1737 | 7.85k | netsnmp_subtree_unload(child, prev, context); |
1738 | 7.85k | myptr = child; /* remember this for later */ |
1739 | | |
1740 | | /* |
1741 | | * Now handle any occurances in the following subtrees, |
1742 | | * as a result of splitting this range. Due to the |
1743 | | * nature of the way such splits work, the first |
1744 | | * subtree 'slice' that doesn't refer to the given |
1745 | | * name marks the end of the original region. |
1746 | | * |
1747 | | * This should also serve to register ranges. |
1748 | | */ |
1749 | | |
1750 | 7.85k | for (list = myptr->next; list != NULL; list = next) { |
1751 | 0 | next = list->next; /* list gets freed sometimes; cache next */ |
1752 | 0 | for (child = list, prev = NULL; child != NULL; |
1753 | 0 | prev = child, child = child->children) { |
1754 | 0 | if ((netsnmp_oid_equals(child->name_a, child->namelen, |
1755 | 0 | name, len) == 0) && |
1756 | 0 | (child->priority == priority)) { |
1757 | 0 | netsnmp_subtree_unload(child, prev, context); |
1758 | 0 | netsnmp_subtree_free(child); |
1759 | 0 | break; |
1760 | 0 | } |
1761 | 0 | } |
1762 | 0 | if (child == NULL) /* Didn't find the given name */ |
1763 | 0 | break; |
1764 | 0 | } |
1765 | | |
1766 | | /* Maybe we are in a range... */ |
1767 | 7.85k | if (orig_subid_val != -1){ |
1768 | 0 | if (++name[range_subid-1] >= orig_subid_val+range_ubound) |
1769 | 0 | { |
1770 | 0 | unregistering=0; |
1771 | 0 | name[range_subid-1] = orig_subid_val; |
1772 | 0 | } |
1773 | 0 | } |
1774 | 7.85k | else { |
1775 | 7.85k | unregistering=0; |
1776 | 7.85k | } |
1777 | 7.85k | } |
1778 | | |
1779 | 7.85k | memset(®_parms, 0x0, sizeof(reg_parms)); |
1780 | 7.85k | reg_parms.name = name; |
1781 | 7.85k | reg_parms.namelen = len; |
1782 | 7.85k | reg_parms.priority = priority; |
1783 | 7.85k | reg_parms.range_subid = range_subid; |
1784 | 7.85k | reg_parms.range_ubound = range_ubound; |
1785 | 7.85k | reg_parms.flags = 0x00; /* this is okay I think */ |
1786 | 7.85k | reg_parms.contextName = context; |
1787 | 7.85k | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
1788 | 7.85k | SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); |
1789 | | |
1790 | 7.85k | netsnmp_subtree_free(myptr); |
1791 | 7.85k | netsnmp_set_lookup_cache_size(old_lookup_cache_val); |
1792 | 7.85k | invalidate_lookup_cache(context); |
1793 | 7.85k | return MIB_UNREGISTERED_OK; |
1794 | 7.85k | } |
1795 | | |
1796 | | #ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW |
1797 | | int |
1798 | | netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority, |
1799 | | int var_subid, oid range_ubound, |
1800 | | const char *context) |
1801 | 0 | { |
1802 | 0 | netsnmp_subtree *list, *myptr, *futureptr; |
1803 | 0 | netsnmp_subtree *prev, *child; /* loop through children */ |
1804 | 0 | struct register_parameters reg_parms; |
1805 | 0 | oid range_lbound = name[var_subid - 1]; |
1806 | |
|
1807 | 0 | DEBUGMSGTL(("register_mib", "unregistering ")); |
1808 | 0 | DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound)); |
1809 | 0 | DEBUGMSG(("register_mib", "\n")); |
1810 | |
|
1811 | 0 | for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) { |
1812 | 0 | list = netsnmp_subtree_find(name, len, |
1813 | 0 | netsnmp_subtree_find_first(context), context); |
1814 | |
|
1815 | 0 | if (list == NULL) { |
1816 | 0 | continue; |
1817 | 0 | } |
1818 | | |
1819 | 0 | for (child = list, prev = NULL; child != NULL; |
1820 | 0 | prev = child, child = child->children) { |
1821 | |
|
1822 | 0 | if (netsnmp_oid_equals(child->name_a, child->namelen, |
1823 | 0 | name, len) == 0 && |
1824 | 0 | (child->priority == priority)) { |
1825 | 0 | break; /* found it */ |
1826 | 0 | } |
1827 | 0 | } |
1828 | |
|
1829 | 0 | if (child == NULL) { |
1830 | 0 | continue; |
1831 | 0 | } |
1832 | | |
1833 | 0 | netsnmp_subtree_unload(child, prev, context); |
1834 | 0 | myptr = child; /* remember this for later */ |
1835 | |
|
1836 | 0 | for (list = myptr->next; list != NULL; list = futureptr) { |
1837 | | /* remember the next spot in the list in case we free this node */ |
1838 | 0 | futureptr = list->next; |
1839 | | |
1840 | | /* check each child */ |
1841 | 0 | for (child = list, prev = NULL; child != NULL; |
1842 | 0 | prev = child, child = child->children) { |
1843 | |
|
1844 | 0 | if (netsnmp_oid_equals(child->name_a, child->namelen, |
1845 | 0 | name, len) == 0 && |
1846 | 0 | (child->priority == priority)) { |
1847 | 0 | netsnmp_subtree_unload(child, prev, context); |
1848 | 0 | netsnmp_subtree_free(child); |
1849 | 0 | break; |
1850 | 0 | } |
1851 | 0 | } |
1852 | | |
1853 | | /* XXX: wjh: not sure why we're bailing here */ |
1854 | 0 | if (child == NULL) { /* Didn't find the given name */ |
1855 | 0 | break; |
1856 | 0 | } |
1857 | 0 | } |
1858 | 0 | netsnmp_subtree_free(myptr); |
1859 | 0 | } |
1860 | |
|
1861 | 0 | name[var_subid - 1] = range_lbound; |
1862 | 0 | memset(®_parms, 0x0, sizeof(reg_parms)); |
1863 | 0 | reg_parms.name = name; |
1864 | 0 | reg_parms.namelen = len; |
1865 | 0 | reg_parms.priority = priority; |
1866 | 0 | reg_parms.range_subid = var_subid; |
1867 | 0 | reg_parms.range_ubound = range_ubound; |
1868 | 0 | reg_parms.flags = 0x00; /* this is okay I think */ |
1869 | 0 | reg_parms.contextName = context; |
1870 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
1871 | 0 | SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); |
1872 | |
|
1873 | 0 | return 0; |
1874 | 0 | } |
1875 | | #endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_MIB_TABLE_ROW */ |
1876 | | |
1877 | | /** |
1878 | | * Unregisters a module registered against a given OID (or range) in the default context. |
1879 | | * Typically used when a module has multiple contexts defined. |
1880 | | * The parameters priority, range_subid, and range_ubound should |
1881 | | * match those used to register the module originally. |
1882 | | * |
1883 | | * @param name the specific OID to unregister if it conatins the associated |
1884 | | * context. |
1885 | | * |
1886 | | * @param len the length of the OID, use OID_LENGTH macro. |
1887 | | * |
1888 | | * @param priority a value between 1 and 255, used to achieve a desired |
1889 | | * configuration when different sessions register identical or |
1890 | | * overlapping regions. Subagents with no particular |
1891 | | * knowledge of priority should register with the default |
1892 | | * value of 127. |
1893 | | * |
1894 | | * @param range_subid permits specifying a range in place of one of a subtree |
1895 | | * sub-identifiers. When this value is zero, no range is |
1896 | | * being specified. |
1897 | | * |
1898 | | * @param range_ubound the upper bound of a sub-identifier's range. |
1899 | | * This field is present only if range_subid is not 0. |
1900 | | * |
1901 | | * @return gives MIB_UNREGISTERED_OK or MIB_* error code. |
1902 | | * |
1903 | | * @see unregister_mib() |
1904 | | * @see unregister_mib_priority() |
1905 | | * @see unregister_mib_context() |
1906 | | */ |
1907 | | int |
1908 | | unregister_mib_range(oid * name, size_t len, int priority, |
1909 | | int range_subid, oid range_ubound) |
1910 | 0 | { |
1911 | 0 | return unregister_mib_context(name, len, priority, range_subid, |
1912 | 0 | range_ubound, ""); |
1913 | 0 | } |
1914 | | |
1915 | | /** |
1916 | | * Unregisters a module registered against a given OID at the specified priority. |
1917 | | * The priority parameter should match that used to register the module originally. |
1918 | | * |
1919 | | * @param name the specific OID to unregister if it conatins the associated |
1920 | | * context. |
1921 | | * |
1922 | | * @param len the length of the OID, use OID_LENGTH macro. |
1923 | | * |
1924 | | * @param priority a value between 1 and 255, used to achieve a desired |
1925 | | * configuration when different sessions register identical or |
1926 | | * overlapping regions. Subagents with no particular |
1927 | | * knowledge of priority should register with the default |
1928 | | * value of 127. |
1929 | | * |
1930 | | * @return gives MIB_UNREGISTERED_OK or MIB_* error code. |
1931 | | * |
1932 | | * @see unregister_mib() |
1933 | | * @see unregister_mib_range() |
1934 | | * @see unregister_mib_context() |
1935 | | */ |
1936 | | int |
1937 | | unregister_mib_priority(oid * name, size_t len, int priority) |
1938 | 0 | { |
1939 | 0 | return unregister_mib_range(name, len, priority, 0, 0); |
1940 | 0 | } |
1941 | | |
1942 | | /** |
1943 | | * Unregisters a module registered against a given OID at the default priority. |
1944 | | * |
1945 | | * @param name the specific OID to unregister if it conatins the associated |
1946 | | * context. |
1947 | | * |
1948 | | * @param len the length of the OID, use OID_LENGTH macro. |
1949 | | * |
1950 | | * @return gives MIB_UNREGISTERED_OK or MIB_* error code. |
1951 | | * |
1952 | | * @see unregister_mib_priority() |
1953 | | * @see unregister_mib_context() |
1954 | | * @see unregister_mib_range() |
1955 | | * @see unregister_agentx_list() |
1956 | | */ |
1957 | | int |
1958 | | unregister_mib(oid * name, size_t len) |
1959 | 0 | { |
1960 | 0 | return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY); |
1961 | 0 | } |
1962 | | |
1963 | | /** Unregisters subtree of OIDs bounded to given session. |
1964 | | * |
1965 | | * @param ss Session which OIDs will be removed from tree. |
1966 | | * |
1967 | | * @see unregister_mib() |
1968 | | * @see unregister_agentx_list() |
1969 | | */ |
1970 | | void |
1971 | | unregister_mibs_by_session(netsnmp_session * ss) |
1972 | 0 | { |
1973 | 0 | netsnmp_subtree *list, *list2; |
1974 | 0 | netsnmp_subtree *child, *prev, *next_child; |
1975 | 0 | struct register_parameters rp; |
1976 | 0 | subtree_context_cache *contextptr; |
1977 | |
|
1978 | 0 | DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n", |
1979 | 0 | ss, (ss && ss->contextName) ? ss->contextName : "[NIL]")); |
1980 | |
|
1981 | 0 | for (contextptr = get_top_context_cache(); contextptr != NULL; |
1982 | 0 | contextptr = contextptr->next) { |
1983 | 0 | for (list = contextptr->first_subtree; list != NULL; list = list2) { |
1984 | 0 | list2 = list->next; |
1985 | |
|
1986 | 0 | for (child = list, prev = NULL; child != NULL; child = next_child){ |
1987 | 0 | next_child = child->children; |
1988 | |
|
1989 | 0 | if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && |
1990 | 0 | child->session == ss) || |
1991 | 0 | (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session && |
1992 | 0 | child->session->subsession == ss)) { |
1993 | |
|
1994 | 0 | memset(&rp,0x0,sizeof(rp)); |
1995 | 0 | rp.name = child->name_a; |
1996 | 0 | child->name_a = NULL; |
1997 | 0 | rp.namelen = child->namelen; |
1998 | 0 | rp.priority = child->priority; |
1999 | 0 | rp.range_subid = child->range_subid; |
2000 | 0 | rp.range_ubound = child->range_ubound; |
2001 | 0 | rp.timeout = child->timeout; |
2002 | 0 | rp.flags = child->flags; |
2003 | 0 | if ((NULL != child->reginfo) && |
2004 | 0 | (NULL != child->reginfo->contextName)) |
2005 | 0 | rp.contextName = child->reginfo->contextName; |
2006 | |
|
2007 | 0 | if (child->reginfo != NULL) { |
2008 | | /* |
2009 | | * Don't let's free the session pointer just yet! |
2010 | | */ |
2011 | 0 | child->reginfo->handler->myvoid = NULL; |
2012 | 0 | netsnmp_handler_registration_free(child->reginfo); |
2013 | 0 | child->reginfo = NULL; |
2014 | 0 | } |
2015 | |
|
2016 | 0 | netsnmp_subtree_unload(child, prev, contextptr->context_name); |
2017 | 0 | netsnmp_subtree_free(child); |
2018 | |
|
2019 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2020 | 0 | SNMPD_CALLBACK_UNREGISTER_OID, &rp); |
2021 | 0 | SNMP_FREE(rp.name); |
2022 | 0 | } else { |
2023 | 0 | prev = child; |
2024 | 0 | } |
2025 | 0 | } |
2026 | 0 | } |
2027 | 0 | netsnmp_subtree_join(contextptr->first_subtree); |
2028 | 0 | } |
2029 | 0 | } |
2030 | | |
2031 | | /** Determines if given PDU is allowed to see (or update) a given OID. |
2032 | | * |
2033 | | * @param name The OID to check access for. |
2034 | | * On return, this parameter holds the OID actually matched |
2035 | | * |
2036 | | * @param namelen Number of sub-identifiers in the OID. |
2037 | | * On return, this parameter holds the length of the matched OID |
2038 | | * |
2039 | | * @param pdu PDU requesting access to the OID. |
2040 | | * |
2041 | | * @param type ANS.1 type of the value at given OID. |
2042 | | * (Used for catching SNMPv1 requests for SMIv2-only objects) |
2043 | | * |
2044 | | * @return gives VACM_SUCCESS if the OID is in the PDU, otherwise error code. |
2045 | | */ |
2046 | | int |
2047 | | in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type) |
2048 | 498 | { |
2049 | 498 | struct view_parameters view_parms; |
2050 | | |
2051 | 498 | if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { |
2052 | | /* Enable bypassing of view-based access control */ |
2053 | 498 | return VACM_SUCCESS; |
2054 | 498 | } |
2055 | | |
2056 | | /* |
2057 | | * check for v1 and counter64s, since snmpv1 doesn't support it |
2058 | | */ |
2059 | 0 | #ifndef NETSNMP_DISABLE_SNMPV1 |
2060 | 0 | if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) { |
2061 | 0 | return VACM_NOTINVIEW; |
2062 | 0 | } |
2063 | 0 | #endif |
2064 | | |
2065 | 0 | view_parms.pdu = pdu; |
2066 | 0 | view_parms.name = name; |
2067 | 0 | if (namelen != NULL) { |
2068 | 0 | view_parms.namelen = *namelen; |
2069 | 0 | } else { |
2070 | 0 | view_parms.namelen = 0; |
2071 | 0 | } |
2072 | 0 | view_parms.errorcode = 0; |
2073 | 0 | view_parms.check_subtree = 0; |
2074 | |
|
2075 | 0 | switch (pdu->version) { |
2076 | 0 | #ifndef NETSNMP_DISABLE_SNMPV1 |
2077 | 0 | case SNMP_VERSION_1: |
2078 | 0 | #endif |
2079 | 0 | #ifndef NETSNMP_DISABLE_SNMPV2C |
2080 | 0 | case SNMP_VERSION_2c: |
2081 | 0 | #endif |
2082 | 0 | case SNMP_VERSION_3: |
2083 | 0 | NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version); |
2084 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2085 | 0 | SNMPD_CALLBACK_ACM_CHECK, &view_parms); |
2086 | 0 | return view_parms.errorcode; |
2087 | 0 | } |
2088 | 0 | unsupported_version: |
2089 | 0 | return VACM_NOSECNAME; |
2090 | 0 | } |
2091 | | |
2092 | | /** Determines if the given PDU request could potentially succeed. |
2093 | | * (Preliminary, OID-independent validation) |
2094 | | * |
2095 | | * @param pdu PDU requesting access |
2096 | | * |
2097 | | * @return gives VACM_SUCCESS if the entire MIB tree is accessible |
2098 | | * VACM_NOTINVIEW if the entire MIB tree is inaccessible |
2099 | | * VACM_SUBTREE_UNKNOWN if some portions are accessible |
2100 | | * other codes may returned on error |
2101 | | */ |
2102 | | int |
2103 | | check_access(netsnmp_pdu *pdu) |
2104 | 9.84k | { /* IN - pdu being checked */ |
2105 | 9.84k | struct view_parameters view_parms; |
2106 | 9.84k | view_parms.pdu = pdu; |
2107 | 9.84k | view_parms.name = NULL; |
2108 | 9.84k | view_parms.namelen = 0; |
2109 | 9.84k | view_parms.errorcode = 0; |
2110 | 9.84k | view_parms.check_subtree = 0; |
2111 | | |
2112 | 9.84k | if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { |
2113 | | /* Enable bypassing of view-based access control */ |
2114 | 9.84k | return 0; |
2115 | 9.84k | } |
2116 | | |
2117 | 0 | switch (pdu->version) { |
2118 | 0 | #ifndef NETSNMP_DISABLE_SNMPV1 |
2119 | 0 | case SNMP_VERSION_1: |
2120 | 0 | #endif |
2121 | 0 | #ifndef NETSNMP_DISABLE_SNMPV2C |
2122 | 0 | case SNMP_VERSION_2c: |
2123 | 0 | #endif |
2124 | 0 | case SNMP_VERSION_3: |
2125 | 0 | NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version); |
2126 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2127 | 0 | SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms); |
2128 | 0 | return view_parms.errorcode; |
2129 | 0 | } |
2130 | 0 | unsupported_version: |
2131 | 0 | return 1; |
2132 | 0 | } |
2133 | | |
2134 | | /** Determines if the given PDU request could potentially access |
2135 | | * the specified MIB subtree |
2136 | | * |
2137 | | * @param pdu PDU requesting access |
2138 | | * |
2139 | | * @param name The OID to check access for. |
2140 | | * |
2141 | | * @param namelen Number of sub-identifiers in the OID. |
2142 | | * |
2143 | | * @return gives VACM_SUCCESS if the entire MIB tree is accessible |
2144 | | * VACM_NOTINVIEW if the entire MIB tree is inaccessible |
2145 | | * VACM_SUBTREE_UNKNOWN if some portions are accessible |
2146 | | * other codes may returned on error |
2147 | | */ |
2148 | | int |
2149 | | netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen) |
2150 | 0 | { /* IN - pdu being checked */ |
2151 | 0 | struct view_parameters view_parms; |
2152 | 0 | view_parms.pdu = pdu; |
2153 | 0 | view_parms.name = name; |
2154 | 0 | view_parms.namelen = namelen; |
2155 | 0 | view_parms.errorcode = 0; |
2156 | 0 | view_parms.check_subtree = 1; |
2157 | |
|
2158 | 0 | if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { |
2159 | | /* Enable bypassing of view-based access control */ |
2160 | 0 | return 0; |
2161 | 0 | } |
2162 | | |
2163 | 0 | switch (pdu->version) { |
2164 | 0 | #ifndef NETSNMP_DISABLE_SNMPV1 |
2165 | 0 | case SNMP_VERSION_1: |
2166 | 0 | #endif |
2167 | 0 | #ifndef NETSNMP_DISABLE_SNMPV2C |
2168 | 0 | case SNMP_VERSION_2c: |
2169 | 0 | #endif |
2170 | 0 | case SNMP_VERSION_3: |
2171 | 0 | NETSNMP_RUNTIME_PROTOCOL_CHECK(pdu->version,unsupported_version); |
2172 | 0 | snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
2173 | 0 | SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms); |
2174 | 0 | return view_parms.errorcode; |
2175 | 0 | } |
2176 | 0 | unsupported_version: |
2177 | 0 | return 1; |
2178 | 0 | } |
2179 | | |
2180 | | netsnmp_feature_child_of(get_session_for_oid,netsnmp_unused); |
2181 | | #ifndef NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID |
2182 | | netsnmp_session * |
2183 | | get_session_for_oid(const oid *name, size_t len, const char *context_name) |
2184 | 0 | { |
2185 | 0 | netsnmp_subtree *myptr; |
2186 | |
|
2187 | 0 | myptr = netsnmp_subtree_find_prev(name, len, |
2188 | 0 | netsnmp_subtree_find_first(context_name), |
2189 | 0 | context_name); |
2190 | |
|
2191 | 0 | while (myptr && myptr->variables == NULL) { |
2192 | 0 | myptr = myptr->next; |
2193 | 0 | } |
2194 | |
|
2195 | 0 | if (myptr == NULL) { |
2196 | 0 | return NULL; |
2197 | 0 | } else { |
2198 | 0 | return myptr->session; |
2199 | 0 | } |
2200 | 0 | } |
2201 | | #endif /* NETSNMP_FEATURE_REMOVE_GET_SESSION_FOR_OID */ |
2202 | | |
2203 | | void |
2204 | | setup_tree(void) |
2205 | 2.61k | { |
2206 | 2.61k | oid ccitt[1] = { 0 }; |
2207 | 2.61k | oid iso[1] = { 1 }; |
2208 | 2.61k | oid joint_ccitt_iso[1] = { 2 }; |
2209 | | |
2210 | 2.61k | #ifdef USING_AGENTX_SUBAGENT_MODULE |
2211 | 2.61k | int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
2212 | 2.61k | NETSNMP_DS_AGENT_ROLE); |
2213 | | |
2214 | 2.61k | netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, |
2215 | 2.61k | MASTER_AGENT); |
2216 | 2.61k | #endif |
2217 | | |
2218 | | /* |
2219 | | * we need to have the oid's in the heap, that we can *free* it for every case, |
2220 | | * thats the purpose of the duplicate_objid's |
2221 | | */ |
2222 | 2.61k | netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1); |
2223 | 2.61k | netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1); |
2224 | 2.61k | netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1); |
2225 | | |
2226 | 2.61k | #ifdef USING_AGENTX_SUBAGENT_MODULE |
2227 | 2.61k | netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, |
2228 | 2.61k | role); |
2229 | 2.61k | #endif |
2230 | 2.61k | } |
2231 | | |
2232 | | int |
2233 | 7.85k | remove_tree_entry (oid *name, size_t len) { |
2234 | | |
2235 | 7.85k | netsnmp_subtree *sub = NULL; |
2236 | | |
2237 | 7.85k | if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) { |
2238 | 0 | return MIB_NO_SUCH_REGISTRATION; |
2239 | 0 | } |
2240 | | |
2241 | 7.85k | return unregister_mib_context(name, len, sub->priority, |
2242 | 7.85k | sub->range_subid, sub->range_ubound, ""); |
2243 | | |
2244 | 7.85k | } |
2245 | | |
2246 | | |
2247 | | void |
2248 | 2.61k | shutdown_tree(void) { |
2249 | 2.61k | oid ccitt[1] = { 0 }; |
2250 | 2.61k | oid iso[1] = { 1 }; |
2251 | 2.61k | oid joint_ccitt_iso[1] = { 2 }; |
2252 | | |
2253 | 2.61k | DEBUGMSGTL(("agent_registry", "shut down tree\n")); |
2254 | | |
2255 | 2.61k | remove_tree_entry(joint_ccitt_iso, 1); |
2256 | 2.61k | remove_tree_entry(iso, 1); |
2257 | 2.61k | remove_tree_entry(ccitt, 1); |
2258 | | |
2259 | 2.61k | } |
2260 | | |
2261 | | void |
2262 | | dump_registry(void) |
2263 | 0 | { |
2264 | 0 | struct variable *vp = NULL; |
2265 | 0 | netsnmp_subtree *myptr, *myptr2; |
2266 | 0 | u_char *s = NULL, *e = NULL, *v = NULL; |
2267 | 0 | size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0; |
2268 | 0 | int i = 0; |
2269 | |
|
2270 | 0 | if ((s = calloc(sl, 1)) != NULL && |
2271 | 0 | (e = calloc(sl, 1)) != NULL && |
2272 | 0 | (v = calloc(sl, 1)) != NULL) { |
2273 | |
|
2274 | 0 | subtree_context_cache *ptr; |
2275 | 0 | for (ptr = context_subtrees; ptr; ptr = ptr->next) { |
2276 | 0 | printf("Subtrees for Context: %s\n", ptr->context_name); |
2277 | 0 | for (myptr = ptr->first_subtree; myptr != NULL; |
2278 | 0 | myptr = myptr->next) { |
2279 | 0 | sl_o = el_o = vl_o = 0; |
2280 | |
|
2281 | 0 | if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, |
2282 | 0 | myptr->start_a, |
2283 | 0 | myptr->start_len)) { |
2284 | 0 | break; |
2285 | 0 | } |
2286 | 0 | if (!sprint_realloc_objid(&e, &el, &el_o, 1, |
2287 | 0 | myptr->end_a, |
2288 | 0 | myptr->end_len)) { |
2289 | 0 | break; |
2290 | 0 | } |
2291 | | |
2292 | 0 | if (myptr->variables) { |
2293 | 0 | printf("%02x ( %s - %s ) [", myptr->flags, s, e); |
2294 | 0 | for (i = 0, vp = myptr->variables; |
2295 | 0 | i < myptr->variables_len; i++) { |
2296 | 0 | vl_o = 0; |
2297 | 0 | if (!sprint_realloc_objid |
2298 | 0 | (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) { |
2299 | 0 | break; |
2300 | 0 | } |
2301 | 0 | printf("%s, ", v); |
2302 | 0 | vp = (struct variable *) ((char *) vp + |
2303 | 0 | myptr->variables_width); |
2304 | 0 | } |
2305 | 0 | printf("]\n"); |
2306 | 0 | } else { |
2307 | 0 | printf("%02x %s - %s \n", myptr->flags, s, e); |
2308 | 0 | } |
2309 | 0 | for (myptr2 = myptr; myptr2 != NULL; |
2310 | 0 | myptr2 = myptr2->children) { |
2311 | 0 | if (myptr2->label_a && myptr2->label_a[0]) { |
2312 | 0 | if (strcmp(myptr2->label_a, "old_api") == 0) { |
2313 | 0 | struct variable *vp = |
2314 | 0 | (struct variable*)myptr2->reginfo->handler->myvoid; |
2315 | |
|
2316 | 0 | if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, |
2317 | 0 | vp->name, vp->namelen)) { |
2318 | 0 | continue; |
2319 | 0 | } |
2320 | 0 | printf("\t%s[%s] %p var %s\n", myptr2->label_a, |
2321 | 0 | myptr2->reginfo->handlerName ? |
2322 | 0 | myptr2->reginfo->handlerName : "no-name", |
2323 | 0 | myptr2->reginfo, s); |
2324 | 0 | } else { |
2325 | 0 | printf("\t%s %s %p\n", myptr2->label_a, |
2326 | 0 | myptr2->reginfo->handlerName ? |
2327 | 0 | myptr2->reginfo->handlerName : "no-handler-name", |
2328 | 0 | myptr2->reginfo); |
2329 | 0 | } |
2330 | 0 | } |
2331 | 0 | } |
2332 | 0 | } |
2333 | 0 | } |
2334 | 0 | } |
2335 | |
|
2336 | 0 | SNMP_FREE(s); |
2337 | 0 | SNMP_FREE(e); |
2338 | 0 | SNMP_FREE(v); |
2339 | |
|
2340 | 0 | dump_idx_registry(); |
2341 | 0 | } |
2342 | | |
2343 | | /** @} */ |
2344 | | /* End of MIB registration code */ |
2345 | | |
2346 | | |
2347 | | netsnmp_feature_child_of(register_signal, netsnmp_unused); |
2348 | | #ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL |
2349 | | |
2350 | | /** @defgroup agent_signals POSIX signals support for agents. |
2351 | | * Registering and unregistering signal handlers. |
2352 | | * @ingroup agent_registry |
2353 | | * |
2354 | | * @{ |
2355 | | */ |
2356 | | |
2357 | | int external_signal_scheduled[NUM_EXTERNAL_SIGS]; |
2358 | | void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int); |
2359 | | |
2360 | | #ifndef WIN32 |
2361 | | |
2362 | | /* |
2363 | | * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines |
2364 | | * below for every single that might be handled by register_signal(). |
2365 | | */ |
2366 | | |
2367 | | RETSIGTYPE |
2368 | | agent_SIGCHLD_handler(int sig) |
2369 | 0 | { |
2370 | 0 | external_signal_scheduled[SIGCHLD]++; |
2371 | | #ifndef HAVE_SIGACTION |
2372 | | /* |
2373 | | * signal() sucks. It *might* have SysV semantics, which means that |
2374 | | * * a signal handler is reset once it gets called. Ensure that it |
2375 | | * * remains active. |
2376 | | */ |
2377 | | signal(SIGCHLD, agent_SIGCHLD_handler); |
2378 | | #endif |
2379 | 0 | } |
2380 | | |
2381 | | /** Registers a POSIX Signal handler. |
2382 | | * Implements the signal registering process for POSIX and non-POSIX |
2383 | | * systems. Also, unifies the way signals work. |
2384 | | * Note that the signal handler should register itself again with |
2385 | | * signal() call before end of execution to prevent possible problems. |
2386 | | * |
2387 | | * @param sig POSIX Signal ID number, as defined in signal.h. |
2388 | | * |
2389 | | * @param func New signal handler function. |
2390 | | * |
2391 | | * @return value is SIG_REGISTERED_OK for success and |
2392 | | * SIG_REGISTRATION_FAILED if the registration can't |
2393 | | * be handled. |
2394 | | */ |
2395 | | int |
2396 | | register_signal(int sig, void (*func) (int)) |
2397 | 0 | { |
2398 | |
|
2399 | 0 | switch (sig) { |
2400 | 0 | #if defined(SIGCHLD) |
2401 | 0 | case SIGCHLD: |
2402 | 0 | #ifdef HAVE_SIGACTION |
2403 | 0 | { |
2404 | 0 | static struct sigaction act; |
2405 | 0 | act.sa_handler = agent_SIGCHLD_handler; |
2406 | 0 | sigemptyset(&act.sa_mask); |
2407 | 0 | act.sa_flags = 0; |
2408 | 0 | sigaction(SIGCHLD, &act, NULL); |
2409 | 0 | } |
2410 | | #else |
2411 | | signal(SIGCHLD, agent_SIGCHLD_handler); |
2412 | | #endif |
2413 | 0 | break; |
2414 | 0 | #endif |
2415 | 0 | default: |
2416 | 0 | snmp_log(LOG_CRIT, |
2417 | 0 | "register_signal: signal %d cannot be handled\n", sig); |
2418 | 0 | return SIG_REGISTRATION_FAILED; |
2419 | 0 | } |
2420 | | |
2421 | 0 | external_signal_handler[sig] = func; |
2422 | 0 | external_signal_scheduled[sig] = 0; |
2423 | |
|
2424 | 0 | DEBUGMSGTL(("register_signal", "registered signal %d\n", sig)); |
2425 | 0 | return SIG_REGISTERED_OK; |
2426 | 0 | } |
2427 | | |
2428 | | /** Unregisters a POSIX Signal handler. |
2429 | | * |
2430 | | * @param sig POSIX Signal ID number, as defined in signal.h. |
2431 | | * |
2432 | | * @return value is SIG_UNREGISTERED_OK for success, or error code. |
2433 | | */ |
2434 | | int |
2435 | | unregister_signal(int sig) |
2436 | 0 | { |
2437 | 0 | signal(sig, SIG_DFL); |
2438 | 0 | DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig)); |
2439 | 0 | return SIG_UNREGISTERED_OK; |
2440 | 0 | } |
2441 | | |
2442 | | #endif /* !WIN32 */ |
2443 | | |
2444 | | /** @} */ |
2445 | | /* End of signals support code */ |
2446 | | |
2447 | | #endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */ |
2448 | | |
2449 | | /** @} */ |
2450 | | |