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