00001 /* 00002 * agent_registry.c 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 00013 */ 00020 #define IN_SNMP_VARS_C 00021 00022 #include <net-snmp/net-snmp-config.h> 00023 #include <signal.h> 00024 #if HAVE_STRING_H 00025 #include <string.h> 00026 #endif 00027 #if HAVE_STDLIB_H 00028 #include <stdlib.h> 00029 #endif 00030 #include <sys/types.h> 00031 #include <stdio.h> 00032 #include <fcntl.h> 00033 #if HAVE_WINSOCK_H 00034 #include <winsock.h> 00035 #endif 00036 #if TIME_WITH_SYS_TIME 00037 # ifdef WIN32 00038 # include <sys/timeb.h> 00039 # else 00040 # include <sys/time.h> 00041 # endif 00042 # include <time.h> 00043 #else 00044 # if HAVE_SYS_TIME_H 00045 # include <sys/time.h> 00046 # else 00047 # include <time.h> 00048 # endif 00049 #endif 00050 #if HAVE_NETINET_IN_H 00051 #include <netinet/in.h> 00052 #endif 00053 00054 #include <net-snmp/net-snmp-includes.h> 00055 #include <net-snmp/agent/net-snmp-agent-includes.h> 00056 #include <net-snmp/agent/agent_callbacks.h> 00057 00058 #include "snmpd.h" 00059 #include "mibgroup/struct.h" 00060 #include <net-snmp/agent/old_api.h> 00061 #include <net-snmp/agent/null.h> 00062 #include <net-snmp/agent/table.h> 00063 #include <net-snmp/agent/table_iterator.h> 00064 #include <net-snmp/agent/agent_registry.h> 00065 #include "mib_module_includes.h" 00066 00067 #ifdef USING_AGENTX_SUBAGENT_MODULE 00068 #include "agentx/subagent.h" 00069 #include "agentx/client.h" 00070 #endif 00071 00072 /* Lookup cache code */ 00073 00074 #define SUBTREE_DEFAULT_CACHE_SIZE 8 00075 #define SUBTREE_MAX_CACHE_SIZE 32 00076 int lookup_cache_size = 0; /*enabled later after registrations are loaded */ 00077 00078 typedef struct lookup_cache_s { 00079 netsnmp_subtree *next; 00080 netsnmp_subtree *previous; 00081 } lookup_cache; 00082 00083 typedef struct lookup_cache_context_s { 00084 char *context; 00085 struct lookup_cache_context_s *next; 00086 int thecachecount; 00087 int currentpos; 00088 lookup_cache cache[SUBTREE_MAX_CACHE_SIZE]; 00089 } lookup_cache_context; 00090 00091 static lookup_cache_context *thecontextcache = NULL; 00092 00104 void 00105 netsnmp_set_lookup_cache_size(int newsize) { 00106 if (newsize < 0) 00107 lookup_cache_size = SUBTREE_DEFAULT_CACHE_SIZE; 00108 else if (newsize < SUBTREE_MAX_CACHE_SIZE) 00109 lookup_cache_size = newsize; 00110 else 00111 lookup_cache_size = SUBTREE_MAX_CACHE_SIZE; 00112 } 00113 00117 int 00118 netsnmp_get_lookup_cache_size(void) { 00119 return lookup_cache_size; 00120 } 00121 00122 NETSNMP_STATIC_INLINE lookup_cache_context * 00123 get_context_lookup_cache(const char *context) { 00124 lookup_cache_context *ptr; 00125 if (!context) 00126 context = ""; 00127 00128 for(ptr = thecontextcache; ptr; ptr = ptr->next) { 00129 if (strcmp(ptr->context, context) == 0) 00130 break; 00131 } 00132 if (!ptr) { 00133 if (netsnmp_subtree_find_first(context)) { 00134 ptr = SNMP_MALLOC_TYPEDEF(lookup_cache_context); 00135 ptr->next = thecontextcache; 00136 ptr->context = strdup(context); 00137 thecontextcache = ptr; 00138 } else { 00139 return NULL; 00140 } 00141 } 00142 return ptr; 00143 } 00144 00145 NETSNMP_STATIC_INLINE void 00146 lookup_cache_add(const char *context, 00147 netsnmp_subtree *next, netsnmp_subtree *previous) { 00148 lookup_cache_context *cptr; 00149 00150 if ((cptr = get_context_lookup_cache(context)) == NULL) 00151 return; 00152 00153 if (cptr->thecachecount < lookup_cache_size) 00154 cptr->thecachecount++; 00155 00156 cptr->cache[cptr->currentpos].next = next; 00157 cptr->cache[cptr->currentpos].previous = previous; 00158 00159 if (++cptr->currentpos >= lookup_cache_size) 00160 cptr->currentpos = 0; 00161 } 00162 00163 NETSNMP_STATIC_INLINE void 00164 lookup_cache_replace(lookup_cache *ptr, 00165 netsnmp_subtree *next, netsnmp_subtree *previous) { 00166 00167 ptr->next = next; 00168 ptr->previous = previous; 00169 } 00170 00171 NETSNMP_STATIC_INLINE lookup_cache * 00172 lookup_cache_find(const char *context, oid *name, size_t name_len, 00173 int *retcmp) { 00174 lookup_cache_context *cptr; 00175 lookup_cache *ret = NULL; 00176 int cmp; 00177 int i; 00178 00179 if ((cptr = get_context_lookup_cache(context)) == NULL) 00180 return NULL; 00181 00182 for(i = 0; i < cptr->thecachecount && i < lookup_cache_size; i++) { 00183 if (cptr->cache[i].previous->start_a) 00184 cmp = snmp_oid_compare(name, name_len, 00185 cptr->cache[i].previous->start_a, 00186 cptr->cache[i].previous->start_len); 00187 else 00188 cmp = 1; 00189 if (cmp >= 0) { 00190 *retcmp = cmp; 00191 ret = &(cptr->cache[i]); 00192 } 00193 } 00194 return ret; 00195 } 00196 00197 NETSNMP_STATIC_INLINE void 00198 invalidate_lookup_cache(const char *context) { 00199 lookup_cache_context *cptr; 00200 if ((cptr = get_context_lookup_cache(context)) != NULL) { 00201 cptr->thecachecount = 0; 00202 cptr->currentpos = 0; 00203 } 00204 } 00205 00206 /* End of Lookup cache code */ 00207 00208 static void register_mib_detach_node(netsnmp_subtree *s); 00209 subtree_context_cache *context_subtrees = NULL; 00210 00211 void 00212 netsnmp_subtree_free(netsnmp_subtree *a) 00213 { 00214 if (a != NULL) { 00215 if (a->variables != NULL && netsnmp_oid_equals(a->name_a, a->namelen, 00216 a->start_a, a->start_len) == 0) { 00217 SNMP_FREE(a->variables); 00218 } 00219 SNMP_FREE(a->name_a); 00220 a->namelen = 0; 00221 SNMP_FREE(a->start_a); 00222 a->start_len = 0; 00223 SNMP_FREE(a->end_a); 00224 a->end_len = 0; 00225 SNMP_FREE(a->label_a); 00226 netsnmp_handler_registration_free(a->reginfo); 00227 a->reginfo = NULL; 00228 SNMP_FREE(a); 00229 } 00230 } 00231 00232 netsnmp_subtree * 00233 netsnmp_subtree_deepcopy(netsnmp_subtree *a) 00234 { 00235 netsnmp_subtree *b = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00236 00237 if (b != NULL) { 00238 memcpy(b, a, sizeof(netsnmp_subtree)); 00239 b->name_a = snmp_duplicate_objid(a->name_a, a->namelen); 00240 b->start_a = snmp_duplicate_objid(a->start_a, a->start_len); 00241 b->end_a = snmp_duplicate_objid(a->end_a, a->end_len); 00242 b->label_a = strdup(a->label_a); 00243 00244 if (b->name_a == NULL || b->start_a == NULL || 00245 b->end_a == NULL || b->label_a == NULL) { 00246 netsnmp_subtree_free(b); 00247 return NULL; 00248 } 00249 00250 if (a->variables != NULL) { 00251 b->variables = (struct variable *)malloc(a->variables_len * 00252 a->variables_width); 00253 if (b->variables != NULL) { 00254 memcpy(b->variables, a->variables,a->variables_len*a->variables_width); 00255 } else { 00256 netsnmp_subtree_free(b); 00257 return NULL; 00258 } 00259 } 00260 00261 if (a->reginfo != NULL) { 00262 b->reginfo = netsnmp_handler_registration_dup(a->reginfo); 00263 if (b->reginfo == NULL) { 00264 netsnmp_subtree_free(b); 00265 return NULL; 00266 } 00267 } 00268 } 00269 return b; 00270 } 00271 00272 subtree_context_cache * 00273 get_top_context_cache(void) 00274 { 00275 return context_subtrees; 00276 } 00277 00278 netsnmp_subtree * 00279 netsnmp_subtree_find_first(const char *context_name) 00280 { 00281 subtree_context_cache *ptr; 00282 00283 if (!context_name) { 00284 context_name = ""; 00285 } 00286 00287 DEBUGMSGTL(("subtree", "looking for subtree for context: \"%s\"\n", 00288 context_name)); 00289 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00290 if (ptr->context_name != NULL && 00291 strcmp(ptr->context_name, context_name) == 0) { 00292 DEBUGMSGTL(("subtree", "found one for: \"%s\"\n", context_name)); 00293 return ptr->first_subtree; 00294 } 00295 } 00296 DEBUGMSGTL(("subtree", "didn't find a subtree for context: \"%s\"\n", 00297 context_name)); 00298 return NULL; 00299 } 00300 00301 netsnmp_subtree * 00302 add_subtree(netsnmp_subtree *new_tree, const char *context_name) 00303 { 00304 subtree_context_cache *ptr = SNMP_MALLOC_TYPEDEF(subtree_context_cache); 00305 00306 if (!context_name) { 00307 context_name = ""; 00308 } 00309 00310 if (!ptr) { 00311 return NULL; 00312 } 00313 00314 DEBUGMSGTL(("subtree", "adding subtree for context: \"%s\"\n", 00315 context_name)); 00316 00317 ptr->next = context_subtrees; 00318 ptr->first_subtree = new_tree; 00319 ptr->context_name = strdup(context_name); 00320 context_subtrees = ptr; 00321 00322 return ptr->first_subtree; 00323 } 00324 00325 netsnmp_subtree * 00326 netsnmp_subtree_replace_first(netsnmp_subtree *new_tree, 00327 const char *context_name) 00328 { 00329 subtree_context_cache *ptr; 00330 if (!context_name) { 00331 context_name = ""; 00332 } 00333 for (ptr = context_subtrees; ptr != NULL; ptr = ptr->next) { 00334 if (ptr->context_name != NULL && 00335 strcmp(ptr->context_name, context_name) == 0) { 00336 ptr->first_subtree = new_tree; 00337 return ptr->first_subtree; 00338 } 00339 } 00340 return add_subtree(new_tree, context_name); 00341 } 00342 00343 NETSNMP_INLINE void 00344 netsnmp_subtree_change_next(netsnmp_subtree *ptr, netsnmp_subtree *thenext) 00345 { 00346 ptr->next = thenext; 00347 if (thenext) 00348 netsnmp_oid_compare_ll(ptr->start_a, 00349 ptr->start_len, 00350 thenext->start_a, 00351 thenext->start_len, 00352 &thenext->oid_off); 00353 } 00354 00355 NETSNMP_INLINE void 00356 netsnmp_subtree_change_prev(netsnmp_subtree *ptr, netsnmp_subtree *theprev) 00357 { 00358 ptr->prev = theprev; 00359 if (theprev) 00360 netsnmp_oid_compare_ll(theprev->start_a, 00361 theprev->start_len, 00362 ptr->start_a, 00363 ptr->start_len, 00364 &ptr->oid_off); 00365 } 00366 00367 int 00368 netsnmp_subtree_compare(const netsnmp_subtree *ap, const netsnmp_subtree *bp) 00369 { 00370 return snmp_oid_compare(ap->name_a, ap->namelen, bp->name_a, bp->namelen); 00371 } 00372 00373 void 00374 netsnmp_subtree_join(netsnmp_subtree *root) 00375 { 00376 netsnmp_subtree *s, *tmp, *c, *d; 00377 00378 while (root != NULL) { 00379 s = root->next; 00380 while (s != NULL && root->reginfo == s->reginfo) { 00381 tmp = s->next; 00382 DEBUGMSGTL(("subtree", "root start ")); 00383 DEBUGMSGOID(("subtree", root->start_a, root->start_len)); 00384 DEBUGMSG(("subtree", " (original end ")); 00385 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00386 DEBUGMSG(("subtree", ")\n")); 00387 DEBUGMSGTL(("subtree", " JOINING to ")); 00388 DEBUGMSGOID(("subtree", s->start_a, s->start_len)); 00389 00390 SNMP_FREE(root->end_a); 00391 root->end_a = s->end_a; 00392 root->end_len = s->end_len; 00393 s->end_a = NULL; 00394 00395 for (c = root; c != NULL; c = c->children) { 00396 netsnmp_subtree_change_next(c, s->next); 00397 } 00398 for (c = s; c != NULL; c = c->children) { 00399 netsnmp_subtree_change_prev(c, root); 00400 } 00401 DEBUGMSG(("subtree", " so new end ")); 00402 DEBUGMSGOID(("subtree", root->end_a, root->end_len)); 00403 DEBUGMSG(("subtree", "\n")); 00404 /* 00405 * Probably need to free children too? 00406 */ 00407 for (c = s->children; c != NULL; c = d) { 00408 d = c->children; 00409 netsnmp_subtree_free(c); 00410 } 00411 netsnmp_subtree_free(s); 00412 s = tmp; 00413 } 00414 root = root->next; 00415 } 00416 } 00417 00418 00419 /* 00420 * Split the subtree into two at the specified point, 00421 * returning the new (second) subtree 00422 */ 00423 netsnmp_subtree * 00424 netsnmp_subtree_split(netsnmp_subtree *current, oid name[], int name_len) 00425 { 00426 struct variable *vp = NULL; 00427 netsnmp_subtree *new_sub, *ptr; 00428 int i = 0, rc = 0, rc2 = 0; 00429 size_t common_len = 0; 00430 char *cp; 00431 oid *tmp_a, *tmp_b; 00432 00433 if (snmp_oid_compare(name, name_len, current->end_a, current->end_len)>0) { 00434 /* Split comes after the end of this subtree */ 00435 return NULL; 00436 } 00437 00438 new_sub = netsnmp_subtree_deepcopy(current); 00439 if (new_sub == NULL) { 00440 return NULL; 00441 } 00442 00443 /* Set up the point of division. */ 00444 tmp_a = snmp_duplicate_objid(name, name_len); 00445 if (tmp_a == NULL) { 00446 netsnmp_subtree_free(new_sub); 00447 return NULL; 00448 } 00449 tmp_b = snmp_duplicate_objid(name, name_len); 00450 if (tmp_b == NULL) { 00451 netsnmp_subtree_free(new_sub); 00452 SNMP_FREE(tmp_a); 00453 return NULL; 00454 } 00455 00456 SNMP_FREE(current->end_a); 00457 current->end_a = tmp_a; 00458 current->end_len = name_len; 00459 if (new_sub->start_a != NULL) { 00460 SNMP_FREE(new_sub->start_a); 00461 } 00462 new_sub->start_a = tmp_b; 00463 new_sub->start_len = name_len; 00464 00465 /* Split the variables between the two new subtrees. */ 00466 i = current->variables_len; 00467 current->variables_len = 0; 00468 00469 for (vp = current->variables; i > 0; i--) { 00470 /* Note that the variable "name" field omits the prefix common to the 00471 whole registration, hence the strange comparison here. */ 00472 00473 rc = snmp_oid_compare(vp->name, vp->namelen, 00474 name + current->namelen, 00475 name_len - current->namelen); 00476 00477 if (name_len - current->namelen > vp->namelen) { 00478 common_len = vp->namelen; 00479 } else { 00480 common_len = name_len - current->namelen; 00481 } 00482 00483 rc2 = snmp_oid_compare(vp->name, common_len, 00484 name + current->namelen, common_len); 00485 00486 if (rc >= 0) { 00487 break; /* All following variables belong to the second subtree */ 00488 } 00489 00490 current->variables_len++; 00491 if (rc2 < 0) { 00492 new_sub->variables_len--; 00493 cp = (char *) new_sub->variables; 00494 new_sub->variables = (struct variable *)(cp + 00495 new_sub->variables_width); 00496 } 00497 vp = (struct variable *) ((char *) vp + current->variables_width); 00498 } 00499 00500 /* Delegated trees should retain their variables regardless */ 00501 if (current->variables_len > 0 && 00502 IS_DELEGATED((u_char) current->variables[0].type)) { 00503 new_sub->variables_len = 1; 00504 new_sub->variables = current->variables; 00505 } 00506 00507 /* Propogate this split down through any children */ 00508 if (current->children) { 00509 new_sub->children = netsnmp_subtree_split(current->children, 00510 name, name_len); 00511 } 00512 00513 /* Retain the correct linking of the list */ 00514 for (ptr = current; ptr != NULL; ptr = ptr->children) { 00515 netsnmp_subtree_change_next(ptr, new_sub); 00516 } 00517 for (ptr = new_sub; ptr != NULL; ptr = ptr->children) { 00518 netsnmp_subtree_change_prev(ptr, current); 00519 } 00520 for (ptr = new_sub->next; ptr != NULL; ptr=ptr->children) { 00521 netsnmp_subtree_change_prev(ptr, new_sub); 00522 } 00523 00524 return new_sub; 00525 } 00526 00527 int 00528 netsnmp_subtree_load(netsnmp_subtree *new_sub, const char *context_name) 00529 { 00530 netsnmp_subtree *tree1, *tree2, *new2; 00531 netsnmp_subtree *prev, *next; 00532 int res, rc = 0; 00533 00534 if (new_sub == NULL) { 00535 return MIB_REGISTERED_OK; /* Degenerate case */ 00536 } 00537 00538 if (!netsnmp_subtree_find_first(context_name)) { 00539 static int inloop = 0; 00540 if (!inloop) { 00541 oid ccitt[1] = { 0 }; 00542 oid iso[1] = { 1 }; 00543 oid joint_ccitt_iso[1] = { 2 }; 00544 inloop = 1; 00545 netsnmp_register_null_context(snmp_duplicate_objid(ccitt, 1), 1, 00546 context_name); 00547 netsnmp_register_null_context(snmp_duplicate_objid(iso, 1), 1, 00548 context_name); 00549 netsnmp_register_null_context(snmp_duplicate_objid(joint_ccitt_iso, 1), 00550 1, context_name); 00551 inloop = 0; 00552 } 00553 } 00554 00555 /* Find the subtree that contains the start of the new subtree (if 00556 any)...*/ 00557 00558 tree1 = netsnmp_subtree_find(new_sub->start_a, new_sub->start_len, 00559 NULL, context_name); 00560 00561 /* ... and the subtree that follows the new one (NULL implies this is the 00562 final region covered). */ 00563 00564 if (tree1 == NULL) { 00565 tree2 = netsnmp_subtree_find_next(new_sub->start_a, new_sub->start_len, 00566 NULL, context_name); 00567 } else { 00568 tree2 = tree1->next; 00569 } 00570 00571 /* Handle new subtrees that start in virgin territory. */ 00572 00573 if (tree1 == NULL) { 00574 new2 = NULL; 00575 /* Is there any overlap with later subtrees? */ 00576 if (tree2 && snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00577 tree2->start_a, tree2->start_len) > 0) { 00578 new2 = netsnmp_subtree_split(new_sub, 00579 tree2->start_a, tree2->start_len); 00580 } 00581 00582 /* Link the new subtree (less any overlapping region) with the list of 00583 existing registrations. */ 00584 00585 if (tree2) { 00586 netsnmp_subtree_change_prev(new_sub, tree2->prev); 00587 netsnmp_subtree_change_prev(tree2, new_sub); 00588 } else { 00589 netsnmp_subtree_change_prev(new_sub, 00590 netsnmp_subtree_find_prev(new_sub->start_a, 00591 new_sub->start_len, NULL, context_name)); 00592 00593 if (new_sub->prev) { 00594 netsnmp_subtree_change_next(new_sub->prev, new_sub); 00595 } else { 00596 netsnmp_subtree_replace_first(new_sub, context_name); 00597 } 00598 00599 netsnmp_subtree_change_next(new_sub, tree2); 00600 00601 /* If there was any overlap, recurse to merge in the overlapping 00602 region (including anything that may follow the overlap). */ 00603 if (new2) { 00604 return netsnmp_subtree_load(new2, context_name); 00605 } 00606 } 00607 } else { 00608 /* If the new subtree starts *within* an existing registration 00609 (rather than at the same point as it), then split the existing 00610 subtree at this point. */ 00611 00612 if (netsnmp_oid_equals(new_sub->start_a, new_sub->start_len, 00613 tree1->start_a, tree1->start_len) != 0) { 00614 tree1 = netsnmp_subtree_split(tree1, new_sub->start_a, 00615 new_sub->start_len); 00616 } 00617 00618 if (tree1 == NULL) { 00619 return MIB_REGISTRATION_FAILED; 00620 } 00621 00622 /* Now consider the end of this existing subtree: 00623 00624 If it matches the new subtree precisely, 00625 simply merge the new one into the list of children 00626 00627 If it includes the whole of the new subtree, 00628 split it at the appropriate point, and merge again 00629 00630 If the new subtree extends beyond this existing region, 00631 split it, and recurse to merge the two parts. */ 00632 00633 rc = snmp_oid_compare(new_sub->end_a, new_sub->end_len, 00634 tree1->end_a, tree1->end_len); 00635 00636 switch (rc) { 00637 00638 case -1: 00639 /* Existing subtree contains new one. */ 00640 netsnmp_subtree_split(tree1, new_sub->end_a, new_sub->end_len); 00641 /* Fall Through */ 00642 00643 case 0: 00644 /* The two trees match precisely. */ 00645 00646 /* Note: This is the only point where the original registration 00647 OID ("name") is used. */ 00648 00649 prev = NULL; 00650 next = tree1; 00651 00652 while (next && next->namelen > new_sub->namelen) { 00653 prev = next; 00654 next = next->children; 00655 } 00656 00657 while (next && next->namelen == new_sub->namelen && 00658 next->priority < new_sub->priority ) { 00659 prev = next; 00660 next = next->children; 00661 } 00662 00663 if (next && (next->namelen == new_sub->namelen) && 00664 (next->priority == new_sub->priority)) { 00665 if (new_sub->namelen != 1) /* ignore root OID dups */ 00666 snmp_log(LOG_ERR, "duplicate registration (%s, %s)", next->label_a, new_sub->label_a); 00667 return MIB_DUPLICATE_REGISTRATION; 00668 } 00669 00670 if (prev) { 00671 prev->children = new_sub; 00672 new_sub->children = next; 00673 netsnmp_subtree_change_prev(new_sub, prev->prev); 00674 netsnmp_subtree_change_next(new_sub, prev->next); 00675 } else { 00676 new_sub->children = next; 00677 netsnmp_subtree_change_prev(new_sub, next->prev); 00678 netsnmp_subtree_change_next(new_sub, next->next); 00679 00680 for (next = new_sub->next; next != NULL;next = next->children){ 00681 netsnmp_subtree_change_prev(next, new_sub); 00682 } 00683 00684 for (prev = new_sub->prev; prev != NULL;prev = prev->children){ 00685 netsnmp_subtree_change_next(prev, new_sub); 00686 } 00687 } 00688 break; 00689 00690 case 1: 00691 /* New subtree contains the existing one. */ 00692 new2 = netsnmp_subtree_split(new_sub, tree1->end_a,tree1->end_len); 00693 res = netsnmp_subtree_load(new_sub, context_name); 00694 if (res != MIB_REGISTERED_OK) { 00695 netsnmp_subtree_free(new2); 00696 return res; 00697 } 00698 return netsnmp_subtree_load(new2, context_name); 00699 } 00700 } 00701 return 0; 00702 } 00703 00704 /* 00705 * Note: reginfo will be freed on failures 00706 */ 00707 int 00708 netsnmp_register_mib(const char *moduleName, 00709 struct variable *var, 00710 size_t varsize, 00711 size_t numvars, 00712 oid * mibloc, 00713 size_t mibloclen, 00714 int priority, 00715 int range_subid, 00716 oid range_ubound, 00717 netsnmp_session * ss, 00718 const char *context, 00719 int timeout, 00720 int flags, 00721 netsnmp_handler_registration *reginfo, 00722 int perform_callback) 00723 { 00724 netsnmp_subtree *subtree, *sub2; 00725 int res, i; 00726 struct register_parameters reg_parms; 00727 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 00728 00729 if (moduleName == NULL || 00730 mibloc == NULL) { 00731 /* Shouldn't happen ??? */ 00732 netsnmp_handler_registration_free(reginfo); 00733 return MIB_REGISTRATION_FAILED; 00734 } 00735 subtree = (netsnmp_subtree *)calloc(1, sizeof(netsnmp_subtree)); 00736 if (subtree == NULL) { 00737 netsnmp_handler_registration_free(reginfo); 00738 return MIB_REGISTRATION_FAILED; 00739 } 00740 00741 DEBUGMSGTL(("register_mib", "registering \"%s\" at ", moduleName)); 00742 DEBUGMSGOIDRANGE(("register_mib", mibloc, mibloclen, range_subid, 00743 range_ubound)); 00744 DEBUGMSG(("register_mib", " with context \"%s\"\n", 00745 SNMP_STRORNULL(context))); 00746 00747 /* 00748 * verify that the passed context is equal to the context 00749 * in the reginfo. 00750 * (which begs the question, why do we have both? It appears that the 00751 * reginfo item didn't appear til 5.2) 00752 */ 00753 if( ((NULL == context) && (NULL != reginfo->contextName)) || 00754 ((NULL != context) && (NULL == reginfo->contextName)) || 00755 ( ((NULL != context) && (NULL != reginfo->contextName)) && 00756 (0 != strcmp(context, reginfo->contextName))) ) { 00757 snmp_log(LOG_WARNING,"context passed during registration does not " 00758 "equal the reginfo contextName! ('%s' != '%s')\n", 00759 context, reginfo->contextName); 00760 netsnmp_assert(!"register context == reginfo->contextName"); /* always false */ 00761 } 00762 00763 /* Create the new subtree node being registered. */ 00764 00765 subtree->reginfo = reginfo; 00766 subtree->name_a = snmp_duplicate_objid(mibloc, mibloclen); 00767 subtree->start_a = snmp_duplicate_objid(mibloc, mibloclen); 00768 subtree->end_a = snmp_duplicate_objid(mibloc, mibloclen); 00769 subtree->label_a = strdup(moduleName); 00770 if (subtree->name_a == NULL || subtree->start_a == NULL || 00771 subtree->end_a == NULL || subtree->label_a == NULL) { 00772 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00773 return MIB_REGISTRATION_FAILED; 00774 } 00775 subtree->namelen = (u_char)mibloclen; 00776 subtree->start_len = (u_char)mibloclen; 00777 subtree->end_len = (u_char)mibloclen; 00778 subtree->end_a[mibloclen - 1]++; 00779 00780 if (var != NULL) { 00781 subtree->variables = (struct variable *)malloc(varsize*numvars); 00782 if (subtree->variables == NULL) { 00783 netsnmp_subtree_free(subtree); /* also frees reginfo */ 00784 return MIB_REGISTRATION_FAILED; 00785 } 00786 memcpy(subtree->variables, var, numvars*varsize); 00787 subtree->variables_len = numvars; 00788 subtree->variables_width = varsize; 00789 } 00790 subtree->priority = priority; 00791 subtree->timeout = timeout; 00792 subtree->range_subid = range_subid; 00793 subtree->range_ubound = range_ubound; 00794 subtree->session = ss; 00795 subtree->flags = (u_char)flags; /* used to identify instance oids */ 00796 subtree->flags |= SUBTREE_ATTACHED; 00797 subtree->global_cacheid = reginfo->global_cacheid; 00798 00799 netsnmp_set_lookup_cache_size(0); 00800 res = netsnmp_subtree_load(subtree, context); 00801 00802 /* If registering a range, use the first subtree as a template for the 00803 rest of the range. */ 00804 00805 if (res == MIB_REGISTERED_OK && range_subid != 0) { 00806 for (i = mibloc[range_subid - 1] + 1; i <= (int)range_ubound; i++) { 00807 sub2 = netsnmp_subtree_deepcopy(subtree); 00808 00809 if (sub2 == NULL) { 00810 unregister_mib_context(mibloc, mibloclen, priority, 00811 range_subid, range_ubound, context); 00812 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00813 invalidate_lookup_cache(context); 00814 return MIB_REGISTRATION_FAILED; 00815 } 00816 00817 sub2->name_a[range_subid - 1] = i; 00818 sub2->start_a[range_subid - 1] = i; 00819 sub2->end_a[range_subid - 1] = i; /* XXX - ???? */ 00820 if (range_subid == (int)mibloclen) { 00821 ++sub2->end_a[range_subid - 1]; 00822 } 00823 sub2->flags |= SUBTREE_ATTACHED; 00824 sub2->global_cacheid = reginfo->global_cacheid; 00825 /* FRQ This is essential for requests to succeed! */ 00826 sub2->reginfo->rootoid[range_subid - 1] = i; 00827 00828 res = netsnmp_subtree_load(sub2, context); 00829 if (res != MIB_REGISTERED_OK) { 00830 unregister_mib_context(mibloc, mibloclen, priority, 00831 range_subid, range_ubound, context); 00832 netsnmp_subtree_free(sub2); 00833 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00834 invalidate_lookup_cache(context); 00835 return res; 00836 } 00837 } 00838 } else if (res == MIB_DUPLICATE_REGISTRATION || 00839 res == MIB_REGISTRATION_FAILED) { 00840 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00841 invalidate_lookup_cache(context); 00842 netsnmp_subtree_free(subtree); 00843 return res; 00844 } 00845 00846 /* 00847 * mark the MIB as detached, if there's no master agent present as of now 00848 */ 00849 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00850 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { 00851 extern struct snmp_session *main_session; 00852 if (main_session == NULL) { 00853 register_mib_detach_node(subtree); 00854 } 00855 } 00856 00857 if (res == MIB_REGISTERED_OK && perform_callback) { 00858 memset(®_parms, 0x0, sizeof(reg_parms)); 00859 reg_parms.name = mibloc; 00860 reg_parms.namelen = mibloclen; 00861 reg_parms.priority = priority; 00862 reg_parms.range_subid = range_subid; 00863 reg_parms.range_ubound = range_ubound; 00864 reg_parms.timeout = timeout; 00865 reg_parms.flags = (u_char) flags; 00866 reg_parms.contextName = context; 00867 reg_parms.session = ss; 00868 reg_parms.reginfo = reginfo; 00869 reg_parms.contextName = context; 00870 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00871 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00872 } 00873 00874 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 00875 invalidate_lookup_cache(context); 00876 return res; 00877 } 00878 00879 /* 00880 * Reattach a particular node. 00881 */ 00882 00883 static void 00884 register_mib_reattach_node(netsnmp_subtree *s) 00885 { 00886 if ((s != NULL) && (s->namelen > 1) && !(s->flags & SUBTREE_ATTACHED)) { 00887 struct register_parameters reg_parms; 00888 /* 00889 * only do registrations that are not the top level nodes 00890 */ 00891 memset(®_parms, 0x0, sizeof(reg_parms)); 00892 00893 /* 00894 * XXX: do this better 00895 */ 00896 reg_parms.name = s->name_a; 00897 reg_parms.namelen = s->namelen; 00898 reg_parms.priority = s->priority; 00899 reg_parms.range_subid = s->range_subid; 00900 reg_parms.range_ubound = s->range_ubound; 00901 reg_parms.timeout = s->timeout; 00902 reg_parms.flags = s->flags; 00903 reg_parms.session = s->session; 00904 reg_parms.reginfo = s->reginfo; 00905 /* XXX: missing in subtree: reg_parms.contextName = s->context; */ 00906 if ((NULL != s->reginfo) && (NULL != s->reginfo->contextName)) 00907 reg_parms.contextName = s->reginfo->contextName; 00908 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 00909 SNMPD_CALLBACK_REGISTER_OID, ®_parms); 00910 s->flags |= SUBTREE_ATTACHED; 00911 } 00912 } 00913 00914 /* 00915 * Call callbacks to reattach all our nodes. 00916 */ 00917 00918 void 00919 register_mib_reattach(void) 00920 { 00921 netsnmp_subtree *s, *t; 00922 subtree_context_cache *ptr; 00923 00924 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00925 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00926 register_mib_reattach_node(s); 00927 for (t = s->children; t != NULL; t = t->children) { 00928 register_mib_reattach_node(t); 00929 } 00930 } 00931 } 00932 } 00933 00934 /* 00935 * Mark a node as detached. 00936 */ 00937 00938 static void 00939 register_mib_detach_node(netsnmp_subtree *s) 00940 { 00941 if (s != NULL) { 00942 s->flags = s->flags & ~SUBTREE_ATTACHED; 00943 } 00944 } 00945 00946 /* 00947 * Mark all our registered OIDs as detached. This is only really 00948 * useful for subagent protocols, when a connection is lost or 00949 * something. 00950 */ 00951 00952 void 00953 register_mib_detach(void) 00954 { 00955 netsnmp_subtree *s, *t; 00956 subtree_context_cache *ptr; 00957 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 00958 for (s = ptr->first_subtree; s != NULL; s = s->next) { 00959 register_mib_detach_node(s); 00960 for (t = s->children; t != NULL; t = t->children) { 00961 register_mib_detach_node(t); 00962 } 00963 } 00964 } 00965 } 00966 00967 int 00968 register_mib_context(const char *moduleName, 00969 struct variable *var, 00970 size_t varsize, 00971 size_t numvars, 00972 oid * mibloc, 00973 size_t mibloclen, 00974 int priority, 00975 int range_subid, 00976 oid range_ubound, 00977 netsnmp_session * ss, 00978 const char *context, int timeout, int flags) 00979 { 00980 return netsnmp_register_old_api(moduleName, var, varsize, numvars, 00981 mibloc, mibloclen, priority, 00982 range_subid, range_ubound, ss, context, 00983 timeout, flags); 00984 } 00985 00986 int 00987 register_mib_range(const char *moduleName, 00988 struct variable *var, 00989 size_t varsize, 00990 size_t numvars, 00991 oid * mibloc, 00992 size_t mibloclen, 00993 int priority, 00994 int range_subid, oid range_ubound, netsnmp_session * ss) 00995 { 00996 return register_mib_context(moduleName, var, varsize, numvars, 00997 mibloc, mibloclen, priority, 00998 range_subid, range_ubound, ss, "", -1, 0); 00999 } 01000 01001 int 01002 register_mib_priority(const char *moduleName, 01003 struct variable *var, 01004 size_t varsize, 01005 size_t numvars, 01006 oid * mibloc, size_t mibloclen, int priority) 01007 { 01008 return register_mib_range(moduleName, var, varsize, numvars, 01009 mibloc, mibloclen, priority, 0, 0, NULL); 01010 } 01011 01012 int 01013 register_mib(const char *moduleName, 01014 struct variable *var, 01015 size_t varsize, 01016 size_t numvars, oid * mibloc, size_t mibloclen) 01017 { 01018 return register_mib_priority(moduleName, var, varsize, numvars, 01019 mibloc, mibloclen, DEFAULT_MIB_PRIORITY); 01020 } 01021 01022 void 01023 netsnmp_subtree_unload(netsnmp_subtree *sub, netsnmp_subtree *prev, const char *context) 01024 { 01025 netsnmp_subtree *ptr; 01026 01027 DEBUGMSGTL(("register_mib", "unload(")); 01028 if (sub != NULL) { 01029 DEBUGMSGOID(("register_mib", sub->start_a, sub->start_len)); 01030 } else { 01031 DEBUGMSG(("register_mib", "[NIL]")); 01032 } 01033 DEBUGMSG(("register_mib", ", ")); 01034 if (prev != NULL) { 01035 DEBUGMSGOID(("register_mib", prev->start_a, prev->start_len)); 01036 } else { 01037 DEBUGMSG(("register_mib", "[NIL]")); 01038 } 01039 DEBUGMSG(("register_mib", ")\n")); 01040 01041 if (prev != NULL) { /* non-leading entries are easy */ 01042 prev->children = sub->children; 01043 invalidate_lookup_cache(context); 01044 return; 01045 } 01046 /* 01047 * otherwise, we need to amend our neighbours as well 01048 */ 01049 01050 if (sub->children == NULL) { /* just remove this node completely */ 01051 for (ptr = sub->prev; ptr; ptr = ptr->children) { 01052 netsnmp_subtree_change_next(ptr, sub->next); 01053 } 01054 for (ptr = sub->next; ptr; ptr = ptr->children) { 01055 netsnmp_subtree_change_prev(ptr, sub->prev); 01056 } 01057 01058 if (sub->prev == NULL) { 01059 netsnmp_subtree_replace_first(sub->next, context); 01060 } 01061 01062 } else { 01063 for (ptr = sub->prev; ptr; ptr = ptr->children) 01064 netsnmp_subtree_change_next(ptr, sub->children); 01065 for (ptr = sub->next; ptr; ptr = ptr->children) 01066 netsnmp_subtree_change_prev(ptr, sub->children); 01067 01068 if (sub->prev == NULL) { 01069 netsnmp_subtree_replace_first(sub->children, context); 01070 } 01071 } 01072 invalidate_lookup_cache(context); 01073 } 01074 01104 int 01105 unregister_mib_context(oid * name, size_t len, int priority, 01106 int range_subid, oid range_ubound, 01107 const char *context) 01108 { 01109 netsnmp_subtree *list, *myptr; 01110 netsnmp_subtree *prev, *child, *next; /* loop through children */ 01111 struct register_parameters reg_parms; 01112 int old_lookup_cache_val = netsnmp_get_lookup_cache_size(); 01113 int unregistering = 1; 01114 int orig_subid_val = -1; 01115 01116 netsnmp_set_lookup_cache_size(0); 01117 01118 if ((range_subid != 0) && (range_subid <= len)) 01119 orig_subid_val = name[range_subid-1]; 01120 01121 while(unregistering){ 01122 DEBUGMSGTL(("register_mib", "unregistering ")); 01123 DEBUGMSGOIDRANGE(("register_mib", name, len, range_subid, range_ubound)); 01124 DEBUGMSG(("register_mib", "\n")); 01125 01126 list = netsnmp_subtree_find(name, len, netsnmp_subtree_find_first(context), 01127 context); 01128 if (list == NULL) { 01129 return MIB_NO_SUCH_REGISTRATION; 01130 } 01131 01132 for (child = list, prev = NULL; child != NULL; 01133 prev = child, child = child->children) { 01134 if (netsnmp_oid_equals(child->name_a, child->namelen, name, len) == 0 && 01135 child->priority == priority) { 01136 break; /* found it */ 01137 } 01138 } 01139 01140 if (child == NULL) { 01141 return MIB_NO_SUCH_REGISTRATION; 01142 } 01143 01144 netsnmp_subtree_unload(child, prev, context); 01145 myptr = child; /* remember this for later */ 01146 01147 /* 01148 * Now handle any occurances in the following subtrees, 01149 * as a result of splitting this range. Due to the 01150 * nature of the way such splits work, the first 01151 * subtree 'slice' that doesn't refer to the given 01152 * name marks the end of the original region. 01153 * 01154 * This should also serve to register ranges. 01155 */ 01156 01157 for (list = myptr->next; list != NULL; list = next) { 01158 next = list->next; /* list gets freed sometimes; cache next */ 01159 for (child = list, prev = NULL; child != NULL; 01160 prev = child, child = child->children) { 01161 if ((netsnmp_oid_equals(child->name_a, child->namelen, 01162 name, len) == 0) && 01163 (child->priority == priority)) { 01164 netsnmp_subtree_unload(child, prev, context); 01165 netsnmp_subtree_free(child); 01166 break; 01167 } 01168 } 01169 if (child == NULL) /* Didn't find the given name */ 01170 break; 01171 } 01172 01173 /* Maybe we are in a range... */ 01174 if (orig_subid_val != -1){ 01175 if (++name[range_subid-1] >= orig_subid_val+range_ubound) 01176 { 01177 unregistering=0; 01178 name[range_subid-1] = orig_subid_val; 01179 } 01180 } 01181 else { 01182 unregistering=0; 01183 } 01184 } 01185 01186 memset(®_parms, 0x0, sizeof(reg_parms)); 01187 reg_parms.name = name; 01188 reg_parms.namelen = len; 01189 reg_parms.priority = priority; 01190 reg_parms.range_subid = range_subid; 01191 reg_parms.range_ubound = range_ubound; 01192 reg_parms.flags = 0x00; /* this is okay I think */ 01193 reg_parms.contextName = context; 01194 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01195 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01196 01197 netsnmp_subtree_free(myptr); 01198 netsnmp_set_lookup_cache_size(old_lookup_cache_val); 01199 invalidate_lookup_cache(context); 01200 return MIB_UNREGISTERED_OK; 01201 } 01202 01203 int 01204 netsnmp_unregister_mib_table_row(oid * name, size_t len, int priority, 01205 int var_subid, oid range_ubound, 01206 const char *context) 01207 { 01208 netsnmp_subtree *list, *myptr, *futureptr; 01209 netsnmp_subtree *prev, *child; /* loop through children */ 01210 struct register_parameters reg_parms; 01211 oid range_lbound = name[var_subid - 1]; 01212 01213 DEBUGMSGTL(("register_mib", "unregistering ")); 01214 DEBUGMSGOIDRANGE(("register_mib", name, len, var_subid, range_ubound)); 01215 DEBUGMSG(("register_mib", "\n")); 01216 01217 for (; name[var_subid - 1] <= range_ubound; name[var_subid - 1]++) { 01218 list = netsnmp_subtree_find(name, len, 01219 netsnmp_subtree_find_first(context), context); 01220 01221 if (list == NULL) { 01222 continue; 01223 } 01224 01225 for (child = list, prev = NULL; child != NULL; 01226 prev = child, child = child->children) { 01227 01228 if (netsnmp_oid_equals(child->name_a, child->namelen, 01229 name, len) == 0 && 01230 (child->priority == priority)) { 01231 break; /* found it */ 01232 } 01233 } 01234 01235 if (child == NULL) { 01236 continue; 01237 } 01238 01239 netsnmp_subtree_unload(child, prev, context); 01240 myptr = child; /* remember this for later */ 01241 01242 for (list = myptr->next; list != NULL; list = futureptr) { 01243 /* remember the next spot in the list in case we free this node */ 01244 futureptr = list->next; 01245 01246 /* check each child */ 01247 for (child = list, prev = NULL; child != NULL; 01248 prev = child, child = child->children) { 01249 01250 if (netsnmp_oid_equals(child->name_a, child->namelen, 01251 name, len) == 0 && 01252 (child->priority == priority)) { 01253 netsnmp_subtree_unload(child, prev, context); 01254 netsnmp_subtree_free(child); 01255 break; 01256 } 01257 } 01258 01259 /* XXX: wjh: not sure why we're bailing here */ 01260 if (child == NULL) { /* Didn't find the given name */ 01261 break; 01262 } 01263 } 01264 netsnmp_subtree_free(myptr); 01265 } 01266 01267 name[var_subid - 1] = range_lbound; 01268 memset(®_parms, 0x0, sizeof(reg_parms)); 01269 reg_parms.name = name; 01270 reg_parms.namelen = len; 01271 reg_parms.priority = priority; 01272 reg_parms.range_subid = var_subid; 01273 reg_parms.range_ubound = range_ubound; 01274 reg_parms.flags = 0x00; /* this is okay I think */ 01275 reg_parms.contextName = context; 01276 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01277 SNMPD_CALLBACK_UNREGISTER_OID, ®_parms); 01278 01279 return 0; 01280 } 01281 01282 int 01283 unregister_mib_range(oid * name, size_t len, int priority, 01284 int range_subid, oid range_ubound) 01285 { 01286 return unregister_mib_context(name, len, priority, range_subid, 01287 range_ubound, ""); 01288 } 01289 01290 int 01291 unregister_mib_priority(oid * name, size_t len, int priority) 01292 { 01293 return unregister_mib_range(name, len, priority, 0, 0); 01294 } 01295 01296 int 01297 unregister_mib(oid * name, size_t len) 01298 { 01299 return unregister_mib_priority(name, len, DEFAULT_MIB_PRIORITY); 01300 } 01301 01302 void 01303 unregister_mibs_by_session(netsnmp_session * ss) 01304 { 01305 netsnmp_subtree *list, *list2; 01306 netsnmp_subtree *child, *prev, *next_child; 01307 struct register_parameters rp; 01308 subtree_context_cache *contextptr; 01309 01310 DEBUGMSGTL(("register_mib", "unregister_mibs_by_session(%p) ctxt \"%s\"\n", 01311 ss, (ss && ss->contextName) ? ss->contextName : "[NIL]")); 01312 01313 for (contextptr = get_top_context_cache(); contextptr != NULL; 01314 contextptr = contextptr->next) { 01315 for (list = contextptr->first_subtree; list != NULL; list = list2) { 01316 list2 = list->next; 01317 01318 for (child = list, prev = NULL; child != NULL; child = next_child){ 01319 next_child = child->children; 01320 01321 if (((!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && 01322 child->session == ss) || 01323 (!(!ss || ss->flags & SNMP_FLAGS_SUBSESSION) && child->session && 01324 child->session->subsession == ss)) { 01325 01326 memset(&rp,0x0,sizeof(rp)); 01327 rp.name = child->name_a; 01328 child->name_a = NULL; 01329 rp.namelen = child->namelen; 01330 rp.priority = child->priority; 01331 rp.range_subid = child->range_subid; 01332 rp.range_ubound = child->range_ubound; 01333 rp.timeout = child->timeout; 01334 rp.flags = child->flags; 01335 if ((NULL != child->reginfo) && 01336 (NULL != child->reginfo->contextName)) 01337 rp.contextName = child->reginfo->contextName; 01338 01339 if (child->reginfo != NULL) { 01340 /* 01341 * Don't let's free the session pointer just yet! 01342 */ 01343 child->reginfo->handler->myvoid = NULL; 01344 netsnmp_handler_registration_free(child->reginfo); 01345 child->reginfo = NULL; 01346 } 01347 01348 netsnmp_subtree_unload(child, prev, contextptr->context_name); 01349 netsnmp_subtree_free(child); 01350 01351 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01352 SNMPD_CALLBACK_UNREGISTER_OID, &rp); 01353 SNMP_FREE(rp.name); 01354 } else { 01355 prev = child; 01356 } 01357 } 01358 } 01359 netsnmp_subtree_join(contextptr->first_subtree); 01360 } 01361 } 01362 01363 /* 01364 * in_a_view: determines if a given snmp_pdu is allowed to see a 01365 * given name/namelen OID pointer 01366 * name IN - name of var, OUT - name matched 01367 * nameLen IN -number of sub-ids in name, OUT - subid-is in matched name 01368 * pi IN - relevant auth info re PDU 01369 * cvp IN - relevant auth info re mib module 01370 */ 01371 01372 int 01373 in_a_view(oid *name, size_t *namelen, netsnmp_pdu *pdu, int type) 01374 { 01375 struct view_parameters view_parms; 01376 01377 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01378 /* Enable bypassing of view-based access control */ 01379 return VACM_SUCCESS; 01380 } 01381 01382 /* 01383 * check for v1 and counter64s, since snmpv1 doesn't support it 01384 */ 01385 #ifndef NETSNMP_DISABLE_SNMPV1 01386 if (pdu->version == SNMP_VERSION_1 && type == ASN_COUNTER64) { 01387 return VACM_NOTINVIEW; 01388 } 01389 #endif 01390 01391 view_parms.pdu = pdu; 01392 view_parms.name = name; 01393 if (namelen != NULL) { 01394 view_parms.namelen = *namelen; 01395 } else { 01396 view_parms.namelen = 0; 01397 } 01398 view_parms.errorcode = 0; 01399 view_parms.check_subtree = 0; 01400 01401 switch (pdu->version) { 01402 #ifndef NETSNMP_DISABLE_SNMPV1 01403 case SNMP_VERSION_1: 01404 #endif 01405 #ifndef NETSNMP_DISABLE_SNMPV2C 01406 case SNMP_VERSION_2c: 01407 #endif 01408 case SNMP_VERSION_3: 01409 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01410 SNMPD_CALLBACK_ACM_CHECK, &view_parms); 01411 return view_parms.errorcode; 01412 } 01413 return VACM_NOSECNAME; 01414 } 01415 01416 /* 01417 * check_acces: determines if a given snmp_pdu is ever going to be 01418 * allowed to do anynthing or if it's not going to ever be 01419 * authenticated. 01420 */ 01421 int 01422 check_access(netsnmp_pdu *pdu) 01423 { /* IN - pdu being checked */ 01424 struct view_parameters view_parms; 01425 view_parms.pdu = pdu; 01426 view_parms.name = NULL; 01427 view_parms.namelen = 0; 01428 view_parms.errorcode = 0; 01429 view_parms.check_subtree = 0; 01430 01431 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01432 /* Enable bypassing of view-based access control */ 01433 return 0; 01434 } 01435 01436 switch (pdu->version) { 01437 #ifndef NETSNMP_DISABLE_SNMPV1 01438 case SNMP_VERSION_1: 01439 #endif 01440 #ifndef NETSNMP_DISABLE_SNMPV2C 01441 case SNMP_VERSION_2c: 01442 #endif 01443 case SNMP_VERSION_3: 01444 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01445 SNMPD_CALLBACK_ACM_CHECK_INITIAL, &view_parms); 01446 return view_parms.errorcode; 01447 } 01448 return 1; 01449 } 01450 01458 int 01459 netsnmp_acm_check_subtree(netsnmp_pdu *pdu, oid *name, size_t namelen) 01460 { /* IN - pdu being checked */ 01461 struct view_parameters view_parms; 01462 view_parms.pdu = pdu; 01463 view_parms.name = name; 01464 view_parms.namelen = namelen; 01465 view_parms.errorcode = 0; 01466 view_parms.check_subtree = 1; 01467 01468 if (pdu->flags & UCD_MSG_FLAG_ALWAYS_IN_VIEW) { 01469 /* Enable bypassing of view-based access control */ 01470 return 0; 01471 } 01472 01473 switch (pdu->version) { 01474 #ifndef NETSNMP_DISABLE_SNMPV1 01475 case SNMP_VERSION_1: 01476 #endif 01477 #ifndef NETSNMP_DISABLE_SNMPV2C 01478 case SNMP_VERSION_2c: 01479 #endif 01480 case SNMP_VERSION_3: 01481 snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, 01482 SNMPD_CALLBACK_ACM_CHECK_SUBTREE, &view_parms); 01483 return view_parms.errorcode; 01484 } 01485 return 1; 01486 } 01487 01488 netsnmp_subtree * 01489 netsnmp_subtree_find_prev(oid *name, size_t len, netsnmp_subtree *subtree, 01490 const char *context_name) 01491 { 01492 lookup_cache *lookup_cache = NULL; 01493 netsnmp_subtree *myptr = NULL, *previous = NULL; 01494 int cmp = 1; 01495 size_t ll_off = 0; 01496 01497 if (subtree) { 01498 myptr = subtree; 01499 } else { 01500 /* look through everything */ 01501 if (lookup_cache_size) { 01502 lookup_cache = lookup_cache_find(context_name, name, len, &cmp); 01503 if (lookup_cache) { 01504 myptr = lookup_cache->next; 01505 previous = lookup_cache->previous; 01506 } 01507 if (!myptr) 01508 myptr = netsnmp_subtree_find_first(context_name); 01509 } else { 01510 myptr = netsnmp_subtree_find_first(context_name); 01511 } 01512 } 01513 01514 /* 01515 * this optimization causes a segfault on sf cf alpha-linux1. 01516 * ifdef out until someone figures out why and fixes it. xxx-rks 20051117 01517 */ 01518 #ifndef __alpha 01519 #define WTEST_OPTIMIZATION 1 01520 #endif 01521 #ifdef WTEST_OPTIMIZATION 01522 DEBUGMSGTL(("wtest","oid in: ")); 01523 DEBUGMSGOID(("wtest", name, len)); 01524 DEBUGMSG(("wtest","\n")); 01525 #endif 01526 for (; myptr != NULL; previous = myptr, myptr = myptr->next) { 01527 #ifdef WTEST_OPTIMIZATION 01528 /* Compare the incoming oid with the linked list. If we have 01529 results of previous compares, its faster to make sure the 01530 length we differed in the last check is greater than the 01531 length between this pointer and the last then we don't need 01532 to actually perform a comparison */ 01533 DEBUGMSGTL(("wtest","oid cmp: ")); 01534 DEBUGMSGOID(("wtest", myptr->start_a, myptr->start_len)); 01535 DEBUGMSG(("wtest"," --- off = %lu, in off = %lu test = %d\n", 01536 (unsigned long)myptr->oid_off, (unsigned long)ll_off, 01537 !(ll_off && myptr->oid_off && 01538 myptr->oid_off > ll_off))); 01539 if (!(ll_off && myptr->oid_off && myptr->oid_off > ll_off) && 01540 netsnmp_oid_compare_ll(name, len, 01541 myptr->start_a, myptr->start_len, 01542 &ll_off) < 0) { 01543 #else 01544 if (snmp_oid_compare(name, len, myptr->start_a, myptr->start_len) < 0) { 01545 #endif 01546 if (lookup_cache_size && previous && cmp) { 01547 if (lookup_cache) { 01548 lookup_cache_replace(lookup_cache, myptr, previous); 01549 } else { 01550 lookup_cache_add(context_name, myptr, previous); 01551 } 01552 } 01553 return previous; 01554 } 01555 } 01556 return previous; 01557 } 01558 01559 netsnmp_subtree * 01560 netsnmp_subtree_find_next(oid *name, size_t len, 01561 netsnmp_subtree *subtree, const char *context_name) 01562 { 01563 netsnmp_subtree *myptr = NULL; 01564 01565 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01566 01567 if (myptr != NULL) { 01568 myptr = myptr->next; 01569 while (myptr != NULL && (myptr->variables == NULL || 01570 myptr->variables_len == 0)) { 01571 myptr = myptr->next; 01572 } 01573 return myptr; 01574 } else if (subtree != NULL && snmp_oid_compare(name, len, 01575 subtree->start_a, subtree->start_len) < 0) { 01576 return subtree; 01577 } else { 01578 return NULL; 01579 } 01580 } 01581 01582 netsnmp_subtree * 01583 netsnmp_subtree_find(oid *name, size_t len, netsnmp_subtree *subtree, 01584 const char *context_name) 01585 { 01586 netsnmp_subtree *myptr; 01587 01588 myptr = netsnmp_subtree_find_prev(name, len, subtree, context_name); 01589 if (myptr && myptr->end_a && 01590 snmp_oid_compare(name, len, myptr->end_a, myptr->end_len)<0) { 01591 return myptr; 01592 } 01593 01594 return NULL; 01595 } 01596 01597 netsnmp_session * 01598 get_session_for_oid(oid *name, size_t len, const char *context_name) 01599 { 01600 netsnmp_subtree *myptr; 01601 01602 myptr = netsnmp_subtree_find_prev(name, len, 01603 netsnmp_subtree_find_first(context_name), 01604 context_name); 01605 01606 while (myptr && myptr->variables == NULL) { 01607 myptr = myptr->next; 01608 } 01609 01610 if (myptr == NULL) { 01611 return NULL; 01612 } else { 01613 return myptr->session; 01614 } 01615 } 01616 01617 void 01618 setup_tree(void) 01619 { 01620 oid ccitt[1] = { 0 }; 01621 oid iso[1] = { 1 }; 01622 oid joint_ccitt_iso[1] = { 2 }; 01623 01624 #ifdef USING_AGENTX_SUBAGENT_MODULE 01625 int role = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01626 NETSNMP_DS_AGENT_ROLE); 01627 01628 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01629 MASTER_AGENT); 01630 #endif 01631 01632 /* 01633 * we need to have the oid's in the heap, that we can *free* it for every case, 01634 * thats the purpose of the duplicate_objid's 01635 */ 01636 netsnmp_register_null(snmp_duplicate_objid(ccitt, 1), 1); 01637 netsnmp_register_null(snmp_duplicate_objid(iso, 1), 1); 01638 netsnmp_register_null(snmp_duplicate_objid(joint_ccitt_iso, 1), 1); 01639 01640 #ifdef USING_AGENTX_SUBAGENT_MODULE 01641 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 01642 role); 01643 #endif 01644 } 01645 01646 int 01647 remove_tree_entry (oid *name, size_t len) { 01648 01649 netsnmp_subtree *sub = NULL; 01650 01651 if ((sub = netsnmp_subtree_find(name, len, NULL, "")) == NULL) { 01652 return MIB_NO_SUCH_REGISTRATION; 01653 } 01654 01655 return unregister_mib_context(name, len, sub->priority, 01656 sub->range_subid, sub->range_ubound, ""); 01657 01658 } 01659 01660 01661 void 01662 shutdown_tree(void) { 01663 oid ccitt[1] = { 0 }; 01664 oid iso[1] = { 1 }; 01665 oid joint_ccitt_iso[1] = { 2 }; 01666 01667 DEBUGMSGTL(("agent_registry", "shut down tree\n")); 01668 01669 remove_tree_entry(joint_ccitt_iso, 1); 01670 remove_tree_entry(iso, 1); 01671 remove_tree_entry(ccitt, 1); 01672 01673 } 01674 01675 void 01676 clear_subtree (netsnmp_subtree *sub) { 01677 01678 netsnmp_subtree *nxt; 01679 01680 if (sub == NULL) 01681 return; 01682 01683 for(nxt = sub; nxt;) { 01684 if (nxt->children != NULL) { 01685 clear_subtree(nxt->children); 01686 } 01687 sub = nxt; 01688 nxt = nxt->next; 01689 netsnmp_subtree_free(sub); 01690 } 01691 01692 } 01693 01694 void 01695 clear_lookup_cache(void) { 01696 01697 lookup_cache_context *ptr = NULL, *next = NULL; 01698 01699 ptr = thecontextcache; 01700 while (ptr) { 01701 next = ptr->next; 01702 SNMP_FREE(ptr->context); 01703 SNMP_FREE(ptr); 01704 ptr = next; 01705 } 01706 thecontextcache = NULL; /* !!! */ 01707 } 01708 01709 void 01710 clear_context(void) { 01711 01712 subtree_context_cache *ptr = NULL, *next = NULL; 01713 01714 DEBUGMSGTL(("agent_registry", "clear context\n")); 01715 01716 ptr = get_top_context_cache(); 01717 while (ptr) { 01718 next = ptr->next; 01719 01720 if (ptr->first_subtree) { 01721 clear_subtree(ptr->first_subtree); 01722 } 01723 01724 SNMP_FREE(ptr->context_name); 01725 SNMP_FREE(ptr); 01726 01727 ptr = next; 01728 } 01729 context_subtrees = NULL; /* !!! */ 01730 clear_lookup_cache(); 01731 } 01732 01733 extern void dump_idx_registry(void); 01734 void 01735 dump_registry(void) 01736 { 01737 struct variable *vp = NULL; 01738 netsnmp_subtree *myptr, *myptr2; 01739 u_char *s = NULL, *e = NULL, *v = NULL; 01740 size_t sl = 256, el = 256, vl = 256, sl_o = 0, el_o = 0, vl_o = 0; 01741 int i = 0; 01742 01743 if ((s = (u_char *) calloc(sl, 1)) != NULL && 01744 (e = (u_char *) calloc(sl, 1)) != NULL && 01745 (v = (u_char *) calloc(sl, 1)) != NULL) { 01746 01747 subtree_context_cache *ptr; 01748 for (ptr = context_subtrees; ptr; ptr = ptr->next) { 01749 printf("Subtrees for Context: %s\n", ptr->context_name); 01750 for (myptr = ptr->first_subtree; myptr != NULL; 01751 myptr = myptr->next) { 01752 sl_o = el_o = vl_o = 0; 01753 01754 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 01755 myptr->start_a, 01756 myptr->start_len)) { 01757 break; 01758 } 01759 if (!sprint_realloc_objid(&e, &el, &el_o, 1, 01760 myptr->end_a, 01761 myptr->end_len)) { 01762 break; 01763 } 01764 01765 if (myptr->variables) { 01766 printf("%02x ( %s - %s ) [", myptr->flags, s, e); 01767 for (i = 0, vp = myptr->variables; 01768 i < myptr->variables_len; i++) { 01769 vl_o = 0; 01770 if (!sprint_realloc_objid 01771 (&v, &vl, &vl_o, 1, vp->name, vp->namelen)) { 01772 break; 01773 } 01774 printf("%s, ", v); 01775 vp = (struct variable *) ((char *) vp + 01776 myptr->variables_width); 01777 } 01778 printf("]\n"); 01779 } else { 01780 printf("%02x %s - %s \n", myptr->flags, s, e); 01781 } 01782 for (myptr2 = myptr; myptr2 != NULL; 01783 myptr2 = myptr2->children) { 01784 if (myptr2->label_a && myptr2->label_a[0]) { 01785 if (strcmp(myptr2->label_a, "old_api") == 0) { 01786 struct variable *vp = 01787 myptr2->reginfo->handler->myvoid; 01788 01789 if (!sprint_realloc_objid(&s, &sl, &sl_o, 1, 01790 vp->name, vp->namelen)) { 01791 continue; 01792 } 01793 printf("\t%s[%s] %p var %s\n", myptr2->label_a, 01794 myptr2->reginfo->handlerName ? 01795 myptr2->reginfo->handlerName : "no-name", 01796 myptr2->reginfo, s); 01797 } else { 01798 printf("\t%s %s %p\n", myptr2->label_a, 01799 myptr2->reginfo->handlerName ? 01800 myptr2->reginfo->handlerName : "no-handler-name", 01801 myptr2->reginfo); 01802 } 01803 } 01804 } 01805 } 01806 } 01807 } 01808 01809 if (s != NULL) { 01810 SNMP_FREE(s); 01811 } 01812 if (e != NULL) { 01813 SNMP_FREE(e); 01814 } 01815 if (v != NULL) { 01816 SNMP_FREE(v); 01817 } 01818 01819 dump_idx_registry(); 01820 } 01821 01822 int external_signal_scheduled[NUM_EXTERNAL_SIGS]; 01823 void (*external_signal_handler[NUM_EXTERNAL_SIGS]) (int); 01824 01825 #ifndef WIN32 01826 01827 /* 01828 * TODO: add agent_SIGXXX_handler functions and `case SIGXXX: ...' lines 01829 * below for every single that might be handled by register_signal(). 01830 */ 01831 01832 RETSIGTYPE 01833 agent_SIGCHLD_handler(int sig) 01834 { 01835 external_signal_scheduled[SIGCHLD]++; 01836 #ifndef HAVE_SIGACTION 01837 /* 01838 * signal() sucks. It *might* have SysV semantics, which means that 01839 * * a signal handler is reset once it gets called. Ensure that it 01840 * * remains active. 01841 */ 01842 signal(SIGCHLD, agent_SIGCHLD_handler); 01843 #endif 01844 } 01845 01846 int 01847 register_signal(int sig, void (*func) (int)) 01848 { 01849 01850 switch (sig) { 01851 #if defined(SIGCHLD) 01852 case SIGCHLD: 01853 #ifdef HAVE_SIGACTION 01854 { 01855 static struct sigaction act; 01856 act.sa_handler = agent_SIGCHLD_handler; 01857 sigemptyset(&act.sa_mask); 01858 act.sa_flags = 0; 01859 sigaction(SIGCHLD, &act, NULL); 01860 } 01861 #else 01862 signal(SIGCHLD, agent_SIGCHLD_handler); 01863 #endif 01864 break; 01865 #endif 01866 default: 01867 snmp_log(LOG_CRIT, 01868 "register_signal: signal %d cannot be handled\n", sig); 01869 return SIG_REGISTRATION_FAILED; 01870 } 01871 01872 external_signal_handler[sig] = func; 01873 external_signal_scheduled[sig] = 0; 01874 01875 DEBUGMSGTL(("register_signal", "registered signal %d\n", sig)); 01876 return SIG_REGISTERED_OK; 01877 } 01878 01879 int 01880 unregister_signal(int sig) 01881 { 01882 signal(sig, SIG_DFL); 01883 DEBUGMSGTL(("unregister_signal", "unregistered signal %d\n", sig)); 01884 return SIG_UNREGISTERED_OK; 01885 } 01886 01887 #endif /* !WIN32 */ 01888
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.