net-snmp
5.4.1
|
00001 /* 00002 * snmp_agent.c 00003 * 00004 * Simple Network Management Protocol (RFC 1067). 00005 */ 00006 /* Portions of this file are subject to the following copyright(s). See 00007 * the Net-SNMP's COPYING file for more details and other copyrights 00008 * that may apply: 00009 */ 00010 /* Portions of this file are subject to the following copyrights. See 00011 * the Net-SNMP's COPYING file for more details and other copyrights 00012 * that may apply: 00013 */ 00014 /*********************************************************** 00015 Copyright 1988, 1989 by Carnegie Mellon University 00016 00017 All Rights Reserved 00018 00019 Permission to use, copy, modify, and distribute this software and its 00020 documentation for any purpose and without fee is hereby granted, 00021 provided that the above copyright notice appear in all copies and that 00022 both that copyright notice and this permission notice appear in 00023 supporting documentation, and that the name of CMU not be 00024 used in advertising or publicity pertaining to distribution of the 00025 software without specific, written prior permission. 00026 00027 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 00028 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 00029 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 00030 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 00031 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 00032 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00033 SOFTWARE. 00034 ******************************************************************/ 00035 /* 00036 * Portions of this file are copyrighted by: 00037 * Copyright © 2003 Sun Microsystems, Inc. All rights 00038 * reserved. Use is subject to license terms specified in the 00039 * COPYING file distributed with the Net-SNMP package. 00040 */ 00046 #include <net-snmp/net-snmp-config.h> 00047 00048 #include <sys/types.h> 00049 #ifdef HAVE_LIMITS_H 00050 #include <limits.h> 00051 #endif 00052 #ifdef HAVE_STDLIB_H 00053 #include <stdlib.h> 00054 #endif 00055 #if HAVE_UNISTD_H 00056 #include <unistd.h> 00057 #endif 00058 #if HAVE_STRING_H 00059 #include <string.h> 00060 #endif 00061 #if TIME_WITH_SYS_TIME 00062 # ifdef WIN32 00063 # include <sys/timeb.h> 00064 # else 00065 # include <sys/time.h> 00066 # endif 00067 # include <time.h> 00068 #else 00069 # if HAVE_SYS_TIME_H 00070 # include <sys/time.h> 00071 # else 00072 # include <time.h> 00073 # endif 00074 #endif 00075 #if HAVE_SYS_SELECT_H 00076 #include <sys/select.h> 00077 #endif 00078 #if HAVE_NETINET_IN_H 00079 #include <netinet/in.h> 00080 #endif 00081 #include <errno.h> 00082 #if HAVE_WINSOCK_H 00083 #include <winsock.h> 00084 #endif 00085 00086 #define SNMP_NEED_REQUEST_LIST 00087 #include <net-snmp/net-snmp-includes.h> 00088 #include <net-snmp/agent/net-snmp-agent-includes.h> 00089 #include <net-snmp/library/snmp_assert.h> 00090 00091 #if HAVE_SYSLOG_H 00092 #include <syslog.h> 00093 #endif 00094 00095 #ifdef NETSNMP_USE_LIBWRAP 00096 #include <tcpd.h> 00097 int allow_severity = LOG_INFO; 00098 int deny_severity = LOG_WARNING; 00099 #endif 00100 00101 #include "snmpd.h" 00102 #include "mibgroup/struct.h" 00103 #include "mibgroup/util_funcs.h" 00104 #include <net-snmp/agent/mib_module_config.h> 00105 #include <net-snmp/agent/mib_modules.h> 00106 00107 #ifdef USING_AGENTX_PROTOCOL_MODULE 00108 #include "agentx/protocol.h" 00109 #endif 00110 00111 #ifdef USING_AGENTX_MASTER_MODULE 00112 #include "agentx/master.h" 00113 #endif 00114 00115 #ifdef USING_SMUX_MODULE 00116 #include "smux/smux.h" 00117 #endif 00118 00119 oid version_sysoid[] = { NETSNMP_SYSTEM_MIB }; 00120 int version_sysoid_len = OID_LENGTH(version_sysoid); 00121 00122 #define SNMP_ADDRCACHE_SIZE 10 00123 #define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */ 00124 00125 enum { 00126 SNMP_ADDRCACHE_UNUSED = 0, 00127 SNMP_ADDRCACHE_USED = 1 00128 }; 00129 00130 struct addrCache { 00131 char *addr; 00132 int status; 00133 struct timeval lastHit; 00134 }; 00135 00136 static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE]; 00137 int log_addresses = 0; 00138 00139 00140 00141 typedef struct _agent_nsap { 00142 int handle; 00143 netsnmp_transport *t; 00144 void *s; /* Opaque internal session pointer. */ 00145 struct _agent_nsap *next; 00146 } agent_nsap; 00147 00148 static agent_nsap *agent_nsap_list = NULL; 00149 static netsnmp_agent_session *agent_session_list = NULL; 00150 netsnmp_agent_session *netsnmp_processing_set = NULL; 00151 netsnmp_agent_session *agent_delegated_list = NULL; 00152 netsnmp_agent_session *netsnmp_agent_queued_list = NULL; 00153 00154 00155 int netsnmp_agent_check_packet(netsnmp_session *, 00156 struct netsnmp_transport_s *, 00157 void *, int); 00158 int netsnmp_agent_check_parse(netsnmp_session *, netsnmp_pdu *, 00159 int); 00160 void delete_subnetsnmp_tree_cache(netsnmp_agent_session *asp); 00161 int handle_pdu(netsnmp_agent_session *asp); 00162 int netsnmp_handle_request(netsnmp_agent_session *asp, 00163 int status); 00164 int netsnmp_wrap_up_request(netsnmp_agent_session *asp, 00165 int status); 00166 int check_delayed_request(netsnmp_agent_session *asp); 00167 int handle_getnext_loop(netsnmp_agent_session *asp); 00168 int handle_set_loop(netsnmp_agent_session *asp); 00169 00170 int netsnmp_check_queued_chain_for(netsnmp_agent_session *asp); 00171 int netsnmp_add_queued(netsnmp_agent_session *asp); 00172 int netsnmp_remove_from_delegated(netsnmp_agent_session *asp); 00173 00174 00175 static int current_globalid = 0; 00176 00177 int netsnmp_running = 1; 00178 00179 int 00180 netsnmp_allocate_globalcacheid(void) 00181 { 00182 return ++current_globalid; 00183 } 00184 00185 int 00186 netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid) 00187 { 00188 while (cache_store != NULL) { 00189 if (cache_store->globalid == globalid) 00190 return cache_store->cacheid; 00191 cache_store = cache_store->next; 00192 } 00193 return -1; 00194 } 00195 00196 netsnmp_cachemap * 00197 netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store, 00198 int globalid, int localid) 00199 { 00200 netsnmp_cachemap *tmpp; 00201 00202 tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap); 00203 if (*cache_store) { 00204 tmpp->next = *cache_store; 00205 *cache_store = tmpp; 00206 } else { 00207 *cache_store = tmpp; 00208 } 00209 00210 tmpp->globalid = globalid; 00211 tmpp->cacheid = localid; 00212 return tmpp; 00213 } 00214 00215 void 00216 netsnmp_free_cachemap(netsnmp_cachemap *cache_store) 00217 { 00218 netsnmp_cachemap *tmpp; 00219 while (cache_store) { 00220 tmpp = cache_store; 00221 cache_store = cache_store->next; 00222 SNMP_FREE(tmpp); 00223 } 00224 } 00225 00226 00227 typedef struct agent_set_cache_s { 00228 /* 00229 * match on these 2 00230 */ 00231 int transID; 00232 netsnmp_session *sess; 00233 00234 /* 00235 * store this info 00236 */ 00237 netsnmp_tree_cache *treecache; 00238 int treecache_len; 00239 int treecache_num; 00240 00241 int vbcount; 00242 netsnmp_request_info *requests; 00243 netsnmp_variable_list *saved_vars; 00244 netsnmp_data_list *agent_data; 00245 00246 /* 00247 * list 00248 */ 00249 struct agent_set_cache_s *next; 00250 } agent_set_cache; 00251 00252 static agent_set_cache *Sets = NULL; 00253 00254 agent_set_cache * 00255 save_set_cache(netsnmp_agent_session *asp) 00256 { 00257 agent_set_cache *ptr; 00258 00259 if (!asp || !asp->reqinfo || !asp->pdu) 00260 return NULL; 00261 00262 ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache); 00263 if (ptr == NULL) 00264 return NULL; 00265 00266 /* 00267 * Save the important information 00268 */ 00269 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n", 00270 asp, asp->reqinfo, asp->pdu->command)); 00271 ptr->transID = asp->pdu->transid; 00272 ptr->sess = asp->session; 00273 ptr->treecache = asp->treecache; 00274 ptr->treecache_len = asp->treecache_len; 00275 ptr->treecache_num = asp->treecache_num; 00276 ptr->agent_data = asp->reqinfo->agent_data; 00277 ptr->requests = asp->requests; 00278 ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */ 00279 ptr->vbcount = asp->vbcount; 00280 00281 /* 00282 * make the agent forget about what we've saved 00283 */ 00284 asp->treecache = NULL; 00285 asp->reqinfo->agent_data = NULL; 00286 asp->pdu->variables = NULL; 00287 asp->requests = NULL; 00288 00289 ptr->next = Sets; 00290 Sets = ptr; 00291 00292 return ptr; 00293 } 00294 00295 int 00296 get_set_cache(netsnmp_agent_session *asp) 00297 { 00298 agent_set_cache *ptr, *prev = NULL; 00299 00300 for (ptr = Sets; ptr != NULL; ptr = ptr->next) { 00301 if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) { 00302 /* 00303 * remove this item from list 00304 */ 00305 if (prev) 00306 prev->next = ptr->next; 00307 else 00308 Sets = ptr->next; 00309 00310 /* 00311 * found it. Get the needed data 00312 */ 00313 asp->treecache = ptr->treecache; 00314 asp->treecache_len = ptr->treecache_len; 00315 asp->treecache_num = ptr->treecache_num; 00316 00317 /* 00318 * Free previously allocated requests before overwriting by 00319 * cached ones, otherwise memory leaks! 00320 */ 00321 if (asp->requests) { 00322 /* 00323 * I don't think this case should ever happen. Please email 00324 * the net-snmp-coders@lists.sourceforge.net if you have 00325 * a test case that hits this assert. -- rstory 00326 */ 00327 int i; 00328 netsnmp_assert(NULL == asp->requests); /* see note above */ 00329 for (i = 0; i < asp->vbcount; i++) { 00330 netsnmp_free_request_data_sets(&asp->requests[i]); 00331 } 00332 free(asp->requests); 00333 } 00334 /* 00335 * If we replace asp->requests with the info from the set cache, 00336 * we should replace asp->pdu->variables also with the cached 00337 * info, as asp->requests contains pointers to them. And we 00338 * should also free the current asp->pdu->variables list... 00339 */ 00340 if (ptr->saved_vars) { 00341 if (asp->pdu->variables) 00342 snmp_free_varbind(asp->pdu->variables); 00343 asp->pdu->variables = ptr->saved_vars; 00344 asp->vbcount = ptr->vbcount; 00345 } else { 00346 /* 00347 * when would we not have saved variables? someone 00348 * let me know if they hit this assert. -- rstory 00349 */ 00350 netsnmp_assert(NULL != ptr->saved_vars); 00351 } 00352 asp->requests = ptr->requests; 00353 00354 netsnmp_assert(NULL != asp->reqinfo); 00355 asp->reqinfo->asp = asp; 00356 asp->reqinfo->agent_data = ptr->agent_data; 00357 00358 /* 00359 * update request reqinfo, if it's out of date. 00360 * yyy-rks: investigate when/why sometimes they match, 00361 * sometimes they don't. 00362 */ 00363 if(asp->requests->agent_req_info != asp->reqinfo) { 00364 /* 00365 * - one don't match case: agentx subagents. prev asp & reqinfo 00366 * freed, request reqinfo ptrs not cleared. 00367 */ 00368 netsnmp_request_info *tmp = asp->requests; 00369 DEBUGMSGTL(("verbose:asp", 00370 " reqinfo %p doesn't match cached reqinfo %p\n", 00371 asp->reqinfo, asp->requests->agent_req_info)); 00372 for(; tmp; tmp = tmp->next) 00373 tmp->agent_req_info = asp->reqinfo; 00374 } else { 00375 /* 00376 * - match case: ? 00377 */ 00378 DEBUGMSGTL(("verbose:asp", 00379 " reqinfo %p matches cached reqinfo %p\n", 00380 asp->reqinfo, asp->requests->agent_req_info)); 00381 } 00382 00383 SNMP_FREE(ptr); 00384 return SNMP_ERR_NOERROR; 00385 } 00386 prev = ptr; 00387 } 00388 return SNMP_ERR_GENERR; 00389 } 00390 00391 /* Bulkcache holds the values for the *repeating* varbinds (only), 00392 * but ordered "by column" - i.e. the repetitions for each 00393 * repeating varbind follow on immediately from one another, 00394 * rather than being interleaved, as required by the protocol. 00395 * 00396 * So we need to rearrange the varbind list so it's ordered "by row". 00397 * 00398 * In the following code chunk: 00399 * n = # non-repeating varbinds 00400 * r = # repeating varbinds 00401 * asp->vbcount = # varbinds in the incoming PDU 00402 * (So asp->vbcount = n+r) 00403 * 00404 * repeats = Desired # of repetitions (of 'r' varbinds) 00405 */ 00406 NETSNMP_STATIC_INLINE void 00407 _reorder_getbulk(netsnmp_agent_session *asp) 00408 { 00409 int i, n = 0, r = 0; 00410 int repeats = asp->pdu->errindex; 00411 int j, k; 00412 int all_eoMib; 00413 netsnmp_variable_list *prev = NULL, *curr; 00414 00415 if (asp->vbcount == 0) /* Nothing to do! */ 00416 return; 00417 00418 if (asp->pdu->errstat < asp->vbcount) { 00419 n = asp->pdu->errstat; 00420 } else { 00421 n = asp->vbcount; 00422 } 00423 if ((r = asp->vbcount - n) < 0) { 00424 r = 0; 00425 } 00426 00427 /* we do nothing if there is nothing repeated */ 00428 if (r == 0) 00429 return; 00430 00431 /* Fix endOfMibView entries. */ 00432 for (i = 0; i < r; i++) { 00433 prev = NULL; 00434 for (j = 0; j < repeats; j++) { 00435 curr = asp->bulkcache[i * repeats + j]; 00436 /* 00437 * If we don't have a valid name for a given repetition 00438 * (and probably for all the ones that follow as well), 00439 * extend the previous result to indicate 'endOfMibView'. 00440 * Or if the repetition already has type endOfMibView make 00441 * sure it has the correct objid (i.e. that of the previous 00442 * entry or that of the original request). 00443 */ 00444 if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) { 00445 if (prev == NULL) { 00446 /* Use objid from original pdu. */ 00447 prev = asp->orig_pdu->variables; 00448 for (k = i; prev && k > 0; k--) 00449 prev = prev->next_variable; 00450 } 00451 if (prev) { 00452 snmp_set_var_objid(curr, prev->name, prev->name_length); 00453 snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0); 00454 } 00455 } 00456 prev = curr; 00457 } 00458 } 00459 00460 /* 00461 * For each of the original repeating varbinds (except the last), 00462 * go through the block of results for that varbind, 00463 * and link each instance to the corresponding instance 00464 * in the next block. 00465 */ 00466 for (i = 0; i < r - 1; i++) { 00467 for (j = 0; j < repeats; j++) { 00468 asp->bulkcache[i * repeats + j]->next_variable = 00469 asp->bulkcache[(i + 1) * repeats + j]; 00470 } 00471 } 00472 00473 /* 00474 * For the last of the original repeating varbinds, 00475 * go through that block of results, and link each 00476 * instance to the *next* instance in the *first* block. 00477 * 00478 * The very last instance of this block is left untouched 00479 * since it (correctly) points to the end of the list. 00480 */ 00481 for (j = 0; j < repeats - 1; j++) { 00482 asp->bulkcache[(r - 1) * repeats + j]->next_variable = 00483 asp->bulkcache[j + 1]; 00484 } 00485 00486 /* 00487 * If we've got a full row of endOfMibViews, then we 00488 * can truncate the result varbind list after that. 00489 * 00490 * Look for endOfMibView exception values in the list of 00491 * repetitions for the first varbind, and check the 00492 * corresponding instances for the other varbinds 00493 * (following the next_variable links). 00494 * 00495 * If they're all endOfMibView too, then we can terminate 00496 * the linked list there, and free any redundant varbinds. 00497 */ 00498 all_eoMib = 0; 00499 for (i = 0; i < repeats; i++) { 00500 if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) { 00501 all_eoMib = 1; 00502 for (j = 1, prev=asp->bulkcache[i]; 00503 j < r; 00504 j++, prev=prev->next_variable) { 00505 if (prev->type != SNMP_ENDOFMIBVIEW) { 00506 all_eoMib = 0; 00507 break; /* Found a real value */ 00508 } 00509 } 00510 if (all_eoMib) { 00511 /* 00512 * This is indeed a full endOfMibView row. 00513 * Terminate the list here & free the rest. 00514 */ 00515 snmp_free_varbind( prev->next_variable ); 00516 prev->next_variable = NULL; 00517 break; 00518 } 00519 } 00520 } 00521 } 00522 00523 00524 /* EndOfMibView replies to a GETNEXT request should according to RFC3416 00525 * have the object ID set to that of the request. Our tree search 00526 * algorithm will sometimes break that requirement. This function will 00527 * fix that. 00528 */ 00529 NETSNMP_STATIC_INLINE void 00530 _fix_endofmibview(netsnmp_agent_session *asp) 00531 { 00532 netsnmp_variable_list *vb, *ovb; 00533 00534 if (asp->vbcount == 0) /* Nothing to do! */ 00535 return; 00536 00537 for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables; 00538 vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) { 00539 if (vb->type == SNMP_ENDOFMIBVIEW) 00540 snmp_set_var_objid(vb, ovb->name, ovb->name_length); 00541 } 00542 } 00543 00544 00545 int 00546 getNextSessID() 00547 { 00548 static int SessionID = 0; 00549 00550 return ++SessionID; 00551 } 00552 00565 int 00566 agent_check_and_process(int block) 00567 { 00568 int numfds; 00569 fd_set fdset; 00570 struct timeval timeout = { LONG_MAX, 0 }, *tvp = &timeout; 00571 int count; 00572 int fakeblock = 0; 00573 00574 numfds = 0; 00575 FD_ZERO(&fdset); 00576 snmp_select_info(&numfds, &fdset, tvp, &fakeblock); 00577 if (block != 0 && fakeblock != 0) { 00578 /* 00579 * There are no alarms registered, and the caller asked for blocking, so 00580 * let select() block forever. 00581 */ 00582 00583 tvp = NULL; 00584 } else if (block != 0 && fakeblock == 0) { 00585 /* 00586 * The caller asked for blocking, but there is an alarm due sooner than 00587 * LONG_MAX seconds from now, so use the modified timeout returned by 00588 * snmp_select_info as the timeout for select(). 00589 */ 00590 00591 } else if (block == 0) { 00592 /* 00593 * The caller does not want us to block at all. 00594 */ 00595 00596 tvp->tv_sec = 0; 00597 tvp->tv_usec = 0; 00598 } 00599 00600 count = select(numfds, &fdset, 0, 0, tvp); 00601 00602 if (count > 0) { 00603 /* 00604 * packets found, process them 00605 */ 00606 snmp_read(&fdset); 00607 } else 00608 switch (count) { 00609 case 0: 00610 snmp_timeout(); 00611 break; 00612 case -1: 00613 if (errno != EINTR) { 00614 snmp_log_perror("select"); 00615 } 00616 return -1; 00617 default: 00618 snmp_log(LOG_ERR, "select returned %d\n", count); 00619 return -1; 00620 } /* endif -- count>0 */ 00621 00622 /* 00623 * Run requested alarms. 00624 */ 00625 run_alarms(); 00626 00627 netsnmp_check_outstanding_agent_requests(); 00628 00629 return count; 00630 } 00631 00632 00633 /* 00634 * Set up the address cache. 00635 */ 00636 void 00637 netsnmp_addrcache_initialise(void) 00638 { 00639 int i = 0; 00640 00641 for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) { 00642 addrCache[i].addr = NULL; 00643 addrCache[i].status = SNMP_ADDRCACHE_UNUSED; 00644 } 00645 } 00646 00647 /* 00648 * Adds a new entry to the cache of addresses that 00649 * have recently made connections to the agent. 00650 * Returns 0 if the entry already exists (but updates 00651 * the entry with a new timestamp) and 1 if the 00652 * entry did not previously exist. 00653 * 00654 * Implements a simple LRU cache replacement 00655 * policy. Uses a linear search, which should be 00656 * okay, as long as SNMP_ADDRCACHE_SIZE remains 00657 * relatively small. 00658 * 00659 * @retval 0 : updated existing entry 00660 * @retval 1 : added new entry 00661 */ 00662 int 00663 netsnmp_addrcache_add(const char *addr) 00664 { 00665 int oldest = -1; /* Index of the oldest cache entry */ 00666 int unused = -1; /* Index of the first free cache entry */ 00667 int i; /* Looping variable */ 00668 int rc = -1; 00669 struct timeval now; /* What time is it now? */ 00670 struct timeval aged; /* Oldest allowable cache entry */ 00671 00672 /* 00673 * First get the current and oldest allowable timestamps 00674 */ 00675 gettimeofday(&now, (struct timezone*) NULL); 00676 aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE; 00677 aged.tv_usec = now.tv_usec; 00678 00679 /* 00680 * Now look for a place to put this thing 00681 */ 00682 for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) { 00683 if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */ 00684 /* 00685 * remember this location, in case addr isn't in the cache 00686 */ 00687 if (unused < 0) 00688 unused = i; 00689 } 00690 else { /* If used */ 00691 if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) { 00692 /* 00693 * found a match 00694 */ 00695 memcpy(&addrCache[i].lastHit, &now, sizeof(struct timeval)); 00696 if (timercmp(&addrCache[i].lastHit, &aged, <)) 00697 rc = 1; /* should have expired, so is new */ 00698 else 00699 rc = 0; /* not expired, so is existing entry */ 00700 break; 00701 } 00702 else { 00703 /* 00704 * Used, but not this address. check if it's stale. 00705 */ 00706 if (timercmp(&addrCache[i].lastHit, &aged, <)) { 00707 /* 00708 * Stale, reuse 00709 */ 00710 SNMP_FREE(addrCache[i].addr); 00711 addrCache[i].status = SNMP_ADDRCACHE_UNUSED; 00712 /* 00713 * remember this location, in case addr isn't in the cache 00714 */ 00715 if (unused < 0) 00716 unused = i; 00717 } 00718 else { 00719 /* 00720 * Still fresh, but a candidate for LRU replacement 00721 */ 00722 if (oldest < 0) 00723 oldest = i; 00724 else if (timercmp(&addrCache[i].lastHit, 00725 &addrCache[oldest].lastHit, <)) 00726 oldest = i; 00727 } /* fresh */ 00728 } /* used, no match */ 00729 } /* used */ 00730 } /* for loop */ 00731 00732 if ((-1 == rc) && (NULL != addr)) { 00733 /* 00734 * We didn't find the entry in the cache 00735 */ 00736 if (unused >= 0) { 00737 /* 00738 * If we have a slot free anyway, use it 00739 */ 00740 addrCache[unused].addr = strdup(addr); 00741 addrCache[unused].status = SNMP_ADDRCACHE_USED; 00742 memcpy(&addrCache[unused].lastHit, &now, sizeof(struct timeval)); 00743 } 00744 else { /* Otherwise, replace oldest entry */ 00745 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00746 NETSNMP_DS_AGENT_VERBOSE)) 00747 snmp_log(LOG_INFO, "Purging address from address cache: %s", 00748 addrCache[oldest].addr); 00749 00750 free(addrCache[oldest].addr); 00751 addrCache[oldest].addr = strdup(addr); 00752 memcpy(&addrCache[oldest].lastHit, &now, sizeof(struct timeval)); 00753 } 00754 rc = 1; 00755 } 00756 if ((log_addresses && (1 == rc)) || 00757 netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00758 NETSNMP_DS_AGENT_VERBOSE)) { 00759 snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr); 00760 } 00761 00762 return rc; 00763 } 00764 00765 /* 00766 * Age the entries in the address cache. 00767 * 00768 * backwards compatability; not used anywhere 00769 */ 00770 void 00771 netsnmp_addrcache_age(void) 00772 { 00773 (void)netsnmp_addrcache_add(NULL); 00774 } 00775 00776 /*******************************************************************-o-****** 00777 * netsnmp_agent_check_packet 00778 * 00779 * Parameters: 00780 * session, transport, transport_data, transport_data_length 00781 * 00782 * Returns: 00783 * 1 On success. 00784 * 0 On error. 00785 * 00786 * Handler for all incoming messages (a.k.a. packets) for the agent. If using 00787 * the libwrap utility, log the connection and deny/allow the access. Print 00788 * output when appropriate, and increment the incoming counter. 00789 * 00790 */ 00791 00792 int 00793 netsnmp_agent_check_packet(netsnmp_session * session, 00794 netsnmp_transport *transport, 00795 void *transport_data, int transport_data_length) 00796 { 00797 char *addr_string = NULL; 00798 #ifdef NETSNMP_USE_LIBWRAP 00799 char *tcpudpaddr, *name; 00800 short not_log_connection; 00801 00802 name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 00803 NETSNMP_DS_LIB_APPTYPE); 00804 00805 /* not_log_connection will be 1 if we should skip the messages */ 00806 not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00807 NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS); 00808 00809 /* 00810 * handle the error case 00811 * default to logging the messages 00812 */ 00813 if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0; 00814 #endif 00815 00816 /* 00817 * Log the message and/or dump the message. 00818 * Optionally cache the network address of the sender. 00819 */ 00820 00821 if (transport != NULL && transport->f_fmtaddr != NULL) { 00822 /* 00823 * Okay I do know how to format this address for logging. 00824 */ 00825 addr_string = transport->f_fmtaddr(transport, transport_data, 00826 transport_data_length); 00827 /* 00828 * Don't forget to free() it. 00829 */ 00830 } 00831 #ifdef NETSNMP_USE_LIBWRAP 00832 /* Catch udp,udp6,tcp,tcp6 transports using "[" */ 00833 tcpudpaddr = strstr(addr_string, "["); 00834 if ( tcpudpaddr != 0 ) { 00835 char sbuf[64]; 00836 char *xp; 00837 strncpy(sbuf, tcpudpaddr + 1, sizeof(sbuf)); 00838 sbuf[sizeof(sbuf)-1] = '\0'; 00839 xp = strstr(sbuf, "]"); 00840 if (xp) 00841 *xp = '\0'; 00842 00843 if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) { 00844 if (!not_log_connection) { 00845 snmp_log(allow_severity, "Connection from %s\n", addr_string); 00846 } 00847 } else { 00848 snmp_log(deny_severity, "Connection from %s REFUSED\n", 00849 addr_string); 00850 SNMP_FREE(addr_string); 00851 return 0; 00852 } 00853 } else { 00854 /* 00855 * don't log callback connections. 00856 * What about 'Local IPC', 'IPX' and 'AAL5 PVC'? 00857 */ 00858 if (0 == strncmp(addr_string, "callback", 8)) 00859 ; 00860 else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){ 00861 if (!not_log_connection) { 00862 snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string); 00863 }; 00864 SNMP_FREE(addr_string); 00865 addr_string = strdup("<UNKNOWN>"); 00866 } else { 00867 snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string); 00868 SNMP_FREE(addr_string); 00869 return 0; 00870 } 00871 } 00872 #endif /*NETSNMP_USE_LIBWRAP */ 00873 00874 snmp_increment_statistic(STAT_SNMPINPKTS); 00875 00876 if (addr_string != NULL) { 00877 netsnmp_addrcache_add(addr_string); 00878 SNMP_FREE(addr_string); 00879 } 00880 return 1; 00881 } 00882 00883 00884 int 00885 netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu, 00886 int result) 00887 { 00888 if (result == 0) { 00889 if (snmp_get_do_logging() && 00890 netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 00891 NETSNMP_DS_AGENT_VERBOSE)) { 00892 netsnmp_variable_list *var_ptr; 00893 00894 switch (pdu->command) { 00895 case SNMP_MSG_GET: 00896 snmp_log(LOG_DEBUG, " GET message\n"); 00897 break; 00898 case SNMP_MSG_GETNEXT: 00899 snmp_log(LOG_DEBUG, " GETNEXT message\n"); 00900 break; 00901 case SNMP_MSG_RESPONSE: 00902 snmp_log(LOG_DEBUG, " RESPONSE message\n"); 00903 break; 00904 case SNMP_MSG_SET: 00905 snmp_log(LOG_DEBUG, " SET message\n"); 00906 break; 00907 case SNMP_MSG_TRAP: 00908 snmp_log(LOG_DEBUG, " TRAP message\n"); 00909 break; 00910 case SNMP_MSG_GETBULK: 00911 snmp_log(LOG_DEBUG, " GETBULK message, non-rep=%ld, max_rep=%ld\n", 00912 pdu->errstat, pdu->errindex); 00913 break; 00914 case SNMP_MSG_INFORM: 00915 snmp_log(LOG_DEBUG, " INFORM message\n"); 00916 break; 00917 case SNMP_MSG_TRAP2: 00918 snmp_log(LOG_DEBUG, " TRAP2 message\n"); 00919 break; 00920 case SNMP_MSG_REPORT: 00921 snmp_log(LOG_DEBUG, " REPORT message\n"); 00922 break; 00923 00924 case SNMP_MSG_INTERNAL_SET_RESERVE1: 00925 snmp_log(LOG_DEBUG, " INTERNAL RESERVE1 message\n"); 00926 break; 00927 00928 case SNMP_MSG_INTERNAL_SET_RESERVE2: 00929 snmp_log(LOG_DEBUG, " INTERNAL RESERVE2 message\n"); 00930 break; 00931 00932 case SNMP_MSG_INTERNAL_SET_ACTION: 00933 snmp_log(LOG_DEBUG, " INTERNAL ACTION message\n"); 00934 break; 00935 00936 case SNMP_MSG_INTERNAL_SET_COMMIT: 00937 snmp_log(LOG_DEBUG, " INTERNAL COMMIT message\n"); 00938 break; 00939 00940 case SNMP_MSG_INTERNAL_SET_FREE: 00941 snmp_log(LOG_DEBUG, " INTERNAL FREE message\n"); 00942 break; 00943 00944 case SNMP_MSG_INTERNAL_SET_UNDO: 00945 snmp_log(LOG_DEBUG, " INTERNAL UNDO message\n"); 00946 break; 00947 00948 default: 00949 snmp_log(LOG_DEBUG, " UNKNOWN message, type=%02X\n", 00950 pdu->command); 00951 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); 00952 return 0; 00953 } 00954 00955 for (var_ptr = pdu->variables; var_ptr != NULL; 00956 var_ptr = var_ptr->next_variable) { 00957 size_t c_oidlen = 256, c_outlen = 0; 00958 u_char *c_oid = (u_char *) malloc(c_oidlen); 00959 00960 if (c_oid) { 00961 if (!sprint_realloc_objid 00962 (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name, 00963 var_ptr->name_length)) { 00964 snmp_log(LOG_DEBUG, " -- %s [TRUNCATED]\n", 00965 c_oid); 00966 } else { 00967 snmp_log(LOG_DEBUG, " -- %s\n", c_oid); 00968 } 00969 SNMP_FREE(c_oid); 00970 } 00971 } 00972 } 00973 return 1; 00974 } 00975 return 0; /* XXX: does it matter what the return value 00976 * is? Yes: if we return 0, then the PDU is 00977 * dumped. */ 00978 } 00979 00980 00981 /* 00982 * Global access to the primary session structure for this agent. 00983 * for Index Allocation use initially. 00984 */ 00985 00986 /* 00987 * I don't understand what this is for at the moment. AFAICS as long as it 00988 * gets set and points at a session, that's fine. ??? 00989 */ 00990 00991 netsnmp_session *main_session = NULL; 00992 00993 00994 00995 /* 00996 * Set up an agent session on the given transport. Return a handle 00997 * which may later be used to de-register this transport. A return 00998 * value of -1 indicates an error. 00999 */ 01000 01001 int 01002 netsnmp_register_agent_nsap(netsnmp_transport *t) 01003 { 01004 netsnmp_session *s, *sp = NULL; 01005 agent_nsap *a = NULL, *n = NULL, **prevNext = &agent_nsap_list; 01006 int handle = 0; 01007 void *isp = NULL; 01008 01009 if (t == NULL) { 01010 return -1; 01011 } 01012 01013 DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock)); 01014 01015 n = (agent_nsap *) malloc(sizeof(agent_nsap)); 01016 if (n == NULL) { 01017 return -1; 01018 } 01019 s = (netsnmp_session *) malloc(sizeof(netsnmp_session)); 01020 if (s == NULL) { 01021 SNMP_FREE(n); 01022 return -1; 01023 } 01024 memset(s, 0, sizeof(netsnmp_session)); 01025 snmp_sess_init(s); 01026 01027 /* 01028 * Set up the session appropriately for an agent. 01029 */ 01030 01031 s->version = SNMP_DEFAULT_VERSION; 01032 s->callback = handle_snmp_packet; 01033 s->authenticator = NULL; 01034 s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 01035 NETSNMP_DS_AGENT_FLAGS); 01036 s->isAuthoritative = SNMP_SESS_AUTHORITATIVE; 01037 01038 sp = snmp_add(s, t, netsnmp_agent_check_packet, 01039 netsnmp_agent_check_parse); 01040 if (sp == NULL) { 01041 SNMP_FREE(s); 01042 SNMP_FREE(n); 01043 return -1; 01044 } 01045 01046 isp = snmp_sess_pointer(sp); 01047 if (isp == NULL) { /* over-cautious */ 01048 SNMP_FREE(s); 01049 SNMP_FREE(n); 01050 return -1; 01051 } 01052 01053 n->s = isp; 01054 n->t = t; 01055 01056 if (main_session == NULL) { 01057 main_session = snmp_sess_session(isp); 01058 } 01059 01060 for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle; 01061 a = a->next) { 01062 handle = a->handle; 01063 prevNext = &(a->next); 01064 } 01065 01066 if (handle < INT_MAX) { 01067 n->handle = handle + 1; 01068 n->next = a; 01069 *prevNext = n; 01070 SNMP_FREE(s); 01071 return n->handle; 01072 } else { 01073 SNMP_FREE(s); 01074 SNMP_FREE(n); 01075 return -1; 01076 } 01077 } 01078 01079 void 01080 netsnmp_deregister_agent_nsap(int handle) 01081 { 01082 agent_nsap *a = NULL, **prevNext = &agent_nsap_list; 01083 int main_session_deregistered = 0; 01084 01085 DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle)); 01086 01087 for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) { 01088 prevNext = &(a->next); 01089 } 01090 01091 if (a != NULL && a->handle == handle) { 01092 *prevNext = a->next; 01093 if (main_session == snmp_sess_session(a->s)) { 01094 main_session_deregistered = 1; 01095 } 01096 snmp_close(snmp_sess_session(a->s)); 01097 /* 01098 * The above free()s the transport and session pointers. 01099 */ 01100 SNMP_FREE(a); 01101 } 01102 01103 /* 01104 * If we've deregistered the session that main_session used to point to, 01105 * then make it point to another one, or in the last resort, make it equal 01106 * to NULL. Basically this shouldn't ever happen in normal operation 01107 * because main_session starts off pointing at the first session added by 01108 * init_master_agent(), which then discards the handle. 01109 */ 01110 01111 if (main_session_deregistered) { 01112 if (agent_nsap_list != NULL) { 01113 DEBUGMSGTL(("snmp_agent", 01114 "WARNING: main_session ptr changed from %p to %p\n", 01115 main_session, snmp_sess_session(agent_nsap_list->s))); 01116 main_session = snmp_sess_session(agent_nsap_list->s); 01117 } else { 01118 DEBUGMSGTL(("snmp_agent", 01119 "WARNING: main_session ptr changed from %p to NULL\n", 01120 main_session)); 01121 main_session = NULL; 01122 } 01123 } 01124 } 01125 01126 01127 01128 /* 01129 * 01130 * This function has been modified to use the experimental 01131 * netsnmp_register_agent_nsap interface. The major responsibility of this 01132 * function now is to interpret a string specified to the agent (via -p on the 01133 * command line, or from a configuration file) as a list of agent NSAPs on 01134 * which to listen for SNMP packets. Typically, when you add a new transport 01135 * domain "foo", you add code here such that if the "foo" code is compiled 01136 * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the 01137 * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate 01138 * transport descriptor. netsnmp_register_agent_nsap is then called with that 01139 * transport descriptor and sets up a listening agent session on it. 01140 * 01141 * Everything then works much as normal: the agent runs in an infinite loop 01142 * (in the snmpd.c/receive()routine), which calls snmp_read() when a request 01143 * is readable on any of the given transports. This routine then traverses 01144 * the library 'Sessions' list to identify the relevant session and eventually 01145 * invokes '_sess_read'. This then processes the incoming packet, calling the 01146 * pre_parse, parse, post_parse and callback routines in turn. 01147 * 01148 * JBPN 20001117 01149 */ 01150 01151 int 01152 init_master_agent(void) 01153 { 01154 netsnmp_transport *transport; 01155 char *cptr; 01156 char buf[SPRINT_MAX_LEN]; 01157 char *st; 01158 01159 /* default to a default cache size */ 01160 netsnmp_set_lookup_cache_size(-1); 01161 01162 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01163 NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) { 01164 DEBUGMSGTL(("snmp_agent", 01165 "init_master_agent; not master agent\n")); 01166 01167 netsnmp_assert("agent role !master && !sub_agent"); 01168 01169 return 0; /* No error if ! MASTER_AGENT */ 01170 } 01171 #ifdef USING_AGENTX_MASTER_MODULE 01172 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 01173 NETSNMP_DS_AGENT_AGENTX_MASTER) == 1) 01174 real_init_master(); 01175 #endif 01176 #ifdef USING_SMUX_MODULE 01177 if(should_init("smux")) 01178 real_init_smux(); 01179 #endif 01180 01181 /* 01182 * Have specific agent ports been specified? 01183 */ 01184 cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 01185 NETSNMP_DS_AGENT_PORTS); 01186 01187 if (cptr) { 01188 snprintf(buf, sizeof(buf), "%s", cptr); 01189 buf[ sizeof(buf)-1 ] = 0; 01190 } else { 01191 /* 01192 * No, so just specify the default port. 01193 */ 01194 buf[0] = 0; 01195 } 01196 01197 DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf)); 01198 st = buf; 01199 do { 01200 /* 01201 * Specification format: 01202 * 01203 * NONE: (a pseudo-transport) 01204 * UDP:[address:]port (also default if no transport is specified) 01205 * TCP:[address:]port (if supported) 01206 * Unix:pathname (if supported) 01207 * AAL5PVC:itf.vpi.vci (if supported) 01208 * IPX:[network]:node[/port] (if supported) 01209 * 01210 */ 01211 01212 cptr = st; 01213 st = strchr(st, ','); 01214 if (st) 01215 *st++ = '\0'; 01216 01217 DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n", 01218 cptr)); 01219 01220 if (strncasecmp(cptr, "none", 4) == 0) { 01221 DEBUGMSGTL(("snmp_agent", 01222 "init_master_agent; pseudo-transport \"none\" " 01223 "requested\n")); 01224 return 0; 01225 } 01226 transport = netsnmp_transport_open_server("snmp", cptr); 01227 01228 if (transport == NULL) { 01229 snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n", 01230 cptr); 01231 return 1; 01232 } 01233 01234 if (netsnmp_register_agent_nsap(transport) == 0) { 01235 snmp_log(LOG_ERR, 01236 "Error registering specified transport \"%s\" as an " 01237 "agent NSAP\n", cptr); 01238 return 1; 01239 } else { 01240 DEBUGMSGTL(("snmp_agent", 01241 "init_master_agent; \"%s\" registered as an agent " 01242 "NSAP\n", cptr)); 01243 } 01244 } while(st && *st != '\0'); 01245 01246 return 0; 01247 } 01248 01249 void 01250 clear_nsap_list(void) 01251 { 01252 DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n")); 01253 01254 while (agent_nsap_list != NULL) 01255 netsnmp_deregister_agent_nsap(agent_nsap_list->handle); 01256 } 01257 01258 void 01259 shutdown_master_agent(void) 01260 { 01261 clear_nsap_list(); 01262 } 01263 01264 01265 netsnmp_agent_session * 01266 init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu) 01267 { 01268 netsnmp_agent_session *asp = (netsnmp_agent_session *) 01269 calloc(1, sizeof(netsnmp_agent_session)); 01270 01271 if (asp == NULL) { 01272 return NULL; 01273 } 01274 01275 DEBUGMSGTL(("snmp_agent","agent_sesion %08p created\n", asp)); 01276 asp->session = session; 01277 asp->pdu = snmp_clone_pdu(pdu); 01278 asp->orig_pdu = snmp_clone_pdu(pdu); 01279 asp->rw = READ; 01280 asp->exact = TRUE; 01281 asp->next = NULL; 01282 asp->mode = RESERVE1; 01283 asp->status = SNMP_ERR_NOERROR; 01284 asp->index = 0; 01285 asp->oldmode = 0; 01286 asp->treecache_num = -1; 01287 asp->treecache_len = 0; 01288 asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info); 01289 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n", 01290 asp, asp->reqinfo)); 01291 01292 return asp; 01293 } 01294 01295 void 01296 free_agent_snmp_session(netsnmp_agent_session *asp) 01297 { 01298 if (!asp) 01299 return; 01300 01301 DEBUGMSGTL(("snmp_agent","agent_session %08p released\n", asp)); 01302 01303 netsnmp_remove_from_delegated(asp); 01304 01305 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n", 01306 asp, asp->reqinfo)); 01307 if (asp->orig_pdu) 01308 snmp_free_pdu(asp->orig_pdu); 01309 if (asp->pdu) 01310 snmp_free_pdu(asp->pdu); 01311 if (asp->reqinfo) 01312 netsnmp_free_agent_request_info(asp->reqinfo); 01313 if (asp->treecache) { 01314 SNMP_FREE(asp->treecache); 01315 } 01316 if (asp->bulkcache) { 01317 SNMP_FREE(asp->bulkcache); 01318 } 01319 if (asp->requests) { 01320 int i; 01321 for (i = 0; i < asp->vbcount; i++) { 01322 netsnmp_free_request_data_sets(&asp->requests[i]); 01323 } 01324 SNMP_FREE(asp->requests); 01325 } 01326 if (asp->cache_store) { 01327 netsnmp_free_cachemap(asp->cache_store); 01328 asp->cache_store = NULL; 01329 } 01330 SNMP_FREE(asp); 01331 } 01332 01333 int 01334 netsnmp_check_for_delegated(netsnmp_agent_session *asp) 01335 { 01336 int i; 01337 netsnmp_request_info *request; 01338 01339 if (NULL == asp->treecache) 01340 return 0; 01341 01342 for (i = 0; i <= asp->treecache_num; i++) { 01343 for (request = asp->treecache[i].requests_begin; request; 01344 request = request->next) { 01345 if (request->delegated) 01346 return 1; 01347 } 01348 } 01349 return 0; 01350 } 01351 01352 int 01353 netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp) 01354 { 01355 netsnmp_agent_session *asptmp; 01356 for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) { 01357 if (asptmp == asp) 01358 return 1; 01359 } 01360 return 0; 01361 } 01362 01363 int 01364 netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp) 01365 { 01366 if (netsnmp_check_for_delegated(asp)) { 01367 if (!netsnmp_check_delegated_chain_for(asp)) { 01368 /* 01369 * add to delegated request chain 01370 */ 01371 asp->next = agent_delegated_list; 01372 agent_delegated_list = asp; 01373 DEBUGMSGTL(("snmp_agent", "delegate session == %08p\n", asp)); 01374 } 01375 return 1; 01376 } 01377 return 0; 01378 } 01379 01380 int 01381 netsnmp_remove_from_delegated(netsnmp_agent_session *asp) 01382 { 01383 netsnmp_agent_session *curr, *prev = NULL; 01384 01385 for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) { 01386 /* 01387 * is this us? 01388 */ 01389 if (curr != asp) 01390 continue; 01391 01392 /* 01393 * remove from queue 01394 */ 01395 if (prev != NULL) 01396 prev->next = asp->next; 01397 else 01398 agent_delegated_list = asp->next; 01399 01400 DEBUGMSGTL(("snmp_agent", "remove delegated session == %08p\n", asp)); 01401 01402 return 1; 01403 } 01404 01405 return 0; 01406 } 01407 01408 /* 01409 * netsnmp_remove_delegated_requests_for_session 01410 * 01411 * called when a session is being closed. Check all delegated requests to 01412 * see if the are waiting on this session, and if set, set the status for 01413 * that request to GENERR. 01414 */ 01415 int 01416 netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess) 01417 { 01418 netsnmp_agent_session *asp; 01419 int count = 0; 01420 01421 for (asp = agent_delegated_list; asp; asp = asp->next) { 01422 /* 01423 * check each request 01424 */ 01425 netsnmp_request_info *request; 01426 for(request = asp->requests; request; request = request->next) { 01427 /* 01428 * check session 01429 */ 01430 netsnmp_assert(NULL!=request->subtree); 01431 if(request->subtree->session != sess) 01432 continue; 01433 01434 /* 01435 * matched! mark request as done 01436 */ 01437 netsnmp_request_set_error(request, SNMP_ERR_GENERR); 01438 ++count; 01439 } 01440 } 01441 01442 /* 01443 * if we found any, that request may be finished now 01444 */ 01445 if(count) { 01446 DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session " 01447 "%08p\n", count, sess)); 01448 netsnmp_check_outstanding_agent_requests(); 01449 } 01450 01451 return count; 01452 } 01453 01454 int 01455 netsnmp_check_queued_chain_for(netsnmp_agent_session *asp) 01456 { 01457 netsnmp_agent_session *asptmp; 01458 for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) { 01459 if (asptmp == asp) 01460 return 1; 01461 } 01462 return 0; 01463 } 01464 01465 int 01466 netsnmp_add_queued(netsnmp_agent_session *asp) 01467 { 01468 netsnmp_agent_session *asp_tmp; 01469 01470 /* 01471 * first item? 01472 */ 01473 if (NULL == netsnmp_agent_queued_list) { 01474 netsnmp_agent_queued_list = asp; 01475 return 1; 01476 } 01477 01478 01479 /* 01480 * add to end of queued request chain 01481 */ 01482 asp_tmp = netsnmp_agent_queued_list; 01483 for (; asp_tmp; asp_tmp = asp_tmp->next) { 01484 /* 01485 * already in queue? 01486 */ 01487 if (asp_tmp == asp) 01488 break; 01489 01490 /* 01491 * end of queue? 01492 */ 01493 if (NULL == asp_tmp->next) 01494 asp_tmp->next = asp; 01495 } 01496 return 1; 01497 } 01498 01499 01500 int 01501 netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status) 01502 { 01503 netsnmp_variable_list *var_ptr; 01504 int i; 01505 01506 /* 01507 * if this request was a set, clear the global now that we are 01508 * done. 01509 */ 01510 if (asp == netsnmp_processing_set) { 01511 DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %08p\n", 01512 asp)); 01513 netsnmp_processing_set = NULL; 01514 } 01515 01516 if (asp->pdu) { 01517 /* 01518 * If we've got an error status, then this needs to be 01519 * passed back up to the higher levels.... 01520 */ 01521 if ( status != 0 && asp->status == 0 ) 01522 asp->status = status; 01523 01524 switch (asp->pdu->command) { 01525 case SNMP_MSG_INTERNAL_SET_BEGIN: 01526 case SNMP_MSG_INTERNAL_SET_RESERVE1: 01527 case SNMP_MSG_INTERNAL_SET_RESERVE2: 01528 case SNMP_MSG_INTERNAL_SET_ACTION: 01529 /* 01530 * some stuff needs to be saved in special subagent cases 01531 */ 01532 save_set_cache(asp); 01533 break; 01534 01535 case SNMP_MSG_GETNEXT: 01536 _fix_endofmibview(asp); 01537 break; 01538 01539 case SNMP_MSG_GETBULK: 01540 /* 01541 * for a GETBULK response we need to rearrange the varbinds 01542 */ 01543 _reorder_getbulk(asp); 01544 break; 01545 } 01546 01547 /* 01548 * May need to "dumb down" a SET error status for a 01549 * v1 query. See RFC2576 - section 4.3 01550 */ 01551 #ifndef NETSNMP_DISABLE_SNMPV1 01552 if ((asp->pdu->command == SNMP_MSG_SET) && 01553 (asp->pdu->version == SNMP_VERSION_1)) { 01554 switch (asp->status) { 01555 case SNMP_ERR_WRONGVALUE: 01556 case SNMP_ERR_WRONGENCODING: 01557 case SNMP_ERR_WRONGTYPE: 01558 case SNMP_ERR_WRONGLENGTH: 01559 case SNMP_ERR_INCONSISTENTVALUE: 01560 status = SNMP_ERR_BADVALUE; 01561 asp->status = SNMP_ERR_BADVALUE; 01562 break; 01563 case SNMP_ERR_NOACCESS: 01564 case SNMP_ERR_NOTWRITABLE: 01565 case SNMP_ERR_NOCREATION: 01566 case SNMP_ERR_INCONSISTENTNAME: 01567 case SNMP_ERR_AUTHORIZATIONERROR: 01568 status = SNMP_ERR_NOSUCHNAME; 01569 asp->status = SNMP_ERR_NOSUCHNAME; 01570 break; 01571 case SNMP_ERR_RESOURCEUNAVAILABLE: 01572 case SNMP_ERR_COMMITFAILED: 01573 case SNMP_ERR_UNDOFAILED: 01574 status = SNMP_ERR_GENERR; 01575 asp->status = SNMP_ERR_GENERR; 01576 break; 01577 } 01578 } 01579 /* 01580 * Similarly we may need to "dumb down" v2 exception 01581 * types to throw an error for a v1 query. 01582 * See RFC2576 - section 4.1.2.3 01583 */ 01584 if ((asp->pdu->command != SNMP_MSG_SET) && 01585 (asp->pdu->version == SNMP_VERSION_1)) { 01586 for (var_ptr = asp->pdu->variables, i = 1; 01587 var_ptr != NULL; var_ptr = var_ptr->next_variable, i++) { 01588 switch (var_ptr->type) { 01589 case SNMP_NOSUCHOBJECT: 01590 case SNMP_NOSUCHINSTANCE: 01591 case SNMP_ENDOFMIBVIEW: 01592 case ASN_COUNTER64: 01593 status = SNMP_ERR_NOSUCHNAME; 01594 asp->status = SNMP_ERR_NOSUCHNAME; 01595 asp->index = i; 01596 break; 01597 } 01598 } 01599 } 01600 #endif /* snmpv1 support */ 01601 } 01603 /* 01604 * Update the snmp error-count statistics 01605 * XXX - should we include the V2 errors in this or not? 01606 */ 01607 #define INCLUDE_V2ERRORS_IN_V1STATS 01608 01609 switch (status) { 01610 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01611 case SNMP_ERR_WRONGVALUE: 01612 case SNMP_ERR_WRONGENCODING: 01613 case SNMP_ERR_WRONGTYPE: 01614 case SNMP_ERR_WRONGLENGTH: 01615 case SNMP_ERR_INCONSISTENTVALUE: 01616 #endif 01617 case SNMP_ERR_BADVALUE: 01618 snmp_increment_statistic(STAT_SNMPOUTBADVALUES); 01619 break; 01620 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01621 case SNMP_ERR_NOACCESS: 01622 case SNMP_ERR_NOTWRITABLE: 01623 case SNMP_ERR_NOCREATION: 01624 case SNMP_ERR_INCONSISTENTNAME: 01625 case SNMP_ERR_AUTHORIZATIONERROR: 01626 #endif 01627 case SNMP_ERR_NOSUCHNAME: 01628 snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES); 01629 break; 01630 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01631 case SNMP_ERR_RESOURCEUNAVAILABLE: 01632 case SNMP_ERR_COMMITFAILED: 01633 case SNMP_ERR_UNDOFAILED: 01634 #endif 01635 case SNMP_ERR_GENERR: 01636 snmp_increment_statistic(STAT_SNMPOUTGENERRS); 01637 break; 01638 01639 case SNMP_ERR_TOOBIG: 01640 snmp_increment_statistic(STAT_SNMPOUTTOOBIGS); 01641 break; 01642 } 01643 01644 if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) { 01645 snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ? 01646 STAT_SNMPINTOTALSETVARS : 01647 STAT_SNMPINTOTALREQVARS), 01648 count_varbinds(asp->pdu->variables)); 01649 } else { 01650 /* 01651 * Use a copy of the original request 01652 * to report failures. 01653 */ 01654 snmp_free_pdu(asp->pdu); 01655 asp->pdu = asp->orig_pdu; 01656 asp->orig_pdu = NULL; 01657 } 01658 if (asp->pdu) { 01659 asp->pdu->command = SNMP_MSG_RESPONSE; 01660 asp->pdu->errstat = asp->status; 01661 asp->pdu->errindex = asp->index; 01662 if (!snmp_send(asp->session, asp->pdu)) { 01663 netsnmp_variable_list *var_ptr; 01664 snmp_perror("send response"); 01665 for (var_ptr = asp->pdu->variables; var_ptr != NULL; 01666 var_ptr = var_ptr->next_variable) { 01667 size_t c_oidlen = 256, c_outlen = 0; 01668 u_char *c_oid = (u_char *) malloc(c_oidlen); 01669 01670 if (c_oid) { 01671 if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1, 01672 var_ptr->name, 01673 var_ptr->name_length)) { 01674 snmp_log(LOG_ERR, " -- %s [TRUNCATED]\n", c_oid); 01675 } else { 01676 snmp_log(LOG_ERR, " -- %s\n", c_oid); 01677 } 01678 SNMP_FREE(c_oid); 01679 } 01680 } 01681 snmp_free_pdu(asp->pdu); 01682 asp->pdu = NULL; 01683 } 01684 snmp_increment_statistic(STAT_SNMPOUTPKTS); 01685 snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES); 01686 asp->pdu = NULL; /* yyy-rks: redundant, no? */ 01687 netsnmp_remove_and_free_agent_snmp_session(asp); 01688 } 01689 return 1; 01690 } 01691 01692 void 01693 dump_sess_list(void) 01694 { 01695 netsnmp_agent_session *a; 01696 01697 DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> ")); 01698 for (a = agent_session_list; a != NULL; a = a->next) { 01699 DEBUGMSG(("snmp_agent", "%08p[session %08p] -> ", a, a->session)); 01700 } 01701 DEBUGMSG(("snmp_agent", "[NIL]\n")); 01702 } 01703 01704 void 01705 netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp) 01706 { 01707 netsnmp_agent_session *a, **prevNext = &agent_session_list; 01708 01709 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", asp)); 01710 01711 for (a = agent_session_list; a != NULL; a = *prevNext) { 01712 if (a == asp) { 01713 *prevNext = a->next; 01714 a->next = NULL; 01715 free_agent_snmp_session(a); 01716 asp = NULL; 01717 break; 01718 } else { 01719 prevNext = &(a->next); 01720 } 01721 } 01722 01723 if (a == NULL && asp != NULL) { 01724 /* 01725 * We coulnd't find it on the list, so free it anyway. 01726 */ 01727 free_agent_snmp_session(asp); 01728 } 01729 } 01730 01731 void 01732 netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess, 01733 void (*free_request) 01734 (netsnmp_request_list *)) 01735 { 01736 netsnmp_agent_session *a, *next, **prevNext = &agent_session_list; 01737 01738 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", sess)); 01739 01740 for (a = agent_session_list; a != NULL; a = next) { 01741 if (a->session == sess) { 01742 *prevNext = a->next; 01743 next = a->next; 01744 free_agent_snmp_session(a); 01745 } else { 01746 prevNext = &(a->next); 01747 next = a->next; 01748 } 01749 } 01750 } 01751 01753 int 01754 handle_snmp_packet(int op, netsnmp_session * session, int reqid, 01755 netsnmp_pdu *pdu, void *magic) 01756 { 01757 netsnmp_agent_session *asp; 01758 int status, access_ret, rc; 01759 01760 /* 01761 * We only support receiving here. 01762 */ 01763 if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) { 01764 return 1; 01765 } 01766 01767 /* 01768 * RESPONSE messages won't get this far, but TRAP-like messages 01769 * might. 01770 */ 01771 if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM || 01772 pdu->command == SNMP_MSG_TRAP2) { 01773 DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n", 01774 pdu->command)); 01775 pdu->command = SNMP_MSG_TRAP2; 01776 snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS); 01777 return 1; 01778 } 01779 01780 /* 01781 * send snmpv3 authfail trap. 01782 */ 01783 if (pdu->version == SNMP_VERSION_3 && 01784 session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) { 01785 send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); 01786 return 1; 01787 } 01788 01789 if (magic == NULL) { 01790 asp = init_agent_snmp_session(session, pdu); 01791 status = SNMP_ERR_NOERROR; 01792 } else { 01793 asp = (netsnmp_agent_session *) magic; 01794 status = asp->status; 01795 } 01796 01797 if ((access_ret = check_access(asp->pdu)) != 0) { 01798 if (access_ret == VACM_NOSUCHCONTEXT) { 01799 /* 01800 * rfc3413 section 3.2, step 5 says that we increment the 01801 * counter but don't return a response of any kind 01802 */ 01803 01804 /* 01805 * we currently don't support unavailable contexts, as 01806 * there is no reason to that I currently know of 01807 */ 01808 snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS); 01809 01810 /* 01811 * drop the request 01812 */ 01813 netsnmp_remove_and_free_agent_snmp_session(asp); 01814 return 0; 01815 } else { 01816 /* 01817 * access control setup is incorrect 01818 */ 01819 send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); 01820 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01821 #if defined(NETSNMP_DISABLE_SNMPV1) 01822 if (asp->pdu->version != SNMP_VERSION_2c) { 01823 #else 01824 #if defined(NETSNMP_DISABLE_SNMPV2C) 01825 if (asp->pdu->version != SNMP_VERSION_1) { 01826 #else 01827 if (asp->pdu->version != SNMP_VERSION_1 01828 && asp->pdu->version != SNMP_VERSION_2c) { 01829 #endif 01830 #endif 01831 asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR; 01832 asp->pdu->command = SNMP_MSG_RESPONSE; 01833 snmp_increment_statistic(STAT_SNMPOUTPKTS); 01834 if (!snmp_send(asp->session, asp->pdu)) 01835 snmp_free_pdu(asp->pdu); 01836 asp->pdu = NULL; 01837 netsnmp_remove_and_free_agent_snmp_session(asp); 01838 return 1; 01839 } else { 01840 #endif /* support for community based SNMP */ 01841 /* 01842 * drop the request 01843 */ 01844 netsnmp_remove_and_free_agent_snmp_session(asp); 01845 return 0; 01846 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01847 } 01848 #endif /* support for community based SNMP */ 01849 } 01850 } 01851 01852 rc = netsnmp_handle_request(asp, status); 01853 01854 /* 01855 * done 01856 */ 01857 DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %08p\n", 01858 asp)); 01859 return rc; 01860 } 01861 01862 netsnmp_request_info * 01863 netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount, 01864 netsnmp_variable_list * varbind_ptr, 01865 netsnmp_subtree *tp) 01866 { 01867 netsnmp_request_info *request = NULL; 01868 int cacheid; 01869 01870 DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount)); 01871 DEBUGMSGOID(("snmp_agent", varbind_ptr->name, 01872 varbind_ptr->name_length)); 01873 DEBUGMSG(("snmp_agent", ", %8p)\n", tp)); 01874 01875 if (tp && 01876 (asp->pdu->command == SNMP_MSG_GETNEXT || 01877 asp->pdu->command == SNMP_MSG_GETBULK)) { 01878 int result; 01879 int prefix_len; 01880 01881 prefix_len = netsnmp_oid_find_prefix(tp->start_a, 01882 tp->start_len, 01883 tp->end_a, tp->end_len); 01884 if (prefix_len < 1) { 01885 result = VACM_NOTINVIEW; /* ack... bad bad thing happened */ 01886 } else { 01887 result = 01888 netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len); 01889 } 01890 01891 while (result == VACM_NOTINVIEW) { 01892 /* the entire subtree is not in view. Skip it. */ 01900 tp = tp->next; 01901 if (tp) { 01902 prefix_len = netsnmp_oid_find_prefix(tp->start_a, 01903 tp->start_len, 01904 tp->end_a, 01905 tp->end_len); 01906 if (prefix_len < 1) { 01907 /* ack... bad bad thing happened */ 01908 result = VACM_NOTINVIEW; 01909 } else { 01910 result = 01911 netsnmp_acm_check_subtree(asp->pdu, 01912 tp->start_a, prefix_len); 01913 } 01914 } 01915 else 01916 break; 01917 } 01918 } 01919 if (tp == NULL) { 01920 /* 01921 * no appropriate registration found 01922 */ 01923 /* 01924 * make up the response ourselves 01925 */ 01926 switch (asp->pdu->command) { 01927 case SNMP_MSG_GETNEXT: 01928 case SNMP_MSG_GETBULK: 01929 varbind_ptr->type = SNMP_ENDOFMIBVIEW; 01930 break; 01931 01932 case SNMP_MSG_SET: 01933 case SNMP_MSG_GET: 01934 varbind_ptr->type = SNMP_NOSUCHOBJECT; 01935 break; 01936 01937 default: 01938 return NULL; /* shouldn't get here */ 01939 } 01940 } else { 01941 DEBUGMSGTL(("snmp_agent", "tp->start ")); 01942 DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len)); 01943 DEBUGMSG(("snmp_agent", ", tp->end ")); 01944 DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len)); 01945 DEBUGMSG(("snmp_agent", ", \n")); 01946 01947 /* 01948 * malloc the request structure 01949 */ 01950 request = &(asp->requests[vbcount - 1]); 01951 request->index = vbcount; 01952 request->delegated = 0; 01953 request->processed = 0; 01954 request->status = 0; 01955 request->subtree = tp; 01956 request->agent_req_info = asp->reqinfo; 01957 if (request->parent_data) { 01958 netsnmp_free_request_data_sets(request); 01959 } 01960 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", 01961 asp, asp->reqinfo)); 01962 01963 /* 01964 * for non-SET modes, set the type to NULL 01965 */ 01966 if (!MODE_IS_SET(asp->pdu->command)) { 01967 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", 01968 asp, asp->reqinfo)); 01969 if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) { 01970 DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n", 01971 request->index)); 01972 request->inclusive = 1; 01973 } 01974 varbind_ptr->type = ASN_NULL; 01975 } 01976 01977 /* 01978 * place them in a cache 01979 */ 01980 if (tp->global_cacheid) { 01981 /* 01982 * we need to merge all marked subtrees together 01983 */ 01984 if (asp->cache_store && -1 != 01985 (cacheid = netsnmp_get_local_cachid(asp->cache_store, 01986 tp->global_cacheid))) { 01987 } else { 01988 cacheid = ++(asp->treecache_num); 01989 netsnmp_get_or_add_local_cachid(&asp->cache_store, 01990 tp->global_cacheid, 01991 cacheid); 01992 goto mallocslot; /* XXX: ick */ 01993 } 01994 } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num && 01995 asp->treecache[tp->cacheid].subtree == tp) { 01996 /* 01997 * we have already added a request to this tree 01998 * pointer before 01999 */ 02000 cacheid = tp->cacheid; 02001 } else { 02002 cacheid = ++(asp->treecache_num); 02003 mallocslot: 02004 /* 02005 * new slot needed 02006 */ 02007 if (asp->treecache_num >= asp->treecache_len) { 02008 /* 02009 * exapand cache array 02010 */ 02011 /* 02012 * WWW: non-linear expansion needed (with cap) 02013 */ 02014 #define CACHE_GROW_SIZE 16 02015 asp->treecache_len = 02016 (asp->treecache_len + CACHE_GROW_SIZE); 02017 asp->treecache = 02018 realloc(asp->treecache, 02019 sizeof(netsnmp_tree_cache) * 02020 asp->treecache_len); 02021 if (asp->treecache == NULL) 02022 return NULL; 02023 memset(&(asp->treecache[cacheid]), 0x00, 02024 sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE)); 02025 } 02026 asp->treecache[cacheid].subtree = tp; 02027 asp->treecache[cacheid].requests_begin = request; 02028 tp->cacheid = cacheid; 02029 } 02030 02031 /* 02032 * if this is a search type, get the ending range oid as well 02033 */ 02034 if (asp->pdu->command == SNMP_MSG_GETNEXT || 02035 asp->pdu->command == SNMP_MSG_GETBULK) { 02036 request->range_end = tp->end_a; 02037 request->range_end_len = tp->end_len; 02038 } else { 02039 request->range_end = NULL; 02040 request->range_end_len = 0; 02041 } 02042 02043 /* 02044 * link into chain 02045 */ 02046 if (asp->treecache[cacheid].requests_end) 02047 asp->treecache[cacheid].requests_end->next = request; 02048 request->next = NULL; 02049 request->prev = asp->treecache[cacheid].requests_end; 02050 asp->treecache[cacheid].requests_end = request; 02051 02052 /* 02053 * add the given request to the list of requests they need 02054 * to handle results for 02055 */ 02056 request->requestvb = request->requestvb_start = varbind_ptr; 02057 } 02058 return request; 02059 } 02060 02061 /* 02062 * check the ACM(s) for the results on each of the varbinds. 02063 * If ACM disallows it, replace the value with type 02064 * 02065 * Returns number of varbinds with ACM errors 02066 */ 02067 int 02068 check_acm(netsnmp_agent_session *asp, u_char type) 02069 { 02070 int view; 02071 int i, j, k; 02072 netsnmp_request_info *request; 02073 int ret = 0; 02074 netsnmp_variable_list *vb, *vb2, *vbc; 02075 int earliest = 0; 02076 02077 for (i = 0; i <= asp->treecache_num; i++) { 02078 for (request = asp->treecache[i].requests_begin; 02079 request; request = request->next) { 02080 /* 02081 * for each request, run it through in_a_view() 02082 */ 02083 earliest = 0; 02084 for(j = request->repeat, vb = request->requestvb_start; 02085 vb && j > -1; 02086 j--, vb = vb->next_variable) { 02087 if (vb->type != ASN_NULL && 02088 vb->type != ASN_PRIV_RETRY) { /* not yet processed */ 02089 view = 02090 in_a_view(vb->name, &vb->name_length, 02091 asp->pdu, vb->type); 02092 02093 /* 02094 * if a ACM error occurs, mark it as type passed in 02095 */ 02096 if (view != VACM_SUCCESS) { 02097 ret++; 02098 if (request->repeat < request->orig_repeat) { 02099 /* basically this means a GETBULK */ 02100 request->repeat++; 02101 if (!earliest) { 02102 request->requestvb = vb; 02103 earliest = 1; 02104 } 02105 02106 /* ugh. if a whole now exists, we need to 02107 move the contents up the chain and fill 02108 in at the end else we won't end up 02109 lexographically sorted properly */ 02110 if (j > -1 && vb->next_variable && 02111 vb->next_variable->type != ASN_NULL && 02112 vb->next_variable->type != ASN_PRIV_RETRY) { 02113 for(k = j, vbc = vb, vb2 = vb->next_variable; 02114 k > -2 && vbc && vb2; 02115 k--, vbc = vb2, vb2 = vb2->next_variable) { 02116 /* clone next into the current */ 02117 snmp_clone_var(vb2, vbc); 02118 vbc->next_variable = vb2; 02119 } 02120 } 02121 } 02122 snmp_set_var_typed_value(vb, type, NULL, 0); 02123 } 02124 } 02125 } 02126 } 02127 } 02128 return ret; 02129 } 02130 02131 02132 int 02133 netsnmp_create_subtree_cache(netsnmp_agent_session *asp) 02134 { 02135 netsnmp_subtree *tp; 02136 netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext; 02137 int view; 02138 int vbcount = 0; 02139 int bulkcount = 0, bulkrep = 0; 02140 int i = 0, n = 0, r = 0; 02141 netsnmp_request_info *request; 02142 02143 if (asp->treecache == NULL && asp->treecache_len == 0) { 02144 asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16); 02145 asp->treecache = 02146 calloc(asp->treecache_len, sizeof(netsnmp_tree_cache)); 02147 if (asp->treecache == NULL) 02148 return SNMP_ERR_GENERR; 02149 } 02150 asp->treecache_num = -1; 02151 02152 if (asp->pdu->command == SNMP_MSG_GETBULK) { 02153 /* 02154 * getbulk prep 02155 */ 02156 int count = count_varbinds(asp->pdu->variables); 02157 if (asp->pdu->errstat < 0) { 02158 asp->pdu->errstat = 0; 02159 } 02160 if (asp->pdu->errindex < 0) { 02161 asp->pdu->errindex = 0; 02162 } 02163 02164 if (asp->pdu->errstat < count) { 02165 n = asp->pdu->errstat; 02166 } else { 02167 n = count; 02168 } 02169 if ((r = count - n) <= 0) { 02170 r = 0; 02171 asp->bulkcache = NULL; 02172 } else { 02173 int numresponses; 02174 int maxbulk = 02175 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 02176 NETSNMP_DS_AGENT_MAX_GETBULKREPEATS); 02177 int maxresponses = 02178 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 02179 NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES); 02180 02181 if (maxresponses == 0) 02182 maxresponses = 100; /* more than reasonable default */ 02183 02184 if (maxbulk == 0) 02185 maxbulk = -1; 02186 02187 /* limit getbulk number of repeats to a configured size */ 02188 if (asp->pdu->errindex > maxbulk && maxbulk != -1) { 02189 asp->pdu->errindex = maxbulk; 02190 } 02191 02192 numresponses = asp->pdu->errindex * r; 02193 02194 /* limit getbulk number of getbulk responses to a configured size */ 02195 if (maxresponses != -1 && numresponses > maxresponses) { 02196 /* attempt to truncate this */ 02197 asp->pdu->errindex = maxresponses/r; 02198 numresponses = asp->pdu->errindex * r; 02199 DEBUGMSGTL(("snmp_agent", "truncating number of getbulk repeats to %d\n", asp->pdu->errindex)); 02200 } 02201 02202 asp->bulkcache = 02203 (netsnmp_variable_list **) malloc(numresponses * 02204 sizeof(struct 02205 varbind_list *)); 02206 if (!asp->bulkcache) { 02207 DEBUGMSGTL(("snmp_agent", "Bulkcache malloc failed\n")); 02208 return SNMP_ERR_GENERR; 02209 } 02210 } 02211 DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %d, R = %d\n", 02212 n, asp->pdu->errindex, r)); 02213 } 02214 02215 /* 02216 * collect varbinds into their registered trees 02217 */ 02218 prevNext = &(asp->pdu->variables); 02219 for (varbind_ptr = asp->pdu->variables; varbind_ptr; 02220 varbind_ptr = vbsave) { 02221 02222 /* 02223 * getbulk mess with this pointer, so save it 02224 */ 02225 vbsave = varbind_ptr->next_variable; 02226 02227 if (asp->pdu->command == SNMP_MSG_GETBULK) { 02228 if (n > 0) { 02229 n--; 02230 } else { 02231 /* 02232 * repeate request varbinds on GETBULK. These will 02233 * have to be properly rearranged later though as 02234 * responses are supposed to actually be interlaced 02235 * with each other. This is done with the asp->bulkcache. 02236 */ 02237 bulkrep = asp->pdu->errindex - 1; 02238 if (asp->pdu->errindex > 0) { 02239 vbptr = varbind_ptr; 02240 asp->bulkcache[bulkcount++] = vbptr; 02241 02242 for (i = 1; i < asp->pdu->errindex; i++) { 02243 vbptr->next_variable = 02244 SNMP_MALLOC_STRUCT(variable_list); 02245 /* 02246 * don't clone the oid as it's got to be 02247 * overwritten anyway 02248 */ 02249 if (!vbptr->next_variable) { 02250 /* 02251 * XXXWWW: ack!!! 02252 */ 02253 DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n")); 02254 } else { 02255 vbptr = vbptr->next_variable; 02256 vbptr->name_length = 0; 02257 vbptr->type = ASN_NULL; 02258 asp->bulkcache[bulkcount++] = vbptr; 02259 } 02260 } 02261 vbptr->next_variable = vbsave; 02262 } else { 02263 /* 02264 * 0 repeats requested for this varbind, so take it off 02265 * the list. 02266 */ 02267 vbptr = varbind_ptr; 02268 *prevNext = vbptr->next_variable; 02269 vbptr->next_variable = NULL; 02270 snmp_free_varbind(vbptr); 02271 asp->vbcount--; 02272 continue; 02273 } 02274 } 02275 } 02276 02277 /* 02278 * count the varbinds 02279 */ 02280 ++vbcount; 02281 02282 /* 02283 * find the owning tree 02284 */ 02285 tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length, 02286 NULL, asp->pdu->contextName); 02287 02288 /* 02289 * check access control 02290 */ 02291 switch (asp->pdu->command) { 02292 case SNMP_MSG_GET: 02293 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, 02294 asp->pdu, varbind_ptr->type); 02295 if (view != VACM_SUCCESS) 02296 snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT, 02297 NULL, 0); 02298 break; 02299 02300 case SNMP_MSG_SET: 02301 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, 02302 asp->pdu, varbind_ptr->type); 02303 if (view != VACM_SUCCESS) 02304 return SNMP_ERR_NOACCESS; 02305 break; 02306 02307 case SNMP_MSG_GETNEXT: 02308 case SNMP_MSG_GETBULK: 02309 default: 02310 view = VACM_SUCCESS; 02311 /* 02312 * XXXWWW: check VACM here to see if "tp" is even worthwhile 02313 */ 02314 } 02315 if (view == VACM_SUCCESS) { 02316 request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr, 02317 tp); 02318 if (request && asp->pdu->command == SNMP_MSG_GETBULK) { 02319 request->repeat = request->orig_repeat = bulkrep; 02320 } 02321 } 02322 02323 prevNext = &(varbind_ptr->next_variable); 02324 } 02325 02326 return SNMPERR_SUCCESS; 02327 } 02328 02329 /* 02330 * this function is only applicable in getnext like contexts 02331 */ 02332 int 02333 netsnmp_reassign_requests(netsnmp_agent_session *asp) 02334 { 02335 /* 02336 * assume all the requests have been filled or rejected by the 02337 * subtrees, so reassign the rejected ones to the next subtree in 02338 * the chain 02339 */ 02340 02341 int i; 02342 02343 /* 02344 * get old info 02345 */ 02346 netsnmp_tree_cache *old_treecache = asp->treecache; 02347 02348 /* 02349 * malloc new space 02350 */ 02351 asp->treecache = 02352 (netsnmp_tree_cache *) calloc(asp->treecache_len, 02353 sizeof(netsnmp_tree_cache)); 02354 asp->treecache_num = -1; 02355 if (asp->cache_store) { 02356 netsnmp_free_cachemap(asp->cache_store); 02357 asp->cache_store = NULL; 02358 } 02359 02360 for (i = 0; i < asp->vbcount; i++) { 02361 if (asp->requests[i].requestvb == NULL) { 02362 /* 02363 * Occurs when there's a mixture of still active 02364 * and "endOfMibView" repetitions 02365 */ 02366 continue; 02367 } 02368 if (asp->requests[i].requestvb->type == ASN_NULL) { 02369 if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index, 02370 asp->requests[i].requestvb, 02371 asp->requests[i].subtree->next)) { 02372 if (old_treecache != NULL) { 02373 SNMP_FREE(old_treecache); 02374 old_treecache = NULL; 02375 } 02376 } 02377 } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) { 02378 /* 02379 * re-add the same subtree 02380 */ 02381 asp->requests[i].requestvb->type = ASN_NULL; 02382 if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index, 02383 asp->requests[i].requestvb, 02384 asp->requests[i].subtree)) { 02385 if (old_treecache != NULL) { 02386 SNMP_FREE(old_treecache); 02387 old_treecache = NULL; 02388 } 02389 } 02390 } 02391 } 02392 02393 if (old_treecache != NULL) { 02394 SNMP_FREE(old_treecache); 02395 } 02396 return SNMP_ERR_NOERROR; 02397 } 02398 02399 void 02400 netsnmp_delete_request_infos(netsnmp_request_info *reqlist) 02401 { 02402 while (reqlist) { 02403 netsnmp_free_request_data_sets(reqlist); 02404 reqlist = reqlist->next; 02405 } 02406 } 02407 02408 void 02409 netsnmp_delete_subtree_cache(netsnmp_agent_session *asp) 02410 { 02411 while (asp->treecache_num >= 0) { 02412 /* 02413 * don't delete subtrees 02414 */ 02415 netsnmp_delete_request_infos(asp->treecache[asp->treecache_num]. 02416 requests_begin); 02417 asp->treecache_num--; 02418 } 02419 } 02420 02421 /* 02422 * check all requests for errors 02423 * 02424 * @Note: 02425 * This function is a little different from the others in that 02426 * it does not use any linked lists, instead using the original 02427 * asp requests array. This is of particular importance for 02428 * cases where the linked lists are unreliable. One known instance 02429 * of this scenario occurs when the row_merge helper is used, which 02430 * may temporarily disrupts linked lists during its (and its childrens) 02431 * handling of requests. 02432 */ 02433 int 02434 netsnmp_check_all_requests_error(netsnmp_agent_session *asp, 02435 int look_for_specific) 02436 { 02437 int i; 02438 02439 /* 02440 * find any errors marked in the requests 02441 */ 02442 for( i = 0; i < asp->vbcount; ++i ) { 02443 if ((SNMP_ERR_NOERROR != asp->requests[i].status) && 02444 (!look_for_specific || 02445 asp->requests[i].status == look_for_specific)) 02446 return asp->requests[i].status; 02447 } 02448 02449 return SNMP_ERR_NOERROR; 02450 } 02451 02452 int 02453 netsnmp_check_requests_error(netsnmp_request_info *requests) 02454 { 02455 /* 02456 * find any errors marked in the requests 02457 */ 02458 for (;requests;requests = requests->next) { 02459 if (requests->status != SNMP_ERR_NOERROR) 02460 return requests->status; 02461 } 02462 return SNMP_ERR_NOERROR; 02463 } 02464 02465 int 02466 netsnmp_check_requests_status(netsnmp_agent_session *asp, 02467 netsnmp_request_info *requests, 02468 int look_for_specific) 02469 { 02470 /* 02471 * find any errors marked in the requests 02472 */ 02473 while (requests) { 02474 if(requests->agent_req_info != asp->reqinfo) { 02475 DEBUGMSGTL(("verbose:asp", 02476 "**reqinfo %p doesn't match cached reqinfo %p\n", 02477 asp->reqinfo, requests->agent_req_info)); 02478 } 02479 if (requests->status != SNMP_ERR_NOERROR && 02480 (!look_for_specific || requests->status == look_for_specific) 02481 && (look_for_specific || asp->index == 0 02482 || requests->index < asp->index)) { 02483 asp->index = requests->index; 02484 asp->status = requests->status; 02485 } 02486 requests = requests->next; 02487 } 02488 return asp->status; 02489 } 02490 02491 int 02492 netsnmp_check_all_requests_status(netsnmp_agent_session *asp, 02493 int look_for_specific) 02494 { 02495 int i; 02496 for (i = 0; i <= asp->treecache_num; i++) { 02497 netsnmp_check_requests_status(asp, 02498 asp->treecache[i].requests_begin, 02499 look_for_specific); 02500 } 02501 return asp->status; 02502 } 02503 02504 int 02505 handle_var_requests(netsnmp_agent_session *asp) 02506 { 02507 int i, retstatus = SNMP_ERR_NOERROR, 02508 status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR; 02509 netsnmp_handler_registration *reginfo; 02510 02511 asp->reqinfo->asp = asp; 02512 asp->reqinfo->mode = asp->mode; 02513 02514 /* 02515 * now, have the subtrees in the cache go search for their results 02516 */ 02517 for (i = 0; i <= asp->treecache_num; i++) { 02518 /* 02519 * don't call handlers w/null reginfo. 02520 * - when is this? sub agent disconnected while request processing? 02521 * - should this case encompass more of this subroutine? 02522 * - does check_request_status make send if handlers weren't called? 02523 */ 02524 if(NULL != asp->treecache[i].subtree->reginfo) { 02525 reginfo = asp->treecache[i].subtree->reginfo; 02526 status = netsnmp_call_handlers(reginfo, asp->reqinfo, 02527 asp->treecache[i].requests_begin); 02528 } 02529 else 02530 status = SNMP_ERR_GENERR; 02531 02532 /* 02533 * find any errors marked in the requests. For later parts of 02534 * SET processing, only check for new errors specific to that 02535 * set processing directive (which must superceed the previous 02536 * errors). 02537 */ 02538 switch (asp->mode) { 02539 case MODE_SET_COMMIT: 02540 retstatus = netsnmp_check_requests_status(asp, 02541 asp->treecache[i]. 02542 requests_begin, 02543 SNMP_ERR_COMMITFAILED); 02544 break; 02545 02546 case MODE_SET_UNDO: 02547 retstatus = netsnmp_check_requests_status(asp, 02548 asp->treecache[i]. 02549 requests_begin, 02550 SNMP_ERR_UNDOFAILED); 02551 break; 02552 02553 default: 02554 retstatus = netsnmp_check_requests_status(asp, 02555 asp->treecache[i]. 02556 requests_begin, 0); 02557 break; 02558 } 02559 02560 /* 02561 * always take lowest varbind if possible 02562 */ 02563 if (retstatus != SNMP_ERR_NOERROR) { 02564 status = retstatus; 02565 } 02566 02567 /* 02568 * other things we know less about (no index) 02569 */ 02570 /* 02571 * WWW: drop support for this? 02572 */ 02573 if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) { 02574 /* 02575 * we can't break here, since some processing needs to be 02576 * done for all requests anyway (IE, SET handling for UNDO 02577 * needs to be called regardless of previous status 02578 * results. 02579 * WWW: This should be predictable though and 02580 * breaking should be possible in some cases (eg GET, 02581 * GETNEXT, ...) 02582 */ 02583 final_status = status; 02584 } 02585 } 02586 02587 return final_status; 02588 } 02589 02590 /* 02591 * loop through our sessions known delegated sessions and check to see 02592 * if they've completed yet. If there are no more delegated sessions, 02593 * check for and process any queued requests 02594 */ 02595 void 02596 netsnmp_check_outstanding_agent_requests(void) 02597 { 02598 netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL; 02599 02600 /* 02601 * deal with delegated requests 02602 */ 02603 for (asp = agent_delegated_list; asp; asp = next_asp) { 02604 next_asp = asp->next; /* save in case we clean up asp */ 02605 if (!netsnmp_check_for_delegated(asp)) { 02606 02607 /* 02608 * we're done with this one, remove from queue 02609 */ 02610 if (prev_asp != NULL) 02611 prev_asp->next = asp->next; 02612 else 02613 agent_delegated_list = asp->next; 02614 asp->next = NULL; 02615 02616 /* 02617 * check request status 02618 */ 02619 netsnmp_check_all_requests_status(asp, 0); 02620 02621 /* 02622 * continue processing or finish up 02623 */ 02624 check_delayed_request(asp); 02625 02626 /* 02627 * if head was removed, don't drop it if it 02628 * was it re-queued 02629 */ 02630 if ((prev_asp == NULL) && (agent_delegated_list == asp)) { 02631 prev_asp = asp; 02632 } 02633 } else { 02634 02635 /* 02636 * asp is still on the queue 02637 */ 02638 prev_asp = asp; 02639 } 02640 } 02641 02642 /* 02643 * if we are processing a set and there are more delegated 02644 * requests, keep waiting before getting to queued requests. 02645 */ 02646 if (netsnmp_processing_set && (NULL != agent_delegated_list)) 02647 return; 02648 02649 while (netsnmp_agent_queued_list) { 02650 02651 /* 02652 * if we are processing a set, the first item better be 02653 * the set being (or waiting to be) processed. 02654 */ 02655 netsnmp_assert((!netsnmp_processing_set) || 02656 (netsnmp_processing_set == netsnmp_agent_queued_list)); 02657 02658 /* 02659 * if the top request is a set, don't pop it 02660 * off if there are delegated requests 02661 */ 02662 if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) && 02663 (agent_delegated_list)) { 02664 02665 netsnmp_assert(netsnmp_processing_set == NULL); 02666 02667 netsnmp_processing_set = netsnmp_agent_queued_list; 02668 DEBUGMSGTL(("snmp_agent", "SET request remains queued while " 02669 "delegated requests finish, asp = %08p\n", asp)); 02670 break; 02671 } 02672 02673 /* 02674 * pop the first request and process it 02675 */ 02676 asp = netsnmp_agent_queued_list; 02677 netsnmp_agent_queued_list = asp->next; 02678 DEBUGMSGTL(("snmp_agent", 02679 "processing queued request, asp = %08p\n", asp)); 02680 02681 netsnmp_handle_request(asp, asp->status); 02682 02683 /* 02684 * if we hit a set, stop 02685 */ 02686 if (NULL != netsnmp_processing_set) 02687 break; 02688 } 02689 } 02690 02696 int 02697 netsnmp_check_transaction_id(int transaction_id) 02698 { 02699 netsnmp_agent_session *asp, *prev_asp = NULL; 02700 02701 for (asp = agent_delegated_list; asp; prev_asp = asp, asp = asp->next) { 02702 if (asp->pdu->transid == transaction_id) 02703 return SNMPERR_SUCCESS; 02704 } 02705 return SNMPERR_GENERR; 02706 } 02707 02708 02709 /* 02710 * check_delayed_request(asp) 02711 * 02712 * Called to rexamine a set of requests and continue processing them 02713 * once all the previous (delayed) requests have been handled one way 02714 * or another. 02715 */ 02716 02717 int 02718 check_delayed_request(netsnmp_agent_session *asp) 02719 { 02720 int status = SNMP_ERR_NOERROR; 02721 02722 DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %08p\n", 02723 asp)); 02724 02725 switch (asp->mode) { 02726 case SNMP_MSG_GETBULK: 02727 case SNMP_MSG_GETNEXT: 02728 netsnmp_check_all_requests_status(asp, 0); 02729 handle_getnext_loop(asp); 02730 if (netsnmp_check_for_delegated(asp) && 02731 netsnmp_check_transaction_id(asp->pdu->transid) != 02732 SNMPERR_SUCCESS) { 02733 /* 02734 * add to delegated request chain 02735 */ 02736 if (!netsnmp_check_delegated_chain_for(asp)) { 02737 asp->next = agent_delegated_list; 02738 agent_delegated_list = asp; 02739 } 02740 } 02741 break; 02742 02743 case MODE_SET_COMMIT: 02744 netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED); 02745 goto settop; 02746 02747 case MODE_SET_UNDO: 02748 netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED); 02749 goto settop; 02750 02751 case MODE_SET_BEGIN: 02752 case MODE_SET_RESERVE1: 02753 case MODE_SET_RESERVE2: 02754 case MODE_SET_ACTION: 02755 case MODE_SET_FREE: 02756 settop: 02757 /* If we should do only one pass, this mean we */ 02758 /* should not reenter this function */ 02759 if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { 02760 /* We should have finished the processing after the first */ 02761 /* handle_set_loop, so just wrap up */ 02762 break; 02763 } 02764 handle_set_loop(asp); 02765 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { 02766 02767 if (netsnmp_check_for_delegated_and_add(asp)) { 02768 /* 02769 * add to delegated request chain 02770 */ 02771 if (!asp->status) 02772 asp->status = status; 02773 } 02774 02775 return SNMP_ERR_NOERROR; 02776 } 02777 break; 02778 02779 default: 02780 break; 02781 } 02782 02783 /* 02784 * if we don't have anything outstanding (delegated), wrap up 02785 */ 02786 if (!netsnmp_check_for_delegated(asp)) 02787 return netsnmp_wrap_up_request(asp, status); 02788 02789 return 1; 02790 } 02791 02793 int 02794 check_getnext_results(netsnmp_agent_session *asp) 02795 { 02796 /* 02797 * get old info 02798 */ 02799 netsnmp_tree_cache *old_treecache = asp->treecache; 02800 int old_treecache_num = asp->treecache_num; 02801 int count = 0; 02802 int i, special = 0; 02803 netsnmp_request_info *request; 02804 02805 if (asp->mode == SNMP_MSG_GET) { 02806 /* 02807 * Special case for doing INCLUSIVE getNext operations in 02808 * AgentX subagents. 02809 */ 02810 DEBUGMSGTL(("snmp_agent", 02811 "asp->mode == SNMP_MSG_GET in ch_getnext\n")); 02812 asp->mode = asp->oldmode; 02813 special = 1; 02814 } 02815 02816 for (i = 0; i <= old_treecache_num; i++) { 02817 for (request = old_treecache[i].requests_begin; request; 02818 request = request->next) { 02819 02820 /* 02821 * If we have just done the special case AgentX GET, then any 02822 * requests which were not INCLUSIVE will now have a wrong 02823 * response, so junk them and retry from the same place (except 02824 * that this time the handler will be called in "inexact" 02825 * mode). 02826 */ 02827 02828 if (special) { 02829 if (!request->inclusive) { 02830 DEBUGMSGTL(("snmp_agent", 02831 "request %d wasn't inclusive\n", 02832 request->index)); 02833 snmp_set_var_typed_value(request->requestvb, 02834 ASN_PRIV_RETRY, NULL, 0); 02835 } else if (request->requestvb->type == ASN_NULL || 02836 request->requestvb->type == SNMP_NOSUCHINSTANCE || 02837 request->requestvb->type == SNMP_NOSUCHOBJECT) { 02838 /* 02839 * it was inclusive, but no results. Still retry this 02840 * search. 02841 */ 02842 snmp_set_var_typed_value(request->requestvb, 02843 ASN_PRIV_RETRY, NULL, 0); 02844 } 02845 } 02846 02847 /* 02848 * out of range? 02849 */ 02850 if (snmp_oid_compare(request->requestvb->name, 02851 request->requestvb->name_length, 02852 request->range_end, 02853 request->range_end_len) >= 0) { 02854 /* 02855 * ack, it's beyond the accepted end of range. 02856 */ 02857 /* 02858 * fix it by setting the oid to the end of range oid instead 02859 */ 02860 DEBUGMSGTL(("check_getnext_results", 02861 "request response %d out of range\n", 02862 request->index)); 02863 /* 02864 * I'm not sure why inclusive is set unconditionally here (see 02865 * comments for revision 1.161), but it causes a problem for 02866 * GETBULK over an overridden variable. The bulk-to-next 02867 * handler re-uses the same request for multiple varbinds, 02868 * and once inclusive was set, it was never cleared. So, a 02869 * hack. Instead of setting it to 1, set it to 2, so bulk-to 02870 * next can clear it later. As of the time of this hack, all 02871 * checks of this var are boolean checks (not == 1), so this 02872 * should be safe. Cross your fingers. 02873 */ 02874 request->inclusive = 2; 02875 /* 02876 * XXX: should set this to the original OID? 02877 */ 02878 snmp_set_var_objid(request->requestvb, 02879 request->range_end, 02880 request->range_end_len); 02881 snmp_set_var_typed_value(request->requestvb, ASN_NULL, 02882 NULL, 0); 02883 } 02884 02885 /* 02886 * mark any existent requests with illegal results as NULL 02887 */ 02888 if (request->requestvb->type == SNMP_ENDOFMIBVIEW) { 02889 /* 02890 * illegal response from a subagent. Change it back to NULL 02891 * xxx-rks: err, how do we know this is a subagent? 02892 */ 02893 request->requestvb->type = ASN_NULL; 02894 request->inclusive = 1; 02895 } 02896 02897 if (request->requestvb->type == ASN_NULL || 02898 request->requestvb->type == ASN_PRIV_RETRY || 02899 (asp->reqinfo->mode == MODE_GETBULK 02900 && request->repeat > 0)) 02901 count++; 02902 } 02903 } 02904 return count; 02905 } 02906 02910 int 02911 handle_getnext_loop(netsnmp_agent_session *asp) 02912 { 02913 int status; 02914 netsnmp_variable_list *var_ptr; 02915 02916 /* 02917 * loop 02918 */ 02919 while (netsnmp_running) { 02920 02921 /* 02922 * bail for now if anything is delegated. 02923 */ 02924 if (netsnmp_check_for_delegated(asp)) { 02925 return SNMP_ERR_NOERROR; 02926 } 02927 02928 /* 02929 * check vacm against results 02930 */ 02931 check_acm(asp, ASN_PRIV_RETRY); 02932 02933 /* 02934 * need to keep going we're not done yet. 02935 */ 02936 if (!check_getnext_results(asp)) 02937 /* 02938 * nothing left, quit now 02939 */ 02940 break; 02941 02942 /* 02943 * never had a request (empty pdu), quit now 02944 */ 02945 /* 02946 * XXXWWW: huh? this would be too late, no? shouldn't we 02947 * catch this earlier? 02948 */ 02949 /* 02950 * if (count == 0) 02951 * break; 02952 */ 02953 02954 DEBUGIF("results") { 02955 DEBUGMSGTL(("results", 02956 "getnext results, before next pass:\n")); 02957 for (var_ptr = asp->pdu->variables; var_ptr; 02958 var_ptr = var_ptr->next_variable) { 02959 DEBUGMSGTL(("results", "\t")); 02960 DEBUGMSGVAR(("results", var_ptr)); 02961 DEBUGMSG(("results", "\n")); 02962 } 02963 } 02964 02965 netsnmp_reassign_requests(asp); 02966 status = handle_var_requests(asp); 02967 if (status != SNMP_ERR_NOERROR) { 02968 return status; /* should never really happen */ 02969 } 02970 } 02971 return SNMP_ERR_NOERROR; 02972 } 02973 02974 int 02975 handle_set(netsnmp_agent_session *asp) 02976 { 02977 int status; 02978 /* 02979 * SETS require 3-4 passes through the var_op_list. 02980 * The first two 02981 * passes verify that all types, lengths, and values are valid 02982 * and may reserve resources and the third does the set and a 02983 * fourth executes any actions. Then the identical GET RESPONSE 02984 * packet is returned. 02985 * If either of the first two passes returns an error, another 02986 * pass is made so that any reserved resources can be freed. 02987 * If the third pass returns an error, another pass is 02988 * made so that 02989 * any changes can be reversed. 02990 * If the fourth pass (or any of the error handling passes) 02991 * return an error, we'd rather not know about it! 02992 */ 02993 if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { 02994 switch (asp->mode) { 02995 case MODE_SET_BEGIN: 02996 snmp_increment_statistic(STAT_SNMPINSETREQUESTS); 02997 asp->rw = WRITE; /* WWW: still needed? */ 02998 asp->mode = MODE_SET_RESERVE1; 02999 asp->status = SNMP_ERR_NOERROR; 03000 break; 03001 03002 case MODE_SET_RESERVE1: 03003 03004 if (asp->status != SNMP_ERR_NOERROR) 03005 asp->mode = MODE_SET_FREE; 03006 else 03007 asp->mode = MODE_SET_RESERVE2; 03008 break; 03009 03010 case MODE_SET_RESERVE2: 03011 if (asp->status != SNMP_ERR_NOERROR) 03012 asp->mode = MODE_SET_FREE; 03013 else 03014 asp->mode = MODE_SET_ACTION; 03015 break; 03016 03017 case MODE_SET_ACTION: 03018 if (asp->status != SNMP_ERR_NOERROR) 03019 asp->mode = MODE_SET_UNDO; 03020 else 03021 asp->mode = MODE_SET_COMMIT; 03022 break; 03023 03024 case MODE_SET_COMMIT: 03025 if (asp->status != SNMP_ERR_NOERROR) { 03026 asp->mode = FINISHED_FAILURE; 03027 } else { 03028 asp->mode = FINISHED_SUCCESS; 03029 } 03030 break; 03031 03032 case MODE_SET_UNDO: 03033 asp->mode = FINISHED_FAILURE; 03034 break; 03035 03036 case MODE_SET_FREE: 03037 asp->mode = FINISHED_FAILURE; 03038 break; 03039 } 03040 } 03041 03042 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { 03043 DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode, 03044 se_find_label_in_slist("agent_mode", asp->mode))); 03045 status = handle_var_requests(asp); 03046 DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n", 03047 asp->mode, status)); 03048 if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) || 03049 status == SNMP_ERR_COMMITFAILED || 03050 status == SNMP_ERR_UNDOFAILED) { 03051 asp->status = status; 03052 } 03053 } 03054 return asp->status; 03055 } 03056 03057 int 03058 handle_set_loop(netsnmp_agent_session *asp) 03059 { 03060 while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) { 03061 handle_set(asp); 03062 if (netsnmp_check_for_delegated(asp)) { 03063 return SNMP_ERR_NOERROR; 03064 } 03065 if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) { 03066 return asp->status; 03067 } 03068 } 03069 return asp->status; 03070 } 03071 03072 int 03073 netsnmp_handle_request(netsnmp_agent_session *asp, int status) 03074 { 03075 /* 03076 * if this isn't a delegated request trying to finish, 03077 * processing of a set request should not start until all 03078 * delegated requests have completed, and no other new requests 03079 * should be processed until the set request completes. 03080 */ 03081 if ((0 == netsnmp_check_delegated_chain_for(asp)) && 03082 (asp != netsnmp_processing_set)) { 03083 /* 03084 * if we are processing a set and this is not a delegated 03085 * request, queue the request 03086 */ 03087 if (netsnmp_processing_set) { 03088 netsnmp_add_queued(asp); 03089 DEBUGMSGTL(("snmp_agent", 03090 "request queued while processing set, " 03091 "asp = %08p\n", asp)); 03092 return 1; 03093 } 03094 03095 /* 03096 * check for set request 03097 */ 03098 if (asp->pdu->command == SNMP_MSG_SET) { 03099 netsnmp_processing_set = asp; 03100 03101 /* 03102 * if there are delegated requests, we must wait for them 03103 * to finish. 03104 */ 03105 if (agent_delegated_list) { 03106 DEBUGMSGTL(("snmp_agent", "SET request queued while " 03107 "delegated requests finish, asp = %08p\n", 03108 asp)); 03109 netsnmp_add_queued(asp); 03110 return 1; 03111 } 03112 } 03113 } 03114 03115 /* 03116 * process the request 03117 */ 03118 status = handle_pdu(asp); 03119 03120 /* 03121 * print the results in appropriate debugging mode 03122 */ 03123 DEBUGIF("results") { 03124 netsnmp_variable_list *var_ptr; 03125 DEBUGMSGTL(("results", "request results (status = %d):\n", 03126 status)); 03127 for (var_ptr = asp->pdu->variables; var_ptr; 03128 var_ptr = var_ptr->next_variable) { 03129 DEBUGMSGTL(("results", "\t")); 03130 DEBUGMSGVAR(("results", var_ptr)); 03131 DEBUGMSG(("results", "\n")); 03132 } 03133 } 03134 03135 /* 03136 * check for uncompleted requests 03137 */ 03138 if (netsnmp_check_for_delegated_and_add(asp)) { 03139 /* 03140 * add to delegated request chain 03141 */ 03142 asp->status = status; 03143 } else { 03144 /* 03145 * if we don't have anything outstanding (delegated), wrap up 03146 */ 03147 return netsnmp_wrap_up_request(asp, status); 03148 } 03149 03150 return 1; 03151 } 03152 03204 int 03205 handle_pdu(netsnmp_agent_session *asp) 03206 { 03207 int status, inclusives = 0; 03208 netsnmp_variable_list *v = NULL; 03209 03210 /* 03211 * for illegal requests, mark all nodes as ASN_NULL 03212 */ 03213 switch (asp->pdu->command) { 03214 03215 case SNMP_MSG_INTERNAL_SET_RESERVE2: 03216 case SNMP_MSG_INTERNAL_SET_ACTION: 03217 case SNMP_MSG_INTERNAL_SET_COMMIT: 03218 case SNMP_MSG_INTERNAL_SET_FREE: 03219 case SNMP_MSG_INTERNAL_SET_UNDO: 03220 status = get_set_cache(asp); 03221 if (status != SNMP_ERR_NOERROR) 03222 return status; 03223 break; 03224 03225 case SNMP_MSG_GET: 03226 case SNMP_MSG_GETNEXT: 03227 case SNMP_MSG_GETBULK: 03228 for (v = asp->pdu->variables; v != NULL; v = v->next_variable) { 03229 if (v->type == ASN_PRIV_INCL_RANGE) { 03230 /* 03231 * Leave the type for now (it gets set to 03232 * ASN_NULL in netsnmp_add_varbind_to_cache, 03233 * called by create_subnetsnmp_tree_cache below). 03234 * If we set it to ASN_NULL now, we wouldn't be 03235 * able to distinguish INCLUSIVE search 03236 * ranges. 03237 */ 03238 inclusives++; 03239 } else { 03240 snmp_set_var_typed_value(v, ASN_NULL, NULL, 0); 03241 } 03242 } 03243 /* 03244 * fall through 03245 */ 03246 03247 case SNMP_MSG_INTERNAL_SET_BEGIN: 03248 case SNMP_MSG_INTERNAL_SET_RESERVE1: 03249 default: 03250 asp->vbcount = count_varbinds(asp->pdu->variables); 03251 if (asp->vbcount) /* efence doesn't like 0 size allocs */ 03252 asp->requests = (netsnmp_request_info *) 03253 calloc(asp->vbcount, sizeof(netsnmp_request_info)); 03254 /* 03255 * collect varbinds 03256 */ 03257 status = netsnmp_create_subtree_cache(asp); 03258 if (status != SNMP_ERR_NOERROR) 03259 return status; 03260 } 03261 03262 asp->mode = asp->pdu->command; 03263 switch (asp->mode) { 03264 case SNMP_MSG_GET: 03265 /* 03266 * increment the message type counter 03267 */ 03268 snmp_increment_statistic(STAT_SNMPINGETREQUESTS); 03269 03270 /* 03271 * check vacm ahead of time 03272 */ 03273 check_acm(asp, SNMP_NOSUCHOBJECT); 03274 03275 /* 03276 * get the results 03277 */ 03278 status = handle_var_requests(asp); 03279 03280 /* 03281 * Deal with unhandled results -> noSuchInstance (rather 03282 * than noSuchObject -- in that case, the type will 03283 * already have been set to noSuchObject when we realised 03284 * we couldn't find an appropriate tree). 03285 */ 03286 if (status == SNMP_ERR_NOERROR) 03287 snmp_replace_var_types(asp->pdu->variables, ASN_NULL, 03288 SNMP_NOSUCHINSTANCE); 03289 break; 03290 03291 case SNMP_MSG_GETNEXT: 03292 snmp_increment_statistic(STAT_SNMPINGETNEXTS); 03293 /* 03294 * fall through 03295 */ 03296 03297 case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */ 03298 /* 03299 * loop through our mib tree till we find an 03300 * appropriate response to return to the caller. 03301 */ 03302 03303 if (inclusives) { 03304 /* 03305 * This is a special case for AgentX INCLUSIVE getNext 03306 * requests where a result lexi-equal to the request is okay 03307 * but if such a result does not exist, we still want the 03308 * lexi-next one. So basically we do a GET first, and if any 03309 * of the INCLUSIVE requests are satisfied, we use that 03310 * value. Then, unsatisfied INCLUSIVE requests, and 03311 * non-INCLUSIVE requests get done as normal. 03312 */ 03313 03314 DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n")); 03315 asp->oldmode = asp->mode; 03316 asp->mode = SNMP_MSG_GET; 03317 } 03318 03319 /* 03320 * first pass 03321 */ 03322 status = handle_var_requests(asp); 03323 if (status != SNMP_ERR_NOERROR) { 03324 if (!inclusives) 03325 return status; /* should never really happen */ 03326 else 03327 asp->status = SNMP_ERR_NOERROR; 03328 } 03329 03330 /* 03331 * loop through our mib tree till we find an 03332 * appropriate response to return to the caller. 03333 */ 03334 03335 status = handle_getnext_loop(asp); 03336 break; 03337 03338 case SNMP_MSG_SET: 03339 #ifdef NETSNMP_DISABLE_SET_SUPPORT 03340 return SNMP_ERR_NOTWRITABLE; 03341 #else 03342 /* 03343 * check access permissions first 03344 */ 03345 if (check_acm(asp, SNMP_NOSUCHOBJECT)) 03346 return SNMP_ERR_NOTWRITABLE; 03347 03348 asp->mode = MODE_SET_BEGIN; 03349 status = handle_set_loop(asp); 03350 #endif 03351 break; 03352 03353 case SNMP_MSG_INTERNAL_SET_BEGIN: 03354 case SNMP_MSG_INTERNAL_SET_RESERVE1: 03355 case SNMP_MSG_INTERNAL_SET_RESERVE2: 03356 case SNMP_MSG_INTERNAL_SET_ACTION: 03357 case SNMP_MSG_INTERNAL_SET_COMMIT: 03358 case SNMP_MSG_INTERNAL_SET_FREE: 03359 case SNMP_MSG_INTERNAL_SET_UNDO: 03360 asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY; 03361 status = handle_set_loop(asp); 03362 /* 03363 * asp related cache is saved in cleanup 03364 */ 03365 break; 03366 03367 case SNMP_MSG_RESPONSE: 03368 snmp_increment_statistic(STAT_SNMPINGETRESPONSES); 03369 return SNMP_ERR_NOERROR; 03370 03371 case SNMP_MSG_TRAP: 03372 case SNMP_MSG_TRAP2: 03373 snmp_increment_statistic(STAT_SNMPINTRAPS); 03374 return SNMP_ERR_NOERROR; 03375 03376 default: 03377 /* 03378 * WWW: are reports counted somewhere ? 03379 */ 03380 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); 03381 return SNMPERR_GENERR; /* shouldn't get here */ 03382 /* 03383 * WWW 03384 */ 03385 } 03386 return status; 03387 } 03388 03392 NETSNMP_STATIC_INLINE int 03393 _request_set_error(netsnmp_request_info *request, int mode, int error_value) 03394 { 03395 if (!request) 03396 return SNMPERR_NO_VARS; 03397 03398 request->processed = 1; 03399 request->delegated = REQUEST_IS_NOT_DELEGATED; 03400 03401 switch (error_value) { 03402 case SNMP_NOSUCHOBJECT: 03403 case SNMP_NOSUCHINSTANCE: 03404 case SNMP_ENDOFMIBVIEW: 03405 /* 03406 * these are exceptions that should be put in the varbind 03407 * in the case of a GET but should be translated for a SET 03408 * into a real error status code and put in the request 03409 */ 03410 switch (mode) { 03411 case MODE_GET: 03412 case MODE_GETNEXT: 03413 case MODE_GETBULK: 03414 request->requestvb->type = error_value; 03415 return SNMPERR_SUCCESS; 03416 03417 /* 03418 * These are technically illegal to set by the 03419 * client APIs for these modes. But accepting 03420 * them here allows the 'sparse_table' helper to 03421 * provide some common table handling processing 03422 * 03423 snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n", 03424 error_value, mode); 03425 return SNMPERR_VALUE; 03426 */ 03427 03428 default: 03429 request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */ 03430 return SNMPERR_SUCCESS; 03431 } 03432 break; /* never get here */ 03433 03434 default: 03435 if (error_value < 0) { 03436 /* 03437 * illegal local error code. translate to generr 03438 */ 03439 /* 03440 * WWW: full translation map? 03441 */ 03442 snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n", 03443 error_value, SNMP_ERR_GENERR); 03444 request->status = SNMP_ERR_GENERR; 03445 } else { 03446 /* 03447 * WWW: translations and mode checking? 03448 */ 03449 request->status = error_value; 03450 } 03451 return SNMPERR_SUCCESS; 03452 } 03453 return SNMPERR_SUCCESS; 03454 } 03455 03460 int 03461 netsnmp_request_set_error(netsnmp_request_info *request, int error_value) 03462 { 03463 if (!request || !request->agent_req_info) 03464 return SNMPERR_NO_VARS; 03465 03466 return _request_set_error(request, request->agent_req_info->mode, 03467 error_value); 03468 } 03469 03475 int 03476 netsnmp_request_set_error_idx(netsnmp_request_info *request, 03477 int error_value, int idx) 03478 { 03479 int i; 03480 netsnmp_request_info *req = request; 03481 03482 if (!request || !request->agent_req_info) 03483 return SNMPERR_NO_VARS; 03484 03485 /* 03486 * Skip to the indicated varbind 03487 */ 03488 for ( i=2; i<idx; i++) { 03489 req = req->next; 03490 if (!req) 03491 return SNMPERR_NO_VARS; 03492 } 03493 03494 return _request_set_error(req, request->agent_req_info->mode, 03495 error_value); 03496 } 03497 03503 NETSNMP_INLINE int 03504 netsnmp_request_set_error_all( netsnmp_request_info *requests, int error) 03505 { 03506 int mode, rc, result = SNMPERR_SUCCESS; 03507 03508 if((NULL == requests) || (NULL == requests->agent_req_info)) 03509 return SNMPERR_NO_VARS; 03510 03511 mode = requests->agent_req_info->mode; /* every req has same mode */ 03512 03513 for(; requests ; requests = requests->next) { 03514 03516 netsnmp_assert(NULL != requests->agent_req_info); 03517 netsnmp_assert(mode == requests->agent_req_info->mode); 03518 03519 /* 03520 * set error for this request. Log any errors, save the last 03521 * to return to the user. 03522 */ 03523 if((rc = _request_set_error(requests, mode, error))) { 03524 snmp_log(LOG_WARNING,"got %d while setting request error\n", rc); 03525 result = rc; 03526 } 03527 } 03528 return result; 03529 } 03530 03531 extern struct timeval starttime; 03532 03533 /* 03534 * Return the value of 'sysUpTime' at the given marker 03535 */ 03536 u_long 03537 netsnmp_marker_uptime(marker_t pm) 03538 { 03539 u_long res; 03540 marker_t start = (marker_t) & starttime; 03541 03542 res = uatime_hdiff(start, pm); 03543 return res; /* atime_diff works in msec, not csec */ 03544 } 03545 03546 /* 03547 * struct timeval equivalents of these 03548 */ 03549 u_long 03550 netsnmp_timeval_uptime(struct timeval * tv) 03551 { 03552 return netsnmp_marker_uptime((marker_t) tv); 03553 } 03554 03555 /* 03556 * Return the current value of 'sysUpTime' 03557 */ 03558 u_long 03559 netsnmp_get_agent_uptime(void) 03560 { 03561 struct timeval now; 03562 gettimeofday(&now, NULL); 03563 03564 return netsnmp_timeval_uptime(&now); 03565 } 03566 03567 03568 03569 NETSNMP_INLINE void 03570 netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari, 03571 netsnmp_data_list *node) 03572 { 03573 if (ari) { 03574 if (ari->agent_data) { 03575 netsnmp_add_list_data(&ari->agent_data, node); 03576 } else { 03577 ari->agent_data = node; 03578 } 03579 } 03580 } 03581 03582 NETSNMP_INLINE int 03583 netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari, 03584 const char * name) 03585 { 03586 if ((NULL == ari) || (NULL == ari->agent_data)) 03587 return 1; 03588 03589 return netsnmp_remove_list_node(&ari->agent_data, name); 03590 } 03591 03592 NETSNMP_INLINE void * 03593 netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari, 03594 const char *name) 03595 { 03596 if (ari) { 03597 return netsnmp_get_list_data(ari->agent_data, name); 03598 } 03599 return NULL; 03600 } 03601 03602 NETSNMP_INLINE void 03603 netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari) 03604 { 03605 if (ari) { 03606 netsnmp_free_list_data(ari->agent_data); 03607 } 03608 } 03609 03610 NETSNMP_INLINE void 03611 netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari) 03612 { 03613 if (ari) { 03614 netsnmp_free_all_list_data(ari->agent_data); 03615 } 03616 } 03617 03618 NETSNMP_INLINE void 03619 netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari) 03620 { 03621 if (ari) { 03622 if (ari->agent_data) { 03623 netsnmp_free_all_list_data(ari->agent_data); 03624 } 03625 SNMP_FREE(ari); 03626 } 03627 } 03628 03629 /************************************************************************* 03630 * 03631 * deprecated functions 03632 * 03633 */ 03634 03642 int 03643 netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo, 03644 netsnmp_request_info *request, int error_value) 03645 { 03646 if (!request || !reqinfo) 03647 return error_value; 03648 03649 _request_set_error(request, reqinfo->mode, error_value); 03650 03651 return error_value; 03652 } 03653 03661 int 03662 netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request, 03663 int error_value) 03664 { 03665 _request_set_error(request, mode, error_value); 03666 03667 return error_value; 03668 } 03669 03677 int 03678 netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo, 03679 netsnmp_request_info *requests, 03680 int error_value) 03681 { 03682 netsnmp_request_set_error_all(requests, error_value); 03683 return error_value; 03684 }