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