net-snmp 5.7
asn1.c
00001 /*
00002  * Abstract Syntax Notation One, ASN.1
00003  * As defined in ISO/IS 8824 and ISO/IS 8825
00004  * This implements a subset of the above International Standards that
00005  * is sufficient to implement SNMP.
00006  *
00007  * Encodes abstract data types into a machine independent stream of bytes.
00008  *
00009  */
00010 /**********************************************************************
00011         Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
00012 
00013                       All Rights Reserved
00014 
00015 Permission to use, copy, modify, and distribute this software and its 
00016 documentation for any purpose and without fee is hereby granted, 
00017 provided that the above copyright notice appear in all copies and that
00018 both that copyright notice and this permission notice appear in 
00019 supporting documentation, and that the name of CMU not be
00020 used in advertising or publicity pertaining to distribution of the
00021 software without specific, written prior permission.  
00022 
00023 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00024 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00025 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00026 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00027 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00028 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00029 SOFTWARE.
00030 ******************************************************************/
00156 #include <net-snmp/net-snmp-config.h>
00157 
00158 #ifdef KINETICS
00159 #include "gw.h"
00160 #endif
00161 
00162 #if HAVE_STRING_H
00163 #include <string.h>
00164 #else
00165 #include <strings.h>
00166 #endif
00167 
00168 #include <sys/types.h>
00169 #include <stdio.h>
00170 #ifdef HAVE_STDLIB_H
00171 #include <stdlib.h>
00172 #endif
00173 #if HAVE_NETINET_IN_H
00174 #include <netinet/in.h>
00175 #endif
00176 
00177 #ifdef vms
00178 #include <in.h>
00179 #endif
00180 
00181 #if HAVE_DMALLOC_H
00182 #include <dmalloc.h>
00183 #endif
00184 
00185 #include <net-snmp/output_api.h>
00186 #include <net-snmp/utilities.h>
00187 
00188 #include <net-snmp/library/asn1.h>
00189 #include <net-snmp/library/int64.h>
00190 #include <net-snmp/library/mib.h>
00191 
00192 #ifndef NULL
00193 #define NULL    0
00194 #endif
00195 
00196 #include <net-snmp/library/snmp_api.h>
00197 
00198 #ifndef INT32_MAX
00199 #   define INT32_MAX 2147483647
00200 #endif
00201 
00202 #ifndef INT32_MIN
00203 #   define INT32_MIN (0 - INT32_MAX - 1)
00204 #endif
00205 
00206 
00207 #if SIZEOF_LONG == 4
00208 #  define CHECK_OVERFLOW_S(x,y)
00209 #  define CHECK_OVERFLOW_U(x,y)
00210 #else
00211 #  define CHECK_OVERFLOW_S(x,y) do {                                    \
00212         if (x > INT32_MAX) {                                            \
00213             DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
00214             x &= 0xffffffff;                                            \
00215         } else if (x < INT32_MIN) {                                     \
00216             DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
00217             x = 0 - (x & 0xffffffff);                                   \
00218         }                                                               \
00219     } while(0)
00220 
00221 #  define CHECK_OVERFLOW_U(x,y) do {                                    \
00222         if (x > UINT32_MAX) {                                           \
00223             x &= 0xffffffff;                                            \
00224             DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
00225         }                                                               \
00226     } while(0)
00227 #endif
00228 
00237 static
00238     void
00239 _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
00240 {
00241     char            ebuf[128];
00242 
00243     snprintf(ebuf, sizeof(ebuf),
00244             "%s size %lu: s/b %lu", str,
00245             (unsigned long)wrongsize, (unsigned long)rightsize);
00246     ebuf[ sizeof(ebuf)-1 ] = 0;
00247     ERROR_MSG(ebuf);
00248 }
00249 
00257 static
00258     void
00259 _asn_type_err(const char *str, int wrongtype)
00260 {
00261     char            ebuf[128];
00262 
00263     snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
00264     ebuf[ sizeof(ebuf)-1 ] = 0;
00265     ERROR_MSG(ebuf);
00266 }
00267 
00276 static
00277     void
00278 _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
00279 {
00280     char            ebuf[128];
00281 
00282     snprintf(ebuf, sizeof(ebuf),
00283             "%s length %lu too large: exceeds %lu", str,
00284             (unsigned long)wrongsize, (unsigned long)rightsize);
00285     ebuf[ sizeof(ebuf)-1 ] = 0;
00286     ERROR_MSG(ebuf);
00287 }
00288 
00301 static
00302     int
00303 _asn_parse_length_check(const char *str,
00304                         const u_char * bufp, const u_char * data,
00305                         u_long plen, size_t dlen)
00306 {
00307     char            ebuf[128];
00308     size_t          header_len;
00309 
00310     if (bufp == NULL) {
00311         /*
00312          * error message is set 
00313          */
00314         return 1;
00315     }
00316     header_len = bufp - data;
00317     if (plen > 0x7fffffff || header_len > 0x7fffffff ||
00318         ((size_t) plen + header_len) > dlen) {
00319         snprintf(ebuf, sizeof(ebuf),
00320                 "%s: message overflow: %d len + %d delta > %d len",
00321                 str, (int) plen, (int) header_len, (int) dlen);
00322         ebuf[ sizeof(ebuf)-1 ] = 0;
00323         ERROR_MSG(ebuf);
00324         return 1;
00325     }
00326     return 0;
00327 }
00328 
00329 
00341 static
00342     int
00343 _asn_build_header_check(const char *str, const u_char * data,
00344                         size_t datalen, size_t typedlen)
00345 {
00346     char            ebuf[128];
00347 
00348     if (data == NULL) {
00349         /*
00350          * error message is set 
00351          */
00352         return 1;
00353     }
00354     if (datalen < typedlen) {
00355         snprintf(ebuf, sizeof(ebuf),
00356                 "%s: bad header, length too short: %lu < %lu", str,
00357                 (unsigned long)datalen, (unsigned long)typedlen);
00358         ebuf[ sizeof(ebuf)-1 ] = 0;
00359         ERROR_MSG(ebuf);
00360         return 1;
00361     }
00362     return 0;
00363 }
00364 
00376 static
00377     int
00378 _asn_realloc_build_header_check(const char *str,
00379                                 u_char ** pkt,
00380                                 const size_t * pkt_len, size_t typedlen)
00381 {
00382     char            ebuf[128];
00383 
00384     if (pkt == NULL || *pkt == NULL) {
00385         /*
00386          * Error message is set.  
00387          */
00388         return 1;
00389     }
00390 
00391     if (*pkt_len < typedlen) {
00392         snprintf(ebuf, sizeof(ebuf),
00393                 "%s: bad header, length too short: %lu < %lu", str,
00394                 (unsigned long)*pkt_len, (unsigned long)typedlen);
00395         ebuf[ sizeof(ebuf)-1 ] = 0;
00396         ERROR_MSG(ebuf);
00397         return 1;
00398     }
00399     return 0;
00400 }
00401 
00411 int
00412 asn_check_packet(u_char * pkt, size_t len)
00413 {
00414     u_long          asn_length;
00415 
00416     if (len < 2)
00417         return 0;               /* always too short */
00418 
00419     if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
00420         return -1;              /* wrong type */
00421 
00422     if (*(pkt + 1) & 0x80) {
00423         /*
00424          * long length 
00425          */
00426         if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
00427             return 0;           /* still to short, incomplete length */
00428         asn_parse_length(pkt + 1, &asn_length);
00429         return (asn_length + 2 + (*(pkt + 1) & ~0x80));
00430     } else {
00431         /*
00432          * short length 
00433          */
00434         return (*(pkt + 1) + 2);
00435     }
00436 }
00437 
00438 static
00439     int
00440 _asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
00441 {
00442     char            ebuf[128];
00443 
00444     if (asn_length < 1) {
00445         snprintf(ebuf, sizeof(ebuf),
00446                 "%s: length %d too small", str, (int) asn_length);
00447         ebuf[ sizeof(ebuf)-1 ] = 0;
00448         ERROR_MSG(ebuf);
00449         return 1;
00450     }
00451     /*
00452      * if (datum > 7){
00453      * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
00454      * ERROR_MSG(ebuf);
00455      * return 1;
00456      * }
00457      */
00458     return 0;
00459 }
00460 
00482 u_char         *
00483 asn_parse_int(u_char * data,
00484               size_t * datalength,
00485               u_char * type, long *intp, size_t intsize)
00486 {
00487     /*
00488      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
00489      */
00490     static const char *errpre = "parse int";
00491     register u_char *bufp = data;
00492     u_long          asn_length;
00493     register long   value = 0;
00494 
00495     if (intsize != sizeof(long)) {
00496         _asn_size_err(errpre, intsize, sizeof(long));
00497         return NULL;
00498     }
00499     *type = *bufp++;
00500     if (*type != ASN_INTEGER) {
00501         _asn_type_err(errpre, *type);
00502         return NULL;
00503     }
00504 
00505     bufp = asn_parse_length(bufp, &asn_length);
00506     if (_asn_parse_length_check
00507         (errpre, bufp, data, asn_length, *datalength))
00508         return NULL;
00509 
00510     if ((size_t) asn_length > intsize) {
00511         _asn_length_err(errpre, (size_t) asn_length, intsize);
00512         return NULL;
00513     }
00514 
00515     *datalength -= (int) asn_length + (bufp - data);
00516     if (*bufp & 0x80)
00517         value = -1;             /* integer is negative */
00518 
00519     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
00520 
00521     while (asn_length--)
00522         value = (value << 8) | *bufp++;
00523 
00524     CHECK_OVERFLOW_S(value,1);
00525 
00526     DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value, value));
00527 
00528     *intp = value;
00529     return bufp;
00530 }
00531 
00532 
00554 u_char         *
00555 asn_parse_unsigned_int(u_char * data,
00556                        size_t * datalength,
00557                        u_char * type, u_long * intp, size_t intsize)
00558 {
00559     /*
00560      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
00561      */
00562     static const char *errpre = "parse uint";
00563     register u_char *bufp = data;
00564     u_long          asn_length;
00565     register u_long value = 0;
00566 
00567     if (intsize != sizeof(long)) {
00568         _asn_size_err(errpre, intsize, sizeof(long));
00569         return NULL;
00570     }
00571     *type = *bufp++;
00572     if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
00573             && *type != ASN_UINTEGER) {
00574         _asn_type_err(errpre, *type);
00575         return NULL;
00576     }
00577     bufp = asn_parse_length(bufp, &asn_length);
00578     if (_asn_parse_length_check
00579         (errpre, bufp, data, asn_length, *datalength))
00580         return NULL;
00581 
00582     if ((asn_length > (intsize + 1)) ||
00583         ((asn_length == intsize + 1) && *bufp != 0x00)) {
00584         _asn_length_err(errpre, (size_t) asn_length, intsize);
00585         return NULL;
00586     }
00587     *datalength -= (int) asn_length + (bufp - data);
00588     if (*bufp & 0x80)
00589         value = ~value;         /* integer is negative */
00590 
00591     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
00592 
00593     while (asn_length--)
00594         value = (value << 8) | *bufp++;
00595 
00596     CHECK_OVERFLOW_U(value,2);
00597 
00598     DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
00599 
00600     *intp = value;
00601     return bufp;
00602 }
00603 
00604 
00628 u_char         *
00629 asn_build_int(u_char * data,
00630            size_t * datalength, u_char type, const long *intp, size_t intsize)
00631 {
00632     /*
00633      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
00634      */
00635     static const char *errpre = "build int";
00636     register long   integer;
00637     register u_long mask;
00638 #ifndef NETSNMP_NO_DEBUGGING
00639     u_char         *initdatap = data;
00640 #endif
00641 
00642     if (intsize != sizeof(long)) {
00643         _asn_size_err(errpre, intsize, sizeof(long));
00644         return NULL;
00645     }
00646     integer = *intp;
00647     CHECK_OVERFLOW_S(integer,3);
00648     /*
00649      * Truncate "unnecessary" bytes off of the most significant end of this
00650      * 2's complement integer.  There should be no sequence of 9
00651      * consecutive 1's or 0's at the most significant end of the
00652      * integer.
00653      */
00654     mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
00655     /*
00656      * mask is 0xFF800000 on a big-endian machine 
00657      */
00658     while ((((integer & mask) == 0) || ((integer & mask) == mask))
00659            && intsize > 1) {
00660         intsize--;
00661         integer <<= 8;
00662     }
00663     data = asn_build_header(data, datalength, type, intsize);
00664     if (_asn_build_header_check(errpre, data, *datalength, intsize))
00665         return NULL;
00666 
00667     *datalength -= intsize;
00668     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
00669     /*
00670      * mask is 0xFF000000 on a big-endian machine 
00671      */
00672     while (intsize--) {
00673         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
00674         integer <<= 8;
00675     }
00676     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
00677     DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp, *intp));
00678     return data;
00679 }
00680 
00681 
00682 
00706 u_char         *
00707 asn_build_unsigned_int(u_char * data,
00708                        size_t * datalength,
00709                        u_char type, const u_long * intp, size_t intsize)
00710 {
00711     /*
00712      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
00713      */
00714     static const char *errpre = "build uint";
00715     register u_long integer;
00716     register u_long mask;
00717     int             add_null_byte = 0;
00718 #ifndef NETSNMP_NO_DEBUGGING
00719     u_char         *initdatap = data;
00720 #endif
00721 
00722     if (intsize != sizeof(long)) {
00723         _asn_size_err(errpre, intsize, sizeof(long));
00724         return NULL;
00725     }
00726     integer = *intp;
00727     CHECK_OVERFLOW_U(integer,4);
00728 
00729     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
00730     /*
00731      * mask is 0xFF000000 on a big-endian machine 
00732      */
00733     if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
00734         /*
00735          * if MSB is set 
00736          */
00737         add_null_byte = 1;
00738         intsize++;
00739     } else {
00740         /*
00741          * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
00742          * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
00743          * integer.
00744          */
00745         mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
00746         /*
00747          * mask is 0xFF800000 on a big-endian machine 
00748          */
00749         while ((((integer & mask) == 0) || ((integer & mask) == mask))
00750                && intsize > 1) {
00751             intsize--;
00752             integer <<= 8;
00753         }
00754     }
00755     data = asn_build_header(data, datalength, type, intsize);
00756     if (_asn_build_header_check(errpre, data, *datalength, intsize))
00757         return NULL;
00758 
00759     *datalength -= intsize;
00760     if (add_null_byte == 1) {
00761         *data++ = '\0';
00762         intsize--;
00763     }
00764     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
00765     /*
00766      * mask is 0xFF000000 on a big-endian machine 
00767      */
00768     while (intsize--) {
00769         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
00770         integer <<= 8;
00771     }
00772     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
00773     DEBUGMSG(("dumpv_send", "  UInteger:\t%ld (0x%.2lX)\n", *intp, *intp));
00774     return data;
00775 }
00776 
00777 
00806 u_char         *
00807 asn_parse_string(u_char * data,
00808                  size_t * datalength,
00809                  u_char * type, u_char * str, size_t * strlength)
00810 {
00811     static const char *errpre = "parse string";
00812     u_char         *bufp = data;
00813     u_long          asn_length;
00814 
00815     *type = *bufp++;
00816     if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
00817             && *type != ASN_NSAP) {
00818         _asn_type_err(errpre, *type);
00819         return NULL;
00820     }
00821 
00822     bufp = asn_parse_length(bufp, &asn_length);
00823     if (_asn_parse_length_check
00824         (errpre, bufp, data, asn_length, *datalength)) {
00825         return NULL;
00826     }
00827 
00828     if (asn_length > *strlength) {
00829         _asn_length_err(errpre, (size_t) asn_length, *strlength);
00830         return NULL;
00831     }
00832 
00833     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
00834 
00835     memmove(str, bufp, asn_length);
00836     if (*strlength > asn_length)
00837         str[asn_length] = 0;
00838     *strlength = asn_length;
00839     *datalength -= asn_length + (bufp - data);
00840 
00841     DEBUGIF("dumpv_recv") {
00842         u_char         *buf = (u_char *) malloc(1 + asn_length);
00843         size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
00844 
00845         if (sprint_realloc_asciistring
00846             (&buf, &l, &ol, 1, str, asn_length)) {
00847             DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
00848         } else {
00849             if (buf == NULL) {
00850                 DEBUGMSG(("dumpv_recv", "  String:\t[TRUNCATED]\n"));
00851             } else {
00852                 DEBUGMSG(("dumpv_recv", "  String:\t%s [TRUNCATED]\n",
00853                           buf));
00854             }
00855         }
00856         if (buf != NULL) {
00857             free(buf);
00858         }
00859     }
00860 
00861     return bufp + asn_length;
00862 }
00863 
00864 
00887 u_char         *
00888 asn_build_string(u_char * data,
00889                  size_t * datalength,
00890                  u_char type, const u_char * str, size_t strlength)
00891 {
00892     /*
00893      * ASN.1 octet string ::= primstring | cmpdstring
00894      * primstring ::= 0x04 asnlength byte {byte}*
00895      * cmpdstring ::= 0x24 asnlength string {string}*
00896      * This code will never send a compound string.
00897      */
00898 #ifndef NETSNMP_NO_DEBUGGING
00899     u_char         *initdatap = data;
00900 #endif
00901     data = asn_build_header(data, datalength, type, strlength);
00902     if (_asn_build_header_check
00903         ("build string", data, *datalength, strlength))
00904         return NULL;
00905 
00906     if (strlength) {
00907         if (str == NULL) {
00908             memset(data, 0, strlength);
00909         } else {
00910             memmove(data, str, strlength);
00911         }
00912     }
00913     *datalength -= strlength;
00914     DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
00915     DEBUGIF("dumpv_send") {
00916         u_char         *buf = (u_char *) malloc(1 + strlength);
00917         size_t          l = (buf != NULL) ? (1 + strlength) : 0, ol = 0;
00918 
00919         if (sprint_realloc_asciistring
00920             (&buf, &l, &ol, 1, str, strlength)) {
00921             DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
00922         } else {
00923             if (buf == NULL) {
00924                 DEBUGMSG(("dumpv_send", "  String:\t[TRUNCATED]\n"));
00925             } else {
00926                 DEBUGMSG(("dumpv_send", "  String:\t%s [TRUNCATED]\n",
00927                           buf));
00928             }
00929         }
00930         if (buf != NULL) {
00931             free(buf);
00932         }
00933     }
00934     return data + strlength;
00935 }
00936 
00937 
00938 
00958 u_char         *
00959 asn_parse_header(u_char * data, size_t * datalength, u_char * type)
00960 {
00961     register u_char *bufp;
00962     u_long          asn_length;
00963 
00964     if (!data || !datalength || !type) {
00965         ERROR_MSG("parse header: NULL pointer");
00966         return NULL;
00967     }
00968     bufp = data;
00969     /*
00970      * this only works on data types < 30, i.e. no extension octets 
00971      */
00972     if (IS_EXTENSION_ID(*bufp)) {
00973         ERROR_MSG("can't process ID >= 30");
00974         return NULL;
00975     }
00976     *type = *bufp;
00977     bufp = asn_parse_length(bufp + 1, &asn_length);
00978 
00979     if (_asn_parse_length_check
00980         ("parse header", bufp, data, asn_length, *datalength))
00981         return NULL;
00982 
00983 #ifdef DUMP_PRINT_HEADERS
00984     DEBUGDUMPSETUP("recv", data, (bufp - data));
00985     DEBUGMSG(("dumpv_recv", "  Header: 0x%.2X, len = %d (0x%X)\n", *data,
00986               asn_length, asn_length));
00987 #else
00988     /*
00989      * DEBUGMSGHEXTLI(("recv",data,(bufp-data)));
00990      * DEBUGMSG(("dumpH_recv","\n"));
00991      */
00992 #endif
00993 
00994 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
00995 
00996     if ((*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
00997 
00998         /*
00999          * check if 64-but counter 
01000          */
01001         switch (*(bufp + 1)) {
01002         case ASN_OPAQUE_COUNTER64:
01003         case ASN_OPAQUE_U64:
01004         case ASN_OPAQUE_FLOAT:
01005         case ASN_OPAQUE_DOUBLE:
01006         case ASN_OPAQUE_I64:
01007             *type = *(bufp + 1);
01008             break;
01009 
01010         default:
01011             /*
01012              * just an Opaque 
01013              */
01014             *datalength = (int) asn_length;
01015             return bufp;
01016         }
01017         /*
01018          * value is encoded as special format 
01019          */
01020         bufp = asn_parse_length(bufp + 2, &asn_length);
01021         if (_asn_parse_length_check("parse opaque header", bufp, data,
01022                                     asn_length, *datalength))
01023             return NULL;
01024     }
01025 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
01026 
01027     *datalength = (int) asn_length;
01028 
01029     return bufp;
01030 }
01031 
01046 u_char         *
01047 asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type,     /* must be this type */
01048                    const char *estr)
01049 {                               /* error message prefix */
01050     data = asn_parse_header(data, datalength, type);
01051     if (data && (*type != expected_type)) {
01052         char            ebuf[128];
01053         snprintf(ebuf, sizeof(ebuf),
01054                  "%s header type %02X: s/b %02X", estr,
01055                 (u_char) * type, (u_char) expected_type);
01056         ebuf[ sizeof(ebuf)-1 ] = 0;
01057         ERROR_MSG(ebuf);
01058         return NULL;
01059     }
01060     return data;
01061 }
01062 
01063 
01064 
01087 u_char         *
01088 asn_build_header(u_char * data,
01089                  size_t * datalength, u_char type, size_t length)
01090 {
01091     char            ebuf[128];
01092 
01093     if (*datalength < 1) {
01094         snprintf(ebuf, sizeof(ebuf),
01095                 "bad header length < 1 :%lu, %lu",
01096                 (unsigned long)*datalength, (unsigned long)length);
01097         ebuf[ sizeof(ebuf)-1 ] = 0;
01098         ERROR_MSG(ebuf);
01099         return NULL;
01100     }
01101     *data++ = type;
01102     (*datalength)--;
01103     return asn_build_length(data, datalength, length);
01104 }
01105 
01129 u_char         *
01130 asn_build_sequence(u_char * data,
01131                    size_t * datalength, u_char type, size_t length)
01132 {
01133     static const char *errpre = "build seq";
01134     char            ebuf[128];
01135 
01136     if (*datalength < 4) {
01137         snprintf(ebuf, sizeof(ebuf),
01138                 "%s: length %d < 4: PUNT", errpre,
01139                 (int) *datalength);
01140         ebuf[ sizeof(ebuf)-1 ] = 0;
01141         ERROR_MSG(ebuf);
01142         return NULL;
01143     }
01144     *datalength -= 4;
01145     *data++ = type;
01146     *data++ = (u_char) (0x02 | ASN_LONG_LEN);
01147     *data++ = (u_char) ((length >> 8) & 0xFF);
01148     *data++ = (u_char) (length & 0xFF);
01149     return data;
01150 }
01151 
01169 u_char         *
01170 asn_parse_length(u_char * data, u_long * length)
01171 {
01172     static const char *errpre = "parse length";
01173     char            ebuf[128];
01174     register u_char lengthbyte;
01175 
01176     if (!data || !length) {
01177         ERROR_MSG("parse length: NULL pointer");
01178         return NULL;
01179     }
01180     lengthbyte = *data;
01181 
01182     if (lengthbyte & ASN_LONG_LEN) {
01183         lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
01184         if (lengthbyte == 0) {
01185             snprintf(ebuf, sizeof(ebuf),
01186                      "%s: indefinite length not supported", errpre);
01187             ebuf[ sizeof(ebuf)-1 ] = 0;
01188             ERROR_MSG(ebuf);
01189             return NULL;
01190         }
01191         if (lengthbyte > sizeof(long)) {
01192             snprintf(ebuf, sizeof(ebuf),
01193                     "%s: data length %d > %lu not supported", errpre,
01194                     lengthbyte, (unsigned long)sizeof(long));
01195             ebuf[ sizeof(ebuf)-1 ] = 0;
01196             ERROR_MSG(ebuf);
01197             return NULL;
01198         }
01199         data++;
01200         *length = 0;            /* protect against short lengths */
01201         while (lengthbyte--) {
01202             *length <<= 8;
01203             *length |= *data++;
01204         }
01205         if ((long) *length < 0) {
01206             snprintf(ebuf, sizeof(ebuf),
01207                      "%s: negative data length %ld\n", errpre,
01208                      (long) *length);
01209             ebuf[ sizeof(ebuf)-1 ] = 0;
01210             ERROR_MSG(ebuf);
01211             return NULL;
01212         }
01213         return data;
01214     } else {                    /* short asnlength */
01215         *length = (long) lengthbyte;
01216         return data + 1;
01217     }
01218 }
01219 
01240 u_char         *
01241 asn_build_length(u_char * data, size_t * datalength, size_t length)
01242 {
01243     static const char *errpre = "build length";
01244     char            ebuf[128];
01245 
01246     u_char         *start_data = data;
01247 
01248     /*
01249      * no indefinite lengths sent 
01250      */
01251     if (length < 0x80) {
01252         if (*datalength < 1) {
01253             snprintf(ebuf, sizeof(ebuf),
01254                     "%s: bad length < 1 :%lu, %lu", errpre,
01255                     (unsigned long)*datalength, (unsigned long)length);
01256             ebuf[ sizeof(ebuf)-1 ] = 0;
01257             ERROR_MSG(ebuf);
01258             return NULL;
01259         }
01260         *data++ = (u_char) length;
01261     } else if (length <= 0xFF) {
01262         if (*datalength < 2) {
01263             snprintf(ebuf, sizeof(ebuf),
01264                     "%s: bad length < 2 :%lu, %lu", errpre,
01265                     (unsigned long)*datalength, (unsigned long)length);
01266             ebuf[ sizeof(ebuf)-1 ] = 0;
01267             ERROR_MSG(ebuf);
01268             return NULL;
01269         }
01270         *data++ = (u_char) (0x01 | ASN_LONG_LEN);
01271         *data++ = (u_char) length;
01272     } else {                    /* 0xFF < length <= 0xFFFF */
01273         if (*datalength < 3) {
01274             snprintf(ebuf, sizeof(ebuf),
01275                     "%s: bad length < 3 :%lu, %lu", errpre,
01276                     (unsigned long)*datalength, (unsigned long)length);
01277             ebuf[ sizeof(ebuf)-1 ] = 0;
01278             ERROR_MSG(ebuf);
01279             return NULL;
01280         }
01281         *data++ = (u_char) (0x02 | ASN_LONG_LEN);
01282         *data++ = (u_char) ((length >> 8) & 0xFF);
01283         *data++ = (u_char) (length & 0xFF);
01284     }
01285     *datalength -= (data - start_data);
01286     return data;
01287 
01288 }
01289 
01315 u_char         *
01316 asn_parse_objid(u_char * data,
01317                 size_t * datalength,
01318                 u_char * type, oid * objid, size_t * objidlength)
01319 {
01320     static const char *errpre = "parse objid";
01321     /*
01322      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
01323      * subidentifier ::= {leadingbyte}* lastbyte
01324      * leadingbyte ::= 1 7bitvalue
01325      * lastbyte ::= 0 7bitvalue
01326      */
01327     register u_char *bufp = data;
01328     register oid   *oidp = objid + 1;
01329     register u_long subidentifier;
01330     register long   length;
01331     u_long          asn_length;
01332     size_t          original_length = *objidlength;
01333 
01334     *type = *bufp++;
01335     if (*type != ASN_OBJECT_ID) {
01336         _asn_type_err(errpre, *type);
01337         return NULL;
01338     }
01339     bufp = asn_parse_length(bufp, &asn_length);
01340     if (_asn_parse_length_check("parse objid", bufp, data,
01341                                 asn_length, *datalength))
01342         return NULL;
01343 
01344     *datalength -= (int) asn_length + (bufp - data);
01345 
01346     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
01347 
01348     /*
01349      * Handle invalid object identifier encodings of the form 06 00 robustly 
01350      */
01351     if (asn_length == 0)
01352         objid[0] = objid[1] = 0;
01353 
01354     length = asn_length;
01355     (*objidlength)--;           /* account for expansion of first byte */
01356 
01357     while (length > 0 && (*objidlength)-- > 0) {
01358         subidentifier = 0;
01359         do {                    /* shift and add in low order 7 bits */
01360             subidentifier =
01361                 (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
01362             length--;
01363         } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
01364 
01365         if (length == 0) {
01366             u_char *last_byte = bufp - 1;
01367             if (*last_byte & ASN_BIT8) {
01368                 /* last byte has high bit set -> wrong BER encoded OID */
01369                 ERROR_MSG("subidentifier syntax error");
01370                 return NULL;
01371             }
01372         }
01373 #if defined(EIGHTBIT_SUBIDS) || (SIZEOF_LONG != 4)
01374         if (subidentifier > (u_long) MAX_SUBID) {
01375             ERROR_MSG("subidentifier too large");
01376             return NULL;
01377         }
01378 #endif
01379         *oidp++ = (oid) subidentifier;
01380     }
01381 
01382     if (0 != length) {
01383         ERROR_MSG("OID length exceeds buffer size");
01384         *objidlength = original_length;
01385         return NULL;
01386     }
01387 
01388     /*
01389      * The first two subidentifiers are encoded into the first component
01390      * with the value (X * 40) + Y, where:
01391      *  X is the value of the first subidentifier.
01392      *  Y is the value of the second subidentifier.
01393      */
01394     subidentifier = (u_long) objid[1];
01395     if (subidentifier == 0x2B) {
01396         objid[0] = 1;
01397         objid[1] = 3;
01398     } else {
01399         if (subidentifier < 40) {
01400             objid[0] = 0;
01401             objid[1] = subidentifier;
01402         } else if (subidentifier < 80) {
01403             objid[0] = 1;
01404             objid[1] = subidentifier - 40;
01405         } else {
01406             objid[0] = 2;
01407             objid[1] = subidentifier - 80;
01408         }
01409     }
01410 
01411     *objidlength = (int) (oidp - objid);
01412 
01413     DEBUGMSG(("dumpv_recv", "  ObjID: "));
01414     DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
01415     DEBUGMSG(("dumpv_recv", "\n"));
01416     return bufp;
01417 }
01418 
01442 u_char         *
01443 asn_build_objid(u_char * data,
01444                 size_t * datalength,
01445                 u_char type, oid * objid, size_t objidlength)
01446 {
01447     /*
01448      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
01449      * subidentifier ::= {leadingbyte}* lastbyte
01450      * leadingbyte ::= 1 7bitvalue
01451      * lastbyte ::= 0 7bitvalue
01452      */
01453     size_t          asnlength;
01454     register oid   *op = objid;
01455     u_char          objid_size[MAX_OID_LEN];
01456     register u_long objid_val;
01457     u_long          first_objid_val;
01458     register int    i;
01459 #ifndef NETSNMP_NO_DEBUGGING
01460     u_char         *initdatap = data;
01461 #endif
01462 
01463     /*
01464      * check if there are at least 2 sub-identifiers 
01465      */
01466     if (objidlength == 0) {
01467         /*
01468          * there are not, so make OID have two with value of zero 
01469          */
01470         objid_val = 0;
01471         objidlength = 2;
01472     } else if (objid[0] > 2) {
01473         ERROR_MSG("build objid: bad first subidentifier");
01474         return NULL;
01475     } else if (objidlength == 1) {
01476         /*
01477          * encode the first value 
01478          */
01479         objid_val = (op[0] * 40);
01480         objidlength = 2;
01481         op++;
01482     } else {
01483         /*
01484          * combine the first two values 
01485          */
01486         if ((op[1] > 40) &&
01487             (op[0] < 2)) {
01488             ERROR_MSG("build objid: bad second subidentifier");
01489             return NULL;
01490         }
01491         objid_val = (op[0] * 40) + op[1];
01492         op += 2;
01493     }
01494     first_objid_val = objid_val;
01495 
01496     /*
01497      * ditch illegal calls now 
01498      */
01499     if (objidlength > MAX_OID_LEN)
01500         return NULL;
01501 
01502     /*
01503      * calculate the number of bytes needed to store the encoded value 
01504      */
01505     for (i = 1, asnlength = 0;;) {
01506 
01507         CHECK_OVERFLOW_U(objid_val,5);
01508         if (objid_val < (unsigned) 0x80) {
01509             objid_size[i] = 1;
01510             asnlength += 1;
01511         } else if (objid_val < (unsigned) 0x4000) {
01512             objid_size[i] = 2;
01513             asnlength += 2;
01514         } else if (objid_val < (unsigned) 0x200000) {
01515             objid_size[i] = 3;
01516             asnlength += 3;
01517         } else if (objid_val < (unsigned) 0x10000000) {
01518             objid_size[i] = 4;
01519             asnlength += 4;
01520         } else {
01521             objid_size[i] = 5;
01522             asnlength += 5;
01523         }
01524         i++;
01525         if (i >= (int) objidlength)
01526             break;
01527         objid_val = *op++;      /* XXX - doesn't handle 2.X (X > 40) */
01528     }
01529 
01530     /*
01531      * store the ASN.1 tag and length 
01532      */
01533     data = asn_build_header(data, datalength, type, asnlength);
01534     if (_asn_build_header_check
01535         ("build objid", data, *datalength, asnlength))
01536         return NULL;
01537 
01538     /*
01539      * store the encoded OID value 
01540      */
01541     for (i = 1, objid_val = first_objid_val, op = objid + 2;
01542          i < (int) objidlength; i++) {
01543         if (i != 1) {
01544             objid_val = *op++;
01545 #if SIZEOF_LONG != 4
01546             if (objid_val > 0xffffffff) /* already logged warning above */
01547                 objid_val &= 0xffffffff;
01548 #endif
01549         }
01550         switch (objid_size[i]) {
01551         case 1:
01552             *data++ = (u_char) objid_val;
01553             break;
01554 
01555         case 2:
01556             *data++ = (u_char) ((objid_val >> 7) | 0x80);
01557             *data++ = (u_char) (objid_val & 0x07f);
01558             break;
01559 
01560         case 3:
01561             *data++ = (u_char) ((objid_val >> 14) | 0x80);
01562             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
01563             *data++ = (u_char) (objid_val & 0x07f);
01564             break;
01565 
01566         case 4:
01567             *data++ = (u_char) ((objid_val >> 21) | 0x80);
01568             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
01569             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
01570             *data++ = (u_char) (objid_val & 0x07f);
01571             break;
01572 
01573         case 5:
01574             *data++ = (u_char) ((objid_val >> 28) | 0x80);
01575             *data++ = (u_char) ((objid_val >> 21 & 0x7f) | 0x80);
01576             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
01577             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
01578             *data++ = (u_char) (objid_val & 0x07f);
01579             break;
01580         }
01581     }
01582 
01583     /*
01584      * return the length and data ptr 
01585      */
01586     *datalength -= asnlength;
01587     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
01588     DEBUGMSG(("dumpv_send", "  ObjID: "));
01589     DEBUGMSGOID(("dumpv_send", objid, objidlength));
01590     DEBUGMSG(("dumpv_send", "\n"));
01591     return data;
01592 }
01593 
01613 u_char         *
01614 asn_parse_null(u_char * data, size_t * datalength, u_char * type)
01615 {
01616     /*
01617      * ASN.1 null ::= 0x05 0x00
01618      */
01619     register u_char *bufp = data;
01620     u_long          asn_length;
01621 
01622     *type = *bufp++;
01623     bufp = asn_parse_length(bufp, &asn_length);
01624     if (bufp == NULL) {
01625         ERROR_MSG("parse null: bad length");
01626         return NULL;
01627     }
01628     if (asn_length != 0) {
01629         ERROR_MSG("parse null: malformed ASN.1 null");
01630         return NULL;
01631     }
01632 
01633     *datalength -= (bufp - data);
01634 
01635     DEBUGDUMPSETUP("recv", data, bufp - data);
01636     DEBUGMSG(("dumpv_recv", "  NULL\n"));
01637 
01638     return bufp + asn_length;
01639 }
01640 
01641 
01662 u_char         *
01663 asn_build_null(u_char * data, size_t * datalength, u_char type)
01664 {
01665     /*
01666      * ASN.1 null ::= 0x05 0x00
01667      */
01668 #ifndef NETSNMP_NO_DEBUGGING
01669     u_char         *initdatap = data;
01670 #endif
01671     data = asn_build_header(data, datalength, type, 0);
01672     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
01673     DEBUGMSG(("dumpv_send", "  NULL\n"));
01674     return data;
01675 }
01676 
01700 u_char         *
01701 asn_parse_bitstring(u_char * data,
01702                     size_t * datalength,
01703                     u_char * type, u_char * str, size_t * strlength)
01704 {
01705     /*
01706      * bitstring ::= 0x03 asnlength unused {byte}*
01707      */
01708     static const char *errpre = "parse bitstring";
01709     register u_char *bufp = data;
01710     u_long          asn_length;
01711 
01712     *type = *bufp++;
01713     if (*type != ASN_BIT_STR) {
01714         _asn_type_err(errpre, *type);
01715         return NULL;
01716     }
01717     bufp = asn_parse_length(bufp, &asn_length);
01718     if (_asn_parse_length_check(errpre, bufp, data,
01719                                 asn_length, *datalength))
01720         return NULL;
01721 
01722     if ((size_t) asn_length > *strlength) {
01723         _asn_length_err(errpre, (size_t) asn_length, *strlength);
01724         return NULL;
01725     }
01726     if (_asn_bitstring_check(errpre, asn_length, *bufp))
01727         return NULL;
01728 
01729     DEBUGDUMPSETUP("recv", data, bufp - data);
01730     DEBUGMSG(("dumpv_recv", "  Bitstring: "));
01731     DEBUGMSGHEX(("dumpv_recv", data, asn_length));
01732     DEBUGMSG(("dumpv_recv", "\n"));
01733 
01734     memmove(str, bufp, asn_length);
01735     *strlength = (int) asn_length;
01736     *datalength -= (int) asn_length + (bufp - data);
01737     return bufp + asn_length;
01738 }
01739 
01740 
01763 u_char         *
01764 asn_build_bitstring(u_char * data,
01765                     size_t * datalength,
01766                     u_char type, const u_char * str, size_t strlength)
01767 {
01768     /*
01769      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
01770      */
01771     static const char *errpre = "build bitstring";
01772     if (_asn_bitstring_check
01773         (errpre, strlength, (u_char)((str) ? *str :  0)))
01774         return NULL;
01775 
01776     data = asn_build_header(data, datalength, type, strlength);
01777     if (_asn_build_header_check(errpre, data, *datalength, strlength))
01778         return NULL;
01779 
01780     if (strlength > 0 && str)
01781         memmove(data, str, strlength);
01782     else if (strlength > 0 && !str) {
01783         ERROR_MSG("no string passed into asn_build_bitstring\n");
01784         return NULL;
01785     }
01786 
01787     *datalength -= strlength;
01788     DEBUGDUMPSETUP("send", data, strlength);
01789     DEBUGMSG(("dumpv_send", "  Bitstring: "));
01790     DEBUGMSGHEX(("dumpv_send", data, strlength));
01791     DEBUGMSG(("dumpv_send", "\n"));
01792     return data + strlength;
01793 }
01794 
01817 u_char         *
01818 asn_parse_unsigned_int64(u_char * data,
01819                          size_t * datalength,
01820                          u_char * type,
01821                          struct counter64 * cp, size_t countersize)
01822 {
01823     /*
01824      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
01825      */
01826     static const char *errpre = "parse uint64";
01827     const int       uint64sizelimit = (4 * 2) + 1;
01828     register u_char *bufp = data;
01829     u_long          asn_length;
01830     register u_long low = 0, high = 0;
01831 
01832     if (countersize != sizeof(struct counter64)) {
01833         _asn_size_err(errpre, countersize, sizeof(struct counter64));
01834         return NULL;
01835     }
01836     *type = *bufp++;
01837     if (*type != ASN_COUNTER64
01838 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
01839             && *type != ASN_OPAQUE_COUNTER64 && *type != ASN_OPAQUE_U64
01840 #endif
01841             ) {
01842         _asn_type_err(errpre, *type);
01843         return NULL;
01844     }
01845     bufp = asn_parse_length(bufp, &asn_length);
01846     if (_asn_parse_length_check
01847         (errpre, bufp, data, asn_length, *datalength))
01848         return NULL;
01849 
01850     DEBUGDUMPSETUP("recv", data, bufp - data);
01851 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
01852     /*
01853      * 64 bit counters as opaque 
01854      */
01855     if ((*type == ASN_OPAQUE) &&
01856         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
01857         (*bufp == ASN_OPAQUE_TAG1) &&
01858         ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
01859          (*(bufp + 1) == ASN_OPAQUE_U64))) {
01860         /*
01861          * change type to Counter64 or U64 
01862          */
01863         *type = *(bufp + 1);
01864         /*
01865          * value is encoded as special format 
01866          */
01867         bufp = asn_parse_length(bufp + 2, &asn_length);
01868         if (_asn_parse_length_check("parse opaque uint64", bufp, data,
01869                                     asn_length, *datalength))
01870             return NULL;
01871     }
01872 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
01873     if (((int) asn_length > uint64sizelimit) ||
01874         (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
01875         _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
01876         return NULL;
01877     }
01878     *datalength -= (int) asn_length + (bufp - data);
01879     while (asn_length--) {
01880         high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
01881         low = ((low & 0x00FFFFFF) << 8) | *bufp++;
01882     }
01883 
01884     CHECK_OVERFLOW_U(high,6);
01885     CHECK_OVERFLOW_U(low,6);
01886 
01887     cp->low = low;
01888     cp->high = high;
01889 
01890     DEBUGIF("dumpv_recv") {
01891         char            i64buf[I64CHARSZ + 1];
01892         printU64(i64buf, cp);
01893         DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
01894     }
01895 
01896     return bufp;
01897 }
01898 
01899 
01921 u_char         *
01922 asn_build_unsigned_int64(u_char * data,
01923                          size_t * datalength,
01924                          u_char type,
01925                          const struct counter64 * cp, size_t countersize)
01926 {
01927     /*
01928      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
01929      */
01930 
01931     register u_long low, high;
01932     register u_long mask, mask2;
01933     int             add_null_byte = 0;
01934     size_t          intsize;
01935 #ifndef NETSNMP_NO_DEBUGGING
01936     u_char         *initdatap = data;
01937 #endif
01938 
01939     if (countersize != sizeof(struct counter64)) {
01940         _asn_size_err("build uint64", countersize,
01941                       sizeof(struct counter64));
01942         return NULL;
01943     }
01944     intsize = 8;
01945     low = cp->low;
01946     high = cp->high;
01947 
01948     CHECK_OVERFLOW_U(high,7);
01949     CHECK_OVERFLOW_U(low,7);
01950 
01951     mask = 0xff000000U;
01952     if (high & 0x80000000U) {
01953         /*
01954          * if MSB is set 
01955          */
01956         add_null_byte = 1;
01957         intsize++;
01958     } else {
01959         /*
01960          * Truncate "unnecessary" bytes off of the most significant end of this 2's
01961          * complement integer.
01962          * There should be no sequence of 9 consecutive 1's or 0's at the most
01963          * significant end of the integer.
01964          */
01965         mask2 = 0xff800000U;
01966         while ((((high & mask2) == 0) || ((high & mask2) == mask2))
01967                && intsize > 1) {
01968             intsize--;
01969             high = ((high & 0x00ffffffu) << 8) | ((low & mask) >> 24);
01970             low = (low & 0x00ffffffu) << 8;
01971         }
01972     }
01973 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
01974     /*
01975      * encode a Counter64 as an opaque (it also works in SNMPv1) 
01976      */
01977     /*
01978      * turn into Opaque holding special tagged value 
01979      */
01980     if (type == ASN_OPAQUE_COUNTER64) {
01981         /*
01982          * put the tag and length for the Opaque wrapper 
01983          */
01984         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
01985         if (_asn_build_header_check
01986             ("build counter u64", data, *datalength, intsize + 3))
01987             return NULL;
01988 
01989         /*
01990          * put the special tag and length 
01991          */
01992         *data++ = ASN_OPAQUE_TAG1;
01993         *data++ = ASN_OPAQUE_COUNTER64;
01994         *data++ = (u_char) intsize;
01995         *datalength = *datalength - 3;
01996     } else
01997         /*
01998          * Encode the Unsigned int64 in an opaque 
01999          */
02000         /*
02001          * turn into Opaque holding special tagged value 
02002          */
02003     if (type == ASN_OPAQUE_U64) {
02004         /*
02005          * put the tag and length for the Opaque wrapper 
02006          */
02007         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
02008         if (_asn_build_header_check
02009             ("build opaque u64", data, *datalength, intsize + 3))
02010             return NULL;
02011 
02012         /*
02013          * put the special tag and length 
02014          */
02015         *data++ = ASN_OPAQUE_TAG1;
02016         *data++ = ASN_OPAQUE_U64;
02017         *data++ = (u_char) intsize;
02018         *datalength = *datalength - 3;
02019     } else {
02020 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
02021         data = asn_build_header(data, datalength, type, intsize);
02022         if (_asn_build_header_check
02023             ("build uint64", data, *datalength, intsize))
02024             return NULL;
02025 
02026 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
02027     }
02028 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
02029     *datalength -= intsize;
02030     if (add_null_byte == 1) {
02031         *data++ = '\0';
02032         intsize--;
02033     }
02034     while (intsize--) {
02035         *data++ = (u_char) (high >> 24);
02036         high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
02037         low = (low & 0x00ffffff) << 8;
02038 
02039     }
02040     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
02041     DEBUGIF("dumpv_send") {
02042         char            i64buf[I64CHARSZ + 1];
02043         printU64(i64buf, cp);
02044         DEBUGMSG(("dumpv_send", "%s", i64buf));
02045     }
02046     return data;
02047 }
02048 
02049 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
02050 
02051 
02075 u_char         *
02076 asn_parse_signed_int64(u_char * data,
02077                        size_t * datalength,
02078                        u_char * type,
02079                        struct counter64 * cp, size_t countersize)
02080 {
02081     static const char *errpre = "parse int64";
02082     const int       int64sizelimit = (4 * 2) + 1;
02083     char            ebuf[128];
02084     register u_char *bufp = data;
02085     u_long          asn_length;
02086     register u_int  low = 0, high = 0;
02087 
02088     if (countersize != sizeof(struct counter64)) {
02089         _asn_size_err(errpre, countersize, sizeof(struct counter64));
02090         return NULL;
02091     }
02092     *type = *bufp++;
02093     bufp = asn_parse_length(bufp, &asn_length);
02094     if (_asn_parse_length_check
02095         (errpre, bufp, data, asn_length, *datalength))
02096         return NULL;
02097 
02098     DEBUGDUMPSETUP("recv", data, bufp - data);
02099     if ((*type == ASN_OPAQUE) &&
02100         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
02101         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
02102         /*
02103          * change type to Int64 
02104          */
02105         *type = *(bufp + 1);
02106         /*
02107          * value is encoded as special format 
02108          */
02109         bufp = asn_parse_length(bufp + 2, &asn_length);
02110         if (_asn_parse_length_check("parse opaque int64", bufp, data,
02111                                     asn_length, *datalength))
02112             return NULL;
02113     }
02114     /*
02115      * this should always have been true until snmp gets int64 PDU types 
02116      */
02117     else {
02118         snprintf(ebuf, sizeof(ebuf),
02119                 "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
02120                 errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
02121         ebuf[ sizeof(ebuf)-1 ] = 0;
02122         ERROR_MSG(ebuf);
02123         return NULL;
02124     }
02125     if (((int) asn_length > int64sizelimit) ||
02126         (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
02127         _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
02128         return NULL;
02129     }
02130     *datalength -= (int) asn_length + (bufp - data);
02131     if (*bufp & 0x80) {
02132         low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
02133         high = 0xFFFFFF;
02134     }
02135 
02136     while (asn_length--) {
02137         high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
02138         low = ((low & 0x00FFFFFF) << 8) | *bufp++;
02139     }
02140 
02141     CHECK_OVERFLOW_U(high,8);
02142     CHECK_OVERFLOW_U(low,8);
02143 
02144     cp->low = low;
02145     cp->high = high;
02146 
02147     DEBUGIF("dumpv_recv") {
02148         char            i64buf[I64CHARSZ + 1];
02149         printI64(i64buf, cp);
02150         DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
02151     }
02152 
02153     return bufp;
02154 }
02155 
02156 
02157 
02179 u_char         *
02180 asn_build_signed_int64(u_char * data,
02181                        size_t * datalength,
02182                        u_char type,
02183                        const struct counter64 * cp, size_t countersize)
02184 {
02185     /*
02186      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
02187      */
02188 
02189     register u_int  mask, mask2;
02190     u_long          low;
02191     long            high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
02192     size_t          intsize;
02193 #ifndef NETSNMP_NO_DEBUGGING
02194     u_char         *initdatap = data;
02195 #endif
02196 
02197     if (countersize != sizeof(struct counter64)) {
02198         _asn_size_err("build int64", countersize,
02199                       sizeof(struct counter64));
02200         return NULL;
02201     }
02202     intsize = 8;
02203     low = cp->low;
02204     high = cp->high; /* unsigned to signed conversion */
02205 
02206     CHECK_OVERFLOW_S(high,9);
02207     CHECK_OVERFLOW_U(low,9);
02208 
02209     /*
02210      * Truncate "unnecessary" bytes off of the most significant end of this
02211      * 2's complement integer.  There should be no sequence of 9
02212      * consecutive 1's or 0's at the most significant end of the
02213      * integer.
02214      */
02215     mask = 0xFF000000U;
02216     mask2 = 0xFF800000U;
02217     while ((((high & mask2) == 0) || ((high & mask2) == mask2))
02218            && intsize > 1) {
02219         intsize--;
02220         high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
02221         low = (low & 0x00ffffff) << 8;
02222     }
02223     /*
02224      * until a real int64 gets incorperated into SNMP, we are going to
02225      * encode it as an opaque instead.  First, we build the opaque
02226      * header and then the int64 tag type we use to mark it as an
02227      * int64 in the opaque string. 
02228      */
02229     data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
02230     if (_asn_build_header_check
02231         ("build int64", data, *datalength, intsize + 3))
02232         return NULL;
02233 
02234     *data++ = ASN_OPAQUE_TAG1;
02235     *data++ = ASN_OPAQUE_I64;
02236     *data++ = (u_char) intsize;
02237     *datalength -= (3 + intsize);
02238 
02239     while (intsize--) {
02240         *data++ = (u_char) (high >> 24);
02241         high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
02242         low = (low & 0x00ffffff) << 8;
02243     }
02244     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
02245     DEBUGIF("dumpv_send") {
02246         char            i64buf[I64CHARSZ + 1];
02247         printU64(i64buf, cp);
02248         DEBUGMSG(("dumpv_send", "%s\n", i64buf));
02249     }
02250     return data;
02251 }
02252 
02253 
02275 u_char         *
02276 asn_parse_float(u_char * data,
02277                 size_t * datalength,
02278                 u_char * type, float *floatp, size_t floatsize)
02279 {
02280     static const char *errpre = "parse float";
02281     register u_char *bufp = data;
02282     u_long          asn_length;
02283     union {
02284         float           floatVal;
02285         long            longVal;
02286         u_char          c[sizeof(float)];
02287     } fu;
02288 
02289     if (floatsize != sizeof(float)) {
02290         _asn_size_err("parse float", floatsize, sizeof(float));
02291         return NULL;
02292     }
02293     *type = *bufp++;
02294     bufp = asn_parse_length(bufp, &asn_length);
02295     if (_asn_parse_length_check("parse float", bufp, data,
02296                                 asn_length, *datalength))
02297         return NULL;
02298 
02299     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
02300     /*
02301      * the float is encoded as an opaque 
02302      */
02303     if ((*type == ASN_OPAQUE) &&
02304         (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
02305         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
02306 
02307         /*
02308          * value is encoded as special format 
02309          */
02310         bufp = asn_parse_length(bufp + 2, &asn_length);
02311         if (_asn_parse_length_check("parse opaque float", bufp, data,
02312                                     asn_length, *datalength))
02313             return NULL;
02314 
02315         /*
02316          * change type to Float 
02317          */
02318         *type = ASN_OPAQUE_FLOAT;
02319     }
02320 
02321     if (*type != ASN_OPAQUE_FLOAT) {
02322         _asn_type_err(errpre, *type);
02323         return NULL;
02324     }
02325 
02326     if (asn_length != sizeof(float)) {
02327         _asn_size_err("parse seq float", asn_length, sizeof(float));
02328         return NULL;
02329     }
02330 
02331     *datalength -= (int) asn_length + (bufp - data);
02332     memcpy(&fu.c[0], bufp, asn_length);
02333 
02334     /*
02335      * correct for endian differences 
02336      */
02337     fu.longVal = ntohl(fu.longVal);
02338 
02339     *floatp = fu.floatVal;
02340 
02341     DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
02342     return bufp;
02343 }
02344 
02368 u_char         *
02369 asn_build_float(u_char * data,
02370                 size_t * datalength,
02371                 u_char type, const float *floatp, size_t floatsize)
02372 {
02373     union {
02374         float           floatVal;
02375         int             intVal;
02376         u_char          c[sizeof(float)];
02377     } fu;
02378 #ifndef NETSNMP_NO_DEBUGGING
02379     u_char         *initdatap = data;
02380 #endif
02381 
02382     if (floatsize != sizeof(float)) {
02383         _asn_size_err("build float", floatsize, sizeof(float));
02384         return NULL;
02385     }
02386     /*
02387      * encode the float as an opaque 
02388      */
02389     /*
02390      * turn into Opaque holding special tagged value 
02391      */
02392 
02393     /*
02394      * put the tag and length for the Opaque wrapper 
02395      */
02396     data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
02397     if (_asn_build_header_check
02398         ("build float", data, *datalength, (floatsize + 3)))
02399         return NULL;
02400 
02401     /*
02402      * put the special tag and length 
02403      */
02404     *data++ = ASN_OPAQUE_TAG1;
02405     *data++ = ASN_OPAQUE_FLOAT;
02406     *data++ = (u_char) floatsize;
02407     *datalength = *datalength - 3;
02408 
02409     fu.floatVal = *floatp;
02410     /*
02411      * correct for endian differences 
02412      */
02413     fu.intVal = htonl(fu.intVal);
02414 
02415     *datalength -= floatsize;
02416     memcpy(data, &fu.c[0], floatsize);
02417 
02418     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
02419     DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
02420     data += floatsize;
02421     return data;
02422 }
02423 
02424 
02446 u_char         *
02447 asn_parse_double(u_char * data,
02448                  size_t * datalength,
02449                  u_char * type, double *doublep, size_t doublesize)
02450 {
02451     static const char *errpre = "parse double";
02452     register u_char *bufp = data;
02453     u_long          asn_length;
02454     long            tmp;
02455     union {
02456         double          doubleVal;
02457         int             intVal[2];
02458         u_char          c[sizeof(double)];
02459     } fu;
02460 
02461 
02462     if (doublesize != sizeof(double)) {
02463         _asn_size_err("parse double", doublesize, sizeof(double));
02464         return NULL;
02465     }
02466     *type = *bufp++;
02467     bufp = asn_parse_length(bufp, &asn_length);
02468     if (_asn_parse_length_check("parse double", bufp, data,
02469                                 asn_length, *datalength))
02470         return NULL;
02471 
02472     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
02473     /*
02474      * the double is encoded as an opaque 
02475      */
02476     if ((*type == ASN_OPAQUE) &&
02477         (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
02478         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
02479 
02480         /*
02481          * value is encoded as special format 
02482          */
02483         bufp = asn_parse_length(bufp + 2, &asn_length);
02484         if (_asn_parse_length_check("parse opaque double", bufp, data,
02485                                     asn_length, *datalength))
02486             return NULL;
02487 
02488         /*
02489          * change type to Double 
02490          */
02491         *type = ASN_OPAQUE_DOUBLE;
02492     }
02493 
02494     if (*type != ASN_OPAQUE_DOUBLE) {
02495         _asn_type_err(errpre, *type);
02496         return NULL;
02497     }
02498 
02499     if (asn_length != sizeof(double)) {
02500         _asn_size_err("parse seq double", asn_length, sizeof(double));
02501         return NULL;
02502     }
02503     *datalength -= (int) asn_length + (bufp - data);
02504     memcpy(&fu.c[0], bufp, asn_length);
02505 
02506     /*
02507      * correct for endian differences 
02508      */
02509 
02510     tmp = ntohl(fu.intVal[0]);
02511     fu.intVal[0] = ntohl(fu.intVal[1]);
02512     fu.intVal[1] = tmp;
02513 
02514     *doublep = fu.doubleVal;
02515     DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
02516 
02517     return bufp;
02518 }
02519 
02520 
02543 u_char         *
02544 asn_build_double(u_char * data,
02545                  size_t * datalength,
02546                  u_char type, const double *doublep, size_t doublesize)
02547 {
02548     long            tmp;
02549     union {
02550         double          doubleVal;
02551         int             intVal[2];
02552         u_char          c[sizeof(double)];
02553     } fu;
02554 #ifndef NETSNMP_NO_DEBUGGING
02555     u_char         *initdatap = data;
02556 #endif
02557 
02558     if (doublesize != sizeof(double)) {
02559         _asn_size_err("build double", doublesize, sizeof(double));
02560         return NULL;
02561     }
02562 
02563     /*
02564      * encode the double as an opaque 
02565      */
02566     /*
02567      * turn into Opaque holding special tagged value 
02568      */
02569 
02570     /*
02571      * put the tag and length for the Opaque wrapper 
02572      */
02573     data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
02574     if (_asn_build_header_check
02575         ("build double", data, *datalength, doublesize + 3))
02576         return NULL;
02577 
02578     /*
02579      * put the special tag and length 
02580      */
02581     *data++ = ASN_OPAQUE_TAG1;
02582     *data++ = ASN_OPAQUE_DOUBLE;
02583     *data++ = (u_char) doublesize;
02584     *datalength = *datalength - 3;
02585 
02586     fu.doubleVal = *doublep;
02587     /*
02588      * correct for endian differences 
02589      */
02590     tmp = htonl(fu.intVal[0]);
02591     fu.intVal[0] = htonl(fu.intVal[1]);
02592     fu.intVal[1] = tmp;
02593     *datalength -= doublesize;
02594     memcpy(data, &fu.c[0], doublesize);
02595 
02596     data += doublesize;
02597     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
02598     DEBUGMSG(("dumpv_send", "  Opaque double: %f\n", *doublep));
02599     return data;
02600 }
02601 
02602 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
02603 
02604 
02619 int
02620 asn_realloc(u_char ** pkt, size_t * pkt_len)
02621 {
02622     if (pkt != NULL && pkt_len != NULL) {
02623         size_t          old_pkt_len = *pkt_len;
02624 
02625         DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %lu\n",
02626                     *pkt, (unsigned long)old_pkt_len));
02627 
02628         if (snmp_realloc(pkt, pkt_len)) {
02629             DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %lu\n",
02630                         *pkt, (unsigned long)*pkt_len));
02631             DEBUGMSGTL(("asn_realloc",
02632                         " memmove(%8p + %08x, %8p, %08x)\n",
02633                         *pkt, (unsigned)(*pkt_len - old_pkt_len),
02634                         *pkt, (unsigned)old_pkt_len));
02635             memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
02636             memset(*pkt, (int) ' ', *pkt_len - old_pkt_len);
02637             return 1;
02638         } else {
02639             DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
02640         }
02641     }
02642     return 0;
02643 }
02644 
02645 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
02646 
02661 int
02662 asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
02663                           size_t * offset, int r, size_t length)
02664 {
02665     static const char *errpre = "build length";
02666     char            ebuf[128];
02667     int             tmp_int;
02668     size_t          start_offset = *offset;
02669 
02670     if (length <= 0x7f) {
02671         if (((*pkt_len - *offset) < 1)
02672             && !(r && asn_realloc(pkt, pkt_len))) {
02673             snprintf(ebuf, sizeof(ebuf),
02674                     "%s: bad length < 1 :%ld, %lu", errpre,
02675                     (long)(*pkt_len - *offset), (unsigned long)length);
02676             ebuf[ sizeof(ebuf)-1 ] = 0;
02677             ERROR_MSG(ebuf);
02678             return 0;
02679         }
02680         *(*pkt + *pkt_len - (++*offset)) = length;
02681     } else {
02682         while (length > 0xff) {
02683             if (((*pkt_len - *offset) < 1)
02684                 && !(r && asn_realloc(pkt, pkt_len))) {
02685                 snprintf(ebuf, sizeof(ebuf),
02686                         "%s: bad length < 1 :%ld, %lu", errpre,
02687                         (long)(*pkt_len - *offset), (unsigned long)length);
02688                 ebuf[ sizeof(ebuf)-1 ] = 0;
02689                 ERROR_MSG(ebuf);
02690                 return 0;
02691             }
02692             *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
02693             length >>= 8;
02694         }
02695 
02696         while ((*pkt_len - *offset) < 2) {
02697             if (!(r && asn_realloc(pkt, pkt_len))) {
02698                 snprintf(ebuf, sizeof(ebuf),
02699                         "%s: bad length < 1 :%ld, %lu", errpre,
02700                         (long)(*pkt_len - *offset), (unsigned long)length);
02701                 ebuf[ sizeof(ebuf)-1 ] = 0;
02702                 ERROR_MSG(ebuf);
02703                 return 0;
02704             }
02705         }
02706 
02707         *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
02708         tmp_int = *offset - start_offset;
02709         *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
02710     }
02711 
02712     return 1;
02713 }
02714 
02732 int
02733 asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
02734                           size_t * offset, int r,
02735                           u_char type, size_t length)
02736 {
02737     char            ebuf[128];
02738 
02739     if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
02740         if (((*pkt_len - *offset) < 1)
02741             && !(r && asn_realloc(pkt, pkt_len))) {
02742             snprintf(ebuf, sizeof(ebuf),
02743                     "bad header length < 1 :%ld, %lu",
02744                     (long)(*pkt_len - *offset), (unsigned long)length);
02745             ebuf[ sizeof(ebuf)-1 ] = 0;
02746             ERROR_MSG(ebuf);
02747             return 0;
02748         }
02749         *(*pkt + *pkt_len - (++*offset)) = type;
02750         return 1;
02751     }
02752     return 0;
02753 }
02754 
02772 int
02773 asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
02774                        size_t * offset, int r,
02775                        u_char type, const long *intp, size_t intsize)
02776 {
02777     static const char *errpre = "build int";
02778     register long   integer = *intp;
02779     int             testvalue;
02780     size_t          start_offset = *offset;
02781 
02782     if (intsize != sizeof(long)) {
02783         _asn_size_err(errpre, intsize, sizeof(long));
02784         return 0;
02785     }
02786 
02787     CHECK_OVERFLOW_S(integer,10);
02788     testvalue = (integer < 0) ? -1 : 0;
02789 
02790     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
02791         return 0;
02792     }
02793     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
02794     integer >>= 8;
02795 
02796     while (integer != testvalue) {
02797         if (((*pkt_len - *offset) < 1)
02798             && !(r && asn_realloc(pkt, pkt_len))) {
02799             return 0;
02800         }
02801         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
02802         integer >>= 8;
02803     }
02804 
02805     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
02806         /*
02807          * Make sure left most bit is representational of the rest of the bits
02808          * that aren't encoded.  
02809          */
02810         if (((*pkt_len - *offset) < 1)
02811             && !(r && asn_realloc(pkt, pkt_len))) {
02812             return 0;
02813         }
02814         *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
02815     }
02816 
02817     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
02818                                   (*offset - start_offset))) {
02819         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
02820                                             (*offset - start_offset))) {
02821             return 0;
02822         } else {
02823             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
02824                            (*offset - start_offset));
02825             DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp,
02826                       *intp));
02827             return 1;
02828         }
02829     }
02830 
02831     return 0;
02832 }
02833 
02852 int
02853 asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
02854                           size_t * offset, int r,
02855                           u_char type,
02856                           const u_char * str, size_t strlength)
02857 {
02858     static const char *errpre = "build string";
02859     size_t          start_offset = *offset;
02860 
02861     while ((*pkt_len - *offset) < strlength) {
02862         if (!(r && asn_realloc(pkt, pkt_len))) {
02863             return 0;
02864         }
02865     }
02866 
02867     *offset += strlength;
02868     memcpy(*pkt + *pkt_len - *offset, str, strlength);
02869 
02870     if (asn_realloc_rbuild_header
02871         (pkt, pkt_len, offset, r, type, strlength)) {
02872         if (_asn_realloc_build_header_check
02873             (errpre, pkt, pkt_len, strlength)) {
02874             return 0;
02875         } else {
02876             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
02877                            *offset - start_offset);
02878             DEBUGIF("dumpv_send") {
02879                 if (strlength == 0) {
02880                     DEBUGMSG(("dumpv_send", "  String: [NULL]\n"));
02881                 } else {
02882                     u_char         *buf = (u_char *) malloc(2 * strlength);
02883                     size_t          l =
02884                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
02885 
02886                     if (sprint_realloc_asciistring
02887                         (&buf, &l, &ol, 1, str, strlength)) {
02888                         DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
02889                     } else {
02890                         if (buf == NULL) {
02891                             DEBUGMSG(("dumpv_send",
02892                                       "  String:\t[TRUNCATED]\n"));
02893                         } else {
02894                             DEBUGMSG(("dumpv_send",
02895                                       "  String:\t%s [TRUNCATED]\n", buf));
02896                         }
02897                     }
02898                     if (buf != NULL) {
02899                         free(buf);
02900                     }
02901                 }
02902             }
02903         }
02904         return 1;
02905     }
02906 
02907     return 0;
02908 }
02909 
02927 int
02928 asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
02929                                 size_t * offset, int r,
02930                             u_char type, const u_long * intp, size_t intsize)
02931 {
02932     static const char *errpre = "build uint";
02933     register u_long integer = *intp;
02934     size_t          start_offset = *offset;
02935 
02936     if (intsize != sizeof(unsigned long)) {
02937         _asn_size_err(errpre, intsize, sizeof(unsigned long));
02938         return 0;
02939     }
02940 
02941     CHECK_OVERFLOW_U(integer,11);
02942 
02943     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
02944         return 0;
02945     }
02946     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
02947     integer >>= 8;
02948 
02949     while (integer != 0) {
02950         if (((*pkt_len - *offset) < 1)
02951             && !(r && asn_realloc(pkt, pkt_len))) {
02952             return 0;
02953         }
02954         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
02955         integer >>= 8;
02956     }
02957 
02958     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
02959         /*
02960          * Make sure left most bit is representational of the rest of the bits
02961          * that aren't encoded.  
02962          */
02963         if (((*pkt_len - *offset) < 1)
02964             && !(r && asn_realloc(pkt, pkt_len))) {
02965             return 0;
02966         }
02967         *(*pkt + *pkt_len - (++*offset)) = 0;
02968     }
02969 
02970     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
02971                                   (*offset - start_offset))) {
02972         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
02973                                             (*offset - start_offset))) {
02974             return 0;
02975         } else {
02976             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
02977                            (*offset - start_offset));
02978             DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2lX)\n", *intp,
02979                       *intp));
02980             return 1;
02981         }
02982     }
02983 
02984     return 0;
02985 }
02986 
03004 int
03005 asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
03006                             size_t * offset, int r,
03007                             u_char type, size_t length)
03008 {
03009     return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
03010                                      length);
03011 }
03012 
03031 int
03032 asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
03033                          size_t * offset, int r,
03034                          u_char type,
03035                          const oid * objid, size_t objidlength)
03036 {
03037     /*
03038      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
03039      * subidentifier ::= {leadingbyte}* lastbyte
03040      * leadingbyte ::= 1 7bitvalue
03041      * lastbyte ::= 0 7bitvalue
03042      */
03043     register size_t i;
03044     register oid    tmpint;
03045     size_t          start_offset = *offset;
03046     const char     *errpre = "build objid";
03047 
03048     /*
03049      * Check if there are at least 2 sub-identifiers.  
03050      */
03051     if (objidlength == 0) {
03052         /*
03053          * There are not, so make OID have two with value of zero.  
03054          */
03055         while ((*pkt_len - *offset) < 2) {
03056             if (!(r && asn_realloc(pkt, pkt_len))) {
03057                 return 0;
03058             }
03059         }
03060 
03061         *(*pkt + *pkt_len - (++*offset)) = 0;
03062         *(*pkt + *pkt_len - (++*offset)) = 0;
03063     } else if (objid[0] > 2) {
03064         ERROR_MSG("build objid: bad first subidentifier");
03065         return 0;
03066     } else if (objidlength == 1) {
03067         /*
03068          * Encode the first value.  
03069          */
03070         if (((*pkt_len - *offset) < 1)
03071             && !(r && asn_realloc(pkt, pkt_len))) {
03072             return 0;
03073         }
03074         *(*pkt + *pkt_len - (++*offset)) = (u_char) objid[0];
03075     } else {
03076         for (i = objidlength; i > 2; i--) {
03077             tmpint = objid[i - 1];
03078             CHECK_OVERFLOW_U(tmpint,12);
03079 
03080             if (((*pkt_len - *offset) < 1)
03081                 && !(r && asn_realloc(pkt, pkt_len))) {
03082                 return 0;
03083             }
03084             *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
03085             tmpint >>= 7;
03086 
03087             while (tmpint > 0) {
03088                 if (((*pkt_len - *offset) < 1)
03089                     && !(r && asn_realloc(pkt, pkt_len))) {
03090                     return 0;
03091                 }
03092                 *(*pkt + *pkt_len - (++*offset)) =
03093                     (u_char) ((tmpint & 0x7f) | 0x80);
03094                 tmpint >>= 7;
03095             }
03096         }
03097 
03098         /*
03099          * Combine the first two values.  
03100          */
03101         if ((objid[1] > 40) &&
03102             (objid[0] < 2)) {
03103             ERROR_MSG("build objid: bad second subidentifier");
03104             return 0;
03105         }
03106         tmpint = ((objid[0] * 40) + objid[1]);
03107         if (((*pkt_len - *offset) < 1)
03108             && !(r && asn_realloc(pkt, pkt_len))) {
03109             return 0;
03110         }
03111         *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
03112         tmpint >>= 7;
03113 
03114         while (tmpint > 0) {
03115             if (((*pkt_len - *offset) < 1)
03116                 && !(r && asn_realloc(pkt, pkt_len))) {
03117                 return 0;
03118             }
03119             *(*pkt + *pkt_len - (++*offset)) =
03120                 (u_char) ((tmpint & 0x7f) | 0x80);
03121             tmpint >>= 7;
03122         }
03123     }
03124 
03125     tmpint = *offset - start_offset;
03126     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
03127                                   (*offset - start_offset))) {
03128         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
03129                                             (*offset - start_offset))) {
03130             return 0;
03131         } else {
03132             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
03133                            (*offset - start_offset));
03134             DEBUGMSG(("dumpv_send", "  ObjID: "));
03135             DEBUGMSGOID(("dumpv_send", objid, objidlength));
03136             DEBUGMSG(("dumpv_send", "\n"));
03137             return 1;
03138         }
03139     }
03140 
03141     return 0;
03142 }
03143 
03160 int
03161 asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
03162                         size_t * offset, int r, u_char type)
03163 {
03164     /*
03165      * ASN.1 null ::= 0x05 0x00
03166      */
03167     size_t          start_offset = *offset;
03168 
03169     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
03170         DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
03171                        (*offset - start_offset));
03172         DEBUGMSG(("dumpv_send", "  NULL\n"));
03173         return 1;
03174     } else {
03175         return 0;
03176     }
03177 }
03178 
03197 int
03198 asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
03199                              size_t * offset, int r,
03200                              u_char type,
03201                              const u_char * str, size_t strlength)
03202 {
03203     /*
03204      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
03205      */
03206     static const char *errpre = "build bitstring";
03207     size_t          start_offset = *offset;
03208 
03209     while ((*pkt_len - *offset) < strlength) {
03210         if (!(r && asn_realloc(pkt, pkt_len))) {
03211             return 0;
03212         }
03213     }
03214 
03215     *offset += strlength;
03216     memcpy(*pkt + *pkt_len - *offset, str, strlength);
03217 
03218     if (asn_realloc_rbuild_header
03219         (pkt, pkt_len, offset, r, type, strlength)) {
03220         if (_asn_realloc_build_header_check
03221             (errpre, pkt, pkt_len, strlength)) {
03222             return 0;
03223         } else {
03224             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
03225                            *offset - start_offset);
03226             DEBUGIF("dumpv_send") {
03227                 if (strlength == 0) {
03228                     DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]\n"));
03229                 } else {
03230                     u_char         *buf = (u_char *) malloc(2 * strlength);
03231                     size_t          l =
03232                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
03233 
03234                     if (sprint_realloc_asciistring
03235                         (&buf, &l, &ol, 1, str, strlength)) {
03236                         DEBUGMSG(("dumpv_send", "  Bitstring:\t%s\n",
03237                                   buf));
03238                     } else {
03239                         if (buf == NULL) {
03240                             DEBUGMSG(("dumpv_send",
03241                                       "  Bitstring:\t[TRUNCATED]\n"));
03242                         } else {
03243                             DEBUGMSG(("dumpv_send",
03244                                       "  Bitstring:\t%s [TRUNCATED]\n",
03245                                       buf));
03246                         }
03247                     }
03248                     if (buf != NULL) {
03249                         free(buf);
03250                     }
03251                 }
03252             }
03253         }
03254         return 1;
03255     }
03256 
03257     return 0;
03258 }
03259 
03277 int
03278 asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
03279                                   size_t * offset, int r,
03280                                   u_char type,
03281                                const struct counter64 *cp, size_t countersize)
03282 {
03283     /*
03284      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
03285      */
03286     register u_long low = cp->low, high = cp->high;
03287     size_t          intsize, start_offset = *offset;
03288     int             count;
03289 
03290     if (countersize != sizeof(struct counter64)) {
03291         _asn_size_err("build uint64", countersize,
03292                       sizeof(struct counter64));
03293         return 0;
03294     }
03295 
03296     CHECK_OVERFLOW_U(high,13);
03297     CHECK_OVERFLOW_U(low,13);
03298 
03299     /*
03300      * Encode the low 4 bytes first.  
03301      */
03302     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
03303         return 0;
03304     }
03305     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
03306     low >>= 8;
03307     count = 1;
03308 
03309     while (low != 0) {
03310         count++;
03311         if (((*pkt_len - *offset) < 1)
03312             && !(r && asn_realloc(pkt, pkt_len))) {
03313             return 0;
03314         }
03315         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
03316         low >>= 8;
03317     }
03318 
03319     /*
03320      * Then the high byte if present.  
03321      */
03322     if (high) {
03323         /*
03324          * Do the rest of the low byte.  
03325          */
03326         for (; count < 4; count++) {
03327             if (((*pkt_len - *offset) < 1)
03328                 && !(r && asn_realloc(pkt, pkt_len))) {
03329                 return 0;
03330             }
03331             *(*pkt + *pkt_len - (++*offset)) = 0;
03332         }
03333 
03334         /*
03335          * Do high byte.  
03336          */
03337         if (((*pkt_len - *offset) < 1)
03338             && !(r && asn_realloc(pkt, pkt_len))) {
03339             return 0;
03340         }
03341         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
03342         high >>= 8;
03343 
03344         while (high != 0) {
03345             if (((*pkt_len - *offset) < 1)
03346                 && !(r && asn_realloc(pkt, pkt_len))) {
03347                 return 0;
03348             }
03349             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
03350             high >>= 8;
03351         }
03352     }
03353 
03354     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
03355         /*
03356          * Make sure left most bit is representational of the rest of the bits
03357          * that aren't encoded.  
03358          */
03359         if (((*pkt_len - *offset) < 1)
03360             && !(r && asn_realloc(pkt, pkt_len))) {
03361             return 0;
03362         }
03363         *(*pkt + *pkt_len - (++*offset)) = 0;
03364     }
03365 
03366     intsize = *offset - start_offset;
03367 
03368 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
03369     /*
03370      * Encode a Counter64 as an opaque (it also works in SNMPv1).  
03371      */
03372     if (type == ASN_OPAQUE_COUNTER64) {
03373         while ((*pkt_len - *offset) < 5) {
03374             if (!(r && asn_realloc(pkt, pkt_len))) {
03375                 return 0;
03376             }
03377         }
03378 
03379         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
03380         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
03381         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
03382 
03383         /*
03384          * Put the tag and length for the Opaque wrapper.  
03385          */
03386         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
03387                                       ASN_OPAQUE, intsize + 3)) {
03388             if (_asn_realloc_build_header_check
03389                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
03390                 return 0;
03391             }
03392         } else {
03393             return 0;
03394         }
03395     } else if (type == ASN_OPAQUE_U64) {
03396         /*
03397          * Encode the Unsigned int64 in an opaque.  
03398          */
03399         while ((*pkt_len - *offset) < 5) {
03400             if (!(r && asn_realloc(pkt, pkt_len))) {
03401                 return 0;
03402             }
03403         }
03404 
03405         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
03406         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
03407         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
03408 
03409         /*
03410          * Put the tag and length for the Opaque wrapper.  
03411          */
03412         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
03413                                       ASN_OPAQUE, intsize + 3)) {
03414             if (_asn_realloc_build_header_check
03415                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
03416                 return 0;
03417             }
03418         } else {
03419             return 0;
03420         }
03421     } else {
03422 
03423 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
03424         if (asn_realloc_rbuild_header
03425             (pkt, pkt_len, offset, r, type, intsize)) {
03426             if (_asn_realloc_build_header_check
03427                 ("build uint64", pkt, pkt_len, intsize)) {
03428                 return 0;
03429             }
03430         } else {
03431             return 0;
03432         }
03433 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
03434     }
03435 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
03436 
03437     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
03438     DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
03439     return 1;
03440 }
03441 
03442 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
03443 
03444 
03462 int
03463 asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
03464                                 size_t * offset, int r,
03465                                 u_char type,
03466                                 const struct counter64 *cp, size_t countersize)
03467 {
03468     /*
03469      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
03470      */
03471     register long low = cp->low, high = cp->high;
03472     size_t          intsize, start_offset = *offset;
03473     int             count, testvalue = (high & 0x80000000) ? -1 : 0;
03474 
03475     if (countersize != sizeof(struct counter64)) {
03476         _asn_size_err("build uint64", countersize,
03477                       sizeof(struct counter64));
03478         return 0;
03479     }
03480 
03481     CHECK_OVERFLOW_S(high,14);
03482     CHECK_OVERFLOW_U(low,14);
03483 
03484     /*
03485      * Encode the low 4 bytes first.  
03486      */
03487     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
03488         return 0;
03489     }
03490     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
03491     low >>= 8;
03492     count = 1;
03493 
03494     while ((int) low != testvalue && count < 4) {
03495         count++;
03496         if (((*pkt_len - *offset) < 1)
03497             && !(r && asn_realloc(pkt, pkt_len))) {
03498             return 0;
03499         }
03500         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
03501         low >>= 8;
03502     }
03503 
03504     /*
03505      * Then the high byte if present.  
03506      */
03507     if (high != testvalue) {
03508         /*
03509          * Do the rest of the low byte.  
03510          */
03511         for (; count < 4; count++) {
03512             if (((*pkt_len - *offset) < 1)
03513                 && !(r && asn_realloc(pkt, pkt_len))) {
03514                 return 0;
03515             }
03516             *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
03517         }
03518 
03519         /*
03520          * Do high byte.  
03521          */
03522         if (((*pkt_len - *offset) < 1)
03523             && !(r && asn_realloc(pkt, pkt_len))) {
03524             return 0;
03525         }
03526         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
03527         high >>= 8;
03528 
03529         while ((int) high != testvalue) {
03530             if (((*pkt_len - *offset) < 1)
03531                 && !(r && asn_realloc(pkt, pkt_len))) {
03532                 return 0;
03533             }
03534             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
03535             high >>= 8;
03536         }
03537     }
03538 
03539     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
03540         /*
03541          * Make sure left most bit is representational of the rest of the bits
03542          * that aren't encoded.  
03543          */
03544         if (((*pkt_len - *offset) < 1)
03545             && !(r && asn_realloc(pkt, pkt_len))) {
03546             return 0;
03547         }
03548         *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
03549     }
03550 
03551     intsize = *offset - start_offset;
03552 
03553     while ((*pkt_len - *offset) < 5) {
03554         if (!(r && asn_realloc(pkt, pkt_len))) {
03555             return 0;
03556         }
03557     }
03558 
03559     *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
03560     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
03561     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
03562 
03563     /*
03564      * Put the tag and length for the Opaque wrapper.  
03565      */
03566     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
03567                                   ASN_OPAQUE, intsize + 3)) {
03568         if (_asn_realloc_build_header_check
03569             ("build counter u64", pkt, pkt_len, intsize + 3)) {
03570             return 0;
03571         }
03572     } else {
03573         return 0;
03574     }
03575 
03576     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
03577     DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
03578     return 1;
03579 }
03580 
03599 int
03600 asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
03601                          size_t * offset, int r,
03602                          u_char type, const float *floatp, size_t floatsize)
03603 {
03604     size_t          start_offset = *offset;
03605     union {
03606         float           floatVal;
03607         int             intVal;
03608         u_char          c[sizeof(float)];
03609     } fu;
03610 
03611     /*
03612      * Floatsize better not be larger than realistic.  
03613      */
03614     if (floatsize != sizeof(float) || floatsize > 122) {
03615         return 0;
03616     }
03617 
03618     while ((*pkt_len - *offset) < floatsize + 3) {
03619         if (!(r && asn_realloc(pkt, pkt_len))) {
03620             return 0;
03621         }
03622     }
03623 
03624     /*
03625      * Correct for endian differences and copy value.  
03626      */
03627     fu.floatVal = *floatp;
03628     fu.intVal = htonl(fu.intVal);
03629     *offset += floatsize;
03630     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
03631 
03632     /*
03633      * Put the special tag and length (3 bytes).  
03634      */
03635     *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
03636     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
03637     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
03638 
03639     /*
03640      * Put the tag and length for the Opaque wrapper.  
03641      */
03642     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
03643                                   ASN_OPAQUE, floatsize + 3)) {
03644         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
03645                                             floatsize + 3)) {
03646             return 0;
03647         } else {
03648             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
03649                            *offset - start_offset);
03650             DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
03651             return 1;
03652         }
03653     }
03654 
03655     return 0;
03656 }
03657 
03676 int
03677 asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
03678                           size_t * offset, int r,
03679                           u_char type, const double *doublep, size_t doublesize)
03680 {
03681     size_t          start_offset = *offset;
03682     long            tmp;
03683     union {
03684         double          doubleVal;
03685         int             intVal[2];
03686         u_char          c[sizeof(double)];
03687     } fu;
03688 
03689     /*
03690      * Doublesize better not be larger than realistic.  
03691      */
03692     if (doublesize != sizeof(double) || doublesize > 122) {
03693         return 0;
03694     }
03695 
03696     while ((*pkt_len - *offset) < doublesize + 3) {
03697         if (!(r && asn_realloc(pkt, pkt_len))) {
03698             return 0;
03699         }
03700     }
03701 
03702     /*
03703      * Correct for endian differences and copy value.  
03704      */
03705     fu.doubleVal = *doublep;
03706     tmp = htonl(fu.intVal[0]);
03707     fu.intVal[0] = htonl(fu.intVal[1]);
03708     fu.intVal[1] = tmp;
03709     *offset += doublesize;
03710     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
03711 
03712     /*
03713      * Put the special tag and length (3 bytes).  
03714      */
03715     *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
03716     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
03717     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
03718 
03719     /*
03720      * Put the tag and length for the Opaque wrapper.  
03721      */
03722     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
03723                                   ASN_OPAQUE, doublesize + 3)) {
03724         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
03725                                             doublesize + 3)) {
03726             return 0;
03727         } else {
03728             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
03729                            *offset - start_offset);
03730             DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
03731             return 1;
03732         }
03733     }
03734 
03735     return 0;
03736 }
03737 
03738 #endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
03739 #endif                          /*  NETSNMP_USE_REVERSE_ASNENCODING  */
03740