snmp_vars.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:14k
- /*
- * SNMP Variable Binding. Complies with:
- *
- * RFC 1905: Protocol Operations for SNMPv2
- *
- */
- /**********************************************************************
- *
- * Copyright 1997 by Carnegie Mellon University
- *
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation, and that the name of CMU not be
- * used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- *
- * Author: Ryan Troll <ryan+@andrew.cmu.edu>
- *
- **********************************************************************/
- #include "config.h"
- #include <stdio.h>
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #if HAVE_CTYPE_H
- #include <ctype.h>
- #endif
- #if HAVE_GNUMALLOC_H
- #include <gnumalloc.h>
- #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
- #include <malloc.h>
- #endif
- #if HAVE_MEMORY_H
- #include <memory.h>
- #endif
- #ifdef HAVE_STRING_H
- #include <string.h>
- #endif
- #ifdef HAVE_STRINGS_H
- #include <strings.h>
- #endif
- #if HAVE_BSTRING_H
- #include <bstring.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #if HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #if HAVE_SYS_TIME_H
- #include <sys/time.h>
- #endif
- #if HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #include "snmp.h"
- #include "asn1.h"
- #include "snmp_vars.h"
- #if 0
- #include "mibii.h"
- #endif
- #include "snmp_api_error.h"
- #include "snmp_pdu.h"
- #include "snmp_msg.h"
- #include "util.h"
- /* #define DEBUG_VARS 1 */
- /* #define DEBUG_VARS_MALLOC 1 */
- /* #define DEBUG_VARS_DECODE 1 */
- /* #define DEBUG_VARS_ENCODE 1 */
- #define ASN_PARSE_ERROR(x) { return(x); }
- /* Create a new variable_list structure representing oid Name of length Len.
- *
- * Returns NULL upon error.
- */
- struct variable_list *
- snmp_var_new(oid * Name, int Len)
- {
- struct variable_list *New;
- #ifdef DEBUG_VARS
- printf("VARS: Creating.n");
- #endif
- New = (struct variable_list *) xmalloc(sizeof(struct variable_list));
- if (New == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- memset(New, ' ', sizeof(struct variable_list));
- /* New->next_variable = NULL; */
- New->type = ASN_NULL;
- New->name_length = Len;
- if (New->name_length == 0) {
- New->name = NULL;
- return (New);
- }
- New->name = (oid *) xmalloc(Len * sizeof(oid));
- if (New->name == NULL) {
- xfree(New);
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- #ifdef DEBUG_VARS
- printf("VARS: Copying name, size (%d)n", Len);
- #endif
- /* Only copy a name if it was specified. */
- if (Name)
- xmemcpy((char *) New->name, (char *) Name, Len * sizeof(oid));
- return (New);
- }
- /* Clone a variable list.
- *
- * Returns NULL upon error.
- */
- struct variable_list *
- snmp_var_clone(struct variable_list *Src)
- {
- struct variable_list *Dest;
- #ifdef DEBUG_VARS
- printf("VARS: Cloning.n");
- #endif
- Dest = (struct variable_list *) xmalloc(sizeof(struct variable_list));
- if (Dest == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- #ifdef DEBUG_VARS
- printf("VARS: Copying entire variable list. (Size %d)n",
- sizeof(struct variable_list));
- #endif
- xmemcpy((char *) Dest, (char *) Src, sizeof(struct variable_list));
- if (Src->name != NULL) {
- Dest->name = (oid *) xmalloc(Src->name_length * sizeof(oid));
- if (Dest->name == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- xfree(Dest);
- return (NULL);
- }
- #ifdef DEBUG_VARS
- printf("VARS: Copying name OID. (Size %d)n", Src->name_length);
- #endif
- xmemcpy((char *) Dest->name, (char *) Src->name,
- Src->name_length * sizeof(oid));
- }
- /* CISCO Catalyst 2900 returns NULL strings as data of length 0. */
- if ((Src->val.string != NULL) &&
- (Src->val_len)) {
- Dest->val.string = (u_char *) xmalloc(Src->val_len);
- if (Dest->val.string == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- xfree(Dest->name);
- xfree(Dest);
- return (NULL);
- }
- #ifdef DEBUG_VARS
- printf("VARS: Copying value (Size %d)n", Src->val_len);
- #endif
- xmemcpy((char *) Dest->val.string, (char *) Src->val.string, Src->val_len);
- }
- #ifdef DEBUG_VARS
- printf("VARS: Cloned %x.n", (unsigned int) Dest);
- #endif
- #ifdef DEBUG_VARS_MALLOC
- printf("VARS: Cloned (%x)n", (unsigned int) Dest);
- printf("VARS: Name is (%x)n", (unsigned int) Dest->name);
- #endif
- return (Dest);
- }
- /* Free a variable_list.
- */
- void
- snmp_var_free(struct variable_list *Ptr)
- {
- if (Ptr->name && Ptr->name_length > 0)
- xfree((char *) Ptr->name);
- if (Ptr->val.string && Ptr->val_len > 0)
- xfree((char *) Ptr->val.string);
- else if (Ptr->val.integer && Ptr->val_len > 0)
- xfree((char *) Ptr->val.integer);
- xfree(Ptr);
- }
- /**********************************************************************/
- /* Build a variable binding.
- *
- * RFC 1905: Protocol Operations for SNMPv2
- *
- * VarBind ::=
- * SEQUENCE {
- * name ObjectName
- * CHOICE {
- * value ObjectSyntax
- * unSpecified NULL
- * noSuchObject[0] NULL
- * noSuchInstance[1] NULL
- * endOfMibView[2] NULL
- * }
- * }
- */
- u_char *
- snmp_var_EncodeVarBind(u_char * Buffer, int *BufLenP,
- variable_list * VarList,
- int Version)
- {
- struct variable_list *Vars;
- u_char *bufp;
- u_char *HeaderStart;
- u_char *HeaderEnd;
- int FakeArg = *BufLenP;
- bufp = Buffer;
- for (Vars = VarList; Vars; Vars = Vars->next_variable) {
- /* Build the header for this variable
- *
- * Use Maximum size.
- */
- HeaderStart = bufp;
- HeaderEnd = asn_build_header(HeaderStart, BufLenP,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- FakeArg);
- if (HeaderEnd == NULL)
- return (NULL);
- /* Now, let's put the Object Identifier into the buffer */
- bufp = asn_build_objid(HeaderEnd, BufLenP,
- (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_OBJECT_ID),
- Vars->name, Vars->name_length);
- if (bufp == NULL)
- return (NULL);
- /* Now put the data in */
- switch (Vars->type) {
- case ASN_INTEGER:
- bufp = asn_build_int(bufp,
- BufLenP, Vars->type,
- (int *) Vars->val.integer, Vars->val_len);
- break;
- case SMI_COUNTER32:
- case SMI_GAUGE32:
- /* case SMI_UNSIGNED32: */
- case SMI_TIMETICKS:
- bufp = asn_build_unsigned_int(bufp, BufLenP,
- Vars->type,
- (u_int *) Vars->val.integer, Vars->val_len);
- break;
- case ASN_OCTET_STR:
- case SMI_IPADDRESS:
- case SMI_OPAQUE:
- bufp = asn_build_string(bufp, BufLenP, Vars->type,
- Vars->val.string, Vars->val_len);
- break;
- case ASN_OBJECT_ID:
- bufp = asn_build_objid(bufp, BufLenP, Vars->type,
- (oid *) Vars->val.objid, Vars->val_len / sizeof(oid));
- break;
- case SMI_NOSUCHINSTANCE:
- case SMI_NOSUCHOBJECT:
- case SMI_ENDOFMIBVIEW:
- if (Version == SNMP_VERSION_1) {
- /* SNMP Version 1 does not support these error codes. */
- bufp = asn_build_null(bufp, BufLenP, SMI_NOSUCHOBJECT);
- } else {
- bufp = asn_build_exception(bufp, BufLenP, Vars->type);
- }
- break;
- case ASN_NULL:
- bufp = asn_build_null(bufp, BufLenP, Vars->type);
- break;
- case SMI_COUNTER64:
- snmplib_debug(2, "Unable to encode type SMI_COUNTER64!n");
- /* Fall through */
- default:
- snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
- return (NULL);
- }
- /* ASSERT: bufp should now point to the next valid byte. */
- if (bufp == NULL)
- return (NULL);
- /* Rebuild the header with the appropriate length */
- HeaderEnd = asn_build_header(HeaderStart, &FakeArg,
- (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
- (bufp - HeaderEnd));
- /* Returns NULL */
- if (HeaderEnd == NULL)
- return (NULL);
- }
- /* or the end of the entire thing */
- return (bufp);
- }
- /* Parse all Vars from the buffer */
- u_char *
- snmp_var_DecodeVarBind(u_char * Buffer, int *BufLen,
- struct variable_list ** VarP,
- int Version)
- {
- struct variable_list *Var, **VarLastP;
- u_char *bufp, *tmp;
- u_char VarBindType;
- u_char *DataPtr;
- int DataLen;
- oid TmpBuf[MAX_NAME_LEN];
- int AllVarLen = *BufLen;
- int ThisVarLen = 0;
- VarLastP = VarP;
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoding buffer of length %dn", *BufLen);
- #endif
- /* Now parse the variables */
- bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
- snmp_set_api_error(SNMPERR_PDU_PARSE);
- ASN_PARSE_ERROR(NULL);
- }
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: All Variable length %dn", AllVarLen);
- #endif
- /* We know how long the variable list is. Parse it. */
- while ((int) AllVarLen > 0) {
- /* Create a new variable */
- Var = snmp_var_new(NULL, MAX_NAME_LEN);
- if (Var == NULL)
- return (NULL);
- /* Parse the header to find out the length of this variable. */
- ThisVarLen = AllVarLen;
- tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType);
- if (tmp == NULL)
- ASN_PARSE_ERROR(NULL);
- /* Now that we know the length , figure out how it relates to
- * the entire variable list
- */
- AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp));
- bufp = tmp;
- /* Is it valid? */
- if (VarBindType != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
- snmp_set_api_error(SNMPERR_PDU_PARSE);
- ASN_PARSE_ERROR(NULL);
- }
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Header type 0x%x (%d bytes left)n", VarBindType, ThisVarLen);
- #endif
- /* Parse the OBJID */
- bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType,
- Var->name, &(Var->name_length));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- if (VarBindType != (u_char) (ASN_UNIVERSAL |
- ASN_PRIMITIVE |
- ASN_OBJECT_ID)) {
- snmp_set_api_error(SNMPERR_PDU_PARSE);
- ASN_PARSE_ERROR(NULL);
- }
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)n",
- Var->name_length, ThisVarLen);
- #endif
- /* Keep a pointer to this object */
- DataPtr = bufp;
- DataLen = ThisVarLen;
- /* find out type of object */
- bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type));
- if (bufp == NULL)
- ASN_PARSE_ERROR(NULL);
- ThisVarLen = DataLen;
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Data type %dn", Var->type);
- #endif
- /* Parse the type */
- switch ((short) Var->type) {
- case ASN_INTEGER:
- Var->val.integer = (int *) xmalloc(sizeof(int));
- if (Var->val.integer == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- Var->val_len = sizeof(int);
- bufp = asn_parse_int(DataPtr, &ThisVarLen,
- &Var->type, (int *) Var->val.integer,
- Var->val_len);
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoded integer '%d' (%d bytes left)n",
- *(Var->val.integer), ThisVarLen);
- #endif
- break;
- case SMI_COUNTER32:
- case SMI_GAUGE32:
- /* case SMI_UNSIGNED32: */
- case SMI_TIMETICKS:
- Var->val.integer = (int *) xmalloc(sizeof(u_int));
- if (Var->val.integer == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- Var->val_len = sizeof(u_int);
- bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen,
- &Var->type, (u_int *) Var->val.integer,
- Var->val_len);
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoded timeticks '%d' (%d bytes left)n",
- *(Var->val.integer), ThisVarLen);
- #endif
- break;
- case ASN_OCTET_STR:
- case SMI_IPADDRESS:
- case SMI_OPAQUE:
- Var->val_len = *&ThisVarLen; /* String is this at most */
- Var->val.string = (u_char *) xmalloc((unsigned) Var->val_len);
- if (Var->val.string == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- bufp = asn_parse_string(DataPtr, &ThisVarLen,
- &Var->type, Var->val.string,
- &Var->val_len);
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoded string '%s' (length %d) (%d bytes left)n",
- (Var->val.string), Var->val_len, ThisVarLen);
- #endif
- break;
- case ASN_OBJECT_ID:
- Var->val_len = MAX_NAME_LEN;
- bufp = asn_parse_objid(DataPtr, &ThisVarLen,
- &Var->type, TmpBuf, &Var->val_len);
- Var->val_len *= sizeof(oid);
- Var->val.objid = (oid *) xmalloc((unsigned) Var->val_len);
- if (Var->val.integer == NULL) {
- snmp_set_api_error(SNMPERR_OS_ERR);
- return (NULL);
- }
- /* Only copy if we successfully decoded something */
- if (bufp) {
- xmemcpy((char *) Var->val.objid, (char *) TmpBuf, Var->val_len);
- }
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Decoded OBJID (length %d) (%d bytes left)n",
- Var->val_len, ThisVarLen);
- #endif
- break;
- case ASN_NULL:
- case SMI_NOSUCHINSTANCE:
- case SMI_NOSUCHOBJECT:
- case SMI_ENDOFMIBVIEW:
- break;
- case SMI_COUNTER64:
- snmplib_debug(2, "Unable to parse type SMI_COUNTER64!n");
- snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
- return (NULL);
- break;
- default:
- snmplib_debug(2, "bad type returned (%x)n", Var->type);
- snmp_set_api_error(SNMPERR_PDU_PARSE);
- return (NULL);
- break;
- } /* End of var type switch */
- if (bufp == NULL)
- return (NULL);
- #ifdef DEBUG_VARS_DECODE
- printf("VARS: Adding to list.n");
- #endif
- /* Add variable to the list */
- *VarLastP = Var;
- VarLastP = &(Var->next_variable);
- }
- return (bufp);
- }