TARG = libsnmp.a
-CSRCS = snmp_client.c snmp.c snmp_auth.c asn1.c mib.c \
- parse.c snmp_api.c usec.c snmpdump.c
-OBJS = snmp_client.o snmp.o snmp_auth.o asn1.o mib.o \
- parse.o snmp_api.o usec.o snmpdump.o
+CSRCS = asn1.c parse.c snmp_dump.c snmp_vars.c \
+ coexistance.c snmp_api.c snmp_error.c \
+ mib.c snmp_api_error.c \
+ mibii.c snmp_api_util.c snmp_msg.c \
+ snmp_client.c snmp_pdu.c
+
+OBJS = asn1.o parse.o snmp_dump.o snmp_vars.o \
+ coexistance.o snmp_api.o snmp_error.o \
+ mib.o snmp_api_error.o \
+ mibii.o snmp_api_util.o snmp_msg.o \
+ snmp_client.o snmp_pdu.o
CC = @CC@
AR_R = @AR_R@
* Encodes abstract data types into a machine independent stream of bytes.
*
*/
-/**********************************************************************
- Copyright 1988, 1989, 1991, 1992 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.
-******************************************************************/
+/***************************************************************************
+ *
+ * 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.
+ *
+ ***************************************************************************/
#include "config.h"
-#if HAVE_STDIO_H
#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
-#if HAVE_STRING_H
-#include <string.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_ASSERT_H
-#include <assert.h>
+#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 "asn1.h"
+#include "snmp_api_error.h"
-#ifdef DEBUG
-#define ERROR(string) printf("%s(%d): %s",__FILE__, __LINE__, string);
-#else
-#define ERROR(string)
-#endif
+
+u_char *asn_build_header(u_char *data, /* IN - ptr to start of object */
+ int *datalength, /* IN/OUT - # of valid bytes */
+ /* left in buffer */
+ u_char type, /* IN - ASN type of object */
+ int length) /* IN - length of object */
+{
+ /* Truth is 0 'cause we don't know yet */
+ return(asn_build_header_with_truth(data, datalength, type, length, 0));
+}
/*
- * asn_parse_int - pulls a long out of an ASN int type.
+ * asn_parse_int - pulls an int out of an ASN int type.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the end of this object.
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_int(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - asn type of object */
- long *intp, /* IN/OUT - pointer to start of output buffer */
- int intsize)
-{ /* IN - size of output buffer */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- */
- u_char *bufp = data;
- u_long asn_length;
- long value = 0;
-
- if (intsize != sizeof(long)) {
- ERROR("not long");
- return NULL;
- }
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL) {
- ERROR("bad length");
- return NULL;
- }
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- if (asn_length > intsize) {
- ERROR("I don't support such large integers");
- return NULL;
- }
- *datalength -= (int) asn_length + (bufp - data);
- if (*bufp & 0x80)
- value = -1; /* integer is negative */
- while (asn_length--)
- value = (value << 8) | *bufp++;
- *intp = value;
- return bufp;
+u_char *asn_parse_int(u_char *data, int *datalength,
+ u_char *type, int *intp, int intsize)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char *type; OUT - asn type of object */
+ /* int *intp; IN/OUT - pointer to start of output buffer */
+ /* int intsize; IN - size of output buffer */
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ u_char *bufp = data;
+ u_int asn_length;
+ int value = 0;
+
+ /* Room to store int? */
+ if (intsize != sizeof (int)) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Type */
+ *type = *bufp++;
+
+ /* Extract length */
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ /* Make sure the entire int is in the buffer */
+ if (asn_length + (bufp - data) > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Can we store this int? */
+ if (asn_length > intsize) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Remaining data */
+ *datalength -= (int)asn_length + (bufp - data);
+
+ /* Is the int negative? */
+ if (*bufp & 0x80)
+ value = -1; /* integer is negative */
+
+ /* Extract the bytes */
+ while(asn_length--)
+ value = (value << 8) | *bufp++;
+
+ /* That's it! */
+ *intp = value;
+ return(bufp);
}
-
/*
- * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
+ * asn_parse_unsigned_int - pulls an unsigned int out of an ASN int type.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the end of this object.
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_unsigned_int(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - asn type of object */
- u_long * intp, /* IN/OUT - pointer to start of output buffer */
- int intsize)
-{ /* IN - size of output buffer */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- */
- u_char *bufp = data;
- u_long asn_length;
- u_long value = 0;
-
- if (intsize != sizeof(long)) {
- ERROR("not long");
- return NULL;
- }
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL) {
- ERROR("bad length");
- return NULL;
- }
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- if ((asn_length > (intsize + 1)) ||
- ((asn_length == intsize + 1) && *bufp != 0x00)) {
- ERROR("I don't support such large integers");
- return NULL;
- }
- *datalength -= (int) asn_length + (bufp - data);
- if (*bufp & 0x80)
- value = -1; /* integer is negative */
- while (asn_length--)
- value = (value << 8) | *bufp++;
- *intp = value;
- return bufp;
+u_char *asn_parse_unsigned_int(u_char *data, int *datalength,
+ u_char *type, u_int *intp, int intsize)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char *type; OUT - asn type of object */
+ /* u_int *intp; IN/OUT - pointer to start of output buffer */
+ /* int intsize; IN - size of output buffer */
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ u_char *bufp = data;
+ u_int asn_length;
+ int value = 0;
+
+ /* Room to store int? */
+ if (intsize != sizeof (int)) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Type */
+ *type = *bufp++;
+
+ /* Extract length */
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ /* Make sure the entire int is in the buffer */
+ if (asn_length + (bufp - data) > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Can we store this int? */
+ if ((asn_length > (intsize + 1)) ||
+ ((asn_length == intsize + 1) && *bufp != 0x00)) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ /* Remaining data */
+ *datalength -= (int)asn_length + (bufp - data);
+
+ /* Is the int negative? */
+ if (*bufp & 0x80)
+ value = -1; /* integer is negative */
+
+ /* Extract the bytes */
+ while(asn_length--)
+ value = (value << 8) | *bufp++;
+
+ /* That's it! */
+ *intp = value;
+ return(bufp);
}
-
/*
* asn_build_int - builds an ASN object containing an integer.
* On entry, datalength is input as the number of valid bytes following
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_int(
- u_char * data, /* IN - pointer to start of output buffer */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - asn type of object */
- long *intp, /* IN - pointer to start of long integer */
- int intsize)
-{ /* IN - size of *intp */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- */
-
- long integer;
- u_long mask;
-
- if (intsize != sizeof(long)) {
- ERROR("not long");
- return NULL;
- }
- integer = *intp;
- /*
- * Truncate "unnecessary" bytes off of the most significant end of this
- * 2's complement integer. There should be no sequence of 9
- * consecutive 1's or 0's at the most significant end of the
- * integer.
- */
- mask = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
- /* mask is 0xFF800000 on a big-endian machine */
- while ((((integer & mask) == 0) || ((integer & mask) == mask))
+u_char *asn_build_int(u_char *data, int *datalength,
+ u_char type, int *intp, int intsize)
+ /* u_char *data; IN - pointer to start of output buffer */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char type; IN - asn type of object */
+ /* int *intp; IN - pointer to start of integer */
+ /* int intsize; IN - size of *intp */
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ int integer;
+ u_int mask;
+
+ if (intsize != sizeof (int)) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ integer = *intp;
+
+ /*
+ * Truncate "unnecessary" bytes off of the most significant end of this
+ * 2's complement integer. There should be no sequence of 9
+ * consecutive 1's or 0's at the most significant end of the
+ * integer.
+ */
+ mask = (u_int)0x1FF << ((8 * (sizeof(int) - 1)) - 1);
+ /* mask is 0xFF800000 on a big-endian machine */
+
+ while((((integer & mask) == 0) || ((integer & mask) == mask))
&& intsize > 1) {
- intsize--;
- integer <<= 8;
- }
- data = asn_build_header(data, datalength, type, intsize);
- if (data == NULL)
- return NULL;
- if (*datalength < intsize)
- return NULL;
- *datalength -= intsize;
- mask = 0xFF << (8 * (NUM32LEN - 1));
- /* mask is 0xFF000000 on a big-endian machine */
- while (intsize--) {
- *data++ = (u_char) ((integer & mask) >> (8 * (NUM32LEN - 1)));
- integer <<= 8;
- }
- return data;
+ intsize--;
+ integer <<= 8;
+ }
+
+ data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
+ if (data == NULL)
+ return(NULL);
+
+ /* Enough room for what we just encoded? */
+ if (*datalength < intsize) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ /* Insert it */
+ *datalength -= intsize;
+ mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
+ /* mask is 0xFF000000 on a big-endian machine */
+ while(intsize--) {
+ *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int) - 1)));
+ integer <<= 8;
+ }
+ return(data);
}
-
/*
* asn_build_unsigned_int - builds an ASN object containing an integer.
* On entry, datalength is input as the number of valid bytes following
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_unsigned_int(
- u_char * data, /* IN - pointer to start of output buffer */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - asn type of object */
- u_long * intp, /* IN - pointer to start of long integer */
- int intsize)
-{ /* IN - size of *intp */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- */
-
- u_long integer;
- u_long mask;
- int add_null_byte = 0;
-
- if (intsize != sizeof(long)) {
- ERROR("not long");
- return NULL;
- }
- integer = *intp;
- mask = 0xFF << (8 * (NUM32LEN - 1));
- /* mask is 0xFF000000 on a big-endian machine */
- if ((u_char) ((integer & mask) >> (8 * (NUM32LEN - 1))) & 0x80) {
- /* if MSB is set */
- add_null_byte = 1;
- intsize++;
- }
- /*
- * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
- * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
- * integer.
- */
- mask = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
- /* mask is 0xFF800000 on a big-endian machine */
- while ((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1) {
- intsize--;
- integer <<= 8;
- }
- data = asn_build_header(data, datalength, type, intsize);
- if (data == NULL)
- return NULL;
- if (*datalength < intsize)
- return NULL;
- *datalength -= intsize;
- if (add_null_byte == 1) {
- *data++ = '\0';
- intsize--;
- }
- mask = 0xFF << (8 * (NUM32LEN - 1));
- /* mask is 0xFF000000 on a big-endian machine */
- while (intsize--) {
- *data++ = (u_char) ((integer & mask) >> (8 * (NUM32LEN - 1)));
- integer <<= 8;
- }
- return data;
+u_char *asn_build_unsigned_int(u_char *data, int *datalength,
+ u_char type, u_int *intp, int intsize)
+ /* u_char *data; IN - pointer to start of output buffer */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char type; IN - asn type of object */
+ /* u_int *intp; IN - pointer to start of integer */
+ /* int intsize; IN - size of *intp */
+{
+ /*
+ * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ */
+ u_int integer;
+ u_int mask;
+ int add_null_byte = 0;
+
+ if (intsize != sizeof (int)) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ integer = *intp;
+ mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
+ /* mask is 0xFF000000 on a big-endian machine */
+ if ((u_char)((integer & mask) >> (8 * (sizeof(int) - 1))) & 0x80) {
+ /* if MSB is set */
+ add_null_byte = 1;
+ intsize++;
+ }
+
+ /*
+ * Truncate "unnecessary" bytes off of the most significant end of
+ * this 2's complement integer.
+ * There should be no sequence of 9 consecutive 1's or 0's at the
+ * most significant end of the integer.
+ */
+ mask = (u_int)0x1FF << ((8 * (sizeof(int) - 1)) - 1);
+ /* mask is 0xFF800000 on a big-endian machine */
+ while((((integer & mask) == 0)
+ || ((integer & mask) == mask)) && intsize > 1) {
+ intsize--;
+ integer <<= 8;
+ }
+
+ data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
+ if (data == NULL)
+ return(NULL);
+
+ if (*datalength < intsize) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ *datalength -= intsize;
+ if (add_null_byte == 1) {
+ *data++ = '\0';
+ intsize--;
+ }
+
+ mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
+ /* mask is 0xFF000000 on a big-endian machine */
+ while(intsize--) {
+ *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int) - 1)));
+ integer <<= 8;
+ }
+ return(data);
}
-
/*
* asn_parse_string - pulls an octet string out of an ASN octet string type.
* On entry, datalength is input as the number of valid bytes following
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_string(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - asn type of object */
- u_char * string, /* IN/OUT - pointer to start of output buffer */
- int *strlength)
-{ /* IN/OUT - size of output buffer */
-/*
- * ASN.1 octet string ::= primstring | cmpdstring
- * primstring ::= 0x04 asnlength byte {byte}*
- * cmpdstring ::= 0x24 asnlength string {string}*
- */
- u_char *bufp = data;
- u_long asn_length;
-
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL)
- return NULL;
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- if (asn_length > *strlength) {
- ERROR("I don't support such long strings");
- return NULL;
- }
- xmemcpy(string, bufp, (int) asn_length);
- *strlength = (int) asn_length;
- *datalength -= (int) asn_length + (bufp - data);
- return bufp + asn_length;
+u_char *asn_parse_string(u_char *data, int *datalength,
+ u_char *type, u_char *string, int *strlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char *type; OUT - asn type of object */
+ /* u_char *string; IN/OUT - pointer to start of output buffer */
+ /* int *strlength; IN/OUT - size of output buffer */
+{
+ /*
+ * ASN.1 octet string ::= primstring | cmpdstring
+ * primstring ::= 0x04 asnlength byte {byte}*
+ * cmpdstring ::= 0x24 asnlength string {string}*
+ */
+ u_char *bufp = data;
+ u_int asn_length;
+
+ *type = *bufp++;
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ if (asn_length + (bufp - data) > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ if (asn_length > *strlength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ xmemcpy((char *)string, (char *)bufp, (int)asn_length);
+ *strlength = (int)asn_length;
+ *datalength -= (int)asn_length + (bufp - data);
+ return(bufp + asn_length);
}
-
/*
- * asn_build_string - Builds an ASN octet string object containing the input string.
- * On entry, datalength is input as the number of valid bytes following
- * "data". On exit, it is returned as the number of valid bytes
+ * asn_build_string - Builds an ASN octet string object containing the input
+ * string. On entry, datalength is input as the number of valid bytes
+ * following "data". On exit, it is returned as the number of valid bytes
* following the beginning of the next object.
*
* Returns a pointer to the first byte past the end
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_string(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - ASN type of string */
- u_char * string, /* IN - pointer to start of input buffer */
- int strlength)
-{ /* IN - size of input buffer */
-/*
- * ASN.1 octet string ::= primstring | cmpdstring
- * primstring ::= 0x04 asnlength byte {byte}*
- * cmpdstring ::= 0x24 asnlength string {string}*
- * This code will never send a compound string.
- */
- data = asn_build_header(data, datalength, type, strlength);
- if (data == NULL)
- return NULL;
- if (*datalength < strlength)
- return NULL;
- xmemcpy(data, string, strlength);
- *datalength -= strlength;
- return data + strlength;
+u_char *asn_build_string(u_char *data, int *datalength,
+ u_char type, u_char *string, int strlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char type; IN - ASN type of string */
+ /* u_char *string; IN - pointer to start of input buffer */
+ /* int strlength; IN - size of input buffer */
+{
+ /*
+ * ASN.1 octet string ::= primstring | cmpdstring
+ * primstring ::= 0x04 asnlength byte {byte}*
+ * cmpdstring ::= 0x24 asnlength string {string}*
+ * This code will never send a compound string.
+ */
+ data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
+ if (data == NULL)
+ return(NULL);
+
+ if (*datalength < strlength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ xmemcpy((char *)data, (char *)string, strlength);
+ *datalength -= strlength;
+ return(data + strlength);
}
* Returns a pointer to the first byte of the contents of this object.
* Returns NULL on any error.
*/
-u_char *
-asn_parse_header(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type)
-{ /* OUT - ASN type of object */
- u_char *bufp = data;
- int header_len;
- u_long asn_length;
-
- if (*datalength <= 0) {
- return NULL;
- }
- /* this only works on data types < 30, i.e. no extension octets */
- if (IS_EXTENSION_ID(*bufp)) {
- ERROR("can't process ID >= 30");
- return NULL;
- }
- *type = *bufp;
- bufp = asn_parse_length(bufp + 1, &asn_length);
- if (bufp == NULL)
- return NULL;
- header_len = bufp - data;
- if (header_len + asn_length > *datalength) {
- ERROR("asn length too long");
- return NULL;
- }
- *datalength = (int) asn_length;
- return bufp;
+u_char *asn_parse_header(u_char *data, int *datalength, u_char *type)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char *type; OUT - ASN type of object */
+{
+ u_char *bufp = data;
+ int header_len;
+ u_int asn_length;
+
+ /* this only works on data types < 30, i.e. no extension octets */
+ if (IS_EXTENSION_ID(*bufp)) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ *type = *bufp;
+ bufp = asn_parse_length(bufp + 1, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ header_len = bufp - data;
+ if (header_len + asn_length > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ *datalength = (int)asn_length;
+ return(bufp);
}
/*
* Returns a pointer to the first byte of the contents of this object.
* Returns NULL on any error.
*/
-u_char *
-asn_build_header(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - ASN type of object */
- int length)
-{ /* IN - length of object */
- if (*datalength < 1)
- return NULL;
- *data++ = type;
- (*datalength)--;
- return asn_build_length(data, datalength, length);
+u_char *asn_build_header_with_truth(u_char *data, int *datalength,
+ u_char type, int length, int truth)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char type; IN - ASN type of object */
+ /* int length; IN - length of object */
+ /* int truth; IN - Whether length is truth */
+{
+ if (*datalength < 1) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ *data++ = type;
+ (*datalength)--;
+ return(asn_build_length(data, datalength, length, truth));
}
/*
* Returns a pointer to the first byte of the contents of this object.
* Returns NULL on any error.
*/
-u_char *
-asn_build_sequence(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - ASN type of object */
- int length)
-{ /* IN - length of object */
- assert(*datalength >= 0);
- *datalength -= 4;
- if (*datalength < 0) {
- *datalength += 4; /* fix up before punting */
- return NULL;
- }
- *data++ = type;
- *data++ = (u_char) (0x02 | ASN_LONG_LEN);
- *data++ = (u_char) ((length >> 8) & 0xFF);
- *data++ = (u_char) (length & 0xFF);
- return data;
+u_char *asn_build_sequence(u_char *data, int *datalength,
+ u_char type, int length)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buffer */
+ /* u_char type; IN - ASN type of object */
+ /* int length; IN - length of object */
+{
+ *datalength -= 4;
+ if (*datalength < 0) {
+ *datalength += 4; /* fix up before punting */
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ *data++ = type;
+ *data++ = (u_char)(0x02 | ASN_LONG_LEN);
+ *data++ = (u_char)((length >> 8) & 0xFF);
+ *data++ = (u_char)(length & 0xFF);
+ return(data);
}
/*
* field (aka: the start of the data field).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_length(
- u_char * data, /* IN - pointer to start of length field */
- u_long * length)
-{ /* OUT - value of length field */
- u_char lengthbyte = *data;
-
- *length = 0;
- if (lengthbyte & ASN_LONG_LEN) {
- lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
- if (lengthbyte == 0) {
- ERROR("We don't support indefinite lengths");
- return NULL;
- }
- if (lengthbyte > sizeof(long)) {
- ERROR("we can't support data lengths that long");
- return NULL;
- }
- xmemcpy(length, data + 1, (int) lengthbyte);
- /* XXX: is this useable on a 64bit platform ? */
- *length = ntohl(*length);
- *length >>= (8 * ((sizeof(*length)) - lengthbyte));
- return data + lengthbyte + 1;
- } else { /* short asnlength */
- *length = (long) lengthbyte;
- return data + 1;
+u_char *asn_parse_length(u_char *data, u_int *length)
+ /* u_char *data; IN - pointer to start of length field */
+ /* u_int *length; OUT - value of length field */
+{
+ u_char lengthbyte = *data;
+
+ if (lengthbyte & ASN_LONG_LEN) {
+ lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
+
+ if (lengthbyte == 0) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
}
+
+ if (lengthbyte > sizeof(int)) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ *length = (u_int)0;
+ xmemcpy((char *)(length), (char *)data + 1, (int)lengthbyte);
+ *length = ntohl(*length);
+ *length >>= (8 * ((sizeof *length) - lengthbyte));
+ return(data + lengthbyte + 1);
+
+ }
+
+ /* short asnlength */
+
+ *length = (int)lengthbyte;
+ return(data + 1);
}
-u_char *
-asn_build_length(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- int length)
-{ /* IN - length of object */
- u_char *start_data = data;
+
+u_char *asn_build_length(u_char *data, int *datalength,
+ int length, int truth)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* int length; IN - length of object */
+ /* int truth; IN - If 1, this is the true len. */
+{
+ u_char *start_data = data;
+
+ if (truth) {
/* no indefinite lengths sent */
if (length < 0x80) {
- if (*datalength < 1) {
- ERROR("build_length");
- return NULL;
- }
- *data++ = (u_char) length;
+ if (*datalength < 1) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+ *data++ = (u_char)length;
+
} else if (length <= 0xFF) {
- if (*datalength < 2) {
- ERROR("build_length");
- return NULL;
- }
- *data++ = (u_char) (0x01 | ASN_LONG_LEN);
- *data++ = (u_char) length;
- } else { /* 0xFF < length <= 0xFFFF */
- if (*datalength < 3) {
- ERROR("build_length");
- return NULL;
- }
- *data++ = (u_char) (0x02 | ASN_LONG_LEN);
- *data++ = (u_char) ((length >> 8) & 0xFF);
- *data++ = (u_char) (length & 0xFF);
+ if (*datalength < 2) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+ *data++ = (u_char)(0x01 | ASN_LONG_LEN);
+ *data++ = (u_char)length;
+ } else { /* 0xFF < length <= 0xFFFF */
+ if (*datalength < 3) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+ *data++ = (u_char)(0x02 | ASN_LONG_LEN);
+ *data++ = (u_char)((length >> 8) & 0xFF);
+ *data++ = (u_char)(length & 0xFF);
+ }
+
+ } else {
+
+ /* Don't know if this is the true length. Make sure it's large
+ * enough for later.
+ */
+ if (*datalength < 3) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
}
- *datalength -= (data - start_data);
- return data;
+ *data++ = (u_char)(0x02 | ASN_LONG_LEN);
+ *data++ = (u_char)((length >> 8) & 0xFF);
+ *data++ = (u_char)(length & 0xFF);
+ }
+ *datalength -= (data - start_data);
+ return(data);
}
/*
- * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
+ * asn_parse_objid - pulls an object indentifier out of an ASN object
+ * identifier type.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
* following the beginning of the next object.
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_objid(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - ASN type of object */
- oid * objid, /* IN/OUT - pointer to start of output buffer */
- int *objidlength)
-{ /* IN/OUT - number of sub-id's in objid */
-/*
- * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
- * subidentifier ::= {leadingbyte}* lastbyte
- * leadingbyte ::= 1 7bitvalue
- * lastbyte ::= 0 7bitvalue
- */
- u_char *bufp = data;
- oid *oidp = objid + 1;
- u_long subidentifier;
- long length;
- u_long asn_length;
-
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL)
- return NULL;
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- *datalength -= (int) asn_length + (bufp - data);
-
- /* Handle invalid object identifier encodings of the form 06 00 robustly */
- if (asn_length == 0)
- objid[0] = objid[1] = 0;
-
- length = asn_length;
- (*objidlength)--; /* account for expansion of first byte */
- while (length > 0 && (*objidlength)-- > 0) {
- subidentifier = 0;
- do { /* shift and add in low order 7 bits */
- subidentifier = (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
- length--;
- } while (*(u_char *) bufp++ & ASN_BIT8); /* last byte has high bit clear */
- if (subidentifier > (u_long) MAX_SUBID) {
- ERROR("subidentifier too long");
- return NULL;
- }
- *oidp++ = (oid) subidentifier;
- }
-
- /*
- * The first two subidentifiers are encoded into the first component
- * with the value (X * 40) + Y, where:
- * X is the value of the first subidentifier.
- * Y is the value of the second subidentifier.
- */
- subidentifier = (u_long) objid[1];
- if (subidentifier == 0x2B) {
- objid[0] = 1;
- objid[1] = 3;
- } else {
- objid[1] = (u_char) (subidentifier % 40);
- objid[0] = (u_char) ((subidentifier - objid[1]) / 40);
- }
-
- *objidlength = (int) (oidp - objid);
- return bufp;
+u_char *asn_parse_objid(u_char *data, int *datalength,
+ u_char *type, oid *objid, int *objidlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char *type; OUT - ASN type of object */
+ /* oid *objid; IN/OUT - pointer to start of output buffer */
+ /* int *objidlength; IN/OUT - number of sub-id's in objid */
+{
+ /*
+ * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+ * subidentifier ::= {leadingbyte}* lastbyte
+ * leadingbyte ::= 1 7bitvalue
+ * lastbyte ::= 0 7bitvalue
+ */
+ u_char *bufp = data;
+ oid *oidp = objid + 1;
+ u_int subidentifier;
+ int length;
+ u_int asn_length;
+
+ *type = *bufp++;
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ if (asn_length + (bufp - data) > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+ *datalength -= (int)asn_length + (bufp - data);
+
+ /* Handle invalid object identifier encodings of the form 06 00 robustly */
+ if (asn_length == 0)
+ objid[0] = objid[1] = 0;
+
+ length = asn_length;
+ (*objidlength)--; /* account for expansion of first byte */
+ while (length > 0 && (*objidlength)-- > 0) {
+ subidentifier = 0;
+
+ do { /* shift and add in low order 7 bits */
+ subidentifier = (subidentifier << 7)
+ + (*(u_char *)bufp & ~ASN_BIT8);
+ length--;
+ } while (*(u_char *)bufp++ & ASN_BIT8);
+
+ /* while last byte has high bit clear */
+ if (subidentifier > (u_int)MAX_SUBID) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+ *oidp++ = (oid)subidentifier;
+ }
+
+ /*
+ * The first two subidentifiers are encoded into the first component
+ * with the value (X * 40) + Y, where:
+ * X is the value of the first subidentifier.
+ * Y is the value of the second subidentifier.
+ */
+ subidentifier = (u_int)objid[1];
+ if (subidentifier == 0x2B) {
+ objid[0] = 1;
+ objid[1] = 3;
+ } else {
+ objid[1] = (u_char)(subidentifier % 40);
+ objid[0] = (u_char)((subidentifier - objid[1]) / 40);
+ }
+
+ *objidlength = (int)(oidp - objid);
+ return(bufp);
}
/*
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_objid(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - ASN type of object */
- oid * objid, /* IN - pointer to start of input buffer */
- int objidlength)
-{ /* IN - number of sub-id's in objid */
-/*
- * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
- * subidentifier ::= {leadingbyte}* lastbyte
- * leadingbyte ::= 1 7bitvalue
- * lastbyte ::= 0 7bitvalue
- */
- u_char buf[MAX_OID_LEN];
- u_char *bp = buf;
- oid *op = objid;
- int asnlength;
- u_long subid, mask, testmask;
- int bits, testbits;
-
- if (objidlength < 2) {
- *bp++ = 0;
- objidlength = 0;
+u_char *asn_build_objid(u_char *data, int *datalength,
+ u_char type, oid *objid, int objidlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char type; IN - ASN type of object */
+ /* oid *objid; IN - pointer to start of input buffer */
+ /* int objidlength; IN - number of sub-id's in objid */
+{
+ /*
+ * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+ * subidentifier ::= {leadingbyte}* lastbyte
+ * leadingbyte ::= 1 7bitvalue
+ * lastbyte ::= 0 7bitvalue
+ */
+ u_char buf[MAX_OID_LEN];
+ u_char *bp = buf;
+ oid *op = objid;
+ int asnlength;
+ u_int subid, mask, testmask;
+ int bits, testbits;
+
+ if (objidlength < 2) {
+ *bp++ = 0;
+ objidlength = 0;
+ } else {
+ *bp++ = op[1] + (op[0] * 40);
+ objidlength -= 2;
+ op += 2;
+ }
+
+ while(objidlength-- > 0) {
+ subid = *op++;
+ if (subid < 127) { /* off by one? */
+ *bp++ = subid;
} else {
- *bp++ = op[1] + (op[0] * 40);
- objidlength -= 2;
- op += 2;
- }
-
- while (objidlength-- > 0) {
- subid = *op++;
- if (subid < 127) { /* off by one? */
- *bp++ = subid;
- } else {
- mask = 0x7F; /* handle subid == 0 case */
- bits = 0;
- /* testmask *MUST* !!!! be of an unsigned type */
- for (testmask = 0x7F, testbits = 0; testmask != 0;
- testmask <<= 7, testbits += 7) {
- if (subid & testmask) { /* if any bits set */
- mask = testmask;
- bits = testbits;
- }
- }
- /* mask can't be zero here */
- for (; mask != 0x7F; mask >>= 7, bits -= 7) {
- /* fix a mask that got truncated above */
- if (mask == 0x1E00000)
- mask = 0xFE00000;
- *bp++ = (u_char) (((subid & mask) >> bits) | ASN_BIT8);
- }
- *bp++ = (u_char) (subid & mask);
+ mask = 0x7F; /* handle subid == 0 case */
+ bits = 0;
+ /* testmask *MUST* !!!! be of an unsigned type */
+ for(testmask = 0x7F, testbits = 0; testmask != 0;
+ testmask <<= 7, testbits += 7) {
+ if (subid & testmask) { /* if any bits set */
+ mask = testmask;
+ bits = testbits;
}
- }
- asnlength = bp - buf;
- data = asn_build_header(data, datalength, type, asnlength);
- if (data == NULL)
- return NULL;
- if (*datalength < asnlength)
- return NULL;
- xmemcpy(data, buf, asnlength);
- *datalength -= asnlength;
- return data + asnlength;
+ }
+ /* mask can't be zero here */
+ for(;mask != 0x7F; mask >>= 7, bits -= 7) {
+ /* fix a mask that got truncated above */
+ if (mask == 0x1E00000)
+ mask = 0xFE00000;
+ *bp++ = (u_char)(((subid & mask) >> bits) | ASN_BIT8);
+ }
+ *bp++ = (u_char)(subid & mask);
+ }
+ }
+
+ asnlength = bp - buf;
+ data = asn_build_header_with_truth(data, datalength, type, asnlength, 1);
+ if (data == NULL)
+ return(NULL);
+ if (*datalength < asnlength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+ xmemcpy((char *)data, (char *)buf, asnlength);
+ *datalength -= asnlength;
+ return(data + asnlength);
}
/*
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_null(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type)
-{ /* OUT - ASN type of object */
-/*
- * ASN.1 null ::= 0x05 0x00
- */
- u_char *bufp = data;
- u_long asn_length;
-
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL)
- return NULL;
- if (asn_length != 0) {
- ERROR("Malformed NULL");
- return NULL;
- }
- *datalength -= (bufp - data);
- return bufp + asn_length;
+u_char *asn_parse_null(u_char *data, int *datalength, u_char *type)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char *type; OUT - ASN type of object */
+{
+ /*
+ * ASN.1 null ::= 0x05 0x00
+ */
+ u_char *bufp = data;
+ u_int asn_length;
+
+ *type = *bufp++;
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ if (asn_length != 0) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ *datalength -= (bufp - data);
+ return(bufp + asn_length);
}
-
/*
* asn_build_null - Builds an ASN null object.
* On entry, datalength is input as the number of valid bytes following
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_null(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type)
-{ /* IN - ASN type of object */
-/*
- * ASN.1 null ::= 0x05 0x00
- */
- return asn_build_header(data, datalength, type, 0);
+u_char *asn_build_null(u_char *data, int *datalength, u_char type)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char type; IN - ASN type of object */
+{
+ /*
+ * ASN.1 null ::= 0x05 0x00
+ */
+ return(asn_build_header_with_truth(data, datalength, type, 0, 1));
}
/*
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_parse_bitstring(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - asn type of object */
- u_char * string, /* IN/OUT - pointer to start of output buffer */
- int *strlength)
-{ /* IN/OUT - size of output buffer */
-/*
- * bitstring ::= 0x03 asnlength unused {byte}*
- */
- u_char *bufp = data;
- u_long asn_length;
-
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL)
- return NULL;
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- if (asn_length > *strlength) {
- ERROR("I don't support such long bitstrings");
- return NULL;
- }
- if (asn_length < 1) {
- ERROR("Invalid bitstring");
- return NULL;
- }
- if ( /** *bufp < 0 || **/ *bufp > 7) {
- ERROR("Invalid bitstring");
- return NULL;
- }
- xmemcpy(string, bufp, (int) asn_length);
- *strlength = (int) asn_length;
- *datalength -= (int) asn_length + (bufp - data);
- return bufp + asn_length;
+u_char *asn_parse_bitstring(u_char *data, int *datalength,
+ u_char *type, u_char *string, int *strlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char *type; OUT - asn type of object */
+ /* u_char *string; IN/OUT - pointer to start of output buf */
+ /* int *strlength; IN/OUT - size of output buffer */
+{
+ /*
+ * bitstring ::= 0x03 asnlength unused {byte}*
+ */
+ u_char *bufp = data;
+ u_int asn_length;
+
+ *type = *bufp++;
+ bufp = asn_parse_length(bufp, &asn_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ if (asn_length + (bufp - data) > *datalength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ if (asn_length > *strlength) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ if (asn_length < 1) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ if ((int)(*(char *)bufp) < 0 || (int)(*bufp) > 7) {
+ snmp_set_api_error(SNMPERR_ASN_DECODE);
+ return(NULL);
+ }
+
+ xmemcpy((char *)string, (char *)bufp, (int)asn_length);
+ *strlength = (int)asn_length;
+ *datalength -= (int)asn_length + (bufp - data);
+ return(bufp + asn_length);
}
-
/*
* asn_build_bitstring - Builds an ASN bit string object containing the
* input string.
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
*/
-u_char *
-asn_build_bitstring(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - ASN type of string */
- u_char * string, /* IN - pointer to start of input buffer */
- int strlength)
-{ /* IN - size of input buffer */
-/*
- * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
- */
- if (strlength < 1 || /** *string < 0 || **/ *string > 7) {
- ERROR("Building invalid bitstring");
- return NULL;
- }
- data = asn_build_header(data, datalength, type, strlength);
- if (data == NULL)
- return NULL;
- if (*datalength < strlength)
- return NULL;
- xmemcpy(data, string, strlength);
- *datalength -= strlength;
- return data + strlength;
+u_char *asn_build_bitstring(u_char *data, int *datalength,
+ u_char type, u_char *string, int strlength)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char type; IN - ASN type of string */
+ /* u_char *string; IN - pointer to start of input buffer */
+ /* int strlength; IN - size of input buffer */
+{
+ /*
+ * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
+ */
+ if ((strlength < 1) || ((*(char *)string) < 0) || ((*string) > 7)) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
+ if (data == NULL)
+ return(NULL);
+
+ if (*datalength < strlength) {
+ snmp_set_api_error(SNMPERR_ASN_ENCODE);
+ return(NULL);
+ }
+
+ xmemcpy((char *)data, (char *)string, strlength);
+ *datalength -= strlength;
+ return(data + strlength);
}
/*
- * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
- * type.
- * On entry, datalength is input as the number of valid bytes following
- * "data". On exit, it is returned as the number of valid bytes
- * following the end of this object.
- *
- * Returns a pointer to the first byte past the end
- * of this object (i.e. the start of the next object).
- * Returns NULL on any error.
- */
-u_char *
-asn_parse_unsigned_int64(
- u_char * data, /* IN - pointer to start of object */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char * type, /* OUT - asn type of object */
- struct counter64 * cp, /* IN/OUT -pointer to counter struct */
- int countersize)
-{ /* IN - size of output buffer */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+ * To do: Write an asn_parse_exception function to go with the new
+ * asn_build_exception function below so that the exceptional values can
+ * be handled in input packets aswell as output ones.
*/
- u_char *bufp = data;
- u_long asn_length;
- u_long low = 0, high = 0;
- int intsize = 4;
-
- if (countersize != sizeof(struct counter64)) {
- ERROR("not counter64 size");
- return NULL;
- }
- *type = *bufp++;
- bufp = asn_parse_length(bufp, &asn_length);
- if (bufp == NULL) {
- ERROR("bad length");
- return NULL;
- }
- if (asn_length + (bufp - data) > *datalength) {
- ERROR("overflow of message");
- return NULL;
- }
- if ((asn_length > (intsize * 2 + 1)) ||
- ((asn_length == (intsize * 2) + 1) && *bufp != 0x00)) {
- ERROR("I don't support such large integers");
- return NULL;
- }
- *datalength -= (int) asn_length + (bufp - data);
- if (*bufp & 0x80) {
- low = -1; /* integer is negative */
- high = -1;
- }
- while (asn_length--) {
- high = (high << 8) | ((low & 0xFF000000) >> 24);
- low = (low << 8) | *bufp++;
- }
- cp->low = low;
- cp->high = high;
- return bufp;
-}
-
/*
- * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
+ * asn_build_exception - Builds an ASN exception object.
* On entry, datalength is input as the number of valid bytes following
* "data". On exit, it is returned as the number of valid bytes
- * following the end of this object.
+ * following the beginning of the next object.
*
* Returns a pointer to the first byte past the end
* of this object (i.e. the start of the next object).
* Returns NULL on any error.
- */
-u_char *
-asn_build_unsigned_int64(
- u_char * data, /* IN - pointer to start of output buffer */
- int *datalength, /* IN/OUT - number of valid bytes left in buffer */
- u_char type, /* IN - asn type of object */
- struct counter64 * cp, /* IN - pointer to counter struct */
- int countersize)
-{ /* IN - size of *intp */
-/*
- * ASN.1 integer ::= 0x02 asnlength byte {byte}*
- */
-
- u_num32 low, high;
- u_num32 mask, mask2;
- int add_null_byte = 0;
- int intsize;
-
- if (countersize != sizeof(struct counter64)) {
- ERROR("not counter64 size");
- return NULL;
- }
- intsize = 8;
- low = cp->low;
- high = cp->high;
- mask = 0xFF << (8 * (NUM32LEN - 1));
- /* mask is 0xFF000000 on a big-endian machine */
- if ((u_char) ((high & mask) >> (8 * (NUM32LEN - 1))) & 0x80) {
- /* if MSB is set */
- add_null_byte = 1;
- intsize++;
- }
- /*
- * Truncate "unnecessary" bytes off of the most significant end of this 2's
- * complement integer.
- * There should be no sequence of 9 consecutive 1's or 0's at the most
- * significant end of the integer.
- */
- mask2 = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
- /* mask2 is 0xFF800000 on a big-endian machine */
- while ((((high & mask2) == 0) || ((high & mask2) == mask2))
- && intsize > 1) {
- intsize--;
- high = (high << 8)
- | ((low & mask) >> (8 * (NUM32LEN - 1)));
- low <<= 8;
- }
- data = asn_build_header(data, datalength, type, intsize);
- if (data == NULL)
- return NULL;
- if (*datalength < intsize)
- return NULL;
- *datalength -= intsize;
- if (add_null_byte == 1) {
- *data++ = '\0';
- intsize--;
- }
- while (intsize--) {
- *data++ = (u_char) ((high & mask) >> (8 * (NUM32LEN - 1)));
- high = (high << 8)
- | ((low & mask) >> (8 * (NUM32LEN - 1)));
- low <<= 8;
-
- }
- return data;
+ *
+ * ASN.1 variable exception ::= 0x8i 0x00, where 'i' is one of these
+ * exception identifiers:
+ * 0 -- noSuchObject
+ * 1 -- noSuchInstance
+ * 2 -- endOfMibView
+ */
+u_char *asn_build_exception(u_char *data, int *datalength, u_char type)
+ /* u_char *data; IN - pointer to start of object */
+ /* int *datalength; IN/OUT - # of valid bytes left in buf */
+ /* u_char type; IN - ASN type of object */
+{
+ return(asn_build_header_with_truth(data, datalength, type, 0, 1));
}
--- /dev/null
+/*
+ * RFC 1908: Coexistence between SNMPv1 and 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 "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"
+#include "snmp_pdu.h"
+#include "snmp_error.h"
+#include "snmp_api_error.h"
+
+#include "util.h"
+
+/*
+ * RFC 1908: Coexistence between SNMPv1 and SNMPv2
+ *
+ * These convert:
+ *
+ * V1 PDUs from an ** AGENT ** to V2 PDUs for an ** MANAGER **
+ * V2 PDUs from an ** MANAGER ** to V1 PDUs for an ** AGENT **
+ *
+ * We will never convert V1 information from a manager into V2 PDUs. V1
+ * requests are always honored by V2 agents, and the responses will be
+ * valid V1 responses. (I think. XXXXX)
+ *
+ */
+int snmp_coexist_V2toV1(struct snmp_pdu *PDU)
+{
+ /* Per 3.1.1:
+ */
+ switch (PDU->command) {
+
+ case SNMP_PDU_GET:
+ case SNMP_PDU_GETNEXT:
+ case SNMP_PDU_SET:
+ return(1);
+ break;
+
+ case SNMP_PDU_GETBULK:
+ PDU->non_repeaters = 0;
+ PDU->max_repetitions = 0;
+ PDU->command = SNMP_PDU_GETNEXT;
+ return(1);
+ break;
+
+ default:
+ snmplib_debug(2, "Unable to translate PDU %d to SNMPv1!\n", PDU->command);
+ snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+ return(0);
+ }
+}
+
+oid SysUptime[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
+/* SNMPv2: .1 .3 .6 .1 .6
+ * snmpModules: .3
+ * snmpMib: .1
+ * snmpMIBObjects: .1
+ * snmpTrap: .4
+ */
+oid TrapOid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
+oid EnterOid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 3, 0};
+oid snmpTrapsOid[]= { 1, 3, 6, 1, 6, 3, 1, 1, 5};
+
+int snmp_coexist_V1toV2(struct snmp_pdu *PDU)
+{
+ /* Per 3.1.2:
+ */
+ switch (PDU->command) {
+
+ case SNMP_PDU_RESPONSE:
+
+ if (PDU->errstat == SNMP_ERR_TOOBIG) {
+ snmp_var_free(PDU->variables);
+ PDU->variables = NULL;
+ }
+ return(1);
+ break;
+
+ case TRP_REQ_MSG:
+ {
+ struct variable_list *VarP;
+ oid NewOid[MAX_NAME_LEN];
+ oid NewOidLen = 0;
+
+ /* Fake SysUptime */
+ VarP = snmp_var_new(SysUptime, sizeof(SysUptime) / sizeof(oid));
+ if (VarP == NULL)
+ return(0);
+ VarP->type = ASN_INTEGER;
+ *VarP->val.integer = PDU->time;
+
+ /* Fake SNMPTrapOid */
+ VarP->next_variable = snmp_var_new(TrapOid, sizeof(TrapOid) / sizeof(oid));
+ if (VarP == NULL) {
+ snmp_var_free(VarP);
+ return(0);
+ }
+
+ if (PDU->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
+ xmemcpy(NewOid, PDU->enterprise, PDU->enterprise_length);
+ NewOidLen = PDU->enterprise_length;
+ NewOid[NewOidLen++] = 0;
+ NewOid[NewOidLen++] = PDU->specific_type;
+ } else {
+
+ /* Trap prefix */
+ NewOidLen = sizeof(snmpTrapsOid) / sizeof(oid);
+ xmemcpy(NewOid, snmpTrapsOid, NewOidLen);
+
+ switch (PDU->trap_type) {
+ case SNMP_TRAP_COLDSTART:
+ NewOid[NewOidLen++] = 1;
+ break;
+ case SNMP_TRAP_WARMSTART:
+ NewOid[NewOidLen++] = 2;
+ break;
+ case SNMP_TRAP_LINKDOWN:
+ NewOid[NewOidLen++] = 3; /* RFC 1573 */
+ break;
+ case SNMP_TRAP_LINKUP:
+ NewOid[NewOidLen++] = 4; /* RFC 1573 */
+ break;
+ case SNMP_TRAP_AUTHENTICATIONFAILURE:
+ NewOid[NewOidLen++] = 5;
+ break;
+ case SNMP_TRAP_EGPNEIGHBORLOSS:
+ NewOid[NewOidLen++] = 6; /* RFC 1213 */
+ break;
+ default:
+ snmplib_debug(2, "Unable to translate v1 trap type %d!\n",
+ PDU->trap_type);
+ snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+ return(0);
+ }
+ }
+
+ /* ASSERT: NewOid contains the new OID. */
+ VarP->next_variable->type = ASN_OBJECT_ID;
+ VarP->next_variable->val_len = NewOidLen;
+ VarP->next_variable->val.string = xmalloc(sizeof(oid)*NewOidLen);
+ if (VarP->next_variable->val.string == NULL) {
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(0);
+ }
+ xmemcpy((char *)VarP->next_variable->val.string,
+ (char *)NewOid,
+ sizeof(oid)*NewOidLen);
+
+ /* Prepend this list */
+ VarP->next_variable->next_variable = PDU->variables;
+ PDU->variables = VarP;
+
+ /* Finally, append the last piece */
+
+ for(VarP = PDU->variables; VarP->next_variable; VarP=VarP->next_variable)
+ ; /* Find the last element of the list. */
+
+ VarP->next_variable = snmp_var_new(EnterOid,
+ sizeof(EnterOid) / sizeof(oid));
+ if (VarP->next_variable == NULL)
+ return(0);
+ VarP->next_variable->type = ASN_OBJECT_ID;
+ VarP->next_variable->val_len = PDU->enterprise_length;
+ VarP->next_variable->val.string = (u_char *)PDU->enterprise;
+
+ PDU->command = SNMP_PDU_V2TRAP;
+
+ } /* End of trap conversion */
+ return(1);
+ break;
+ default:
+ snmplib_debug(2, "Unable to translate PDU %d to SNMPv2!\n", PDU->command);
+ snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+ return(0);
+ }
+}
-
-/**********************************************************************
- Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
+/***********************************************************
+ Copyright 1988, 1989 by Carnegie Mellon University
All Rights Reserved
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
+
#include "config.h"
+#include <stdio.h>
+
#if HAVE_UNISTD_H
#include <unistd.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
#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 "asn1.h"
#include "snmp.h"
+
+#include "snmp_pdu.h"
+#include "snmp_vars.h"
+#include "snmp_session.h"
#include "snmp_impl.h"
#include "snmp_api.h"
#include "parse.h"
-#include "mib.h"
-
#include "util.h"
#include "snprintf.h"
-/* fwd: */
static void sprint_by_type();
-char *snmp_new_prefix(char *);
-static void set_functions();
-static int parse_subtree();
-static int lc_cmp();
-static void sprint_variable();
-static struct tree *get_symbol();
static char *
-uptimeString(unsigned long timeticks, char *buf)
+uptimeString(timeticks, buf)
+ int timeticks;
+ char *buf;
{
- int seconds, minutes, hours, days;
+ int seconds, minutes, hours, days;
timeticks /= 100;
days = timeticks / (60 * 60 * 24);
minutes = timeticks / 60;
seconds = timeticks % 60;
- if (days == 0) {
- snprintf(buf, 32, "%d:%02d:%02d", hours, minutes, seconds);
+ if (days == 0){
+ snprintf(buf,32, "%d:%02d:%02d", hours, minutes, seconds);
} else if (days == 1) {
- snprintf(buf, 32, "%d day, %d:%02d:%02d", days, hours, minutes, seconds);
+ snprintf(buf,32, "%d day, %d:%02d:%02d", days, hours, minutes, seconds);
} else {
- snprintf(buf, 32, "%d days, %d:%02d:%02d", days, hours, minutes, seconds);
+ snprintf(buf,32, "%d days, %d:%02d:%02d", days, hours, minutes, seconds);
}
return buf;
}
-static void
-sprint_hexstring(char *buf, unsigned char *cp, int len)
+static void sprint_hexstring(buf, cp, len)
+ char *buf;
+ u_char *cp;
+ int len;
{
- for (; len >= 16; len -= 16) {
- sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ for(; len >= 16; len -= 16){
+ snprintf(buf,26, "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
buf += strlen(buf);
cp += 8;
- sprintf(buf, "%02X %02X %02X %02X %02X %02X %02X %02X\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
+ snprintf(buf,26, "%02X %02X %02X %02X %02X %02X %02X %02X\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
buf += strlen(buf);
cp += 8;
}
- for (; len > 0; len--) {
- sprintf(buf, "%02X ", *cp++);
+ for(; len > 0; len--){
+ snprintf(buf, 4, "%02X ", *cp++);
buf += strlen(buf);
}
*buf = '\0';
}
-static void
-sprint_asciistring(char *buf, unsigned char *cp, int len)
+static void sprint_asciistring(buf, cp, len)
+ char *buf;
+ u_char *cp;
+ int len;
{
- int x;
+ int x;
- for (x = 0; x < len; x++) {
- if (isprint(*cp)) {
+ for(x = 0; x < len; x++){
+ if (isprint(*cp)){
*buf++ = *cp++;
} else {
*buf++ = '.';
cp++;
}
-#if 0
if ((x % 48) == 47)
*buf++ = '\n';
-#endif
}
*buf = '\0';
}
-#ifdef UNUSED
-int
-read_rawobjid(char *input, oid * output, int *out_len)
-{
- char buf[12], *cp;
- oid *op = output;
- u_long subid;
-
- while (*input != '\0') {
- if (!isdigit(*input))
- break;
- cp = buf;
- while (isdigit(*input))
- *cp++ = *input++;
- *cp = '\0';
- subid = atoi(buf);
- if (subid > MAX_SUBID) {
- fprintf(stderr, "sub-identifier too large: %s\n", buf);
- return 0;
- }
- if ((*out_len)-- <= 0) {
- fprintf(stderr, "object identifier too long\n");
- return 0;
- }
- *op++ = subid;
- if (*input++ != '.')
- break;
- }
- *out_len = op - output;
- if (*out_len == 0)
- return 0;
- return 1;
-}
-
-#endif /* UNUSED */
-
-/*
- * 0
- * < 4
- * hex
- *
- * 0 ""
- * < 4 hex Hex: oo oo oo
- * < 4 "fgh" Hex: oo oo oo
- * > 4 hex Hex: oo oo oo oo oo oo oo oo
- * > 4 "this is a test"
- *
- */
static void
-sprint_octet_string(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_octet_string(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+ int quiet;
{
int hex, x;
u_char *cp;
- if (var->type != ASN_OCTET_STR) {
+ if (var->type != ASN_OCTET_STR){
sprintf(buf, "Wrong Type (should be OCTET STRING): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
hex = 0;
- for (cp = var->val.string, x = 0; x < var->val_len; x++, cp++) {
+ for(cp = var->val.string, x = 0; x < var->val_len; x++, cp++){
if (!(isprint(*cp) || isspace(*cp)))
hex = 1;
}
- if (var->val_len == 0) {
- strcpy(buf, "\"\"");
- return;
- }
- if (!hex) {
- *buf++ = '"';
- sprint_asciistring(buf, var->val.string, var->val_len);
- buf += strlen(buf);
- *buf++ = '"';
- *buf = '\0';
- }
- if (hex || var->val_len <= 4) {
- sprintf(buf, " Hex: ");
+ if (var->val_len <= 4)
+ hex = 1; /* not likely to be ascii */
+ if (hex){
+ if (!quiet) {
+ sprintf(buf, "OCTET STRING- (hex):\t");
buf += strlen(buf);
+ }
sprint_hexstring(buf, var->val.string, var->val_len);
+ } else {
+ if (!quiet) {
+ sprintf(buf, "OCTET STRING- (ascii):\t");
+ buf += strlen(buf);
+ }
+ sprint_asciistring(buf, var->val.string, var->val_len);
}
}
static void
-sprint_opaque(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_opaque(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+ void *foo;
+ int quiet;
{
- if (var->type != OPAQUE) {
+ if (var->type != SMI_OPAQUE){
sprintf(buf, "Wrong Type (should be Opaque): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "OPAQUE: ");
- buf += strlen(buf);
+ if (!quiet) {
+ sprintf(buf, "OPAQUE - (hex):\t");
+ buf += strlen(buf);
+ }
sprint_hexstring(buf, var->val.string, var->val_len);
}
static void
-sprint_object_identifier(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_object_identifier(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+ void *foo;
+ int quiet;
{
- if (var->type != ASN_OBJECT_ID) {
+ if (var->type != SMI_OBJID){
sprintf(buf, "Wrong Type (should be OBJECT IDENTIFIER): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "OID: ");
- buf += strlen(buf);
- sprint_objid(buf, (oid *) (var->val.objid), var->val_len / sizeof(oid));
+ if (!quiet) {
+ sprintf(buf, "OBJECT IDENTIFIER:\t");
+ buf += strlen(buf);
+ }
+ sprint_objid(buf, (oid *)(var->val.objid), var->val_len / sizeof(oid));
}
static void
-sprint_timeticks(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_timeticks(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+ void *foo;
+ int quiet;
{
char timebuf[32];
- if (var->type != TIMETICKS) {
+ if (var->type != SMI_TIMETICKS){
sprintf(buf, "Wrong Type (should be Timeticks): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "Timeticks: (%ld) %s", *(u_long *) (var->val.integer),
- uptimeString(*(u_long *) (var->val.integer), timebuf));
+ if (!quiet) {
+ sprintf(buf, "Timeticks: ");
+ buf += strlen(buf);
+ }
+ sprintf(buf, "(%u) %s",
+ *(var->val.integer),
+ uptimeString(*(var->val.integer), timebuf));
}
static void
-sprint_integer(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_integer(buf, var, enums, quiet)
+ char *buf;
+ variable_list *var;
+ struct enum_list *enums;
+ int quiet;
{
- char *enum_string = NULL;
+ char *enum_string = NULL;
- if (var->type != ASN_INTEGER) {
+ if (var->type != SMI_INTEGER){
sprintf(buf, "Wrong Type (should be INTEGER): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
for (; enums; enums = enums->next)
- if (enums->value == *var->val.integer) {
+ if (enums->value == *var->val.integer){
enum_string = enums->label;
break;
}
- if (enum_string == NULL)
- sprintf(buf, "%ld", *var->val.integer);
- else
- sprintf(buf, "%s(%ld)", enum_string, *var->val.integer);
-}
-
-static void
-sprint_uinteger(char *buf, struct variable_list *var, struct enum_list *enums)
-{
- char *enum_string = NULL;
- if (var->type != UINTEGER) {
- sprintf(buf, "Wrong Type (should be UInteger32): ");
- buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
- return;
+ if (!quiet) {
+ sprintf(buf, "INTEGER: ");
+ buf += strlen(buf);
}
- for (; enums; enums = enums->next)
- if (enums->value == *var->val.integer) {
- enum_string = enums->label;
- break;
- }
+
if (enum_string == NULL)
- sprintf(buf, "%ld", *var->val.integer);
+ sprintf(buf, "%u", *var->val.integer);
else
- sprintf(buf, "%s(%ld)", enum_string, *var->val.integer);
+ sprintf(buf, "%s(%u)", enum_string, *var->val.integer);
}
static void
-sprint_gauge(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_gauge(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+int quiet;
{
- if (var->type != GAUGE) {
+ if (var->type != SMI_GAUGE32){
sprintf(buf, "Wrong Type (should be Gauge): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "Gauge: %lu", *var->val.integer);
+ if (!quiet) {
+ sprintf(buf, "Gauge: ");
+ buf += strlen(buf);
+ }
+ sprintf(buf, "%u", *var->val.integer);
}
static void
-sprint_counter(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_counter(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+ int quiet;
{
- if (var->type != COUNTER) {
+ if (var->type != SMI_COUNTER32){
sprintf(buf, "Wrong Type (should be Counter): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "%lu", *var->val.integer);
+ if (!quiet) {
+ sprintf(buf, "Counter: ");
+ buf += strlen(buf);
+ }
+ sprintf(buf, "%u", *var->val.integer);
}
static void
-sprint_networkaddress(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_networkaddress(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+ int quiet;
{
int x, len;
u_char *cp;
- sprintf(buf, "Network Address: ");
- buf += strlen(buf);
- cp = var->val.string;
+ if (!quiet) {
+ sprintf(buf, "Network Address:\t");
+ buf += strlen(buf);
+ }
+ cp = var->val.string;
len = var->val_len;
- for (x = 0; x < len; x++) {
+ for(x = 0; x < len; x++){
sprintf(buf, "%02X", *cp++);
buf += strlen(buf);
if (x < (len - 1))
}
static void
-sprint_ipaddress(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_ipaddress(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+int quiet;
{
u_char *ip;
- if (var->type != IPADDRESS) {
+ if (var->type != SMI_IPADDRESS){
sprintf(buf, "Wrong Type (should be Ipaddress): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
ip = var->val.string;
- sprintf(buf, "IpAddress: %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+ if (!quiet) {
+ sprintf(buf, "IPAddress:\t");
+ buf += strlen(buf);
+ }
+ sprintf(buf, "%d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]);
}
#if 0
static void
-sprint_unsigned_short(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_unsigned_short(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+ int quiet;
{
- if (var->type != ASN_INTEGER) {
+ if (var->type != SMI_INTEGER){
sprintf(buf, "Wrong Type (should be INTEGER): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
- sprintf(buf, "INT: %lu", *var->val.integer);
+ if (!quiet) {
+ sprintf(buf, "INTEGER (0..65535): ");
+ buf += strlen(buf);
+ }
+ sprintf(buf, "%u", *var->val.integer);
}
-#endif
+#endif
static void
-sprint_null(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_null(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+int quiet;
{
- if (var->type != ASN_NULL) {
+ if (var->type != SMI_NULLOBJ){
sprintf(buf, "Wrong Type (should be NULL): ");
buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
+ sprint_by_type(buf, var, (struct enum_list *)NULL, quiet);
return;
}
sprintf(buf, "NULL");
}
static void
-sprint_bitstring(char *buf, struct variable_list *var, struct enum_list *enums)
-{
- int len, bit;
- u_char *cp;
- char *enum_string;
-
- if (var->type != ASN_BIT_STR) {
- sprintf(buf, "Wrong Type (should be BIT STRING): ");
- buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
- return;
- }
- sprintf(buf, "BIT_STRING: ");
- buf += strlen(buf);
- sprint_hexstring(buf, var->val.bitstring, var->val_len);
- buf += strlen(buf);
-
- cp = var->val.bitstring + 1;
- for (len = 0; len < var->val_len - 1; len++) {
- for (bit = 0; bit < 8; bit++) {
- if (*cp & (0x80 >> bit)) {
- enum_string = NULL;
- for (; enums; enums = enums->next)
- if (enums->value == (len * 8) + bit) {
- enum_string = enums->label;
- break;
- }
- if (enum_string == NULL)
- sprintf(buf, "%d ", (len * 8) + bit);
- else
- sprintf(buf, "%s(%d) ", enum_string, (len * 8) + bit);
- buf += strlen(buf);
- }
- }
- cp++;
- }
-}
-
-static void
-sprint_nsapaddress(char *buf, struct variable_list *var, struct enum_list *enums)
-{
- if (var->type != NSAP) {
- sprintf(buf, "Wrong Type (should be NsapAddress): ");
- buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
- return;
- }
- sprintf(buf, "NsapAddress: ");
- buf += strlen(buf);
- sprint_hexstring(buf, var->val.string, var->val_len);
-}
-
-static void
-sprint_counter64(char *buf, struct variable_list *var, struct enum_list *enums)
-{
- if (var->type != COUNTER64) {
- sprintf(buf, "Wrong Type (should be Counter64): ");
- buf += strlen(buf);
- sprint_by_type(buf, var, (struct enum_list *) NULL);
- return;
- }
-/* XXX */
- sprintf(buf, "Counter64: ");
- buf += strlen(buf);
-
- sprint_hexstring(buf, (unsigned char *) &var->val.counter64->high,
- sizeof(var->val.counter64->high));
- buf += strlen(buf);
- sprint_hexstring(buf, (unsigned char *) &var->val.counter64->low,
- sizeof(var->val.counter64->low));
-}
-
-
-static void
-sprint_unknowntype(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_unknowntype(buf, var, foo, quiet)
+ char *buf;
+ variable_list *var;
+void *foo;
+int quiet;
{
/* sprintf(buf, "Variable has bad type"); */
- sprint_by_type(buf, var, NULL);
+ sprint_by_type(buf, var, foo, quiet);
}
static void
-sprint_badtype(char *buf, struct variable_list *var, struct enum_list *enums)
+sprint_badtype(buf)
+ char *buf;
{
sprintf(buf, "Variable has bad type");
}
static void
-sprint_by_type(char *buf, struct variable_list *var, struct enum_list *enums)
-{
- switch (var->type) {
- case ASN_INTEGER:
- sprint_integer(buf, var, enums);
- break;
- case ASN_OCTET_STR:
- sprint_octet_string(buf, var, enums);
- break;
- case OPAQUE:
- sprint_opaque(buf, var, enums);
- break;
- case ASN_OBJECT_ID:
- sprint_object_identifier(buf, var, enums);
- break;
- case TIMETICKS:
- sprint_timeticks(buf, var, enums);
- break;
- case GAUGE:
- sprint_gauge(buf, var, enums);
- break;
- case COUNTER:
- sprint_counter(buf, var, enums);
- break;
- case IPADDRESS:
- sprint_ipaddress(buf, var, enums);
- break;
- case ASN_NULL:
- sprint_null(buf, var, enums);
- break;
- case UINTEGER:
- sprint_uinteger(buf, var, enums);
- break;
- default:
- sprint_badtype(buf, var, enums);
- break;
- }
-}
-
-struct tree *get_symbol();
-
-oid RFC1213_MIB[] =
-{1, 3, 6, 1, 2, 1};
-unsigned char RFC1213_MIB_text[] = ".iso.org.dod.internet.mgmt.mib-2";
-unsigned char EXPERIMENTAL_MIB_text[] = ".iso.org.dod.internet.experimental";
-unsigned char PRIVATE_MIB_text[] = ".iso.org.dod.internet.private";
-unsigned char PARTY_MIB_text[] = ".iso.org.dod.internet.snmpParties";
-unsigned char SECRETS_MIB_text[] = ".iso.org.dod.internet.snmpSecrets";
-struct tree *Mib = 0;
-
-static char Standard_Prefix[] = ".1.3.6.1.2.1.";
-static char Prefix[256];
-static int Suffix;
-
-void
-init_mib(const char *file)
-{
- char *prefix;
- if (Mib != NULL)
- return;
-
- Mib = 0;
- if (file)
- Mib = read_mib(file);
- if (!Mib)
- Mib = read_mib("mib.txt");
-#ifdef MIBFILEPATH
- if (!Mib) {
- char tmp[1024];
- sprintf(tmp, "%s/mib.txt", MIBFILEPATH);
- Mib = read_mib(tmp);
- }
-#endif
- if (!Mib)
- Mib = read_mib("/etc/mib.txt");
- if (!Mib) {
- fprintf(stderr, "Couldn't find mib file\n");
- exit(2);
- }
- prefix = getenv("PREFIX");
- if (!prefix) {
- prefix = Standard_Prefix;
- }
- /* save prefix: */
- snmp_new_prefix(prefix);
-
- if (getenv("SUFFIX"))
- Suffix = TRUE;
- else
- Suffix = FALSE;
- set_functions(Mib);
-}
-
-
-/*
- * Phil Wood <cpw@lanl.gov>:
- *
- * [...] I made an addition to mib.c to accomodate some old perl snmp
- * code for a program called vulture that used a global pointer to the
- * prefix to change things.
- */
-
-char *
-snmp_new_prefix(char *prefix)
-{
- char *lastchar;
- int plen;
-
- if (prefix) {
- lastchar = ".";
- if (*prefix == '.') {
- prefix++;
- }
- if ((plen = strlen(prefix))) {
- lastchar = prefix + plen - 1;
- }
- strncpy(Prefix, prefix, sizeof(Prefix) - 2);
- Prefix[sizeof(Prefix) - 2] = 0;
- if (*lastchar != '.') {
- Prefix[plen++] = '.';
- Prefix[plen] = 0;
- }
- return Prefix;
- }
- return (char *) NULL;
-}
-
-
-
-static void
-set_functions(subtree)
- struct tree *subtree;
-{
- for (; subtree; subtree = subtree->next_peer) {
- switch (subtree->type) {
- case TYPE_OBJID:
- subtree->printer = sprint_object_identifier;
- break;
- case TYPE_OCTETSTR:
- subtree->printer = sprint_octet_string;
- break;
- case TYPE_INTEGER:
- subtree->printer = sprint_integer;
- break;
- case TYPE_NETADDR:
- subtree->printer = sprint_networkaddress;
- break;
- case TYPE_IPADDR:
- subtree->printer = sprint_ipaddress;
+sprint_by_type(buf, var, enums, quiet)
+ char *buf;
+ variable_list *var;
+ struct enum_list *enums;
+ int quiet;
+{
+ switch (var->type){
+ case SMI_INTEGER:
+ sprint_integer(buf, var, enums, quiet);
break;
- case TYPE_COUNTER:
- subtree->printer = sprint_counter;
+ case SMI_STRING:
+ sprint_octet_string(buf, var, enums, quiet);
break;
- case TYPE_GAUGE:
- subtree->printer = sprint_gauge;
+ case SMI_OPAQUE:
+ sprint_opaque(buf, var, enums, quiet);
break;
- case TYPE_TIMETICKS:
- subtree->printer = sprint_timeticks;
+ case SMI_OBJID:
+ sprint_object_identifier(buf, var, enums, quiet);
break;
- case TYPE_OPAQUE:
- subtree->printer = sprint_opaque;
+ case SMI_TIMETICKS:
+ sprint_timeticks(buf, var, enums, quiet);
break;
- case TYPE_NULL:
- subtree->printer = sprint_null;
+ case SMI_GAUGE32:
+ sprint_gauge(buf, var, enums, quiet);
break;
- case TYPE_BITSTRING:
- subtree->printer = sprint_bitstring;
+ case SMI_COUNTER32:
+ sprint_counter(buf, var, enums, quiet);
break;
- case TYPE_NSAPADDRESS:
- subtree->printer = sprint_nsapaddress;
+ case SMI_IPADDRESS:
+ sprint_ipaddress(buf, var, enums, quiet);
break;
- case TYPE_COUNTER64:
- subtree->printer = sprint_counter64;
+ case SMI_NULLOBJ:
+ sprint_null(buf, var, enums, quiet);
break;
- case TYPE_UINTEGER:
- subtree->printer = sprint_uinteger;
- break;
- case TYPE_OTHER:
default:
- subtree->printer = sprint_unknowntype;
+ sprint_badtype(buf, enums, quiet);
break;
- }
- set_functions(subtree->child_list);
}
}
-#ifdef testing
-int snmp_dump_packet = 0;
+static struct snmp_mib_tree *get_symbol();
-main(argc, argv)
- int argc;
- char *argv[];
+oid RFC1066_MIB[] = { 1, 3, 6, 1, 2, 1 };
+unsigned char RFC1066_MIB_text[] = ".iso.org.dod.internet.mgmt.mib";
+struct snmp_mib_tree *Mib;
+
+static void
+set_functions(subtree)
+ struct snmp_mib_tree *subtree;
{
- oid objid[64];
- int objidlen = sizeof(objid);
- int count;
- struct variable variable;
-
- init_mib();
- if (argc < 2)
- print_subtree(Mib, 0);
- variable.type = ASN_INTEGER;
- variable.val.integer = 3;
- variable.val_len = 4;
- for (argc--; argc; argc--, argv++) {
- objidlen = sizeof(objid);
- printf("read_objid(%s) = %d\n",
- argv[1], read_objid(argv[1], objid, &objidlen));
- for (count = 0; count < objidlen; count++)
- printf("%d.", objid[count]);
- printf("\n");
- print_variable(objid, objidlen, &variable);
+ for(; subtree; subtree = subtree->next_peer){
+ switch(subtree->type){
+ case TYPE_OBJID:
+ subtree->printer = sprint_object_identifier;
+ break;
+ case TYPE_OCTETSTR:
+ subtree->printer = sprint_octet_string;
+ break;
+ case TYPE_INTEGER:
+ subtree->printer = sprint_integer;
+ break;
+ case TYPE_NETADDR:
+ subtree->printer = sprint_networkaddress;
+ break;
+ case TYPE_IPADDR:
+ subtree->printer = sprint_ipaddress;
+ break;
+ case TYPE_COUNTER:
+ subtree->printer = sprint_counter;
+ break;
+ case TYPE_GAUGE:
+ subtree->printer = sprint_gauge;
+ break;
+ case TYPE_TIMETICKS:
+ subtree->printer = sprint_timeticks;
+ break;
+ case TYPE_OPAQUE:
+ subtree->printer = sprint_opaque;
+ break;
+ case TYPE_NULL:
+ subtree->printer = sprint_null;
+ break;
+ case TYPE_OTHER:
+ default:
+ subtree->printer = sprint_unknowntype;
+ break;
+ }
+ set_functions(subtree->child_list);
}
}
-#endif /* testing */
+void init_mib(char *file)
+{
+ if (snmplib_debug != NULL)
+ snmplib_debug(6, "init_mib: Called.\n");
+ if (Mib != NULL)
+ return;
+
+ if (file != NULL)
+ Mib = read_mib(file);
+ set_functions(Mib);
+}
-#if 0
-static struct tree *
-find_rfc1213_mib(root)
- struct tree *root;
+static struct snmp_mib_tree *
+find_rfc1066_mib(root)
+ struct snmp_mib_tree *root;
{
- oid *op = RFC1213_MIB;
- struct tree *tp;
+ oid *op = RFC1066_MIB;
+ struct snmp_mib_tree *tp;
int len;
- for (len = sizeof(RFC1213_MIB) / sizeof(oid); len; len--, op++) {
- for (tp = root; tp; tp = tp->next_peer) {
- if (tp->subid == *op) {
+ for(len = sizeof(RFC1066_MIB)/sizeof(oid); len; len--, op++){
+ for(tp = root; tp; tp = tp->next_peer){
+ if (tp->subid == *op){
root = tp->child_list;
break;
}
}
return root;
}
-#endif
-int
-read_objid(input, output, out_len)
- char *input;
- oid *output;
- int *out_len; /* number of subid's in "output" */
-{
- struct tree *root = Mib;
- oid *op = output;
- char buf[512];
-
- memset(buf, '\0', sizeof(buf));
-
- if (*input == '.')
- input++;
- else {
- strcpy(buf, Prefix);
- strcat(buf, input);
- input = buf;
- }
-
- if (root == NULL) {
- fprintf(stderr, "Mib not initialized. Exiting.\n");
- exit(1);
- }
- if ((*out_len =
- parse_subtree(root, input, output, out_len)) == 0)
- return (0);
- *out_len += output - op;
-
- return (1);
-}
-
-#ifdef notdef
-int
-read_objid(input, output, out_len)
- char *input;
- oid *output;
- int *out_len; /* number of subid's in "output" */
+static int
+lc_cmp(s1, s2)
+ char *s1, *s2;
{
- struct tree *root = Mib;
- oid *op = output;
- int i;
-
- if (*input == '.')
- input++;
- else {
- root = find_rfc1213_mib(root);
- for (i = 0; i < sizeof(RFC1213_MIB) / sizeof(oid); i++) {
- if ((*out_len)-- > 0)
- *output++ = RFC1213_MIB[i];
- else {
- fprintf(stderr, "object identifier too long\n");
- return (0);
- }
- }
- }
+ char c1, c2;
- if (root == NULL) {
- fprintf(stderr, "Mib not initialized. Exiting.\n");
- exit(1);
+ while(*s1 && *s2){
+ if (isupper(*s1))
+ c1 = tolower(*s1);
+ else
+ c1 = *s1;
+ if (isupper(*s2))
+ c2 = tolower(*s2);
+ else
+ c2 = *s2;
+ if (c1 != c2)
+ return ((c1 - c2) > 0 ? 1 : -1);
+ s1++;
+ s2++;
}
- if ((*out_len =
- parse_subtree(root, input, output, out_len)) == 0)
- return (0);
- *out_len += output - op;
- return (1);
+ if (*s1)
+ return -1;
+ if (*s2)
+ return 1;
+ return 0;
}
-#endif
static int
parse_subtree(subtree, input, output, out_len)
- struct tree *subtree;
- char *input;
- oid *output;
- int *out_len; /* number of subid's */
+ struct snmp_mib_tree *subtree;
+ char *input;
+ oid *output;
+ int *out_len; /* number of subid's */
{
char buf[128], *to = buf;
- u_long subid = 0;
- struct tree *tp;
+ u_int subid = 0;
+ struct snmp_mib_tree *tp;
/*
* No empty strings. Can happen if there is a trailing '.' or two '.'s
goto found;
}
tp = NULL;
- } else {
+ }
+ else {
/*
* Read the name into a buffer.
*/
while ((*input != '\0') &&
- (*input != '.')) {
+ (*input != '.')) {
*to++ = *input++;
}
*to = '\0';
* If we didn't find the entry, punt...
*/
if (tp == NULL) {
- fprintf(stderr, "sub-identifier not found: %s\n", buf);
+ snmplib_debug(0, "sub-identifier not found: %s\n", buf);
return (0);
}
}
- found:
- if (subid > (u_long) MAX_SUBID) {
- fprintf(stderr, "sub-identifier too large: %s\n", buf);
+found:
+ if(subid > (u_int)MAX_SUBID){
+ snmplib_debug(0, "sub-identifier too large: %s\n", buf);
return (0);
}
- if ((*out_len)-- <= 0) {
- fprintf(stderr, "object identifier too long\n");
+
+ if ((*out_len)-- <= 0){
+ snmplib_debug(0, "object identifier too long\n");
return (0);
}
*output++ = subid;
if (*input != '.')
return (1);
if ((*out_len =
- parse_subtree(tp ? tp->child_list : NULL, ++input, output, out_len)) == 0)
+ parse_subtree(tp ? tp->child_list : NULL, ++input, output, out_len)) == 0)
return (0);
return (++*out_len);
}
-void
-sprint_objid(char *buf, oid * objid, int objidlen)
+int read_objid(input, output, out_len)
+ char *input;
+ oid *output;
+ int *out_len; /* number of subid's in "output" */
{
- char tempbuf[2048], *cp;
- struct tree *subtree = Mib;
- *tempbuf = '.'; /* this is a fully qualified name */
- get_symbol(objid, objidlen, subtree, tempbuf + 1);
- if (Suffix) {
- for (cp = tempbuf; *cp; cp++);
- while (cp >= tempbuf) {
- if (isalpha(*cp))
- break;
- cp--;
- }
- while (cp >= tempbuf) {
- if (*cp == '.')
- break;
- cp--;
- }
- cp++;
- if (cp < tempbuf)
- cp = tempbuf;
- } else {
- cp = tempbuf;
- if ((strlen(tempbuf) > strlen((char *) RFC1213_MIB_text))
- && !bcmp(tempbuf, (char *) RFC1213_MIB_text,
- strlen((char *) RFC1213_MIB_text))) {
- cp += sizeof(RFC1213_MIB_text);
- }
- if ((strlen(tempbuf) > strlen((char *) EXPERIMENTAL_MIB_text))
- && !bcmp(tempbuf, (char *) EXPERIMENTAL_MIB_text,
- strlen((char *) EXPERIMENTAL_MIB_text))) {
- cp += sizeof(EXPERIMENTAL_MIB_text);
- }
- if ((strlen(tempbuf) > strlen((char *) PRIVATE_MIB_text))
- && !bcmp(tempbuf, (char *) PRIVATE_MIB_text,
- strlen((char *) PRIVATE_MIB_text))) {
- cp += sizeof(PRIVATE_MIB_text);
- }
- if ((strlen(tempbuf) > strlen((char *) PARTY_MIB_text))
- && !bcmp(tempbuf, (char *) PARTY_MIB_text,
- strlen((char *) PARTY_MIB_text))) {
- cp += sizeof(PARTY_MIB_text);
- }
- if ((strlen(tempbuf) > strlen((char *) SECRETS_MIB_text))
- && !bcmp(tempbuf, (char *) SECRETS_MIB_text,
- strlen((char *) SECRETS_MIB_text))) {
- cp += sizeof(SECRETS_MIB_text);
+ struct snmp_mib_tree *root = Mib;
+ oid *op = output;
+ int i;
+
+ if (*input == '.')
+ input++;
+ else {
+ root = find_rfc1066_mib(root);
+ for (i = 0; i < sizeof (RFC1066_MIB)/sizeof(oid); i++) {
+ if ((*out_len)-- > 0)
+ *output++ = RFC1066_MIB[i];
+ else {
+ snmplib_debug(0, "object identifier too long\n");
+ return (0);
+ }
}
}
- strcpy(buf, cp);
+
+ if (root == NULL){
+ snmplib_debug(0, "Mib not initialized. Exiting.\n");
+ exit(1);
+ }
+ if ((*out_len =
+ parse_subtree(root, input, output, out_len)) == 0)
+ return (0);
+ *out_len += output - op;
+
+ return (1);
}
-void
-print_objid(oid * objid, int objidlen)
+void print_objid(objid, objidlen)
+ oid *objid;
+ int objidlen; /* number of subidentifiers */
{
- char buf[256];
+ char buf[256];
+ struct snmp_mib_tree *subtree = Mib;
- sprint_objid(buf, objid, objidlen);
- printf("%s\n", buf);
+ *buf = '.'; /* this is a fully qualified name */
+ get_symbol(objid, objidlen, subtree, buf + 1);
+ snmplib_debug(7, "%s\n", buf);
+
}
+void sprint_objid(buf, objid, objidlen)
+ char *buf;
+ oid *objid;
+ int objidlen; /* number of subidentifiers */
+{
+ struct snmp_mib_tree *subtree = Mib;
+
+ *buf = '.'; /* this is a fully qualified name */
+ get_symbol(objid, objidlen, subtree, buf + 1);
+}
-void
-print_variable(oid * objid, int objidlen, struct variable_list *variable)
+
+void print_variable(objid, objidlen, pvariable)
+ oid *objid;
+ int objidlen;
+ struct variable_list *pvariable;
{
- char buf[2048];
+ char buf[1024], *cp;
+ struct snmp_mib_tree *subtree = Mib;
- sprint_variable(buf, objid, objidlen, variable);
- printf("%s", buf);
+ *buf = '.'; /* this is a fully qualified name */
+ subtree = get_symbol(objid, objidlen, subtree, buf + 1);
+ cp = buf;
+ if ((strlen(buf) >= strlen((char *)RFC1066_MIB_text)) && !memcmp(buf, (char *)RFC1066_MIB_text,
+ strlen((char *)RFC1066_MIB_text))){
+ cp += sizeof(RFC1066_MIB_text);
+ }
+ printf("Name: %s -> ", cp);
+ *buf = '\0';
+ if (subtree->printer)
+ (*subtree->printer)(buf, pvariable, subtree->enums, 0);
+ else {
+ sprint_by_type(buf, pvariable, subtree->enums, 0);
+ }
+ printf("%s\n", buf);
}
-static void
-sprint_variable(char *buf, oid * objid, int objidlen, struct variable_list *variable)
+
+void sprint_variable(buf, objid, objidlen, pvariable)
+ char *buf;
+ oid *objid;
+ int objidlen;
+ struct variable_list *pvariable;
{
- char tempbuf[2048];
- struct tree *subtree = Mib;
+ char tempbuf[512], *cp;
+ struct snmp_mib_tree *subtree = Mib;
- sprint_objid(buf, objid, objidlen);
- buf += strlen(buf);
- strcat(buf, " = ");
+ *tempbuf = '.'; /* this is a fully qualified name */
+ subtree = get_symbol(objid, objidlen, subtree, tempbuf + 1);
+ cp = tempbuf;
+ if ((strlen(buf) >= strlen((char *)RFC1066_MIB_text)) && !memcmp(buf, (char *)RFC1066_MIB_text,
+ strlen((char *)RFC1066_MIB_text))){
+ cp += sizeof(RFC1066_MIB_text);
+ }
+ sprintf(buf, "Name: %s -> ", cp);
buf += strlen(buf);
-
- if (variable->type == SNMP_NOSUCHOBJECT)
- sprintf(buf, "No Such Object available on this agent\n");
- else if (variable->type == SNMP_NOSUCHINSTANCE)
- sprintf(buf, "No Such Instance currently exists\n");
- else if (variable->type == SNMP_ENDOFMIBVIEW)
- sprintf(buf, "No more variables left in this MIB View\n");
+ if (subtree->printer)
+ (*subtree->printer)(buf, pvariable, subtree->enums, 0);
else {
- *tempbuf = '.'; /* this is a fully qualified name */
- subtree = get_symbol(objid, objidlen, subtree, tempbuf + 1);
- buf += strlen(buf);
- if (subtree->printer)
- (*subtree->printer) (buf, variable, subtree->enums);
- else {
- sprint_by_type(buf, variable, subtree->enums);
- }
- strcat(buf, "\n");
+ sprint_by_type(buf, pvariable, subtree->enums, 0);
}
+ strcat(buf, "\n");
}
-void
-sprint_value(char *buf, oid * objid, int objidlen, struct variable_list *variable)
+void sprint_value(buf, objid, objidlen, pvariable)
+ char *buf;
+ oid *objid;
+ int objidlen;
+ struct variable_list *pvariable;
{
- char tempbuf[2048];
- struct tree *subtree = Mib;
-
- if (variable->type == SNMP_NOSUCHOBJECT)
- sprintf(buf, "No Such Object available on this agent\n");
- else if (variable->type == SNMP_NOSUCHINSTANCE)
- sprintf(buf, "No Such Instance currently exists\n");
- else if (variable->type == SNMP_ENDOFMIBVIEW)
- sprintf(buf, "No more variables left in this MIB View\n");
+ char tempbuf[512];
+ struct snmp_mib_tree *subtree = Mib;
+
+ subtree = get_symbol(objid, objidlen, subtree, tempbuf);
+ if (subtree->printer)
+ (*subtree->printer)(buf, pvariable, subtree->enums, 0);
else {
- subtree = get_symbol(objid, objidlen, subtree, tempbuf);
- if (subtree->printer)
- (*subtree->printer) (buf, variable, subtree->enums);
- else {
- sprint_by_type(buf, variable, subtree->enums);
- }
+ sprint_by_type(buf, pvariable, subtree->enums, 0);
}
}
-void
-print_value(oid * objid, int objidlen, struct variable_list *variable)
+void print_value(objid, objidlen, pvariable)
+ oid *objid;
+ int objidlen;
+ struct variable_list *pvariable;
{
- char tempbuf[2048];
+ char tempbuf[512];
+ struct snmp_mib_tree *subtree = Mib;
- sprint_value(tempbuf, objid, objidlen, variable);
+ subtree = get_symbol(objid, objidlen, subtree, tempbuf);
+ if (subtree->printer)
+ (*subtree->printer)(tempbuf, pvariable, subtree->enums, 0);
+ else {
+ sprint_by_type(tempbuf, pvariable, subtree->enums, 0);
+ }
printf("%s\n", tempbuf);
}
-static struct tree *
-get_symbol(oid * objid, int objidlen, struct tree *subtree, char *buf)
+static struct snmp_mib_tree *
+get_symbol(objid, objidlen, subtree, buf)
+ oid *objid;
+ int objidlen;
+ struct snmp_mib_tree *subtree;
+ char *buf;
{
- struct tree *return_tree = NULL;
+ struct snmp_mib_tree *return_tree = NULL;
- for (; subtree; subtree = subtree->next_peer) {
- if (*objid == subtree->subid) {
+ for(; subtree; subtree = subtree->next_peer){
+ if (*objid == subtree->subid){
strcpy(buf, subtree->label);
goto found;
}
}
/* subtree not found */
- while (objidlen--) { /* output rest of name, uninterpreted */
- sprintf(buf, "%lu.", *objid++);
- while (*buf)
+ while(objidlen--){ /* output rest of name, uninterpreted */
+ sprintf(buf, "%u.", *objid++);
+ while(*buf)
buf++;
}
- *(buf - 1) = '\0'; /* remove trailing dot */
+ *(buf - 1) = '\0'; /* remove trailing dot */
return NULL;
- found:
- if (objidlen > 1) {
- while (*buf)
+found:
+ if (objidlen > 1){
+ while(*buf)
buf++;
*buf++ = '.';
*buf = '\0';
- return_tree = get_symbol(objid + 1, objidlen - 1, subtree->child_list,
- buf);
- }
+ return_tree = get_symbol(objid + 1, objidlen - 1, subtree->child_list, buf);
+ }
if (return_tree != NULL)
return return_tree;
else
}
-static int
-lc_cmp(char *s1, char *s2)
-{
- char c1, c2;
-
- while (*s1 && *s2) {
- if (isupper(*s1))
- c1 = tolower(*s1);
- else
- c1 = *s1;
- if (isupper(*s2))
- c2 = tolower(*s2);
- else
- c2 = *s2;
- if (c1 != c2)
- return ((c1 - c2) > 0 ? 1 : -1);
- s1++;
- s2++;
- }
-
- if (*s1)
- return -1;
- if (*s2)
- return 1;
- return 0;
-}
-
-/*
- * Clone of get_symbol that doesn't take a buffer argument
- */
-static struct tree *
-get_tree(oid * objid, int objidlen, struct tree *subtree)
-{
- struct tree *return_tree = NULL;
-
- for (; subtree; subtree = subtree->next_peer) {
- if (*objid == subtree->subid)
- goto found;
- }
- return NULL;
- found:
- if (objidlen > 1)
- return_tree = get_tree(objid + 1, objidlen - 1, subtree->child_list);
- if (return_tree != NULL)
- return return_tree;
- else
- return subtree;
-}
-#if 0
-static char *
-get_description(oid * objid, int objidlen)
+void print_variable_list(variable_list *V)
{
- struct tree *subtree = Mib;
-
- subtree = get_tree(objid, objidlen, subtree);
- if (subtree)
- return (subtree->description);
- else
- return NULL;
+ print_variable(V->name, V->name_length, V);
}
-#endif
-#if 0
-static void
-print_description(oid * objid, int objidlen)
+void print_variable_list_value(variable_list *pvariable)
{
- char *desc = get_description(objid, objidlen);
+ char buf[512];
+ struct snmp_mib_tree *subtree = Mib;
- if (desc && desc[0] != '\0')
- printf("Description: \"%s\"\n", desc);
- else
- printf("No description\n");
-}
-#endif
+ *buf = '.'; /* this is a fully qualified name */
+ subtree = get_symbol(pvariable->name, pvariable->name_length, subtree, buf + 1);
+ *buf = '\0';
+ if (subtree->printer)
+ (*subtree->printer)(buf, pvariable, subtree->enums, 1);
+ else {
+ sprint_by_type(buf, pvariable, subtree->enums, 1);
+ }
+ printf("%s", buf);
+}
-static struct tree *
-find_node(char *name, struct tree *subtree)
+void print_type(variable_list *var)
{
- struct tree *tp, *ret;
-
- for (tp = subtree; tp; tp = tp->next_peer) {
- if (!strcasecmp(name, tp->label))
- return tp;
- ret = find_node(name, tp->child_list);
- if (ret)
- return ret;
- }
- return 0;
+ switch (var->type){
+ case SMI_INTEGER:
+ printf("Integer");
+ break;
+ case SMI_STRING:
+ printf("Octet String");
+ break;
+ case SMI_OPAQUE:
+ printf("Opaque");
+ break;
+ case SMI_OBJID:
+ printf("Object Identifier");
+ break;
+ case SMI_TIMETICKS:
+ printf("Timeticks");
+ break;
+ case SMI_GAUGE32:
+ printf("Gauge");
+ break;
+ case SMI_COUNTER32:
+ printf("Counter");
+ break;
+ case SMI_IPADDRESS:
+ printf("IP Address");
+ break;
+ case SMI_NULLOBJ:
+ printf("NULL");
+ break;
+ default:
+ printf("Unknown type %d\n", var->type);
+ break;
+ }
}
-
-#if 0
-static int
-get_node(char *name, oid * objid, int *objidlen)
+void print_oid_nums(oid *O, int len)
{
- struct tree *tp;
- oid newname[64], *op;
-
- tp = find_node(name, Mib);
- if (tp) {
- for (op = newname + 63; op >= newname; op--) {
- *op = tp->subid;
- tp = tp->parent;
- if (tp == NULL)
- break;
- }
- if (newname + 64 - op > *objidlen)
- return 0;
- *objidlen = newname + 64 - op;
- xmemcpy(objid, op, (newname + 64 - op) * sizeof(oid));
- return 1;
- } else {
- return 0;
- }
-
+ int x;
+ for (x=0;x<len;x++)
+ printf(".%u", O[x]);
}
-#endif
-/******************************************************************
- Copyright 1989, 1991, 1992 by Carnegie Mellon University
+/***********************************************************
+ Copyright 1989 by Carnegie Mellon University
All Rights Reserved
SOFTWARE.
******************************************************************/
+/*
+ * parse.c
+ */
#include "config.h"
-#if HAVE_STDIO_H
#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
+#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 "asn1.h"
+#include "snmp_vars.h"
#include "parse.h"
#include "util.h"
-#define free +
-
-/* A quoted string value-- too long for a general "token" */
-char *quoted_string_buffer;
-
/*
- * This is one element of an object identifier with either an integer
- * subidentifier, or a textual string label, or both.
+ * This is one element of an object identifier with either an integer subidentifier,
+ * or a textual string label, or both.
* The subid is -1 if not present, and label is NULL if not present.
*/
struct subid {
char *label;
};
-/* use large token buffer in case of very long tokens: */
-#define MAXTC 1024
-struct tc { /* textual conventions */
- int type;
- char descriptor[MAXTOKEN];
- struct enum_list *enums;
-} tclist[MAXTC];
-
-
+/*
+ * A linked list of nodes.
+ */
+struct node {
+ struct node *next;
+ char label[64]; /* This node's (unique) textual name */
+ u_int subid; /* This node's integer subidentifier */
+ char parent[64];/* The parent's textual name */
+ int type; /* The type of object this represents */
+ struct enum_list *enums; /* (optional) list of enumerated integers (otherwise NULL) */
+};
int Line = 1;
-#define SYNTAX_MASK 0x80
-/* types of tokens
- * Tokens wiht the SYNTAX_MASK bit set are syntax tokens */
+/* types of tokens */
#define CONTINUE -1
#define ENDOFFILE 0
#define LABEL 1
#define SUBTREE 2
#define SYNTAX 3
-#define OBJID (4 | SYNTAX_MASK)
-#define OCTETSTR (5 | SYNTAX_MASK)
-#define INTEGER (6 | SYNTAX_MASK)
-#define NETADDR (7 | SYNTAX_MASK)
-#define IPADDR (8 | SYNTAX_MASK)
-#define COUNTER (9 | SYNTAX_MASK)
-#define GAUGE (10 | SYNTAX_MASK)
-#define TIMETICKS (11 | SYNTAX_MASK)
-#define OPAQUE (12 | SYNTAX_MASK)
-#define NUL (13 | SYNTAX_MASK)
+#define OBJID 4
+#define OCTETSTR 5
+#define INTEGER 6
+#define NETADDR 7
+#define IPADDR 8
+#define COUNTER 9
+#define GAUGE 10
+#define TIMETICKS 11
+#define OPAQUE 12
+#define NUL 13
#define SEQUENCE 14
-#define OF 15 /* SEQUENCE OF */
+#define OF 15 /* SEQUENCE OF */
#define OBJTYPE 16
#define ACCESS 17
#define READONLY 18
#define MANDATORY 23
#define OPTIONAL 24
#define OBSOLETE 25
-/* #define RECOMMENDED 26 */
+#define RECOMMENDED 26
#define PUNCT 27
#define EQUALS 28
#define NUMBER 29
#define LEFTPAREN 32
#define RIGHTPAREN 33
#define COMMA 34
+/* For SNMPv2 SMI pseudo-compliance */
#define DESCRIPTION 35
-#define QUOTESTRING 36
-#define INDEX 37
-#define DEFVAL 38
-#define DEPRECATED 39
-#define SIZE 40
-#define BITSTRING (41 | SYNTAX_MASK)
-#define NSAPADDRESS (42 | SYNTAX_MASK)
-#define COUNTER64 (43 | SYNTAX_MASK)
-#define OBJGROUP 44
-#define NOTIFTYPE 45
-#define AUGMENTS 46
-#define COMPLIANCE 47
-#define READCREATE 48
-#define UNITS 49
-#define REFERENCE 50
-#define NUM_ENTRIES 51
-#define MODULEIDENTITY 52
-#define LASTUPDATED 53
-#define ORGANIZATION 54
-#define CONTACTINFO 55
-#define UINTEGER32 (56 | SYNTAX_MASK)
-#define CURRENT 57
-#define DEFINITIONS 58
-#define END 59
-#define SEMI 60
+#define INDEX 36
+#define QUOTE 37
struct tok {
- char *name; /* token name */
- int len; /* length not counting nul */
- int token; /* value */
- int hash; /* hash of name */
- struct tok *next; /* pointer to next in hash table */
+ char *name; /* token name */
+ int len; /* length not counting nul */
+ int token; /* value */
+ int hash; /* hash of name */
+ struct tok *next; /* pointer to next in hash table */
};
-struct tok tokens[] =
-{
- {"obsolete", sizeof("obsolete") - 1, OBSOLETE},
- {"Opaque", sizeof("Opaque") - 1, OPAQUE},
-/* { "recommended", sizeof("recommended")-1, RECOMMENDED }, */
- {"optional", sizeof("optional") - 1, OPTIONAL},
- {"LAST-UPDATED", sizeof("LAST-UPDATED") - 1, LASTUPDATED},
- {"ORGANIZATION", sizeof("ORGANIZATION") - 1, ORGANIZATION},
- {"CONTACT-INFO", sizeof("CONTACT-INFO") - 1, CONTACTINFO},
- {"MODULE-IDENTITY", sizeof("MODULE-IDENTITY") - 1, MODULEIDENTITY},
- {"MODULE-COMPLIANCE", sizeof("MODULE-COMPLIANCE") - 1, COMPLIANCE},
- {"DEFINITIONS", sizeof("DEFINITIONS") - 1, DEFINITIONS},
- {"END", sizeof("END") - 1, END},
- {";", sizeof(";") - 1, SEMI},
- {"AUGMENTS", sizeof("AUGMENTS") - 1, AUGMENTS},
- {"not-accessible", sizeof("not-accessible") - 1, NOACCESS},
- {"write-only", sizeof("write-only") - 1, WRITEONLY},
- {"NsapAddress", sizeof("NsapAddress") - 1, NSAPADDRESS},
- {"UNITS", sizeof("Units") - 1, UNITS},
- {"REFERENCE", sizeof("REFERENCE") - 1, REFERENCE},
- {"NUM-ENTRIES", sizeof("NUM-ENTRIES") - 1, NUM_ENTRIES},
- {"BITSTRING", sizeof("BitString") - 1, BITSTRING},
- {"BIT", sizeof("BIT") - 1, CONTINUE},
- {"Counter64", sizeof("Counter64") - 1, COUNTER64},
- {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS},
- {"NOTIFICATION-TYPE", sizeof("NOTIFICATION-TYPE") - 1, NOTIFTYPE},
- {"OBJECT-GROUP", sizeof("OBJECT-GROUP") - 1, OBJGROUP},
- {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID},
+struct tok tokens[] = {
+ { "obsolete", sizeof ("obsolete")-1, OBSOLETE },
+ { "Opaque", sizeof ("Opaque")-1, OPAQUE },
+ { "recommended", sizeof("recommended")-1, RECOMMENDED },
+ { "optional", sizeof ("optional")-1, OPTIONAL },
+ { "mandatory", sizeof ("mandatory")-1, MANDATORY },
+ { "current", sizeof ("current")-1, MANDATORY },
+ { "not-accessible", sizeof ("not-accessible")-1, NOACCESS },
+ { "write-only", sizeof ("write-only")-1, WRITEONLY },
+ { "read-write", sizeof ("read-write")-1, READWRITE },
+ { "TimeTicks", sizeof ("TimeTicks")-1, TIMETICKS },
+ { "OBJECTIDENTIFIER", sizeof ("OBJECTIDENTIFIER")-1, OBJID },
/*
* This CONTINUE appends the next word onto OBJECT,
* hopefully matching OBJECTIDENTIFIER above.
*/
- {"OBJECT", sizeof("OBJECT") - 1, CONTINUE},
- {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR},
- {"Gauge", sizeof("Gauge") - 1, GAUGE},
- {"read-write", sizeof("read-write") - 1, READWRITE},
- {"read-create", sizeof("read-create") - 1, READCREATE},
- {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR},
- {"OCTET", sizeof("OCTET") - 1, -1},
- {"OF", sizeof("OF") - 1, OF},
- {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE},
- {"NULL", sizeof("NULL") - 1, NUL},
- {"IpAddress", sizeof("IpAddress") - 1, IPADDR},
- {"UInteger32", sizeof("UInteger32") - 1, UINTEGER32},
- {"INTEGER", sizeof("INTEGER") - 1, INTEGER},
- {"Counter", sizeof("Counter") - 1, COUNTER},
- {"read-only", sizeof("read-only") - 1, READONLY},
- {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION},
- {"INDEX", sizeof("INDEX") - 1, INDEX},
- {"DEFVAL", sizeof("DEFVAL") - 1, DEFVAL},
- {"deprecated", sizeof("deprecated") - 1, DEPRECATED},
- {"SIZE", sizeof("SIZE") - 1, SIZE},
- {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS},
- {"ACCESS", sizeof("ACCESS") - 1, ACCESS},
- {"mandatory", sizeof("mandatory") - 1, MANDATORY},
- {"current", sizeof("current") - 1, CURRENT},
- {"STATUS", sizeof("STATUS") - 1, STATUS},
- {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX},
- {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE},
- {"{", sizeof("{") - 1, LEFTBRACKET},
- {"}", sizeof("}") - 1, RIGHTBRACKET},
- {"::=", sizeof("::=") - 1, EQUALS},
- {"(", sizeof("(") - 1, LEFTPAREN},
- {")", sizeof(")") - 1, RIGHTPAREN},
- {",", sizeof(",") - 1, COMMA},
- {NULL}
+ { "OBJECT", sizeof ("OBJECT")-1, CONTINUE },
+ { "NetworkAddress", sizeof ("NetworkAddress")-1, NETADDR },
+ { "Gauge", sizeof ("Gauge")-1, GAUGE },
+ { "OCTETSTRING", sizeof ("OCTETSTRING")-1, OCTETSTR },
+ { "OCTET", sizeof ("OCTET")-1, -1 },
+ { "OF", sizeof ("OF")-1, OF },
+ { "SEQUENCE", sizeof ("SEQUENCE")-1, SEQUENCE },
+ { "NULL", sizeof ("NULL")-1, NUL },
+ { "IpAddress", sizeof ("IpAddress")-1, IPADDR },
+ { "INTEGER", sizeof ("INTEGER")-1, INTEGER },
+ { "Counter", sizeof ("Counter")-1, COUNTER },
+ { "read-only", sizeof ("read-only")-1, READONLY },
+ { "ACCESS", sizeof ("ACCESS")-1, ACCESS },
+ { "MAX-ACCESS", sizeof ("MAX-ACCESS")-1, ACCESS },
+ { "STATUS", sizeof ("STATUS")-1, STATUS },
+ { "SYNTAX", sizeof ("SYNTAX")-1, SYNTAX },
+ { "OBJECT-TYPE", sizeof ("OBJECT-TYPE")-1, OBJTYPE },
+ { "{", sizeof ("{")-1, LEFTBRACKET },
+ { "}", sizeof ("}")-1, RIGHTBRACKET },
+ { "::=", sizeof ("::=")-1, EQUALS },
+ { "(", sizeof ("(")-1, LEFTPAREN },
+ { ")", sizeof (")")-1, RIGHTPAREN },
+ { ",", sizeof (",")-1, COMMA },
+ { "DESCRIPTION", sizeof ("DESCRIPTION")-1, DESCRIPTION },
+ { "INDEX", sizeof ("INDEX")-1, INDEX },
+ { "\"", sizeof ("\"")-1, QUOTE },
+/* Hacks for easier MIBFILE coercing */
+ { "read-create", sizeof ("read-create")-1, READWRITE },
+ { NULL }
};
#define HASHSIZE 32
#define BUCKET(x) (x & 0x01F)
-struct tok *buckets[HASHSIZE];
-
-static void do_subtree();
-static int get_token();
-static int parseQuoteString();
-static int tossObjectIdentifier();
+static struct tok *buckets[HASHSIZE];
static void
-hash_init(void)
+hash_init()
{
- struct tok *tp;
- char *cp;
- int h;
- int b;
-
- memset(buckets, '\0', sizeof(buckets));
- for (tp = tokens; tp->name; tp++) {
- for (h = 0, cp = tp->name; *cp; cp++)
- h += *cp;
- tp->hash = h;
- b = BUCKET(h);
- if (buckets[b])
- tp->next = buckets[b]; /* BUG ??? */
- buckets[b] = tp;
- }
+ register struct tok *tp;
+ register char *cp;
+ register int h;
+ register int b;
+
+ memset((char *)buckets, '\0', sizeof(buckets));
+ for (tp = tokens; tp->name; tp++) {
+ for (h = 0, cp = tp->name; *cp; cp++)
+ h += *cp;
+ tp->hash = h;
+ b = BUCKET(h);
+ if (buckets[b])
+ tp->next = buckets[b]; /* BUG ??? */
+ buckets[b] = tp;
+ }
}
#define NHASHSIZE 128
#define NBUCKET(x) (x & 0x7F)
struct node *nbuckets[NHASHSIZE];
-void
-init_node_hash(struct node *nodes)
+static void init_node_hash(nodes)
+ struct node *nodes;
{
- struct node *np, *nextp;
- char *cp;
- int hash;
-
- memset(nbuckets, '\0', sizeof(nbuckets));
- for (np = nodes; np;) {
- nextp = np->next;
- hash = 0;
- for (cp = np->parent; *cp; cp++)
- hash += *cp;
- np->next = nbuckets[NBUCKET(hash)];
- nbuckets[NBUCKET(hash)] = np;
- np = nextp;
- }
+ register struct node *np, *nextp;
+ register char *cp;
+ register int hash;
+
+ memset((char *)nbuckets, '\0', sizeof(nbuckets));
+ for(np = nodes; np;){
+ nextp = np->next;
+ hash = 0;
+ for(cp = np->parent; *cp; cp++)
+ hash += *cp;
+ np->next = nbuckets[NBUCKET(hash)];
+ nbuckets[NBUCKET(hash)] = np;
+ np = nextp;
+ }
}
-static char *
-Malloc(unsigned int num)
-{
- /* this is to fix (what seems to be) a problem with the IBM RT C
- * library malloc */
- if (num < 16)
- num = 16;
- return xcalloc(1, num);
-}
static void
-print_error(char *string, char *token, int type)
+print_error(string, token, type)
+ char *string;
+ char *token;
+ int type;
{
if (type == ENDOFFILE)
- fprintf(stderr, "%s(EOF): On or around line %d\n", string, Line);
+ snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line);
else if (token)
- fprintf(stderr, "%s(%s): On or around line %d\n", string, token, Line);
+ snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line);
else
- fprintf(stderr, "%s: On or around line %d\n", string, Line);
+ snmplib_debug(0, "%s: On or around line %d\n", string, Line);
}
#ifdef TEST
-print_subtree(struct tree *tree, int count)
+print_subtree(tree, count)
+ struct snmp_mib_tree *tree;
+ int count;
{
- struct tree *tp;
+ struct snmp_mib_tree *tp;
int i;
- for (i = 0; i < count; i++)
+ for(i = 0; i < count; i++)
printf(" ");
printf("Children of %s:\n", tree->label);
count++;
- for (tp = tree->child_list; tp; tp = tp->next_peer) {
- for (i = 0; i < count; i++)
+ for(tp = tree->child_list; tp; tp = tp->next_peer){
+ for(i = 0; i < count; i++)
printf(" ");
printf("%s\n", tp->label);
}
- for (tp = tree->child_list; tp; tp = tp->next_peer) {
+ for(tp = tree->child_list; tp; tp = tp->next_peer){
print_subtree(tp, count);
}
}
#endif /* TEST */
-int translation_table[256];
+int translation_table[40];
-void
-build_translation_table(void)
-{
+static void build_translation_table(){
int count;
- for (count = 0; count < 256; count++) {
- switch (count) {
- case OBJID:
- translation_table[count] = TYPE_OBJID;
- break;
- case OCTETSTR:
- translation_table[count] = TYPE_OCTETSTR;
- break;
- case INTEGER:
- translation_table[count] = TYPE_INTEGER;
- break;
- case NETADDR:
- translation_table[count] = TYPE_IPADDR;
- break;
- case IPADDR:
- translation_table[count] = TYPE_IPADDR;
- break;
- case COUNTER:
- translation_table[count] = TYPE_COUNTER;
- break;
- case GAUGE:
- translation_table[count] = TYPE_GAUGE;
- break;
- case TIMETICKS:
- translation_table[count] = TYPE_TIMETICKS;
- break;
- case OPAQUE:
- translation_table[count] = TYPE_OPAQUE;
- break;
- case NUL:
- translation_table[count] = TYPE_NULL;
- break;
- case COUNTER64:
- translation_table[count] = TYPE_COUNTER64;
- break;
- case BITSTRING:
- translation_table[count] = TYPE_BITSTRING;
- break;
- case NSAPADDRESS:
- translation_table[count] = TYPE_NSAPADDRESS;
- break;
- case UINTEGER32:
- translation_table[count] = TYPE_UINTEGER;
- break;
- default:
- translation_table[count] = TYPE_OTHER;
- break;
- }
- }
-}
-
-static struct tree *
-build_tree(struct node *nodes)
-{
- struct node *np;
- struct tree *tp, *lasttp;
- int bucket, nodes_left = 0;
-
- build_translation_table();
- /* grow tree from this root node */
- init_node_hash(nodes);
-
- /* build root node */
- tp = (struct tree *) Malloc(sizeof(struct tree));
- tp->parent = NULL;
- tp->next_peer = NULL;
- tp->child_list = NULL;
- tp->enums = NULL;
- strcpy(tp->label, "joint-iso-ccitt");
- tp->subid = 2;
- tp->type = 0;
- tp->description = 0;
- /* XXX nodes isn't needed in do_subtree() ??? */
- do_subtree(tp, &nodes);
- lasttp = tp;
-
- /* build root node */
- tp = (struct tree *) Malloc(sizeof(struct tree));
- tp->parent = NULL;
- tp->next_peer = lasttp;
- tp->child_list = NULL;
- tp->enums = NULL;
- strcpy(tp->label, "ccitt");
- tp->subid = 0;
- tp->type = 0;
- tp->description = 0;
- /* XXX nodes isn't needed in do_subtree() ??? */
- do_subtree(tp, &nodes);
- lasttp = tp;
-
- /* build root node */
- tp = (struct tree *) Malloc(sizeof(struct tree));
- tp->parent = NULL;
- tp->next_peer = lasttp;
- tp->child_list = NULL;
- tp->enums = NULL;
- strcpy(tp->label, "iso");
- tp->subid = 1;
- tp->type = 0;
- tp->description = 0;
- /* XXX nodes isn't needed in do_subtree() ??? */
- do_subtree(tp, &nodes);
-
-
-#ifdef TEST
- print_subtree(tp, 0);
-#endif /* TEST */
- /* If any nodes are left, the tree is probably inconsistent */
- for (bucket = 0; bucket < NHASHSIZE; bucket++) {
- if (nbuckets[bucket]) {
- nodes_left = 1;
- break;
- }
- }
- if (nodes_left) {
- fprintf(stderr, "The mib description doesn't seem to be consistent.\n");
- fprintf(stderr, "Some nodes couldn't be linked under the \"iso\" tree.\n");
- fprintf(stderr, "these nodes are left:\n");
- for (bucket = 0; bucket < NHASHSIZE; bucket++) {
- for (np = nbuckets[bucket]; np; np = np->next)
- fprintf(stderr, "%s ::= { %s %ld } (%d)\n", np->label,
- np->parent, np->subid, np->type);
+ for(count = 0; count < 40; count++){
+ switch(count){
+ case OBJID:
+ translation_table[count] = TYPE_OBJID;
+ break;
+ case OCTETSTR:
+ translation_table[count] = TYPE_OCTETSTR;
+ break;
+ case INTEGER:
+ translation_table[count] = TYPE_INTEGER;
+ break;
+ case NETADDR:
+ translation_table[count] = TYPE_IPADDR;
+ break;
+ case IPADDR:
+ translation_table[count] = TYPE_IPADDR;
+ break;
+ case COUNTER:
+ translation_table[count] = TYPE_COUNTER;
+ break;
+ case GAUGE:
+ translation_table[count] = TYPE_GAUGE;
+ break;
+ case TIMETICKS:
+ translation_table[count] = TYPE_TIMETICKS;
+ break;
+ case OPAQUE:
+ translation_table[count] = TYPE_OPAQUE;
+ break;
+ case NUL:
+ translation_table[count] = TYPE_NULL;
+ break;
+ default:
+ translation_table[count] = TYPE_OTHER;
+ break;
}
}
- return tp;
}
/*
* tree and out of the nodes list.
*/
static void
-do_subtree(struct tree *root, struct node **nodes)
+do_subtree(root, nodes)
+ struct snmp_mib_tree *root;
+ struct node **nodes;
{
- struct tree *tp;
- struct tree *peer = NULL;
- struct node *np, **headp;
+ register struct snmp_mib_tree *tp;
+ struct snmp_mib_tree *peer = NULL;
+ register struct node *np=NULL , **headp=NULL;
struct node *oldnp = NULL, *child_list = NULL, *childp = NULL;
char *cp;
int hash;
-
+
tp = root;
hash = 0;
- for (cp = tp->label; *cp; cp++)
- hash += *cp;
+ for(cp = tp->label; *cp; cp++)
+ hash += *cp;
headp = &nbuckets[NBUCKET(hash)];
/*
* Search each of the nodes for one whose parent is root, and
* move each into a separate list.
*/
- for (np = *headp; np; np = np->next) {
- if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)) {
- if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)) {
+ for(np = *headp; np; np = np->next){
+ if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)){
+ if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)){
/* if there is another node with the same label, assume that
* any children after this point in the list belong to the other node.
* This adds some scoping to the table and allows vendors to
}
oldnp = np;
} else {
- if (child_list == NULL) {
- child_list = childp = np; /* first entry in child list */
+ if (child_list == NULL){
+ child_list = childp = np; /* first entry in child list */
} else {
childp->next = np;
childp = np;
}
/* take this node out of the node list */
- if (oldnp == NULL) {
- *headp = np->next; /* fix root of node list */
+ if (oldnp == NULL){
+ *headp = np->next; /* fix root of node list */
} else {
- oldnp->next = np->next; /* link around this node */
+ oldnp->next = np->next; /* link around this node */
}
}
}
/*
* Take each element in the child list and place it into the tree.
*/
- for (np = child_list; np; np = np->next) {
- tp = (struct tree *) Malloc(sizeof(struct tree));
+ for(np = child_list; np; np = np->next){
+ tp = (struct snmp_mib_tree *)xmalloc(sizeof(struct snmp_mib_tree));
tp->parent = root;
tp->next_peer = NULL;
tp->child_list = NULL;
tp->type = translation_table[np->type];
tp->enums = np->enums;
np->enums = NULL; /* so we don't free them later */
- tp->description = np->description; /* steals memory from np */
- np->description = NULL; /* so we don't free it later */
- if (root->child_list == NULL) {
+ if (root->child_list == NULL){
root->child_list = tp;
} else {
peer->next_peer = tp;
}
peer = tp;
-/* if (tp->type == TYPE_OTHER) */
- do_subtree(tp, nodes); /* recurse on this child if it isn't
- * an end node */
+/* if (tp->type == TYPE_OTHER) */
+ do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */
}
/* free all nodes that were copied into tree */
oldnp = NULL;
- for (np = child_list; np; np = np->next) {
+ for(np = child_list; np; np = np->next){
if (oldnp)
xfree(oldnp);
oldnp = np;
xfree(oldnp);
}
+#ifndef TEST
+static
+#endif
+struct snmp_mib_tree *
+build_tree(nodes)
+ struct node *nodes;
+{
+ struct node *np;
+ struct snmp_mib_tree *tp;
+ int bucket, nodes_left = 0;
+
+ /* build root node */
+ tp = (struct snmp_mib_tree *)xmalloc(sizeof(struct snmp_mib_tree));
+ tp->parent = NULL;
+ tp->next_peer = NULL;
+ tp->child_list = NULL;
+ tp->enums = NULL;
+ strcpy(tp->label, "iso");
+ tp->subid = 1;
+ tp->type = 0;
+ build_translation_table();
+ /* grow tree from this root node */
+ init_node_hash(nodes);
+ /* XXX nodes isn't needed in do_subtree() ??? */
+ do_subtree(tp, &nodes);
+#ifdef TEST
+ print_subtree(tp, 0);
+#endif /* TEST */
+ /* If any nodes are left, the tree is probably inconsistent */
+ for(bucket = 0; bucket < NHASHSIZE; bucket++){
+ if (nbuckets[bucket]){
+ nodes_left = 1;
+ break;
+ }
+ }
+ if (nodes_left){
+ snmplib_debug(0, "The mib description doesn't seem to be consistent.\n");
+ snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n");
+ snmplib_debug(0, "these nodes are left:\n");
+ for(bucket = 0; bucket < NHASHSIZE; bucket++){
+ for(np = nbuckets[bucket]; np; np = np->next)
+ snmplib_debug(0, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
+ np->type);
+ }
+ }
+ return tp;
+}
+
+
+/*
+ * Parses a token from the file. The type of the token parsed is returned,
+ * and the text is placed in the string pointed to by token.
+ */
+static char last = ' ';
+
+static int
+get_token(fp, token)
+ register FILE *fp;
+ register char *token;
+{
+ register int ch;
+ register char *cp = token;
+ register int hash = 0;
+ register struct tok *tp;
+
+ *cp = 0;
+ ch = last;
+ /* skip all white space */
+ while(isspace(ch) && ch != -1){
+ ch = getc(fp);
+ if (ch == '\n')
+ Line++;
+ }
+ if (ch == -1)
+ return ENDOFFILE;
+
+ /*
+ * Accumulate characters until end of token is found. Then attempt to match this
+ * token as a reserved word. If a match is found, return the type. Else it is
+ * a label.
+ */
+ do {
+ if (ch == '\n')
+ Line++;
+ if (isspace(ch) || ch == '(' || ch == ')' ||
+ ch == '{' || ch == '}' || ch == ',' ||
+ ch == '"' ) {
+ if (!isspace(ch) && *token == 0){
+ hash += ch;
+ *cp++ = ch;
+ last = ' ';
+ } else {
+ last = ch;
+ }
+ *cp = '\0';
+
+ for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
+ if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
+ break;
+ }
+ if (tp){
+ if (tp->token == CONTINUE)
+ continue;
+ return (tp->token);
+ }
+
+ if (token[0] == '-' && token[1] == '-'){
+ /* strip comment */
+ while ((ch = getc(fp)) != -1)
+ if (ch == '\n'){
+ Line++;
+ break;
+ }
+ if (ch == -1)
+ return ENDOFFILE;
+ last = ch;
+ return get_token(fp, token);
+ }
+ for(cp = token; *cp; cp++)
+ if (!isdigit(*cp))
+ return LABEL;
+ return NUMBER;
+ } else {
+ hash += ch;
+ *cp++ = ch;
+ if (ch == '\n')
+ Line++;
+ }
+
+ } while ((ch = getc(fp)) != -1);
+ return ENDOFFILE;
+}
/*
* Takes a list of the form:
* Returns NULL on error.
*/
static int
-getoid(FILE * fp, struct subid *oid, int length)
+getoid(fp, SubOid, length)
+ register FILE *fp;
+ register struct subid *SubOid; /* an array of subids */
+ int length; /* the length of the array */
{
- int count;
+ register int count;
int type;
- char token[MAXTOKEN];
- char *cp;
+ char token[128];
+ register char *cp;
- if ((type = get_token(fp, token)) != LEFTBRACKET) {
+ if ((type = get_token(fp, token)) != LEFTBRACKET){
print_error("Expected \"{\"", token, type);
return 0;
}
type = get_token(fp, token);
- for (count = 0; count < length; count++, oid++) {
- oid->label = 0;
- oid->subid = -1;
- if (type == RIGHTBRACKET) {
+ for(count = 0; count < length; count++, SubOid++){
+ SubOid->label = 0;
+ SubOid->subid = -1;
+ if (type == RIGHTBRACKET){
return count;
- } else if (type != LABEL && type != NUMBER) {
+ } else if (type != LABEL && type != NUMBER){
print_error("Not valid for object identifier", token, type);
return 0;
}
- if (type == LABEL) {
+ if (type == LABEL){
/* this entry has a label */
- cp = (char *) Malloc((unsigned) strlen(token) + 1);
+ cp = (char *)xmalloc((unsigned)strlen(token) + 1);
strcpy(cp, token);
- oid->label = cp;
+ SubOid->label = cp;
type = get_token(fp, token);
- if (type == LEFTPAREN) {
+ if (type == LEFTPAREN){
type = get_token(fp, token);
- if (type == NUMBER) {
- oid->subid = atoi(token);
- if ((type = get_token(fp, token)) != RIGHTPAREN) {
+ if (type == NUMBER){
+ SubOid->subid = atoi(token);
+ if ((type = get_token(fp, token)) != RIGHTPAREN){
print_error("Unexpected a closing parenthesis", token, type);
return 0;
}
}
} else {
/* this entry has just an integer sub-identifier */
- oid->subid = atoi(token);
+ SubOid->subid = atoi(token);
}
type = get_token(fp, token);
}
}
static void
-free_node(struct node *np)
+free_node(np)
+ struct node *np;
{
struct enum_list *ep, *tep;
ep = np->enums;
- while (ep) {
+ while(ep){
tep = ep;
ep = ep->next;
- xfree((char *) tep);
+ xfree((char *)tep);
}
- xfree((char *) np);
+ xfree((char *)np);
}
/*
* Returns 0 on error.
*/
static struct node *
-parse_objectid(FILE * fp, char *name)
+parse_objectid(fp, name)
+ FILE *fp;
+ char *name;
{
int type;
- char token[MAXTOKEN];
- int count;
- struct subid *op, *nop;
+ char token[64];
+ register int count;
+ register struct subid *op, *nop;
int length;
- struct subid oid[32];
+ struct subid SubOid[32];
struct node *np, *root, *oldnp = NULL;
type = get_token(fp, token);
- if (type != EQUALS) {
+ if (type != EQUALS){
print_error("Bad format", token, type);
return 0;
}
- if ((length = getoid(fp, oid, 32)) != 0) {
- np = root = (struct node *) Malloc(sizeof(struct node));
- memset(np, '\0', sizeof(struct node));
+ if ((length = getoid(fp, SubOid, 32)) != 0){
+ np = root = (struct node *)xmalloc(sizeof(struct node));
+ memset((char *)np, '\0', sizeof(struct node));
/*
* For each parent-child subid pair in the subid array,
* create a node and link it into the node list.
*/
- for (count = 0, op = oid, nop = oid + 1; count < (length - 2); count++,
- op++, nop++) {
+ for(count = 0, op = SubOid, nop=SubOid+1; count < (length - 2); count++,
+ op++, nop++){
/* every node must have parent's name and child's name or number */
- if (op->label && (nop->label || (nop->subid != -1))) {
+ if (op->label && (nop->label || (nop->subid != -1))){
strcpy(np->parent, op->label);
if (nop->label)
strcpy(np->label, nop->label);
np->type = 0;
np->enums = 0;
/* set up next entry */
- np->next = (struct node *) Malloc(sizeof(*np->next));
- memset(np->next, '\0', sizeof(struct node));
+ np->next = (struct node *)xmalloc(sizeof(*np->next));
+ memset((char *)np->next, '\0', sizeof(struct node));
oldnp = np;
np = np->next;
}
}
- np->next = (struct node *) NULL;
+ np->next = (struct node *)NULL;
/*
* The above loop took care of all but the last pair. This pair is taken
* care of here. The name for this node is taken from the label for this
* entry.
* np still points to an unused entry.
*/
- if (count == (length - 2)) {
- if (op->label) {
+ if (count == (length - 2)){
+ if (op->label){
strcpy(np->parent, op->label);
strcpy(np->label, name);
if (nop->subid != -1)
np->subid = nop->subid;
else
- print_error("Warning: This entry is pretty silly",
- np->label, type);
+ print_error("Warning: This entry is pretty silly", np->label, type);
} else {
free_node(np);
if (oldnp)
return NULL;
}
} else {
- print_error("Missing end of oid", (char *) NULL, type);
- free_node(np); /* the last node allocated wasn't used */
+ print_error("Missing end of oid", (char *)NULL, type);
+ free_node(np); /* the last node allocated wasn't used */
if (oldnp)
oldnp->next = NULL;
return NULL;
}
/* free the oid array */
- for (count = 0, op = oid; count < length; count++, op++) {
+ for(count = 0, op = SubOid; count < length; count++, op++){
if (op->label)
xfree(op->label);
op->label = 0;
}
return root;
} else {
- print_error("Bad object identifier", (char *) NULL, type);
+ print_error("Bad object identifier", (char *)NULL, type);
return 0;
}
}
+/*
+ * Parses an asn type. This structure is ignored by this parser.
+ * Returns NULL on error.
+ */
static int
-get_tc(char *descriptor, struct enum_list **ep)
+parse_asntype(fp)
+ FILE *fp;
{
- int i;
+ int type;
+ char token[64];
- for (i = 0; i < MAXTC; i++) {
- if (tclist[i].type == 0)
- break;
- if (!strcmp(descriptor, tclist[i].descriptor)) {
- *ep = tclist[i].enums;
- return tclist[i].type;
- }
+ type = get_token(fp, token);
+ if (type != SEQUENCE){
+ print_error("Not a sequence", token, type); /* should we handle this */
+ return ENDOFFILE;
}
- return LABEL;
+ while((type = get_token(fp, token)) != ENDOFFILE){
+ if (type == RIGHTBRACKET)
+ return type;
+ }
+ print_error("Expected \"}\"", token, type);
+ return ENDOFFILE;
}
/*
- * Parses an asn type. Structures are ignored by this parser.
- * Returns NULL on error.
+ * Parses an OBJECT TYPE macro.
+ * Returns 0 on error.
*/
-static int
-parse_asntype(FILE * fp, char *name, int *ntype, char *ntoken)
+static struct node *
+parse_objecttype(fp, name)
+ register FILE *fp;
+ char *name;
{
- int type, i;
- char token[MAXTOKEN];
- struct enum_list *ep = 0;
- struct tc *tcp;
- int level;
+ register int type;
+ char token[64];
+ int count, length;
+ struct subid SubOid[32];
+ char syntax[64];
+ int nexttype;
+ char nexttoken[64];
+ register struct node *np=NULL;
+ register struct enum_list *ep=NULL;
type = get_token(fp, token);
- if (type == SEQUENCE) {
- while ((type = get_token(fp, token)) != ENDOFFILE) {
- if (type == RIGHTBRACKET) {
- *ntype = get_token(fp, ntoken);
- return 1;
- }
- }
- print_error("Expected \"}\"", token, type);
+ if (type != SYNTAX){
+ print_error("Bad format for OBJECT TYPE", token, type);
return 0;
- } else {
- if (!strcmp(token, "TEXTUAL-CONVENTION")) {
- while (type != SYNTAX)
- type = get_token(fp, token);
- type = get_token(fp, token);
- }
- /* textual convention */
- for (i = 0; i < MAXTC; i++) {
- if (tclist[i].type == 0)
- break;
- }
- if (i == MAXTC) {
- print_error("No more textual conventions possible.", token, type);
- return 0;
- }
- tcp = &tclist[i];
- strcpy(tcp->descriptor, name);
- if (!(type & SYNTAX_MASK)) {
- print_error("Textual convention doesn't map to real type.", token,
- type);
- return 0;
- }
- tcp->type = type;
- *ntype = get_token(fp, ntoken);
- if (*ntype == LEFTPAREN) {
- level = 1;
- /* don't record any constraints for now */
- while (level > 0) {
- *ntype = get_token(fp, ntoken);
- if (*ntype == LEFTPAREN)
- level++;
- if (*ntype == RIGHTPAREN)
- level--;
- }
- *ntype = get_token(fp, ntoken);
- } else if (*ntype == LEFTBRACKET) {
- /* if there is an enumeration list, parse it */
- while ((type = get_token(fp, token)) != ENDOFFILE) {
- if (type == RIGHTBRACKET)
- break;
- if (type == LABEL) {
- /* this is an enumerated label */
- if (tcp->enums == 0) {
- ep = tcp->enums = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- } else {
- ep->next = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- ep = ep->next;
- }
- ep->next = 0;
- /* a reasonable approximation for the length */
- ep->label =
- (char *) Malloc((unsigned) strlen(token) + 1);
- strcpy(ep->label, token);
- type = get_token(fp, token);
- if (type != LEFTPAREN) {
- print_error("Expected \"(\"", token, type);
- /* free_node(np); */
- return 0;
- }
- type = get_token(fp, token);
- if (type != NUMBER) {
- print_error("Expected integer", token, type);
- /* free_node(np); */
- return 0;
- }
- ep->value = atoi(token);
- type = get_token(fp, token);
- if (type != RIGHTPAREN) {
- print_error("Expected \")\"", token, type);
- /* free_node(np); */
- return 0;
- }
- }
- }
- if (type == ENDOFFILE) {
- print_error("Expected \"}\"", token, type);
- /* free_node(np); */
- return 0;
- }
- *ntype = get_token(fp, ntoken);
- }
- return 1;
}
-}
-
-
-/*
- * Parses an OBJECT TYPE macro.
- * Returns 0 on error.
- */
-static struct node *
-parse_objecttype(FILE * fp, char *name)
-{
- int type;
- char token[MAXTOKEN];
- int count, length;
- struct subid oid[32];
- char syntax[MAXTOKEN];
- int nexttype, tctype;
- char nexttoken[MAXTOKEN];
- struct node *np;
- struct enum_list *ep = 0;
-
- type = get_token(fp, token);
- if (type != SYNTAX) {
- print_error("Bad format for OBJECT TYPE", token, type);
- return 0;
- }
- np = (struct node *) Malloc(sizeof(struct node));
+ np = (struct node *)xmalloc(sizeof(struct node));
np->next = 0;
np->enums = 0;
- np->description = NULL; /* default to an empty description */
type = get_token(fp, token);
- if (type == LABEL) {
- tctype = get_tc(token, &(np->enums));
-#if 0
- if (tctype == LABEL) {
- print_error("No known translation for type", token, type);
- return 0;
- }
-#endif
- type = tctype;
- }
- np->type = type;
nexttype = get_token(fp, nexttoken);
- switch (type) {
- case SEQUENCE:
- strcpy(syntax, token);
- if (nexttype == OF) {
- strcat(syntax, " ");
- strcat(syntax, nexttoken);
- nexttype = get_token(fp, nexttoken);
- strcat(syntax, " ");
- strcat(syntax, nexttoken);
- nexttype = get_token(fp, nexttoken);
- }
- break;
- case INTEGER:
- case UINTEGER32:
- strcpy(syntax, token);
- if (nexttype == LEFTBRACKET) {
- /* if there is an enumeration list, parse it */
- while ((type = get_token(fp, token)) != ENDOFFILE) {
- if (type == RIGHTBRACKET)
- break;
- if (type == LABEL) {
- /* this is an enumerated label */
- if (np->enums == 0) {
- ep = np->enums = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- } else {
- ep->next = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- ep = ep->next;
- }
- ep->next = 0;
- /* a reasonable approximation for the length */
- ep->label =
- (char *) Malloc((unsigned) strlen(token) + 1);
- strcpy(ep->label, token);
- type = get_token(fp, token);
- if (type != LEFTPAREN) {
- print_error("Expected \"(\"", token, type);
- free_node(np);
- return 0;
- }
- type = get_token(fp, token);
- if (type != NUMBER) {
- print_error("Expected integer", token, type);
- free_node(np);
- return 0;
- }
- ep->value = atoi(token);
- type = get_token(fp, token);
- if (type != RIGHTPAREN) {
- print_error("Expected \")\"", token, type);
- free_node(np);
- return 0;
- }
- }
- }
- if (type == ENDOFFILE) {
- print_error("Expected \"}\"", token, type);
- free_node(np);
- return 0;
- }
- nexttype = get_token(fp, nexttoken);
- } else if (nexttype == LEFTPAREN) {
- /* ignore the "constrained integer" for now */
- nexttype = get_token(fp, nexttoken);
- nexttype = get_token(fp, nexttoken);
- nexttype = get_token(fp, nexttoken);
- }
- break;
- case BITSTRING:
- strcpy(syntax, token);
- if (nexttype == LEFTBRACKET) {
- /* if there is an enumeration list, parse it */
- while ((type = get_token(fp, token)) != ENDOFFILE) {
- if (type == RIGHTBRACKET)
- break;
- if (type == LABEL) {
- /* this is an enumerated label */
- if (np->enums == 0) {
- ep = np->enums = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- } else {
- ep->next = (struct enum_list *)
- Malloc(sizeof(struct enum_list));
- ep = ep->next;
- }
- ep->next = 0;
- /* a reasonable approximation for the length */
- ep->label =
- (char *) Malloc((unsigned) strlen(token) + 1);
- strcpy(ep->label, token);
- type = get_token(fp, token);
- if (type != LEFTPAREN) {
- print_error("Expected \"(\"", token, type);
- free_node(np);
- return 0;
- }
- type = get_token(fp, token);
- if (type != NUMBER) {
- print_error("Expected integer", token, type);
- free_node(np);
- return 0;
- }
- ep->value = atoi(token);
- type = get_token(fp, token);
- if (type != RIGHTPAREN) {
- print_error("Expected \")\"", token, type);
- free_node(np);
- return 0;
- }
- }
- }
- if (type == ENDOFFILE) {
- print_error("Expected \"}\"", token, type);
- free_node(np);
- return 0;
- }
- nexttype = get_token(fp, nexttoken);
- } else if (nexttype == LEFTPAREN) {
- /* ignore the "constrained integer" for now */
- nexttype = get_token(fp, nexttoken);
- nexttype = get_token(fp, nexttoken);
- nexttype = get_token(fp, nexttoken);
- }
- break;
- case OCTETSTR:
- strcpy(syntax, token);
- /* ignore the "constrained octet string" for now */
- if (nexttype == LEFTPAREN) {
- nexttype = get_token(fp, nexttoken);
- if (nexttype == SIZE) {
+ np->type = type;
+ switch(type){
+ case SEQUENCE:
+ strcpy(syntax, token);
+ if (nexttype == OF){
+ strcat(syntax, " ");
+ strcat(syntax, nexttoken);
+ nexttype = get_token(fp, nexttoken);
+ strcat(syntax, " ");
+ strcat(syntax, nexttoken);
nexttype = get_token(fp, nexttoken);
- if (nexttype == LEFTPAREN) {
- nexttype = get_token(fp, nexttoken); /* 0..255 */
- nexttype = get_token(fp, nexttoken); /* ) */
- nexttype = get_token(fp, nexttoken); /* ) */
- if (nexttype == RIGHTPAREN) {
- nexttype = get_token(fp, nexttoken);
+ }
+ break;
+ case INTEGER:
+ strcpy(syntax, token);
+ if (nexttype == LEFTBRACKET) {
+ /* if there is an enumeration list, parse it */
+ while((type = get_token(fp, token)) != ENDOFFILE){
+ if (type == RIGHTBRACKET)
break;
+ if (type == LABEL){
+ /* this is an enumerated label */
+ if (np->enums == 0){
+ ep = np->enums = (struct enum_list *)
+ xmalloc(sizeof(struct enum_list));
+ } else {
+ ep->next = (struct enum_list *)
+ xmalloc(sizeof(struct enum_list));
+ ep = ep->next;
+ }
+ ep->next = 0;
+ /* a reasonable approximation for the length */
+ ep->label = (char *)xmalloc((unsigned)strlen(token) + 1);
+ strcpy(ep->label, token);
+ type = get_token(fp, token);
+ if (type != LEFTPAREN){
+ print_error("Expected \"(\"", token, type);
+ free_node(np);
+ return 0;
+ }
+ type = get_token(fp, token);
+ if (type != NUMBER){
+ print_error("Expected integer", token, type);
+ free_node(np);
+ return 0;
+ }
+ ep->value = atoi(token);
+ type = get_token(fp, token);
+ if (type != RIGHTPAREN){
+ print_error("Expected \")\"", token, type);
+ free_node(np);
+ return 0;
+ }
}
}
+ if (type == ENDOFFILE){
+ print_error("Expected \"}\"", token, type);
+ free_node(np);
+ return 0;
+ }
+ nexttype = get_token(fp, nexttoken);
+ } else if (nexttype == LEFTPAREN){
+ /* ignore the "constrained integer" for now */
+ nexttype = get_token(fp, nexttoken);
+ nexttype = get_token(fp, nexttoken);
+ nexttype = get_token(fp, nexttoken);
}
+ break;
+ case OBJID:
+ case OCTETSTR:
+ case NETADDR:
+ case IPADDR:
+ case COUNTER:
+ case GAUGE:
+ case TIMETICKS:
+ case OPAQUE:
+ case NUL:
+ case LABEL:
+ strcpy(syntax, token);
+ break;
+ default:
print_error("Bad syntax", token, type);
free_node(np);
return 0;
- }
- break;
- case OBJID:
- case NETADDR:
- case IPADDR:
- case COUNTER:
- case GAUGE:
- case TIMETICKS:
- case OPAQUE:
- case NUL:
- case LABEL:
- case NSAPADDRESS:
- case COUNTER64:
- strcpy(syntax, token);
- break;
- default:
- print_error("Bad syntax", token, type);
- free_node(np);
- return 0;
- }
- if (nexttype == UNITS) {
- type = get_token(fp, token);
- if (type != QUOTESTRING) {
- print_error("Bad DESCRIPTION", token, type);
- free_node(np);
- return 0;
- }
- nexttype = get_token(fp, nexttoken);
}
- if (nexttype != ACCESS) {
+ if (nexttype != ACCESS){
print_error("Should be ACCESS", nexttoken, nexttype);
free_node(np);
return 0;
}
type = get_token(fp, token);
if (type != READONLY && type != READWRITE && type != WRITEONLY
- && type != NOACCESS && type != READCREATE) {
+ && type != NOACCESS){
print_error("Bad access type", nexttoken, nexttype);
free_node(np);
return 0;
}
type = get_token(fp, token);
- if (type != STATUS) {
+ if (type != STATUS){
print_error("Should be STATUS", token, nexttype);
free_node(np);
return 0;
}
type = get_token(fp, token);
- if (type != MANDATORY && type != CURRENT && type != OPTIONAL && type != OBSOLETE && type != DEPRECATED) {
+ if (type != MANDATORY && type != OPTIONAL && type != OBSOLETE && type != RECOMMENDED){
print_error("Bad status", token, type);
free_node(np);
return 0;
}
- /*
- * Optional parts of the OBJECT-TYPE macro
+ /* Fetch next token. Either:
+ *
+ * -> EQUALS (Old MIB format)
+ * -> DESCRIPTION, INDEX (New MIB format)
*/
type = get_token(fp, token);
- while (type != EQUALS) {
- switch (type) {
- case DESCRIPTION:
- type = get_token(fp, token);
- if (type != QUOTESTRING) {
- print_error("Bad DESCRIPTION", token, type);
- free_node(np);
- return 0;
- }
-#ifdef TEST
- printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
- np->description = quoted_string_buffer;
- quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
- break;
+ if ((type != DESCRIPTION) && (type != INDEX) && (type != EQUALS)) {
+ print_error("Should be DESCRIPTION, INDEX, or EQUALS", token, nexttype);
+ free_node(np);
+ return 0;
+ }
- case REFERENCE:
- type = get_token(fp, token);
- if (type != QUOTESTRING) {
- print_error("Bad DESCRIPTION", token, type);
- free_node(np);
- return 0;
- }
- break;
- case INDEX:
- case DEFVAL:
- case AUGMENTS:
- case NUM_ENTRIES:
- if (tossObjectIdentifier(fp) != OBJID) {
- print_error("Bad Object Identifier", token, type);
- free_node(np);
- return 0;
- }
- break;
+ if (type == DESCRIPTION) {
- default:
- print_error("Bad format of optional clauses", token, type);
- free_node(np);
- return 0;
-
- }
- type = get_token(fp, token);
- }
- if (type != EQUALS) {
- print_error("Bad format", token, type);
+ type = get_token(fp, token);
+ if (type != QUOTE) {
+ print_error("Should be Description open quote", token, nexttype);
free_node(np);
return 0;
- }
- length = getoid(fp, oid, 32);
- if (length > 1 && length <= 32) {
- /* just take the last pair in the oid list */
- if (oid[length - 2].label)
- strncpy(np->parent, oid[length - 2].label, MAXLABEL);
- strcpy(np->label, name);
- if (oid[length - 1].subid != -1)
- np->subid = oid[length - 1].subid;
- else
- print_error("Warning: This entry is pretty silly", np->label, type);
- } else {
- print_error("No end to oid", (char *) NULL, type);
- free_node(np);
- np = 0;
- }
- /* free oid array */
- for (count = 0; count < length; count++) {
- if (oid[count].label)
- xfree(oid[count].label);
- oid[count].label = 0;
- }
- return np;
-}
+ }
+ /* Fetch description string */
+ {
+ int ReadChar;
-/*
- * Parses an OBJECT GROUP macro.
- * Returns 0 on error.
- */
-static struct node *
-parse_objectgroup(FILE * fp, char *name)
-{
- int type;
- char token[MAXTOKEN];
- int count, length;
- struct subid oid[32];
- struct node *np;
-
- np = (struct node *) Malloc(sizeof(struct node));
- np->type = 0;
- np->next = 0;
- np->enums = 0;
- np->description = NULL; /* default to an empty description */
- type = get_token(fp, token);
- while (type != EQUALS) {
- switch (type) {
- case DESCRIPTION:
- type = get_token(fp, token);
- if (type != QUOTESTRING) {
- print_error("Bad DESCRIPTION", token, type);
- free_node(np);
- return 0;
- }
-#ifdef TEST
- printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
- np->description = quoted_string_buffer;
- quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
- break;
-
- default:
- /* NOTHING */
- break;
+ ReadChar = last;
+ /* skip everything until closing quote */
+ while((ReadChar != '"') && (ReadChar != -1)) {
+ ReadChar = getc(fp);
+ if (ReadChar == '\n')
+ Line++;
}
- type = get_token(fp, token);
- }
- length = getoid(fp, oid, 32);
- if (length > 1 && length <= 32) {
- /* just take the last pair in the oid list */
- if (oid[length - 2].label)
- strncpy(np->parent, oid[length - 2].label, MAXLABEL);
- strcpy(np->label, name);
- if (oid[length - 1].subid != -1)
- np->subid = oid[length - 1].subid;
- else
- print_error("Warning: This entry is pretty silly", np->label, type);
- } else {
- print_error("No end to oid", (char *) NULL, type);
- free_node(np);
- np = 0;
+ last = ' ';
+ }
+ /* ASSERT: Done with description. */
+ type = get_token(fp, token);
}
- /* free oid array */
- for (count = 0; count < length; count++) {
- if (oid[count].label)
- xfree(oid[count].label);
- oid[count].label = 0;
+
+ if ((type != INDEX) && (type != EQUALS)) {
+ print_error("Should be INDEX, or EQUALS", token, nexttype);
+ free_node(np);
+ return 0;
}
- return np;
-}
-/*
- * Parses a NOTIFICATION-TYPE macro.
- * Returns 0 on error.
- */
-static struct node *
-parse_notificationDefinition(FILE * fp, char *name)
-{
- int type;
- char token[MAXTOKEN];
- int count, length;
- struct subid oid[32];
- struct node *np;
+ if (type == INDEX) {
- np = (struct node *) Malloc(sizeof(struct node));
- np->type = 0;
- np->next = 0;
- np->enums = 0;
- np->description = NULL; /* default to an empty description */
- type = get_token(fp, token);
- while (type != EQUALS) {
- switch (type) {
- case DESCRIPTION:
- type = get_token(fp, token);
- if (type != QUOTESTRING) {
- print_error("Bad DESCRIPTION", token, type);
- free_node(np);
- return 0;
- }
-#ifdef TEST
- printf("Description== \"%.50s\"\n", quoted_string_buffer);
-#endif
- np->description = quoted_string_buffer;
- quoted_string_buffer = xcalloc(1, MAXQUOTESTR);
- break;
+ /* Scarf INDEX */
- default:
- /* NOTHING */
- break;
- }
- type = get_token(fp, token);
- }
- length = getoid(fp, oid, 32);
- if (length > 1 && length <= 32) {
- /* just take the last pair in the oid list */
- if (oid[length - 2].label)
- strncpy(np->parent, oid[length - 2].label, MAXLABEL);
- strcpy(np->label, name);
- if (oid[length - 1].subid != -1)
- np->subid = oid[length - 1].subid;
- else
- print_error("Warning: This entry is pretty silly", np->label, type);
- } else {
- print_error("No end to oid", (char *) NULL, type);
+ type = get_token(fp, token);
+ if (type != LEFTBRACKET){
+ print_error("Should be INDEX left brace", token, type);
free_node(np);
- np = 0;
- }
- /* free oid array */
- for (count = 0; count < length; count++) {
- if (oid[count].label)
- xfree(oid[count].label);
- oid[count].label = 0;
- }
- return np;
-}
+ return 0;
+ }
-/*
- * Parses a compliance macro
- * Returns 0 on error.
- */
-static struct node *
-parse_compliance(FILE * fp, char *name)
-{
- int type;
- char token[MAXTOKEN];
- int count, length;
- struct subid oid[32];
- struct node *np;
+ /* Fetch description string */
+ {
+ int ReadChar;
- np = (struct node *) Malloc(sizeof(struct node));
- np->type = 0;
- np->next = 0;
- np->enums = 0;
- np->description = NULL; /* default to an empty description */
- type = get_token(fp, token);
- while (type != EQUALS) {
- type = get_token(fp, token);
- }
- length = getoid(fp, oid, 32);
- if (length > 1 && length <= 32) {
- /* just take the last pair in the oid list */
- if (oid[length - 2].label)
- strncpy(np->parent, oid[length - 2].label, MAXLABEL);
- strcpy(np->label, name);
- if (oid[length - 1].subid != -1)
- np->subid = oid[length - 1].subid;
- else
- print_error("Warning: This entry is pretty silly", np->label, type);
- } else {
- print_error("No end to oid", (char *) NULL, type);
- free_node(np);
- np = 0;
- }
- /* free oid array */
- for (count = 0; count < length; count++) {
- if (oid[count].label)
- xfree(oid[count].label);
- oid[count].label = 0;
+ ReadChar = last;
+ /* skip everything until closing quote */
+ while((ReadChar != '}') && (ReadChar != -1)) {
+ ReadChar = getc(fp);
+ if (ReadChar == '\n')
+ Line++;
+ }
+ last = ' ';
+ }
+ /* ASSERT: Done with INDEX. */
+ type = get_token(fp, token);
}
- return np;
-}
-
-
-
-/*
- * Parses a module identity macro
- * Returns 0 on error.
- */
-static struct node *
-parse_moduleIdentity(FILE * fp, char *name)
-{
- int type;
- char token[MAXTOKEN];
- int count, length;
- struct subid oid[32];
- struct node *np;
- np = (struct node *) Malloc(sizeof(struct node));
- np->type = 0;
- np->next = 0;
- np->enums = 0;
- np->description = NULL; /* default to an empty description */
- type = get_token(fp, token);
- while (type != EQUALS) {
- type = get_token(fp, token);
+ if (type != EQUALS){
+ print_error("Bad format", token, type);
+ free_node(np);
+ return 0;
}
- length = getoid(fp, oid, 32);
- if (length > 1 && length <= 32) {
+ length = getoid(fp, SubOid, 32);
+ if (length > 1 && length <= 32){
/* just take the last pair in the oid list */
- if (oid[length - 2].label)
- strncpy(np->parent, oid[length - 2].label, MAXLABEL);
+ if (SubOid[length - 2].label)
+ strncpy(np->parent, SubOid[length - 2].label, 64);
strcpy(np->label, name);
- if (oid[length - 1].subid != -1)
- np->subid = oid[length - 1].subid;
+ if (SubOid[length - 1].subid != -1)
+ np->subid = SubOid[length - 1].subid;
else
print_error("Warning: This entry is pretty silly", np->label, type);
} else {
- print_error("No end to oid", (char *) NULL, type);
+ print_error("No end to oid", (char *)NULL, type);
free_node(np);
np = 0;
}
/* free oid array */
- for (count = 0; count < length; count++) {
- if (oid[count].label)
- xfree(oid[count].label);
- oid[count].label = 0;
+ for(count = 0; count < length; count++){
+ if (SubOid[count].label)
+ xfree(SubOid[count].label);
+ SubOid[count].label = 0;
}
return np;
}
-int
-parse_mib_header(FILE * fp, char *name)
-{
- int type = DEFINITIONS;
- char token[MAXTOKEN];
-
- /* This probably isn't good enough. If there is no
- * imports clause we can't go around waiting (forever) for a semicolon.
- * We need to check for semi following an EXPORTS clause or an IMPORTS
- * clause of both. Look for BEGIN; in my initial MIBs to see those
- * that I needed to hack to get to parse because they didn't have
- * an IMPORTS or and EXPORTS clause.
- */
- while (type != SEMI && type != ENDOFFILE) {
- type = get_token(fp, token);
- }
- return (type == SEMI);
-}
-
-
/*
* Parses a mib file and returns a linked list of nodes found in the file.
* Returns NULL on error.
*/
-static struct node *
-parse(FILE * fp)
+#ifndef TEST
+static
+#endif
+struct node *
+parse(fp)
+ FILE *fp;
{
- char token[MAXTOKEN];
- char name[MAXTOKEN];
- int type = 1;
-#define BETWEEN_MIBS 1
-#define IN_MIB 2
- int state = BETWEEN_MIBS;
- struct node *np = 0, *root = NULL;
+ char token[64];
+ char name[64];
+ int type = 1;
+ struct node *np=NULL, *root = NULL;
hash_init();
- quoted_string_buffer = xcalloc(1, MAXQUOTESTR); /* free this later */
- memset(tclist, '\0', 64 * sizeof(struct tc));
- while (type != ENDOFFILE) {
+ while(type != ENDOFFILE){
type = get_token(fp, token);
- skipget:
- if (type == END) {
- if (state != IN_MIB) {
- print_error("Error, end before start of MIB.", (char *) NULL, type);
- return NULL;
- }
- state = BETWEEN_MIBS;
- continue;
- } else if (type != LABEL) {
- if (type == ENDOFFILE) {
+ if (type != LABEL){
+ if (type == ENDOFFILE){
return root;
}
print_error(token, "is a reserved word", type);
return NULL;
}
- strncpy(name, token, MAXTOKEN);
+ strncpy(name, token, 64);
type = get_token(fp, token);
- if (type == DEFINITIONS) {
- if (state != BETWEEN_MIBS) {
- print_error("Error, nested MIBS.", (char *) NULL, type);
- return NULL;
- }
- state = IN_MIB;
- if (!parse_mib_header(fp, name)) {
- print_error("Bad parse of module header", (char *) NULL, type);
- return NULL;
- }
- } else if (type == OBJTYPE) {
- if (root == NULL) {
+ if (type == OBJTYPE){
+ if (root == NULL){
/* first link in chain */
np = root = parse_objecttype(fp, name);
- if (np == NULL) {
- print_error("Bad parse of object type", (char *) NULL,
- type);
+ if (np == NULL){
+ print_error("Bad parse of object type", (char *)NULL, type);
return NULL;
}
} else {
np->next = parse_objecttype(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of objecttype", (char *) NULL,
- type);
- return NULL;
- }
- }
- /* now find end of chain */
- while (np->next)
- np = np->next;
- } else if (type == OBJGROUP) {
- if (root == NULL) {
- /* first link in chain */
- np = root = parse_objectgroup(fp, name);
- if (np == NULL) {
- print_error("Bad parse of object group", (char *) NULL,
- type);
- return NULL;
- }
- } else {
- np->next = parse_objectgroup(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of objectgroup", (char *) NULL,
- type);
- return NULL;
- }
- }
- /* now find end of chain */
- while (np->next)
- np = np->next;
- } else if (type == NOTIFTYPE) {
- if (root == NULL) {
- /* first link in chain */
- np = root = parse_notificationDefinition(fp, name);
- if (np == NULL) {
- print_error("Bad parse of notification definition",
- (char *) NULL, type);
- return NULL;
- }
- } else {
- np->next = parse_notificationDefinition(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of notification definition",
- (char *) NULL, type);
+ if (np->next == NULL){
+ print_error("Bad parse of objecttype", (char *)NULL, type);
return NULL;
}
}
/* now find end of chain */
- while (np->next)
+ while(np->next)
np = np->next;
- } else if (type == COMPLIANCE) {
- if (root == NULL) {
- /* first link in chain */
- np = root = parse_compliance(fp, name);
- if (np == NULL) {
- print_error("Bad parse of module compliance", (char *) NULL,
- type);
- return NULL;
- }
- } else {
- np->next = parse_compliance(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of module compliance", (char *) NULL,
- type);
- return NULL;
- }
- }
- /* now find end of chain */
- while (np->next)
- np = np->next;
- } else if (type == MODULEIDENTITY) {
- if (root == NULL) {
- /* first link in chain */
- np = root = parse_moduleIdentity(fp, name);
- if (np == NULL) {
- print_error("Bad parse of module identity", (char *) NULL,
- type);
- return NULL;
- }
- } else {
- np->next = parse_moduleIdentity(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of module identity", (char *) NULL,
- type);
- return NULL;
- }
- }
- /* now find end of chain */
- while (np->next)
- np = np->next;
- } else if (type == OBJID) {
- if (root == NULL) {
+ } else if (type == OBJID){
+ if (root == NULL){
/* first link in chain */
np = root = parse_objectid(fp, name);
- if (np == NULL) {
- print_error("Bad parse of object id", (char *) NULL, type);
+ if (np == NULL){
+ print_error("Bad parse of object id", (char *)NULL, type);
return NULL;
}
} else {
np->next = parse_objectid(fp, name);
- if (np->next == NULL) {
- print_error("Bad parse of object type", (char *) NULL,
- type);
+ if (np->next == NULL){
+ print_error("Bad parse of object type", (char *)NULL, type);
return NULL;
}
}
/* now find end of chain */
- while (np->next)
+ while(np->next)
np = np->next;
- } else if (type == EQUALS) {
- if (!parse_asntype(fp, name, &type, token)) {
- print_error("Bad parse of ASN type definition.", NULL, EQUALS);
- return NULL;
- }
- goto skipget;
- } else if (type == ENDOFFILE) {
+ } else if (type == EQUALS){
+ type = parse_asntype(fp);
+ } else if (type == ENDOFFILE){
break;
} else {
- print_error("Bad operator", (char *) NULL, type);
+ print_error("Bad operator", (char *)NULL, type);
return NULL;
}
}
#ifdef TEST
- {
- struct enum_list *ep;
-
- for (np = root; np; np = np->next) {
- printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
+{
+ struct enum_list *ep;
+
+ for(np = root; np; np = np->next){
+ printf("%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid,
np->type);
- if (np->enums) {
- printf("Enums: \n");
- for (ep = np->enums; ep; ep = ep->next) {
- printf("%s(%d)\n", ep->label, ep->value);
- }
+ if (np->enums){
+ printf("Enums: \n");
+ for(ep = np->enums; ep; ep = ep->next){
+ printf("%s(%d)\n", ep->label, ep->value);
}
}
}
+}
#endif /* TEST */
return root;
}
-/*
- * Parses a token from the file. The type of the token parsed is returned,
- * and the text is placed in the string pointed to by token.
- */
-static int
-get_token(FILE * fp, char *token)
-{
- static char last = ' ';
- int ch;
- char *cp = token;
- int hash = 0;
- struct tok *tp;
-
- *cp = 0;
- ch = last;
- /* skip all white space */
- while (isspace(ch) && ch != -1) {
- ch = getc(fp);
- if (ch == '\n')
- Line++;
- }
- if (ch == -1) {
- return ENDOFFILE;
- } else if (ch == '"') {
- return parseQuoteString(fp, token);
- }
- /*
- * Accumulate characters until end of token is found. Then attempt to
- * match this token as a reserved word. If a match is found, return the
- * type. Else it is a label.
- */
- do {
- if (ch == '\n')
- Line++;
- if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' ||
- ch == ',' || ch == ';') {
- if (!isspace(ch) && *token == 0) {
- hash += ch;
- *cp++ = ch;
- last = ' ';
- } else {
- last = ch;
- }
- *cp = '\0';
-
- for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) {
- if ((tp->hash == hash) && (strcmp(tp->name, token) == 0))
- break;
- }
- if (tp) {
- if (tp->token == CONTINUE)
- continue;
- return (tp->token);
- }
- if (token[0] == '-' && token[1] == '-') {
- /* strip comment */
- if (ch != '\n') {
- while ((ch = getc(fp)) != -1)
- if (ch == '\n') {
- Line++;
- break;
- }
- }
- if (ch == -1)
- return ENDOFFILE;
- last = ch;
- return get_token(fp, token);
- }
- for (cp = token; *cp; cp++)
- if (!isdigit(*cp))
- return LABEL;
- return NUMBER;
- } else {
- hash += ch;
- *cp++ = ch;
- if (ch == '\n')
- Line++;
- }
-
- } while ((ch = getc(fp)) != -1);
- return ENDOFFILE;
-}
-
-struct tree *
-read_mib(const char *filename)
+struct snmp_mib_tree *
+read_mib(filename)
+ char *filename;
{
FILE *fp;
struct node *nodes;
- struct tree *tree;
+ struct snmp_mib_tree *tree;
fp = fopen(filename, "r");
if (fp == NULL)
- return NULL;
+ return(NULL);
nodes = parse(fp);
- if (!nodes) {
- fprintf(stderr, "Mib table is bad. Exiting\n");
+ if (!nodes){
+ snmplib_debug(0, "Mib table is bad. Exiting\n");
exit(1);
}
tree = build_tree(nodes);
fclose(fp);
- return tree;
-}
-
-
-#ifdef TEST
-main(int argc, char *argv[])
-{
- FILE *fp;
- struct node *nodes;
- struct tree *tp;
-
- fp = fopen("mib.txt", "r");
- if (fp == NULL) {
- fprintf(stderr, "open failed\n");
- return 1;
- }
- nodes = parse(fp);
- tp = build_tree(nodes);
- print_subtree(tp, 0);
- fclose(fp);
-}
-
-#endif /* TEST */
-
-static int
-parseQuoteString(FILE * fp, char *token)
-{
- int ch;
-
- ch = ' ';
- *token = '\0'; /* make the token empty */
-
- while (ch != -1) {
- ch = getc(fp);
- if (ch == '\n')
- Line++;
- else if (ch == '"') {
- return QUOTESTRING;
- }
- }
-
- return 0;
+ return(tree);
}
-/*
- * This routine parses a string like { blah blah blah } and returns OBJID if
- * it is well formed, and NULL if not.
- */
-static int
-tossObjectIdentifier(FILE * fp)
-{
- int ch;
- ch = getc(fp);
-/* ch = last; = ' '? */
- /* skip all white space */
- while (isspace(ch) && ch != -1) {
- ch = getc(fp);
- if (ch == '\n')
- Line++;
- }
- if (ch != '{')
- return 0;
-
- while (ch != -1) {
- ch = getc(fp);
-
- if (ch == '\n')
- Line++;
- else if (ch == '}')
- return OBJID;
- }
-
-/* last = ch; */
- return 0;
-}
-/*
- * Copyright 1989 by Carnegie Mellon University
+/**********************************************************************
+ *
+ * Copyright 1997 by Carnegie Mellon University
*
- * All Rights Reserved
+ * All Rights Reserved
*
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
+ * 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
+ * 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.
+ * 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
* 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.
- */
-/*
- * snmp_api.c - API for access to snmp.
- */
+ *
+ **********************************************************************/
#include "config.h"
+#include <stdio.h>
+
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-
-#define free +
-
-#define DEBUG_SNMPTRACE 0 /* set to 1 to print all SNMP actions */
-#define DEBUG_SNMPFULLDUMP 0 /* set to 1 to dump all SNMP packets */
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
#include "asn1.h"
#include "snmp.h"
+
+#include "snmp-internal.h"
#include "snmp_impl.h"
+#include "snmp_session.h"
+
+#include "mibii.h"
+#include "snmp_dump.h"
+#include "snmp_error.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+
#include "snmp_api.h"
#include "snmp_client.h"
+#include "snmp_api_error.h"
+#include "snmp_api_util.h"
#include "util.h"
-#define PACKET_LENGTH 4500
+extern int snmp_errno;
-oid default_enterprise[] =
-{1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */
-#define DEFAULT_COMMUNITY "public"
-#define DEFAULT_REMPORT SNMP_PORT
-#define DEFAULT_ENTERPRISE default_enterprise
-#define DEFAULT_TIME 0
-#define DEFAULT_MMS 1389 /* large, randomly picked for testing purposes */
-
-/*
- * Internal information about the state of the snmp session.
- */
-struct snmp_internal_session {
- int sd; /* socket descriptor for this connection */
- ipaddr addr; /* address of connected peer */
- struct request_list *requests; /* Info about outstanding requests */
-};
+/*#define DEBUG_API 1*/
/*
- * A list of all the outstanding requests for a particular session.
+ * RFC 1906: Transport Mappings for SNMPv2
*/
-struct request_list {
- struct request_list *next_request;
- u_long request_id; /* request id */
- int retries; /* Number of retries */
- u_long timeout; /* length to wait for timeout */
- struct timeval time; /* Time this request was made */
- struct timeval expire; /* time this request is due to expire */
- struct snmp_pdu *pdu; /* The pdu for this request (saved so it can be retransmitted */
-};
-/*
- * The list of active/open sessions.
- */
-struct session_list {
- struct session_list *next;
- struct snmp_session *session;
- struct snmp_internal_session *internal;
-};
-struct session_list *Sessions = NULL;
+oid default_enterprise[] = {1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */
-u_long Reqid = 0;
-int snmp_errno = 0;
-
-char *api_errors[4] =
-{
- "Unknown session",
- "Unknown host",
- "Invalid local port",
- "Unknown Error"
-};
+#define DEFAULT_COMMUNITY "public"
+#define DEFAULT_RETRIES 4
+#define DEFAULT_TIMEOUT 1000000L
+#define DEFAULT_REMPORT SNMP_PORT
+#define DEFAULT_ENTERPRISE default_enterprise
+#define DEFAULT_TIME 0
+extern int snmp_errno;
-static void sync_with_agent(struct snmp_session *session);
-#if NO_PRINTFS
-static char *
-api_errstring(int snmp_errnumber)
-{
- if (snmp_errnumber <= SNMPERR_BAD_SESSION && snmp_errnumber >= SNMPERR_GENERR) {
- return api_errors[snmp_errnumber + 4];
- } else {
- return "Unknown Error";
- }
-}
-#endif
+struct session_list *Sessions = NULL;
-#if UNUSED_CODE
/*
- * Gets initial request ID for all transactions.
+ * Get initial request ID for all transactions.
*/
-static void
-init_snmp(void)
+static int Reqid = 0;
+
+static void init_snmp(void)
{
- struct timeval tv;
+ struct timeval tv;
- gettimeofday(&tv, (struct timezone *) 0);
- srandom(tv.tv_sec ^ tv.tv_usec);
- Reqid = random();
+ gettimeofday(&tv, (struct timezone *)0);
+ squid_srandom(tv.tv_sec ^ tv.tv_usec);
+ Reqid = squid_random();
}
-#endif
/*
- * Dump snmp packet to stdout:
+ * Free each element in the input request list.
*/
-static void
-snmp_print_packet(char *packet, int length, ipaddr addr, int code)
+static void free_request_list(rp)
+ struct request_list *rp;
{
- if (length < 0) {
- return;
- }
-#if NO_PRINTFS
- if (code <= 0) { /* received */
- printf("\nReceived %4d bytes from ", length);
- } else { /* sending */
- printf("\nSending %4d bytes to ", length);
- }
- printf("%s:", inet_ntoa(addr.sin_addr));
-#endif
-#if DEBUG_SNMPFULLDUMP
- for (count = 0; count < length; count++) {
- if ((count & 15) == 0) {
- printf("\n ");
- }
- printf("%02X ", (int) (packet[count] & 255));
- }
-#endif
-#if NO_PRINTFS
- fflush(stdout);
-#endif
-}
+ struct request_list *orp;
-#if DEBUG_SNMPTRACE
-/*
- * Print request
- */
-#define TRACE_SEND (0)
-#define TRACE_RECV (1)
-#define TRACE_TIMEOUT (2)
-static void
-snmp_print_trace(struct session_list *slp, struct request_list *rp, int code)
-{
- int reqid = 0, retries = 1;
- if (rp) {
- reqid = rp->request_id;
- retries = rp->retries;
- }
- printf("\n Session %2d ReqId %4d ", slp->internal->sd, reqid);
- switch (code) {
- case TRACE_SEND:
- printf("send pdu (%d)", retries);
- break;
- case TRACE_RECV:
- printf("recv pdu");
- break;
- case TRACE_TIMEOUT:
- printf("time out");
- break;
+ while(rp){
+ orp = rp;
+ rp = rp->next_request;
+ if (orp->pdu != NULL)
+ snmp_free_pdu(orp->pdu);
+ xfree((char *)orp);
}
- fflush(stdout);
}
-#endif /* DEBUG_SNMPTRACE */
-
-
+/**********************************************************************/
/*
* Sets up the session with the snmp_session information provided
* the pointer passed to snmp_open()). On any error, NULL is returned
* and snmp_errno is set to the appropriate error code.
*/
-struct snmp_session *
-snmp_open(struct snmp_session *session)
+struct snmp_session *snmp_open(struct snmp_session *session)
{
- struct session_list *slp;
- struct snmp_internal_session *isp;
- u_char *cp;
- int sd;
- u_long addr;
- struct sockaddr_in me;
- struct hostent *hp;
- struct servent *servp;
- extern int check_received_pkt();
-
- /* Copy session structure and link into list */
- slp = xcalloc(1, sizeof(struct session_list));
- slp->internal = isp = xcalloc(1, sizeof(struct snmp_internal_session));
- memset(isp, '\0', sizeof(struct snmp_internal_session));
- slp->internal->sd = -1; /* mark it not set */
- slp->session = xcalloc(1, sizeof(struct snmp_session));
- xmemcpy(slp->session, session, sizeof(struct snmp_session));
- session = slp->session;
- /* now link it in. */
- slp->next = Sessions;
- Sessions = slp;
-
- /*
- * session now points to the new structure that still contains pointers to
- * data allocated elsewhere. Some of this data is copied to space malloc'd
- * here, and the pointer replaced with the new one.
- */
-
- if (session->peername != NULL) {
- cp = xcalloc(1, (unsigned) strlen(session->peername) + 1);
- strcpy((char *) cp, session->peername);
- session->peername = (char *) cp;
- }
- if (session->retries == SNMP_DEFAULT_RETRIES)
- session->retries = SNMP_API_DEFAULT_RETRIES;
- if (session->timeout == SNMP_DEFAULT_TIMEOUT)
- session->timeout = SNMP_API_DEFAULT_TIMEOUT;
- if (session->MMS == 0)
- session->MMS = DEFAULT_MMS;
- isp->requests = NULL;
-
-
- /* Fill in defaults if necessary */
- if (session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
- if (*session->community == '+') {
- session->community_len--;
- cp = xcalloc(1, (unsigned) session->community_len);
- bcopy((char *) session->community + 1, (char *) cp,
- session->community_len);
- session->version = SNMP_VERSION_2C;
- } else {
- cp = xcalloc(1, (unsigned) session->community_len);
- bcopy((char *) session->community, (char *) cp,
- session->community_len);
- }
-
+ struct session_list *slp;
+ struct snmp_internal_session *isp;
+ u_char *cp;
+ int sd;
+ u_int addr;
+ struct sockaddr_in me;
+ struct hostent *hp;
+ struct servent *servp;
+
+ if (Reqid == 0)
+ init_snmp();
+
+ /* Copy session structure and link into list */
+ slp = (struct session_list *)xmalloc(sizeof(struct session_list));
+ if (slp == NULL) {
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ /* Internal session */
+ isp = (struct snmp_internal_session *)xmalloc(sizeof(struct snmp_internal_session));
+ if (isp == NULL) {
+ xfree(slp);
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ slp->internal = isp;
+ memset((char *)isp, '\0', sizeof(struct snmp_internal_session));
+ slp->internal->sd = -1; /* mark it not set */
+
+ /* The actual session */
+ slp->session = (struct snmp_session *)xmalloc(sizeof(struct snmp_session));
+ if (slp->session == NULL) {
+ xfree(isp);
+ xfree(slp);
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ xmemcpy((char *)slp->session, (char *)session, sizeof(struct snmp_session));
+ session = slp->session;
+ /* now link it in. */
+ slp->next = Sessions;
+ Sessions = slp;
+
+ /*
+ * session now points to the new structure that still contains pointers to
+ * data allocated elsewhere. Some of this data is copied to space malloc'd
+ * here, and the pointer replaced with the new one.
+ */
+
+ if (session->peername != NULL) {
+ cp = (u_char *)xmalloc((unsigned)strlen(session->peername) + 1);
+ if (cp == NULL) {
+ xfree(slp->session);
+ xfree(isp);
+ xfree(slp);
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ strcpy((char *)cp, session->peername);
+ session->peername = (char *)cp;
+ }
+
+ /* Fill in defaults if necessary */
+ if (session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
+ cp = (u_char *)xmalloc((unsigned)session->community_len);
+ if (cp)
+ xmemcpy((char *)cp, (char *)session->community, session->community_len);
+ } else {
+ session->community_len = strlen(DEFAULT_COMMUNITY);
+ cp = (u_char *)xmalloc((unsigned)session->community_len);
+ if (cp)
+ xmemcpy((char *)cp, (char *)DEFAULT_COMMUNITY,
+ session->community_len);
+ }
+ if (cp == NULL) {
+ xfree(session->peername);
+ xfree(slp->session);
+ xfree(isp);
+ xfree(slp);
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ session->community = cp; /* replace pointer with pointer to new data */
+
+ if (session->retries == SNMP_DEFAULT_RETRIES)
+ session->retries = DEFAULT_RETRIES;
+ if (session->timeout == SNMP_DEFAULT_TIMEOUT)
+ session->timeout = DEFAULT_TIMEOUT;
+ isp->requests = NULL;
+
+ /* Set up connections */
+ sd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sd < 0) {
+ perror("socket");
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ if (!snmp_close(session)) {
+ snmplib_debug(5, "Couldn't abort session: %s. Exiting\n",
+ api_errstring(snmp_errno));
+ exit(1);
+ }
+ return(NULL);
+ }
+
+#ifdef SO_BSDCOMPAT
+ /* Patch for Linux. Without this, UDP packets that fail get an ICMP
+ * response. Linux turns the failed ICMP response into an error message
+ * and return value, unlike all other OS's.
+ */
+ {
+ int one=1;
+ setsockopt(sd, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
+ }
+#endif /* SO_BSDCOMPAT */
+
+ isp->sd = sd;
+ if (session->peername != SNMP_DEFAULT_PEERNAME) {
+ if ((addr = inet_addr(session->peername)) != -1) {
+ xmemcpy((char *)&isp->addr.sin_addr, (char *)&addr,
+ sizeof(isp->addr.sin_addr));
} else {
- session->community_len = strlen(DEFAULT_COMMUNITY);
- cp = xcalloc(1, (unsigned) session->community_len);
- xmemcpy(cp, DEFAULT_COMMUNITY, session->community_len);
- }
-
- /* Set up connections */
- sd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sd < 0) {
- perror("socket");
- snmp_errno = SNMPERR_GENERR;
- if (!snmp_close(session)) {
-#if NO_PRINTFS
- fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
-#endif
- exit(1);
- }
- return 0;
- }
- isp->sd = sd;
-
- if (session->peername != SNMP_DEFAULT_PEERNAME) {
- if ((addr = inet_addr(session->peername)) != -1) {
- xmemcpy(&isp->addr.sin_addr, &addr, sizeof(isp->addr.sin_addr));
- } else {
- hp = gethostbyname(session->peername);
- if (hp == NULL) {
-#if NO_PRINTFS
- fprintf(stderr, "unknown host: %s\n", session->peername);
-#endif
- snmp_errno = SNMPERR_BAD_ADDRESS;
- if (!snmp_close(session)) {
-#if NO_PRINTFS
- fprintf(stderr, "Couldn't abort session: %s. Exiting\n", api_errstring(snmp_errno));
-#endif
- exit(2);
- }
- return 0;
- } else {
- xmemcpy(&isp->addr.sin_addr, hp->h_addr, hp->h_length);
- }
- }
- isp->addr.sin_family = AF_INET;
- if (session->remote_port == SNMP_DEFAULT_REMPORT) {
- /*servp = getservbyname("snmp", "udp"); */
- servp = NULL;
- if (servp != NULL) {
- isp->addr.sin_port = servp->s_port;
- } else {
- isp->addr.sin_port = htons(SNMP_PORT);
- }
- } else {
- isp->addr.sin_port = htons(session->remote_port);
+ hp = gethostbyname(session->peername);
+ if (hp == NULL){
+ snmplib_debug(3, "unknown host: %s\n", session->peername);
+ snmp_errno = SNMPERR_BAD_ADDRESS;
+ if (!snmp_close(session)){
+ snmplib_debug(3, "Couldn't abort session: %s. Exiting\n",
+ api_errstring(snmp_errno));
+ exit(2);
}
+ return(NULL);
+ } else {
+ xmemcpy((char *)&isp->addr.sin_addr, (char *)hp->h_addr,
+ hp->h_length);
+ }
+ }
+
+ isp->addr.sin_family = AF_INET;
+ if (session->remote_port == SNMP_DEFAULT_REMPORT) {
+ servp = getservbyname("snmp", "udp");
+ if (servp != NULL){
+ isp->addr.sin_port = servp->s_port;
+ } else {
+ isp->addr.sin_port = htons(SNMP_PORT);
+ }
} else {
- isp->addr.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
- }
-
- me.sin_family = AF_INET;
- me.sin_addr.s_addr = INADDR_ANY;
- me.sin_port = htons(session->local_port);
- if (bind(sd, (struct sockaddr *) &me, sizeof(me)) != 0) {
- perror("bind");
- snmp_errno = SNMPERR_BAD_LOCPORT;
- if (!snmp_close(session)) {
-#if NO_PRINTFS
- fprintf(stderr, "Couldn't abort session: %s. Exiting\n",
- api_errstring(snmp_errno));
-#endif
- exit(3);
- }
- return 0;
- }
- if (*cp == '/') {
- session->authenticator = check_received_pkt;
- sync_with_agent(session);
- parse_app_community_string(session);
- session->qoS |= USEC_QOS_GENREPORT;
- }
- /* replace comm pointer with pointer to new data: */
- session->community = cp;
-
- return session;
-}
-
-static void
-sync_with_agent(struct snmp_session *session)
-{
- struct snmp_pdu *pdu, *response = 0;
- int status;
-
- session->qoS = USEC_QOS_GENREPORT;
- session->userLen = 6;
- session->version = SNMP_VERSION_2;
- strcpy((char *)session->userName, "public");
-
- snmp_synch_setup(session);
- pdu = snmp_pdu_create(GET_REQ_MSG);
- status = snmp_synch_response(session, pdu, &response);
-
- if (status == STAT_SUCCESS) {
- memcpy(session->agentID, response->params.agentID, 12);
-
- /* save the clocks -- even though they are not authentic */
- session->agentBoots = response->params.agentBoots;
- session->agentTime = response->params.agentTime;
- session->agentClock = response->params.agentTime - time(NULL);
-
- } else {
-#if NO_PRINTFS
- if (status == STAT_TIMEOUT) {
- printf("No Response from %s\n", session->peername);
- } else { /* status == STAT_ERROR */
- printf("An error occurred, Quitting\n");
- }
-#endif
- exit(-1);
- }
-
- /** freed to early:
- snmp_free_pdu(pdu);
- if (response) snmp_free_pdu(response);
- **/
+ isp->addr.sin_port = htons(session->remote_port);
+ }
+ } else {
+ isp->addr.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
+ }
+
+ memset(&me, '\0', sizeof(me));
+ me.sin_family = AF_INET;
+ me.sin_addr.s_addr = INADDR_ANY;
+ me.sin_port = htons(session->local_port);
+ if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0) {
+ perror("bind");
+ snmp_errno = SNMPERR_BAD_LOCPORT;
+ if (!snmp_close(session)) {
+ snmplib_debug(3, "Couldn't abort session: %s. Exiting\n",
+ api_errstring(snmp_errno));
+ exit(3);
+ }
+ return(NULL);
+ }
+ return(session);
}
-/*
- * Unlink one element from input request list,
- * then free it and it's pdu.
- */
-static void
-free_one_request(struct snmp_internal_session *isp, struct request_list *orp)
-{
- struct request_list *rp;
- if (!orp)
- return;
- if (isp->requests == orp) {
- isp->requests = orp->next_request; /* unlink head */
- } else {
- for (rp = isp->requests; rp; rp = rp->next_request) {
- if (rp->next_request == orp) {
- rp->next_request = orp->next_request; /* unlink element */
- break;
- }
- }
- }
- if (orp->pdu != NULL) {
- snmp_free_pdu(orp->pdu);
- }
- xfree((char *) orp);
-}
-
-/*
- * Free each element in the input request list.
- */
-static void
-free_request_list(struct request_list *rp)
-{
- struct request_list *orp;
- while (rp) {
- orp = rp;
- rp = rp->next_request;
- if (orp->pdu != NULL)
- snmp_free_pdu(orp->pdu);
- xfree((char *) orp);
- }
-}
/*
* Close the input session. Frees all data allocated for the session,
* dequeues any pending requests, and closes any sockets allocated for
* the session. Returns 0 on error, 1 otherwise.
*/
-int
-snmp_close(struct snmp_session *session)
+int snmp_close(struct snmp_session *session)
{
- struct session_list *slp = NULL, *oslp = NULL;
-
- if (Sessions->session == session) { /* If first entry */
- slp = Sessions;
- Sessions = slp->next;
- } else {
- for (slp = Sessions; slp; slp = slp->next) {
- if (slp->session == session) {
- if (oslp) /* if we found entry that points here */
- oslp->next = slp->next; /* link around this entry */
- break;
- }
- oslp = slp;
- }
- }
- /* If we found the session, free all data associated with it */
- if (slp) {
- if (slp->session->community != NULL)
- xfree((char *) slp->session->community);
- if (slp->session->peername != NULL)
- xfree((char *) slp->session->peername);
- xfree((char *) slp->session);
- if (slp->internal->sd != -1)
- close(slp->internal->sd);
- free_request_list(slp->internal->requests);
- xfree((char *) slp->internal);
- xfree((char *) slp);
- } else {
- snmp_errno = SNMPERR_BAD_SESSION;
- return 0;
- }
- return 1;
+ struct session_list *slp = NULL, *oslp = NULL;
+
+ if (Sessions->session == session) { /* If first entry */
+ slp = Sessions;
+ Sessions = slp->next;
+ } else {
+ for(slp = Sessions; slp; slp = slp->next){
+ if (slp->session == session){
+ if (oslp) /* if we found entry that points here */
+ oslp->next = slp->next; /* link around this entry */
+ break;
+ }
+ oslp = slp;
+ }
+ }
+
+ /* If we found the session, free all data associated with it */
+ if (slp) {
+ if (slp->session->community != NULL)
+ xfree((char *)slp->session->community);
+ if(slp->session->peername != NULL)
+ xfree((char *)slp->session->peername);
+ xfree((char *)slp->session);
+ if (slp->internal->sd != -1)
+ close(slp->internal->sd);
+ free_request_list(slp->internal->requests);
+ xfree((char *)slp->internal);
+ xfree((char *)slp);
+ } else {
+ snmp_errno = SNMPERR_BAD_SESSION;
+ return(0);
+ }
+ return(1);
}
/*
* Takes a session and a pdu and serializes the ASN PDU into the area
* pointed to by packet. out_length is the size of the data area available.
- * Returns the length of the completed packet in out_length. If any errors
- * occur, -1 is returned. If all goes well, 0 is returned.
+ * Returns the length of the encoded packet in out_length. If an error
+ * occurs, -1 is returned. If all goes well, 0 is returned.
*/
int
-snmp_build(
- struct snmp_session *session,
- struct snmp_pdu *pdu,
- u_char * packet,
- int *out_length,
- int is_agent)
+snmp_build(session, pdu, packet, out_length)
+ struct snmp_session *session;
+ struct snmp_pdu *pdu;
+ u_char *packet;
+ int *out_length;
{
- u_char buf[PACKET_LENGTH];
- u_char *cp;
- struct variable_list *vp;
- int length;
- int totallength;
-
- length = *out_length;
- cp = packet;
- for (vp = pdu->variables; vp; vp = vp->next_variable) {
- cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type, vp->val_len, (u_char *) vp->val.string, &length);
- if (cp == NULL)
- return -1;
- }
- totallength = cp - packet;
-
- length = PACKET_LENGTH;
- cp = asn_build_header(buf, &length, (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), totallength);
- if (cp == NULL)
- return -1;
- xmemcpy(cp, packet, totallength);
- totallength += cp - buf;
-
- length = *out_length;
- if (pdu->command != TRP_REQ_MSG) {
- /* request id */
- cp = asn_build_int(packet, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->reqid, sizeof(pdu->reqid));
- if (cp == NULL)
- return -1;
- /* error status */
- cp = asn_build_int(cp, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->errstat, sizeof(pdu->errstat));
- if (cp == NULL)
- return -1;
- /* error index */
- cp = asn_build_int(cp, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->errindex, sizeof(pdu->errindex));
- if (cp == NULL)
- return -1;
- } else { /* this is a trap message */
- /* enterprise */
- cp = asn_build_objid(packet, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
- (oid *) pdu->enterprise, pdu->enterprise_length);
- if (cp == NULL)
- return -1;
- /* agent-addr */
- cp = asn_build_string(cp, &length, (u_char) IPADDRESS,
- (u_char *) & pdu->agent_addr.sin_addr.s_addr, sizeof(pdu->agent_addr.sin_addr.s_addr));
- if (cp == NULL)
- return -1;
- /* generic trap */
- cp = asn_build_int(cp, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->trap_type, sizeof(pdu->trap_type));
- if (cp == NULL)
- return -1;
- /* specific trap */
- cp = asn_build_int(cp, &length,
- (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
- (long *) &pdu->specific_type, sizeof(pdu->specific_type));
- if (cp == NULL)
- return -1;
- /* timestamp */
- cp = asn_build_int(cp, &length, (u_char) TIMETICKS,
- (long *) &pdu->time, sizeof(pdu->time));
- if (cp == NULL)
- return -1;
- }
- if (length < totallength)
- return -1;
- xmemcpy(cp, buf, totallength);
- totallength += cp - packet;
-
- length = PACKET_LENGTH;
- cp = asn_build_header(buf, &length, (u_char) pdu->command, totallength);
- if (cp == NULL)
- return -1;
- if (length < totallength)
- return -1;
- xmemcpy(cp, packet, totallength);
- totallength += cp - buf;
-
- length = *out_length;
-
- cp = snmp_auth_build(packet, &length, session, is_agent, totallength);
- if (cp == NULL)
- return -1;
- if ((*out_length - (cp - packet)) < totallength)
- return -1;
- xmemcpy(cp, buf, totallength);
- totallength += cp - packet;
- *out_length = totallength;
-
- if (session->qoS & USEC_QOS_AUTH)
- md5Digest(packet, totallength, cp - (session->contextLen + 16),
- cp - (session->contextLen + 16));
-
- return 0;
+ u_char *bufp;
+
+ bufp = snmp_msg_Encode(packet, out_length,
+ session->community, session->community_len,
+ session->Version,
+ pdu);
+ snmplib_debug(8,"LIBSNMP: snmp_build(): Packet len difference %d, returning %d (requid %d)\n",
+ (bufp - packet), *out_length, pdu->reqid);
+
+ if (bufp == NULL)
+ return(-1);
+
+ return(0);
}
/*
- * Parses the packet received on the input session, and places the data into
+ * Parses the packet recieved on the input session, and places the data into
* the input pdu. length is the length of the input packet. If any errors
- * are encountered, -1 is returned. Otherwise, a 0 is returned.
+ * are encountered, NULL is returned. If not, the community is.
*/
-static int
-snmp_parse(
- struct snmp_session *session,
- struct snmp_pdu *pdu,
- u_char * data,
- int length)
+u_char *snmp_parse(struct snmp_session *session,
+ struct snmp_pdu *pdu,
+ u_char *data,
+ int length)
{
- u_char msg_type;
- u_char type;
- u_char *var_val;
- long version;
- int len, four;
- u_char community[256];
- int community_length = 256;
- struct variable_list *vp = 0;
- oid objid[MAX_NAME_LEN], *op;
- u_char *origdata = data;
- int origlength = length;
- int ret = 0;
- u_char *save_data;
-
- /* authenticates message and returns length if valid */
- data = snmp_auth_parse(data, &length, community, &community_length, &version);
+ u_char Community[128];
+ u_char *bufp;
+ int CommunityLen = 128;
+
+ /* Decode the entire message. */
+ data = snmp_msg_Decode(data, &length,
+ Community, &CommunityLen,
+ &session->Version, pdu);
if (data == NULL)
- return -1;
+ return(NULL);
- if (version != SNMP_VERSION_1 && version != SNMP_VERSION_2C && version != SNMP_VERSION_2) {
-#if NO_PRINTFS
- fprintf(stderr, "Wrong version: %ld\n", version);
-#endif
- return -1;
- }
- save_data = data;
+ bufp = (u_char *)xmalloc(CommunityLen+1);
+ if (bufp == NULL)
+ return(NULL);
- data = asn_parse_header(data, &length, &msg_type);
- if (data == NULL)
- return -1;
- pdu->command = msg_type;
-
- if (session->authenticator) {
- ret = session->authenticator(origdata, origlength, save_data - community_length,
- community_length, session, pdu);
- if (ret < 0)
- return ret;
- }
- if (pdu->command != TRP_REQ_MSG) {
- data = asn_parse_int(data, &length, &type, (long *) &pdu->reqid, sizeof(pdu->reqid));
- if (data == NULL)
- return -1;
- data = asn_parse_int(data, &length, &type, (long *) &pdu->errstat, sizeof(pdu->errstat));
- if (data == NULL)
- return -1;
- data = asn_parse_int(data, &length, &type, (long *) &pdu->errindex, sizeof(pdu->errindex));
- if (data == NULL)
- return -1;
- } else {
- pdu->enterprise_length = MAX_NAME_LEN;
- data = asn_parse_objid(data, &length, &type, objid, &pdu->enterprise_length);
- if (data == NULL)
- return -1;
- pdu->enterprise = xcalloc(1, pdu->enterprise_length * sizeof(oid));
- xmemcpy(pdu->enterprise, objid, pdu->enterprise_length * sizeof(oid));
-
- four = 4;
- data = asn_parse_string(data, &length, &type, (u_char *) & pdu->agent_addr.sin_addr.s_addr, &four);
- if (data == NULL)
- return -1;
- data = asn_parse_int(data, &length, &type, (long *) &pdu->trap_type, sizeof(pdu->trap_type));
- if (data == NULL)
- return -1;
- data = asn_parse_int(data, &length, &type, (long *) &pdu->specific_type, sizeof(pdu->specific_type));
- if (data == NULL)
- return -1;
- data = asn_parse_int(data, &length, &type, (long *) &pdu->time, sizeof(pdu->time));
- if (data == NULL)
- return -1;
- }
- data = asn_parse_header(data, &length, &type);
- if (data == NULL)
- return -1;
- if (type != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
- return -1;
- while ((int) length > 0) {
- if (pdu->variables == NULL) {
- pdu->variables = vp = xcalloc(1, sizeof(struct variable_list));
- } else {
- vp->next_variable = xcalloc(1, sizeof(struct variable_list));
- vp = vp->next_variable;
- }
- vp->next_variable = NULL;
- vp->val.string = NULL;
- vp->name = NULL;
- vp->name_length = MAX_NAME_LEN;
- data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type, &vp->val_len, &var_val, (int *) &length);
- if (data == NULL)
- return -1;
- op = xcalloc(1, (unsigned) vp->name_length * sizeof(oid));
- xmemcpy(op, objid, vp->name_length * sizeof(oid));
- vp->name = op;
-
- len = PACKET_LENGTH;
- switch ((short) vp->type) {
- case ASN_INTEGER:
- vp->val.integer = xcalloc(1, sizeof(long));
- vp->val_len = sizeof(long);
- asn_parse_int(var_val, &len, &vp->type, (long *) vp->val.integer, sizeof(vp->val.integer));
- break;
- case COUNTER:
- case GAUGE:
- case TIMETICKS:
- case UINTEGER:
- vp->val.integer = xcalloc(1, sizeof(unsigned long));
- vp->val_len = sizeof(unsigned long);
- asn_parse_unsigned_int(var_val, &len, &vp->type, (unsigned long *) vp->val.integer, sizeof(vp->val.integer));
- break;
- case COUNTER64:
- vp->val.counter64 = xcalloc(1, sizeof(struct counter64));
- vp->val_len = sizeof(struct counter64);
- asn_parse_unsigned_int64(var_val, &len, &vp->type,
- (struct counter64 *) vp->val.counter64,
- sizeof(*vp->val.counter64));
- break;
- case ASN_OCTET_STR:
- case IPADDRESS:
- case OPAQUE:
- case NSAP:
- vp->val.string = xcalloc(1, (unsigned) vp->val_len);
- asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
- break;
- case ASN_OBJECT_ID:
- vp->val_len = MAX_NAME_LEN;
- asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
- vp->val_len *= sizeof(oid);
- vp->val.objid = xcalloc(1, (unsigned) vp->val_len);
- xmemcpy(vp->val.objid, objid, vp->val_len);
- break;
- case SNMP_NOSUCHOBJECT:
- case SNMP_NOSUCHINSTANCE:
- case SNMP_ENDOFMIBVIEW:
- case ASN_NULL:
- break;
- default:
-#if NO_PRINTFS
- fprintf(stderr, "bad type returned (%x)\n", vp->type);
-#endif
- break;
- }
- }
- return ret;
+ strcpy((char *)bufp, (char *)Community);
+ return(bufp);
}
/*
* On any error, 0 is returned.
* The pdu is freed by snmp_send() unless a failure occured.
*/
-int
-snmp_send(struct snmp_session *session, struct snmp_pdu *pdu)
+int snmp_send(struct snmp_session *session, struct snmp_pdu *pdu)
{
struct session_list *slp;
struct snmp_internal_session *isp = NULL;
- u_char packet[PACKET_LENGTH];
+ u_char packet[PACKET_LENGTH];
int length = PACKET_LENGTH;
struct request_list *rp;
struct timeval tv;
- for (slp = Sessions; slp; slp = slp->next) {
- if (slp->session == session) {
+ if (Reqid == 0)
+ init_snmp();
+
+ for(slp = Sessions; slp; slp = slp->next){
+ if (slp->session == session){
isp = slp->internal;
break;
}
}
-
- if (!pdu) {
- snmp_errno = SNMPERR_GENERR;
- return 0;
- }
- if (isp == NULL) {
+ if (isp == NULL){
snmp_errno = SNMPERR_BAD_SESSION;
return 0;
}
- if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
- || pdu->command == GET_RSP_MSG || pdu->command == SET_REQ_MSG
- || pdu->command == GETBULK_REQ_MSG) {
- if (pdu->reqid == SNMP_DEFAULT_REQID)
- pdu->reqid = ++Reqid;
- if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
- pdu->errstat = 0;
- if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
- pdu->errindex = 0;
+
+ if (pdu->command == SNMP_PDU_GET ||
+ pdu->command == SNMP_PDU_GETNEXT ||
+ pdu->command == SNMP_PDU_RESPONSE ||
+ pdu->command == SNMP_PDU_SET) {
+
+ if (pdu->reqid == SNMP_DEFAULT_REQID)
+ pdu->reqid = ++Reqid;
+ if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
+ pdu->errstat = 0;
+ if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
+ pdu->errindex = 0;
+
+ } else if (pdu->command == SNMP_PDU_INFORM ||
+ pdu->command == SNMP_PDU_GETBULK ||
+ pdu->command == SNMP_PDU_V2TRAP) {
+
+ if (session->Version != SNMP_VERSION_2){
+ snmplib_debug(3, "Cant send SNMPv2 PDU's in SNMP message.\n");
+ snmp_errno = SNMPERR_GENERR;/* Fix this XXXXX */
+ return 0;
+ }
+ if (pdu->reqid == SNMP_DEFAULT_REQID)
+ pdu->reqid = ++Reqid;
+ if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
+ pdu->errstat = 0;
+ if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
+ pdu->errindex = 0;
+
} else {
/* fill in trap defaults */
- pdu->reqid = 1; /* give a bogus non-error reqid for traps */
- if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
- pdu->enterprise = xcalloc(1, sizeof(DEFAULT_ENTERPRISE));
- xmemcpy(pdu->enterprise, DEFAULT_ENTERPRISE, sizeof(DEFAULT_ENTERPRISE));
- pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE) / sizeof(oid);
- }
- if (pdu->time == SNMP_DEFAULT_TIME)
- pdu->time = DEFAULT_TIME;
+ pdu->reqid = 1; /* give a bogus non-error reqid for traps */
+ if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
+ pdu->enterprise = (oid *)xmalloc(sizeof(DEFAULT_ENTERPRISE));
+ xmemcpy((char *)pdu->enterprise, (char *)DEFAULT_ENTERPRISE,
+ sizeof(DEFAULT_ENTERPRISE));
+ pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
+ }
+ if (pdu->time == SNMP_DEFAULT_TIME)
+ pdu->time = DEFAULT_TIME;
}
+
if (pdu->address.sin_addr.s_addr == SNMP_DEFAULT_ADDRESS) {
- if (isp->addr.sin_addr.s_addr != SNMP_DEFAULT_ADDRESS) {
- xmemcpy(&pdu->address, &isp->addr, sizeof(pdu->address));
- } else {
-#if NO_PRINTFS
- fprintf(stderr, "No remote IP address specified\n");
-#endif
- snmp_errno = SNMPERR_BAD_ADDRESS;
- return 0;
- }
- }
- if (snmp_build(session, pdu, packet, &length, 0) < 0) {
-#if NO_PRINTFS
- fprintf(stderr, "Error building packet\n");
-#endif
- snmp_errno = SNMPERR_GENERR;
+ if (isp->addr.sin_addr.s_addr != SNMP_DEFAULT_ADDRESS) {
+ xmemcpy((char *)&pdu->address, (char *)&isp->addr,
+ sizeof(pdu->address));
+ } else {
+ snmplib_debug(3, "No remote IP address specified\n");
+ snmp_errno = SNMPERR_BAD_ADDRESS;
return 0;
+ }
}
- if (snmp_dump_packet) {
- snmp_print_packet((char *)packet, length, pdu->address, 1);
+
+ if (snmp_build(session, pdu, packet, &length) < 0) {
+ snmplib_debug(3, "Error building packet\n");
+ snmp_errno = SNMPERR_GENERR;
+ return 0;
}
- gettimeofday(&tv, (struct timezone *) 0);
- if (sendto(isp->sd, (char *) packet, length, 0, (struct sockaddr *) &pdu->address, sizeof(pdu->address)) < 0) {
- perror("sendto");
- snmp_errno = SNMPERR_GENERR;
- return 0;
- }
- if (pdu->command == GET_REQ_MSG || pdu->command == GETNEXT_REQ_MSG
- || pdu->command == SET_REQ_MSG || pdu->command == GETBULK_REQ_MSG) {
- /* set up to expect a response */
- rp = xcalloc(1, sizeof(struct request_list));
-
-#if NOT_NEEDED
- if (!rp) {
- fprintf(stderr, "Out of memory!\n");
- snmp_errno = SNMPERR_GENERR;
- return 0;
- }
-#endif
- rp->next_request = isp->requests;
- isp->requests = rp;
- rp->pdu = pdu;
- rp->request_id = pdu->reqid;
-
- rp->retries = 1;
- rp->timeout = session->timeout;
- rp->time = tv;
- tv.tv_usec += rp->timeout;
- tv.tv_sec += tv.tv_usec / 1000000L;
- tv.tv_usec %= 1000000L;
- rp->expire = tv;
-#if DEBUG_SNMPTRACE
- snmp_print_trace(slp, rp, TRACE_SEND);
-#endif
+
+ snmp_dump(packet, length, "sending", pdu->address.sin_addr);
+
+ gettimeofday(&tv, (struct timezone *)0);
+ if (sendto(isp->sd, (char *)packet, length, 0,
+ (struct sockaddr *)&pdu->address, sizeof(pdu->address)) < 0){
+ perror("sendto");
+ snmp_errno = SNMPERR_GENERR;
+ return 0;
}
- return pdu->reqid;
-}
-/*
- * Frees the pdu and any malloc'd data associated with it.
- */
-void
-snmp_free_pdu(struct snmp_pdu *pdu)
-{
- struct variable_list *vp, *ovp;
+ snmplib_debug(6,"LIBSNMP: Sent PDU %s, Reqid %d\n",
+ snmp_pdu_type(pdu), pdu->reqid);
- if (!pdu)
- return;
+ if (pdu->command == SNMP_PDU_GET ||
+ pdu->command == SNMP_PDU_GETNEXT ||
+ pdu->command == SNMP_PDU_SET ||
+ pdu->command == SNMP_PDU_GETBULK ||
+ pdu->command == SNMP_PDU_INFORM) {
- vp = pdu->variables;
- while (vp) {
- if (vp->name) {
- xfree((char *) vp->name);
- }
- if (vp->val.string) {
- xfree((char *) vp->val.string);
- }
- ovp = vp;
- vp = vp->next_variable;
- xfree((char *) ovp);
- }
- if (pdu->enterprise) {
- xfree((char *) pdu->enterprise);
+snmplib_debug(6,"LIBSNMP: Setting up to recieve a response for reqid %d\n",
+ pdu->reqid);
+
+ /* set up to expect a response */
+ rp = (struct request_list *)xmalloc(sizeof(struct request_list));
+ rp->next_request = isp->requests;
+ isp->requests = rp;
+
+ rp->pdu = pdu;
+ rp->request_id = pdu->reqid;
+
+ rp->retries = 1;
+ rp->timeout = session->timeout;
+ rp->time = tv;
+ tv.tv_usec += rp->timeout;
+ tv.tv_sec += tv.tv_usec / 1000000L;
+ tv.tv_usec %= 1000000L;
+ rp->expire = tv;
}
- xfree((char *) pdu);
-}
+ return(pdu->reqid);
+}
/*
* Checks to see if any of the fd's set in the fdset belong to
* routine returns successfully, the pdu and it's request are deleted.
*/
void
-snmp_read(fd_set * fdset)
+snmp_read(fdset)
+ fd_set *fdset;
{
struct session_list *slp;
struct snmp_session *sp;
struct snmp_internal_session *isp;
u_char packet[PACKET_LENGTH];
- struct sockaddr_in from;
- ssize_t length;
- int fromlength;
+ struct sockaddr_in from;
+ int length, fromlength;
struct snmp_pdu *pdu;
- struct request_list *rp /**, *orp **/ ;
+ struct request_list *rp, *orp;
+ u_char *bufp;
- for (slp = Sessions; slp; slp = slp->next) {
- if (FD_ISSET(slp->internal->sd, fdset)) {
- sp = slp->session;
- isp = slp->internal;
- fromlength = sizeof(from);
- length = recvfrom(isp->sd,
- (char *) packet,
- PACKET_LENGTH,
- 0,
- (struct sockaddr *) &from,
- &fromlength);
- if (length == -1) {
- perror("recvfrom");
- return;
- }
- if (snmp_dump_packet) {
- snmp_print_packet((char *)packet, length, from, 0);
- }
- pdu = xcalloc(1, sizeof(struct snmp_pdu));
-#if NOT_NEEDED
- if (!pdu) {
- fprintf(stderr, "Out of memory!\n");
- snmp_errno = SNMPERR_GENERR;
- return;
- }
-#endif
- pdu->address = from;
- pdu->reqid = 0;
- pdu->variables = NULL;
- pdu->enterprise = NULL;
- pdu->enterprise_length = 0;
- if (snmp_parse(sp, pdu, packet, length) < 0) {
-#if NO_PRINTFS
- fprintf(stderr, "Mangled packet\n");
-#endif
- snmp_free_pdu(pdu);
- return;
- }
- if (pdu->command == GET_RSP_MSG || pdu->command == REPORT_MSG) {
-
- struct request_list *rp_next = 0;
- for (rp = isp->requests; rp; rp = rp_next) {
- rp_next = rp->next_request;
- if (rp->request_id == pdu->reqid) {
-#if DEBUG_SNMPTRACE
- snmp_print_trace(slp, rp, TRACE_RECV);
-#endif
- if (sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic) == 1) {
- /* successful, so delete request */
- free_one_request(isp, rp);
- break; /* no more request with the same reqid */
- }
+ for(slp = Sessions; slp; slp = slp->next) {
+ if (FD_ISSET(slp->internal->sd, fdset)) {
+ sp = slp->session;
+ isp = slp->internal;
+ fromlength = sizeof from;
+ length = recvfrom(isp->sd, (char *)packet,
+ PACKET_LENGTH, 0, (struct sockaddr *)&from,
+ &fromlength);
+ if (length == -1)
+ perror("recvfrom");
+
+ snmp_dump(packet, length, "received", from.sin_addr);
+
+ pdu = snmp_pdu_create(0);
+ pdu->address = from;
+ pdu->reqid = 0;
+
+ /* Parse the incoming packet */
+ bufp = snmp_parse(sp, pdu, packet, length);
+ if (bufp == NULL) {
+ snmplib_debug(3, "Mangled packet\n");
+ snmp_free_pdu(pdu);
+ return;
+ }
+ if (sp->community)
+ xfree(sp->community);
+ sp->community = bufp;
+ sp->community_len = strlen((char *)bufp);
+
+snmplib_debug(6,"LIBSNMP: Read PDU %s, ReqId %d\n", snmp_pdu_type(pdu), pdu->reqid);
+
+ if (pdu->command == SNMP_PDU_RESPONSE) {
+ for(rp = isp->requests; rp; rp = rp->next_request) {
+ if (rp->request_id == pdu->reqid) {
+snmplib_debug(6,"LIBSNMP: ReqId %d: Calling callback\n", pdu->reqid);
+ if (sp->callback(RECEIVED_MESSAGE, sp,
+ pdu->reqid, pdu,
+ sp->callback_magic) == 1) {
+ /* successful, so delete request */
+snmplib_debug(6,"LIBSNMP: ReqId %d: Success. Removing ReqId.\n", pdu->reqid);
+ orp = rp;
+ if (isp->requests == orp){
+ /* first in list */
+ isp->requests = orp->next_request;
+ } else {
+ for(rp = isp->requests; rp; rp = rp->next_request){
+ if (rp->next_request == orp){
+ /* link around it */
+ rp->next_request = orp->next_request;
+ break;
}
+ }
}
- } else if (pdu->command == GET_REQ_MSG
- || pdu->command == GETNEXT_REQ_MSG
- || pdu->command == GETBULK_REQ_MSG
- || pdu->command == TRP_REQ_MSG || pdu->command == SET_REQ_MSG) {
-#if DEBUG_SNMPTRACE
- snmp_print_trace(slp, NULL, TRACE_RECV);
-#endif
- sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu, sp->callback_magic);
+ snmp_free_pdu(orp->pdu);
+ xfree((char *)orp);
+ /* there shouldn't be another req with the same reqid */
+ break;
+ }
}
- snmp_free_pdu(pdu);
+ }
+ } else if (pdu->command == SNMP_PDU_GET ||
+ pdu->command == SNMP_PDU_GETNEXT ||
+ pdu->command == TRP_REQ_MSG ||
+ pdu->command == SNMP_PDU_SET ||
+ pdu->command == SNMP_PDU_GETBULK ||
+ pdu->command == SNMP_PDU_INFORM ||
+ pdu->command == SNMP_PDU_V2TRAP) {
+ sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid,
+ pdu, sp->callback_magic);
}
+ snmp_free_pdu(pdu);
+ }
}
}
* If a timeout is received, snmp_timeout should be called to check if the
* timeout was for SNMP. (snmp_timeout is idempotent)
*
- * Block is 1 if the select is requested to block indefinitely, rather
- * than time out. If block is input as 1, the timeout value will be
- * treated as undefined, but it must be available for setting in
- * snmp_select_info. On return, if block is true, the value of
- * timeout will be undefined.
+ * Block is 1 if the select is requested to block indefinitely, rather than time out.
+ * If block is input as 1, the timeout value will be treated as undefined, but it must
+ * be available for setting in snmp_select_info. On return, if block is true, the value
+ * of timeout will be undefined.
*
- * snmp_select_info returns the number of open sockets. (i.e. The
- * number of sessions open)
+ * snmp_select_info returns the number of open sockets. (i.e. The number of sessions open)
*/
int
-snmp_select_info(
- int *numfds,
- fd_set * fdset,
- struct timeval *timeout,
- int *block)
-{ /* should the select block until input arrives (i.e. no input) */
+snmp_select_info(numfds, fdset, timeout, block)
+ int *numfds;
+ fd_set *fdset;
+ struct timeval *timeout;
+ int *block; /* should the select block until input arrives (i.e. no input) */
+{
struct session_list *slp;
struct snmp_internal_session *isp;
struct request_list *rp;
* For each request outstanding, add it's socket to the fdset,
* and if it is the earliest timeout to expire, mark it as lowest.
*/
- for (slp = Sessions; slp; slp = slp->next) {
+ for(slp = Sessions; slp; slp = slp->next){
+
active++;
isp = slp->internal;
if ((isp->sd + 1) > *numfds)
*numfds = (isp->sd + 1);
FD_SET(isp->sd, fdset);
- if (isp->requests) {
+ snmplib_debug(6,"LIBSNMP: select(): Adding port %d\n", isp->sd);
+ if (isp->requests){
/* found another session with outstanding requests */
requests++;
- for (rp = isp->requests; rp; rp = rp->next_request) {
- if (!timerisset(&earliest) || timercmp(&rp->expire, &earliest, <))
+ for(rp = isp->requests; rp; rp = rp->next_request){
+ if (!timerisset(&earliest) ||
+ timercmp(&rp->expire, &earliest, <))
earliest = rp->expire;
}
}
}
- if (requests == 0) /* if none are active, skip arithmetic */
+ snmplib_debug(6,"LIBSNMP: Select Info: %d active, %d requests pending.\n",
+ active, requests);
+
+ if (requests == 0) /* if none are active, skip arithmetic */
return active;
/*
* transforms earliest from an absolute time into a delta time, the
* time left until the select should timeout.
*/
- gettimeofday(&now, (struct timezone *) 0);
- earliest.tv_sec--; /* adjust time to make arithmetic easier */
+ gettimeofday(&now, (struct timezone *)0);
+ earliest.tv_sec--; /* adjust time to make arithmetic easier */
earliest.tv_usec += 1000000L;
earliest.tv_sec -= now.tv_sec;
earliest.tv_usec -= now.tv_usec;
- while (earliest.tv_usec >= 1000000L) {
+ while (earliest.tv_usec >= 1000000L){
earliest.tv_usec -= 1000000L;
earliest.tv_sec += 1;
}
- if (earliest.tv_sec < 0) {
+ if (earliest.tv_sec < 0){
earliest.tv_sec = 0;
earliest.tv_usec = 0;
}
+
/* if it was blocking before or our delta time is less, reset timeout */
- if (*block == 1 || timercmp(&earliest, timeout, <)) {
+ if (*block == 1 || timercmp(&earliest, timeout, <)){
*timeout = earliest;
*block = 0;
}
return active;
}
-/*
- * snmp_timeout should be called whenever the timeout from
- * snmp_select_info expires, but it is idempotent, so snmp_timeout can
- * be polled (probably a cpu expensive proposition). snmp_timeout
- * checks to see if any of the sessions have an outstanding request
- * that has timed out. If it finds one (or more), and that pdu has
- * more retries available, a new packet is formed from the pdu and is
- * resent. If there are no more retries available, the callback for
- * the session is used to alert the user of the timeout.
+/*
+ * snmp_timeout should be called whenever the timeout from snmp_select_info
+ * expires, but it is idempotent, so snmp_timeout can be polled (probably a
+ * cpu expensive proposition). snmp_timeout checks to see if any of the
+ * sessions have an outstanding request that has timed out. If it finds one
+ * (or more), and that pdu has more retries available, a new packet is formed
+ * from the pdu and is resent. If there are no more retries available, the
+ * callback for the session is used to alert the user of the timeout.
*/
-void
-snmp_timeout(void)
+void snmp_timeout(void)
{
- struct session_list *slp;
- struct snmp_session *sp;
- struct snmp_internal_session *isp;
- struct request_list *rp, *rp_next = 0;
- struct timeval now;
-
- gettimeofday(&now, (struct timezone *) 0);
- /*
- * For each request outstanding, check to see if it has expired.
- */
- for (slp = Sessions; slp; slp = slp->next) {
- sp = slp->session;
- isp = slp->internal;
- for (rp = isp->requests; rp; rp = rp_next) {
- rp_next = rp->next_request;
- if (timercmp(&rp->expire, &now, <)) {
- /* this timer has expired */
- if (rp->retries >= sp->retries) {
-#if DEBUG_SNMPTRACE
- snmp_print_trace(slp, rp, TRACE_TIMEOUT);
-#endif
- /* No more chances, delete this entry */
- sp->callback(TIMED_OUT, sp, rp->pdu->reqid, rp->pdu, sp->callback_magic);
- free_one_request(isp, rp);
- continue;
- } else {
- u_char packet[PACKET_LENGTH];
+ struct session_list *slp;
+ struct snmp_session *sp;
+ struct snmp_internal_session *isp;
+ struct request_list *rp, *orp, *freeme = NULL;
+ struct timeval now;
+
+ gettimeofday(&now, (struct timezone *)0);
+
+ /*
+ * For each request outstanding, check to see if it has expired.
+ */
+ for(slp = Sessions; slp; slp = slp->next) {
+ sp = slp->session;
+ isp = slp->internal;
+ orp = NULL;
+snmplib_debug(6,"LIBSNMP: Checking session %s\n",
+ (sp->peername != NULL) ? sp->peername : "<NULL>");
+ for(rp = isp->requests; rp; rp = rp->next_request) {
+snmplib_debug(6,"LIBSNMP: Checking session request %d, expire at %u, Retry %d/%d\n",
+ rp->request_id, rp->expire.tv_sec, rp->retries, sp->retries);
+
+ if (freeme != NULL) {
+ /* frees rp's after the for loop goes on to the next_request */
+ xfree((char *)freeme);
+ freeme = NULL;
+ }
+
+ if (timercmp(&rp->expire, &now, <)) {
+
+snmplib_debug(6,"LIBSNMP: Expired.\n");
+
+ /* this timer has expired */
+ if (rp->retries >= sp->retries) {
+ /* No more chances, delete this entry */
+ sp->callback(TIMED_OUT, sp, rp->pdu->reqid,
+ rp->pdu, sp->callback_magic);
+ if (orp == NULL) {
+ isp->requests = rp->next_request;
+ } else {
+ orp->next_request = rp->next_request;
+ }
+ snmp_free_pdu(rp->pdu);
+ freeme = rp;
+ continue; /* don't update orp below */
+ } else {
+ u_char packet[PACKET_LENGTH];
int length = PACKET_LENGTH;
struct timeval tv;
+snmplib_debug(6,"LIBSNMP: Retransmitting.\n");
/* retransmit this pdu */
rp->retries++;
rp->timeout <<= 1;
- if (snmp_build(sp, rp->pdu, packet, &length, 0) < 0) {
-#if NO_PRINTFS
- fprintf(stderr, "Error building packet\n");
-#endif
+ if (snmp_build(sp, rp->pdu, packet, &length) < 0){
+ snmplib_debug(3, "Error building packet\n");
}
- if (snmp_dump_packet) {
- snmp_print_packet((char *)packet, length, rp->pdu->address, 1);
- }
- gettimeofday(&tv, (struct timezone *) 0);
- if (sendto(isp->sd, (char *) packet, length, 0, (struct sockaddr *) &rp->pdu->address, sizeof(rp->pdu->address)) < 0) {
+
+ snmp_dump(packet, length,
+ "sending", rp->pdu->address.sin_addr);
+
+ gettimeofday(&tv, (struct timezone *)0);
+ if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&rp->pdu->address, sizeof(rp->pdu->address)) < 0){
perror("sendto");
}
rp->time = tv;
tv.tv_sec += tv.tv_usec / 1000000L;
tv.tv_usec %= 1000000L;
rp->expire = tv;
-#if DEBUG_SNMPTRACE
- snmp_print_trace(slp, rp, TRACE_SEND);
-#endif
}
}
+ orp = rp;
+ }
+ if (freeme != NULL){
+ xfree((char *)freeme);
+ freeme = NULL;
+ }
+ }
+}
+
+
+/* Print some API stats */
+void snmp_api_stats(void *outP)
+{
+ struct session_list *slp;
+ struct request_list *rp;
+ struct snmp_internal_session *isp;
+ FILE *out = (FILE *)outP;
+
+ int active = 0;
+ int requests = 0;
+ int count = 0;
+ int rcount = 0;
+
+ fprintf(out, "LIBSNMP: Session List Dump\n");
+ fprintf(out, "LIBSNMP: ----------------------------------------\n");
+ for(slp = Sessions; slp; slp = slp->next){
+
+ isp = slp->internal;
+ active++;
+ count++;
+ fprintf(out, "LIBSNMP: %2d: Host %s\n", count,
+ (slp->session->peername == NULL) ? "NULL" : slp->session->peername);
+
+ if (isp->requests) {
+ /* found another session with outstanding requests */
+ requests++;
+ rcount=0;
+ for (rp=isp->requests; rp; rp=rp->next_request) {
+ rcount++;
+ {
+ struct hostent *hp;
+ hp = gethostbyaddr((char *)&(rp->pdu->address),
+ sizeof(u_int), AF_INET);
+ fprintf(out, "LIBSNMP: %2d: ReqId %d (%s) (%s)\n",
+ rcount, rp->request_id, snmp_pdu_type(rp->pdu),
+ (hp == NULL) ? "NULL" : hp->h_name);
}
+ }
}
+ fprintf(out, "LIBSNMP: ----------------------------------------\n");
+ }
+ fprintf(out, "LIBSNMP: Session List: %d active, %d have requests pending.\n",
+ active, requests);
}
--- /dev/null
+/*
+ * Error routines concerning the error status of the SNMP API.
+ *
+ * Sometimes things don't work out the way we wanted.
+ *
+ */
+/***************************************************************************
+ *
+ * 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>
+ *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include "snmp_api_error.h"
+
+
+/***************************************************************************
+ *
+ ***************************************************************************/
+
+int snmp_errno = 0;
+
+static char *api_errors[17] = {
+ "Unknown Error",
+ "Generic Error",
+ "Invalid local port",
+ "Unknown host",
+ "Unknown session",
+ "Too Long",
+
+ "Encoding ASN.1 Information", /* 6 */
+ "Decoding ASN.1 Information", /* 7 */
+ "PDU Translation error",
+ "OS Error",
+ "Invalid Textual OID",
+
+ "Unable to fix PDU",
+ "Unsupported SNMP Type",
+ "Unable to parse PDU",
+ "Packet Error",
+ "No Response From Host",
+
+
+ "Unknown Error"
+};
+
+void snmp_set_api_error(int x)
+{
+ snmp_errno = x;
+}
+
+char *snmp_api_error(int err)
+{
+ int foo = (err * -1);
+ if ((foo < SNMPERR_GENERR) ||
+ (foo > SNMPERR_LAST))
+ foo=0;
+
+ return(api_errors[foo]);
+}
+
+int snmp_api_errno(void)
+{
+ return(snmp_errno);
+}
+
+char *api_errstring(int snmp_errnumber)
+{
+ return(snmp_api_error(snmp_errnumber));
+}
--- /dev/null
+/*
+ * The possible SNMP Error messages, from the SNMP Protocol Operations
+ * [ RFC 1905 ]
+ */
+/**********************************************************************
+ *
+ * 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.
+ *
+ **********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "snmp_error.h"
+
+
+static char *error_string[19] = {
+ "No Error",
+ "Response message would have been too large.",
+ "There is no such variable name in this MIB.",
+ "The value given has the wrong type, length, or value",
+ "This variable is read only",
+ "A general failure occured",
+
+ /* SNMPv2 Errors */
+ "NOACCESS",
+ "WRONGTYPE",
+ "WRONGLENGTH",
+ "WRONGENCODING",
+ "WRONGVALUE",
+ "NOCREATION",
+ "INCONSISTENTVALUE",
+ "RESOURCEUNAVAILABLE",
+ "COMMITFAILED",
+ "UNDOFAILED",
+ "AUTHORIZATIONERROR",
+ "NOTWRITABLE",
+ "INCONSISTENTNAME",
+
+};
+
+char *snmp_errstring(int errstat)
+{
+ if ((errstat <= (SNMP_ERR_INCONSISTENTNAME)) &&
+ (errstat >= (SNMP_ERR_NOERROR))) {
+ return error_string[errstat];
+ } else {
+ return "Unknown Error";
+ }
+}
--- /dev/null
+/*
+ * SNMP Message Encoding Routines
+ *
+ * Complies with:
+ *
+ * RFC 1901: Introduction to Community-based SNMPv2
+ * RFC 1157: A Simple Network Management Protocol (SNMP)
+ *
+ */
+/**********************************************************************
+ *
+ * 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"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+#include "mibii.h"
+
+
+/*
+ * RFC 1901: Introduction to Community-based SNMPv2
+ *
+ * Message ::=
+ * SEQUENCE {
+ * version INTEGER
+ * community OCTET STRING
+ * data
+ * }
+ *
+ * RFC 1157: A Simple Network Management Protocol (SNMP)
+ *
+ * Message ::=
+ * SEQUENCE {
+ * version INTEGER
+ * community OCTET STRING
+ * data
+ * }
+ *
+ */
+
+/* Encode a SNMP Message Header. Return a pointer to the beginning of the
+ * data.
+ */
+
+#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
+
+/* Encode an SNMP Message
+ *
+ * Returns a pointer to the end of the message, or NULL.
+ *
+ * *BufLenP (Second Argument) will contain the amount of space left
+ * in the buffer.
+ */
+
+u_char *snmp_msg_Encode(u_char *Buffer, int *BufLenP,
+ u_char *Community, int CommLen,
+ int Version,
+ struct snmp_pdu *PDU)
+{
+ u_char *bufp, *tmp;
+ u_char *PDUHeaderPtr, *VARHeaderPtr;
+ u_char *PDUDataStart, *VARDataStart;
+ u_char *MsgPtr;
+ int FakeArg = 1024;
+
+ /* Header for the entire thing, with a false, large length */
+ bufp = asn_build_header(Buffer, BufLenP,
+ (u_char)(ASN_SEQUENCE |
+ ASN_CONSTRUCTOR),
+ (*BufLenP));
+ if (bufp == NULL) {
+ snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n");
+ return(NULL);
+ }
+ MsgPtr = bufp;
+
+ /* Version */
+ bufp = asn_build_int(bufp, BufLenP,
+ (u_char)(ASN_UNIVERSAL |
+ ASN_PRIMITIVE |
+ ASN_INTEGER),
+ (int *)(&Version), sizeof(Version));
+ if (bufp == NULL){
+ snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n");
+ return(NULL);
+ }
+
+ snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen);
+
+ /* Community */
+ bufp = asn_build_string(bufp, BufLenP,
+ (u_char)(ASN_UNIVERSAL |
+ ASN_PRIMITIVE |
+ ASN_OCTET_STR),
+ Community, CommLen);
+ if (bufp == NULL){
+ snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n");
+ return(NULL);
+ }
+
+ /* Encode the rest. */
+
+ /* A nice header for this PDU.
+ * Encoded with the wrong length. We'll fix it later.
+ */
+ snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%x (fake len %d) (%d bytes so far)\n",
+ bufp, *BufLenP, *BufLenP);
+ PDUHeaderPtr = bufp;
+ bufp = asn_build_header(bufp, BufLenP,
+ (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+ (*BufLenP));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* Encode this PDU. */
+ PDUDataStart = bufp;
+ bufp = snmp_pdu_encode(bufp, BufLenP, PDU);
+ if (bufp == NULL)
+ return(NULL); /* snmp_pdu_encode registered failure */
+
+ VARHeaderPtr = bufp;
+ bufp = asn_build_header(bufp, BufLenP,
+ (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+ FakeArg);
+ if (bufp == NULL)
+ return(NULL);
+ VARDataStart = bufp;
+
+ /* And build the variables */
+ bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version);
+ if (bufp == NULL)
+ return(NULL); /* snmp_var_EncodeVarBind registered failure */
+
+ /* Cool. Now insert the appropriate lengths.
+ */
+#ifdef DEBUG_MSG_ENCODE
+ snmplib_debug(9, "Msg: Vars returned 0x%x. PDU Started at 0x%x\n",
+ bufp, PDUHeaderPtr);
+ snmplib_debug(9, "MSG: Entire PDU length is %d (0x%x - 0x%x)\n",
+ (int)(bufp - PDUDataStart), PDUHeaderPtr, bufp);
+#endif
+ tmp = asn_build_header(PDUHeaderPtr, &FakeArg,
+ (u_char)PDU->command,
+ (int)(bufp - PDUDataStart));
+ /* Length of the PDU and Vars */
+ if (tmp == NULL)
+ return(NULL);
+
+#ifdef DEBUG_MSG_ENCODE
+ snmplib_debug(9, "MSG: Entire message length is %d (0x%x - 0x%x)\n",
+ (int)(bufp - MsgPtr), MsgPtr, bufp);
+#endif
+ tmp = asn_build_header(Buffer,
+ &FakeArg,
+ (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+ (bufp - MsgPtr)); /* Length of everything */
+ if (tmp == NULL)
+ return(NULL);
+
+ tmp = asn_build_header(VARHeaderPtr,
+ &FakeArg,
+ (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+ (bufp - VARDataStart)); /* Length of everything */
+ if (tmp == NULL)
+ return(NULL);
+
+ *BufLenP = (bufp - Buffer);
+ return (u_char *)bufp;
+}
+
+/**********************************************************************/
+
+u_char *snmp_msg_Decode(u_char *Packet, int *PacketLenP,
+ u_char *Community, int *CommLenP,
+ int *Version, struct snmp_pdu *PDU)
+{
+ u_char *bufp;
+ u_char type;
+
+ bufp = asn_parse_header(Packet, PacketLenP, &type);
+ if (bufp == NULL){
+ snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
+ ASN_PARSE_ERROR(NULL);
+ }
+ if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
+ snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
+ ASN_PARSE_ERROR(NULL);
+ }
+
+ bufp = asn_parse_int(bufp, PacketLenP,
+ &type,
+ (int *)Version, sizeof(*Version));
+ if (bufp == NULL){
+ snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Version)!\n");
+ ASN_PARSE_ERROR(NULL);
+ }
+ bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
+ if (bufp == NULL){
+ snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Community)!\n");
+ ASN_PARSE_ERROR(NULL);
+ }
+ Community[*CommLenP] = '\0';
+
+ if ((*Version != SNMP_VERSION_1) &&
+ (*Version != SNMP_VERSION_2)) {
+
+ /* Don't know how to handle this one. */
+ snmpInBadVersions_Add(1);
+ snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
+ snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
+ }
+
+ /* Now that we know the header, decode the PDU */
+
+ /* XXXXX -- More than one PDU? */
+ bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
+ if (bufp == NULL)
+ /* snmp_pdu_decode registered failure */
+ return(NULL);
+
+ bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
+ if (bufp == NULL)
+ /* snmp_var_DecodeVarBind registered failure */
+ return(NULL);
+
+ return (u_char *)bufp;
+}
--- /dev/null
+/*
+ * SNMP PDU Encoding
+ *
+ * Complies with:
+ *
+ * RFC 1902: Structure of Management Information 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_error.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+#include "mibii.h"
+#include "snmp_api_error.h"
+
+#include "util.h"
+
+/* #define DEBUG_PDU 1 */
+/* #define DEBUG_PDU_DECODE 1 */
+/* #define DEBUG_PDU_ENCODE 1 */
+
+#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
+
+/**********************************************************************/
+
+/* Create a PDU.
+ */
+
+struct snmp_pdu *snmp_pdu_create(int command)
+{
+ struct snmp_pdu *pdu;
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU: Creating\n");
+#endif
+
+ pdu = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
+ if (pdu == NULL) {
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ memset((char *)pdu, '\0', sizeof(struct snmp_pdu));
+
+ pdu->command = command;
+ pdu->errstat = SNMP_DEFAULT_ERRSTAT;
+ pdu->errindex = SNMP_DEFAULT_ERRINDEX;
+ pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
+ pdu->enterprise = NULL;
+ pdu->enterprise_length = 0;
+ pdu->variables = NULL;
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU: Created %x\n", (unsigned int)pdu);
+#endif
+
+ return(pdu);
+}
+
+/**********************************************************************/
+
+/* Clone an existing PDU.
+ */
+struct snmp_pdu *snmp_pdu_clone(struct snmp_pdu *Src)
+{
+ struct snmp_pdu *Dest;
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU %x: Cloning\n", (unsigned int)Src);
+#endif
+
+ Dest = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
+ if (Dest == NULL) {
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+ xmemcpy((char *)Dest, (char *)Src, sizeof(struct snmp_pdu));
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU %x: Created %x\n", (unsigned int)Src, (unsigned int)Dest);
+#endif
+ return(Dest);
+}
+
+/**********************************************************************/
+
+/*
+ * If there was an error in the input pdu, creates a clone of the pdu
+ * that includes all the variables except the one marked by the errindex.
+ * The command is set to the input command and the reqid, errstat, and
+ * errindex are set to default values.
+ * If the error status didn't indicate an error, the error index didn't
+ * indicate a variable, the pdu wasn't a get response message, or there
+ * would be no remaining variables, this function will return NULL.
+ * If everything was successful, a pointer to the fixed cloned pdu will
+ * be returned.
+ */
+struct snmp_pdu *snmp_pdu_fix(struct snmp_pdu *pdu, int command)
+{
+ return(snmp_fix_pdu(pdu, command));
+}
+
+struct snmp_pdu *snmp_fix_pdu(struct snmp_pdu *pdu, int command)
+{
+ struct variable_list *var, *newvar;
+ struct snmp_pdu *newpdu;
+ int index;
+ int copied = 0;
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU %x: Fixing. Err index is %d\n",
+ (unsigned int)pdu, (unsigned int)pdu->errindex);
+#endif
+
+ if (pdu->command != SNMP_PDU_RESPONSE ||
+ pdu->errstat == SNMP_ERR_NOERROR ||
+ pdu->errindex <= 0) {
+ snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
+ return(NULL);
+ }
+
+ /* clone the pdu */
+ newpdu = snmp_pdu_clone(pdu);
+ if (newpdu == NULL)
+ return(NULL);
+
+ newpdu->variables = 0;
+ newpdu->command = command;
+ newpdu->reqid = SNMP_DEFAULT_REQID;
+ newpdu->errstat = SNMP_DEFAULT_ERRSTAT;
+ newpdu->errindex = SNMP_DEFAULT_ERRINDEX;
+
+ /* Loop through the variables, removing whatever isn't necessary */
+
+ var = pdu->variables;
+ index = 1;
+
+ /* skip first variable if necessary*/
+ if (pdu->errindex == index) {
+ var = var->next_variable;
+ index++;
+ }
+
+ if (var != NULL) {
+
+ /* VAR is the first uncopied variable */
+
+ /* Clone this variable */
+ newpdu->variables = snmp_var_clone(var);
+ if (newpdu->variables == NULL) {
+ snmp_pdu_free(newpdu);
+ return(NULL);
+ }
+ copied++;
+
+ newvar = newpdu->variables;
+
+ /* VAR has been copied to NEWVAR. */
+ while(var->next_variable) {
+
+ /* Skip the item that was bad */
+ if (++index == pdu->errindex) {
+ var = var->next_variable;
+ continue;
+ }
+
+ /* Copy this var */
+ newvar->next_variable = snmp_var_clone(var->next_variable);
+ if (newvar->next_variable == NULL) {
+ snmp_pdu_free(newpdu);
+ return(NULL);
+ }
+
+ /* Move to the next one */
+ newvar = newvar->next_variable;
+ var = var->next_variable;
+ copied++;
+ }
+ newvar->next_variable = NULL;
+ }
+
+ /* If we didn't copy anything, free the new pdu. */
+ if (index < pdu->errindex || copied == 0) {
+ snmp_free_pdu(newpdu);
+ snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
+ return(NULL);
+ }
+
+#ifdef DEBUG_PDU
+ snmplib_debug(8,"PDU %x: Fixed PDU is %x\n",
+ (unsigned int)pdu, (unsigned int)newpdu);
+#endif
+ return(newpdu);
+}
+
+
+/**********************************************************************/
+
+void snmp_pdu_free(struct snmp_pdu *pdu)
+{
+ snmp_free_pdu(pdu);
+}
+
+/*
+ * Frees the pdu and any xmalloc'd data associated with it.
+ */
+void snmp_free_pdu(struct snmp_pdu *pdu)
+{
+ struct variable_list *vp, *ovp;
+
+ vp = pdu->variables;
+ while(vp) {
+ ovp = vp;
+ vp = vp->next_variable;
+ snmp_var_free(ovp);
+ }
+
+ if (pdu->enterprise)
+ xfree((char *)pdu->enterprise);
+ xfree((char *)pdu);
+}
+
+/**********************************************************************/
+
+/* Encode this PDU into DestBuf.
+ *
+ * Returns a pointer to the next byte in the buffer (where the Variable
+ * Bindings belong.)
+ */
+
+/*
+ * RFC 1902: Structure of Management Information for SNMPv2
+ *
+ * PDU ::=
+ * SEQUENCE {
+ * request-id INTEGER32
+ * error-status INTEGER
+ * error-index INTEGER
+ * Variable Bindings
+ * }
+ *
+ * BulkPDU ::=
+ * SEQUENCE {
+ * request-id INTEGER32
+ * non-repeaters INTEGER
+ * max-repetitions INTEGER
+ * Variable Bindings
+ * }
+ */
+
+/*
+ * RFC 1157: A Simple Network Management Protocol (SNMP)
+ *
+ * PDU ::=
+ * SEQUENCE {
+ * request-id INTEGER
+ * error-status INTEGER
+ * error-index INTEGER
+ * Variable Bindings
+ * }
+ *
+ * TrapPDU ::=
+ * SEQUENCE {
+ * enterprise NetworkAddress
+ * generic-trap INTEGER
+ * specific-trap INTEGER
+ * time-stamp TIMETICKS
+ * Variable Bindings
+ * }
+ */
+
+u_char *snmp_pdu_encode(u_char *DestBuf, int *DestBufLen,
+ struct snmp_pdu *PDU)
+{
+ u_char *bufp;
+
+#ifdef DEBUG_PDU_ENCODE
+ snmplib_debug(8,"PDU: Encoding %d\n", PDU->command);
+#endif
+
+ /* ASN.1 Header */
+ switch (PDU->command) {
+
+ /**********************************************************************/
+
+ case TRP_REQ_MSG:
+
+ /* SNMPv1 Trap */
+
+ /* enterprise */
+ bufp = asn_build_objid(DestBuf, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+ (oid *)PDU->enterprise, PDU->enterprise_length);
+ if (bufp == NULL)
+ return(NULL);
+
+ /* agent-addr */
+ bufp = asn_build_string(bufp, DestBufLen,
+ (u_char)(SMI_IPADDRESS | ASN_PRIMITIVE),
+ (u_char *)&PDU->agent_addr.sin_addr.s_addr,
+ sizeof(PDU->agent_addr.sin_addr.s_addr));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* generic trap */
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ (int *)&PDU->trap_type, sizeof(PDU->trap_type));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* specific trap */
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ (int *)&PDU->specific_type,
+ sizeof(PDU->specific_type));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* timestamp */
+ bufp = asn_build_unsigned_int(bufp, DestBufLen,
+ (u_char)(SMI_TIMETICKS | ASN_PRIMITIVE),
+ &PDU->time, sizeof(PDU->time));
+ if (bufp == NULL)
+ return(NULL);
+ break;
+
+ /**********************************************************************/
+
+ case SNMP_PDU_GETBULK:
+
+ /* SNMPv2 Bulk Request */
+
+ /* request id */
+ bufp = asn_build_int(DestBuf, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->reqid, sizeof(PDU->reqid));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* non-repeaters */
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->non_repeaters,
+ sizeof(PDU->non_repeaters));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* max-repetitions */
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->max_repetitions,
+ sizeof(PDU->max_repetitions));
+ if (bufp == NULL)
+ return(NULL);
+ break;
+
+ /**********************************************************************/
+
+ default:
+
+ /* Normal PDU Encoding */
+
+ /* request id */
+#ifdef DEBUG_PDU_ENCODE
+ snmplib_debug(8,"PDU: Request ID %d (0x%x)\n", PDU->reqid, DestBuf);
+#endif
+ bufp = asn_build_int(DestBuf, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->reqid, sizeof(PDU->reqid));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* error status */
+#ifdef DEBUG_PDU_ENCODE
+ snmplib_debug(8,"PDU: Error Status %d (0x%x)\n", PDU->errstat, bufp);
+#endif
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->errstat, sizeof(PDU->errstat));
+ if (bufp == NULL)
+ return(NULL);
+
+ /* error index */
+#ifdef DEBUG_PDU_ENCODE
+ snmplib_debug(8,"PDU: Error index %d (0x%x)\n", PDU->errindex, bufp);
+#endif
+ bufp = asn_build_int(bufp, DestBufLen,
+ (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+ &PDU->errindex, sizeof(PDU->errindex));
+ if (bufp == NULL)
+ return(NULL);
+ break;
+ } /* End of encoding */
+
+ return(bufp);
+}
+
+/**********************************************************************/
+
+/* Decodes PDU from Packet into PDU.
+ *
+ * Returns a pointer to the next byte of the packet, which is where the
+ * Variable Bindings start.
+ */
+u_char *snmp_pdu_decode(u_char *Packet, /* data */
+ int *Length, /* &length */
+ struct snmp_pdu *PDU) /* pdu */
+{
+ u_char *bufp;
+ u_char PDUType;
+ int four;
+ u_char ASNType;
+ oid objid[MAX_NAME_LEN];
+
+ bufp = asn_parse_header(Packet, Length, &PDUType);
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+ snmplib_debug(8,"PDU Type: %d\n", PDUType);
+#endif
+
+ PDU->command = PDUType;
+ switch (PDUType) {
+
+ case TRP_REQ_MSG:
+
+ /* SNMPv1 Trap Message */
+
+ /* enterprise */
+ PDU->enterprise_length = MAX_NAME_LEN;
+ bufp = asn_parse_objid(bufp, Length,
+ &ASNType, objid, &PDU->enterprise_length);
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ PDU->enterprise = (oid *)xmalloc(PDU->enterprise_length * sizeof(oid));
+ if (PDU->enterprise == NULL) {
+ snmp_set_api_error(SNMPERR_OS_ERR);
+ return(NULL);
+ }
+
+ xmemcpy((char *)PDU->enterprise, (char *)objid,
+ PDU->enterprise_length * sizeof(oid));
+
+ /* Agent-addr */
+ four = 4;
+ bufp = asn_parse_string(bufp, Length,
+ &ASNType,
+ (u_char *)&PDU->agent_addr.sin_addr.s_addr,
+ &four);
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ /* Generic trap */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ (int *)&PDU->trap_type,
+ sizeof(PDU->trap_type));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ /* Specific Trap */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ (int *)&PDU->specific_type,
+ sizeof(PDU->specific_type));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ /* Timestamp */
+ bufp = asn_parse_unsigned_int(bufp, Length,
+ &ASNType,
+ &PDU->time, sizeof(PDU->time));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+ break;
+
+ /**********************************************************************/
+
+ case SNMP_PDU_GETBULK:
+
+ /* SNMPv2 Bulk Request */
+
+ /* request id */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->reqid, sizeof(PDU->reqid));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ /* non-repeaters */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->non_repeaters, sizeof(PDU->non_repeaters));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ /* max-repetitions */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->max_repetitions, sizeof(PDU->max_repetitions));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+ break;
+ /**********************************************************************/
+
+ default:
+
+ /* Normal PDU Encoding */
+
+ /* request id */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->reqid, sizeof(PDU->reqid));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+ snmplib_debug(8,"PDU Request ID: %d\n", PDU->reqid);
+#endif
+
+ /* error status */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->errstat, sizeof(PDU->errstat));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+ snmplib_debug(8,"PDU Error Status: %d\n", PDU->errstat);
+#endif
+
+ /* error index */
+ bufp = asn_parse_int(bufp, Length,
+ &ASNType,
+ &PDU->errindex, sizeof(PDU->errindex));
+ if (bufp == NULL)
+ ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+ snmplib_debug(8,"PDU Error Index: %d\n", PDU->errindex);
+#endif
+
+ break;
+ }
+
+ return(bufp);
+}
+
+
+char *snmp_pdu_type(struct snmp_pdu *PDU)
+{
+ switch(PDU->command) {
+ case SNMP_PDU_GET:
+ return("GET");
+ break;
+ case SNMP_PDU_GETNEXT:
+ return("GETNEXT");
+ break;
+ case SNMP_PDU_RESPONSE:
+ return("RESPONSE");
+ break;
+ case SNMP_PDU_SET:
+ return("SET");
+ break;
+ case SNMP_PDU_GETBULK:
+ return("GETBULK");
+ break;
+ case SNMP_PDU_INFORM:
+ return("INFORM");
+ break;
+ case SNMP_PDU_V2TRAP:
+ return("V2TRAP");
+ break;
+ case SNMP_PDU_REPORT:
+ return("REPORT");
+ break;
+
+ case TRP_REQ_MSG:
+ return("V1TRAP");
+ break;
+ default:
+ return("Unknown");
+ break;
+ }
+}
+
+/*
+ * Add a null variable with the requested name to the end of the list of
+ * variables for this pdu.
+ */
+void snmp_add_null_var(struct snmp_pdu *pdu, oid *name, int name_length)
+{
+ struct variable_list *vars;
+ struct variable_list *ptr;
+
+ vars = snmp_var_new(name, name_length);
+ if (vars == NULL) {
+ perror("snmp_add_null_var:xmalloc");
+ return;
+ }
+
+ if (pdu->variables == NULL) {
+ pdu->variables = vars;
+ } else {
+
+ /* Insert at the end */
+ for (ptr = pdu->variables;
+ ptr->next_variable;
+ ptr = ptr->next_variable)
+ /*EXIT*/;
+ ptr->next_variable = vars;
+ }
+
+ return;
+}
+
--- /dev/null
+/*
+ * 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"
+#include "mibii.h"
+#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) { snmpInASNParseErrs_Add(1); 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, '\0', 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));
+
+ /* New->val.string = NULL; */
+ /* New->val_len = 0; */
+
+#ifdef DEBUG_VARS
+ printf("VARS: Created %x.\n", (unsigned int)New);
+#endif
+
+#ifdef DEBUG_VARS_MALLOC
+ printf("VARS: Created (%x)\n", (unsigned int)New);
+ printf("VARS: Name is (%x)\n", (unsigned int)New->name);
+#endif
+ 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)
+{
+#ifdef DEBUG_VARS_MALLOC
+ printf("VARS: Free'd (%x)\n", (unsigned int)Ptr);
+ printf("VARS: Name was(%x)\n", (unsigned int)Ptr->name);
+#endif
+
+ if (Ptr->name && Ptr->name_length > 0)
+ xfree((char *) Ptr->name);
+
+ if (Ptr->val.string && Ptr->val_len > 0)
+ xfree((char *) Ptr->val.string);
+
+ 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,
+ struct variable_list *VarList,
+ int Version)
+{
+ struct variable_list *Vars;
+ u_char *bufp;
+ u_char *HeaderStart;
+ u_char *HeaderEnd;
+ int FakeArg = *BufLenP;
+#ifdef DEBUG_VARS_ENCODE
+ int StartLen = *BufLenP;
+ int Counter = 1;
+#endif
+
+ bufp = Buffer;
+
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS: Encoding Variable list into buffer at 0x%x.\n", Buffer);
+#endif
+
+ for (Vars=VarList; Vars; Vars=Vars->next_variable) {
+
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding Variable 0x%x.\n", Counter, Vars);
+ printf("VARS %d: Starting at 0x%x (%d bytes left)\n",
+ Counter, bufp, *BufLenP);
+#endif
+
+ /* 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);
+
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding Object Identifier 0x%x (%d bytes) at 0x%x (%d bytes left)\n",
+ Counter, Vars,
+ Vars->name_length, HeaderEnd, *BufLenP);
+ print_oid(Vars->name, Vars->name_length),
+#endif
+ /* 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:
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding Integer %d at 0x%x\n", Counter,
+ *(Vars->val.integer), bufp);
+#endif
+
+ 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:
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding Timeticks %d at 0x%x\n", Counter,
+ *(Vars->val.integer), bufp);
+#endif
+ 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:
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding String %s (%d bytes) at 0x%x\n", Counter,
+ (Vars->val.string), Vars->val_len, bufp);
+#endif
+ bufp = asn_build_string(bufp, BufLenP, Vars->type,
+ Vars->val.string, Vars->val_len);
+ break;
+
+ case ASN_OBJECT_ID:
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding Object Identifier (%d bytes) at 0x%x\n",
+ Counter,
+ Vars->val_len, bufp);
+#endif
+ 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:
+
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding NULL at 0x%x\n", Counter, bufp);
+#endif
+ 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:
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Encoding NULL at 0x%x\n", Counter, bufp);
+#endif
+ 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 */
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS %d: Resetting length to %d at 0x%x (%d bytes left)\n",
+ Counter,
+ (bufp - HeaderEnd), HeaderStart, *BufLenP);
+#endif
+ HeaderEnd = asn_build_header(HeaderStart, &FakeArg,
+ (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+ (bufp - HeaderEnd));
+
+ /* Returns NULL */
+ if (HeaderEnd == NULL)
+ return(NULL);
+
+#ifdef DEBUG_VARS_ENCODE
+ Counter++;
+#endif
+ }
+
+#ifdef DEBUG_VARS_ENCODE
+ printf("VARS: Variable list of %d vars takes up %d bytes.\n",
+ --Counter, StartLen - *BufLenP);
+#endif
+
+ /* 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 %d\n", *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 %d\n", 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 %d\n", 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);
+}