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