|
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 asp->flags = SNMP_AGENT_FLAGS_NONE; 01290 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n", 01291 asp, asp->reqinfo)); 01292 01293 return asp; 01294 } 01295 01296 void 01297 free_agent_snmp_session(netsnmp_agent_session *asp) 01298 { 01299 if (!asp) 01300 return; 01301 01302 DEBUGMSGTL(("snmp_agent","agent_session %08p released\n", asp)); 01303 01304 netsnmp_remove_from_delegated(asp); 01305 01306 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n", 01307 asp, asp->reqinfo)); 01308 if (asp->orig_pdu) 01309 snmp_free_pdu(asp->orig_pdu); 01310 if (asp->pdu) 01311 snmp_free_pdu(asp->pdu); 01312 if (asp->reqinfo) 01313 netsnmp_free_agent_request_info(asp->reqinfo); 01314 if (asp->treecache) { 01315 SNMP_FREE(asp->treecache); 01316 } 01317 if (asp->bulkcache) { 01318 SNMP_FREE(asp->bulkcache); 01319 } 01320 if (asp->requests) { 01321 int i; 01322 for (i = 0; i < asp->vbcount; i++) { 01323 netsnmp_free_request_data_sets(&asp->requests[i]); 01324 } 01325 SNMP_FREE(asp->requests); 01326 } 01327 if (asp->cache_store) { 01328 netsnmp_free_cachemap(asp->cache_store); 01329 asp->cache_store = NULL; 01330 } 01331 SNMP_FREE(asp); 01332 } 01333 01334 int 01335 netsnmp_check_for_delegated(netsnmp_agent_session *asp) 01336 { 01337 int i; 01338 netsnmp_request_info *request; 01339 01340 if (NULL == asp->treecache) 01341 return 0; 01342 01343 if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) 01344 return 0; 01345 01346 for (i = 0; i <= asp->treecache_num; i++) { 01347 for (request = asp->treecache[i].requests_begin; request; 01348 request = request->next) { 01349 if (request->delegated) 01350 return 1; 01351 } 01352 } 01353 return 0; 01354 } 01355 01356 int 01357 netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp) 01358 { 01359 netsnmp_agent_session *asptmp; 01360 for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) { 01361 if (asptmp == asp) 01362 return 1; 01363 } 01364 return 0; 01365 } 01366 01367 int 01368 netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp) 01369 { 01370 if (netsnmp_check_for_delegated(asp)) { 01371 if (!netsnmp_check_delegated_chain_for(asp)) { 01372 /* 01373 * add to delegated request chain 01374 */ 01375 asp->next = agent_delegated_list; 01376 agent_delegated_list = asp; 01377 DEBUGMSGTL(("snmp_agent", "delegate session == %08p\n", asp)); 01378 } 01379 return 1; 01380 } 01381 return 0; 01382 } 01383 01384 int 01385 netsnmp_remove_from_delegated(netsnmp_agent_session *asp) 01386 { 01387 netsnmp_agent_session *curr, *prev = NULL; 01388 01389 for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) { 01390 /* 01391 * is this us? 01392 */ 01393 if (curr != asp) 01394 continue; 01395 01396 /* 01397 * remove from queue 01398 */ 01399 if (prev != NULL) 01400 prev->next = asp->next; 01401 else 01402 agent_delegated_list = asp->next; 01403 01404 DEBUGMSGTL(("snmp_agent", "remove delegated session == %08p\n", asp)); 01405 01406 return 1; 01407 } 01408 01409 return 0; 01410 } 01411 01412 /* 01413 * netsnmp_remove_delegated_requests_for_session 01414 * 01415 * called when a session is being closed. Check all delegated requests to 01416 * see if the are waiting on this session, and if set, set the status for 01417 * that request to GENERR. 01418 */ 01419 int 01420 netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess) 01421 { 01422 netsnmp_agent_session *asp; 01423 int total_count = 0; 01424 01425 for (asp = agent_delegated_list; asp; asp = asp->next) { 01426 /* 01427 * check each request 01428 */ 01429 int i; 01430 int count = 0; 01431 netsnmp_request_info *request; 01432 for (i = 0; i <= asp->treecache_num; i++) { 01433 for (request = asp->treecache[i].requests_begin; request; 01434 request = request->next) { 01435 /* 01436 * check session 01437 */ 01438 netsnmp_assert(NULL!=request->subtree); 01439 if(request->subtree->session != sess) 01440 continue; 01441 01442 /* 01443 * matched! mark request as done 01444 */ 01445 netsnmp_request_set_error(request, SNMP_ERR_GENERR); 01446 ++count; 01447 } 01448 } 01449 if (count) { 01450 asp->flags |= SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS; 01451 total_count += count; 01452 } 01453 } 01454 01455 /* 01456 * if we found any, that request may be finished now 01457 */ 01458 if(total_count) { 01459 DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session " 01460 "%08p\n", total_count, sess)); 01461 netsnmp_check_delegated_requests(); 01462 } 01463 01464 return total_count; 01465 } 01466 01467 int 01468 netsnmp_check_queued_chain_for(netsnmp_agent_session *asp) 01469 { 01470 netsnmp_agent_session *asptmp; 01471 for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) { 01472 if (asptmp == asp) 01473 return 1; 01474 } 01475 return 0; 01476 } 01477 01478 int 01479 netsnmp_add_queued(netsnmp_agent_session *asp) 01480 { 01481 netsnmp_agent_session *asp_tmp; 01482 01483 /* 01484 * first item? 01485 */ 01486 if (NULL == netsnmp_agent_queued_list) { 01487 netsnmp_agent_queued_list = asp; 01488 return 1; 01489 } 01490 01491 01492 /* 01493 * add to end of queued request chain 01494 */ 01495 asp_tmp = netsnmp_agent_queued_list; 01496 for (; asp_tmp; asp_tmp = asp_tmp->next) { 01497 /* 01498 * already in queue? 01499 */ 01500 if (asp_tmp == asp) 01501 break; 01502 01503 /* 01504 * end of queue? 01505 */ 01506 if (NULL == asp_tmp->next) 01507 asp_tmp->next = asp; 01508 } 01509 return 1; 01510 } 01511 01512 01513 int 01514 netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status) 01515 { 01516 netsnmp_variable_list *var_ptr; 01517 int i; 01518 01519 /* 01520 * if this request was a set, clear the global now that we are 01521 * done. 01522 */ 01523 if (asp == netsnmp_processing_set) { 01524 DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %08p\n", 01525 asp)); 01526 netsnmp_processing_set = NULL; 01527 } 01528 01529 if (asp->pdu) { 01530 /* 01531 * If we've got an error status, then this needs to be 01532 * passed back up to the higher levels.... 01533 */ 01534 if ( status != 0 && asp->status == 0 ) 01535 asp->status = status; 01536 01537 switch (asp->pdu->command) { 01538 case SNMP_MSG_INTERNAL_SET_BEGIN: 01539 case SNMP_MSG_INTERNAL_SET_RESERVE1: 01540 case SNMP_MSG_INTERNAL_SET_RESERVE2: 01541 case SNMP_MSG_INTERNAL_SET_ACTION: 01542 /* 01543 * some stuff needs to be saved in special subagent cases 01544 */ 01545 save_set_cache(asp); 01546 break; 01547 01548 case SNMP_MSG_GETNEXT: 01549 _fix_endofmibview(asp); 01550 break; 01551 01552 case SNMP_MSG_GETBULK: 01553 /* 01554 * for a GETBULK response we need to rearrange the varbinds 01555 */ 01556 _reorder_getbulk(asp); 01557 break; 01558 } 01559 01560 /* 01561 * May need to "dumb down" a SET error status for a 01562 * v1 query. See RFC2576 - section 4.3 01563 */ 01564 #ifndef NETSNMP_DISABLE_SNMPV1 01565 if ((asp->pdu->command == SNMP_MSG_SET) && 01566 (asp->pdu->version == SNMP_VERSION_1)) { 01567 switch (asp->status) { 01568 case SNMP_ERR_WRONGVALUE: 01569 case SNMP_ERR_WRONGENCODING: 01570 case SNMP_ERR_WRONGTYPE: 01571 case SNMP_ERR_WRONGLENGTH: 01572 case SNMP_ERR_INCONSISTENTVALUE: 01573 status = SNMP_ERR_BADVALUE; 01574 asp->status = SNMP_ERR_BADVALUE; 01575 break; 01576 case SNMP_ERR_NOACCESS: 01577 case SNMP_ERR_NOTWRITABLE: 01578 case SNMP_ERR_NOCREATION: 01579 case SNMP_ERR_INCONSISTENTNAME: 01580 case SNMP_ERR_AUTHORIZATIONERROR: 01581 status = SNMP_ERR_NOSUCHNAME; 01582 asp->status = SNMP_ERR_NOSUCHNAME; 01583 break; 01584 case SNMP_ERR_RESOURCEUNAVAILABLE: 01585 case SNMP_ERR_COMMITFAILED: 01586 case SNMP_ERR_UNDOFAILED: 01587 status = SNMP_ERR_GENERR; 01588 asp->status = SNMP_ERR_GENERR; 01589 break; 01590 } 01591 } 01592 /* 01593 * Similarly we may need to "dumb down" v2 exception 01594 * types to throw an error for a v1 query. 01595 * See RFC2576 - section 4.1.2.3 01596 */ 01597 if ((asp->pdu->command != SNMP_MSG_SET) && 01598 (asp->pdu->version == SNMP_VERSION_1)) { 01599 for (var_ptr = asp->pdu->variables, i = 1; 01600 var_ptr != NULL; var_ptr = var_ptr->next_variable, i++) { 01601 switch (var_ptr->type) { 01602 case SNMP_NOSUCHOBJECT: 01603 case SNMP_NOSUCHINSTANCE: 01604 case SNMP_ENDOFMIBVIEW: 01605 case ASN_COUNTER64: 01606 status = SNMP_ERR_NOSUCHNAME; 01607 asp->status = SNMP_ERR_NOSUCHNAME; 01608 asp->index = i; 01609 break; 01610 } 01611 } 01612 } 01613 #endif /* snmpv1 support */ 01614 } 01616 /* 01617 * Update the snmp error-count statistics 01618 * XXX - should we include the V2 errors in this or not? 01619 */ 01620 #define INCLUDE_V2ERRORS_IN_V1STATS 01621 01622 switch (status) { 01623 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01624 case SNMP_ERR_WRONGVALUE: 01625 case SNMP_ERR_WRONGENCODING: 01626 case SNMP_ERR_WRONGTYPE: 01627 case SNMP_ERR_WRONGLENGTH: 01628 case SNMP_ERR_INCONSISTENTVALUE: 01629 #endif 01630 case SNMP_ERR_BADVALUE: 01631 snmp_increment_statistic(STAT_SNMPOUTBADVALUES); 01632 break; 01633 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01634 case SNMP_ERR_NOACCESS: 01635 case SNMP_ERR_NOTWRITABLE: 01636 case SNMP_ERR_NOCREATION: 01637 case SNMP_ERR_INCONSISTENTNAME: 01638 case SNMP_ERR_AUTHORIZATIONERROR: 01639 #endif 01640 case SNMP_ERR_NOSUCHNAME: 01641 snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES); 01642 break; 01643 #ifdef INCLUDE_V2ERRORS_IN_V1STATS 01644 case SNMP_ERR_RESOURCEUNAVAILABLE: 01645 case SNMP_ERR_COMMITFAILED: 01646 case SNMP_ERR_UNDOFAILED: 01647 #endif 01648 case SNMP_ERR_GENERR: 01649 snmp_increment_statistic(STAT_SNMPOUTGENERRS); 01650 break; 01651 01652 case SNMP_ERR_TOOBIG: 01653 snmp_increment_statistic(STAT_SNMPOUTTOOBIGS); 01654 break; 01655 } 01656 01657 if ((status == SNMP_ERR_NOERROR) && (asp->pdu)) { 01658 snmp_increment_statistic_by((asp->pdu->command == SNMP_MSG_SET ? 01659 STAT_SNMPINTOTALSETVARS : 01660 STAT_SNMPINTOTALREQVARS), 01661 count_varbinds(asp->pdu->variables)); 01662 } else { 01663 /* 01664 * Use a copy of the original request 01665 * to report failures. 01666 */ 01667 snmp_free_pdu(asp->pdu); 01668 asp->pdu = asp->orig_pdu; 01669 asp->orig_pdu = NULL; 01670 } 01671 if (asp->pdu) { 01672 asp->pdu->command = SNMP_MSG_RESPONSE; 01673 asp->pdu->errstat = asp->status; 01674 asp->pdu->errindex = asp->index; 01675 if (!snmp_send(asp->session, asp->pdu)) { 01676 netsnmp_variable_list *var_ptr; 01677 snmp_perror("send response"); 01678 for (var_ptr = asp->pdu->variables; var_ptr != NULL; 01679 var_ptr = var_ptr->next_variable) { 01680 size_t c_oidlen = 256, c_outlen = 0; 01681 u_char *c_oid = (u_char *) malloc(c_oidlen); 01682 01683 if (c_oid) { 01684 if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1, 01685 var_ptr->name, 01686 var_ptr->name_length)) { 01687 snmp_log(LOG_ERR, " -- %s [TRUNCATED]\n", c_oid); 01688 } else { 01689 snmp_log(LOG_ERR, " -- %s\n", c_oid); 01690 } 01691 SNMP_FREE(c_oid); 01692 } 01693 } 01694 snmp_free_pdu(asp->pdu); 01695 asp->pdu = NULL; 01696 } 01697 snmp_increment_statistic(STAT_SNMPOUTPKTS); 01698 snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES); 01699 asp->pdu = NULL; /* yyy-rks: redundant, no? */ 01700 netsnmp_remove_and_free_agent_snmp_session(asp); 01701 } 01702 return 1; 01703 } 01704 01705 void 01706 dump_sess_list(void) 01707 { 01708 netsnmp_agent_session *a; 01709 01710 DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> ")); 01711 for (a = agent_session_list; a != NULL; a = a->next) { 01712 DEBUGMSG(("snmp_agent", "%08p[session %08p] -> ", a, a->session)); 01713 } 01714 DEBUGMSG(("snmp_agent", "[NIL]\n")); 01715 } 01716 01717 void 01718 netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp) 01719 { 01720 netsnmp_agent_session *a, **prevNext = &agent_session_list; 01721 01722 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", asp)); 01723 01724 for (a = agent_session_list; a != NULL; a = *prevNext) { 01725 if (a == asp) { 01726 *prevNext = a->next; 01727 a->next = NULL; 01728 free_agent_snmp_session(a); 01729 asp = NULL; 01730 break; 01731 } else { 01732 prevNext = &(a->next); 01733 } 01734 } 01735 01736 if (a == NULL && asp != NULL) { 01737 /* 01738 * We coulnd't find it on the list, so free it anyway. 01739 */ 01740 free_agent_snmp_session(asp); 01741 } 01742 } 01743 01744 void 01745 netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess, 01746 void (*free_request) 01747 (netsnmp_request_list *)) 01748 { 01749 netsnmp_agent_session *a, *next, **prevNext = &agent_session_list; 01750 01751 DEBUGMSGTL(("snmp_agent", "REMOVE session == %08p\n", sess)); 01752 01753 for (a = agent_session_list; a != NULL; a = next) { 01754 if (a->session == sess) { 01755 *prevNext = a->next; 01756 next = a->next; 01757 free_agent_snmp_session(a); 01758 } else { 01759 prevNext = &(a->next); 01760 next = a->next; 01761 } 01762 } 01763 } 01764 01766 int 01767 handle_snmp_packet(int op, netsnmp_session * session, int reqid, 01768 netsnmp_pdu *pdu, void *magic) 01769 { 01770 netsnmp_agent_session *asp; 01771 int status, access_ret, rc; 01772 01773 /* 01774 * We only support receiving here. 01775 */ 01776 if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) { 01777 return 1; 01778 } 01779 01780 /* 01781 * RESPONSE messages won't get this far, but TRAP-like messages 01782 * might. 01783 */ 01784 if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM || 01785 pdu->command == SNMP_MSG_TRAP2) { 01786 DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n", 01787 pdu->command)); 01788 pdu->command = SNMP_MSG_TRAP2; 01789 snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS); 01790 return 1; 01791 } 01792 01793 /* 01794 * send snmpv3 authfail trap. 01795 */ 01796 if (pdu->version == SNMP_VERSION_3 && 01797 session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) { 01798 send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); 01799 return 1; 01800 } 01801 01802 if (magic == NULL) { 01803 asp = init_agent_snmp_session(session, pdu); 01804 status = SNMP_ERR_NOERROR; 01805 } else { 01806 asp = (netsnmp_agent_session *) magic; 01807 status = asp->status; 01808 } 01809 01810 if ((access_ret = check_access(asp->pdu)) != 0) { 01811 if (access_ret == VACM_NOSUCHCONTEXT) { 01812 /* 01813 * rfc3413 section 3.2, step 5 says that we increment the 01814 * counter but don't return a response of any kind 01815 */ 01816 01817 /* 01818 * we currently don't support unavailable contexts, as 01819 * there is no reason to that I currently know of 01820 */ 01821 snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS); 01822 01823 /* 01824 * drop the request 01825 */ 01826 netsnmp_remove_and_free_agent_snmp_session(asp); 01827 return 0; 01828 } else { 01829 /* 01830 * access control setup is incorrect 01831 */ 01832 send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); 01833 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01834 #if defined(NETSNMP_DISABLE_SNMPV1) 01835 if (asp->pdu->version != SNMP_VERSION_2c) { 01836 #else 01837 #if defined(NETSNMP_DISABLE_SNMPV2C) 01838 if (asp->pdu->version != SNMP_VERSION_1) { 01839 #else 01840 if (asp->pdu->version != SNMP_VERSION_1 01841 && asp->pdu->version != SNMP_VERSION_2c) { 01842 #endif 01843 #endif 01844 asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR; 01845 asp->pdu->command = SNMP_MSG_RESPONSE; 01846 snmp_increment_statistic(STAT_SNMPOUTPKTS); 01847 if (!snmp_send(asp->session, asp->pdu)) 01848 snmp_free_pdu(asp->pdu); 01849 asp->pdu = NULL; 01850 netsnmp_remove_and_free_agent_snmp_session(asp); 01851 return 1; 01852 } else { 01853 #endif /* support for community based SNMP */ 01854 /* 01855 * drop the request 01856 */ 01857 netsnmp_remove_and_free_agent_snmp_session(asp); 01858 return 0; 01859 #if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) 01860 } 01861 #endif /* support for community based SNMP */ 01862 } 01863 } 01864 01865 rc = netsnmp_handle_request(asp, status); 01866 01867 /* 01868 * done 01869 */ 01870 DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %08p\n", 01871 asp)); 01872 return rc; 01873 } 01874 01875 netsnmp_request_info * 01876 netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount, 01877 netsnmp_variable_list * varbind_ptr, 01878 netsnmp_subtree *tp) 01879 { 01880 netsnmp_request_info *request = NULL; 01881 int cacheid; 01882 01883 DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount)); 01884 DEBUGMSGOID(("snmp_agent", varbind_ptr->name, 01885 varbind_ptr->name_length)); 01886 DEBUGMSG(("snmp_agent", ", %8p)\n", tp)); 01887 01888 if (tp && 01889 (asp->pdu->command == SNMP_MSG_GETNEXT || 01890 asp->pdu->command == SNMP_MSG_GETBULK)) { 01891 int result; 01892 int prefix_len; 01893 01894 prefix_len = netsnmp_oid_find_prefix(tp->start_a, 01895 tp->start_len, 01896 tp->end_a, tp->end_len); 01897 if (prefix_len < 1) { 01898 result = VACM_NOTINVIEW; /* ack... bad bad thing happened */ 01899 } else { 01900 result = 01901 netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len); 01902 } 01903 01904 while (result == VACM_NOTINVIEW) { 01905 /* the entire subtree is not in view. Skip it. */ 01913 tp = tp->next; 01914 if (tp) { 01915 prefix_len = netsnmp_oid_find_prefix(tp->start_a, 01916 tp->start_len, 01917 tp->end_a, 01918 tp->end_len); 01919 if (prefix_len < 1) { 01920 /* ack... bad bad thing happened */ 01921 result = VACM_NOTINVIEW; 01922 } else { 01923 result = 01924 netsnmp_acm_check_subtree(asp->pdu, 01925 tp->start_a, prefix_len); 01926 } 01927 } 01928 else 01929 break; 01930 } 01931 } 01932 if (tp == NULL) { 01933 /* 01934 * no appropriate registration found 01935 */ 01936 /* 01937 * make up the response ourselves 01938 */ 01939 switch (asp->pdu->command) { 01940 case SNMP_MSG_GETNEXT: 01941 case SNMP_MSG_GETBULK: 01942 varbind_ptr->type = SNMP_ENDOFMIBVIEW; 01943 break; 01944 01945 case SNMP_MSG_SET: 01946 case SNMP_MSG_GET: 01947 varbind_ptr->type = SNMP_NOSUCHOBJECT; 01948 break; 01949 01950 default: 01951 return NULL; /* shouldn't get here */ 01952 } 01953 } else { 01954 DEBUGMSGTL(("snmp_agent", "tp->start ")); 01955 DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len)); 01956 DEBUGMSG(("snmp_agent", ", tp->end ")); 01957 DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len)); 01958 DEBUGMSG(("snmp_agent", ", \n")); 01959 01960 /* 01961 * malloc the request structure 01962 */ 01963 request = &(asp->requests[vbcount - 1]); 01964 request->index = vbcount; 01965 request->delegated = 0; 01966 request->processed = 0; 01967 request->status = 0; 01968 request->subtree = tp; 01969 request->agent_req_info = asp->reqinfo; 01970 if (request->parent_data) { 01971 netsnmp_free_request_data_sets(request); 01972 } 01973 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", 01974 asp, asp->reqinfo)); 01975 01976 /* 01977 * for non-SET modes, set the type to NULL 01978 */ 01979 if (!MODE_IS_SET(asp->pdu->command)) { 01980 DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n", 01981 asp, asp->reqinfo)); 01982 if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) { 01983 DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n", 01984 request->index)); 01985 request->inclusive = 1; 01986 } 01987 varbind_ptr->type = ASN_NULL; 01988 } 01989 01990 /* 01991 * place them in a cache 01992 */ 01993 if (tp->global_cacheid) { 01994 /* 01995 * we need to merge all marked subtrees together 01996 */ 01997 if (asp->cache_store && -1 != 01998 (cacheid = netsnmp_get_local_cachid(asp->cache_store, 01999 tp->global_cacheid))) { 02000 } else { 02001 cacheid = ++(asp->treecache_num); 02002 netsnmp_get_or_add_local_cachid(&asp->cache_store, 02003 tp->global_cacheid, 02004 cacheid); 02005 goto mallocslot; /* XXX: ick */ 02006 } 02007 } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num && 02008 asp->treecache[tp->cacheid].subtree == tp) { 02009 /* 02010 * we have already added a request to this tree 02011 * pointer before 02012 */ 02013 cacheid = tp->cacheid; 02014 } else { 02015 cacheid = ++(asp->treecache_num); 02016 mallocslot: 02017 /* 02018 * new slot needed 02019 */ 02020 if (asp->treecache_num >= asp->treecache_len) { 02021 /* 02022 * exapand cache array 02023 */ 02024 /* 02025 * WWW: non-linear expansion needed (with cap) 02026 */ 02027 #define CACHE_GROW_SIZE 16 02028 asp->treecache_len = 02029 (asp->treecache_len + CACHE_GROW_SIZE); 02030 asp->treecache = 02031 realloc(asp->treecache, 02032 sizeof(netsnmp_tree_cache) * 02033 asp->treecache_len); 02034 if (asp->treecache == NULL) 02035 return NULL; 02036 memset(&(asp->treecache[cacheid]), 0x00, 02037 sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE)); 02038 } 02039 asp->treecache[cacheid].subtree = tp; 02040 asp->treecache[cacheid].requests_begin = request; 02041 tp->cacheid = cacheid; 02042 } 02043 02044 /* 02045 * if this is a search type, get the ending range oid as well 02046 */ 02047 if (asp->pdu->command == SNMP_MSG_GETNEXT || 02048 asp->pdu->command == SNMP_MSG_GETBULK) { 02049 request->range_end = tp->end_a; 02050 request->range_end_len = tp->end_len; 02051 } else { 02052 request->range_end = NULL; 02053 request->range_end_len = 0; 02054 } 02055 02056 /* 02057 * link into chain 02058 */ 02059 if (asp->treecache[cacheid].requests_end) 02060 asp->treecache[cacheid].requests_end->next = request; 02061 request->next = NULL; 02062 request->prev = asp->treecache[cacheid].requests_end; 02063 asp->treecache[cacheid].requests_end = request; 02064 02065 /* 02066 * add the given request to the list of requests they need 02067 * to handle results for 02068 */ 02069 request->requestvb = request->requestvb_start = varbind_ptr; 02070 } 02071 return request; 02072 } 02073 02074 /* 02075 * check the ACM(s) for the results on each of the varbinds. 02076 * If ACM disallows it, replace the value with type 02077 * 02078 * Returns number of varbinds with ACM errors 02079 */ 02080 int 02081 check_acm(netsnmp_agent_session *asp, u_char type) 02082 { 02083 int view; 02084 int i, j, k; 02085 netsnmp_request_info *request; 02086 int ret = 0; 02087 netsnmp_variable_list *vb, *vb2, *vbc; 02088 int earliest = 0; 02089 02090 for (i = 0; i <= asp->treecache_num; i++) { 02091 for (request = asp->treecache[i].requests_begin; 02092 request; request = request->next) { 02093 /* 02094 * for each request, run it through in_a_view() 02095 */ 02096 earliest = 0; 02097 for(j = request->repeat, vb = request->requestvb_start; 02098 vb && j > -1; 02099 j--, vb = vb->next_variable) { 02100 if (vb->type != ASN_NULL && 02101 vb->type != ASN_PRIV_RETRY) { /* not yet processed */ 02102 view = 02103 in_a_view(vb->name, &vb->name_length, 02104 asp->pdu, vb->type); 02105 02106 /* 02107 * if a ACM error occurs, mark it as type passed in 02108 */ 02109 if (view != VACM_SUCCESS) { 02110 ret++; 02111 if (request->repeat < request->orig_repeat) { 02112 /* basically this means a GETBULK */ 02113 request->repeat++; 02114 if (!earliest) { 02115 request->requestvb = vb; 02116 earliest = 1; 02117 } 02118 02119 /* ugh. if a whole now exists, we need to 02120 move the contents up the chain and fill 02121 in at the end else we won't end up 02122 lexographically sorted properly */ 02123 if (j > -1 && vb->next_variable && 02124 vb->next_variable->type != ASN_NULL && 02125 vb->next_variable->type != ASN_PRIV_RETRY) { 02126 for(k = j, vbc = vb, vb2 = vb->next_variable; 02127 k > -2 && vbc && vb2; 02128 k--, vbc = vb2, vb2 = vb2->next_variable) { 02129 /* clone next into the current */ 02130 snmp_clone_var(vb2, vbc); 02131 vbc->next_variable = vb2; 02132 } 02133 } 02134 } 02135 snmp_set_var_typed_value(vb, type, NULL, 0); 02136 } 02137 } 02138 } 02139 } 02140 } 02141 return ret; 02142 } 02143 02144 02145 int 02146 netsnmp_create_subtree_cache(netsnmp_agent_session *asp) 02147 { 02148 netsnmp_subtree *tp; 02149 netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext; 02150 int view; 02151 int vbcount = 0; 02152 int bulkcount = 0, bulkrep = 0; 02153 int i = 0, n = 0, r = 0; 02154 netsnmp_request_info *request; 02155 02156 if (asp->treecache == NULL && asp->treecache_len == 0) { 02157 asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16); 02158 asp->treecache = 02159 calloc(asp->treecache_len, sizeof(netsnmp_tree_cache)); 02160 if (asp->treecache == NULL) 02161 return SNMP_ERR_GENERR; 02162 } 02163 asp->treecache_num = -1; 02164 02165 if (asp->pdu->command == SNMP_MSG_GETBULK) { 02166 /* 02167 * getbulk prep 02168 */ 02169 int count = count_varbinds(asp->pdu->variables); 02170 if (asp->pdu->errstat < 0) { 02171 asp->pdu->errstat = 0; 02172 } 02173 if (asp->pdu->errindex < 0) { 02174 asp->pdu->errindex = 0; 02175 } 02176 02177 if (asp->pdu->errstat < count) { 02178 n = asp->pdu->errstat; 02179 } else { 02180 n = count; 02181 } 02182 if ((r = count - n) <= 0) { 02183 r = 0; 02184 asp->bulkcache = NULL; 02185 } else { 02186 int numresponses; 02187 int maxbulk = 02188 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 02189 NETSNMP_DS_AGENT_MAX_GETBULKREPEATS); 02190 int maxresponses = 02191 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 02192 NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES); 02193 02194 if (maxresponses == 0) 02195 maxresponses = 100; /* more than reasonable default */ 02196 02197 if (maxbulk == 0) 02198 maxbulk = -1; 02199 02200 /* limit getbulk number of repeats to a configured size */ 02201 if (asp->pdu->errindex > maxbulk && maxbulk != -1) { 02202 asp->pdu->errindex = maxbulk; 02203 } 02204 02205 numresponses = asp->pdu->errindex * r; 02206 02207 /* limit getbulk number of getbulk responses to a configured size */ 02208 if (maxresponses != -1 && numresponses > maxresponses) { 02209 /* attempt to truncate this */ 02210 asp->pdu->errindex = maxresponses/r; 02211 numresponses = asp->pdu->errindex * r; 02212 DEBUGMSGTL(("snmp_agent", "truncating number of getbulk repeats to %d\n", asp->pdu->errindex)); 02213 } 02214 02215 asp->bulkcache = 02216 (netsnmp_variable_list **) malloc(numresponses * 02217 sizeof(struct 02218 varbind_list *)); 02219 if (!asp->bulkcache) { 02220 DEBUGMSGTL(("snmp_agent", "Bulkcache malloc failed\n")); 02221 return SNMP_ERR_GENERR; 02222 } 02223 } 02224 DEBUGMSGTL(("snmp_agent", "GETBULK N = %d, M = %d, R = %d\n", 02225 n, asp->pdu->errindex, r)); 02226 } 02227 02228 /* 02229 * collect varbinds into their registered trees 02230 */ 02231 prevNext = &(asp->pdu->variables); 02232 for (varbind_ptr = asp->pdu->variables; varbind_ptr; 02233 varbind_ptr = vbsave) { 02234 02235 /* 02236 * getbulk mess with this pointer, so save it 02237 */ 02238 vbsave = varbind_ptr->next_variable; 02239 02240 if (asp->pdu->command == SNMP_MSG_GETBULK) { 02241 if (n > 0) { 02242 n--; 02243 } else { 02244 /* 02245 * repeate request varbinds on GETBULK. These will 02246 * have to be properly rearranged later though as 02247 * responses are supposed to actually be interlaced 02248 * with each other. This is done with the asp->bulkcache. 02249 */ 02250 bulkrep = asp->pdu->errindex - 1; 02251 if (asp->pdu->errindex > 0) { 02252 vbptr = varbind_ptr; 02253 asp->bulkcache[bulkcount++] = vbptr; 02254 02255 for (i = 1; i < asp->pdu->errindex; i++) { 02256 vbptr->next_variable = 02257 SNMP_MALLOC_STRUCT(variable_list); 02258 /* 02259 * don't clone the oid as it's got to be 02260 * overwritten anyway 02261 */ 02262 if (!vbptr->next_variable) { 02263 /* 02264 * XXXWWW: ack!!! 02265 */ 02266 DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n")); 02267 } else { 02268 vbptr = vbptr->next_variable; 02269 vbptr->name_length = 0; 02270 vbptr->type = ASN_NULL; 02271 asp->bulkcache[bulkcount++] = vbptr; 02272 } 02273 } 02274 vbptr->next_variable = vbsave; 02275 } else { 02276 /* 02277 * 0 repeats requested for this varbind, so take it off 02278 * the list. 02279 */ 02280 vbptr = varbind_ptr; 02281 *prevNext = vbptr->next_variable; 02282 vbptr->next_variable = NULL; 02283 snmp_free_varbind(vbptr); 02284 asp->vbcount--; 02285 continue; 02286 } 02287 } 02288 } 02289 02290 /* 02291 * count the varbinds 02292 */ 02293 ++vbcount; 02294 02295 /* 02296 * find the owning tree 02297 */ 02298 tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length, 02299 NULL, asp->pdu->contextName); 02300 02301 /* 02302 * check access control 02303 */ 02304 switch (asp->pdu->command) { 02305 case SNMP_MSG_GET: 02306 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, 02307 asp->pdu, varbind_ptr->type); 02308 if (view != VACM_SUCCESS) 02309 snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT, 02310 NULL, 0); 02311 break; 02312 02313 case SNMP_MSG_SET: 02314 view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, 02315 asp->pdu, varbind_ptr->type); 02316 if (view != VACM_SUCCESS) 02317 return SNMP_ERR_NOACCESS; 02318 break; 02319 02320 case SNMP_MSG_GETNEXT: 02321 case SNMP_MSG_GETBULK: 02322 default: 02323 view = VACM_SUCCESS; 02324 /* 02325 * XXXWWW: check VACM here to see if "tp" is even worthwhile 02326 */ 02327 } 02328 if (view == VACM_SUCCESS) { 02329 request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr, 02330 tp); 02331 if (request && asp->pdu->command == SNMP_MSG_GETBULK) { 02332 request->repeat = request->orig_repeat = bulkrep; 02333 } 02334 } 02335 02336 prevNext = &(varbind_ptr->next_variable); 02337 } 02338 02339 return SNMPERR_SUCCESS; 02340 } 02341 02342 /* 02343 * this function is only applicable in getnext like contexts 02344 */ 02345 int 02346 netsnmp_reassign_requests(netsnmp_agent_session *asp) 02347 { 02348 /* 02349 * assume all the requests have been filled or rejected by the 02350 * subtrees, so reassign the rejected ones to the next subtree in 02351 * the chain 02352 */ 02353 02354 int i; 02355 02356 /* 02357 * get old info 02358 */ 02359 netsnmp_tree_cache *old_treecache = asp->treecache; 02360 02361 /* 02362 * malloc new space 02363 */ 02364 asp->treecache = 02365 (netsnmp_tree_cache *) calloc(asp->treecache_len, 02366 sizeof(netsnmp_tree_cache)); 02367 asp->treecache_num = -1; 02368 if (asp->cache_store) { 02369 netsnmp_free_cachemap(asp->cache_store); 02370 asp->cache_store = NULL; 02371 } 02372 02373 for (i = 0; i < asp->vbcount; i++) { 02374 if (asp->requests[i].requestvb == NULL) { 02375 /* 02376 * Occurs when there's a mixture of still active 02377 * and "endOfMibView" repetitions 02378 */ 02379 continue; 02380 } 02381 if (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->next)) { 02385 if (old_treecache != NULL) { 02386 SNMP_FREE(old_treecache); 02387 old_treecache = NULL; 02388 } 02389 } 02390 } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) { 02391 /* 02392 * re-add the same subtree 02393 */ 02394 asp->requests[i].requestvb->type = ASN_NULL; 02395 if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index, 02396 asp->requests[i].requestvb, 02397 asp->requests[i].subtree)) { 02398 if (old_treecache != NULL) { 02399 SNMP_FREE(old_treecache); 02400 old_treecache = NULL; 02401 } 02402 } 02403 } 02404 } 02405 02406 if (old_treecache != NULL) { 02407 SNMP_FREE(old_treecache); 02408 } 02409 return SNMP_ERR_NOERROR; 02410 } 02411 02412 void 02413 netsnmp_delete_request_infos(netsnmp_request_info *reqlist) 02414 { 02415 while (reqlist) { 02416 netsnmp_free_request_data_sets(reqlist); 02417 reqlist = reqlist->next; 02418 } 02419 } 02420 02421 void 02422 netsnmp_delete_subtree_cache(netsnmp_agent_session *asp) 02423 { 02424 while (asp->treecache_num >= 0) { 02425 /* 02426 * don't delete subtrees 02427 */ 02428 netsnmp_delete_request_infos(asp->treecache[asp->treecache_num]. 02429 requests_begin); 02430 asp->treecache_num--; 02431 } 02432 } 02433 02434 /* 02435 * check all requests for errors 02436 * 02437 * @Note: 02438 * This function is a little different from the others in that 02439 * it does not use any linked lists, instead using the original 02440 * asp requests array. This is of particular importance for 02441 * cases where the linked lists are unreliable. One known instance 02442 * of this scenario occurs when the row_merge helper is used, which 02443 * may temporarily disrupts linked lists during its (and its childrens) 02444 * handling of requests. 02445 */ 02446 int 02447 netsnmp_check_all_requests_error(netsnmp_agent_session *asp, 02448 int look_for_specific) 02449 { 02450 int i; 02451 02452 /* 02453 * find any errors marked in the requests 02454 */ 02455 for( i = 0; i < asp->vbcount; ++i ) { 02456 if ((SNMP_ERR_NOERROR != asp->requests[i].status) && 02457 (!look_for_specific || 02458 asp->requests[i].status == look_for_specific)) 02459 return asp->requests[i].status; 02460 } 02461 02462 return SNMP_ERR_NOERROR; 02463 } 02464 02465 int 02466 netsnmp_check_requests_error(netsnmp_request_info *requests) 02467 { 02468 /* 02469 * find any errors marked in the requests 02470 */ 02471 for (;requests;requests = requests->next) { 02472 if (requests->status != SNMP_ERR_NOERROR) 02473 return requests->status; 02474 } 02475 return SNMP_ERR_NOERROR; 02476 } 02477 02478 int 02479 netsnmp_check_requests_status(netsnmp_agent_session *asp, 02480 netsnmp_request_info *requests, 02481 int look_for_specific) 02482 { 02483 /* 02484 * find any errors marked in the requests 02485 */ 02486 while (requests) { 02487 if(requests->agent_req_info != asp->reqinfo) { 02488 DEBUGMSGTL(("verbose:asp", 02489 "**reqinfo %p doesn't match cached reqinfo %p\n", 02490 asp->reqinfo, requests->agent_req_info)); 02491 } 02492 if (requests->status != SNMP_ERR_NOERROR && 02493 (!look_for_specific || requests->status == look_for_specific) 02494 && (look_for_specific || asp->index == 0 02495 || requests->index < asp->index)) { 02496 asp->index = requests->index; 02497 asp->status = requests->status; 02498 } 02499 requests = requests->next; 02500 } 02501 return asp->status; 02502 } 02503 02504 int 02505 netsnmp_check_all_requests_status(netsnmp_agent_session *asp, 02506 int look_for_specific) 02507 { 02508 int i; 02509 for (i = 0; i <= asp->treecache_num; i++) { 02510 netsnmp_check_requests_status(asp, 02511 asp->treecache[i].requests_begin, 02512 look_for_specific); 02513 } 02514 return asp->status; 02515 } 02516 02517 int 02518 handle_var_requests(netsnmp_agent_session *asp) 02519 { 02520 int i, retstatus = SNMP_ERR_NOERROR, 02521 status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR; 02522 netsnmp_handler_registration *reginfo; 02523 02524 asp->reqinfo->asp = asp; 02525 asp->reqinfo->mode = asp->mode; 02526 02527 /* 02528 * now, have the subtrees in the cache go search for their results 02529 */ 02530 for (i = 0; i <= asp->treecache_num; i++) { 02531 /* 02532 * don't call handlers w/null reginfo. 02533 * - when is this? sub agent disconnected while request processing? 02534 * - should this case encompass more of this subroutine? 02535 * - does check_request_status make send if handlers weren't called? 02536 */ 02537 if(NULL != asp->treecache[i].subtree->reginfo) { 02538 reginfo = asp->treecache[i].subtree->reginfo; 02539 status = netsnmp_call_handlers(reginfo, asp->reqinfo, 02540 asp->treecache[i].requests_begin); 02541 } 02542 else 02543 status = SNMP_ERR_GENERR; 02544 02545 /* 02546 * find any errors marked in the requests. For later parts of 02547 * SET processing, only check for new errors specific to that 02548 * set processing directive (which must superceed the previous 02549 * errors). 02550 */ 02551 switch (asp->mode) { 02552 case MODE_SET_COMMIT: 02553 retstatus = netsnmp_check_requests_status(asp, 02554 asp->treecache[i]. 02555 requests_begin, 02556 SNMP_ERR_COMMITFAILED); 02557 break; 02558 02559 case MODE_SET_UNDO: 02560 retstatus = netsnmp_check_requests_status(asp, 02561 asp->treecache[i]. 02562 requests_begin, 02563 SNMP_ERR_UNDOFAILED); 02564 break; 02565 02566 default: 02567 retstatus = netsnmp_check_requests_status(asp, 02568 asp->treecache[i]. 02569 requests_begin, 0); 02570 break; 02571 } 02572 02573 /* 02574 * always take lowest varbind if possible 02575 */ 02576 if (retstatus != SNMP_ERR_NOERROR) { 02577 status = retstatus; 02578 } 02579 02580 /* 02581 * other things we know less about (no index) 02582 */ 02583 /* 02584 * WWW: drop support for this? 02585 */ 02586 if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) { 02587 /* 02588 * we can't break here, since some processing needs to be 02589 * done for all requests anyway (IE, SET handling for UNDO 02590 * needs to be called regardless of previous status 02591 * results. 02592 * WWW: This should be predictable though and 02593 * breaking should be possible in some cases (eg GET, 02594 * GETNEXT, ...) 02595 */ 02596 final_status = status; 02597 } 02598 } 02599 02600 return final_status; 02601 } 02602 02603 void 02604 netsnmp_check_delegated_requests(void) 02605 { 02606 netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL; 02607 02608 for (asp = agent_delegated_list; asp; asp = next_asp) { 02609 next_asp = asp->next; /* save in case we clean up asp */ 02610 if (!netsnmp_check_for_delegated(asp)) { 02611 02612 /* 02613 * we're done with this one, remove from queue 02614 */ 02615 if (prev_asp != NULL) 02616 prev_asp->next = asp->next; 02617 else 02618 agent_delegated_list = asp->next; 02619 asp->next = NULL; 02620 02621 /* 02622 * check request status 02623 */ 02624 netsnmp_check_all_requests_status(asp, 0); 02625 02626 /* 02627 * continue processing or finish up 02628 */ 02629 check_delayed_request(asp); 02630 02631 /* 02632 * if head was removed, don't drop it if it 02633 * was it re-queued 02634 */ 02635 if ((prev_asp == NULL) && (agent_delegated_list == asp)) { 02636 prev_asp = asp; 02637 } 02638 } else { 02639 02640 /* 02641 * asp is still on the queue 02642 */ 02643 prev_asp = asp; 02644 } 02645 } 02646 } 02647 02648 /* 02649 * loop through our sessions known delegated sessions and check to see 02650 * if they've completed yet. If there are no more delegated sessions, 02651 * check for and process any queued requests 02652 */ 02653 void 02654 netsnmp_check_outstanding_agent_requests(void) 02655 { 02656 netsnmp_agent_session *asp; 02657 02658 /* 02659 * deal with delegated requests 02660 */ 02661 netsnmp_check_delegated_requests(); 02662 02663 /* 02664 * if we are processing a set and there are more delegated 02665 * requests, keep waiting before getting to queued requests. 02666 */ 02667 if (netsnmp_processing_set && (NULL != agent_delegated_list)) 02668 return; 02669 02670 while (netsnmp_agent_queued_list) { 02671 02672 /* 02673 * if we are processing a set, the first item better be 02674 * the set being (or waiting to be) processed. 02675 */ 02676 netsnmp_assert((!netsnmp_processing_set) || 02677 (netsnmp_processing_set == netsnmp_agent_queued_list)); 02678 02679 /* 02680 * if the top request is a set, don't pop it 02681 * off if there are delegated requests 02682 */ 02683 if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) && 02684 (agent_delegated_list)) { 02685 02686 netsnmp_assert(netsnmp_processing_set == NULL); 02687 02688 netsnmp_processing_set = netsnmp_agent_queued_list; 02689 DEBUGMSGTL(("snmp_agent", "SET request remains queued while " 02690 "delegated requests finish, asp = %08p\n", 02691 agent_delegated_list)); 02692 break; 02693 } 02694 02695 /* 02696 * pop the first request and process it 02697 */ 02698 asp = netsnmp_agent_queued_list; 02699 netsnmp_agent_queued_list = asp->next; 02700 DEBUGMSGTL(("snmp_agent", 02701 "processing queued request, asp = %08p\n", asp)); 02702 02703 netsnmp_handle_request(asp, asp->status); 02704 02705 /* 02706 * if we hit a set, stop 02707 */ 02708 if (NULL != netsnmp_processing_set) 02709 break; 02710 } 02711 } 02712 02718 int 02719 netsnmp_check_transaction_id(int transaction_id) 02720 { 02721 netsnmp_agent_session *asp, *prev_asp = NULL; 02722 02723 for (asp = agent_delegated_list; asp; prev_asp = asp, asp = asp->next) { 02724 if (asp->pdu->transid == transaction_id) 02725 return SNMPERR_SUCCESS; 02726 } 02727 return SNMPERR_GENERR; 02728 } 02729 02730 02731 /* 02732 * check_delayed_request(asp) 02733 * 02734 * Called to rexamine a set of requests and continue processing them 02735 * once all the previous (delayed) requests have been handled one way 02736 * or another. 02737 */ 02738 02739 int 02740 check_delayed_request(netsnmp_agent_session *asp) 02741 { 02742 int status = SNMP_ERR_NOERROR; 02743 02744 DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %08p\n", 02745 asp)); 02746 02747 switch (asp->mode) { 02748 case SNMP_MSG_GETBULK: 02749 case SNMP_MSG_GETNEXT: 02750 netsnmp_check_all_requests_status(asp, 0); 02751 if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) { 02752 DEBUGMSGTL(("snmp_agent","canceling next walk for asp %p\n", asp)); 02753 break; 02754 } 02755 handle_getnext_loop(asp); 02756 if (netsnmp_check_for_delegated(asp) && 02757 netsnmp_check_transaction_id(asp->pdu->transid) != 02758 SNMPERR_SUCCESS) { 02759 /* 02760 * add to delegated request chain 02761 */ 02762 if (!netsnmp_check_delegated_chain_for(asp)) { 02763 asp->next = agent_delegated_list; 02764 agent_delegated_list = asp; 02765 } 02766 } 02767 break; 02768 02769 case MODE_SET_COMMIT: 02770 netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED); 02771 goto settop; 02772 02773 case MODE_SET_UNDO: 02774 netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED); 02775 goto settop; 02776 02777 case MODE_SET_BEGIN: 02778 case MODE_SET_RESERVE1: 02779 case MODE_SET_RESERVE2: 02780 case MODE_SET_ACTION: 02781 case MODE_SET_FREE: 02782 settop: 02783 /* If we should do only one pass, this mean we */ 02784 /* should not reenter this function */ 02785 if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { 02786 /* We should have finished the processing after the first */ 02787 /* handle_set_loop, so just wrap up */ 02788 break; 02789 } 02790 handle_set_loop(asp); 02791 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { 02792 02793 if (netsnmp_check_for_delegated_and_add(asp)) { 02794 /* 02795 * add to delegated request chain 02796 */ 02797 if (!asp->status) 02798 asp->status = status; 02799 } 02800 02801 return SNMP_ERR_NOERROR; 02802 } 02803 break; 02804 02805 default: 02806 break; 02807 } 02808 02809 /* 02810 * if we don't have anything outstanding (delegated), wrap up 02811 */ 02812 if (!netsnmp_check_for_delegated(asp)) 02813 return netsnmp_wrap_up_request(asp, status); 02814 02815 return 1; 02816 } 02817 02819 int 02820 check_getnext_results(netsnmp_agent_session *asp) 02821 { 02822 /* 02823 * get old info 02824 */ 02825 netsnmp_tree_cache *old_treecache = asp->treecache; 02826 int old_treecache_num = asp->treecache_num; 02827 int count = 0; 02828 int i, special = 0; 02829 netsnmp_request_info *request; 02830 02831 if (asp->mode == SNMP_MSG_GET) { 02832 /* 02833 * Special case for doing INCLUSIVE getNext operations in 02834 * AgentX subagents. 02835 */ 02836 DEBUGMSGTL(("snmp_agent", 02837 "asp->mode == SNMP_MSG_GET in ch_getnext\n")); 02838 asp->mode = asp->oldmode; 02839 special = 1; 02840 } 02841 02842 for (i = 0; i <= old_treecache_num; i++) { 02843 for (request = old_treecache[i].requests_begin; request; 02844 request = request->next) { 02845 02846 /* 02847 * If we have just done the special case AgentX GET, then any 02848 * requests which were not INCLUSIVE will now have a wrong 02849 * response, so junk them and retry from the same place (except 02850 * that this time the handler will be called in "inexact" 02851 * mode). 02852 */ 02853 02854 if (special) { 02855 if (!request->inclusive) { 02856 DEBUGMSGTL(("snmp_agent", 02857 "request %d wasn't inclusive\n", 02858 request->index)); 02859 snmp_set_var_typed_value(request->requestvb, 02860 ASN_PRIV_RETRY, NULL, 0); 02861 } else if (request->requestvb->type == ASN_NULL || 02862 request->requestvb->type == SNMP_NOSUCHINSTANCE || 02863 request->requestvb->type == SNMP_NOSUCHOBJECT) { 02864 /* 02865 * it was inclusive, but no results. Still retry this 02866 * search. 02867 */ 02868 snmp_set_var_typed_value(request->requestvb, 02869 ASN_PRIV_RETRY, NULL, 0); 02870 } 02871 } 02872 02873 /* 02874 * out of range? 02875 */ 02876 if (snmp_oid_compare(request->requestvb->name, 02877 request->requestvb->name_length, 02878 request->range_end, 02879 request->range_end_len) >= 0) { 02880 /* 02881 * ack, it's beyond the accepted end of range. 02882 */ 02883 /* 02884 * fix it by setting the oid to the end of range oid instead 02885 */ 02886 DEBUGMSGTL(("check_getnext_results", 02887 "request response %d out of range\n", 02888 request->index)); 02889 /* 02890 * I'm not sure why inclusive is set unconditionally here (see 02891 * comments for revision 1.161), but it causes a problem for 02892 * GETBULK over an overridden variable. The bulk-to-next 02893 * handler re-uses the same request for multiple varbinds, 02894 * and once inclusive was set, it was never cleared. So, a 02895 * hack. Instead of setting it to 1, set it to 2, so bulk-to 02896 * next can clear it later. As of the time of this hack, all 02897 * checks of this var are boolean checks (not == 1), so this 02898 * should be safe. Cross your fingers. 02899 */ 02900 request->inclusive = 2; 02901 /* 02902 * XXX: should set this to the original OID? 02903 */ 02904 snmp_set_var_objid(request->requestvb, 02905 request->range_end, 02906 request->range_end_len); 02907 snmp_set_var_typed_value(request->requestvb, ASN_NULL, 02908 NULL, 0); 02909 } 02910 02911 /* 02912 * mark any existent requests with illegal results as NULL 02913 */ 02914 if (request->requestvb->type == SNMP_ENDOFMIBVIEW) { 02915 /* 02916 * illegal response from a subagent. Change it back to NULL 02917 * xxx-rks: err, how do we know this is a subagent? 02918 */ 02919 request->requestvb->type = ASN_NULL; 02920 request->inclusive = 1; 02921 } 02922 02923 if (request->requestvb->type == ASN_NULL || 02924 request->requestvb->type == ASN_PRIV_RETRY || 02925 (asp->reqinfo->mode == MODE_GETBULK 02926 && request->repeat > 0)) 02927 count++; 02928 } 02929 } 02930 return count; 02931 } 02932 02936 int 02937 handle_getnext_loop(netsnmp_agent_session *asp) 02938 { 02939 int status; 02940 netsnmp_variable_list *var_ptr; 02941 02942 /* 02943 * loop 02944 */ 02945 while (netsnmp_running) { 02946 02947 /* 02948 * bail for now if anything is delegated. 02949 */ 02950 if (netsnmp_check_for_delegated(asp)) { 02951 return SNMP_ERR_NOERROR; 02952 } 02953 02954 /* 02955 * check vacm against results 02956 */ 02957 check_acm(asp, ASN_PRIV_RETRY); 02958 02959 /* 02960 * need to keep going we're not done yet. 02961 */ 02962 if (!check_getnext_results(asp)) 02963 /* 02964 * nothing left, quit now 02965 */ 02966 break; 02967 02968 /* 02969 * never had a request (empty pdu), quit now 02970 */ 02971 /* 02972 * XXXWWW: huh? this would be too late, no? shouldn't we 02973 * catch this earlier? 02974 */ 02975 /* 02976 * if (count == 0) 02977 * break; 02978 */ 02979 02980 DEBUGIF("results") { 02981 DEBUGMSGTL(("results", 02982 "getnext results, before next pass:\n")); 02983 for (var_ptr = asp->pdu->variables; var_ptr; 02984 var_ptr = var_ptr->next_variable) { 02985 DEBUGMSGTL(("results", "\t")); 02986 DEBUGMSGVAR(("results", var_ptr)); 02987 DEBUGMSG(("results", "\n")); 02988 } 02989 } 02990 02991 netsnmp_reassign_requests(asp); 02992 status = handle_var_requests(asp); 02993 if (status != SNMP_ERR_NOERROR) { 02994 return status; /* should never really happen */ 02995 } 02996 } 02997 return SNMP_ERR_NOERROR; 02998 } 02999 03000 int 03001 handle_set(netsnmp_agent_session *asp) 03002 { 03003 int status; 03004 /* 03005 * SETS require 3-4 passes through the var_op_list. 03006 * The first two 03007 * passes verify that all types, lengths, and values are valid 03008 * and may reserve resources and the third does the set and a 03009 * fourth executes any actions. Then the identical GET RESPONSE 03010 * packet is returned. 03011 * If either of the first two passes returns an error, another 03012 * pass is made so that any reserved resources can be freed. 03013 * If the third pass returns an error, another pass is 03014 * made so that 03015 * any changes can be reversed. 03016 * If the fourth pass (or any of the error handling passes) 03017 * return an error, we'd rather not know about it! 03018 */ 03019 if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) { 03020 switch (asp->mode) { 03021 case MODE_SET_BEGIN: 03022 snmp_increment_statistic(STAT_SNMPINSETREQUESTS); 03023 asp->rw = WRITE; /* WWW: still needed? */ 03024 asp->mode = MODE_SET_RESERVE1; 03025 asp->status = SNMP_ERR_NOERROR; 03026 break; 03027 03028 case MODE_SET_RESERVE1: 03029 03030 if (asp->status != SNMP_ERR_NOERROR) 03031 asp->mode = MODE_SET_FREE; 03032 else 03033 asp->mode = MODE_SET_RESERVE2; 03034 break; 03035 03036 case MODE_SET_RESERVE2: 03037 if (asp->status != SNMP_ERR_NOERROR) 03038 asp->mode = MODE_SET_FREE; 03039 else 03040 asp->mode = MODE_SET_ACTION; 03041 break; 03042 03043 case MODE_SET_ACTION: 03044 if (asp->status != SNMP_ERR_NOERROR) 03045 asp->mode = MODE_SET_UNDO; 03046 else 03047 asp->mode = MODE_SET_COMMIT; 03048 break; 03049 03050 case MODE_SET_COMMIT: 03051 if (asp->status != SNMP_ERR_NOERROR) { 03052 asp->mode = FINISHED_FAILURE; 03053 } else { 03054 asp->mode = FINISHED_SUCCESS; 03055 } 03056 break; 03057 03058 case MODE_SET_UNDO: 03059 asp->mode = FINISHED_FAILURE; 03060 break; 03061 03062 case MODE_SET_FREE: 03063 asp->mode = FINISHED_FAILURE; 03064 break; 03065 } 03066 } 03067 03068 if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) { 03069 DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode, 03070 se_find_label_in_slist("agent_mode", asp->mode))); 03071 status = handle_var_requests(asp); 03072 DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n", 03073 asp->mode, status)); 03074 if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) || 03075 status == SNMP_ERR_COMMITFAILED || 03076 status == SNMP_ERR_UNDOFAILED) { 03077 asp->status = status; 03078 } 03079 } 03080 return asp->status; 03081 } 03082 03083 int 03084 handle_set_loop(netsnmp_agent_session *asp) 03085 { 03086 while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) { 03087 handle_set(asp); 03088 if (netsnmp_check_for_delegated(asp)) { 03089 return SNMP_ERR_NOERROR; 03090 } 03091 if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) { 03092 return asp->status; 03093 } 03094 } 03095 return asp->status; 03096 } 03097 03098 int 03099 netsnmp_handle_request(netsnmp_agent_session *asp, int status) 03100 { 03101 /* 03102 * if this isn't a delegated request trying to finish, 03103 * processing of a set request should not start until all 03104 * delegated requests have completed, and no other new requests 03105 * should be processed until the set request completes. 03106 */ 03107 if ((0 == netsnmp_check_delegated_chain_for(asp)) && 03108 (asp != netsnmp_processing_set)) { 03109 /* 03110 * if we are processing a set and this is not a delegated 03111 * request, queue the request 03112 */ 03113 if (netsnmp_processing_set) { 03114 netsnmp_add_queued(asp); 03115 DEBUGMSGTL(("snmp_agent", 03116 "request queued while processing set, " 03117 "asp = %08p\n", asp)); 03118 return 1; 03119 } 03120 03121 /* 03122 * check for set request 03123 */ 03124 if (asp->pdu->command == SNMP_MSG_SET) { 03125 netsnmp_processing_set = asp; 03126 03127 /* 03128 * if there are delegated requests, we must wait for them 03129 * to finish. 03130 */ 03131 if (agent_delegated_list) { 03132 DEBUGMSGTL(("snmp_agent", "SET request queued while " 03133 "delegated requests finish, asp = %08p\n", 03134 asp)); 03135 netsnmp_add_queued(asp); 03136 return 1; 03137 } 03138 } 03139 } 03140 03141 /* 03142 * process the request 03143 */ 03144 status = handle_pdu(asp); 03145 03146 /* 03147 * print the results in appropriate debugging mode 03148 */ 03149 DEBUGIF("results") { 03150 netsnmp_variable_list *var_ptr; 03151 DEBUGMSGTL(("results", "request results (status = %d):\n", 03152 status)); 03153 for (var_ptr = asp->pdu->variables; var_ptr; 03154 var_ptr = var_ptr->next_variable) { 03155 DEBUGMSGTL(("results", "\t")); 03156 DEBUGMSGVAR(("results", var_ptr)); 03157 DEBUGMSG(("results", "\n")); 03158 } 03159 } 03160 03161 /* 03162 * check for uncompleted requests 03163 */ 03164 if (netsnmp_check_for_delegated_and_add(asp)) { 03165 /* 03166 * add to delegated request chain 03167 */ 03168 asp->status = status; 03169 } else { 03170 /* 03171 * if we don't have anything outstanding (delegated), wrap up 03172 */ 03173 return netsnmp_wrap_up_request(asp, status); 03174 } 03175 03176 return 1; 03177 } 03178 03230 int 03231 handle_pdu(netsnmp_agent_session *asp) 03232 { 03233 int status, inclusives = 0; 03234 netsnmp_variable_list *v = NULL; 03235 03236 /* 03237 * for illegal requests, mark all nodes as ASN_NULL 03238 */ 03239 switch (asp->pdu->command) { 03240 03241 case SNMP_MSG_INTERNAL_SET_RESERVE2: 03242 case SNMP_MSG_INTERNAL_SET_ACTION: 03243 case SNMP_MSG_INTERNAL_SET_COMMIT: 03244 case SNMP_MSG_INTERNAL_SET_FREE: 03245 case SNMP_MSG_INTERNAL_SET_UNDO: 03246 status = get_set_cache(asp); 03247 if (status != SNMP_ERR_NOERROR) 03248 return status; 03249 break; 03250 03251 case SNMP_MSG_GET: 03252 case SNMP_MSG_GETNEXT: 03253 case SNMP_MSG_GETBULK: 03254 for (v = asp->pdu->variables; v != NULL; v = v->next_variable) { 03255 if (v->type == ASN_PRIV_INCL_RANGE) { 03256 /* 03257 * Leave the type for now (it gets set to 03258 * ASN_NULL in netsnmp_add_varbind_to_cache, 03259 * called by create_subnetsnmp_tree_cache below). 03260 * If we set it to ASN_NULL now, we wouldn't be 03261 * able to distinguish INCLUSIVE search 03262 * ranges. 03263 */ 03264 inclusives++; 03265 } else { 03266 snmp_set_var_typed_value(v, ASN_NULL, NULL, 0); 03267 } 03268 } 03269 /* 03270 * fall through 03271 */ 03272 03273 case SNMP_MSG_INTERNAL_SET_BEGIN: 03274 case SNMP_MSG_INTERNAL_SET_RESERVE1: 03275 default: 03276 asp->vbcount = count_varbinds(asp->pdu->variables); 03277 if (asp->vbcount) /* efence doesn't like 0 size allocs */ 03278 asp->requests = (netsnmp_request_info *) 03279 calloc(asp->vbcount, sizeof(netsnmp_request_info)); 03280 /* 03281 * collect varbinds 03282 */ 03283 status = netsnmp_create_subtree_cache(asp); 03284 if (status != SNMP_ERR_NOERROR) 03285 return status; 03286 } 03287 03288 asp->mode = asp->pdu->command; 03289 switch (asp->mode) { 03290 case SNMP_MSG_GET: 03291 /* 03292 * increment the message type counter 03293 */ 03294 snmp_increment_statistic(STAT_SNMPINGETREQUESTS); 03295 03296 /* 03297 * check vacm ahead of time 03298 */ 03299 check_acm(asp, SNMP_NOSUCHOBJECT); 03300 03301 /* 03302 * get the results 03303 */ 03304 status = handle_var_requests(asp); 03305 03306 /* 03307 * Deal with unhandled results -> noSuchInstance (rather 03308 * than noSuchObject -- in that case, the type will 03309 * already have been set to noSuchObject when we realised 03310 * we couldn't find an appropriate tree). 03311 */ 03312 if (status == SNMP_ERR_NOERROR) 03313 snmp_replace_var_types(asp->pdu->variables, ASN_NULL, 03314 SNMP_NOSUCHINSTANCE); 03315 break; 03316 03317 case SNMP_MSG_GETNEXT: 03318 snmp_increment_statistic(STAT_SNMPINGETNEXTS); 03319 /* 03320 * fall through 03321 */ 03322 03323 case SNMP_MSG_GETBULK: /* note: there is no getbulk stat */ 03324 /* 03325 * loop through our mib tree till we find an 03326 * appropriate response to return to the caller. 03327 */ 03328 03329 if (inclusives) { 03330 /* 03331 * This is a special case for AgentX INCLUSIVE getNext 03332 * requests where a result lexi-equal to the request is okay 03333 * but if such a result does not exist, we still want the 03334 * lexi-next one. So basically we do a GET first, and if any 03335 * of the INCLUSIVE requests are satisfied, we use that 03336 * value. Then, unsatisfied INCLUSIVE requests, and 03337 * non-INCLUSIVE requests get done as normal. 03338 */ 03339 03340 DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n")); 03341 asp->oldmode = asp->mode; 03342 asp->mode = SNMP_MSG_GET; 03343 } 03344 03345 /* 03346 * first pass 03347 */ 03348 status = handle_var_requests(asp); 03349 if (status != SNMP_ERR_NOERROR) { 03350 if (!inclusives) 03351 return status; /* should never really happen */ 03352 else 03353 asp->status = SNMP_ERR_NOERROR; 03354 } 03355 03356 /* 03357 * loop through our mib tree till we find an 03358 * appropriate response to return to the caller. 03359 */ 03360 03361 status = handle_getnext_loop(asp); 03362 break; 03363 03364 case SNMP_MSG_SET: 03365 #ifdef NETSNMP_DISABLE_SET_SUPPORT 03366 return SNMP_ERR_NOTWRITABLE; 03367 #else 03368 /* 03369 * check access permissions first 03370 */ 03371 if (check_acm(asp, SNMP_NOSUCHOBJECT)) 03372 return SNMP_ERR_NOTWRITABLE; 03373 03374 asp->mode = MODE_SET_BEGIN; 03375 status = handle_set_loop(asp); 03376 #endif 03377 break; 03378 03379 case SNMP_MSG_INTERNAL_SET_BEGIN: 03380 case SNMP_MSG_INTERNAL_SET_RESERVE1: 03381 case SNMP_MSG_INTERNAL_SET_RESERVE2: 03382 case SNMP_MSG_INTERNAL_SET_ACTION: 03383 case SNMP_MSG_INTERNAL_SET_COMMIT: 03384 case SNMP_MSG_INTERNAL_SET_FREE: 03385 case SNMP_MSG_INTERNAL_SET_UNDO: 03386 asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY; 03387 status = handle_set_loop(asp); 03388 /* 03389 * asp related cache is saved in cleanup 03390 */ 03391 break; 03392 03393 case SNMP_MSG_RESPONSE: 03394 snmp_increment_statistic(STAT_SNMPINGETRESPONSES); 03395 return SNMP_ERR_NOERROR; 03396 03397 case SNMP_MSG_TRAP: 03398 case SNMP_MSG_TRAP2: 03399 snmp_increment_statistic(STAT_SNMPINTRAPS); 03400 return SNMP_ERR_NOERROR; 03401 03402 default: 03403 /* 03404 * WWW: are reports counted somewhere ? 03405 */ 03406 snmp_increment_statistic(STAT_SNMPINASNPARSEERRS); 03407 return SNMPERR_GENERR; /* shouldn't get here */ 03408 /* 03409 * WWW 03410 */ 03411 } 03412 return status; 03413 } 03414 03418 NETSNMP_STATIC_INLINE int 03419 _request_set_error(netsnmp_request_info *request, int mode, int error_value) 03420 { 03421 if (!request) 03422 return SNMPERR_NO_VARS; 03423 03424 request->processed = 1; 03425 request->delegated = REQUEST_IS_NOT_DELEGATED; 03426 03427 switch (error_value) { 03428 case SNMP_NOSUCHOBJECT: 03429 case SNMP_NOSUCHINSTANCE: 03430 case SNMP_ENDOFMIBVIEW: 03431 /* 03432 * these are exceptions that should be put in the varbind 03433 * in the case of a GET but should be translated for a SET 03434 * into a real error status code and put in the request 03435 */ 03436 switch (mode) { 03437 case MODE_GET: 03438 case MODE_GETNEXT: 03439 case MODE_GETBULK: 03440 request->requestvb->type = error_value; 03441 return SNMPERR_SUCCESS; 03442 03443 /* 03444 * These are technically illegal to set by the 03445 * client APIs for these modes. But accepting 03446 * them here allows the 'sparse_table' helper to 03447 * provide some common table handling processing 03448 * 03449 snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n", 03450 error_value, mode); 03451 return SNMPERR_VALUE; 03452 */ 03453 03454 default: 03455 request->status = SNMP_ERR_NOSUCHNAME; /* WWW: correct? */ 03456 return SNMPERR_SUCCESS; 03457 } 03458 break; /* never get here */ 03459 03460 default: 03461 if (error_value < 0) { 03462 /* 03463 * illegal local error code. translate to generr 03464 */ 03465 /* 03466 * WWW: full translation map? 03467 */ 03468 snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n", 03469 error_value, SNMP_ERR_GENERR); 03470 request->status = SNMP_ERR_GENERR; 03471 } else { 03472 /* 03473 * WWW: translations and mode checking? 03474 */ 03475 request->status = error_value; 03476 } 03477 return SNMPERR_SUCCESS; 03478 } 03479 return SNMPERR_SUCCESS; 03480 } 03481 03486 int 03487 netsnmp_request_set_error(netsnmp_request_info *request, int error_value) 03488 { 03489 if (!request || !request->agent_req_info) 03490 return SNMPERR_NO_VARS; 03491 03492 return _request_set_error(request, request->agent_req_info->mode, 03493 error_value); 03494 } 03495 03501 int 03502 netsnmp_request_set_error_idx(netsnmp_request_info *request, 03503 int error_value, int idx) 03504 { 03505 int i; 03506 netsnmp_request_info *req = request; 03507 03508 if (!request || !request->agent_req_info) 03509 return SNMPERR_NO_VARS; 03510 03511 /* 03512 * Skip to the indicated varbind 03513 */ 03514 for ( i=2; i<idx; i++) { 03515 req = req->next; 03516 if (!req) 03517 return SNMPERR_NO_VARS; 03518 } 03519 03520 return _request_set_error(req, request->agent_req_info->mode, 03521 error_value); 03522 } 03523 03529 NETSNMP_INLINE int 03530 netsnmp_request_set_error_all( netsnmp_request_info *requests, int error) 03531 { 03532 int mode, rc, result = SNMPERR_SUCCESS; 03533 03534 if((NULL == requests) || (NULL == requests->agent_req_info)) 03535 return SNMPERR_NO_VARS; 03536 03537 mode = requests->agent_req_info->mode; /* every req has same mode */ 03538 03539 for(; requests ; requests = requests->next) { 03540 03542 netsnmp_assert(NULL != requests->agent_req_info); 03543 netsnmp_assert(mode == requests->agent_req_info->mode); 03544 03545 /* 03546 * set error for this request. Log any errors, save the last 03547 * to return to the user. 03548 */ 03549 if((rc = _request_set_error(requests, mode, error))) { 03550 snmp_log(LOG_WARNING,"got %d while setting request error\n", rc); 03551 result = rc; 03552 } 03553 } 03554 return result; 03555 } 03556 03557 extern struct timeval starttime; 03558 03559 /* 03560 * Return the value of 'sysUpTime' at the given marker 03561 */ 03562 u_long 03563 netsnmp_marker_uptime(marker_t pm) 03564 { 03565 u_long res; 03566 marker_t start = (marker_t) & starttime; 03567 03568 res = uatime_hdiff(start, pm); 03569 return res; /* atime_diff works in msec, not csec */ 03570 } 03571 03572 /* 03573 * struct timeval equivalents of these 03574 */ 03575 u_long 03576 netsnmp_timeval_uptime(struct timeval * tv) 03577 { 03578 return netsnmp_marker_uptime((marker_t) tv); 03579 } 03580 03581 /* 03582 * Return the current value of 'sysUpTime' 03583 */ 03584 u_long 03585 netsnmp_get_agent_uptime(void) 03586 { 03587 struct timeval now; 03588 gettimeofday(&now, NULL); 03589 03590 return netsnmp_timeval_uptime(&now); 03591 } 03592 03593 03594 03595 NETSNMP_INLINE void 03596 netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari, 03597 netsnmp_data_list *node) 03598 { 03599 if (ari) { 03600 if (ari->agent_data) { 03601 netsnmp_add_list_data(&ari->agent_data, node); 03602 } else { 03603 ari->agent_data = node; 03604 } 03605 } 03606 } 03607 03608 NETSNMP_INLINE int 03609 netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari, 03610 const char * name) 03611 { 03612 if ((NULL == ari) || (NULL == ari->agent_data)) 03613 return 1; 03614 03615 return netsnmp_remove_list_node(&ari->agent_data, name); 03616 } 03617 03618 NETSNMP_INLINE void * 03619 netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari, 03620 const char *name) 03621 { 03622 if (ari) { 03623 return netsnmp_get_list_data(ari->agent_data, name); 03624 } 03625 return NULL; 03626 } 03627 03628 NETSNMP_INLINE void 03629 netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari) 03630 { 03631 if (ari) { 03632 netsnmp_free_list_data(ari->agent_data); 03633 } 03634 } 03635 03636 NETSNMP_INLINE void 03637 netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari) 03638 { 03639 if (ari) { 03640 netsnmp_free_all_list_data(ari->agent_data); 03641 } 03642 } 03643 03644 NETSNMP_INLINE void 03645 netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari) 03646 { 03647 if (ari) { 03648 if (ari->agent_data) { 03649 netsnmp_free_all_list_data(ari->agent_data); 03650 } 03651 SNMP_FREE(ari); 03652 } 03653 } 03654 03655 /************************************************************************* 03656 * 03657 * deprecated functions 03658 * 03659 */ 03660 03668 int 03669 netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo, 03670 netsnmp_request_info *request, int error_value) 03671 { 03672 if (!request || !reqinfo) 03673 return error_value; 03674 03675 _request_set_error(request, reqinfo->mode, error_value); 03676 03677 return error_value; 03678 } 03679 03687 int 03688 netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request, 03689 int error_value) 03690 { 03691 _request_set_error(request, mode, error_value); 03692 03693 return error_value; 03694 } 03695 03703 int 03704 netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo, 03705 netsnmp_request_info *requests, 03706 int error_value) 03707 { 03708 netsnmp_request_set_error_all(requests, error_value); 03709 return error_value; 03710 }
1.7.6.1