From: kostas <> Date: Sun, 22 Feb 1998 18:55:22 +0000 (+0000) Subject: Snmplib for squid, based on v1.8, heavily changed X-Git-Tag: SQUID_3_0_PRE1~4033 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85269fdf3c2a36641dfae2cf71f495a38c95cc28;p=thirdparty%2Fsquid.git Snmplib for squid, based on v1.8, heavily changed --- diff --git a/snmplib/Makefile.in b/snmplib/Makefile.in index 521598e545..acfad595a8 100644 --- a/snmplib/Makefile.in +++ b/snmplib/Makefile.in @@ -17,10 +17,17 @@ ALIB = libsnmp.a 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@ diff --git a/snmplib/asn1.c b/snmplib/asn1.c index 3fa9b06c1d..a995dc9ebe 100644 --- a/snmplib/asn1.c +++ b/snmplib/asn1.c @@ -7,60 +7,96 @@ * 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 + +#if HAVE_UNISTD_H +#include #endif #if HAVE_STDLIB_H #include #endif -#if HAVE_STRING_H -#include -#endif #if HAVE_SYS_TYPES_H #include #endif +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif #if HAVE_NETINET_IN_H #include #endif -#if HAVE_ASSERT_H -#include +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include #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. @@ -69,51 +105,65 @@ SOFTWARE. * 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. @@ -122,50 +172,64 @@ asn_parse_int( * 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 @@ -176,55 +240,63 @@ asn_parse_unsigned_int( * 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 @@ -235,65 +307,73 @@ asn_build_int( * 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 @@ -306,73 +386,79 @@ asn_build_unsigned_int( * 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); } @@ -385,35 +471,34 @@ asn_build_string( * 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); } /* @@ -429,19 +514,23 @@ asn_parse_header( * 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)); } /* @@ -457,24 +546,25 @@ asn_build_header( * 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); } /* @@ -485,73 +575,97 @@ asn_build_sequence( * 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. @@ -562,72 +676,77 @@ asn_build_length( * 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); } /* @@ -641,70 +760,73 @@ asn_parse_objid( * 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); } /* @@ -717,31 +839,31 @@ asn_build_objid( * 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 @@ -752,16 +874,15 @@ asn_parse_null( * 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)); } /* @@ -776,47 +897,51 @@ asn_build_null( * 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. @@ -828,165 +953,63 @@ asn_parse_bitstring( * 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)); } diff --git a/snmplib/coexistance.c b/snmplib/coexistance.c new file mode 100644 index 0000000000..7351cd44f4 --- /dev/null +++ b/snmplib/coexistance.c @@ -0,0 +1,252 @@ +/* + * 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 + * + **********************************************************************/ + +#include "config.h" + +#include "config.h" + +#include + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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); + } +} diff --git a/snmplib/mib.c b/snmplib/mib.c index 916eff3d69..7151bb1144 100644 --- a/snmplib/mib.c +++ b/snmplib/mib.c @@ -1,6 +1,5 @@ - -/********************************************************************** - Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University +/*********************************************************** + Copyright 1988, 1989 by Carnegie Mellon University All Rights Reserved @@ -20,8 +19,11 @@ 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 + #if HAVE_UNISTD_H #include #endif @@ -34,6 +36,14 @@ SOFTWARE. #if HAVE_CTYPE_H #include #endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif #ifdef HAVE_STRING_H #include #endif @@ -43,32 +53,43 @@ SOFTWARE. #if HAVE_BSTRING_H #include #endif - +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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); @@ -80,261 +101,249 @@ uptimeString(unsigned long timeticks, char *buf) 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)) @@ -343,364 +352,200 @@ sprint_networkaddress(char *buf, struct variable_list *var, struct enum_list *en } 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 : - * - * [...] 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; } @@ -710,88 +555,45 @@ find_rfc1213_mib(root) } 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 @@ -814,12 +616,13 @@ parse_subtree(subtree, input, output, out_len) goto found; } tp = NULL; - } else { + } + else { /* * Read the name into a buffer. */ while ((*input != '\0') && - (*input != '.')) { + (*input != '.')) { *to++ = *input++; } *to = '\0'; @@ -838,18 +641,19 @@ parse_subtree(subtree, input, output, out_len) * 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; @@ -857,174 +661,190 @@ parse_subtree(subtree, input, output, out_len) 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 @@ -1032,127 +852,73 @@ get_symbol(oid * objid, int objidlen, struct tree *subtree, char *buf) } -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 + +#if HAVE_UNISTD_H +#include #endif -#if HAVE_CTYPE_H -#include +#if HAVE_STDLIB_H +#include #endif #if HAVE_SYS_TYPES_H #include #endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_STRING_H -#include +#if HAVE_CTYPE_H +#include #endif #if HAVE_GNUMALLOC_H #include #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) #include #endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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 { @@ -62,38 +89,38 @@ 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 @@ -104,7 +131,7 @@ int Line = 1; #define MANDATORY 23 #define OPTIONAL 24 #define OBSOLETE 25 -/* #define RECOMMENDED 26 */ +#define RECOMMENDED 26 #define PUNCT 27 #define EQUALS 28 #define NUMBER 29 @@ -113,337 +140,195 @@ int Line = 1; #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; } /* @@ -451,27 +336,29 @@ build_tree(struct node *nodes) * 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 @@ -481,17 +368,17 @@ do_subtree(struct tree *root, struct node **nodes) } 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 */ } } } @@ -500,8 +387,8 @@ do_subtree(struct tree *root, struct node **nodes) /* * 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; @@ -510,21 +397,18 @@ do_subtree(struct tree *root, struct node **nodes) 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; @@ -533,6 +417,138 @@ do_subtree(struct tree *root, struct node **nodes) 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: @@ -541,38 +557,41 @@ do_subtree(struct tree *root, struct node **nodes) * 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; } @@ -585,7 +604,7 @@ getoid(FILE * fp, struct subid *oid, int length) } } else { /* this entry has just an integer sub-identifier */ - oid->subid = atoi(token); + SubOid->subid = atoi(token); } type = get_token(fp, token); } @@ -595,17 +614,18 @@ getoid(FILE * fp, struct subid *oid, int length) } 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); } /* @@ -615,32 +635,34 @@ free_node(struct node *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); @@ -649,28 +671,27 @@ parse_objectid(FILE * fp, char *name) 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) @@ -679,1083 +700,401 @@ parse_objectid(FILE * fp, char *name) 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; -} diff --git a/snmplib/snmp_api.c b/snmplib/snmp_api.c index 5407457a84..c61326d69a 100644 --- a/snmplib/snmp_api.c +++ b/snmplib/snmp_api.c @@ -1,15 +1,16 @@ -/* - * 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 @@ -18,13 +19,13 @@ * 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 + #if HAVE_UNISTD_H #include #endif @@ -63,170 +64,92 @@ #if HAVE_ARPA_INET_H #include #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 +#endif +#if HAVE_NETDB_H +#include +#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 @@ -235,547 +158,280 @@ snmp_print_trace(struct session_list *slp, struct request_list *rp, int code) * 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); } /* @@ -787,138 +443,128 @@ snmp_parse( * 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 @@ -928,83 +574,91 @@ snmp_free_pdu(struct snmp_pdu *pdu) * 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); + } } } @@ -1021,22 +675,20 @@ snmp_read(fd_set * fdset) * 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; @@ -1048,22 +700,28 @@ snmp_select_info( * 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; /* @@ -1071,83 +729,101 @@ snmp_select_info( * 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 : ""); + 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; @@ -1155,11 +831,59 @@ snmp_timeout(void) 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); } diff --git a/snmplib/snmp_api_error.c b/snmplib/snmp_api_error.c new file mode 100644 index 0000000000..d26391ffcf --- /dev/null +++ b/snmplib/snmp_api_error.c @@ -0,0 +1,94 @@ +/* + * 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 + * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#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)); +} diff --git a/snmplib/snmp_error.c b/snmplib/snmp_error.c new file mode 100644 index 0000000000..f2a4dc5de0 --- /dev/null +++ b/snmplib/snmp_error.c @@ -0,0 +1,69 @@ +/* + * 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 + +#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"; + } +} diff --git a/snmplib/snmp_msg.c b/snmplib/snmp_msg.c new file mode 100644 index 0000000000..3e29005f02 --- /dev/null +++ b/snmplib/snmp_msg.c @@ -0,0 +1,300 @@ +/* + * 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 + * + **********************************************************************/ + +#include "config.h" + +#include + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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; +} diff --git a/snmplib/snmp_pdu.c b/snmplib/snmp_pdu.c new file mode 100644 index 0000000000..2a491db5ff --- /dev/null +++ b/snmplib/snmp_pdu.c @@ -0,0 +1,698 @@ +/* + * 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 + * + **********************************************************************/ + +#include "config.h" + +#include + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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; +} + diff --git a/snmplib/snmp_vars.c b/snmplib/snmp_vars.c new file mode 100644 index 0000000000..61ef2f0f3b --- /dev/null +++ b/snmplib/snmp_vars.c @@ -0,0 +1,635 @@ +/* + * 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 + * + **********************************************************************/ + +#include "config.h" + +#include + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_CTYPE_H +#include +#endif +#if HAVE_GNUMALLOC_H +#include +#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_) +#include +#endif +#if HAVE_MEMORY_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STRINGS_H +#include +#endif +#if HAVE_BSTRING_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_NETDB_H +#include +#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); +}