net-snmp 5.7
|
00001 /* 00002 * snmp_client.c - a toolkit of common functions for an SNMP client. 00003 * 00004 */ 00005 /* Portions of this file are subject to the following copyright(s). See 00006 * the Net-SNMP's COPYING file for more details and other copyrights 00007 * that may apply: 00008 */ 00009 /********************************************************************** 00010 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University 00011 00012 All Rights Reserved 00013 00014 Permission to use, copy, modify, and distribute this software and its 00015 documentation for any purpose and without fee is hereby granted, 00016 provided that the above copyright notice appear in all copies and that 00017 both that copyright notice and this permission notice appear in 00018 supporting documentation, and that the name of CMU not be 00019 used in advertising or publicity pertaining to distribution of the 00020 software without specific, written prior permission. 00021 00022 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 00023 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 00024 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 00025 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 00026 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 00027 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00028 SOFTWARE. 00029 ******************************************************************/ 00030 /* 00031 * Portions of this file are copyrighted by: 00032 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00033 * Use is subject to license terms specified in the COPYING file 00034 * distributed with the Net-SNMP package. 00035 */ 00036 00042 #include <net-snmp/net-snmp-config.h> 00043 #include <net-snmp/net-snmp-features.h> 00044 00045 #include <stdio.h> 00046 #include <errno.h> 00047 #if HAVE_STDLIB_H 00048 #include <stdlib.h> 00049 #endif 00050 #if HAVE_STRING_H 00051 #include <string.h> 00052 #else 00053 #include <strings.h> 00054 #endif 00055 #if HAVE_UNISTD_H 00056 #include <unistd.h> 00057 #endif 00058 #include <sys/types.h> 00059 #if TIME_WITH_SYS_TIME 00060 # include <sys/time.h> 00061 # include <time.h> 00062 #else 00063 # if HAVE_SYS_TIME_H 00064 # include <sys/time.h> 00065 # else 00066 # include <time.h> 00067 # endif 00068 #endif 00069 #if HAVE_SYS_PARAM_H 00070 #include <sys/param.h> 00071 #endif 00072 #if HAVE_NETINET_IN_H 00073 #include <netinet/in.h> 00074 #endif 00075 #if HAVE_ARPA_INET_H 00076 #include <arpa/inet.h> 00077 #endif 00078 #if HAVE_SYS_SELECT_H 00079 #include <sys/select.h> 00080 #endif 00081 #if HAVE_SYSLOG_H 00082 #include <syslog.h> 00083 #endif 00084 00085 #if HAVE_DMALLOC_H 00086 #include <dmalloc.h> 00087 #endif 00088 00089 #include <net-snmp/types.h> 00090 00091 #include <net-snmp/agent/ds_agent.h> 00092 #include <net-snmp/library/default_store.h> 00093 #include <net-snmp/library/snmp_api.h> 00094 #include <net-snmp/library/snmp_client.h> 00095 #include <net-snmp/library/snmp_secmod.h> 00096 #include <net-snmp/library/mib.h> 00097 #include <net-snmp/library/snmp_logging.h> 00098 #include <net-snmp/library/snmp_assert.h> 00099 #include <net-snmp/pdu_api.h> 00100 00101 netsnmp_feature_child_of(snmp_client_all, libnetsnmp) 00102 00103 netsnmp_feature_child_of(snmp_split_pdu, snmp_client_all) 00104 netsnmp_feature_child_of(snmp_reset_var_types, snmp_client_all) 00105 netsnmp_feature_child_of(query_set_default_session, snmp_client_all) 00106 netsnmp_feature_child_of(row_create, snmp_client_all) 00107 00108 #ifndef BSD4_3 00109 #define BSD4_2 00110 #endif 00111 00112 #ifndef FD_SET 00113 00114 typedef long fd_mask; 00115 #define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ 00116 00117 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 00118 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 00119 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 00120 #define FD_ZERO(p) memset((p), 0, sizeof(*(p))) 00121 #endif 00122 00123 /* 00124 * Prototype definitions 00125 */ 00126 static int snmp_synch_input(int op, netsnmp_session * session, 00127 int reqid, netsnmp_pdu *pdu, void *magic); 00128 00129 netsnmp_pdu * 00130 snmp_pdu_create(int command) 00131 { 00132 netsnmp_pdu *pdu; 00133 00134 pdu = (netsnmp_pdu *) calloc(1, sizeof(netsnmp_pdu)); 00135 if (pdu) { 00136 pdu->version = SNMP_DEFAULT_VERSION; 00137 pdu->command = command; 00138 pdu->errstat = SNMP_DEFAULT_ERRSTAT; 00139 pdu->errindex = SNMP_DEFAULT_ERRINDEX; 00140 pdu->securityModel = SNMP_DEFAULT_SECMODEL; 00141 pdu->transport_data = NULL; 00142 pdu->transport_data_length = 0; 00143 pdu->securityNameLen = 0; 00144 pdu->contextNameLen = 0; 00145 pdu->time = 0; 00146 pdu->reqid = snmp_get_next_reqid(); 00147 pdu->msgid = snmp_get_next_msgid(); 00148 } 00149 return pdu; 00150 00151 } 00152 00153 00154 /* 00155 * Add a null variable with the requested name to the end of the list of 00156 * variables for this pdu. 00157 */ 00158 netsnmp_variable_list * 00159 snmp_add_null_var(netsnmp_pdu *pdu, const oid * name, size_t name_length) 00160 { 00161 return snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, NULL, 0); 00162 } 00163 00164 00165 #include <net-snmp/library/snmp_debug.h> 00166 static int 00167 snmp_synch_input(int op, 00168 netsnmp_session * session, 00169 int reqid, netsnmp_pdu *pdu, void *magic) 00170 { 00171 struct synch_state *state = (struct synch_state *) magic; 00172 int rpt_type; 00173 00174 if (reqid != state->reqid && pdu && pdu->command != SNMP_MSG_REPORT) { 00175 DEBUGMSGTL(("snmp_synch", "Unexpected response (ReqID: %d,%d - Cmd %d)\n", 00176 reqid, state->reqid, pdu->command )); 00177 return 0; 00178 } 00179 00180 state->waiting = 0; 00181 DEBUGMSGTL(("snmp_synch", "Response (ReqID: %d - Cmd %d)\n", 00182 reqid, (pdu ? pdu->command : -1))); 00183 00184 if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE && pdu) { 00185 if (pdu->command == SNMP_MSG_REPORT) { 00186 rpt_type = snmpv3_get_report_type(pdu); 00187 if (SNMPV3_IGNORE_UNAUTH_REPORTS || 00188 rpt_type == SNMPERR_NOT_IN_TIME_WINDOW) { 00189 state->waiting = 1; 00190 } 00191 state->pdu = NULL; 00192 state->status = STAT_ERROR; 00193 session->s_snmp_errno = rpt_type; 00194 SET_SNMP_ERROR(rpt_type); 00195 } else if (pdu->command == SNMP_MSG_RESPONSE) { 00196 /* 00197 * clone the pdu to return to snmp_synch_response 00198 */ 00199 state->pdu = snmp_clone_pdu(pdu); 00200 state->status = STAT_SUCCESS; 00201 session->s_snmp_errno = SNMPERR_SUCCESS; 00202 } 00203 else { 00204 char msg_buf[50]; 00205 state->status = STAT_ERROR; 00206 session->s_snmp_errno = SNMPERR_PROTOCOL; 00207 SET_SNMP_ERROR(SNMPERR_PROTOCOL); 00208 snprintf(msg_buf, sizeof(msg_buf), "Expected RESPONSE-PDU but got %s-PDU", 00209 snmp_pdu_type(pdu->command)); 00210 snmp_set_detail(msg_buf); 00211 return 0; 00212 } 00213 } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) { 00214 state->pdu = NULL; 00215 state->status = STAT_TIMEOUT; 00216 session->s_snmp_errno = SNMPERR_TIMEOUT; 00217 SET_SNMP_ERROR(SNMPERR_TIMEOUT); 00218 } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) { 00219 state->pdu = NULL; 00220 state->status = STAT_ERROR; 00221 session->s_snmp_errno = SNMPERR_ABORT; 00222 SET_SNMP_ERROR(SNMPERR_ABORT); 00223 } 00224 00225 return 1; 00226 } 00227 00228 00229 /* 00230 * Clone an SNMP variable data structure. 00231 * Sets pointers to structure private storage, or 00232 * allocates larger object identifiers and values as needed. 00233 * 00234 * Caller must make list association for cloned variable. 00235 * 00236 * Returns 0 if successful. 00237 */ 00238 int 00239 snmp_clone_var(netsnmp_variable_list * var, netsnmp_variable_list * newvar) 00240 { 00241 if (!newvar || !var) 00242 return 1; 00243 00244 memmove(newvar, var, sizeof(netsnmp_variable_list)); 00245 newvar->next_variable = NULL; 00246 newvar->name = NULL; 00247 newvar->val.string = NULL; 00248 newvar->data = NULL; 00249 newvar->dataFreeHook = NULL; 00250 newvar->index = 0; 00251 00252 /* 00253 * Clone the object identifier and the value. 00254 * Allocate memory iff original will not fit into local storage. 00255 */ 00256 if (snmp_set_var_objid(newvar, var->name, var->name_length)) 00257 return 1; 00258 00259 /* 00260 * need a pointer to copy a string value. 00261 */ 00262 if (var->val.string) { 00263 if (var->val.string != &var->buf[0]) { 00264 if (var->val_len <= sizeof(var->buf)) 00265 newvar->val.string = newvar->buf; 00266 else { 00267 newvar->val.string = (u_char *) malloc(var->val_len); 00268 if (!newvar->val.string) 00269 return 1; 00270 } 00271 memmove(newvar->val.string, var->val.string, var->val_len); 00272 } else { /* fix the pointer to new local store */ 00273 newvar->val.string = newvar->buf; 00274 /* 00275 * no need for a memmove, since we copied the whole var 00276 * struct (and thus var->buf) at the beginning of this function. 00277 */ 00278 } 00279 } else { 00280 newvar->val.string = NULL; 00281 newvar->val_len = 0; 00282 } 00283 00284 return 0; 00285 } 00286 00287 00288 /* 00289 * Possibly make a copy of source memory buffer. 00290 * Will reset destination pointer if source pointer is NULL. 00291 * Returns 0 if successful, 1 if memory allocation fails. 00292 */ 00293 int 00294 snmp_clone_mem(void **dstPtr, const void *srcPtr, unsigned len) 00295 { 00296 *dstPtr = NULL; 00297 if (srcPtr) { 00298 *dstPtr = malloc(len + 1); 00299 if (!*dstPtr) { 00300 return 1; 00301 } 00302 memmove(*dstPtr, srcPtr, len); 00303 /* 00304 * this is for those routines that expect 0-terminated strings!!! 00305 * someone should rather have called strdup 00306 */ 00307 ((char *) *dstPtr)[len] = 0; 00308 } 00309 return 0; 00310 } 00311 00312 00313 /* 00314 * Walks through a list of varbinds and frees and allocated memory, 00315 * restoring pointers to local buffers 00316 */ 00317 void 00318 snmp_reset_var_buffers(netsnmp_variable_list * var) 00319 { 00320 while (var) { 00321 if (var->name != var->name_loc) { 00322 if(NULL != var->name) 00323 free(var->name); 00324 var->name = var->name_loc; 00325 var->name_length = 0; 00326 } 00327 if (var->val.string != var->buf) { 00328 if (NULL != var->val.string) 00329 free(var->val.string); 00330 var->val.string = var->buf; 00331 var->val_len = 0; 00332 } 00333 var = var->next_variable; 00334 } 00335 } 00336 00337 /* 00338 * Creates and allocates a clone of the input PDU, 00339 * but does NOT copy the variables. 00340 * This function should be used with another function, 00341 * such as _copy_pdu_vars. 00342 * 00343 * Returns a pointer to the cloned PDU if successful. 00344 * Returns 0 if failure. 00345 */ 00346 static 00347 netsnmp_pdu * 00348 _clone_pdu_header(netsnmp_pdu *pdu) 00349 { 00350 netsnmp_pdu *newpdu; 00351 struct snmp_secmod_def *sptr; 00352 00353 newpdu = (netsnmp_pdu *) malloc(sizeof(netsnmp_pdu)); 00354 if (!newpdu) 00355 return NULL; 00356 memmove(newpdu, pdu, sizeof(netsnmp_pdu)); 00357 00358 /* 00359 * reset copied pointers if copy fails 00360 */ 00361 newpdu->variables = NULL; 00362 newpdu->enterprise = NULL; 00363 newpdu->community = NULL; 00364 newpdu->securityEngineID = NULL; 00365 newpdu->securityName = NULL; 00366 newpdu->contextEngineID = NULL; 00367 newpdu->contextName = NULL; 00368 newpdu->transport_data = NULL; 00369 00370 /* 00371 * copy buffers individually. If any copy fails, all are freed. 00372 */ 00373 if (snmp_clone_mem((void **) &newpdu->enterprise, pdu->enterprise, 00374 sizeof(oid) * pdu->enterprise_length) || 00375 snmp_clone_mem((void **) &newpdu->community, pdu->community, 00376 pdu->community_len) || 00377 snmp_clone_mem((void **) &newpdu->contextEngineID, 00378 pdu->contextEngineID, pdu->contextEngineIDLen) 00379 || snmp_clone_mem((void **) &newpdu->securityEngineID, 00380 pdu->securityEngineID, pdu->securityEngineIDLen) 00381 || snmp_clone_mem((void **) &newpdu->contextName, pdu->contextName, 00382 pdu->contextNameLen) 00383 || snmp_clone_mem((void **) &newpdu->securityName, 00384 pdu->securityName, pdu->securityNameLen) 00385 || snmp_clone_mem((void **) &newpdu->transport_data, 00386 pdu->transport_data, 00387 pdu->transport_data_length)) { 00388 snmp_free_pdu(newpdu); 00389 return NULL; 00390 } 00391 if ((sptr = find_sec_mod(newpdu->securityModel)) != NULL && 00392 sptr->pdu_clone != NULL) { 00393 /* 00394 * call security model if it needs to know about this 00395 */ 00396 (*sptr->pdu_clone) (pdu, newpdu); 00397 } 00398 00399 return newpdu; 00400 } 00401 00402 static 00403 netsnmp_variable_list * 00404 _copy_varlist(netsnmp_variable_list * var, /* source varList */ 00405 int errindex, /* index of variable to drop (if any) */ 00406 int copy_count) 00407 { /* !=0 number variables to copy */ 00408 netsnmp_variable_list *newhead, *newvar, *oldvar; 00409 int ii = 0; 00410 00411 newhead = NULL; 00412 oldvar = NULL; 00413 00414 while (var && (copy_count-- > 0)) { 00415 /* 00416 * Drop the specified variable (if applicable) 00417 */ 00418 if (++ii == errindex) { 00419 var = var->next_variable; 00420 continue; 00421 } 00422 00423 /* 00424 * clone the next variable. Cleanup if alloc fails 00425 */ 00426 newvar = (netsnmp_variable_list *) 00427 malloc(sizeof(netsnmp_variable_list)); 00428 if (snmp_clone_var(var, newvar)) { 00429 if (newvar) 00430 free((char *) newvar); 00431 snmp_free_varbind(newhead); 00432 return NULL; 00433 } 00434 00435 /* 00436 * add cloned variable to new list 00437 */ 00438 if (NULL == newhead) 00439 newhead = newvar; 00440 if (oldvar) 00441 oldvar->next_variable = newvar; 00442 oldvar = newvar; 00443 00444 var = var->next_variable; 00445 } 00446 return newhead; 00447 } 00448 00449 00450 /* 00451 * Copy some or all variables from source PDU to target PDU. 00452 * This function consolidates many of the needs of PDU variables: 00453 * Clone PDU : copy all the variables. 00454 * Split PDU : skip over some variables to copy other variables. 00455 * Fix PDU : remove variable associated with error index. 00456 * 00457 * Designed to work with _clone_pdu_header. 00458 * 00459 * If drop_err is set, drop any variable associated with errindex. 00460 * If skip_count is set, skip the number of variable in pdu's list. 00461 * While copy_count is greater than zero, copy pdu variables to newpdu. 00462 * 00463 * If an error occurs, newpdu is freed and pointer is set to 0. 00464 * 00465 * Returns a pointer to the cloned PDU if successful. 00466 * Returns 0 if failure. 00467 */ 00468 static 00469 netsnmp_pdu * 00470 _copy_pdu_vars(netsnmp_pdu *pdu, /* source PDU */ 00471 netsnmp_pdu *newpdu, /* target PDU */ 00472 int drop_err, /* !=0 drop errored variable */ 00473 int skip_count, /* !=0 number of variables to skip */ 00474 int copy_count) 00475 { /* !=0 number of variables to copy */ 00476 netsnmp_variable_list *var, *oldvar; 00477 int ii, copied, drop_idx; 00478 00479 if (!newpdu) 00480 return NULL; /* where is PDU to copy to ? */ 00481 00482 if (drop_err) 00483 drop_idx = pdu->errindex - skip_count; 00484 else 00485 drop_idx = 0; 00486 00487 var = pdu->variables; 00488 while (var && (skip_count-- > 0)) /* skip over pdu variables */ 00489 var = var->next_variable; 00490 00491 oldvar = NULL; 00492 ii = 0; 00493 copied = 0; 00494 if (pdu->flags & UCD_MSG_FLAG_FORCE_PDU_COPY) 00495 copied = 1; /* We're interested in 'empty' responses too */ 00496 00497 newpdu->variables = _copy_varlist(var, drop_idx, copy_count); 00498 if (newpdu->variables) 00499 copied = 1; 00500 00501 #if ALSO_TEMPORARILY_DISABLED 00502 /* 00503 * Error if bad errindex or if target PDU has no variables copied 00504 */ 00505 if ((drop_err && (ii < pdu->errindex)) 00506 #if TEMPORARILY_DISABLED 00507 /* 00508 * SNMPv3 engineID probes are allowed to be empty. 00509 * See the comment in snmp_api.c for further details 00510 */ 00511 || copied == 0 00512 #endif 00513 ) { 00514 snmp_free_pdu(newpdu); 00515 return 0; 00516 } 00517 #endif 00518 return newpdu; 00519 } 00520 00521 00522 /* 00523 * Creates (allocates and copies) a clone of the input PDU. 00524 * If drop_err is set, don't copy any variable associated with errindex. 00525 * This function is called by snmp_clone_pdu and snmp_fix_pdu. 00526 * 00527 * Returns a pointer to the cloned PDU if successful. 00528 * Returns 0 if failure. 00529 */ 00530 static 00531 netsnmp_pdu * 00532 _clone_pdu(netsnmp_pdu *pdu, int drop_err) 00533 { 00534 netsnmp_pdu *newpdu; 00535 newpdu = _clone_pdu_header(pdu); 00536 newpdu = _copy_pdu_vars(pdu, newpdu, drop_err, 0, 10000); /* skip none, copy all */ 00537 00538 return newpdu; 00539 } 00540 00541 00542 /* 00543 * This function will clone a full varbind list 00544 * 00545 * Returns a pointer to the cloned varbind list if successful. 00546 * Returns 0 if failure 00547 */ 00548 netsnmp_variable_list * 00549 snmp_clone_varbind(netsnmp_variable_list * varlist) 00550 { 00551 return _copy_varlist(varlist, 0, 10000); /* skip none, copy all */ 00552 } 00553 00554 /* 00555 * This function will clone a PDU including all of its variables. 00556 * 00557 * Returns a pointer to the cloned PDU if successful. 00558 * Returns 0 if failure 00559 */ 00560 netsnmp_pdu * 00561 snmp_clone_pdu(netsnmp_pdu *pdu) 00562 { 00563 return _clone_pdu(pdu, 0); /* copies all variables */ 00564 } 00565 00566 00567 /* 00568 * This function will clone a PDU including some of its variables. 00569 * 00570 * If skip_count is not zero, it defines the number of variables to skip. 00571 * If copy_count is not zero, it defines the number of variables to copy. 00572 * 00573 * Returns a pointer to the cloned PDU if successful. 00574 * Returns 0 if failure. 00575 */ 00576 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_SPLIT_PDU 00577 netsnmp_pdu * 00578 snmp_split_pdu(netsnmp_pdu *pdu, int skip_count, int copy_count) 00579 { 00580 netsnmp_pdu *newpdu; 00581 newpdu = _clone_pdu_header(pdu); 00582 newpdu = _copy_pdu_vars(pdu, newpdu, 0, /* don't drop any variables */ 00583 skip_count, copy_count); 00584 00585 return newpdu; 00586 } 00587 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_SPLIT_PDU */ 00588 00589 00590 /* 00591 * If there was an error in the input pdu, creates a clone of the pdu 00592 * that includes all the variables except the one marked by the errindex. 00593 * The command is set to the input command and the reqid, errstat, and 00594 * errindex are set to default values. 00595 * If the error status didn't indicate an error, the error index didn't 00596 * indicate a variable, the pdu wasn't a get response message, the 00597 * marked variable was not present in the initial request, or there 00598 * would be no remaining variables, this function will return 0. 00599 * If everything was successful, a pointer to the fixed cloned pdu will 00600 * be returned. 00601 */ 00602 netsnmp_pdu * 00603 snmp_fix_pdu(netsnmp_pdu *pdu, int command) 00604 { 00605 netsnmp_pdu *newpdu; 00606 00607 if ((pdu->command != SNMP_MSG_RESPONSE) 00608 || (pdu->errstat == SNMP_ERR_NOERROR) 00609 || (NULL == pdu->variables) 00610 || (pdu->errindex > (int)snmp_varbind_len(pdu)) 00611 || (pdu->errindex <= 0)) { 00612 return NULL; /* pre-condition tests fail */ 00613 } 00614 00615 newpdu = _clone_pdu(pdu, 1); /* copies all except errored variable */ 00616 if (!newpdu) 00617 return NULL; 00618 if (!newpdu->variables) { 00619 snmp_free_pdu(newpdu); 00620 return NULL; /* no variables. "should not happen" */ 00621 } 00622 newpdu->command = command; 00623 newpdu->reqid = snmp_get_next_reqid(); 00624 newpdu->msgid = snmp_get_next_msgid(); 00625 newpdu->errstat = SNMP_DEFAULT_ERRSTAT; 00626 newpdu->errindex = SNMP_DEFAULT_ERRINDEX; 00627 00628 return newpdu; 00629 } 00630 00631 00632 /* 00633 * Returns the number of variables bound to a PDU structure 00634 */ 00635 unsigned long 00636 snmp_varbind_len(netsnmp_pdu *pdu) 00637 { 00638 register netsnmp_variable_list *vars; 00639 unsigned long retVal = 0; 00640 if (pdu) 00641 for (vars = pdu->variables; vars; vars = vars->next_variable) { 00642 retVal++; 00643 } 00644 00645 return retVal; 00646 } 00647 00648 /* 00649 * Add object identifier name to SNMP variable. 00650 * If the name is large, additional memory is allocated. 00651 * Returns 0 if successful. 00652 */ 00653 00654 int 00655 snmp_set_var_objid(netsnmp_variable_list * vp, 00656 const oid * objid, size_t name_length) 00657 { 00658 size_t len = sizeof(oid) * name_length; 00659 00660 if (vp->name != vp->name_loc && vp->name != NULL) { 00661 /* 00662 * Probably previously-allocated "big storage". Better free it 00663 * else memory leaks possible. 00664 */ 00665 free(vp->name); 00666 } 00667 00668 /* 00669 * use built-in storage for smaller values 00670 */ 00671 if (len <= sizeof(vp->name_loc)) { 00672 vp->name = vp->name_loc; 00673 } else { 00674 vp->name = (oid *) malloc(len); 00675 if (!vp->name) 00676 return 1; 00677 } 00678 if (objid) 00679 memmove(vp->name, objid, len); 00680 vp->name_length = name_length; 00681 return 0; 00682 } 00683 00699 int 00700 snmp_set_var_typed_value(netsnmp_variable_list * newvar, u_char type, 00701 const void * val_str, size_t val_len) 00702 { 00703 newvar->type = type; 00704 return snmp_set_var_value(newvar, val_str, val_len); 00705 } 00706 00707 int 00708 snmp_set_var_typed_integer(netsnmp_variable_list * newvar, 00709 u_char type, long val) 00710 { 00711 newvar->type = type; 00712 return snmp_set_var_value(newvar, &val, sizeof(long)); 00713 } 00714 00715 int 00716 count_varbinds(netsnmp_variable_list * var_ptr) 00717 { 00718 int count = 0; 00719 00720 for (; var_ptr != NULL; var_ptr = var_ptr->next_variable) 00721 count++; 00722 00723 return count; 00724 } 00725 00726 netsnmp_feature_child_of(count_varbinds_of_type, netsnmp_unused) 00727 #ifndef NETSNMP_FEATURE_REMOVE_COUNT_VARBINDS_OF_TYPE 00728 int 00729 count_varbinds_of_type(netsnmp_variable_list * var_ptr, u_char type) 00730 { 00731 int count = 0; 00732 00733 for (; var_ptr != NULL; var_ptr = var_ptr->next_variable) 00734 if (var_ptr->type == type) 00735 count++; 00736 00737 return count; 00738 } 00739 #endif /* NETSNMP_FEATURE_REMOVE_COUNT_VARBINDS_OF_TYPE */ 00740 00741 netsnmp_feature_child_of(find_varind_of_type, netsnmp_unused) 00742 #ifndef NETSNMP_FEATURE_REMOVE_FIND_VARIND_OF_TYPE 00743 netsnmp_variable_list * 00744 find_varbind_of_type(netsnmp_variable_list * var_ptr, u_char type) 00745 { 00746 for (; var_ptr != NULL && var_ptr->type != type; 00747 var_ptr = var_ptr->next_variable); 00748 00749 return var_ptr; 00750 } 00751 #endif /* NETSNMP_FEATURE_REMOVE_FIND_VARIND_OF_TYPE */ 00752 00753 netsnmp_variable_list* 00754 find_varbind_in_list( netsnmp_variable_list *vblist, 00755 const oid *name, size_t len) 00756 { 00757 for (; vblist != NULL; vblist = vblist->next_variable) 00758 if (!snmp_oid_compare(vblist->name, vblist->name_length, name, len)) 00759 return vblist; 00760 00761 return NULL; 00762 } 00763 00764 /* 00765 * Add some value to SNMP variable. 00766 * If the value is large, additional memory is allocated. 00767 * Returns 0 if successful. 00768 */ 00769 00770 int 00771 snmp_set_var_value(netsnmp_variable_list * vars, 00772 const void * value, size_t len) 00773 { 00774 int largeval = 1; 00775 00776 /* 00777 * xxx-rks: why the unconditional free? why not use existing 00778 * memory, if len < vars->val_len ? 00779 */ 00780 if (vars->val.string && vars->val.string != vars->buf) { 00781 free(vars->val.string); 00782 } 00783 vars->val.string = NULL; 00784 vars->val_len = 0; 00785 00786 /* 00787 * use built-in storage for smaller values 00788 */ 00789 if (len <= sizeof(vars->buf)) { 00790 vars->val.string = (u_char *) vars->buf; 00791 largeval = 0; 00792 } 00793 00794 if ((0 == len) || (NULL == value)) { 00795 vars->val.string[0] = 0; 00796 return 0; 00797 } 00798 00799 vars->val_len = len; 00800 switch (vars->type) { 00801 case ASN_INTEGER: 00802 case ASN_UNSIGNED: 00803 case ASN_TIMETICKS: 00804 case ASN_COUNTER: 00805 if (value) { 00806 if (vars->val_len == sizeof(int)) { 00807 if (ASN_INTEGER == vars->type) { 00808 const int *val_int 00809 = (const int *) value; 00810 *(vars->val.integer) = (long) *val_int; 00811 } else { 00812 const u_int *val_uint 00813 = (const u_int *) value; 00814 *(vars->val.integer) = (unsigned long) *val_uint; 00815 } 00816 } 00817 #if SIZEOF_LONG != SIZEOF_INT 00818 else if (vars->val_len == sizeof(long)){ 00819 const u_long *val_ulong 00820 = (const u_long *) value; 00821 *(vars->val.integer) = *val_ulong; 00822 if (*(vars->val.integer) > 0xffffffff) { 00823 snmp_log(LOG_ERR,"truncating integer value > 32 bits\n"); 00824 *(vars->val.integer) &= 0xffffffff; 00825 } 00826 } 00827 #endif 00828 #if defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG != SIZEOF_LONG_LONG) 00829 #if !defined(SIZEOF_INTMAX_T) || (SIZEOF_LONG_LONG != SIZEOF_INTMAX_T) 00830 else if (vars->val_len == sizeof(long long)){ 00831 const unsigned long long *val_ullong 00832 = (const unsigned long long *) value; 00833 *(vars->val.integer) = (long) *val_ullong; 00834 if (*(vars->val.integer) > 0xffffffff) { 00835 snmp_log(LOG_ERR,"truncating integer value > 32 bits\n"); 00836 *(vars->val.integer) &= 0xffffffff; 00837 } 00838 } 00839 #endif 00840 #endif 00841 #if defined(SIZEOF_INTMAX_T) && (SIZEOF_LONG != SIZEOF_INTMAX_T) 00842 else if (vars->val_len == sizeof(intmax_t)){ 00843 const uintmax_t *val_uintmax_t 00844 = (const uintmax_t *) value; 00845 *(vars->val.integer) = (long) *val_uintmax_t; 00846 if (*(vars->val.integer) > 0xffffffff) { 00847 snmp_log(LOG_ERR,"truncating integer value > 32 bits\n"); 00848 *(vars->val.integer) &= 0xffffffff; 00849 } 00850 } 00851 #endif 00852 #if SIZEOF_SHORT != SIZEOF_INT 00853 else if (vars->val_len == sizeof(short)) { 00854 if (ASN_INTEGER == vars->type) { 00855 const short *val_short 00856 = (const short *) value; 00857 *(vars->val.integer) = (long) *val_short; 00858 } else { 00859 const u_short *val_ushort 00860 = (const u_short *) value; 00861 *(vars->val.integer) = (unsigned long) *val_ushort; 00862 } 00863 } 00864 #endif 00865 else if (vars->val_len == sizeof(char)) { 00866 if (ASN_INTEGER == vars->type) { 00867 const char *val_char 00868 = (const char *) value; 00869 *(vars->val.integer) = (long) *val_char; 00870 } else { 00871 const u_char *val_uchar 00872 = (const u_char *) value; 00873 *(vars->val.integer) = (unsigned long) *val_uchar; 00874 } 00875 } 00876 else { 00877 snmp_log(LOG_ERR,"bad size for integer-like type (%d)\n", 00878 (int)vars->val_len); 00879 return (1); 00880 } 00881 } else 00882 *(vars->val.integer) = 0; 00883 vars->val_len = sizeof(long); 00884 break; 00885 00886 case ASN_OBJECT_ID: 00887 case ASN_PRIV_IMPLIED_OBJECT_ID: 00888 case ASN_PRIV_INCL_RANGE: 00889 case ASN_PRIV_EXCL_RANGE: 00890 if (largeval) { 00891 vars->val.objid = (oid *) malloc(vars->val_len); 00892 } 00893 if (vars->val.objid == NULL) { 00894 snmp_log(LOG_ERR,"no storage for OID\n"); 00895 return 1; 00896 } 00897 memmove(vars->val.objid, value, vars->val_len); 00898 break; 00899 00900 case ASN_IPADDRESS: /* snmp_build_var_op treats IPADDR like a string */ 00901 if (4 != vars->val_len) { 00902 netsnmp_assert("ipaddress length == 4"); 00903 } 00905 case ASN_PRIV_IMPLIED_OCTET_STR: 00906 case ASN_OCTET_STR: 00907 case ASN_BIT_STR: 00908 case ASN_OPAQUE: 00909 case ASN_NSAP: 00910 if (vars->val_len >= sizeof(vars->buf)) { 00911 vars->val.string = (u_char *) malloc(vars->val_len + 1); 00912 } 00913 if (vars->val.string == NULL) { 00914 snmp_log(LOG_ERR,"no storage for string\n"); 00915 return 1; 00916 } 00917 memmove(vars->val.string, value, vars->val_len); 00918 /* 00919 * Make sure the string is zero-terminated; some bits of code make 00920 * this assumption. Easier to do this here than fix all these wrong 00921 * assumptions. 00922 */ 00923 vars->val.string[vars->val_len] = '\0'; 00924 break; 00925 00926 case SNMP_NOSUCHOBJECT: 00927 case SNMP_NOSUCHINSTANCE: 00928 case SNMP_ENDOFMIBVIEW: 00929 case ASN_NULL: 00930 vars->val_len = 0; 00931 vars->val.string = NULL; 00932 break; 00933 00934 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 00935 case ASN_OPAQUE_U64: 00936 case ASN_OPAQUE_I64: 00937 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 00938 case ASN_COUNTER64: 00939 if (largeval) { 00940 snmp_log(LOG_ERR,"bad size for counter 64 (%d)\n", 00941 (int)vars->val_len); 00942 return (1); 00943 } 00944 vars->val_len = sizeof(struct counter64); 00945 memmove(vars->val.counter64, value, vars->val_len); 00946 break; 00947 00948 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 00949 case ASN_OPAQUE_FLOAT: 00950 if (largeval) { 00951 snmp_log(LOG_ERR,"bad size for opaque float (%d)\n", 00952 (int)vars->val_len); 00953 return (1); 00954 } 00955 vars->val_len = sizeof(float); 00956 memmove(vars->val.floatVal, value, vars->val_len); 00957 break; 00958 00959 case ASN_OPAQUE_DOUBLE: 00960 if (largeval) { 00961 snmp_log(LOG_ERR,"bad size for opaque double (%d)\n", 00962 (int)vars->val_len); 00963 return (1); 00964 } 00965 vars->val_len = sizeof(double); 00966 memmove(vars->val.doubleVal, value, vars->val_len); 00967 break; 00968 00969 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 00970 00971 default: 00972 snmp_log(LOG_ERR,"Internal error in type switching\n"); 00973 snmp_set_detail("Internal error in type switching\n"); 00974 return (1); 00975 } 00976 00977 return 0; 00978 } 00979 00980 void 00981 snmp_replace_var_types(netsnmp_variable_list * vbl, u_char old_type, 00982 u_char new_type) 00983 { 00984 while (vbl) { 00985 if (vbl->type == old_type) { 00986 snmp_set_var_typed_value(vbl, new_type, NULL, 0); 00987 } 00988 vbl = vbl->next_variable; 00989 } 00990 } 00991 00992 #ifndef NETSNMP_FEATURE_REMOVE_SNMP_RESET_VAR_TYPES 00993 void 00994 snmp_reset_var_types(netsnmp_variable_list * vbl, u_char new_type) 00995 { 00996 while (vbl) { 00997 snmp_set_var_typed_value(vbl, new_type, NULL, 0); 00998 vbl = vbl->next_variable; 00999 } 01000 } 01001 #endif /* NETSNMP_FEATURE_REMOVE_SNMP_RESET_VAR_TYPES */ 01002 01003 int 01004 snmp_synch_response_cb(netsnmp_session * ss, 01005 netsnmp_pdu *pdu, 01006 netsnmp_pdu **response, snmp_callback pcb) 01007 { 01008 struct synch_state lstate, *state; 01009 snmp_callback cbsav; 01010 void *cbmagsav; 01011 int numfds, count; 01012 fd_set fdset; 01013 struct timeval timeout, *tvp; 01014 int block; 01015 01016 memset((void *) &lstate, 0, sizeof(lstate)); 01017 state = &lstate; 01018 cbsav = ss->callback; 01019 cbmagsav = ss->callback_magic; 01020 ss->callback = pcb; 01021 ss->callback_magic = (void *) state; 01022 01023 if ((state->reqid = snmp_send(ss, pdu)) == 0) { 01024 snmp_free_pdu(pdu); 01025 state->status = STAT_ERROR; 01026 } else 01027 state->waiting = 1; 01028 01029 while (state->waiting) { 01030 numfds = 0; 01031 FD_ZERO(&fdset); 01032 block = NETSNMP_SNMPBLOCK; 01033 tvp = &timeout; 01034 timerclear(tvp); 01035 snmp_sess_select_info_flags(0, &numfds, &fdset, tvp, &block, 01036 NETSNMP_SELECT_NOALARMS); 01037 if (block == 1) 01038 tvp = NULL; /* block without timeout */ 01039 count = select(numfds, &fdset, NULL, NULL, tvp); 01040 if (count > 0) { 01041 snmp_read(&fdset); 01042 } else { 01043 switch (count) { 01044 case 0: 01045 snmp_timeout(); 01046 break; 01047 case -1: 01048 if (errno == EINTR) { 01049 continue; 01050 } else { 01051 snmp_errno = SNMPERR_GENERR; /*MTCRITICAL_RESOURCE */ 01052 /* 01053 * CAUTION! if another thread closed the socket(s) 01054 * waited on here, the session structure was freed. 01055 * It would be nice, but we can't rely on the pointer. 01056 * ss->s_snmp_errno = SNMPERR_GENERR; 01057 * ss->s_errno = errno; 01058 */ 01059 snmp_set_detail(strerror(errno)); 01060 } 01061 /* 01062 * FALLTHRU 01063 */ 01064 default: 01065 state->status = STAT_ERROR; 01066 state->waiting = 0; 01067 } 01068 } 01069 01070 if ( ss->flags & SNMP_FLAGS_RESP_CALLBACK ) { 01071 void (*cb)(void); 01072 cb = (void (*)(void))(ss->myvoid); 01073 cb(); /* Used to invoke 'netsnmp_check_outstanding_agent_requests();' 01074 on internal AgentX queries. */ 01075 } 01076 } 01077 *response = state->pdu; 01078 ss->callback = cbsav; 01079 ss->callback_magic = cbmagsav; 01080 return state->status; 01081 } 01082 01083 int 01084 snmp_synch_response(netsnmp_session * ss, 01085 netsnmp_pdu *pdu, netsnmp_pdu **response) 01086 { 01087 return snmp_synch_response_cb(ss, pdu, response, snmp_synch_input); 01088 } 01089 01090 int 01091 snmp_sess_synch_response(void *sessp, 01092 netsnmp_pdu *pdu, netsnmp_pdu **response) 01093 { 01094 netsnmp_session *ss; 01095 struct synch_state lstate, *state; 01096 snmp_callback cbsav; 01097 void *cbmagsav; 01098 int numfds, count; 01099 fd_set fdset; 01100 struct timeval timeout, *tvp; 01101 int block; 01102 01103 ss = snmp_sess_session(sessp); 01104 if (ss == NULL) { 01105 return STAT_ERROR; 01106 } 01107 01108 memset((void *) &lstate, 0, sizeof(lstate)); 01109 state = &lstate; 01110 cbsav = ss->callback; 01111 cbmagsav = ss->callback_magic; 01112 ss->callback = snmp_synch_input; 01113 ss->callback_magic = (void *) state; 01114 01115 if ((state->reqid = snmp_sess_send(sessp, pdu)) == 0) { 01116 snmp_free_pdu(pdu); 01117 state->status = STAT_ERROR; 01118 } else 01119 state->waiting = 1; 01120 01121 while (state->waiting) { 01122 numfds = 0; 01123 FD_ZERO(&fdset); 01124 block = NETSNMP_SNMPBLOCK; 01125 tvp = &timeout; 01126 timerclear(tvp); 01127 snmp_sess_select_info_flags(sessp, &numfds, &fdset, tvp, &block, 01128 NETSNMP_SELECT_NOALARMS); 01129 if (block == 1) 01130 tvp = NULL; /* block without timeout */ 01131 count = select(numfds, &fdset, NULL, NULL, tvp); 01132 if (count > 0) { 01133 snmp_sess_read(sessp, &fdset); 01134 } else 01135 switch (count) { 01136 case 0: 01137 snmp_sess_timeout(sessp); 01138 break; 01139 case -1: 01140 if (errno == EINTR) { 01141 continue; 01142 } else { 01143 snmp_errno = SNMPERR_GENERR; /*MTCRITICAL_RESOURCE */ 01144 /* 01145 * CAUTION! if another thread closed the socket(s) 01146 * waited on here, the session structure was freed. 01147 * It would be nice, but we can't rely on the pointer. 01148 * ss->s_snmp_errno = SNMPERR_GENERR; 01149 * ss->s_errno = errno; 01150 */ 01151 snmp_set_detail(strerror(errno)); 01152 } 01153 /* 01154 * FALLTHRU 01155 */ 01156 default: 01157 state->status = STAT_ERROR; 01158 state->waiting = 0; 01159 } 01160 } 01161 *response = state->pdu; 01162 ss->callback = cbsav; 01163 ss->callback_magic = cbmagsav; 01164 return state->status; 01165 } 01166 01167 01168 const char * 01169 snmp_errstring(int errstat) 01170 { 01171 const char * const error_string[19] = { 01172 "(noError) No Error", 01173 "(tooBig) Response message would have been too large.", 01174 "(noSuchName) There is no such variable name in this MIB.", 01175 "(badValue) The value given has the wrong type or length.", 01176 "(readOnly) The two parties used do not have access to use the specified SNMP PDU.", 01177 "(genError) A general failure occured", 01178 "noAccess", 01179 "wrongType (The set datatype does not match the data type the agent expects)", 01180 "wrongLength (The set value has an illegal length from what the agent expects)", 01181 "wrongEncoding", 01182 "wrongValue (The set value is illegal or unsupported in some way)", 01183 "noCreation (That table does not support row creation or that object can not ever be created)", 01184 "inconsistentValue (The set value is illegal or unsupported in some way)", 01185 "resourceUnavailable (This is likely a out-of-memory failure within the agent)", 01186 "commitFailed", 01187 "undoFailed", 01188 "authorizationError (access denied to that object)", 01189 "notWritable (That object does not support modification)", 01190 "inconsistentName (That object can not currently be created)" 01191 }; 01192 01193 if (errstat <= MAX_SNMP_ERR && errstat >= SNMP_ERR_NOERROR) { 01194 return error_string[errstat]; 01195 } else { 01196 return "Unknown Error"; 01197 } 01198 } 01199 01200 01201 01202 /* 01203 * 01204 * Convenience routines to make various requests 01205 * over the specified SNMP session. 01206 * 01207 */ 01208 #include <net-snmp/library/snmp_debug.h> 01209 01210 static netsnmp_session *_def_query_session = NULL; 01211 01212 #ifndef NETSNMP_FEATURE_REMOVE_QUERY_SET_DEFAULT_SESSION 01213 void 01214 netsnmp_query_set_default_session( netsnmp_session *sess) { 01215 DEBUGMSGTL(("iquery", "set default session %p\n", sess)); 01216 _def_query_session = sess; 01217 } 01218 #endif /* NETSNMP_FEATURE_REMOVE_QUERY_SET_DEFAULT_SESSION */ 01219 01223 netsnmp_session * 01224 netsnmp_query_get_default_session_unchecked( void ) { 01225 DEBUGMSGTL(("iquery", "get default session %p\n", _def_query_session)); 01226 return _def_query_session; 01227 } 01228 01233 netsnmp_session * 01234 netsnmp_query_get_default_session( void ) { 01235 static int warning_logged = 0; 01236 01237 if (! _def_query_session && ! warning_logged) { 01238 if (! netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 01239 NETSNMP_DS_AGENT_INTERNAL_SECNAME)) { 01240 snmp_log(LOG_WARNING, 01241 "iquerySecName has not been configured - internal queries will fail\n"); 01242 } else { 01243 snmp_log(LOG_WARNING, 01244 "default session is not available - internal queries will fail\n"); 01245 } 01246 warning_logged = 1; 01247 } 01248 01249 return netsnmp_query_get_default_session_unchecked(); 01250 } 01251 01252 01253 /* 01254 * Internal utility routine to actually send the query 01255 */ 01256 static int _query(netsnmp_variable_list *list, 01257 int request, 01258 netsnmp_session *session) { 01259 01260 netsnmp_pdu *pdu = snmp_pdu_create( request ); 01261 netsnmp_pdu *response = NULL; 01262 netsnmp_variable_list *vb1, *vb2, *vtmp; 01263 int ret, count; 01264 01265 DEBUGMSGTL(("iquery", "query on session %p\n", session)); 01266 /* 01267 * Clone the varbind list into the request PDU... 01268 */ 01269 pdu->variables = snmp_clone_varbind( list ); 01270 retry: 01271 if ( session ) 01272 ret = snmp_synch_response( session, pdu, &response ); 01273 else if (_def_query_session) 01274 ret = snmp_synch_response( _def_query_session, pdu, &response ); 01275 else { 01276 /* No session specified */ 01277 snmp_free_pdu(pdu); 01278 return SNMP_ERR_GENERR; 01279 } 01280 DEBUGMSGTL(("iquery", "query returned %d\n", ret)); 01281 01282 /* 01283 * ....then copy the results back into the 01284 * list (assuming the request succeeded!). 01285 * This avoids having to worry about how this 01286 * list was originally allocated. 01287 */ 01288 if ( ret == SNMP_ERR_NOERROR ) { 01289 if ( response->errstat != SNMP_ERR_NOERROR ) { 01290 DEBUGMSGT(("iquery", "Error in packet: %s\n", 01291 snmp_errstring(response->errstat))); 01292 /* 01293 * If the request failed, then remove the 01294 * offending varbind and try again. 01295 * (all except SET requests) 01296 * 01297 * XXX - implement a library version of 01298 * NETSNMP_DS_APP_DONT_FIX_PDUS ?? 01299 */ 01300 ret = response->errstat; 01301 if (response->errindex != 0) { 01302 DEBUGMSGT(("iquery:result", "Failed object:\n")); 01303 for (count = 1, vtmp = response->variables; 01304 vtmp && count != response->errindex; 01305 vtmp = vtmp->next_variable, count++) 01306 /*EMPTY*/; 01307 if (vtmp) 01308 DEBUGMSGVAR(("iquery:result", vtmp)); 01309 DEBUGMSG(("iquery:result", "\n")); 01310 } 01311 #ifndef NETSNMP_NO_WRITE_SUPPORT 01312 if (request != SNMP_MSG_SET && 01313 response->errindex != 0) { 01314 DEBUGMSGTL(("iquery", "retrying query (%d, %ld)\n", ret, response->errindex)); 01315 pdu = snmp_fix_pdu( response, request ); 01316 snmp_free_pdu( response ); 01317 response = NULL; 01318 if ( pdu != NULL ) 01319 goto retry; 01320 } 01321 #endif /* !NETSNMP_NO_WRITE_SUPPORT */ 01322 } else { 01323 for (vb1 = response->variables, vb2 = list; 01324 vb1; 01325 vb1 = vb1->next_variable, vb2 = vb2->next_variable) { 01326 DEBUGMSGVAR(("iquery:result", vb1)); 01327 DEBUGMSG(("iquery:results", "\n")); 01328 if ( !vb2 ) { 01329 ret = SNMP_ERR_GENERR; 01330 break; 01331 } 01332 vtmp = vb2->next_variable; 01333 snmp_free_var_internals( vb2 ); 01334 snmp_clone_var( vb1, vb2 ); 01335 vb2->next_variable = vtmp; 01336 } 01337 } 01338 } else { 01339 /* Distinguish snmp_send errors from SNMP errStat errors */ 01340 ret = -ret; 01341 } 01342 snmp_free_pdu( response ); 01343 return ret; 01344 } 01345 01346 /* 01347 * These are simple wrappers round the internal utility routine 01348 */ 01349 int netsnmp_query_get(netsnmp_variable_list *list, 01350 netsnmp_session *session){ 01351 return _query( list, SNMP_MSG_GET, session ); 01352 } 01353 01354 01355 int netsnmp_query_getnext(netsnmp_variable_list *list, 01356 netsnmp_session *session){ 01357 return _query( list, SNMP_MSG_GETNEXT, session ); 01358 } 01359 01360 01361 #ifndef NETSNMP_NO_WRITE_SUPPORT 01362 int netsnmp_query_set(netsnmp_variable_list *list, 01363 netsnmp_session *session){ 01364 return _query( list, SNMP_MSG_SET, session ); 01365 } 01366 #endif /* !NETSNMP_NO_WRITE_SUPPORT */ 01367 01368 /* 01369 * A walk needs a bit more work. 01370 */ 01371 int netsnmp_query_walk(netsnmp_variable_list *list, 01372 netsnmp_session *session) { 01373 /* 01374 * Create a working copy of the original (single) 01375 * varbind, so we can use this varbind parameter 01376 * to check when we've finished walking this subtree. 01377 */ 01378 netsnmp_variable_list *vb = snmp_clone_varbind( list ); 01379 netsnmp_variable_list *res_list = NULL; 01380 netsnmp_variable_list *res_last = NULL; 01381 int ret; 01382 01383 /* 01384 * Now walk the tree as usual 01385 */ 01386 ret = _query( vb, SNMP_MSG_GETNEXT, session ); 01387 while ( ret == SNMP_ERR_NOERROR && 01388 snmp_oidtree_compare( list->name, list->name_length, 01389 vb->name, vb->name_length ) == 0) { 01390 01391 /* 01392 * Copy each response varbind to the end of the result list 01393 * and then re-use this to ask for the next entry. 01394 */ 01395 if ( res_last ) { 01396 res_last->next_variable = snmp_clone_varbind( vb ); 01397 res_last = res_last->next_variable; 01398 } else { 01399 res_list = snmp_clone_varbind( vb ); 01400 res_last = res_list; 01401 } 01402 ret = _query( vb, SNMP_MSG_GETNEXT, session ); 01403 } 01404 /* 01405 * Copy the first result back into the original varbind parameter, 01406 * add the rest of the results (if any), and clean up. 01407 */ 01408 if ( res_list ) { 01409 snmp_clone_var( res_list, list ); 01410 list->next_variable = res_list->next_variable; 01411 res_list->next_variable = NULL; 01412 snmp_free_varbind( res_list ); 01413 } 01414 snmp_free_varbind( vb ); 01415 return ret; 01416 } 01417 01423 int 01424 netsnmp_state_machine_run( netsnmp_state_machine_input *input) 01425 { 01426 netsnmp_state_machine_step *current, *last; 01427 01428 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01429 netsnmp_require_ptr_LRV( input->steps, SNMPERR_GENERR ); 01430 last = current = input->steps; 01431 01432 DEBUGMSGT(("state_machine:run", "starting step: %s\n", current->name)); 01433 01434 while (current) { 01435 01436 /* 01437 * log step and check for required data 01438 */ 01439 DEBUGMSGT(("state_machine:run", "at step: %s\n", current->name)); 01440 if (NULL == current->run) { 01441 DEBUGMSGT(("state_machine:run", "no run step\n")); 01442 current->result = last->result; 01443 break; 01444 } 01445 01446 /* 01447 * run step 01448 */ 01449 DEBUGMSGT(("state_machine:run", "running step: %s\n", current->name)); 01450 current->result = (*current->run)( input, current ); 01451 ++input->steps_so_far; 01452 01453 /* 01454 * log result and move to next step 01455 */ 01456 input->last_run = current; 01457 DEBUGMSGT(("state_machine:run:result", "step %s returned %d\n", 01458 current->name, current->result)); 01459 if (SNMPERR_SUCCESS == current->result) 01460 current = current->on_success; 01461 else if (SNMPERR_ABORT == current->result) { 01462 DEBUGMSGT(("state_machine:run:result", "ABORT from %s\n", 01463 current->name)); 01464 break; 01465 } 01466 else 01467 current = current->on_error; 01468 } 01469 01470 /* 01471 * run cleanup 01472 */ 01473 if ((input->cleanup) && (input->cleanup->run)) 01474 (*input->cleanup->run)( input, input->last_run ); 01475 01476 return input->last_run->result; 01477 } 01478 01479 #ifndef NETSNMP_NO_WRITE_SUPPORT 01480 #ifndef NETSNMP_FEATURE_REMOVE_ROW_CREATE 01481 01486 typedef struct rowcreate_state_s { 01487 01488 netsnmp_session *session; 01489 netsnmp_variable_list *vars; 01490 int row_status_index; 01491 } rowcreate_state; 01492 01493 static netsnmp_variable_list * 01494 _get_vb_num(netsnmp_variable_list *vars, int index) 01495 { 01496 for (; vars && index > 0; --index) 01497 vars = vars->next_variable; 01498 01499 if (!vars || index > 0) 01500 return NULL; 01501 01502 return vars; 01503 } 01504 01505 01506 /* 01507 * cleanup 01508 */ 01509 static int 01510 _row_status_state_cleanup(netsnmp_state_machine_input *input, 01511 netsnmp_state_machine_step *step) 01512 { 01513 rowcreate_state *ctx; 01514 01515 netsnmp_require_ptr_LRV( input, SNMPERR_ABORT ); 01516 netsnmp_require_ptr_LRV( step, SNMPERR_ABORT ); 01517 01518 DEBUGMSGT(("row_create:called", "_row_status_state_cleanup, last run step was %s rc %d\n", 01519 step->name, step->result)); 01520 01521 ctx = (rowcreate_state *)input->input_context; 01522 if (ctx && ctx->vars) 01523 snmp_free_varbind( ctx->vars ); 01524 01525 return SNMPERR_SUCCESS; 01526 } 01527 01528 /* 01529 * send a request to activate the row 01530 */ 01531 static int 01532 _row_status_state_activate(netsnmp_state_machine_input *input, 01533 netsnmp_state_machine_step *step) 01534 { 01535 rowcreate_state *ctx; 01536 netsnmp_variable_list *rs_var, *var = NULL; 01537 int32_t rc, val = RS_ACTIVE; 01538 01539 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01540 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01541 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01542 01543 ctx = (rowcreate_state *)input->input_context; 01544 01545 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01546 01547 /* 01548 * just send the rowstatus varbind 01549 */ 01550 rs_var = _get_vb_num(ctx->vars, ctx->row_status_index); 01551 netsnmp_require_ptr_LRV(rs_var, SNMPERR_GENERR); 01552 01553 var = snmp_varlist_add_variable(&var, rs_var->name, rs_var->name_length, 01554 rs_var->type, &val, sizeof(val)); 01555 netsnmp_require_ptr_LRV( var, SNMPERR_GENERR ); 01556 01557 /* 01558 * send set 01559 */ 01560 rc = netsnmp_query_set( var, ctx->session ); 01561 if (-2 == rc) 01562 rc = SNMPERR_ABORT; 01563 01564 snmp_free_varbind(var); 01565 01566 return rc; 01567 } 01568 01569 /* 01570 * send each non-row status column, one at a time 01571 */ 01572 static int 01573 _row_status_state_single_value_cols(netsnmp_state_machine_input *input, 01574 netsnmp_state_machine_step *step) 01575 { 01576 rowcreate_state *ctx; 01577 netsnmp_variable_list *var, *tmp_next, *row_status; 01578 int rc = SNMPERR_GENERR; 01579 01580 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01581 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01582 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01583 01584 ctx = (rowcreate_state *)input->input_context; 01585 01586 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01587 01588 row_status = _get_vb_num(ctx->vars, ctx->row_status_index); 01589 netsnmp_require_ptr_LRV(row_status, SNMPERR_GENERR); 01590 01591 /* 01592 * try one varbind at a time 01593 */ 01594 for (var = ctx->vars; var; var = var->next_variable) { 01595 if (var == row_status) 01596 continue; 01597 01598 tmp_next = var->next_variable; 01599 var->next_variable = NULL; 01600 01601 /* 01602 * send set 01603 */ 01604 rc = netsnmp_query_set( var, ctx->session ); 01605 var->next_variable = tmp_next; 01606 if (-2 == rc) 01607 rc = SNMPERR_ABORT; 01608 if (rc != SNMPERR_SUCCESS) 01609 break; 01610 } 01611 01612 return rc; 01613 } 01614 01615 /* 01616 * send all values except row status 01617 */ 01618 static int 01619 _row_status_state_multiple_values_cols(netsnmp_state_machine_input *input, 01620 netsnmp_state_machine_step *step) 01621 { 01622 rowcreate_state *ctx; 01623 netsnmp_variable_list *vars, *var, *last, *row_status; 01624 int rc; 01625 01626 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01627 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01628 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01629 01630 ctx = (rowcreate_state *)input->input_context; 01631 01632 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01633 01634 vars = snmp_clone_varbind(ctx->vars); 01635 netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR); 01636 01637 row_status = _get_vb_num(vars, ctx->row_status_index); 01638 if (NULL == row_status) { 01639 snmp_free_varbind(vars); 01640 return SNMPERR_GENERR; 01641 } 01642 01643 /* 01644 * remove row status varbind 01645 */ 01646 if (row_status == vars) { 01647 vars = row_status->next_variable; 01648 row_status->next_variable = NULL; 01649 } 01650 else { 01651 for (last=vars, var=last->next_variable; 01652 var; 01653 last=var, var = var->next_variable) { 01654 if (var == row_status) { 01655 last->next_variable = var->next_variable; 01656 break; 01657 } 01658 } 01659 } 01660 snmp_free_var(row_status); 01661 01662 /* 01663 * send set 01664 */ 01665 rc = netsnmp_query_set( vars, ctx->session ); 01666 if (-2 == rc) 01667 rc = SNMPERR_ABORT; 01668 01669 snmp_free_varbind(vars); 01670 01671 return rc; 01672 } 01673 01674 /* 01675 * send a createAndWait request with no other values 01676 */ 01677 static int 01678 _row_status_state_single_value_createAndWait(netsnmp_state_machine_input *input, 01679 netsnmp_state_machine_step *step) 01680 { 01681 rowcreate_state *ctx; 01682 netsnmp_variable_list *var = NULL, *rs_var; 01683 int32_t rc, val = RS_CREATEANDWAIT; 01684 01685 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01686 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01687 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01688 01689 ctx = (rowcreate_state *)input->input_context; 01690 01691 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01692 01693 rs_var = _get_vb_num(ctx->vars, ctx->row_status_index); 01694 netsnmp_require_ptr_LRV(rs_var, SNMPERR_GENERR); 01695 01696 var = snmp_varlist_add_variable(&var, rs_var->name, rs_var->name_length, 01697 rs_var->type, &val, sizeof(val)); 01698 netsnmp_require_ptr_LRV(var, SNMPERR_GENERR); 01699 01700 /* 01701 * send set 01702 */ 01703 rc = netsnmp_query_set( var, ctx->session ); 01704 if (-2 == rc) 01705 rc = SNMPERR_ABORT; 01706 01707 snmp_free_varbind(var); 01708 01709 return rc; 01710 } 01711 01712 /* 01713 * send a creatAndWait request with all values 01714 */ 01715 static int 01716 _row_status_state_all_values_createAndWait(netsnmp_state_machine_input *input, 01717 netsnmp_state_machine_step *step) 01718 { 01719 rowcreate_state *ctx; 01720 netsnmp_variable_list *vars, *rs_var; 01721 int rc; 01722 01723 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01724 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01725 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01726 01727 ctx = (rowcreate_state *)input->input_context; 01728 01729 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01730 01731 vars = snmp_clone_varbind(ctx->vars); 01732 netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR); 01733 01734 /* 01735 * make sure row stats is createAndWait 01736 */ 01737 rs_var = _get_vb_num(vars, ctx->row_status_index); 01738 if (NULL == rs_var) { 01739 snmp_free_varbind(vars); 01740 return SNMPERR_GENERR; 01741 } 01742 01743 if (*rs_var->val.integer != RS_CREATEANDWAIT) 01744 *rs_var->val.integer = RS_CREATEANDWAIT; 01745 01746 /* 01747 * send set 01748 */ 01749 rc = netsnmp_query_set( vars, ctx->session ); 01750 if (-2 == rc) 01751 rc = SNMPERR_ABORT; 01752 01753 snmp_free_varbind(vars); 01754 01755 return rc; 01756 } 01757 01758 01762 static int 01763 _row_status_state_all_values_createAndGo(netsnmp_state_machine_input *input, 01764 netsnmp_state_machine_step *step) 01765 { 01766 rowcreate_state *ctx; 01767 netsnmp_variable_list *vars, *rs_var; 01768 int rc; 01769 01770 netsnmp_require_ptr_LRV( input, SNMPERR_GENERR ); 01771 netsnmp_require_ptr_LRV( step, SNMPERR_GENERR ); 01772 netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR ); 01773 01774 ctx = (rowcreate_state *)input->input_context; 01775 01776 DEBUGMSGT(("row_create:called", "called %s\n", step->name)); 01777 01778 vars = snmp_clone_varbind(ctx->vars); 01779 netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR); 01780 01781 /* 01782 * make sure row stats is createAndGo 01783 */ 01784 rs_var = _get_vb_num(vars, ctx->row_status_index + 1); 01785 if (NULL == rs_var) { 01786 snmp_free_varbind(vars); 01787 return SNMPERR_GENERR; 01788 } 01789 01790 if (*rs_var->val.integer != RS_CREATEANDGO) 01791 *rs_var->val.integer = RS_CREATEANDGO; 01792 01793 /* 01794 * send set 01795 */ 01796 rc = netsnmp_query_set( vars, ctx->session ); 01797 if (-2 == rc) 01798 rc = SNMPERR_ABORT; 01799 01800 snmp_free_varbind(vars); 01801 01802 return rc; 01803 } 01804 01810 int 01811 netsnmp_row_create(netsnmp_session *sess, netsnmp_variable_list *vars, 01812 int row_status_index) 01813 { 01814 netsnmp_state_machine_step rc_cleanup = 01815 { "row_create_cleanup", 0, _row_status_state_cleanup, 01816 0, NULL, NULL, 0, NULL }; 01817 netsnmp_state_machine_step rc_activate = 01818 { "row_create_activate", 0, _row_status_state_activate, 01819 0, NULL, NULL, 0, NULL }; 01820 netsnmp_state_machine_step rc_sv_cols = 01821 { "row_create_single_value_cols", 0, 01822 _row_status_state_single_value_cols, 0, &rc_activate,NULL, 0, NULL }; 01823 netsnmp_state_machine_step rc_mv_cols = 01824 { "row_create_multiple_values_cols", 0, 01825 _row_status_state_multiple_values_cols, 0, &rc_activate, &rc_sv_cols, 01826 0, NULL }; 01827 netsnmp_state_machine_step rc_sv_caw = 01828 { "row_create_single_value_createAndWait", 0, 01829 _row_status_state_single_value_createAndWait, 0, &rc_mv_cols, NULL, 01830 0, NULL }; 01831 netsnmp_state_machine_step rc_av_caw = 01832 { "row_create_all_values_createAndWait", 0, 01833 _row_status_state_all_values_createAndWait, 0, &rc_activate, 01834 &rc_sv_caw, 0, NULL }; 01835 netsnmp_state_machine_step rc_av_cag = 01836 { "row_create_all_values_createAndGo", 0, 01837 _row_status_state_all_values_createAndGo, 0, NULL, &rc_av_caw, 0, 01838 NULL }; 01839 01840 netsnmp_state_machine_input sm_input = { "row_create_machine", 0, 01841 &rc_av_cag, &rc_cleanup }; 01842 rowcreate_state state; 01843 01844 netsnmp_require_ptr_LRV( sess, SNMPERR_GENERR); 01845 netsnmp_require_ptr_LRV( vars, SNMPERR_GENERR); 01846 01847 state.session = sess; 01848 state.vars = vars; 01849 01850 state.row_status_index = row_status_index; 01851 sm_input.input_context = &state; 01852 01853 netsnmp_state_machine_run( &sm_input); 01854 01855 return SNMPERR_SUCCESS; 01856 } 01857 #endif /* NETSNMP_FEATURE_REMOVE_ROW_CREATE */ 01858 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 01859 01860