]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Snmplib for squid, based on v1.8, heavily changed
authorkostas <>
Sun, 22 Feb 1998 18:55:22 +0000 (18:55 +0000)
committerkostas <>
Sun, 22 Feb 1998 18:55:22 +0000 (18:55 +0000)
snmplib/Makefile.in
snmplib/asn1.c
snmplib/coexistance.c [new file with mode: 0644]
snmplib/mib.c
snmplib/parse.c
snmplib/snmp_api.c
snmplib/snmp_api_error.c [new file with mode: 0644]
snmplib/snmp_error.c [new file with mode: 0644]
snmplib/snmp_msg.c [new file with mode: 0644]
snmplib/snmp_pdu.c [new file with mode: 0644]
snmplib/snmp_vars.c [new file with mode: 0644]

index 521598e5451b2c8f3b8cd4ccbd7d0be93475534c..acfad595a8a852b1f94d1606d9cbbb3ca13b3213 100644 (file)
@@ -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@
index 3fa9b06c1d1f7058443db3bd737c82c77fb3e0bc..a995dc9ebef5ef3f43689d0944dd2115dd6dcaae 100644 (file)
@@ -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 <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
 #endif
 #if HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
-#if HAVE_ASSERT_H
-#include <assert.h>
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
 #endif
 
 #include "asn1.h"
+#include "snmp_api_error.h"
 
-#ifdef DEBUG
-#define ERROR(string)   printf("%s(%d): %s",__FILE__, __LINE__, string);
-#else
-#define ERROR(string)
-#endif
+
+u_char *asn_build_header(u_char *data,       /* IN - ptr to start of object */
+                        int    *datalength, /* IN/OUT - # of valid bytes */
+                                             /*          left in buffer */
+                        u_char  type,       /* IN - ASN type of object */
+                        int     length)     /* IN - length of object */
+{
+  /* Truth is 0 'cause we don't know yet */
+  return(asn_build_header_with_truth(data, datalength, type, length, 0));
+}
 
 
 /*
- * asn_parse_int - pulls a long out of an ASN int type.
+ * asn_parse_int - pulls an int out of an ASN int type.
  *  On entry, datalength is input as the number of valid bytes following
  *   "data".  On exit, it is returned as the number of valid bytes
  *   following the end of this object.
@@ -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 (file)
index 0000000..7351cd4
--- /dev/null
@@ -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 <ryan+@andrew.cmu.edu>
+ * 
+ **********************************************************************/
+
+#include "config.h"
+
+#include "config.h"
+
+#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "snmp.h"
+#include "asn1.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_error.h"
+#include "snmp_api_error.h"
+
+#include "util.h"
+
+/*
+ * RFC 1908: Coexistence between SNMPv1 and SNMPv2
+ *
+ * These convert:
+ *
+ *   V1 PDUs from an ** AGENT **   to V2 PDUs for an ** MANAGER **
+ *   V2 PDUs from an ** MANAGER ** to V1 PDUs for an ** AGENT **
+ *
+ * We will never convert V1 information from a manager into V2 PDUs.  V1
+ * requests are always honored by V2 agents, and the responses will be 
+ * valid V1 responses.  (I think. XXXXX)
+ *
+ */
+int snmp_coexist_V2toV1(struct snmp_pdu *PDU)
+{
+  /* Per 3.1.1:
+   */
+  switch (PDU->command) {
+    
+  case SNMP_PDU_GET:
+  case SNMP_PDU_GETNEXT:
+  case SNMP_PDU_SET:
+    return(1);
+    break;
+
+  case SNMP_PDU_GETBULK:
+    PDU->non_repeaters = 0;
+    PDU->max_repetitions = 0;
+    PDU->command = SNMP_PDU_GETNEXT;
+    return(1);
+    break;
+
+  default:
+    snmplib_debug(2, "Unable to translate PDU %d to SNMPv1!\n", PDU->command);
+    snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+    return(0);
+  }
+}
+
+oid SysUptime[]   = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
+/* SNMPv2:           .1 .3 .6 .1 .6
+ * snmpModules:                     .3
+ * snmpMib:                            .1
+ * snmpMIBObjects:                        .1
+ * snmpTrap:                                 .4
+ */
+oid TrapOid[]     = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
+oid EnterOid[]    = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 3, 0};
+oid snmpTrapsOid[]= { 1, 3, 6, 1, 6, 3, 1, 1, 5};
+
+int snmp_coexist_V1toV2(struct snmp_pdu *PDU)
+{
+  /* Per 3.1.2:
+   */
+  switch (PDU->command) {
+    
+  case SNMP_PDU_RESPONSE:
+
+    if (PDU->errstat == SNMP_ERR_TOOBIG) {
+      snmp_var_free(PDU->variables);
+      PDU->variables = NULL;
+    }
+    return(1);
+    break;
+
+  case TRP_REQ_MSG:
+    {
+      struct variable_list *VarP;
+      oid NewOid[MAX_NAME_LEN];
+      oid NewOidLen = 0;
+
+      /* Fake SysUptime */
+      VarP = snmp_var_new(SysUptime, sizeof(SysUptime) / sizeof(oid));
+      if (VarP == NULL)
+       return(0);
+      VarP->type = ASN_INTEGER;
+      *VarP->val.integer = PDU->time;
+
+      /* Fake SNMPTrapOid */
+      VarP->next_variable = snmp_var_new(TrapOid, sizeof(TrapOid) / sizeof(oid));
+      if (VarP == NULL) {
+       snmp_var_free(VarP);
+       return(0);
+      }
+
+      if (PDU->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
+       xmemcpy(NewOid, PDU->enterprise, PDU->enterprise_length);
+       NewOidLen = PDU->enterprise_length;
+       NewOid[NewOidLen++] = 0;
+       NewOid[NewOidLen++] = PDU->specific_type;
+      } else {
+
+       /* Trap prefix */
+       NewOidLen = sizeof(snmpTrapsOid) / sizeof(oid);
+       xmemcpy(NewOid, snmpTrapsOid, NewOidLen);
+
+       switch (PDU->trap_type) {
+       case SNMP_TRAP_COLDSTART:
+         NewOid[NewOidLen++] = 1;
+         break;
+       case SNMP_TRAP_WARMSTART:
+         NewOid[NewOidLen++] = 2;
+         break;
+       case SNMP_TRAP_LINKDOWN:
+         NewOid[NewOidLen++] = 3; /* RFC 1573 */
+         break;
+       case SNMP_TRAP_LINKUP:
+         NewOid[NewOidLen++] = 4; /* RFC 1573 */
+         break;
+       case SNMP_TRAP_AUTHENTICATIONFAILURE:
+         NewOid[NewOidLen++] = 5;
+         break;
+       case SNMP_TRAP_EGPNEIGHBORLOSS:
+         NewOid[NewOidLen++] = 6; /* RFC 1213 */
+         break;
+       default:
+         snmplib_debug(2, "Unable to translate v1 trap type %d!\n",
+                 PDU->trap_type);
+         snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+         return(0);
+       }
+      }
+
+      /* ASSERT:  NewOid contains the new OID. */
+      VarP->next_variable->type = ASN_OBJECT_ID;
+      VarP->next_variable->val_len = NewOidLen;
+      VarP->next_variable->val.string = xmalloc(sizeof(oid)*NewOidLen);
+      if (VarP->next_variable->val.string == NULL) {
+       snmp_set_api_error(SNMPERR_OS_ERR);
+       return(0);
+      }
+      xmemcpy((char *)VarP->next_variable->val.string, 
+            (char *)NewOid, 
+            sizeof(oid)*NewOidLen);
+      
+      /* Prepend this list */
+      VarP->next_variable->next_variable = PDU->variables;
+      PDU->variables = VarP;
+
+      /* Finally, append the last piece */
+
+      for(VarP = PDU->variables; VarP->next_variable; VarP=VarP->next_variable)
+       ; /* Find the last element of the list. */
+
+      VarP->next_variable = snmp_var_new(EnterOid, 
+                                        sizeof(EnterOid) / sizeof(oid));
+      if (VarP->next_variable == NULL)
+       return(0);
+      VarP->next_variable->type = ASN_OBJECT_ID;
+      VarP->next_variable->val_len = PDU->enterprise_length;
+      VarP->next_variable->val.string = (u_char *)PDU->enterprise;
+
+      PDU->command = SNMP_PDU_V2TRAP;
+
+    } /* End of trap conversion */
+    return(1);
+    break;
+  default:
+    snmplib_debug(2, "Unable to translate PDU %d to SNMPv2!\n", PDU->command);
+    snmp_set_api_error(SNMPERR_PDU_TRANSLATION);
+    return(0);
+  }
+}
index 916eff3d69a7c6f0ee7e18c2230fd5857c88ff93..7151bb114451720f4ce9f04b881fbac63661bad0 100644 (file)
@@ -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 <stdio.h>
+
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -34,6 +36,14 @@ SOFTWARE.
 #if HAVE_CTYPE_H
 #include <ctype.h>
 #endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
@@ -43,32 +53,43 @@ SOFTWARE.
 #if HAVE_BSTRING_H
 #include <bstring.h>
 #endif
-
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
 
 #include "asn1.h"
 #include "snmp.h"
+
+#include "snmp_pdu.h"
+#include "snmp_vars.h"
+#include "snmp_session.h"
 #include "snmp_impl.h"
 #include "snmp_api.h"
 #include "parse.h"
 
-#include "mib.h"
-
 #include "util.h"
 #include "snprintf.h"
 
-/* fwd: */
 static void sprint_by_type();
-char *snmp_new_prefix(char *);
-static void set_functions();
-static int parse_subtree();
-static int lc_cmp();
-static void sprint_variable();
-static struct tree *get_symbol();
 
 static char *
-uptimeString(unsigned long timeticks, char *buf)
+uptimeString(timeticks, buf)
+    int timeticks;
+    char *buf;
 {
-    int seconds, minutes, hours, days;
+    int        seconds, minutes, hours, days;
 
     timeticks /= 100;
     days = timeticks / (60 * 60 * 24);
@@ -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 <cpw@lanl.gov>:
- *
- * [...] I made an addition to mib.c to accomodate some old perl snmp
- * code for a program called vulture that used a global pointer to the
- * prefix to change things.  
- */
-
-char *
-snmp_new_prefix(char *prefix)
-{
-    char *lastchar;
-    int plen;
-
-    if (prefix) {
-       lastchar = ".";
-       if (*prefix == '.') {
-           prefix++;
-       }
-       if ((plen = strlen(prefix))) {
-           lastchar = prefix + plen - 1;
-       }
-       strncpy(Prefix, prefix, sizeof(Prefix) - 2);
-       Prefix[sizeof(Prefix) - 2] = 0;
-       if (*lastchar != '.') {
-           Prefix[plen++] = '.';
-           Prefix[plen] = 0;
-       }
-       return Prefix;
-    }
-    return (char *) NULL;
-}
-
-
-
-static void
-set_functions(subtree)
-     struct tree *subtree;
-{
-    for (; subtree; subtree = subtree->next_peer) {
-       switch (subtree->type) {
-       case TYPE_OBJID:
-           subtree->printer = sprint_object_identifier;
-           break;
-       case TYPE_OCTETSTR:
-           subtree->printer = sprint_octet_string;
-           break;
-       case TYPE_INTEGER:
-           subtree->printer = sprint_integer;
-           break;
-       case TYPE_NETADDR:
-           subtree->printer = sprint_networkaddress;
-           break;
-       case TYPE_IPADDR:
-           subtree->printer = sprint_ipaddress;
+sprint_by_type(buf, var, enums, quiet)
+    char *buf;
+    variable_list *var;
+    struct enum_list       *enums;
+    int quiet;
+{
+    switch (var->type){
+       case SMI_INTEGER:
+           sprint_integer(buf, var, enums, quiet);
            break;
-       case TYPE_COUNTER:
-           subtree->printer = sprint_counter;
+       case SMI_STRING:
+           sprint_octet_string(buf, var, enums, quiet);
            break;
-       case TYPE_GAUGE:
-           subtree->printer = sprint_gauge;
+       case SMI_OPAQUE:
+           sprint_opaque(buf, var, enums, quiet);
            break;
-       case TYPE_TIMETICKS:
-           subtree->printer = sprint_timeticks;
+       case SMI_OBJID:
+           sprint_object_identifier(buf, var, enums, quiet);
            break;
-       case TYPE_OPAQUE:
-           subtree->printer = sprint_opaque;
+       case SMI_TIMETICKS:
+           sprint_timeticks(buf, var, enums, quiet);
            break;
-       case TYPE_NULL:
-           subtree->printer = sprint_null;
+       case SMI_GAUGE32:
+           sprint_gauge(buf, var, enums, quiet);
            break;
-       case TYPE_BITSTRING:
-           subtree->printer = sprint_bitstring;
+       case SMI_COUNTER32:
+           sprint_counter(buf, var, enums, quiet);
            break;
-       case TYPE_NSAPADDRESS:
-           subtree->printer = sprint_nsapaddress;
+       case SMI_IPADDRESS:
+           sprint_ipaddress(buf, var, enums, quiet);
            break;
-       case TYPE_COUNTER64:
-           subtree->printer = sprint_counter64;
+       case SMI_NULLOBJ:
+           sprint_null(buf, var, enums, quiet);
            break;
-       case TYPE_UINTEGER:
-           subtree->printer = sprint_uinteger;
-           break;
-       case TYPE_OTHER:
        default:
-           subtree->printer = sprint_unknowntype;
+           sprint_badtype(buf, enums, quiet);
            break;
-       }
-       set_functions(subtree->child_list);
     }
 }
 
-#ifdef testing
-int snmp_dump_packet = 0;
+static struct snmp_mib_tree *get_symbol();
 
-main(argc, argv)
-     int argc;
-     char *argv[];
+oid RFC1066_MIB[] = { 1, 3, 6, 1, 2, 1 };
+unsigned char RFC1066_MIB_text[] = ".iso.org.dod.internet.mgmt.mib";
+struct snmp_mib_tree *Mib;
+
+static void
+set_functions(subtree)
+    struct snmp_mib_tree *subtree;
 {
-    oid objid[64];
-    int objidlen = sizeof(objid);
-    int count;
-    struct variable variable;
-
-    init_mib();
-    if (argc < 2)
-       print_subtree(Mib, 0);
-    variable.type = ASN_INTEGER;
-    variable.val.integer = 3;
-    variable.val_len = 4;
-    for (argc--; argc; argc--, argv++) {
-       objidlen = sizeof(objid);
-       printf("read_objid(%s) = %d\n",
-           argv[1], read_objid(argv[1], objid, &objidlen));
-       for (count = 0; count < objidlen; count++)
-           printf("%d.", objid[count]);
-       printf("\n");
-       print_variable(objid, objidlen, &variable);
+    for(; subtree; subtree = subtree->next_peer){
+       switch(subtree->type){
+           case TYPE_OBJID:
+               subtree->printer = sprint_object_identifier;
+               break;
+           case TYPE_OCTETSTR:
+               subtree->printer = sprint_octet_string;
+               break;
+           case TYPE_INTEGER:
+               subtree->printer = sprint_integer;
+               break;
+           case TYPE_NETADDR:
+               subtree->printer = sprint_networkaddress;
+               break;
+           case TYPE_IPADDR:
+               subtree->printer = sprint_ipaddress;
+               break;
+           case TYPE_COUNTER:
+               subtree->printer = sprint_counter;
+               break;
+           case TYPE_GAUGE:
+               subtree->printer = sprint_gauge;
+               break;
+           case TYPE_TIMETICKS:
+               subtree->printer = sprint_timeticks;
+               break;
+           case TYPE_OPAQUE:
+               subtree->printer = sprint_opaque;
+               break;
+           case TYPE_NULL:
+               subtree->printer = sprint_null;
+               break;
+           case TYPE_OTHER:
+           default:
+               subtree->printer = sprint_unknowntype;
+               break;
+       }
+       set_functions(subtree->child_list);
     }
 }
 
-#endif /* testing */
+void init_mib(char *file)
+{
+    if (snmplib_debug != NULL)
+       snmplib_debug(6, "init_mib: Called.\n");
+    if (Mib != NULL)
+       return;
+
+    if (file != NULL)
+       Mib = read_mib(file);
+    set_functions(Mib);
+}
 
 
-#if 0
-static struct tree *
-find_rfc1213_mib(root)
-     struct tree *root;
+static struct snmp_mib_tree *
+find_rfc1066_mib(root)
+    struct snmp_mib_tree *root;
 {
-    oid *op = RFC1213_MIB;
-    struct tree *tp;
+    oid *op = RFC1066_MIB;
+    struct snmp_mib_tree *tp;
     int len;
 
-    for (len = sizeof(RFC1213_MIB) / sizeof(oid); len; len--, op++) {
-       for (tp = root; tp; tp = tp->next_peer) {
-           if (tp->subid == *op) {
+    for(len = sizeof(RFC1066_MIB)/sizeof(oid); len; len--, op++){
+       for(tp = root; tp; tp = tp->next_peer){
+           if (tp->subid == *op){
                root = tp->child_list;
                break;
            }
@@ -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<len;x++)
+    printf(".%u", O[x]);
 }
-#endif
index 07d378863db03e311e4f381d8fca6974a6e29cbd..619829bfd261dec9bd59c12a25981ece3bc13070 100644 (file)
@@ -1,5 +1,5 @@
-/******************************************************************
-       Copyright 1989, 1991, 1992 by Carnegie Mellon University
+/***********************************************************
+       Copyright 1989 by Carnegie Mellon University
 
                       All Rights Reserved
 
@@ -20,41 +20,68 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 SOFTWARE.
 ******************************************************************/
 
+/*
+ * parse.c
+ */
 #include "config.h"
 
-#if HAVE_STDIO_H
 #include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
 #endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
 #endif
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
+#if HAVE_CTYPE_H
+#include <ctype.h>
 #endif
 #if HAVE_GNUMALLOC_H
 #include <gnumalloc.h>
 #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
 #include <malloc.h>
 #endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
 
+#include "asn1.h"
+#include "snmp_vars.h"
 #include "parse.h"
 
 #include "util.h"
 
-#define free +
-
-/* A quoted string value-- too long for a general "token" */
-char *quoted_string_buffer;
-
 /*
- * This is one element of an object identifier with either an integer
- * subidentifier, or a textual string label, or both.
+ * This is one element of an object identifier with either an integer subidentifier,
+ * or a textual string label, or both.
  * The subid is -1 if not present, and label is NULL if not present.
  */
 struct subid {
@@ -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;
-}
index 5407457a848e2b90229a2ab06ad3de02fc23be4f..c61326d69a7434dcbbdf0fb1a86686ffd0ceebe9 100644 (file)
@@ -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
  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  * SOFTWARE.
- */
-/*
- * snmp_api.c - API for access to snmp.
- */
+ * 
+ **********************************************************************/
 
 #include "config.h"
 
+#include <stdio.h>
+
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-
-#define free +
-
-#define DEBUG_SNMPTRACE                0       /* set to 1 to print all SNMP actions */
-#define DEBUG_SNMPFULLDUMP     0       /* set to 1 to dump all SNMP packets */
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
 
 #include "asn1.h"
 #include "snmp.h"
+
+#include "snmp-internal.h"
 #include "snmp_impl.h"
+#include "snmp_session.h"
+
+#include "mibii.h"
+#include "snmp_dump.h"
+#include "snmp_error.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+
 #include "snmp_api.h"
 #include "snmp_client.h"
+#include "snmp_api_error.h"
+#include "snmp_api_util.h"
 
 #include "util.h"
 
-#define PACKET_LENGTH  4500
+extern int snmp_errno;
 
-oid default_enterprise[] =
-{1, 3, 6, 1, 4, 1, 3, 1, 1};   /* enterprises.cmu.systems.cmuSNMP */
 
-#define DEFAULT_COMMUNITY   "public"
-#define DEFAULT_REMPORT            SNMP_PORT
-#define DEFAULT_ENTERPRISE  default_enterprise
-#define DEFAULT_TIME       0
-#define DEFAULT_MMS        1389        /* large, randomly picked for testing purposes */
-
-/*
- * Internal information about the state of the snmp session.
- */
-struct snmp_internal_session {
-    int sd;                    /* socket descriptor for this connection */
-    ipaddr addr;               /* address of connected peer */
-    struct request_list *requests;     /* Info about outstanding requests */
-};
+/*#define DEBUG_API 1*/
 
 /*
- * A list of all the outstanding requests for a particular session.
+ * RFC 1906: Transport Mappings for SNMPv2
  */
-struct request_list {
-    struct request_list *next_request;
-    u_long request_id;         /* request id */
-    int retries;               /* Number of retries */
-    u_long timeout;            /* length to wait for timeout */
-    struct timeval time;       /* Time this request was made */
-    struct timeval expire;     /* time this request is due to expire */
-    struct snmp_pdu *pdu;      /* The pdu for this request (saved so it can be retransmitted */
-};
 
-/*
- * The list of active/open sessions.
- */
-struct session_list {
-    struct session_list *next;
-    struct snmp_session *session;
-    struct snmp_internal_session *internal;
-};
 
-struct session_list *Sessions = NULL;
+oid default_enterprise[] = {1, 3, 6, 1, 4, 1, 3, 1, 1}; /* enterprises.cmu.systems.cmuSNMP */
 
-u_long Reqid = 0;
-int snmp_errno = 0;
-
-char *api_errors[4] =
-{
-    "Unknown session",
-    "Unknown host",
-    "Invalid local port",
-    "Unknown Error"
-};
+#define DEFAULT_COMMUNITY   "public"
+#define DEFAULT_RETRIES            4
+#define DEFAULT_TIMEOUT            1000000L
+#define DEFAULT_REMPORT            SNMP_PORT
+#define DEFAULT_ENTERPRISE  default_enterprise
+#define DEFAULT_TIME       0
 
+extern int snmp_errno;
 
-static void sync_with_agent(struct snmp_session *session);
 
-#if NO_PRINTFS
-static char *
-api_errstring(int snmp_errnumber)
-{
-    if (snmp_errnumber <= SNMPERR_BAD_SESSION && snmp_errnumber >= SNMPERR_GENERR) {
-       return api_errors[snmp_errnumber + 4];
-    } else {
-       return "Unknown Error";
-    }
-}
-#endif
+struct session_list *Sessions = NULL;
 
-#if UNUSED_CODE
 /*
- * Gets initial request ID for all transactions.
+ * Get initial request ID for all transactions.
  */
-static void
-init_snmp(void)
+static int Reqid = 0;
+
+static void init_snmp(void) 
 {
-    struct timeval tv;
+  struct timeval tv;
 
-    gettimeofday(&tv, (struct timezone *) 0);
-    srandom(tv.tv_sec ^ tv.tv_usec);
-    Reqid = random();
+  gettimeofday(&tv, (struct timezone *)0);
+  squid_srandom(tv.tv_sec ^ tv.tv_usec);
+  Reqid = squid_random();
 }
 
-#endif
 
 
 /*
- * Dump snmp packet to stdout:
+ * Free each element in the input request list.
  */
-static void
-snmp_print_packet(char *packet, int length, ipaddr addr, int code)
+static void free_request_list(rp)
+    struct request_list *rp;
 {
-    if (length < 0) {
-       return;
-    }
-#if NO_PRINTFS
-    if (code <= 0) {           /* received */
-       printf("\nReceived %4d bytes from ", length);
-    } else {                   /* sending */
-       printf("\nSending  %4d bytes to   ", length);
-    }
-    printf("%s:", inet_ntoa(addr.sin_addr));
-#endif
-#if DEBUG_SNMPFULLDUMP
-    for (count = 0; count < length; count++) {
-       if ((count & 15) == 0) {
-           printf("\n  ");
-       }
-       printf("%02X ", (int) (packet[count] & 255));
-    }
-#endif
-#if NO_PRINTFS
-    fflush(stdout);
-#endif
-}
+    struct request_list *orp;
 
-#if DEBUG_SNMPTRACE
-/*
- * Print request
- */
-#define TRACE_SEND   (0)
-#define TRACE_RECV   (1)
-#define TRACE_TIMEOUT (2)
-static void
-snmp_print_trace(struct session_list *slp, struct request_list *rp, int code)
-{
-    int reqid = 0, retries = 1;
-    if (rp) {
-       reqid = rp->request_id;
-       retries = rp->retries;
-    }
-    printf("\n Session %2d  ReqId %4d  ", slp->internal->sd, reqid);
-    switch (code) {
-    case TRACE_SEND:
-       printf("send pdu (%d)", retries);
-       break;
-    case TRACE_RECV:
-       printf("recv pdu");
-       break;
-    case TRACE_TIMEOUT:
-       printf("time out");
-       break;
+    while(rp){
+       orp = rp;
+       rp = rp->next_request;
+       if (orp->pdu != NULL)
+           snmp_free_pdu(orp->pdu);
+       xfree((char *)orp);
     }
-    fflush(stdout);
 }
-#endif /* DEBUG_SNMPTRACE */
-
-
 
+/**********************************************************************/
 
 /*
  * Sets up the session with the snmp_session information provided
@@ -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 : "<NULL>");
+    for(rp = isp->requests; rp; rp = rp->next_request) {
+snmplib_debug(6,"LIBSNMP:  Checking session request %d, expire at %u, Retry %d/%d\n", 
+       rp->request_id, rp->expire.tv_sec, rp->retries, sp->retries);
+
+      if (freeme != NULL) {
+       /* frees rp's after the for loop goes on to the next_request */
+       xfree((char *)freeme);
+       freeme = NULL;
+      }
+
+      if (timercmp(&rp->expire, &now, <)) {
+
+snmplib_debug(6,"LIBSNMP:  Expired.\n");
+
+       /* this timer has expired */
+       if (rp->retries >= sp->retries) {
+         /* No more chances, delete this entry */
+         sp->callback(TIMED_OUT, sp, rp->pdu->reqid, 
+                      rp->pdu, sp->callback_magic);
+         if (orp == NULL) {
+           isp->requests = rp->next_request;
+         } else {
+           orp->next_request = rp->next_request;
+         }
+         snmp_free_pdu(rp->pdu);
+         freeme = rp;
+         continue;     /* don't update orp below */
+       } else {
+                   u_char  packet[PACKET_LENGTH];
                    int length = PACKET_LENGTH;
                    struct timeval tv;
 
+snmplib_debug(6,"LIBSNMP:  Retransmitting.\n");
                    /* retransmit this pdu */
                    rp->retries++;
                    rp->timeout <<= 1;
-                   if (snmp_build(sp, rp->pdu, packet, &length, 0) < 0) {
-#if NO_PRINTFS
-                       fprintf(stderr, "Error building packet\n");
-#endif
+                   if (snmp_build(sp, rp->pdu, packet, &length) < 0){
+                     snmplib_debug(3, "Error building packet\n");
                    }
-                   if (snmp_dump_packet) {
-                       snmp_print_packet((char *)packet, length, rp->pdu->address, 1);
-                   }
-                   gettimeofday(&tv, (struct timezone *) 0);
-                   if (sendto(isp->sd, (char *) packet, length, 0, (struct sockaddr *) &rp->pdu->address, sizeof(rp->pdu->address)) < 0) {
+
+                   snmp_dump(packet, length, 
+                             "sending", rp->pdu->address.sin_addr);
+
+                   gettimeofday(&tv, (struct timezone *)0);
+                   if (sendto(isp->sd, (char *)packet, length, 0, (struct sockaddr *)&rp->pdu->address, sizeof(rp->pdu->address)) < 0){
                        perror("sendto");
                    }
                    rp->time = tv;
@@ -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 (file)
index 0000000..d26391f
--- /dev/null
@@ -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 <ryan+@andrew.cmu.edu>
+ * 
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include "snmp_api_error.h"
+
+
+/***************************************************************************
+ *
+ ***************************************************************************/
+
+int snmp_errno = 0;
+
+static char *api_errors[17] = {
+  "Unknown Error",
+  "Generic Error", 
+  "Invalid local port",
+  "Unknown host",
+  "Unknown session",
+  "Too Long",
+
+  "Encoding ASN.1 Information", /* 6 */
+  "Decoding ASN.1 Information", /* 7 */
+  "PDU Translation error",
+  "OS Error",
+  "Invalid Textual OID",
+  
+  "Unable to fix PDU",
+  "Unsupported SNMP Type",
+  "Unable to parse PDU",
+  "Packet Error",
+  "No Response From Host",
+
+
+  "Unknown Error"
+};
+
+void snmp_set_api_error(int x)
+{
+  snmp_errno = x;
+}
+
+char *snmp_api_error(int err)
+{
+  int foo = (err * -1);
+  if ((foo < SNMPERR_GENERR) ||
+      (foo > SNMPERR_LAST))
+    foo=0;
+
+  return(api_errors[foo]);
+}
+
+int snmp_api_errno(void)
+{
+  return(snmp_errno);
+}
+
+char *api_errstring(int snmp_errnumber)
+{
+  return(snmp_api_error(snmp_errnumber));
+}
diff --git a/snmplib/snmp_error.c b/snmplib/snmp_error.c
new file mode 100644 (file)
index 0000000..f2a4dc5
--- /dev/null
@@ -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 <stdio.h>
+
+#include "snmp_error.h"
+
+
+static char *error_string[19] = {
+  "No Error",
+  "Response message would have been too large.",
+  "There is no such variable name in this MIB.",
+  "The value given has the wrong type, length, or value",
+  "This variable is read only",
+  "A general failure occured",
+
+  /* SNMPv2 Errors */
+  "NOACCESS",
+  "WRONGTYPE",
+  "WRONGLENGTH",
+  "WRONGENCODING",
+  "WRONGVALUE",
+  "NOCREATION",
+  "INCONSISTENTVALUE",
+  "RESOURCEUNAVAILABLE",
+  "COMMITFAILED",
+  "UNDOFAILED",
+  "AUTHORIZATIONERROR",
+  "NOTWRITABLE",
+  "INCONSISTENTNAME",
+
+};
+
+char *snmp_errstring(int errstat)
+{
+  if ((errstat <= (SNMP_ERR_INCONSISTENTNAME)) && 
+      (errstat >= (SNMP_ERR_NOERROR))) {
+    return error_string[errstat];
+  } else {
+    return "Unknown Error";
+  }
+}
diff --git a/snmplib/snmp_msg.c b/snmplib/snmp_msg.c
new file mode 100644 (file)
index 0000000..3e29005
--- /dev/null
@@ -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 <ryan+@andrew.cmu.edu>
+ * 
+ **********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "snmp.h"
+#include "asn1.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+#include "mibii.h"
+
+
+/* 
+ * RFC 1901: Introduction to Community-based SNMPv2
+ *
+ *  Message ::=
+ *    SEQUENCE {
+ *      version   INTEGER
+ *      community OCTET STRING
+ *      data
+ *    }
+ *
+ * RFC 1157: A Simple Network Management Protocol (SNMP)
+ *
+ *  Message ::=
+ *    SEQUENCE {
+ *      version   INTEGER
+ *      community OCTET STRING
+ *      data
+ *    }
+ *
+ */
+
+/* Encode a SNMP Message Header.  Return a pointer to the beginning of the
+ * data.
+ */
+
+#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
+
+/* Encode an SNMP Message
+ *
+ * Returns a pointer to the end of the message, or NULL.
+ *
+ * *BufLenP (Second Argument) will contain the amount of space left
+ *          in the buffer.
+ */
+
+u_char *snmp_msg_Encode(u_char *Buffer, int *BufLenP,
+                       u_char *Community, int CommLen,
+                       int Version,
+                       struct snmp_pdu *PDU)
+{
+  u_char *bufp, *tmp;
+  u_char *PDUHeaderPtr, *VARHeaderPtr;
+  u_char *PDUDataStart, *VARDataStart;
+  u_char *MsgPtr;
+  int FakeArg = 1024;
+
+  /* Header for the entire thing, with a false, large length */
+  bufp = asn_build_header(Buffer, BufLenP, 
+                         (u_char)(ASN_SEQUENCE |
+                                  ASN_CONSTRUCTOR), 
+                         (*BufLenP));
+  if (bufp == NULL) {
+    snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Header)!\n");
+    return(NULL);
+  }
+  MsgPtr = bufp;
+
+  /* Version */
+  bufp = asn_build_int(bufp, BufLenP,
+                      (u_char)(ASN_UNIVERSAL | 
+                               ASN_PRIMITIVE |
+                               ASN_INTEGER),
+                      (int *)(&Version), sizeof(Version));
+  if (bufp == NULL){
+    snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Version)!\n");
+    return(NULL);
+  }
+
+  snmplib_debug(8, "snmp_msg_Encode: Encoding community (%s) (%d)\n", Community, CommLen);
+
+  /* Community */
+  bufp = asn_build_string(bufp, BufLenP,
+                         (u_char)(ASN_UNIVERSAL | 
+                                  ASN_PRIMITIVE | 
+                                  ASN_OCTET_STR), 
+                         Community, CommLen);
+  if (bufp == NULL){
+     snmplib_debug(4, "snmp_msg_Encode:Error encoding SNMP Message Header (Community)!\n");
+    return(NULL);
+  }
+
+  /* Encode the rest. */
+
+  /* A nice header for this PDU. 
+   * Encoded with the wrong length.  We'll fix it later.
+   */
+   snmplib_debug(8, "snmp_msg_Encode:Encoding PDU Header at 0x%x (fake len %d) (%d bytes so far)\n",
+        bufp, *BufLenP, *BufLenP);
+  PDUHeaderPtr = bufp;
+  bufp = asn_build_header(bufp, BufLenP,
+                         (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                         (*BufLenP));
+  if (bufp == NULL)
+    return(NULL);
+
+  /* Encode this PDU. */
+  PDUDataStart = bufp;
+  bufp = snmp_pdu_encode(bufp, BufLenP, PDU);
+  if (bufp == NULL)
+    return(NULL);  /* snmp_pdu_encode registered failure */
+
+  VARHeaderPtr = bufp;
+  bufp = asn_build_header(bufp, BufLenP,
+                          (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                          FakeArg);
+  if (bufp == NULL)
+    return(NULL);
+  VARDataStart = bufp;
+
+  /* And build the variables */
+  bufp = snmp_var_EncodeVarBind(bufp, BufLenP, PDU->variables, Version);
+  if (bufp == NULL)
+    return(NULL);    /* snmp_var_EncodeVarBind registered failure */
+
+  /* Cool.  Now insert the appropriate lengths.
+   */
+#ifdef DEBUG_MSG_ENCODE
+  snmplib_debug(9, "Msg:  Vars returned 0x%x.  PDU Started at 0x%x\n", 
+        bufp, PDUHeaderPtr);
+  snmplib_debug(9, "MSG:  Entire PDU length is %d (0x%x - 0x%x)\n", 
+        (int)(bufp - PDUDataStart), PDUHeaderPtr, bufp);
+#endif
+  tmp = asn_build_header(PDUHeaderPtr, &FakeArg,
+                        (u_char)PDU->command,
+                        (int)(bufp - PDUDataStart)); 
+  /* Length of the PDU and Vars */
+  if (tmp == NULL)
+    return(NULL);
+
+#ifdef DEBUG_MSG_ENCODE
+  snmplib_debug(9, "MSG:  Entire message length is %d (0x%x - 0x%x)\n", 
+        (int)(bufp - MsgPtr), MsgPtr, bufp);
+#endif
+  tmp = asn_build_header(Buffer,
+                        &FakeArg,
+                        (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                        (bufp - MsgPtr)); /* Length of everything */
+  if (tmp == NULL)
+    return(NULL);
+
+  tmp = asn_build_header(VARHeaderPtr,
+                        &FakeArg,
+                        (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                        (bufp - VARDataStart)); /* Length of everything */
+  if (tmp == NULL)
+    return(NULL);
+
+  *BufLenP = (bufp - Buffer);
+  return (u_char *)bufp;
+}
+
+/**********************************************************************/
+
+u_char *snmp_msg_Decode(u_char *Packet, int *PacketLenP, 
+                       u_char *Community, int *CommLenP, 
+                       int *Version, struct snmp_pdu *PDU)
+{
+  u_char *bufp;
+  u_char    type;
+
+  bufp = asn_parse_header(Packet, PacketLenP, &type);
+  if (bufp == NULL){
+     snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
+    ASN_PARSE_ERROR(NULL);
+  }
+  if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
+     snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Header)!\n");
+    ASN_PARSE_ERROR(NULL);
+  }
+
+  bufp = asn_parse_int(bufp, PacketLenP, 
+                      &type, 
+                      (int *)Version, sizeof(*Version));
+  if (bufp == NULL){
+    snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Version)!\n");
+    ASN_PARSE_ERROR(NULL);
+  }
+  bufp = asn_parse_string(bufp, PacketLenP, &type, Community, CommLenP);
+  if (bufp == NULL){
+     snmplib_debug(4, "snmp_msg_Decode:Error decoding SNMP Messsage Header (Community)!\n");
+    ASN_PARSE_ERROR(NULL);
+  }
+  Community[*CommLenP] = '\0';
+
+  if ((*Version != SNMP_VERSION_1) && 
+      (*Version != SNMP_VERSION_2)) {
+
+    /* Don't know how to handle this one. */
+    snmpInBadVersions_Add(1);
+     snmplib_debug(4, "snmp_msg_Decode:Unable to parse Version %u\n", *Version);
+     snmplib_debug(4, "snmp_msg_Decode:Continuing anyway\n");
+  }
+
+  /* Now that we know the header, decode the PDU */
+
+  /* XXXXX -- More than one PDU? */
+  bufp = snmp_pdu_decode(bufp, PacketLenP, PDU);
+  if (bufp == NULL)
+    /* snmp_pdu_decode registered failure */
+    return(NULL);
+
+  bufp = snmp_var_DecodeVarBind(bufp, PacketLenP, &(PDU->variables), *Version);
+  if (bufp == NULL)
+    /* snmp_var_DecodeVarBind registered failure */
+    return(NULL);
+
+  return (u_char *)bufp;
+}
diff --git a/snmplib/snmp_pdu.c b/snmplib/snmp_pdu.c
new file mode 100644 (file)
index 0000000..2a491db
--- /dev/null
@@ -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 <ryan+@andrew.cmu.edu>
+ * 
+ **********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "snmp.h"
+#include "asn1.h"
+#include "snmp_error.h"
+#include "snmp_vars.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+#include "mibii.h"
+#include "snmp_api_error.h"
+
+#include "util.h"
+
+/* #define DEBUG_PDU 1 */
+/* #define DEBUG_PDU_DECODE 1 */
+/* #define DEBUG_PDU_ENCODE 1 */
+
+#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
+
+/**********************************************************************/
+
+/* Create a PDU.
+ */
+
+struct snmp_pdu *snmp_pdu_create(int command)
+{
+  struct snmp_pdu *pdu;
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU:  Creating\n");
+#endif
+
+  pdu = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
+  if (pdu == NULL) {
+    snmp_set_api_error(SNMPERR_OS_ERR);
+    return(NULL);
+  }
+
+  memset((char *)pdu, '\0', sizeof(struct snmp_pdu));
+
+  pdu->command                 = command;
+  pdu->errstat                 = SNMP_DEFAULT_ERRSTAT;
+  pdu->errindex                = SNMP_DEFAULT_ERRINDEX;
+  pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
+  pdu->enterprise              = NULL;
+  pdu->enterprise_length       = 0;
+  pdu->variables               = NULL;
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU:  Created %x\n", (unsigned int)pdu);
+#endif
+
+  return(pdu);
+}
+
+/**********************************************************************/
+
+/* Clone an existing PDU.
+ */
+struct snmp_pdu *snmp_pdu_clone(struct snmp_pdu *Src)
+{
+  struct snmp_pdu *Dest;
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU %x:  Cloning\n", (unsigned int)Src);
+#endif
+
+  Dest = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
+  if (Dest == NULL) {
+    snmp_set_api_error(SNMPERR_OS_ERR);
+    return(NULL);
+  }
+  xmemcpy((char *)Dest, (char *)Src, sizeof(struct snmp_pdu));
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU %x:  Created %x\n", (unsigned int)Src, (unsigned int)Dest);
+#endif
+  return(Dest);
+}
+
+/**********************************************************************/
+
+/*
+ * If there was an error in the input pdu, creates a clone of the pdu
+ * that includes all the variables except the one marked by the errindex.
+ * The command is set to the input command and the reqid, errstat, and
+ * errindex are set to default values.
+ * If the error status didn't indicate an error, the error index didn't
+ * indicate a variable, the pdu wasn't a get response message, or there
+ * would be no remaining variables, this function will return NULL.
+ * If everything was successful, a pointer to the fixed cloned pdu will
+ * be returned.
+ */
+struct snmp_pdu *snmp_pdu_fix(struct snmp_pdu *pdu, int command)
+{
+  return(snmp_fix_pdu(pdu, command));
+}
+
+struct snmp_pdu *snmp_fix_pdu(struct snmp_pdu *pdu, int command)
+{
+  struct variable_list *var, *newvar;
+  struct snmp_pdu *newpdu;
+  int index;
+  int copied = 0;
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU %x:  Fixing.  Err index is %d\n", 
+        (unsigned int)pdu, (unsigned int)pdu->errindex);
+#endif
+
+  if (pdu->command != SNMP_PDU_RESPONSE || 
+      pdu->errstat == SNMP_ERR_NOERROR || 
+      pdu->errindex <= 0) {
+    snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
+    return(NULL);
+  }
+
+  /* clone the pdu */
+  newpdu            = snmp_pdu_clone(pdu);
+  if (newpdu == NULL)
+    return(NULL);
+
+  newpdu->variables = 0;
+  newpdu->command   = command;
+  newpdu->reqid     = SNMP_DEFAULT_REQID;
+  newpdu->errstat   = SNMP_DEFAULT_ERRSTAT;
+  newpdu->errindex  = SNMP_DEFAULT_ERRINDEX;
+
+  /* Loop through the variables, removing whatever isn't necessary */
+
+  var   = pdu->variables;
+  index = 1;
+
+  /* skip first variable if necessary*/
+  if (pdu->errindex == index) {
+    var = var->next_variable;
+    index++;
+  }
+
+  if (var != NULL) {
+
+    /* VAR is the first uncopied variable */
+
+    /* Clone this variable */
+    newpdu->variables = snmp_var_clone(var);
+    if (newpdu->variables == NULL) {
+      snmp_pdu_free(newpdu);
+      return(NULL);
+    }
+    copied++;
+
+    newvar = newpdu->variables;
+
+    /* VAR has been copied to NEWVAR. */
+    while(var->next_variable) {
+
+      /* Skip the item that was bad */
+      if (++index == pdu->errindex) {
+       var = var->next_variable;
+       continue;
+      }
+
+      /* Copy this var */
+      newvar->next_variable = snmp_var_clone(var->next_variable);
+      if (newvar->next_variable == NULL) {
+       snmp_pdu_free(newpdu);
+       return(NULL);
+      }
+
+      /* Move to the next one */
+      newvar = newvar->next_variable;
+      var = var->next_variable;
+      copied++;
+    }
+    newvar->next_variable = NULL;
+  }
+
+  /* If we didn't copy anything, free the new pdu. */
+  if (index < pdu->errindex || copied == 0) {
+    snmp_free_pdu(newpdu);
+    snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
+    return(NULL);
+  }
+
+#ifdef DEBUG_PDU
+  snmplib_debug(8,"PDU %x:  Fixed PDU is %x\n", 
+        (unsigned int)pdu, (unsigned int)newpdu);
+#endif
+  return(newpdu);
+}
+
+
+/**********************************************************************/
+
+void snmp_pdu_free(struct snmp_pdu *pdu)
+{
+  snmp_free_pdu(pdu);
+}
+
+/*
+ * Frees the pdu and any xmalloc'd data associated with it.
+ */
+void snmp_free_pdu(struct snmp_pdu *pdu)
+{
+  struct variable_list *vp, *ovp;
+
+  vp = pdu->variables;
+  while(vp) {
+    ovp = vp;
+    vp = vp->next_variable;
+    snmp_var_free(ovp);
+  }
+
+  if (pdu->enterprise)
+    xfree((char *)pdu->enterprise);
+  xfree((char *)pdu);
+}
+
+/**********************************************************************/
+
+/* Encode this PDU into DestBuf.
+ *
+ * Returns a pointer to the next byte in the buffer (where the Variable
+ * Bindings belong.)
+ */
+
+/*
+ * RFC 1902: Structure of Management Information for SNMPv2
+ *
+ *   PDU ::= 
+ *    SEQUENCE {
+ *      request-id   INTEGER32
+ *      error-status INTEGER
+ *      error-index  INTEGER
+ *      Variable Bindings
+ *    }
+ *
+ * BulkPDU ::=
+ *    SEQUENCE {
+ *      request-id      INTEGER32
+ *      non-repeaters   INTEGER
+ *      max-repetitions INTEGER
+ *      Variable Bindings
+ *    }
+ */
+
+/*
+ * RFC 1157: A Simple Network Management Protocol (SNMP)
+ *
+ *   PDU ::= 
+ *    SEQUENCE {
+ *      request-id   INTEGER
+ *      error-status INTEGER
+ *      error-index  INTEGER
+ *      Variable Bindings
+ *    }
+ *
+ *   TrapPDU ::=
+ *    SEQUENCE {
+ *      enterprise    NetworkAddress
+ *      generic-trap  INTEGER
+ *      specific-trap INTEGER
+ *      time-stamp    TIMETICKS
+ *      Variable Bindings
+ *    }
+ */
+
+u_char *snmp_pdu_encode(u_char *DestBuf, int *DestBufLen,
+                       struct snmp_pdu *PDU)
+{
+  u_char *bufp;
+
+#ifdef DEBUG_PDU_ENCODE
+  snmplib_debug(8,"PDU: Encoding %d\n", PDU->command);
+#endif
+
+  /* ASN.1 Header */
+  switch (PDU->command) {
+
+    /**********************************************************************/
+
+  case TRP_REQ_MSG:
+
+    /* SNMPv1 Trap */
+
+    /* enterprise */
+    bufp = asn_build_objid(DestBuf, DestBufLen,
+                          (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+                          (oid *)PDU->enterprise, PDU->enterprise_length);
+    if (bufp == NULL)
+      return(NULL);
+
+    /* agent-addr */
+    bufp = asn_build_string(bufp, DestBufLen,
+                           (u_char)(SMI_IPADDRESS | ASN_PRIMITIVE),
+                           (u_char *)&PDU->agent_addr.sin_addr.s_addr,
+                           sizeof(PDU->agent_addr.sin_addr.s_addr));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* generic trap */
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        (int *)&PDU->trap_type, sizeof(PDU->trap_type));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* specific trap */
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        (int *)&PDU->specific_type, 
+                        sizeof(PDU->specific_type));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* timestamp */
+    bufp = asn_build_unsigned_int(bufp, DestBufLen,
+                                 (u_char)(SMI_TIMETICKS | ASN_PRIMITIVE),
+                                 &PDU->time, sizeof(PDU->time));
+    if (bufp == NULL)
+      return(NULL);
+    break;
+
+    /**********************************************************************/
+
+  case SNMP_PDU_GETBULK:
+
+    /* SNMPv2 Bulk Request */
+
+    /* request id */
+    bufp = asn_build_int(DestBuf, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->reqid, sizeof(PDU->reqid));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* non-repeaters */
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->non_repeaters, 
+                        sizeof(PDU->non_repeaters));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* max-repetitions */
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->max_repetitions,
+                        sizeof(PDU->max_repetitions));
+    if (bufp == NULL)
+      return(NULL);
+    break;
+
+    /**********************************************************************/
+
+  default:
+
+    /* Normal PDU Encoding */
+
+    /* request id */
+#ifdef DEBUG_PDU_ENCODE
+    snmplib_debug(8,"PDU: Request ID %d (0x%x)\n", PDU->reqid, DestBuf);
+#endif
+    bufp = asn_build_int(DestBuf, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->reqid, sizeof(PDU->reqid));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* error status */
+#ifdef DEBUG_PDU_ENCODE
+    snmplib_debug(8,"PDU: Error Status %d (0x%x)\n", PDU->errstat, bufp);
+#endif
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->errstat, sizeof(PDU->errstat));
+    if (bufp == NULL)
+      return(NULL);
+
+    /* error index */
+#ifdef DEBUG_PDU_ENCODE
+    snmplib_debug(8,"PDU: Error index %d (0x%x)\n", PDU->errindex, bufp);
+#endif
+    bufp = asn_build_int(bufp, DestBufLen,
+                        (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+                        &PDU->errindex, sizeof(PDU->errindex));
+    if (bufp == NULL)
+      return(NULL);
+    break;
+  } /* End of encoding */
+
+  return(bufp);
+}
+
+/**********************************************************************/
+
+/* Decodes PDU from Packet into PDU.
+ *
+ * Returns a pointer to the next byte of the packet, which is where the
+ * Variable Bindings start.
+ */
+u_char *snmp_pdu_decode(u_char *Packet,       /* data */
+                       int *Length,          /* &length */
+                       struct snmp_pdu *PDU) /* pdu */
+{
+  u_char *bufp;
+  u_char PDUType;
+  int four;
+  u_char ASNType;
+  oid objid[MAX_NAME_LEN];
+
+  bufp = asn_parse_header(Packet, Length, &PDUType);
+  if (bufp == NULL)
+    ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+  snmplib_debug(8,"PDU Type: %d\n", PDUType);
+#endif
+
+  PDU->command = PDUType;
+  switch (PDUType) {
+
+  case TRP_REQ_MSG:
+
+    /* SNMPv1 Trap Message */
+
+    /* enterprise */
+    PDU->enterprise_length = MAX_NAME_LEN;
+    bufp = asn_parse_objid(bufp, Length,
+                          &ASNType, objid, &PDU->enterprise_length);
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    PDU->enterprise = (oid *)xmalloc(PDU->enterprise_length * sizeof(oid));
+    if (PDU->enterprise == NULL) {
+      snmp_set_api_error(SNMPERR_OS_ERR);
+      return(NULL);
+    }
+
+    xmemcpy((char *)PDU->enterprise, (char *)objid, 
+          PDU->enterprise_length * sizeof(oid));
+       
+    /* Agent-addr */
+    four = 4;
+    bufp = asn_parse_string(bufp, Length, 
+                           &ASNType, 
+                           (u_char *)&PDU->agent_addr.sin_addr.s_addr, 
+                           &four);
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* Generic trap */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        (int *)&PDU->trap_type, 
+                        sizeof(PDU->trap_type));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* Specific Trap */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        (int *)&PDU->specific_type, 
+                        sizeof(PDU->specific_type));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* Timestamp */
+    bufp = asn_parse_unsigned_int(bufp, Length, 
+                                 &ASNType, 
+                                 &PDU->time, sizeof(PDU->time));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+    break;
+
+    /**********************************************************************/
+
+  case SNMP_PDU_GETBULK:
+
+    /* SNMPv2 Bulk Request */
+
+    /* request id */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->reqid, sizeof(PDU->reqid));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* non-repeaters */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->non_repeaters, sizeof(PDU->non_repeaters));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* max-repetitions */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->max_repetitions, sizeof(PDU->max_repetitions));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    break;
+    /**********************************************************************/
+
+  default:
+
+    /* Normal PDU Encoding */
+
+    /* request id */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->reqid, sizeof(PDU->reqid));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+    snmplib_debug(8,"PDU Request ID: %d\n", PDU->reqid);
+#endif
+
+    /* error status */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->errstat, sizeof(PDU->errstat));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+    snmplib_debug(8,"PDU Error Status: %d\n", PDU->errstat);
+#endif
+
+    /* error index */
+    bufp = asn_parse_int(bufp, Length, 
+                        &ASNType, 
+                        &PDU->errindex, sizeof(PDU->errindex));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+#ifdef DEBUG_PDU_DECODE
+    snmplib_debug(8,"PDU Error Index: %d\n", PDU->errindex);
+#endif
+
+    break;
+  }
+
+  return(bufp);
+}
+
+
+char *snmp_pdu_type(struct snmp_pdu *PDU)
+{
+  switch(PDU->command) {
+  case SNMP_PDU_GET:
+    return("GET");
+    break;
+  case SNMP_PDU_GETNEXT:
+    return("GETNEXT");
+    break;
+  case SNMP_PDU_RESPONSE:
+    return("RESPONSE");
+    break;
+  case SNMP_PDU_SET:
+    return("SET");
+    break;
+  case SNMP_PDU_GETBULK:
+    return("GETBULK");
+    break;
+  case SNMP_PDU_INFORM:
+    return("INFORM");
+    break;
+  case SNMP_PDU_V2TRAP:
+    return("V2TRAP");
+    break;
+  case SNMP_PDU_REPORT:
+    return("REPORT");
+    break;
+    
+  case TRP_REQ_MSG:
+    return("V1TRAP");
+    break;
+  default:
+    return("Unknown");
+    break;
+  }
+}
+
+/*
+ * Add a null variable with the requested name to the end of the list of
+ * variables for this pdu.
+ */
+void snmp_add_null_var(struct snmp_pdu *pdu, oid *name, int name_length)
+{
+  struct variable_list *vars;
+  struct variable_list *ptr;
+
+  vars = snmp_var_new(name, name_length);
+  if (vars == NULL) {
+    perror("snmp_add_null_var:xmalloc");
+    return;
+  }
+
+  if (pdu->variables == NULL) {
+    pdu->variables = vars;
+  } else {
+
+    /* Insert at the end */
+    for (ptr = pdu->variables; 
+        ptr->next_variable; 
+        ptr = ptr->next_variable)
+      /*EXIT*/;
+    ptr->next_variable = vars;
+  }
+
+  return;
+}
+
diff --git a/snmplib/snmp_vars.c b/snmplib/snmp_vars.c
new file mode 100644 (file)
index 0000000..61ef2f0
--- /dev/null
@@ -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 <ryan+@andrew.cmu.edu>
+ * 
+ **********************************************************************/
+
+#include "config.h"
+
+#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_GNUMALLOC_H
+#include <gnumalloc.h>
+#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
+#include <malloc.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#if HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "snmp.h"
+#include "asn1.h"
+#include "snmp_vars.h"
+#include "mibii.h"
+#include "snmp_api_error.h"
+#include "snmp_pdu.h"
+#include "snmp_msg.h"
+
+#include "util.h"
+
+
+/* #define DEBUG_VARS 1 */
+/* #define DEBUG_VARS_MALLOC 1 */
+/* #define DEBUG_VARS_DECODE 1 */
+/* #define DEBUG_VARS_ENCODE 1 */
+
+#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
+
+/* Create a new variable_list structure representing oid Name of length Len.
+ *
+ * Returns NULL upon error.
+ */
+
+struct variable_list *snmp_var_new(oid *Name, int Len)
+{
+  struct variable_list *New;
+
+#ifdef DEBUG_VARS
+  printf("VARS: Creating.\n");
+#endif
+
+  New = (struct variable_list *)xmalloc(sizeof(struct variable_list));
+  if (New == NULL) {
+    snmp_set_api_error(SNMPERR_OS_ERR);
+    return(NULL);
+  }
+  memset(New, '\0', sizeof(struct variable_list));
+  /*  New->next_variable = NULL; */
+
+  New->type = ASN_NULL;
+  New->name_length = Len;
+
+  if (New->name_length == 0) {
+    New->name = NULL;
+    return(New);
+  }
+
+  New->name = (oid *)xmalloc(Len * sizeof(oid));
+  if (New->name == NULL) {
+    xfree(New);
+    snmp_set_api_error(SNMPERR_OS_ERR);
+    return(NULL);
+  }
+
+#ifdef DEBUG_VARS
+  printf("VARS: Copying name, size (%d)\n", Len);
+#endif
+
+  /* Only copy a name if it was specified. */
+  if (Name)
+    xmemcpy((char *)New->name, (char *)Name, Len * sizeof(oid));
+  
+  /*  New->val.string = NULL; */
+  /*  New->val_len = 0; */
+
+#ifdef DEBUG_VARS
+  printf("VARS: Created %x.\n", (unsigned int)New);
+#endif
+
+#ifdef DEBUG_VARS_MALLOC
+  printf("VARS: Created (%x)\n", (unsigned int)New);
+  printf("VARS: Name is (%x)\n", (unsigned int)New->name);
+#endif
+  return(New);
+}
+
+/* Clone a variable list.
+ *
+ * Returns NULL upon error.
+ */
+
+struct variable_list *snmp_var_clone(struct variable_list *Src)
+{
+  struct variable_list *Dest;
+
+#ifdef DEBUG_VARS
+  printf("VARS: Cloning.\n");
+#endif
+
+  Dest = (struct variable_list *)xmalloc(sizeof(struct variable_list));
+  if (Dest == NULL) {
+    snmp_set_api_error(SNMPERR_OS_ERR);
+    return(NULL);
+  }
+
+#ifdef DEBUG_VARS
+  printf("VARS: Copying entire variable list.  (Size %d)\n",
+        sizeof(struct variable_list));
+#endif
+
+  xmemcpy((char *)Dest, (char *)Src, sizeof(struct variable_list));
+
+  if (Src->name != NULL){
+    Dest->name = (oid *)xmalloc(Src->name_length * sizeof(oid));
+    if (Dest->name == NULL) {
+      snmp_set_api_error(SNMPERR_OS_ERR);
+      xfree(Dest);
+      return(NULL);
+    }
+#ifdef DEBUG_VARS
+    printf("VARS: Copying name OID. (Size %d)\n", Src->name_length);
+#endif
+    xmemcpy((char *)Dest->name, (char *)Src->name,
+          Src->name_length * sizeof(oid));
+  }
+
+  /* CISCO Catalyst 2900 returns NULL strings as data of length 0. */
+  if ((Src->val.string != NULL) &&
+      (Src->val_len)) {
+    Dest->val.string = (u_char *)xmalloc(Src->val_len);
+    if (Dest->val.string == NULL) {
+      snmp_set_api_error(SNMPERR_OS_ERR);
+      xfree(Dest->name);
+      xfree(Dest);
+      return(NULL);
+    }
+
+#ifdef DEBUG_VARS
+    printf("VARS: Copying value (Size %d)\n", Src->val_len);
+#endif
+    xmemcpy((char *)Dest->val.string, (char *)Src->val.string, Src->val_len);
+  }
+
+#ifdef DEBUG_VARS
+  printf("VARS: Cloned %x.\n", (unsigned int)Dest);
+#endif
+#ifdef DEBUG_VARS_MALLOC
+  printf("VARS: Cloned  (%x)\n", (unsigned int)Dest);
+  printf("VARS: Name is (%x)\n", (unsigned int)Dest->name);
+#endif
+
+  return(Dest);
+}
+
+/* Free a variable_list.
+ */
+void snmp_var_free(struct variable_list *Ptr)
+{
+#ifdef DEBUG_VARS_MALLOC
+  printf("VARS: Free'd  (%x)\n", (unsigned int)Ptr);
+  printf("VARS: Name was(%x)\n", (unsigned int)Ptr->name);
+#endif
+
+  if (Ptr->name && Ptr->name_length > 0)
+    xfree((char *) Ptr->name);
+
+  if (Ptr->val.string && Ptr->val_len > 0)
+    xfree((char *) Ptr->val.string);
+
+  xfree(Ptr);
+}
+
+/**********************************************************************/
+
+/* Build a variable binding.
+ *
+ * RFC 1905: Protocol Operations for SNMPv2
+ *
+ * VarBind ::= 
+ *   SEQUENCE {
+ *     name ObjectName
+ *     CHOICE {
+ *       value ObjectSyntax
+ *       unSpecified NULL
+ *       noSuchObject[0] NULL
+ *       noSuchInstance[1] NULL
+ *       endOfMibView[2] NULL
+ *     }
+ *   }
+ */
+u_char *snmp_var_EncodeVarBind(u_char *Buffer, int *BufLenP,
+                              struct variable_list *VarList,
+                              int Version)
+{
+  struct variable_list *Vars;
+  u_char *bufp;
+  u_char *HeaderStart;
+  u_char *HeaderEnd;
+  int FakeArg = *BufLenP;
+#ifdef DEBUG_VARS_ENCODE
+  int StartLen = *BufLenP;
+  int Counter = 1;
+#endif
+
+  bufp = Buffer;
+
+#ifdef DEBUG_VARS_ENCODE
+  printf("VARS: Encoding Variable list into buffer at 0x%x.\n", Buffer);
+#endif
+
+  for (Vars=VarList; Vars; Vars=Vars->next_variable) {
+
+#ifdef DEBUG_VARS_ENCODE
+    printf("VARS %d: Encoding Variable 0x%x.\n", Counter, Vars);
+    printf("VARS %d: Starting at 0x%x (%d bytes left)\n", 
+          Counter, bufp, *BufLenP);
+#endif
+
+    /* Build the header for this variable
+     *
+     * Use Maximum size.
+     */
+    HeaderStart = bufp;
+    HeaderEnd = asn_build_header(HeaderStart, BufLenP,
+                                (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                                FakeArg);
+    if (HeaderEnd == NULL)
+      return(NULL);
+
+#ifdef DEBUG_VARS_ENCODE
+    printf("VARS %d: Encoding Object Identifier 0x%x (%d bytes) at 0x%x (%d bytes left)\n", 
+          Counter, Vars,
+          Vars->name_length, HeaderEnd, *BufLenP);
+    print_oid(Vars->name, Vars->name_length),
+#endif
+    /* Now, let's put the Object Identifier into the buffer */
+    bufp = asn_build_objid(HeaderEnd, BufLenP,
+                          (u_char)(ASN_UNIVERSAL | 
+                                   ASN_PRIMITIVE | 
+                                   ASN_OBJECT_ID),
+                          Vars->name, Vars->name_length);
+    if (bufp == NULL)
+      return(NULL);
+
+    /* Now put the data in */
+    switch(Vars->type) {
+
+    case ASN_INTEGER:
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding Integer %d at 0x%x\n", Counter,
+            *(Vars->val.integer), bufp);
+#endif
+
+      bufp = asn_build_int(bufp, 
+                          BufLenP, Vars->type,
+                          (int *)Vars->val.integer, Vars->val_len);
+      break;
+
+    case SMI_COUNTER32:
+    case SMI_GAUGE32:
+      /*  case SMI_UNSIGNED32: */
+    case SMI_TIMETICKS:
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding Timeticks %d at 0x%x\n", Counter,
+            *(Vars->val.integer), bufp);
+#endif
+      bufp = asn_build_unsigned_int(bufp, BufLenP, 
+                                   Vars->type,
+                                   (u_int *)Vars->val.integer, Vars->val_len);
+      break;
+
+    case ASN_OCTET_STR:
+    case SMI_IPADDRESS:
+    case SMI_OPAQUE:
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding String %s (%d bytes) at 0x%x\n", Counter,
+            (Vars->val.string), Vars->val_len, bufp);
+#endif
+      bufp = asn_build_string(bufp, BufLenP, Vars->type,
+                             Vars->val.string, Vars->val_len);
+      break;
+
+    case ASN_OBJECT_ID:
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding Object Identifier (%d bytes) at 0x%x\n",
+            Counter,
+            Vars->val_len, bufp);
+#endif
+      bufp = asn_build_objid(bufp, BufLenP, Vars->type,
+                            (oid *)Vars->val.objid, Vars->val_len / sizeof(oid));
+      break;
+
+    case SMI_NOSUCHINSTANCE:
+    case SMI_NOSUCHOBJECT:
+    case SMI_ENDOFMIBVIEW:
+
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding NULL at 0x%x\n", Counter, bufp);
+#endif
+      if (Version == SNMP_VERSION_1) {
+        /* SNMP Version 1 does not support these error codes. */
+       bufp = asn_build_null(bufp, BufLenP, SMI_NOSUCHOBJECT);
+      } else {
+       bufp = asn_build_exception(bufp, BufLenP, Vars->type);
+      }
+      break;
+
+    case ASN_NULL:
+#ifdef DEBUG_VARS_ENCODE
+      printf("VARS %d: Encoding NULL at 0x%x\n", Counter, bufp);
+#endif
+      bufp = asn_build_null(bufp, BufLenP, Vars->type);
+      break;
+
+    case SMI_COUNTER64:
+      snmplib_debug(2, "Unable to encode type SMI_COUNTER64!\n");
+      /* Fall through */
+
+    default:
+      snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
+      return(NULL);
+    }
+
+    /* ASSERT:  bufp should now point to the next valid byte. */
+    if (bufp == NULL)
+      return(NULL);
+
+    /* Rebuild the header with the appropriate length */
+#ifdef DEBUG_VARS_ENCODE
+    printf("VARS %d: Resetting length to %d at 0x%x (%d bytes left)\n",
+          Counter,
+          (bufp - HeaderEnd), HeaderStart, *BufLenP);
+#endif
+    HeaderEnd = asn_build_header(HeaderStart, &FakeArg,
+                                (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 
+                                (bufp - HeaderEnd));
+
+    /* Returns NULL */
+    if (HeaderEnd == NULL)
+      return(NULL);
+
+#ifdef DEBUG_VARS_ENCODE
+    Counter++;
+#endif
+  }
+
+#ifdef DEBUG_VARS_ENCODE
+  printf("VARS: Variable list of %d vars takes up %d bytes.\n",
+        --Counter, StartLen - *BufLenP);
+#endif
+
+  /* or the end of the entire thing */
+  return(bufp);
+}
+
+                             
+
+
+/* Parse all Vars from the buffer */
+u_char *snmp_var_DecodeVarBind(u_char *Buffer, int *BufLen,
+                              struct variable_list **VarP,
+                              int Version)
+{
+  struct variable_list *Var, **VarLastP;
+  u_char *bufp, *tmp;
+  u_char  VarBindType;
+  u_char *DataPtr;
+  int     DataLen;
+  oid TmpBuf[MAX_NAME_LEN];
+
+  int AllVarLen = *BufLen;
+  int ThisVarLen = 0;
+
+  VarLastP = VarP;
+#ifdef DEBUG_VARS_DECODE
+  printf("VARS: Decoding buffer of length %d\n", *BufLen);
+#endif
+
+  /* Now parse the variables */
+  bufp = asn_parse_header(Buffer, &AllVarLen, &VarBindType);
+  if (bufp == NULL)
+    ASN_PARSE_ERROR(NULL);
+
+  if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
+      snmp_set_api_error(SNMPERR_PDU_PARSE);
+      ASN_PARSE_ERROR(NULL);
+  }
+
+#ifdef DEBUG_VARS_DECODE
+  printf("VARS: All Variable length %d\n", AllVarLen);
+#endif
+
+  /* We know how long the variable list is.  Parse it. */
+  while ((int)AllVarLen > 0) {
+
+    /* Create a new variable */
+    Var = snmp_var_new(NULL, MAX_NAME_LEN);
+    if (Var == NULL)
+      return(NULL);
+    
+    /* Parse the header to find out the length of this variable. */
+    ThisVarLen = AllVarLen;
+    tmp = asn_parse_header(bufp, &ThisVarLen, &VarBindType);
+    if (tmp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    /* Now that we know the length , figure out how it relates to 
+     * the entire variable list
+     */
+    AllVarLen = AllVarLen - (ThisVarLen + (tmp - bufp));
+    bufp = tmp;
+
+    /* Is it valid? */
+    if (VarBindType != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
+      snmp_set_api_error(SNMPERR_PDU_PARSE);
+      ASN_PARSE_ERROR(NULL);
+    }
+
+#ifdef DEBUG_VARS_DECODE
+    printf("VARS: Header type 0x%x (%d bytes left)\n", VarBindType, ThisVarLen);
+#endif
+
+    /* Parse the OBJID */
+    bufp = asn_parse_objid(bufp, &ThisVarLen, &VarBindType, 
+                          Var->name, &(Var->name_length));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+
+    if (VarBindType != (u_char)(ASN_UNIVERSAL | 
+                               ASN_PRIMITIVE | 
+                               ASN_OBJECT_ID)) {
+      snmp_set_api_error(SNMPERR_PDU_PARSE);
+      ASN_PARSE_ERROR(NULL);
+    }
+
+#ifdef DEBUG_VARS_DECODE
+    printf("VARS: Decoded OBJID (%d bytes). (%d bytes left)\n", 
+          Var->name_length, ThisVarLen);
+#endif
+
+    /* Keep a pointer to this object */
+    DataPtr = bufp;
+    DataLen = ThisVarLen;
+
+    /* find out type of object */
+    bufp = asn_parse_header(bufp, &ThisVarLen, &(Var->type));
+    if (bufp == NULL)
+      ASN_PARSE_ERROR(NULL);
+    ThisVarLen = DataLen;
+
+#ifdef DEBUG_VARS_DECODE
+    printf("VARS: Data type %d\n", Var->type);
+#endif
+
+    /* Parse the type */
+    
+    switch((short)Var->type){
+
+    case ASN_INTEGER:
+      Var->val.integer = (int *)xmalloc(sizeof(int));
+      if (Var->val.integer == NULL) {
+       snmp_set_api_error(SNMPERR_OS_ERR);
+       return(NULL);
+      }
+      Var->val_len = sizeof(int);
+      bufp = asn_parse_int(DataPtr, &ThisVarLen, 
+                          &Var->type, (int *)Var->val.integer, 
+                          Var->val_len);
+#ifdef DEBUG_VARS_DECODE
+      printf("VARS: Decoded integer '%d' (%d bytes left)\n",
+            *(Var->val.integer), ThisVarLen);
+#endif
+      break;
+
+    case SMI_COUNTER32:
+    case SMI_GAUGE32:
+      /*  case SMI_UNSIGNED32: */
+    case SMI_TIMETICKS:
+      Var->val.integer = (int *)xmalloc(sizeof(u_int));
+      if (Var->val.integer == NULL) {
+       snmp_set_api_error(SNMPERR_OS_ERR);
+       return(NULL);
+      }
+      Var->val_len = sizeof(u_int);
+      bufp = asn_parse_unsigned_int(DataPtr, &ThisVarLen, 
+                                   &Var->type, (u_int *)Var->val.integer, 
+                                   Var->val_len);
+#ifdef DEBUG_VARS_DECODE
+      printf("VARS: Decoded timeticks '%d' (%d bytes left)\n",
+            *(Var->val.integer), ThisVarLen);
+#endif
+      break;
+
+    case ASN_OCTET_STR:
+    case SMI_IPADDRESS:
+    case SMI_OPAQUE:
+      Var->val_len = *&ThisVarLen; /* String is this at most */
+      Var->val.string = (u_char *)xmalloc((unsigned)Var->val_len);
+      if (Var->val.string == NULL) {
+       snmp_set_api_error(SNMPERR_OS_ERR);
+       return(NULL);
+      }
+      bufp = asn_parse_string(DataPtr, &ThisVarLen, 
+                             &Var->type, Var->val.string, 
+                             &Var->val_len);
+#ifdef DEBUG_VARS_DECODE
+      printf("VARS: Decoded string '%s' (length %d) (%d bytes left)\n",
+            (Var->val.string), Var->val_len, ThisVarLen);
+#endif
+      break;
+         
+    case ASN_OBJECT_ID:
+      Var->val_len = MAX_NAME_LEN;
+      bufp = asn_parse_objid(DataPtr, &ThisVarLen, 
+                            &Var->type, TmpBuf, &Var->val_len);
+      Var->val_len *= sizeof(oid);
+      Var->val.objid = (oid *)xmalloc((unsigned)Var->val_len);
+      if (Var->val.integer == NULL) {
+       snmp_set_api_error(SNMPERR_OS_ERR);
+       return(NULL);
+      }
+      /* Only copy if we successfully decoded something */
+      if (bufp) {
+       xmemcpy((char *)Var->val.objid, (char *)TmpBuf, Var->val_len);
+      }
+#ifdef DEBUG_VARS_DECODE
+      printf("VARS: Decoded OBJID (length %d) (%d bytes left)\n",
+             Var->val_len, ThisVarLen);
+#endif
+      break;
+
+    case ASN_NULL:
+    case SMI_NOSUCHINSTANCE:
+    case SMI_NOSUCHOBJECT:
+    case SMI_ENDOFMIBVIEW:
+      break;
+
+    case SMI_COUNTER64:
+      snmplib_debug(2, "Unable to parse type SMI_COUNTER64!\n");
+      snmp_set_api_error(SNMPERR_UNSUPPORTED_TYPE);
+      return(NULL);
+      break;
+
+    default:
+      snmplib_debug(2, "bad type returned (%x)\n", Var->type);
+      snmp_set_api_error(SNMPERR_PDU_PARSE);
+      return(NULL);
+      break;
+    } /* End of var type switch */
+
+    if (bufp == NULL)
+      return(NULL);
+
+#ifdef DEBUG_VARS_DECODE
+    printf("VARS:  Adding to list.\n");
+#endif
+    /* Add variable to the list */
+    *VarLastP = Var;
+    VarLastP = &(Var->next_variable);
+  }
+
+  return(bufp);
+}