asn1.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:112k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * Abstract Syntax Notation One, ASN.1
  3.  * As defined in ISO/IS 8824 and ISO/IS 8825
  4.  * This implements a subset of the above International Standards that
  5.  * is sufficient to implement SNMP.
  6.  *
  7.  * Encodes abstract data types into a machine independent stream of bytes.
  8.  *
  9.  */
  10. /**********************************************************************
  11. Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
  12.                       All Rights Reserved
  13. Permission to use, copy, modify, and distribute this software and its 
  14. documentation for any purpose and without fee is hereby granted, 
  15. provided that the above copyright notice appear in all copies and that
  16. both that copyright notice and this permission notice appear in 
  17. supporting documentation, and that the name of CMU not be
  18. used in advertising or publicity pertaining to distribution of the
  19. software without specific, written prior permission.  
  20. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  21. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  22. CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  23. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  24. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  25. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  26. SOFTWARE.
  27. ******************************************************************/
  28. /**
  29.  * @defgroup asn1_packet_parse asn1 parsing and datatype manipulation routines.
  30.  * @ingroup library
  31.  *
  32.  * @{
  33.  * 
  34.  * Note on 
  35.  * 
  36.  * Re-allocating reverse ASN.1 encoder functions.  Synopsis:
  37.  *
  38.  * code
  39.  *
  40.  * u_char *buf = (u_char*)malloc(100);
  41.  * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
  42.  * size_t buf_len = 100, offset = 0;
  43.  * long data = 12345;
  44.  * int allow_realloc = 1;
  45.  * 
  46.  * if (asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
  47.  *                            type, &data, sizeof(long)) == 0) {
  48.  *     error;
  49.  * }
  50.  * 
  51.  * endcode
  52.  *
  53.  * NOTE WELL: after calling one of these functions with allow_realloc
  54.  * non-zero, buf might have moved, buf_len might have grown and
  55.  * offset will have increased by the size of the encoded data.
  56.  * You should **NEVER** do something like this:
  57.  * 
  58.  * code
  59.  *
  60.  * u_char *buf = (u_char *)malloc(100), *ptr;
  61.  * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
  62.  * size_t buf_len = 100, offset = 0;
  63.  * long data1 = 1234, data2 = 5678;
  64.  * int rc = 0, allow_realloc = 1;
  65.  * 
  66.  * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
  67.  *                                type, &data1, sizeof(long));
  68.  * ptr = buf[buf_len - offset];   / * points at encoding of data1 * /
  69.  * if (rc == 0) {
  70.  *      error;
  71.  * }
  72.  * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
  73.  *                              type, &data2, sizeof(long));
  74.  * make use of ptr here;
  75.  * 
  76.  * endcode
  77.  * 
  78.  * ptr is **INVALID** at this point.  In general, you should store the
  79.  * offset value and compute pointers when you need them:
  80.  * 
  81.  * 
  82.  * code
  83.  *
  84.  * u_char *buf = (u_char *)malloc(100), *ptr;
  85.  * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
  86.  * size_t buf_len = 100, offset = 0, ptr_offset;
  87.  * long data1 = 1234, data2 = 5678;
  88.  * int rc = 0, allow_realloc = 1;
  89.  * 
  90.  * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
  91.  *                              type, &data1, sizeof(long));
  92.  * ptr_offset = offset;
  93.  * if (rc == 0) {
  94.  *      error;
  95.  * }
  96.  * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
  97.  *                              type, &data2, sizeof(long));
  98.  * ptr = buf + buf_len - ptr_offset
  99.  * make use of ptr here;
  100.  * 
  101.  * endcode
  102.  * 
  103.  * 
  104.  * Here, you can see that ptr will be a valid pointer even if the block of
  105.  * memory has been moved, as it may well have been.  Plenty of examples of
  106.  * usage all over asn1.c, snmp_api.c, snmpusm.c.
  107.  * 
  108.  * The other thing you should **NEVER** do is to pass a pointer to a buffer
  109.  * on the stack as the first argument when allow_realloc is non-zero, unless
  110.  * you really know what you are doing and your machine/compiler allows you to
  111.  * free non-heap memory.  There are rumours that such things exist, but many
  112.  * consider them no more than the wild tales of a fool.
  113.  * 
  114.  * Of course, you can pass allow_realloc as zero, to indicate that you do not
  115.  * wish the packet buffer to be reallocated for some reason; perhaps because
  116.  * it is on the stack.  This may be useful to emulate the functionality of
  117.  * the old API:
  118.  *
  119.  * code 
  120.  * 
  121.  * u_char my_static_buffer[100], *cp = NULL;
  122.  * size_t my_static_buffer_len = 100;
  123.  * float my_pi = (float)22/(float)7;
  124.  * 
  125.  * cp = asn_rbuild_float(my_static_buffer, &my_static_buffer_len,
  126.  *                       ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
  127.  * if (cp == NULL) {
  128.  * error;
  129.  * }
  130.  * 
  131.  * endcode
  132.  * 
  133.  * IS EQUIVALENT TO:
  134.  * 
  135.  * code
  136.  * 
  137.  * u_char my_static_buffer[100];
  138.  * size_t my_static_buffer_len = 100, my_offset = 0;
  139.  * float my_pi = (float)22/(float)7;
  140.  * int rc = 0;
  141.  * 
  142.  * rc = asn_realloc_rbuild_float(&my_static_buffer, &my_static_buffer_len,
  143.  *                               &my_offset, 0,
  144.  *                               ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
  145.  * if (rc == 0) {
  146.  *   error;
  147.  * }
  148.  * endcode
  149.  * 
  150.  */
  151. #include <net-snmp/net-snmp-config.h>
  152. #ifdef KINETICS
  153. #include "gw.h"
  154. #endif
  155. #if HAVE_STRING_H
  156. #include <string.h>
  157. #else
  158. #include <strings.h>
  159. #endif
  160. #include <sys/types.h>
  161. #include <stdio.h>
  162. #ifdef HAVE_STDLIB_H
  163. #include <stdlib.h>
  164. #endif
  165. #if HAVE_WINSOCK_H
  166. #include <winsock.h>
  167. #endif
  168. #if HAVE_NETINET_IN_H
  169. #include <netinet/in.h>
  170. #endif
  171. #ifdef vms
  172. #include <in.h>
  173. #endif
  174. #if HAVE_DMALLOC_H
  175. #include <dmalloc.h>
  176. #endif
  177. #include <net-snmp/output_api.h>
  178. #include <net-snmp/utilities.h>
  179. #include <net-snmp/library/asn1.h>
  180. #include <net-snmp/library/int64.h>
  181. #include <net-snmp/library/mib.h>
  182. #ifndef NULL
  183. #define NULL 0
  184. #endif
  185. #include <net-snmp/library/snmp_api.h>
  186. #ifndef INT32_MAX
  187. #   define INT32_MAX 2147483647
  188. #endif
  189. #ifndef INT32_MIN
  190. #   define INT32_MIN (0 - INT32_MAX - 1)
  191. #endif
  192. #if SIZEOF_LONG == 4
  193. #  define CHECK_OVERFLOW_S(x,y)
  194. #  define CHECK_OVERFLOW_U(x,y)
  195. #else
  196. #  define CHECK_OVERFLOW_S(x,y) do { int trunc = 0;                     
  197.         if (x > INT32_MAX) {                                            
  198.             trunc = 1;                                                  
  199.             x &= 0xffffffff;                                            
  200.         } else if (x < INT32_MIN) {                                     
  201.             trunc = 1;                                                  
  202.             x = 0 - (x & 0xffffffff);                                   
  203.         }                                                               
  204.         if (trunc)                                                      
  205.             snmp_log(LOG_ERR,"truncating signed value to 32 bits (%d)n",y); 
  206.     } while(0)
  207. #  define CHECK_OVERFLOW_U(x,y) do {                                    
  208.         if (x > UINT32_MAX) {                                           
  209.             x &= 0xffffffff;                                            
  210.             snmp_log(LOG_ERR,"truncating unsigned value to 32 bits (%d)n",y); 
  211.         }                                                               
  212.     } while(0)
  213. #endif
  214. /**
  215.  * @internal
  216.  * output an error for a wrong size
  217.  * 
  218.  * @param str        error string
  219.  * @param wrongsize  wrong size
  220.  * @param rightsize  expected size
  221.  */
  222. static
  223.     void
  224. _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
  225. {
  226.     char            ebuf[128];
  227.     snprintf(ebuf, sizeof(ebuf),
  228.             "%s size %lu: s/b %lu", str,
  229.     (unsigned long)wrongsize, (unsigned long)rightsize);
  230.     ebuf[ sizeof(ebuf)-1 ] = 0;
  231.     ERROR_MSG(ebuf);
  232. }
  233. /**
  234.  * @internal 
  235.  * output an error for a wrong length
  236.  * 
  237.  * @param str        error string
  238.  * @param wrongsize  wrong  length
  239.  * @param rightsize  expected length
  240.  */
  241. static
  242.     void
  243. _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
  244. {
  245.     char            ebuf[128];
  246.     snprintf(ebuf, sizeof(ebuf),
  247.             "%s length %lu too large: exceeds %lu", str,
  248.     (unsigned long)wrongsize, (unsigned long)rightsize);
  249.     ebuf[ sizeof(ebuf)-1 ] = 0;
  250.     ERROR_MSG(ebuf);
  251. }
  252. /**
  253.  * @internal
  254.  * call after asn_parse_length to verify result.
  255.  * 
  256.  * @param str  error string
  257.  * @param bufp start of buffer
  258.  * @param data start of data
  259.  * @param plen  ?
  260.  * @param dlen  ?
  261.  * 
  262.  * @return 1 on error 0 on success
  263.  */
  264. static
  265.     int
  266. _asn_parse_length_check(const char *str,
  267.                         const u_char * bufp, const u_char * data,
  268.                         u_long plen, size_t dlen)
  269. {
  270.     char            ebuf[128];
  271.     size_t          header_len;
  272.     if (bufp == NULL) {
  273.         /*
  274.          * error message is set 
  275.          */
  276.         return 1;
  277.     }
  278.     header_len = bufp - data;
  279.     if (plen > 0x7fffffff || header_len > 0x7fffffff ||
  280.         ((size_t) plen + header_len) > dlen) {
  281.         snprintf(ebuf, sizeof(ebuf),
  282.                 "%s: message overflow: %d len + %d delta > %d len",
  283.                 str, (int) plen, (int) header_len, (int) dlen);
  284.         ebuf[ sizeof(ebuf)-1 ] = 0;
  285.         ERROR_MSG(ebuf);
  286.         return 1;
  287.     }
  288.     return 0;
  289. }
  290. /**
  291.  * @internal 
  292.  * call after asn_build_header to verify result.
  293.  * 
  294.  * @param str     error string to output
  295.  * @param data    data pointer to verify (NULL => error )
  296.  * @param datalen  data len to check
  297.  * @param typedlen  type length
  298.  * 
  299.  * @return 0 on success, 1 on error
  300.  */
  301. static
  302.     int
  303. _asn_build_header_check(const char *str, const u_char * data,
  304.                         size_t datalen, size_t typedlen)
  305. {
  306.     char            ebuf[128];
  307.     if (data == NULL) {
  308.         /*
  309.          * error message is set 
  310.          */
  311.         return 1;
  312.     }
  313.     if (datalen < typedlen) {
  314.         snprintf(ebuf, sizeof(ebuf),
  315.                 "%s: bad header, length too short: %lu < %lu", str,
  316.                 (unsigned long)datalen, (unsigned long)typedlen);
  317.         ebuf[ sizeof(ebuf)-1 ] = 0;
  318.         ERROR_MSG(ebuf);
  319.         return 1;
  320.     }
  321.     return 0;
  322. }
  323. /**
  324.  * @internal 
  325.  * call after asn_build_header to verify result.
  326.  * 
  327.  * @param str       error string
  328.  * @param pkt       packet to check
  329.  * @param pkt_len  length of the packet
  330.  * @param typedlen length of the type
  331.  * 
  332.  * @return 0 on success 1 on error 
  333.  */
  334. static
  335.     int
  336. _asn_realloc_build_header_check(const char *str,
  337.                                 u_char ** pkt,
  338.                                 const size_t * pkt_len, size_t typedlen)
  339. {
  340.     char            ebuf[128];
  341.     if (pkt == NULL || *pkt == NULL) {
  342.         /*
  343.          * Error message is set.  
  344.          */
  345.         return 1;
  346.     }
  347.     if (*pkt_len < typedlen) {
  348.         snprintf(ebuf, sizeof(ebuf),
  349.                 "%s: bad header, length too short: %lu < %lu", str,
  350.                 (unsigned long)*pkt_len, (unsigned long)typedlen);
  351.         ebuf[ sizeof(ebuf)-1 ] = 0;
  352.         ERROR_MSG(ebuf);
  353.         return 1;
  354.     }
  355.     return 0;
  356. }
  357. /**
  358.  * @internal 
  359.  * checks the incoming packet for validity and returns its size or 0 
  360.  * 
  361.  * @param pkt The packet 
  362.  * @param len The length to check 
  363.  * 
  364.  * @return The size of the packet if valid; 0 otherwise
  365.  */
  366. int
  367. asn_check_packet(u_char * pkt, size_t len)
  368. {
  369.     u_long          asn_length;
  370.     if (len < 2)
  371.         return 0;               /* always too short */
  372.     if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
  373.         return -1;              /* wrong type */
  374.     if (*(pkt + 1) & 0x80) {
  375.         /*
  376.          * long length 
  377.          */
  378.         if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
  379.             return 0;           /* still to short, incomplete length */
  380.         asn_parse_length(pkt + 1, &asn_length);
  381.         return (asn_length + 2 + (*(pkt + 1) & ~0x80));
  382.     } else {
  383.         /*
  384.          * short length 
  385.          */
  386.         return (*(pkt + 1) + 2);
  387.     }
  388. }
  389. static
  390.     int
  391. _asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
  392. {
  393.     char            ebuf[128];
  394.     if (asn_length < 1) {
  395.         snprintf(ebuf, sizeof(ebuf),
  396.                 "%s: length %d too small", str, (int) asn_length);
  397.         ebuf[ sizeof(ebuf)-1 ] = 0;
  398.         ERROR_MSG(ebuf);
  399.         return 1;
  400.     }
  401.     /*
  402.      * if (datum > 7){
  403.      * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
  404.      * ERROR_MSG(ebuf);
  405.      * return 1;
  406.      * }
  407.      */
  408.     return 0;
  409. }
  410. /**
  411.  * @internal 
  412.  * asn_parse_int - pulls a long out of an int type.
  413.  *
  414.  *  On entry, datalength is input as the number of valid bytes following
  415.  *   "data".  On exit, it is returned as the number of valid bytes
  416.  *   following the end of this object.
  417.  *
  418.  *  Returns a pointer to the first byte past the end
  419.  *   of this object (i.e. the start of the next object).
  420.  *  Returns NULL on any error.
  421.  *  
  422.  * @param data       IN - pointer to start of object
  423.  * @param datalength IN/OUT - number of valid bytes left in buffer
  424.  * @param type       OUT - asn type of object
  425.  * @param intp       IN/OUT - pointer to start of output buffer
  426.  * @param intsize    IN - size of output buffer
  427.  * 
  428.  * @return pointer to the first byte past the end
  429.  *   of this object (i.e. the start of the next object) Returns NULL on any error
  430.  */
  431. u_char         *
  432. asn_parse_int(u_char * data,
  433.               size_t * datalength,
  434.               u_char * type, long *intp, size_t intsize)
  435. {
  436.     /*
  437.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  438.      */
  439.     static const char *errpre = "parse int";
  440.     register u_char *bufp = data;
  441.     u_long          asn_length;
  442.     register long   value = 0;
  443.     if (intsize != sizeof(long)) {
  444.         _asn_size_err(errpre, intsize, sizeof(long));
  445.         return NULL;
  446.     }
  447.     *type = *bufp++;
  448.     bufp = asn_parse_length(bufp, &asn_length);
  449.     if (_asn_parse_length_check
  450.         (errpre, bufp, data, asn_length, *datalength))
  451.         return NULL;
  452.     if ((size_t) asn_length > intsize) {
  453.         _asn_length_err(errpre, (size_t) asn_length, intsize);
  454.         return NULL;
  455.     }
  456.     *datalength -= (int) asn_length + (bufp - data);
  457.     if (*bufp & 0x80)
  458.         value = -1;             /* integer is negative */
  459.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  460.     while (asn_length--)
  461.         value = (value << 8) | *bufp++;
  462.     CHECK_OVERFLOW_S(value,1);
  463.     DEBUGMSG(("dumpv_recv", "  Integer:t%ld (0x%.2X)n", value, value));
  464.     *intp = value;
  465.     return bufp;
  466. }
  467. /**
  468.  * @internal 
  469.  * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
  470.  *
  471.  *  On entry, datalength is input as the number of valid bytes following
  472.  *   "data".  On exit, it is returned as the number of valid bytes
  473.  *   following the end of this object.
  474.  *
  475.  *  Returns a pointer to the first byte past the end
  476.  *   of this object (i.e. the start of the next object).
  477.  *  Returns NULL on any error.
  478.  *  
  479.  * @param data       IN - pointer to start of object
  480.  * @param datalength IN/OUT - number of valid bytes left in buffer
  481.  * @param type       OUT - asn type of object
  482.  * @param intp       IN/OUT - pointer to start of output buffer
  483.  * @param intsize    IN - size of output buffer
  484.  * 
  485.  * @return pointer to the first byte past the end
  486.  *   of this object (i.e. the start of the next object) Returns NULL on any error
  487.  */
  488. u_char         *
  489. asn_parse_unsigned_int(u_char * data,
  490.                        size_t * datalength,
  491.                        u_char * type, u_long * intp, size_t intsize)
  492. {
  493.     /*
  494.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  495.      */
  496.     static const char *errpre = "parse uint";
  497.     register u_char *bufp = data;
  498.     u_long          asn_length;
  499.     register u_long value = 0;
  500.     if (intsize != sizeof(long)) {
  501.         _asn_size_err(errpre, intsize, sizeof(long));
  502.         return NULL;
  503.     }
  504.     *type = *bufp++;
  505.     bufp = asn_parse_length(bufp, &asn_length);
  506.     if (_asn_parse_length_check
  507.         (errpre, bufp, data, asn_length, *datalength))
  508.         return NULL;
  509.     if (((int) asn_length > (intsize + 1)) ||
  510.         (((int) asn_length == intsize + 1) && *bufp != 0x00)) {
  511.         _asn_length_err(errpre, (size_t) asn_length, intsize);
  512.         return NULL;
  513.     }
  514.     *datalength -= (int) asn_length + (bufp - data);
  515.     if (*bufp & 0x80)
  516.         value = ~value;         /* integer is negative */
  517.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  518.     while (asn_length--)
  519.         value = (value << 8) | *bufp++;
  520.     CHECK_OVERFLOW_U(value,2);
  521.     DEBUGMSG(("dumpv_recv", "  UInteger:t%ld (0x%.2X)n", value, value));
  522.     *intp = value;
  523.     return bufp;
  524. }
  525. /**
  526.  * @internal 
  527.  * asn_build_int - builds an ASN object containing an integer.
  528.  *
  529.  *  On entry, datalength is input as the number of valid bytes following
  530.  *   "data".  On exit, it is returned as the number of valid bytes
  531.  *   following the end of this object.
  532.  *
  533.  *  Returns a pointer to the first byte past the end
  534.  *   of this object (i.e. the start of the next object).
  535.  *  Returns NULL on any error.
  536.  * 
  537.  * 
  538.  * @param data         IN - pointer to start of output buffer
  539.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  540.  * @param type         IN  - asn type of objec
  541.  * @param intp         IN - pointer to start of long integer
  542.  * @param intsize      IN - size of input buffer
  543.  * 
  544.  * @return  Returns a pointer to the first byte past the end
  545.  *          of this object (i.e. the start of the next object).
  546.  *          Returns NULL on any error.
  547.  */
  548. u_char         *
  549. asn_build_int(u_char * data,
  550.            size_t * datalength, u_char type, const long *intp, size_t intsize)
  551. {
  552.     /*
  553.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  554.      */
  555.     static const char *errpre = "build int";
  556.     register long   integer;
  557.     register u_long mask;
  558. #ifndef SNMP_NO_DEBUGGING
  559.     u_char         *initdatap = data;
  560. #endif
  561.     if (intsize != sizeof(long)) {
  562.         _asn_size_err(errpre, intsize, sizeof(long));
  563.         return NULL;
  564.     }
  565.     integer = *intp;
  566.     CHECK_OVERFLOW_S(integer,3);
  567.     /*
  568.      * Truncate "unnecessary" bytes off of the most significant end of this
  569.      * 2's complement integer.  There should be no sequence of 9
  570.      * consecutive 1's or 0's at the most significant end of the
  571.      * integer.
  572.      */
  573.     mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
  574.     /*
  575.      * mask is 0xFF800000 on a big-endian machine 
  576.      */
  577.     while ((((integer & mask) == 0) || ((integer & mask) == mask))
  578.            && intsize > 1) {
  579.         intsize--;
  580.         integer <<= 8;
  581.     }
  582.     data = asn_build_header(data, datalength, type, intsize);
  583.     if (_asn_build_header_check(errpre, data, *datalength, intsize))
  584.         return NULL;
  585.     *datalength -= intsize;
  586.     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
  587.     /*
  588.      * mask is 0xFF000000 on a big-endian machine 
  589.      */
  590.     while (intsize--) {
  591.         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
  592.         integer <<= 8;
  593.     }
  594.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  595.     DEBUGMSG(("dumpv_send", "  Integer:t%ld (0x%.2X)n", *intp, *intp));
  596.     return data;
  597. }
  598. /**
  599.  * @internal 
  600.  * asn_build_unsigned_int - builds an ASN object containing an integer.
  601.  *
  602.  *  On entry, datalength is input as the number of valid bytes following
  603.  *   "data".  On exit, it is returned as the number of valid bytes
  604.  *   following the end of this object.
  605.  *
  606.  *  Returns a pointer to the first byte past the end
  607.  *   of this object (i.e. the start of the next object).
  608.  *  Returns NULL on any error.
  609.  * 
  610.  * 
  611.  * @param data         IN - pointer to start of output buffer
  612.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  613.  * @param type         IN  - asn type of objec
  614.  * @param intp         IN - pointer to start of long integer
  615.  * @param intsize      IN - size of input buffer
  616.  * 
  617.  * @return  Returns a pointer to the first byte past the end
  618.  *          of this object (i.e. the start of the next object).
  619.  *          Returns NULL on any error.
  620.  */
  621. u_char         *
  622. asn_build_unsigned_int(u_char * data,
  623.                        size_t * datalength,
  624.                        u_char type, const u_long * intp, size_t intsize)
  625. {
  626.     /*
  627.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  628.      */
  629.     static const char *errpre = "build uint";
  630.     register u_long integer;
  631.     register u_long mask;
  632.     int             add_null_byte = 0;
  633. #ifndef SNMP_NO_DEBUGGING
  634.     u_char         *initdatap = data;
  635. #endif
  636.     if (intsize != sizeof(long)) {
  637.         _asn_size_err(errpre, intsize, sizeof(long));
  638.         return NULL;
  639.     }
  640.     integer = *intp;
  641.     CHECK_OVERFLOW_U(integer,4);
  642.     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
  643.     /*
  644.      * mask is 0xFF000000 on a big-endian machine 
  645.      */
  646.     if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
  647.         /*
  648.          * if MSB is set 
  649.          */
  650.         add_null_byte = 1;
  651.         intsize++;
  652.     } else {
  653.         /*
  654.          * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
  655.          * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
  656.          * integer.
  657.          */
  658.         mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
  659.         /*
  660.          * mask is 0xFF800000 on a big-endian machine 
  661.          */
  662.         while ((((integer & mask) == 0) || ((integer & mask) == mask))
  663.                && intsize > 1) {
  664.             intsize--;
  665.             integer <<= 8;
  666.         }
  667.     }
  668.     data = asn_build_header(data, datalength, type, intsize);
  669.     if (_asn_build_header_check(errpre, data, *datalength, intsize))
  670.         return NULL;
  671.     *datalength -= intsize;
  672.     if (add_null_byte == 1) {
  673.         *data++ = '';
  674.         intsize--;
  675.     }
  676.     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
  677.     /*
  678.      * mask is 0xFF000000 on a big-endian machine 
  679.      */
  680.     while (intsize--) {
  681.         *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
  682.         integer <<= 8;
  683.     }
  684.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  685.     DEBUGMSG(("dumpv_send", "  UInteger:t%ld (0x%.2X)n", *intp, *intp));
  686.     return data;
  687. }
  688. /**
  689.  * @internal 
  690.  * asn_parse_string - pulls an octet string out of an ASN octet string type.
  691.  *
  692.  *  On entry, datalength is input as the number of valid bytes following
  693.  *   "data".  On exit, it is returned as the number of valid bytes
  694.  *   following the beginning of the next object.
  695.  *
  696.  *  "string" is filled with the octet string.
  697.  * ASN.1 octet string   ::=      primstring | cmpdstring
  698.  * primstring           ::= 0x04 asnlength byte {byte}*
  699.  * cmpdstring           ::= 0x24 asnlength string {string}*
  700.  *
  701.  *  Returns a pointer to the first byte past the end
  702.  *   of this object (i.e. the start of the next object).
  703.  *  Returns NULL on any error.
  704.  * 
  705.  * @param data        IN - pointer to start of object
  706.  * @param datalength  IN/OUT - number of valid bytes left in buffer
  707.  * @param type        OUT - asn type of object 
  708.  * @param string      IN/OUT - pointer to start of output buffer
  709.  * @param strlength   IN/OUT - size of output buffer
  710.  * 
  711.  * @return  Returns a pointer to the first byte past the end
  712.  *          of this object (i.e. the start of the next object).
  713.  *          Returns NULL on any error.
  714.  */
  715. u_char         *
  716. asn_parse_string(u_char * data,
  717.                  size_t * datalength,
  718.                  u_char * type, u_char * str, size_t * strlength)
  719. {
  720.     static const char *errpre = "parse string";
  721.     u_char         *bufp = data;
  722.     u_long          asn_length;
  723.     *type = *bufp++;
  724.     bufp = asn_parse_length(bufp, &asn_length);
  725.     if (_asn_parse_length_check
  726.         (errpre, bufp, data, asn_length, *datalength)) {
  727.         return NULL;
  728.     }
  729.     if ((int) asn_length > *strlength) {
  730.         _asn_length_err(errpre, (size_t) asn_length, *strlength);
  731.         return NULL;
  732.     }
  733.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  734.     memmove(str, bufp, asn_length);
  735.     if (*strlength > (int) asn_length)
  736.         str[asn_length] = 0;
  737.     *strlength = (int) asn_length;
  738.     *datalength -= (int) asn_length + (bufp - data);
  739.     DEBUGIF("dumpv_recv") {
  740.         u_char         *buf = (u_char *) malloc(1 + asn_length);
  741.         size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
  742.         if (sprint_realloc_asciistring
  743.             (&buf, &l, &ol, 1, str, asn_length)) {
  744.             DEBUGMSG(("dumpv_recv", "  String:t%sn", buf));
  745.         } else {
  746.             if (buf == NULL) {
  747.                 DEBUGMSG(("dumpv_recv", "  String:t[TRUNCATED]n"));
  748.             } else {
  749.                 DEBUGMSG(("dumpv_recv", "  String:t%s [TRUNCATED]n",
  750.                           buf));
  751.             }
  752.         }
  753.         if (buf != NULL) {
  754.             free(buf);
  755.         }
  756.     }
  757.     return bufp + asn_length;
  758. }
  759. /**
  760.  * @internal
  761.  * asn_build_string - Builds an ASN octet string object containing the input string.
  762.  *
  763.  *  On entry, datalength is input as the number of valid bytes following
  764.  *   "data".  On exit, it is returned as the number of valid bytes
  765.  *   following the beginning of the next object.
  766.  *
  767.  *  Returns a pointer to the first byte past the end
  768.  *   of this object (i.e. the start of the next object).
  769.  *  Returns NULL on any error.
  770.  *
  771.  * @param data         IN - pointer to start of object
  772.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  773.  * @param type         IN - asn type of object
  774.  * @param string       IN - pointer to start of input buffer
  775.  * @param strlength    IN - size of input buffer
  776.  * @return  Returns a pointer to the first byte past the end
  777.  *          of this object (i.e. the start of the next object).
  778.  *          Returns NULL on any error.
  779.  */
  780. u_char         *
  781. asn_build_string(u_char * data,
  782.                  size_t * datalength,
  783.                  u_char type, const u_char * str, size_t strlength)
  784. {
  785.     /*
  786.      * ASN.1 octet string ::= primstring | cmpdstring
  787.      * primstring ::= 0x04 asnlength byte {byte}*
  788.      * cmpdstring ::= 0x24 asnlength string {string}*
  789.      * This code will never send a compound string.
  790.      */
  791. #ifndef SNMP_NO_DEBUGGING
  792.     u_char         *initdatap = data;
  793. #endif
  794.     data = asn_build_header(data, datalength, type, strlength);
  795.     if (_asn_build_header_check
  796.         ("build string", data, *datalength, strlength))
  797.         return NULL;
  798.     if (strlength) {
  799.         if (str == NULL) {
  800.             memset(data, 0, strlength);
  801.         } else {
  802.             memmove(data, str, strlength);
  803.         }
  804.     }
  805.     *datalength -= strlength;
  806.     DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
  807.     DEBUGIF("dumpv_send") {
  808.         u_char         *buf = (u_char *) malloc(1 + strlength);
  809.         size_t          l = (buf != NULL) ? (1 + strlength) : 0, ol = 0;
  810.         if (sprint_realloc_asciistring
  811.             (&buf, &l, &ol, 1, str, strlength)) {
  812.             DEBUGMSG(("dumpv_send", "  String:t%sn", buf));
  813.         } else {
  814.             if (buf == NULL) {
  815.                 DEBUGMSG(("dumpv_send", "  String:t[TRUNCATED]n"));
  816.             } else {
  817.                 DEBUGMSG(("dumpv_send", "  String:t%s [TRUNCATED]n",
  818.                           buf));
  819.             }
  820.         }
  821.         if (buf != NULL) {
  822.             free(buf);
  823.         }
  824.     }
  825.     return data + strlength;
  826. }
  827. /**
  828.  * @internal
  829.  * asn_parse_header - interprets the ID and length of the current object.
  830.  *
  831.  *  On entry, datalength is input as the number of valid bytes following
  832.  *   "data".  On exit, it is returned as the number of valid bytes
  833.  *   in this object following the id and length.
  834.  *
  835.  *  Returns a pointer to the first byte of the contents of this object.
  836.  *  Returns NULL on any error.
  837.  *
  838.  *
  839.  * @param data         IN - pointer to start of object
  840.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  841.  * @param type         OUT - asn type of object
  842.  * @return  Returns a pointer to the first byte of the contents of this object.
  843.  *          Returns NULL on any error.
  844.  *
  845.  */
  846. u_char         *
  847. asn_parse_header(u_char * data, size_t * datalength, u_char * type)
  848. {
  849.     register u_char *bufp;
  850.     u_long          asn_length;
  851.     if (!data || !datalength || !type) {
  852.         ERROR_MSG("parse header: NULL pointer");
  853.         return NULL;
  854.     }
  855.     bufp = data;
  856.     /*
  857.      * this only works on data types < 30, i.e. no extension octets 
  858.      */
  859.     if (IS_EXTENSION_ID(*bufp)) {
  860.         ERROR_MSG("can't process ID >= 30");
  861.         return NULL;
  862.     }
  863.     *type = *bufp;
  864.     bufp = asn_parse_length(bufp + 1, &asn_length);
  865.     if (_asn_parse_length_check
  866.         ("parse header", bufp, data, asn_length, *datalength))
  867.         return NULL;
  868. #ifdef DUMP_PRINT_HEADERS
  869.     DEBUGDUMPSETUP("recv", data, (bufp - data));
  870.     DEBUGMSG(("dumpv_recv", "  Header: 0x%.2X, len = %d (0x%X)n", *data,
  871.               asn_length, asn_length));
  872. #else
  873.     /*
  874.      * DEBUGMSGHEXTLI(("recv",data,(bufp-data)));
  875.      * DEBUGMSG(("dumpH_recv","n"));
  876.      */
  877. #endif
  878. #ifdef OPAQUE_SPECIAL_TYPES
  879.     if ((*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
  880.         /*
  881.          * check if 64-but counter 
  882.          */
  883.         switch (*(bufp + 1)) {
  884.         case ASN_OPAQUE_COUNTER64:
  885.         case ASN_OPAQUE_U64:
  886.         case ASN_OPAQUE_FLOAT:
  887.         case ASN_OPAQUE_DOUBLE:
  888.         case ASN_OPAQUE_I64:
  889.             *type = *(bufp + 1);
  890.             break;
  891.         default:
  892.             /*
  893.              * just an Opaque 
  894.              */
  895.             *datalength = (int) asn_length;
  896.             return bufp;
  897.         }
  898.         /*
  899.          * value is encoded as special format 
  900.          */
  901.         bufp = asn_parse_length(bufp + 2, &asn_length);
  902.         if (_asn_parse_length_check("parse opaque header", bufp, data,
  903.                                     asn_length, *datalength))
  904.             return NULL;
  905.     }
  906. #endif                          /* OPAQUE_SPECIAL_TYPES */
  907.     *datalength = (int) asn_length;
  908.     return bufp;
  909. }
  910. /**
  911.  * @internal
  912.  * same as asn_parse_header with test for expected type
  913.  *
  914.  * @see asn_parse_header
  915.  *
  916.  * @param data          IN - pointer to start of object
  917.  * @param datalength    IN/OUT - number of valid bytes left in buffer
  918.  * @param type          OUT - asn type of object
  919.  * @param expected_type IN expected type
  920.  * @return  Returns a pointer to the first byte of the contents of this object.
  921.  *          Returns NULL on any error.
  922.  *
  923.  */
  924. u_char         *
  925. asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type,     /* must be this type */
  926.                    const char *estr)
  927. {                               /* error message prefix */
  928.     data = asn_parse_header(data, datalength, type);
  929.     if (data && (*type != expected_type)) {
  930.         char            ebuf[128];
  931.         snprintf(ebuf, sizeof(ebuf),
  932.                  "%s header type %02X: s/b %02X", estr,
  933.                 (u_char) * type, (u_char) expected_type);
  934.         ebuf[ sizeof(ebuf)-1 ] = 0;
  935.         ERROR_MSG(ebuf);
  936.         return NULL;
  937.     }
  938.     return data;
  939. }
  940. /**
  941.  * @internal
  942.  * asn_build_header - builds an ASN header for an object with the ID and
  943.  * length specified.
  944.  *
  945.  *  On entry, datalength is input as the number of valid bytes following
  946.  *   "data".  On exit, it is returned as the number of valid bytes
  947.  *   in this object following the id and length.
  948.  *
  949.  *  This only works on data types < 30, i.e. no extension octets.
  950.  *  The maximum length is 0xFFFF;
  951.  *
  952.  *  Returns a pointer to the first byte of the contents of this object.
  953.  *  Returns NULL on any error.
  954.  *
  955.  * @param data         IN - pointer to start of object
  956.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  957.  * @param type         IN - asn type of object
  958.  * @param length       IN - length of object
  959.  * @return Returns a pointer to the first byte of the contents of this object.
  960.  *          Returns NULL on any error.
  961.  */
  962. u_char         *
  963. asn_build_header(u_char * data,
  964.                  size_t * datalength, u_char type, size_t length)
  965. {
  966.     char            ebuf[128];
  967.     if (*datalength < 1) {
  968.         snprintf(ebuf, sizeof(ebuf),
  969.                 "bad header length < 1 :%lu, %lu",
  970. (unsigned long)*datalength, (unsigned long)length);
  971.         ebuf[ sizeof(ebuf)-1 ] = 0;
  972.         ERROR_MSG(ebuf);
  973.         return NULL;
  974.     }
  975.     *data++ = type;
  976.     (*datalength)--;
  977.     return asn_build_length(data, datalength, length);
  978. }
  979. /**
  980.  * @internal
  981.  * asn_build_sequence - builds an ASN header for a sequence with the ID and
  982.  *
  983.  * length specified.
  984.  *  On entry, datalength is input as the number of valid bytes following
  985.  *   "data".  On exit, it is returned as the number of valid bytes
  986.  *   in this object following the id and length.
  987.  *
  988.  *  This only works on data types < 30, i.e. no extension octets.
  989.  *  The maximum length is 0xFFFF;
  990.  *
  991.  *  Returns a pointer to the first byte of the contents of this object.
  992.  *  Returns NULL on any error.
  993.  *
  994.  * @param data         IN - pointer to start of object
  995.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  996.  * @param type         IN - asn type of object
  997.  * @param length       IN - length of object
  998.  *
  999.  * @return Returns a pointer to the first byte of the contents of this object.
  1000.  *         Returns NULL on any error.
  1001.  */
  1002. u_char         *
  1003. asn_build_sequence(u_char * data,
  1004.                    size_t * datalength, u_char type, size_t length)
  1005. {
  1006.     static const char *errpre = "build seq";
  1007.     char            ebuf[128];
  1008.     if (*datalength < 4) {
  1009.         snprintf(ebuf, sizeof(ebuf),
  1010.                 "%s: length %d < 4: PUNT", errpre,
  1011.                 (int) *datalength);
  1012.         ebuf[ sizeof(ebuf)-1 ] = 0;
  1013.         ERROR_MSG(ebuf);
  1014.         return NULL;
  1015.     }
  1016.     *datalength -= 4;
  1017.     *data++ = type;
  1018.     *data++ = (u_char) (0x02 | ASN_LONG_LEN);
  1019.     *data++ = (u_char) ((length >> 8) & 0xFF);
  1020.     *data++ = (u_char) (length & 0xFF);
  1021.     return data;
  1022. }
  1023. /**
  1024.  * @internal
  1025.  * asn_parse_length - interprets the length of the current object.
  1026.  *
  1027.  *  On exit, length contains the value of this length field.
  1028.  *
  1029.  *  Returns a pointer to the first byte after this length
  1030.  *  field (aka: the start of the data field).
  1031.  *  Returns NULL on any error.
  1032.  *
  1033.  * @param data         IN - pointer to start of length field
  1034.  * @param length       OUT - value of length field
  1035.  *
  1036.  *  @return Returns a pointer to the first byte after this length
  1037.  *          field (aka: the start of the data field).
  1038.  *          Returns NULL on any error.
  1039.  */
  1040. u_char         *
  1041. asn_parse_length(u_char * data, u_long * length)
  1042. {
  1043.     static const char *errpre = "parse length";
  1044.     char            ebuf[128];
  1045.     register u_char lengthbyte;
  1046.     if (!data || !length) {
  1047.         ERROR_MSG("parse length: NULL pointer");
  1048.         return NULL;
  1049.     }
  1050.     lengthbyte = *data;
  1051.     if (lengthbyte & ASN_LONG_LEN) {
  1052.         lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
  1053.         if (lengthbyte == 0) {
  1054.             snprintf(ebuf, sizeof(ebuf),
  1055.                      "%s: indefinite length not supported", errpre);
  1056.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1057.             ERROR_MSG(ebuf);
  1058.             return NULL;
  1059.         }
  1060.         if (lengthbyte > sizeof(long)) {
  1061.             snprintf(ebuf, sizeof(ebuf),
  1062.                     "%s: data length %d > %lu not supported", errpre,
  1063.                     lengthbyte, (unsigned long)sizeof(long));
  1064.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1065.             ERROR_MSG(ebuf);
  1066.             return NULL;
  1067.         }
  1068.         data++;
  1069.         *length = 0;            /* protect against short lengths */
  1070.         while (lengthbyte--) {
  1071.             *length <<= 8;
  1072.             *length |= *data++;
  1073.         }
  1074.         if ((long) *length < 0) {
  1075.             snprintf(ebuf, sizeof(ebuf),
  1076.                      "%s: negative data length %ldn", errpre,
  1077.                      (long) *length);
  1078.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1079.             ERROR_MSG(ebuf);
  1080.             return NULL;
  1081.         }
  1082.         return data;
  1083.     } else {                    /* short asnlength */
  1084.         *length = (long) lengthbyte;
  1085.         return data + 1;
  1086.     }
  1087. }
  1088. /**
  1089.  * @internal
  1090.  * asn_build_length - builds an ASN header for a length with
  1091.  * length specified.
  1092.  *
  1093.  *  On entry, datalength is input as the number of valid bytes following
  1094.  *   "data".  On exit, it is returned as the number of valid bytes
  1095.  *   in this object following the length.
  1096.  *
  1097.  *
  1098.  *  Returns a pointer to the first byte of the contents of this object.
  1099.  *  Returns NULL on any error.
  1100.  *
  1101.  * @param data         IN - pointer to start of object
  1102.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1103.  * @param length       IN - length of object
  1104.  *
  1105.  * @return Returns a pointer to the first byte of the contents of this object.
  1106.  *         Returns NULL on any error.
  1107.  */
  1108. u_char         *
  1109. asn_build_length(u_char * data, size_t * datalength, size_t length)
  1110. {
  1111.     static const char *errpre = "build length";
  1112.     char            ebuf[128];
  1113.     u_char         *start_data = data;
  1114.     /*
  1115.      * no indefinite lengths sent 
  1116.      */
  1117.     if (length < 0x80) {
  1118.         if (*datalength < 1) {
  1119.             snprintf(ebuf, sizeof(ebuf),
  1120.                     "%s: bad length < 1 :%lu, %lu", errpre,
  1121.                     (unsigned long)*datalength, (unsigned long)length);
  1122.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1123.             ERROR_MSG(ebuf);
  1124.             return NULL;
  1125.         }
  1126.         *data++ = (u_char) length;
  1127.     } else if (length <= 0xFF) {
  1128.         if (*datalength < 2) {
  1129.             snprintf(ebuf, sizeof(ebuf),
  1130.                     "%s: bad length < 2 :%lu, %lu", errpre,
  1131.                     (unsigned long)*datalength, (unsigned long)length);
  1132.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1133.             ERROR_MSG(ebuf);
  1134.             return NULL;
  1135.         }
  1136.         *data++ = (u_char) (0x01 | ASN_LONG_LEN);
  1137.         *data++ = (u_char) length;
  1138.     } else {                    /* 0xFF < length <= 0xFFFF */
  1139.         if (*datalength < 3) {
  1140.             snprintf(ebuf, sizeof(ebuf),
  1141.                     "%s: bad length < 3 :%lu, %lu", errpre,
  1142.                     (unsigned long)*datalength, (unsigned long)length);
  1143.             ebuf[ sizeof(ebuf)-1 ] = 0;
  1144.             ERROR_MSG(ebuf);
  1145.             return NULL;
  1146.         }
  1147.         *data++ = (u_char) (0x02 | ASN_LONG_LEN);
  1148.         *data++ = (u_char) ((length >> 8) & 0xFF);
  1149.         *data++ = (u_char) (length & 0xFF);
  1150.     }
  1151.     *datalength -= (data - start_data);
  1152.     return data;
  1153. }
  1154. /**
  1155.  * @internal
  1156.  * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
  1157.  *
  1158.  *  On entry, datalength is input as the number of valid bytes following
  1159.  *   "data".  On exit, it is returned as the number of valid bytes
  1160.  *   following the beginning of the next object.
  1161.  *
  1162.  *  "objid" is filled with the object identifier.
  1163.  *
  1164.  *  Returns a pointer to the first byte past the end
  1165.  *   of this object (i.e. the start of the next object).
  1166.  *  Returns NULL on any error.
  1167.  *
  1168.  * @param data         IN - pointer to start of object
  1169.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1170.  * @param type         OUT - asn type of object
  1171.  * @param objid        IN/OUT - pointer to start of output buffer
  1172.  * @param objidlength  IN/OUT - number of sub-id's in objid
  1173.  *
  1174.  *  @return Returns a pointer to the first byte past the end
  1175.  *   of this object (i.e. the start of the next object).
  1176.  *  Returns NULL on any error.
  1177.  *
  1178.  */
  1179. u_char         *
  1180. asn_parse_objid(u_char * data,
  1181.                 size_t * datalength,
  1182.                 u_char * type, oid * objid, size_t * objidlength)
  1183. {
  1184.     /*
  1185.      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  1186.      * subidentifier ::= {leadingbyte}* lastbyte
  1187.      * leadingbyte ::= 1 7bitvalue
  1188.      * lastbyte ::= 0 7bitvalue
  1189.      */
  1190.     register u_char *bufp = data;
  1191.     register oid   *oidp = objid + 1;
  1192.     register u_long subidentifier;
  1193.     register long   length;
  1194.     u_long          asn_length;
  1195.     *type = *bufp++;
  1196.     bufp = asn_parse_length(bufp, &asn_length);
  1197.     if (_asn_parse_length_check("parse objid", bufp, data,
  1198.                                 asn_length, *datalength))
  1199.         return NULL;
  1200.     *datalength -= (int) asn_length + (bufp - data);
  1201.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  1202.     /*
  1203.      * Handle invalid object identifier encodings of the form 06 00 robustly 
  1204.      */
  1205.     if (asn_length == 0)
  1206.         objid[0] = objid[1] = 0;
  1207.     length = asn_length;
  1208.     (*objidlength)--;           /* account for expansion of first byte */
  1209.     while (length > 0 && (*objidlength)-- > 0) {
  1210.         subidentifier = 0;
  1211.         do {                    /* shift and add in low order 7 bits */
  1212.             subidentifier =
  1213.                 (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
  1214.             length--;
  1215.         } while (*(u_char *) bufp++ & ASN_BIT8);        /* last byte has high bit clear */
  1216. #if defined(EIGHTBIT_SUBIDS) || (SIZEOF_LONG != 4)
  1217.         if (subidentifier > (u_long) MAX_SUBID) {
  1218.             ERROR_MSG("subidentifier too large");
  1219.             return NULL;
  1220.         }
  1221. #endif
  1222.         *oidp++ = (oid) subidentifier;
  1223.     }
  1224.     if (0 != length) {
  1225.         ERROR_MSG("OID length exceeds buffer size");
  1226.         return NULL;
  1227.     }
  1228.     /*
  1229.      * The first two subidentifiers are encoded into the first component
  1230.      * with the value (X * 40) + Y, where:
  1231.      *  X is the value of the first subidentifier.
  1232.      *  Y is the value of the second subidentifier.
  1233.      */
  1234.     subidentifier = (u_long) objid[1];
  1235.     if (subidentifier == 0x2B) {
  1236.         objid[0] = 1;
  1237.         objid[1] = 3;
  1238.     } else {
  1239.         if (subidentifier < 40) {
  1240.             objid[0] = 0;
  1241.             objid[1] = subidentifier;
  1242.         } else if (subidentifier < 80) {
  1243.             objid[0] = 1;
  1244.             objid[1] = subidentifier - 40;
  1245.         } else {
  1246.             objid[0] = 2;
  1247.             objid[1] = subidentifier - 80;
  1248.         }
  1249.     }
  1250.     *objidlength = (int) (oidp - objid);
  1251.     DEBUGMSG(("dumpv_recv", "  ObjID: "));
  1252.     DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
  1253.     DEBUGMSG(("dumpv_recv", "n"));
  1254.     return bufp;
  1255. }
  1256. /**
  1257.  * @internal
  1258.  * asn_build_objid - Builds an ASN object identifier object containing the
  1259.  * input string.
  1260.  *
  1261.  *  On entry, datalength is input as the number of valid bytes following
  1262.  *   "data".  On exit, it is returned as the number of valid bytes
  1263.  *   following the beginning of the next object.
  1264.  *
  1265.  *  Returns a pointer to the first byte past the end
  1266.  *   of this object (i.e. the start of the next object).
  1267.  *  Returns NULL on any error.
  1268.  *
  1269.  * @param data         IN - pointer to start of object
  1270.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1271.  * @param type         IN - asn type of object
  1272.  * @param objid        IN - pointer to start of input buffer
  1273.  * @param objidlength  IN - number of sub-id's in objid
  1274.  *
  1275.  * @return   Returns a pointer to the first byte past the end
  1276.  *           of this object (i.e. the start of the next object).
  1277.  *           Returns NULL on any error.
  1278.  */
  1279. u_char         *
  1280. asn_build_objid(u_char * data,
  1281.                 size_t * datalength,
  1282.                 u_char type, oid * objid, size_t objidlength)
  1283. {
  1284.     /*
  1285.      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  1286.      * subidentifier ::= {leadingbyte}* lastbyte
  1287.      * leadingbyte ::= 1 7bitvalue
  1288.      * lastbyte ::= 0 7bitvalue
  1289.      */
  1290.     size_t          asnlength;
  1291.     register oid   *op = objid;
  1292.     u_char          objid_size[MAX_OID_LEN];
  1293.     register u_long objid_val;
  1294.     u_long          first_objid_val;
  1295.     register int    i;
  1296. #ifndef SNMP_NO_DEBUGGING
  1297.     u_char         *initdatap = data;
  1298. #endif
  1299.     /*
  1300.      * check if there are at least 2 sub-identifiers 
  1301.      */
  1302.     if (objidlength == 0) {
  1303.         /*
  1304.          * there are not, so make OID have two with value of zero 
  1305.          */
  1306.         objid_val = 0;
  1307.         objidlength = 2;
  1308.     } else if (objid[0] > 2) {
  1309.         ERROR_MSG("build objid: bad first subidentifier");
  1310.         return NULL;
  1311.     } else if (objidlength == 1) {
  1312.         /*
  1313.          * encode the first value 
  1314.          */
  1315.         objid_val = (op[0] * 40);
  1316.         objidlength = 2;
  1317.         op++;
  1318.     } else {
  1319.         /*
  1320.          * combine the first two values 
  1321.          */
  1322.         if ((op[1] > 40) &&
  1323.             (op[0] < 2)) {
  1324.             ERROR_MSG("build objid: bad second subidentifier");
  1325.             return NULL;
  1326.         }
  1327.         objid_val = (op[0] * 40) + op[1];
  1328.         op += 2;
  1329.     }
  1330.     first_objid_val = objid_val;
  1331.     /*
  1332.      * ditch illegal calls now 
  1333.      */
  1334.     if (objidlength > MAX_OID_LEN)
  1335.         return NULL;
  1336.     /*
  1337.      * calculate the number of bytes needed to store the encoded value 
  1338.      */
  1339.     for (i = 1, asnlength = 0;;) {
  1340.         CHECK_OVERFLOW_U(objid_val,5);
  1341.         if (objid_val < (unsigned) 0x80) {
  1342.             objid_size[i] = 1;
  1343.             asnlength += 1;
  1344.         } else if (objid_val < (unsigned) 0x4000) {
  1345.             objid_size[i] = 2;
  1346.             asnlength += 2;
  1347.         } else if (objid_val < (unsigned) 0x200000) {
  1348.             objid_size[i] = 3;
  1349.             asnlength += 3;
  1350.         } else if (objid_val < (unsigned) 0x10000000) {
  1351.             objid_size[i] = 4;
  1352.             asnlength += 4;
  1353.         } else {
  1354.             objid_size[i] = 5;
  1355.             asnlength += 5;
  1356.         }
  1357.         i++;
  1358.         if (i >= (int) objidlength)
  1359.             break;
  1360.         objid_val = *op++; /* XXX - doesn't handle 2.X (X > 40) */
  1361.     }
  1362.     /*
  1363.      * store the ASN.1 tag and length 
  1364.      */
  1365.     data = asn_build_header(data, datalength, type, asnlength);
  1366.     if (_asn_build_header_check
  1367.         ("build objid", data, *datalength, asnlength))
  1368.         return NULL;
  1369.     /*
  1370.      * store the encoded OID value 
  1371.      */
  1372.     for (i = 1, objid_val = first_objid_val, op = objid + 2;
  1373.          i < (int) objidlength; i++) {
  1374.         if (i != 1) {
  1375.             objid_val = *op++;
  1376. #if SIZEOF_LONG != 4
  1377.             if (objid_val > 0xffffffff) /* already logged warning above */
  1378.                 objid_val &= 0xffffffff;
  1379. #endif
  1380.         }
  1381.         switch (objid_size[i]) {
  1382.         case 1:
  1383.             *data++ = (u_char) objid_val;
  1384.             break;
  1385.         case 2:
  1386.             *data++ = (u_char) ((objid_val >> 7) | 0x80);
  1387.             *data++ = (u_char) (objid_val & 0x07f);
  1388.             break;
  1389.         case 3:
  1390.             *data++ = (u_char) ((objid_val >> 14) | 0x80);
  1391.             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
  1392.             *data++ = (u_char) (objid_val & 0x07f);
  1393.             break;
  1394.         case 4:
  1395.             *data++ = (u_char) ((objid_val >> 21) | 0x80);
  1396.             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
  1397.             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
  1398.             *data++ = (u_char) (objid_val & 0x07f);
  1399.             break;
  1400.         case 5:
  1401.             *data++ = (u_char) ((objid_val >> 28) | 0x80);
  1402.             *data++ = (u_char) ((objid_val >> 21 & 0x7f) | 0x80);
  1403.             *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
  1404.             *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
  1405.             *data++ = (u_char) (objid_val & 0x07f);
  1406.             break;
  1407.         }
  1408.     }
  1409.     /*
  1410.      * return the length and data ptr 
  1411.      */
  1412.     *datalength -= asnlength;
  1413.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  1414.     DEBUGMSG(("dumpv_send", "  ObjID: "));
  1415.     DEBUGMSGOID(("dumpv_send", objid, objidlength));
  1416.     DEBUGMSG(("dumpv_send", "n"));
  1417.     return data;
  1418. }
  1419. /**
  1420.  * @internal
  1421.  * asn_parse_null - Interprets an ASN null type.
  1422.  *
  1423.  *  On entry, datalength is input as the number of valid bytes following
  1424.  *   "data".  On exit, it is returned as the number of valid bytes
  1425.  *   following the beginning of the next object.
  1426.  *
  1427.  *  Returns a pointer to the first byte past the end
  1428.  *   of this object (i.e. the start of the next object).
  1429.  *  Returns NULL on any error.
  1430.  *
  1431.  * @param data         IN - pointer to start of object
  1432.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1433.  * @param type         OUT - asn type of object
  1434.  *  @return Returns a pointer to the first byte past the end
  1435.  *          of this object (i.e. the start of the next object).
  1436.  *          Returns NULL on any error.
  1437.  */
  1438. u_char         *
  1439. asn_parse_null(u_char * data, size_t * datalength, u_char * type)
  1440. {
  1441.     /*
  1442.      * ASN.1 null ::= 0x05 0x00
  1443.      */
  1444.     register u_char *bufp = data;
  1445.     u_long          asn_length;
  1446.     *type = *bufp++;
  1447.     bufp = asn_parse_length(bufp, &asn_length);
  1448.     if (bufp == NULL) {
  1449.         ERROR_MSG("parse null: bad length");
  1450.         return NULL;
  1451.     }
  1452.     if (asn_length != 0) {
  1453.         ERROR_MSG("parse null: malformed ASN.1 null");
  1454.         return NULL;
  1455.     }
  1456.     *datalength -= (bufp - data);
  1457.     DEBUGDUMPSETUP("recv", data, bufp - data);
  1458.     DEBUGMSG(("dumpv_recv", "  NULLn"));
  1459.     return bufp + asn_length;
  1460. }
  1461. /**
  1462.  * @internal
  1463.  * asn_build_null - Builds an ASN null object.
  1464.  *
  1465.  *  On entry, datalength is input as the number of valid bytes following
  1466.  *   "data".  On exit, it is returned as the number of valid bytes
  1467.  *   following the beginning of the next object.
  1468.  *
  1469.  *  Returns a pointer to the first byte past the end
  1470.  *   of this object (i.e. the start of the next object).
  1471.  *  Returns NULL on any error.
  1472.  *
  1473.  * @param data         IN - pointer to start of object
  1474.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1475.  * @param type         IN - asn type of object
  1476.  * @retun  Returns a pointer to the first byte past the end
  1477.  *         of this object (i.e. the start of the next object).
  1478.  *         Returns NULL on any error.
  1479.  *
  1480.  */
  1481. u_char         *
  1482. asn_build_null(u_char * data, size_t * datalength, u_char type)
  1483. {
  1484.     /*
  1485.      * ASN.1 null ::= 0x05 0x00
  1486.      */
  1487. #ifndef SNMP_NO_DEBUGGING
  1488.     u_char         *initdatap = data;
  1489. #endif
  1490.     data = asn_build_header(data, datalength, type, 0);
  1491.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  1492.     DEBUGMSG(("dumpv_send", "  NULLn"));
  1493.     return data;
  1494. }
  1495. /**
  1496.  * @internal
  1497.  * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
  1498.  *
  1499.  *  On entry, datalength is input as the number of valid bytes following
  1500.  *   "data".  On exit, it is returned as the number of valid bytes
  1501.  *   following the beginning of the next object.
  1502.  *
  1503.  *  "string" is filled with the bit string.
  1504.  *
  1505.  *  Returns a pointer to the first byte past the end
  1506.  *   of this object (i.e. the start of the next object).
  1507.  *  Returns NULL on any error.
  1508.  *
  1509.  * @param data         IN - pointer to start of object
  1510.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1511.  * @param type         OUT - asn type of object
  1512.  * @param string       IN/OUT - pointer to start of output buffer
  1513.  * @param strlength    IN/OUT - size of output buffer
  1514.  * @return Returns a pointer to the first byte past the end
  1515.  *         of this object (i.e. the start of the next object).
  1516.  *         Returns NULL on any error.
  1517.  */
  1518. u_char         *
  1519. asn_parse_bitstring(u_char * data,
  1520.                     size_t * datalength,
  1521.                     u_char * type, u_char * str, size_t * strlength)
  1522. {
  1523.     /*
  1524.      * bitstring ::= 0x03 asnlength unused {byte}*
  1525.      */
  1526.     static const char *errpre = "parse bitstring";
  1527.     register u_char *bufp = data;
  1528.     u_long          asn_length;
  1529.     *type = *bufp++;
  1530.     bufp = asn_parse_length(bufp, &asn_length);
  1531.     if (_asn_parse_length_check(errpre, bufp, data,
  1532.                                 asn_length, *datalength))
  1533.         return NULL;
  1534.     if ((size_t) asn_length > *strlength) {
  1535.         _asn_length_err(errpre, (size_t) asn_length, *strlength);
  1536.         return NULL;
  1537.     }
  1538.     if (_asn_bitstring_check(errpre, asn_length, *bufp))
  1539.         return NULL;
  1540.     DEBUGDUMPSETUP("recv", data, bufp - data);
  1541.     DEBUGMSG(("dumpv_recv", "  Bitstring: "));
  1542.     DEBUGMSGHEX(("dumpv_recv", data, asn_length));
  1543.     DEBUGMSG(("dumpv_recv", "n"));
  1544.     memmove(str, bufp, asn_length);
  1545.     *strlength = (int) asn_length;
  1546.     *datalength -= (int) asn_length + (bufp - data);
  1547.     return bufp + asn_length;
  1548. }
  1549. /**
  1550.  * @internal
  1551.  * asn_build_bitstring - Builds an ASN bit string object containing the
  1552.  * input string.
  1553.  *
  1554.  *  On entry, datalength is input as the number of valid bytes following
  1555.  *   "data".  On exit, it is returned as the number of valid bytes
  1556.  *   following the beginning of the next object.
  1557.  *
  1558.  *  Returns a pointer to the first byte past the end
  1559.  *   of this object (i.e. the start of the next object).
  1560.  *  Returns NULL on any error.
  1561.  *
  1562.  * @param data         IN - pointer to start of object
  1563.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1564.  * @param type         IN - asn type of object
  1565.  * @param string       IN - pointer to start of input buffer
  1566.  * @param strlength    IN - size of input buffer
  1567.  * @return Returns a pointer to the first byte past the end
  1568.  *         of this object (i.e. the start of the next object).
  1569.  *         Returns NULL on any error.
  1570.  */
  1571. u_char         *
  1572. asn_build_bitstring(u_char * data,
  1573.                     size_t * datalength,
  1574.                     u_char type, const u_char * str, size_t strlength)
  1575. {
  1576.     /*
  1577.      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
  1578.      */
  1579.     static const char *errpre = "build bitstring";
  1580.     if (_asn_bitstring_check
  1581.         (errpre, strlength, (u_char)((str) ? *str :  0)))
  1582.         return NULL;
  1583.     data = asn_build_header(data, datalength, type, strlength);
  1584.     if (_asn_build_header_check(errpre, data, *datalength, strlength))
  1585.         return NULL;
  1586.     if (strlength > 0 && str)
  1587.         memmove(data, str, strlength);
  1588.     else if (strlength > 0 && !str) {
  1589.         ERROR_MSG("no string passed into asn_build_bitstringn");
  1590.         return NULL;
  1591.     }
  1592.     *datalength -= strlength;
  1593.     DEBUGDUMPSETUP("send", data, strlength);
  1594.     DEBUGMSG(("dumpv_send", "  Bitstring: "));
  1595.     DEBUGMSGHEX(("dumpv_send", data, strlength));
  1596.     DEBUGMSG(("dumpv_send", "n"));
  1597.     return data + strlength;
  1598. }
  1599. /**
  1600.  * @internal
  1601.  * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
  1602.  * type.
  1603.  *
  1604.  *  On entry, datalength is input as the number of valid bytes following
  1605.  *   "data".  On exit, it is returned as the number of valid bytes
  1606.  *   following the end of this object.
  1607.  *
  1608.  *  Returns a pointer to the first byte past the end
  1609.  *   of this object (i.e. the start of the next object).
  1610.  *  Returns NULL on any error.
  1611.  *
  1612.  * @param data         IN - pointer to start of object
  1613.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1614.  * @param type         OUT - asn type of object
  1615.  * @param cp           IN/OUT - pointer to counter struct
  1616.  * @param countersize  IN - size of output buffer
  1617.  * @return  Returns a pointer to the first byte past the end
  1618.  *          of this object (i.e. the start of the next object).
  1619.  *          Returns NULL on any error.
  1620.  */
  1621. u_char         *
  1622. asn_parse_unsigned_int64(u_char * data,
  1623.                          size_t * datalength,
  1624.                          u_char * type,
  1625.                          struct counter64 * cp, size_t countersize)
  1626. {
  1627.     /*
  1628.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  1629.      */
  1630.     static const char *errpre = "parse uint64";
  1631.     const int       uint64sizelimit = (4 * 2) + 1;
  1632.     register u_char *bufp = data;
  1633.     u_long          asn_length;
  1634.     register u_long low = 0, high = 0;
  1635.     if (countersize != sizeof(struct counter64)) {
  1636.         _asn_size_err(errpre, countersize, sizeof(struct counter64));
  1637.         return NULL;
  1638.     }
  1639.     *type = *bufp++;
  1640.     bufp = asn_parse_length(bufp, &asn_length);
  1641.     if (_asn_parse_length_check
  1642.         (errpre, bufp, data, asn_length, *datalength))
  1643.         return NULL;
  1644.     DEBUGDUMPSETUP("recv", data, bufp - data);
  1645. #ifdef OPAQUE_SPECIAL_TYPES
  1646.     /*
  1647.      * 64 bit counters as opaque 
  1648.      */
  1649.     if ((*type == ASN_OPAQUE) &&
  1650.         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
  1651.         (*bufp == ASN_OPAQUE_TAG1) &&
  1652.         ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
  1653.          (*(bufp + 1) == ASN_OPAQUE_U64))) {
  1654.         /*
  1655.          * change type to Counter64 or U64 
  1656.          */
  1657.         *type = *(bufp + 1);
  1658.         /*
  1659.          * value is encoded as special format 
  1660.          */
  1661.         bufp = asn_parse_length(bufp + 2, &asn_length);
  1662.         if (_asn_parse_length_check("parse opaque uint64", bufp, data,
  1663.                                     asn_length, *datalength))
  1664.             return NULL;
  1665.     }
  1666. #endif                          /* OPAQUE_SPECIAL_TYPES */
  1667.     if (((int) asn_length > uint64sizelimit) ||
  1668.         (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
  1669.         _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
  1670.         return NULL;
  1671.     }
  1672.     *datalength -= (int) asn_length + (bufp - data);
  1673.     if (*bufp & 0x80) {
  1674.         low = ~low;             /* integer is negative */
  1675.         high = ~high;
  1676.     }
  1677.     while (asn_length--) {
  1678.         high = (high << 8) | ((low & 0xFF000000) >> 24);
  1679.         low = (low << 8) | *bufp++;
  1680.     }
  1681.     CHECK_OVERFLOW_U(high,6);
  1682.     CHECK_OVERFLOW_U(low,6);
  1683.     cp->low = low;
  1684.     cp->high = high;
  1685.     DEBUGIF("dumpv_recv") {
  1686.         char            i64buf[I64CHARSZ + 1];
  1687.         printU64(i64buf, cp);
  1688.         DEBUGMSG(("dumpv_recv", "Counter64: %s", i64buf));
  1689.     }
  1690.     return bufp;
  1691. }
  1692. /**
  1693.  * @internal
  1694.  * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
  1695.  *
  1696.  *  On entry, datalength is input as the number of valid bytes following
  1697.  *   "data".  On exit, it is returned as the number of valid bytes
  1698.  *   following the end of this object.
  1699.  *
  1700.  *  Returns a pointer to the first byte past the end
  1701.  *   of this object (i.e. the start of the next object).
  1702.  *  Returns NULL on any error.
  1703.  *
  1704.  * @param data         IN - pointer to start of output buffer
  1705.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1706.  * @param type         IN  - asn type of object
  1707.  * @param cp           IN - pointer to counter struct
  1708.  * @param countersize  IN - size of input buffer
  1709.  * @return  Returns a pointer to the first byte past the end
  1710.  *          of this object (i.e. the start of the next object).
  1711.  *          Returns NULL on any error.
  1712.  */
  1713. u_char         *
  1714. asn_build_unsigned_int64(u_char * data,
  1715.                          size_t * datalength,
  1716.                          u_char type,
  1717.                          const struct counter64 * cp, size_t countersize)
  1718. {
  1719.     /*
  1720.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  1721.      */
  1722.     register u_long low, high;
  1723.     register u_long mask, mask2;
  1724.     int             add_null_byte = 0;
  1725.     size_t          intsize;
  1726. #ifndef SNMP_NO_DEBUGGING
  1727.     u_char         *initdatap = data;
  1728. #endif
  1729.     if (countersize != sizeof(struct counter64)) {
  1730.         _asn_size_err("build uint64", countersize,
  1731.                       sizeof(struct counter64));
  1732.         return NULL;
  1733.     }
  1734.     intsize = 8;
  1735.     low = cp->low;
  1736.     high = cp->high;
  1737.     CHECK_OVERFLOW_U(high,7);
  1738.     CHECK_OVERFLOW_U(low,7);
  1739.     mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
  1740.     /*
  1741.      * mask is 0xFF000000 on a big-endian machine 
  1742.      */
  1743.     if ((u_char) ((high & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
  1744.         /*
  1745.          * if MSB is set 
  1746.          */
  1747.         add_null_byte = 1;
  1748.         intsize++;
  1749.     } else {
  1750.         /*
  1751.          * Truncate "unnecessary" bytes off of the most significant end of this 2's
  1752.          * complement integer.
  1753.          * There should be no sequence of 9 consecutive 1's or 0's at the most
  1754.          * significant end of the integer.
  1755.          */
  1756.         mask2 = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
  1757.         /*
  1758.          * mask2 is 0xFF800000 on a big-endian machine 
  1759.          */
  1760.         while ((((high & mask2) == 0) || ((high & mask2) == mask2))
  1761.                && intsize > 1) {
  1762.             intsize--;
  1763.             high = (high << 8)
  1764.                 | ((low & mask) >> (8 * (sizeof(long) - 1)));
  1765.             low <<= 8;
  1766.         }
  1767.     }
  1768. #ifdef OPAQUE_SPECIAL_TYPES
  1769.     /*
  1770.      * encode a Counter64 as an opaque (it also works in SNMPv1) 
  1771.      */
  1772.     /*
  1773.      * turn into Opaque holding special tagged value 
  1774.      */
  1775.     if (type == ASN_OPAQUE_COUNTER64) {
  1776.         /*
  1777.          * put the tag and length for the Opaque wrapper 
  1778.          */
  1779.         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
  1780.         if (_asn_build_header_check
  1781.             ("build counter u64", data, *datalength, intsize + 3))
  1782.             return NULL;
  1783.         /*
  1784.          * put the special tag and length 
  1785.          */
  1786.         *data++ = ASN_OPAQUE_TAG1;
  1787.         *data++ = ASN_OPAQUE_COUNTER64;
  1788.         *data++ = (u_char) intsize;
  1789.         *datalength = *datalength - 3;
  1790.     } else
  1791.         /*
  1792.          * Encode the Unsigned int64 in an opaque 
  1793.          */
  1794.         /*
  1795.          * turn into Opaque holding special tagged value 
  1796.          */
  1797.     if (type == ASN_OPAQUE_U64) {
  1798.         /*
  1799.          * put the tag and length for the Opaque wrapper 
  1800.          */
  1801.         data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
  1802.         if (_asn_build_header_check
  1803.             ("build opaque u64", data, *datalength, intsize + 3))
  1804.             return NULL;
  1805.         /*
  1806.          * put the special tag and length 
  1807.          */
  1808.         *data++ = ASN_OPAQUE_TAG1;
  1809.         *data++ = ASN_OPAQUE_U64;
  1810.         *data++ = (u_char) intsize;
  1811.         *datalength = *datalength - 3;
  1812.     } else {
  1813. #endif                          /* OPAQUE_SPECIAL_TYPES */
  1814.         data = asn_build_header(data, datalength, type, intsize);
  1815.         if (_asn_build_header_check
  1816.             ("build uint64", data, *datalength, intsize))
  1817.             return NULL;
  1818. #ifdef OPAQUE_SPECIAL_TYPES
  1819.     }
  1820. #endif                          /* OPAQUE_SPECIAL_TYPES */
  1821.     *datalength -= intsize;
  1822.     if (add_null_byte == 1) {
  1823.         *data++ = '';
  1824.         intsize--;
  1825.     }
  1826.     while (intsize--) {
  1827.         *data++ = (u_char) ((high & mask) >> (8 * (sizeof(long) - 1)));
  1828.         high = (high << 8)
  1829.             | ((low & mask) >> (8 * (sizeof(long) - 1)));
  1830.         low <<= 8;
  1831.     }
  1832.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  1833.     DEBUGIF("dumpv_send") {
  1834.         char            i64buf[I64CHARSZ + 1];
  1835.         printU64(i64buf, cp);
  1836.         DEBUGMSG(("dumpv_send", i64buf));
  1837.     }
  1838.     return data;
  1839. }
  1840. #ifdef OPAQUE_SPECIAL_TYPES
  1841. /**
  1842.  * @internal
  1843.  * asn_parse_signed_int64 - pulls a 64 bit signed long out of an ASN int
  1844.  * type.
  1845.  *
  1846.  *  On entry, datalength is input as the number of valid bytes following
  1847.  *   "data".  On exit, it is returned as the number of valid bytes
  1848.  *   following the end of this object.
  1849.  *
  1850.  *  Returns a pointer to the first byte past the end
  1851.  *   of this object (i.e. the start of the next object).
  1852.  *  Returns NULL on any error.
  1853.  
  1854.  * @param data         IN - pointer to start of object
  1855.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1856.  * @param type         OUT - asn type of object
  1857.  * @param cp           IN/OUT - pointer to counter struct
  1858.  * @param countersize  IN - size of output buffer
  1859.  * @return  Returns a pointer to the first byte past the end
  1860.  *          of this object (i.e. the start of the next object).
  1861.  *          Returns NULL on any error.
  1862.  */
  1863. u_char         *
  1864. asn_parse_signed_int64(u_char * data,
  1865.                        size_t * datalength,
  1866.                        u_char * type,
  1867.                        struct counter64 * cp, size_t countersize)
  1868. {
  1869.     static const char *errpre = "parse int64";
  1870.     const int       int64sizelimit = (4 * 2) + 1;
  1871.     char            ebuf[128];
  1872.     register u_char *bufp = data;
  1873.     u_long          asn_length;
  1874.     register u_int  low = 0, high = 0;
  1875.     if (countersize != sizeof(struct counter64)) {
  1876.         _asn_size_err(errpre, countersize, sizeof(struct counter64));
  1877.         return NULL;
  1878.     }
  1879.     *type = *bufp++;
  1880.     bufp = asn_parse_length(bufp, &asn_length);
  1881.     if (_asn_parse_length_check
  1882.         (errpre, bufp, data, asn_length, *datalength))
  1883.         return NULL;
  1884.     DEBUGDUMPSETUP("recv", data, bufp - data);
  1885.     if ((*type == ASN_OPAQUE) &&
  1886.         (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
  1887.         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
  1888.         /*
  1889.          * change type to Int64 
  1890.          */
  1891.         *type = *(bufp + 1);
  1892.         /*
  1893.          * value is encoded as special format 
  1894.          */
  1895.         bufp = asn_parse_length(bufp + 2, &asn_length);
  1896.         if (_asn_parse_length_check("parse opaque int64", bufp, data,
  1897.                                     asn_length, *datalength))
  1898.             return NULL;
  1899.     }
  1900.     /*
  1901.      * this should always have been true until snmp gets int64 PDU types 
  1902.      */
  1903.     else {
  1904.         snprintf(ebuf, sizeof(ebuf),
  1905.                 "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
  1906.                 errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
  1907.         ebuf[ sizeof(ebuf)-1 ] = 0;
  1908.         ERROR_MSG(ebuf);
  1909.         return NULL;
  1910.     }
  1911.     if (((int) asn_length > int64sizelimit) ||
  1912.         (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
  1913.         _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
  1914.         return NULL;
  1915.     }
  1916.     *datalength -= (int) asn_length + (bufp - data);
  1917.     if (*bufp & 0x80) {
  1918.         low = ~low;             /* integer is negative */
  1919.         high = ~high;
  1920.     }
  1921.     while (asn_length--) {
  1922.         high = (high << 8) | ((low & 0xFF000000) >> 24);
  1923.         low = (low << 8) | *bufp++;
  1924.     }
  1925.     CHECK_OVERFLOW_U(high,8);
  1926.     CHECK_OVERFLOW_U(low,8);
  1927.     cp->low = low;
  1928.     cp->high = high;
  1929.     DEBUGIF("dumpv_recv") {
  1930.         char            i64buf[I64CHARSZ + 1];
  1931.         printI64(i64buf, cp);
  1932.         DEBUGMSG(("dumpv_recv", "Integer64: %s", i64buf));
  1933.     }
  1934.     return bufp;
  1935. }
  1936. /**
  1937.  * @internal
  1938.  * asn_build_signed_int64 - builds an ASN object containing a 64 bit integer.
  1939.  *
  1940.  *  On entry, datalength is input as the number of valid bytes following
  1941.  *   "data".  On exit, it is returned as the number of valid bytes
  1942.  *   following the end of this object.
  1943.  *
  1944.  *  Returns a pointer to the first byte past the end
  1945.  *   of this object (i.e. the start of the next object).
  1946.  *  Returns NULL on any error.
  1947.  *
  1948.  * @param data         IN - pointer to start of output buffer
  1949.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  1950.  * @param type         IN  - asn type of object
  1951.  * @param cp           IN - pointer to counter struct
  1952.  * @param countersize  IN - size of input buffer
  1953.  * @return  Returns a pointer to the first byte past the end
  1954.  *          of this object (i.e. the start of the next object).
  1955.  *          Returns NULL on any error.
  1956.  */
  1957. u_char         *
  1958. asn_build_signed_int64(u_char * data,
  1959.                        size_t * datalength,
  1960.                        u_char type,
  1961.                        const struct counter64 * cp, size_t countersize)
  1962. {
  1963.     /*
  1964.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  1965.      */
  1966.     struct counter64 c64;
  1967.     register u_int  mask, mask2;
  1968.     u_long          low, high;
  1969.     size_t          intsize;
  1970. #ifndef SNMP_NO_DEBUGGING
  1971.     u_char         *initdatap = data;
  1972. #endif
  1973.     if (countersize != sizeof(struct counter64)) {
  1974.         _asn_size_err("build int64", countersize,
  1975.                       sizeof(struct counter64));
  1976.         return NULL;
  1977.     }
  1978.     intsize = 8;
  1979.     memcpy(&c64, cp, sizeof(struct counter64)); /* we're may modify it */
  1980.     low = c64.low;
  1981.     high = c64.high;
  1982.     CHECK_OVERFLOW_S(high,9);
  1983.     CHECK_OVERFLOW_U(low,9);
  1984.     /*
  1985.      * Truncate "unnecessary" bytes off of the most significant end of this
  1986.      * 2's complement integer.  There should be no sequence of 9
  1987.      * consecutive 1's or 0's at the most significant end of the
  1988.      * integer.
  1989.      */
  1990.     mask = ((u_int) 0xFF) << (8 * (sizeof(u_int) - 1));
  1991.     mask2 = ((u_int) 0x1FF) << ((8 * (sizeof(u_int) - 1)) - 1);
  1992.     /*
  1993.      * mask is 0xFF800000 on a big-endian machine 
  1994.      */
  1995.     while ((((high & mask2) == 0) || ((high & mask2) == mask2))
  1996.            && intsize > 1) {
  1997.         intsize--;
  1998.         high = (high << 8)
  1999.             | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
  2000.         low <<= 8;
  2001.     }
  2002.     /*
  2003.      * until a real int64 gets incorperated into SNMP, we are going to
  2004.      * encode it as an opaque instead.  First, we build the opaque
  2005.      * header and then the int64 tag type we use to mark it as an
  2006.      * int64 in the opaque string. 
  2007.      */
  2008.     data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
  2009.     if (_asn_build_header_check
  2010.         ("build int64", data, *datalength, intsize + 3))
  2011.         return NULL;
  2012.     *data++ = ASN_OPAQUE_TAG1;
  2013.     *data++ = ASN_OPAQUE_I64;
  2014.     *data++ = (u_char) intsize;
  2015.     *datalength -= (3 + intsize);
  2016.     while (intsize--) {
  2017.         *data++ = (u_char) ((high & mask) >> (8 * (sizeof(u_int) - 1)));
  2018.         high = (high << 8)
  2019.             | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
  2020.         low <<= 8;
  2021.     }
  2022.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  2023.     DEBUGIF("dumpv_send") {
  2024.         char            i64buf[I64CHARSZ + 1];
  2025.         printU64(i64buf, cp);
  2026.         DEBUGMSG(("dumpv_send", i64buf));
  2027.     }
  2028.     return data;
  2029. }
  2030. /**
  2031.  * @internal
  2032.  * asn_parse_float - pulls a single precision floating-point out of an opaque type.
  2033.  *
  2034.  *  On entry, datalength is input as the number of valid bytes following
  2035.  *   "data".  On exit, it is returned as the number of valid bytes
  2036.  *   following the end of this object.
  2037.  *
  2038.  *  Returns a pointer to the first byte past the end
  2039.  *   of this object (i.e. the start of the next object).
  2040.  *  Returns NULL on any error.
  2041.  *
  2042.  * @param data         IN - pointer to start of object
  2043.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  2044.  * @param type         OUT - asn type of object
  2045.  * @param floatp       IN/OUT - pointer to float
  2046.  * @param floatsize    IN - size of output buffer
  2047.  * @return  Returns a pointer to the first byte past the end
  2048.  *          of this object (i.e. the start of the next object).
  2049.  *          Returns NULL on any error.
  2050.  */
  2051. u_char         *
  2052. asn_parse_float(u_char * data,
  2053.                 size_t * datalength,
  2054.                 u_char * type, float *floatp, size_t floatsize)
  2055. {
  2056.     register u_char *bufp = data;
  2057.     u_long          asn_length;
  2058.     union {
  2059.         float           floatVal;
  2060.         long            longVal;
  2061.         u_char          c[sizeof(float)];
  2062.     } fu;
  2063.     if (floatsize != sizeof(float)) {
  2064.         _asn_size_err("parse float", floatsize, sizeof(float));
  2065.         return NULL;
  2066.     }
  2067.     *type = *bufp++;
  2068.     bufp = asn_parse_length(bufp, &asn_length);
  2069.     if (_asn_parse_length_check("parse float", bufp, data,
  2070.                                 asn_length, *datalength))
  2071.         return NULL;
  2072.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  2073.     /*
  2074.      * the float is encoded as an opaque 
  2075.      */
  2076.     if ((*type == ASN_OPAQUE) &&
  2077.         (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
  2078.         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
  2079.         /*
  2080.          * value is encoded as special format 
  2081.          */
  2082.         bufp = asn_parse_length(bufp + 2, &asn_length);
  2083.         if (_asn_parse_length_check("parse opaque float", bufp, data,
  2084.                                     asn_length, *datalength))
  2085.             return NULL;
  2086.         /*
  2087.          * change type to Float 
  2088.          */
  2089.         *type = ASN_OPAQUE_FLOAT;
  2090.     }
  2091.     if (asn_length != sizeof(float)) {
  2092.         _asn_size_err("parse seq float", asn_length, sizeof(float));
  2093.         return NULL;
  2094.     }
  2095.     *datalength -= (int) asn_length + (bufp - data);
  2096.     memcpy(&fu.c[0], bufp, asn_length);
  2097.     /*
  2098.      * correct for endian differences 
  2099.      */
  2100.     fu.longVal = ntohl(fu.longVal);
  2101.     *floatp = fu.floatVal;
  2102.     DEBUGMSG(("dumpv_recv", "Opaque float: %fn", *floatp));
  2103.     return bufp;
  2104. }
  2105. /**
  2106.  * @internal
  2107.  * asn_build_float - builds an ASN object containing a single precision floating-point
  2108.  *                    number in an Opaque value.
  2109.  *
  2110.  *  On entry, datalength is input as the number of valid bytes following
  2111.  *   "data".  On exit, it is returned as the number of valid bytes
  2112.  *   following the end of this object.
  2113.  *
  2114.  *  Returns a pointer to the first byte past the end
  2115.  *   of this object (i.e. the start of the next object).
  2116.  *  Returns NULL on any error.
  2117.  *
  2118.  * @param data         IN - pointer to start of object
  2119.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  2120.  * @param type         IN - asn type of object
  2121.  * @param floatp       IN - pointer to float
  2122.  * @param floatsize    IN - size of input buffer
  2123.  * @return  Returns a pointer to the first byte past the end
  2124.  *          of this object (i.e. the start of the next object).
  2125.  *          Returns NULL on any error.
  2126.  */
  2127. u_char         *
  2128. asn_build_float(u_char * data,
  2129.                 size_t * datalength,
  2130.                 u_char type, const float *floatp, size_t floatsize)
  2131. {
  2132.     union {
  2133.         float           floatVal;
  2134.         int             intVal;
  2135.         u_char          c[sizeof(float)];
  2136.     } fu;
  2137. #ifndef SNMP_NO_DEBUGGING
  2138.     u_char         *initdatap = data;
  2139. #endif
  2140.     if (floatsize != sizeof(float)) {
  2141.         _asn_size_err("build float", floatsize, sizeof(float));
  2142.         return NULL;
  2143.     }
  2144.     /*
  2145.      * encode the float as an opaque 
  2146.      */
  2147.     /*
  2148.      * turn into Opaque holding special tagged value 
  2149.      */
  2150.     /*
  2151.      * put the tag and length for the Opaque wrapper 
  2152.      */
  2153.     data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
  2154.     if (_asn_build_header_check
  2155.         ("build float", data, *datalength, (floatsize + 3)))
  2156.         return NULL;
  2157.     /*
  2158.      * put the special tag and length 
  2159.      */
  2160.     *data++ = ASN_OPAQUE_TAG1;
  2161.     *data++ = ASN_OPAQUE_FLOAT;
  2162.     *data++ = (u_char) floatsize;
  2163.     *datalength = *datalength - 3;
  2164.     fu.floatVal = *floatp;
  2165.     /*
  2166.      * correct for endian differences 
  2167.      */
  2168.     fu.intVal = htonl(fu.intVal);
  2169.     *datalength -= floatsize;
  2170.     memcpy(data, &fu.c[0], floatsize);
  2171.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  2172.     DEBUGMSG(("dumpv_send", "Opaque float: %fn", *floatp));
  2173.     data += floatsize;
  2174.     return data;
  2175. }
  2176. /**
  2177.  * @internal
  2178.  * asn_parse_double - pulls a double out of an opaque type.
  2179.  *
  2180.  *  On entry, datalength is input as the number of valid bytes following
  2181.  *   "data".  On exit, it is returned as the number of valid bytes
  2182.  *   following the end of this object.
  2183.  *
  2184.  *  Returns a pointer to the first byte past the end
  2185.  *   of this object (i.e. the start of the next object).
  2186.  *  Returns NULL on any error.
  2187.  *
  2188.  * @param data         IN - pointer to start of object
  2189.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  2190.  * @param type         OUT - asn type of object
  2191.  * @param doublep       IN/OUT - pointer to double
  2192.  * @param doublesize    IN - size of output buffer
  2193.  * @return  Returns a pointer to the first byte past the end
  2194.  *          of this object (i.e. the start of the next object).
  2195.  *          Returns NULL on any error.
  2196.  */
  2197. u_char         *
  2198. asn_parse_double(u_char * data,
  2199.                  size_t * datalength,
  2200.                  u_char * type, double *doublep, size_t doublesize)
  2201. {
  2202.     register u_char *bufp = data;
  2203.     u_long          asn_length;
  2204.     long            tmp;
  2205.     union {
  2206.         double          doubleVal;
  2207.         int             intVal[2];
  2208.         u_char          c[sizeof(double)];
  2209.     } fu;
  2210.     if (doublesize != sizeof(double)) {
  2211.         _asn_size_err("parse double", doublesize, sizeof(double));
  2212.         return NULL;
  2213.     }
  2214.     *type = *bufp++;
  2215.     bufp = asn_parse_length(bufp, &asn_length);
  2216.     if (_asn_parse_length_check("parse double", bufp, data,
  2217.                                 asn_length, *datalength))
  2218.         return NULL;
  2219.     DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
  2220.     /*
  2221.      * the double is encoded as an opaque 
  2222.      */
  2223.     if ((*type == ASN_OPAQUE) &&
  2224.         (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
  2225.         (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
  2226.         /*
  2227.          * value is encoded as special format 
  2228.          */
  2229.         bufp = asn_parse_length(bufp + 2, &asn_length);
  2230.         if (_asn_parse_length_check("parse opaque double", bufp, data,
  2231.                                     asn_length, *datalength))
  2232.             return NULL;
  2233.         /*
  2234.          * change type to Double 
  2235.          */
  2236.         *type = ASN_OPAQUE_DOUBLE;
  2237.     }
  2238.     if (asn_length != sizeof(double)) {
  2239.         _asn_size_err("parse seq double", asn_length, sizeof(double));
  2240.         return NULL;
  2241.     }
  2242.     *datalength -= (int) asn_length + (bufp - data);
  2243.     memcpy(&fu.c[0], bufp, asn_length);
  2244.     /*
  2245.      * correct for endian differences 
  2246.      */
  2247.     tmp = ntohl(fu.intVal[0]);
  2248.     fu.intVal[0] = ntohl(fu.intVal[1]);
  2249.     fu.intVal[1] = tmp;
  2250.     *doublep = fu.doubleVal;
  2251.     DEBUGMSG(("dumpv_recv", "  Opaque Double:t%fn", *doublep));
  2252.     return bufp;
  2253. }
  2254. /**
  2255.  * @internal
  2256.  * asn_build_double - builds an ASN object containing a double
  2257.  *                    number in an Opaque value.
  2258.  *
  2259.  *  On entry, datalength is input as the number of valid bytes following
  2260.  *   "data".  On exit, it is returned as the number of valid bytes
  2261.  *   following the end of this object.
  2262.  *
  2263.  *  Returns a pointer to the first byte past the end
  2264.  *   of this object (i.e. the start of the next object).
  2265.  *  Returns NULL on any error.
  2266.  *
  2267.  * @param data         IN - pointer to start of object
  2268.  * @param datalength   IN/OUT - number of valid bytes left in buffer
  2269.  * @param type         IN - asn type of object
  2270.  * @param doublep      IN - pointer to double
  2271.  * @param doublesize   IN - size of input buffer
  2272.  * @return  Returns a pointer to the first byte past the end
  2273.  *          of this object (i.e. the start of the next object).
  2274.  *          Returns NULL on any error.
  2275.  */
  2276. u_char         *
  2277. asn_build_double(u_char * data,
  2278.                  size_t * datalength,
  2279.                  u_char type, const double *doublep, size_t doublesize)
  2280. {
  2281.     long            tmp;
  2282.     union {
  2283.         double          doubleVal;
  2284.         int             intVal[2];
  2285.         u_char          c[sizeof(double)];
  2286.     } fu;
  2287. #ifndef SNMP_NO_DEBUGGING
  2288.     u_char         *initdatap = data;
  2289. #endif
  2290.     if (doublesize != sizeof(double)) {
  2291.         _asn_size_err("build double", doublesize, sizeof(double));
  2292.         return NULL;
  2293.     }
  2294.     /*
  2295.      * encode the double as an opaque 
  2296.      */
  2297.     /*
  2298.      * turn into Opaque holding special tagged value 
  2299.      */
  2300.     /*
  2301.      * put the tag and length for the Opaque wrapper 
  2302.      */
  2303.     data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
  2304.     if (_asn_build_header_check
  2305.         ("build double", data, *datalength, doublesize + 3))
  2306.         return NULL;
  2307.     /*
  2308.      * put the special tag and length 
  2309.      */
  2310.     *data++ = ASN_OPAQUE_TAG1;
  2311.     *data++ = ASN_OPAQUE_DOUBLE;
  2312.     *data++ = (u_char) doublesize;
  2313.     *datalength = *datalength - 3;
  2314.     fu.doubleVal = *doublep;
  2315.     /*
  2316.      * correct for endian differences 
  2317.      */
  2318.     tmp = htonl(fu.intVal[0]);
  2319.     fu.intVal[0] = htonl(fu.intVal[1]);
  2320.     fu.intVal[1] = tmp;
  2321.     *datalength -= doublesize;
  2322.     memcpy(data, &fu.c[0], doublesize);
  2323.     data += doublesize;
  2324.     DEBUGDUMPSETUP("send", initdatap, data - initdatap);
  2325.     DEBUGMSG(("dumpv_send", "  Opaque double: %f", *doublep));
  2326.     return data;
  2327. }
  2328. #endif                          /* OPAQUE_SPECIAL_TYPES */
  2329. /**
  2330.  * @internal
  2331.  * This function increases the size of the buffer pointed to by *pkt, which
  2332.  * is initially of size *pkt_len.  Contents are preserved **AT THE TOP END OF 
  2333.  * THE BUFFER** (hence making this function useful for reverse encoding).
  2334.  * You can change the reallocation scheme, but you **MUST** guarantee to
  2335.  * allocate **AT LEAST** one extra byte.  If memory cannot be reallocated,
  2336.  * then return 0; otherwise return 1.   
  2337.  * 
  2338.  * @param pkt     buffer to increase
  2339.  * @param pkt_len initial buffer size
  2340.  * 
  2341.  * @return 1 on success 0 on error (memory cannot be reallocated)
  2342.  */
  2343. int
  2344. asn_realloc(u_char ** pkt, size_t * pkt_len)
  2345. {
  2346.     if (pkt != NULL && pkt_len != NULL) {
  2347.         size_t          old_pkt_len = *pkt_len;
  2348.         DEBUGMSGTL(("asn_realloc", " old_pkt %08p, old_pkt_len %08xn",
  2349.                     *pkt, old_pkt_len));
  2350.         if (snmp_realloc(pkt, pkt_len)) {
  2351.             DEBUGMSGTL(("asn_realloc", " new_pkt %08p, new_pkt_len %08xn",
  2352.                         *pkt, *pkt_len));
  2353.             DEBUGMSGTL(("asn_realloc",
  2354.                         " memmove(%08p + %08x, %08p, %08x)n", *pkt,
  2355.                         (*pkt_len - old_pkt_len), *pkt, old_pkt_len));
  2356.             memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
  2357.             memset(*pkt, (int) ' ', *pkt_len - old_pkt_len);
  2358.             return 1;
  2359.         } else {
  2360.             DEBUGMSG(("asn_realloc", " CANNOT REALLOC()n"));
  2361.         }
  2362.     }
  2363.     return 0;
  2364. }
  2365. #ifdef USE_REVERSE_ASNENCODING
  2366. /**
  2367.  * @internal
  2368.  * reverse  builds an ASN header for a length with
  2369.  * length specified.
  2370.  * 
  2371.  * @param pkt     IN/OUT address of the begining of the buffer.
  2372.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2373.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2374.  * @param r       IN if not zero reallocate the buffer to fit the 
  2375.  *                needed size.
  2376.  * @param length  IN - length of object
  2377.  *
  2378.  * @return 1 on success, 0 on error
  2379.  */
  2380. int
  2381. asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
  2382.                           size_t * offset, int r, size_t length)
  2383. {
  2384.     static const char *errpre = "build length";
  2385.     char            ebuf[128];
  2386.     int             tmp_int;
  2387.     size_t          start_offset = *offset;
  2388.     if (length <= 0x7f) {
  2389.         if (((*pkt_len - *offset) < 1)
  2390.             && !(r && asn_realloc(pkt, pkt_len))) {
  2391.             snprintf(ebuf, sizeof(ebuf),
  2392.                     "%s: bad length < 1 :%ld, %lu", errpre,
  2393.                     (long)(*pkt_len - *offset), (unsigned long)length);
  2394.             ebuf[ sizeof(ebuf)-1 ] = 0;
  2395.             ERROR_MSG(ebuf);
  2396.             return 0;
  2397.         }
  2398.         *(*pkt + *pkt_len - (++*offset)) = length;
  2399.     } else {
  2400.         while (length > 0xff) {
  2401.             if (((*pkt_len - *offset) < 1)
  2402.                 && !(r && asn_realloc(pkt, pkt_len))) {
  2403.                 snprintf(ebuf, sizeof(ebuf),
  2404.                         "%s: bad length < 1 :%ld, %lu", errpre,
  2405.                         (long)(*pkt_len - *offset), (unsigned long)length);
  2406.                 ebuf[ sizeof(ebuf)-1 ] = 0;
  2407.                 ERROR_MSG(ebuf);
  2408.                 return 0;
  2409.             }
  2410.             *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
  2411.             length >>= 8;
  2412.         }
  2413.         while ((*pkt_len - *offset) < 2) {
  2414.             if (!(r && asn_realloc(pkt, pkt_len))) {
  2415.                 snprintf(ebuf, sizeof(ebuf),
  2416.                         "%s: bad length < 1 :%ld, %lu", errpre,
  2417.                         (long)(*pkt_len - *offset), (unsigned long)length);
  2418.                 ebuf[ sizeof(ebuf)-1 ] = 0;
  2419.                 ERROR_MSG(ebuf);
  2420.                 return 0;
  2421.             }
  2422.         }
  2423.         *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
  2424.         tmp_int = *offset - start_offset;
  2425.         *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
  2426.     }
  2427.     return 1;
  2428. }
  2429. /**
  2430.  * @internal
  2431.  * builds an ASN header for an object with the ID and
  2432.  * length specified.
  2433.  *
  2434.  * @see asn_build_header
  2435.  * 
  2436.  * @param pkt     IN/OUT address of the begining of the buffer.
  2437.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2438.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2439.  * @param r       IN if not zero reallocate the buffer to fit the 
  2440.  *                needed size.
  2441.  * @param type   IN - type of object
  2442.  * @param length   IN - length of object
  2443.  *
  2444.  * @return 1 on success, 0 on error
  2445.  */
  2446. int
  2447. asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
  2448.                           size_t * offset, int r,
  2449.                           u_char type, size_t length)
  2450. {
  2451.     char            ebuf[128];
  2452.     if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
  2453.         if (((*pkt_len - *offset) < 1)
  2454.             && !(r && asn_realloc(pkt, pkt_len))) {
  2455.             snprintf(ebuf, sizeof(ebuf),
  2456.                     "bad header length < 1 :%ld, %lu",
  2457.                     (long)(*pkt_len - *offset), (unsigned long)length);
  2458.             ebuf[ sizeof(ebuf)-1 ] = 0;
  2459.             ERROR_MSG(ebuf);
  2460.             return 0;
  2461.         }
  2462.         *(*pkt + *pkt_len - (++*offset)) = type;
  2463.         return 1;
  2464.     }
  2465.     return 0;
  2466. }
  2467. /**
  2468.  * @internal
  2469.  * builds an ASN object containing an int.
  2470.  *
  2471.  * @see asn_build_int
  2472.  * 
  2473.  * @param pkt     IN/OUT address of the begining of the buffer.
  2474.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2475.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2476.  * @param r       IN if not zero reallocate the buffer to fit the 
  2477.  *                needed size.
  2478.  * @param type    IN - type of object
  2479.  * @param intp    IN - pointer to start of long integer
  2480.  * @param intsize IN - size of input buffer
  2481.  *
  2482.  * @return 1 on success, 0 on error
  2483.  */
  2484. int
  2485. asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
  2486.                        size_t * offset, int r,
  2487.                        u_char type, const long *intp, size_t intsize)
  2488. {
  2489.     static const char *errpre = "build int";
  2490.     register long   integer = *intp;
  2491.     int             testvalue;
  2492.     size_t          start_offset = *offset;
  2493.     if (intsize != sizeof(long)) {
  2494.         _asn_size_err(errpre, intsize, sizeof(long));
  2495.         return 0;
  2496.     }
  2497.     CHECK_OVERFLOW_S(integer,10);
  2498.     testvalue = (*intp < 0) ? -1 : 0;
  2499.     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
  2500.         return 0;
  2501.     }
  2502.     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
  2503.     integer >>= 8;
  2504.     while (integer != testvalue) {
  2505.         if (((*pkt_len - *offset) < 1)
  2506.             && !(r && asn_realloc(pkt, pkt_len))) {
  2507.             return 0;
  2508.         }
  2509.         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
  2510.         integer >>= 8;
  2511.     }
  2512.     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
  2513.         /*
  2514.          * Make sure left most bit is representational of the rest of the bits
  2515.          * that aren't encoded.  
  2516.          */
  2517.         if (((*pkt_len - *offset) < 1)
  2518.             && !(r && asn_realloc(pkt, pkt_len))) {
  2519.             return 0;
  2520.         }
  2521.         *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
  2522.     }
  2523.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
  2524.                                   (*offset - start_offset))) {
  2525.         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
  2526.                                             (*offset - start_offset))) {
  2527.             return 0;
  2528.         } else {
  2529.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2530.                            (*offset - start_offset));
  2531.             DEBUGMSG(("dumpv_send", "  Integer:t%ld (0x%.2X)n", *intp,
  2532.                       *intp));
  2533.             return 1;
  2534.         }
  2535.     }
  2536.     return 0;
  2537. }
  2538. /**
  2539.  * @internal
  2540.  * builds an ASN object containing an string.
  2541.  *
  2542.  * @see asn_build_string 
  2543.  * 
  2544.  * @param pkt     IN/OUT address of the begining of the buffer.
  2545.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2546.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2547.  * @param r       IN if not zero reallocate the buffer to fit the 
  2548.  *                needed size.
  2549.  * @param type    IN - type of object
  2550.  * @param string    IN - pointer to start of the string
  2551.  * @param strlength IN - size of input buffer
  2552.  *
  2553.  * @return 1 on success, 0 on error
  2554.  */
  2555. int
  2556. asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
  2557.                           size_t * offset, int r,
  2558.                           u_char type,
  2559.                           const u_char * str, size_t strlength)
  2560. {
  2561.     static const char *errpre = "build string";
  2562.     size_t          start_offset = *offset;
  2563.     while ((*pkt_len - *offset) < strlength) {
  2564.         if (!(r && asn_realloc(pkt, pkt_len))) {
  2565.             return 0;
  2566.         }
  2567.     }
  2568.     *offset += strlength;
  2569.     memcpy(*pkt + *pkt_len - *offset, str, strlength);
  2570.     if (asn_realloc_rbuild_header
  2571.         (pkt, pkt_len, offset, r, type, strlength)) {
  2572.         if (_asn_realloc_build_header_check
  2573.             (errpre, pkt, pkt_len, strlength)) {
  2574.             return 0;
  2575.         } else {
  2576.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2577.                            *offset - start_offset);
  2578.             DEBUGIF("dumpv_send") {
  2579.                 if (strlength == 0) {
  2580.                     DEBUGMSG(("dumpv_send", "  String: [NULL]n"));
  2581.                 } else {
  2582.                     u_char         *buf = (u_char *) malloc(2 * strlength);
  2583.                     size_t          l =
  2584.                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
  2585.                     if (sprint_realloc_asciistring
  2586.                         (&buf, &l, &ol, 1, str, strlength)) {
  2587.                         DEBUGMSG(("dumpv_send", "  String:t%sn", buf));
  2588.                     } else {
  2589.                         if (buf == NULL) {
  2590.                             DEBUGMSG(("dumpv_send",
  2591.                                       "  String:t[TRUNCATED]n"));
  2592.                         } else {
  2593.                             DEBUGMSG(("dumpv_send",
  2594.                                       "  String:t%s [TRUNCATED]n", buf));
  2595.                         }
  2596.                     }
  2597.                     if (buf != NULL) {
  2598.                         free(buf);
  2599.                     }
  2600.                 }
  2601.             }
  2602.         }
  2603.         return 1;
  2604.     }
  2605.     return 0;
  2606. }
  2607. /**
  2608.  * @internal
  2609.  * builds an ASN object containing an unsigned int.
  2610.  *
  2611.  * @see asn_build_unsigned_int
  2612.  * 
  2613.  * @param pkt     IN/OUT address of the begining of the buffer.
  2614.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2615.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2616.  * @param r       IN if not zero reallocate the buffer to fit the 
  2617.  *                needed size.
  2618.  * @param type    IN - type of object
  2619.  * @param intp    IN - pointer to start of unsigned int
  2620.  * @param intsize IN - size of input buffer
  2621.  *
  2622.  * @return 1 on success, 0 on error
  2623.  */
  2624. int
  2625. asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
  2626.                                 size_t * offset, int r,
  2627.                             u_char type, const u_long * intp, size_t intsize)
  2628. {
  2629.     static const char *errpre = "build uint";
  2630.     register u_long integer = *intp;
  2631.     size_t          start_offset = *offset;
  2632.     if (intsize != sizeof(unsigned long)) {
  2633.         _asn_size_err(errpre, intsize, sizeof(unsigned long));
  2634.         return 0;
  2635.     }
  2636.     CHECK_OVERFLOW_U(integer,11);
  2637.     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
  2638.         return 0;
  2639.     }
  2640.     *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
  2641.     integer >>= 8;
  2642.     while (integer != 0) {
  2643.         if (((*pkt_len - *offset) < 1)
  2644.             && !(r && asn_realloc(pkt, pkt_len))) {
  2645.             return 0;
  2646.         }
  2647.         *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
  2648.         integer >>= 8;
  2649.     }
  2650.     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
  2651.         /*
  2652.          * Make sure left most bit is representational of the rest of the bits
  2653.          * that aren't encoded.  
  2654.          */
  2655.         if (((*pkt_len - *offset) < 1)
  2656.             && !(r && asn_realloc(pkt, pkt_len))) {
  2657.             return 0;
  2658.         }
  2659.         *(*pkt + *pkt_len - (++*offset)) = 0;
  2660.     }
  2661.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
  2662.                                   (*offset - start_offset))) {
  2663.         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
  2664.                                             (*offset - start_offset))) {
  2665.             return 0;
  2666.         } else {
  2667.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2668.                            (*offset - start_offset));
  2669.             DEBUGMSG(("dumpv_send", "  UInteger:t%lu (0x%.2X)n", *intp,
  2670.                       *intp));
  2671.             return 1;
  2672.         }
  2673.     }
  2674.     return 0;
  2675. }
  2676. /**
  2677.  * @internal
  2678.  * builds an ASN object containing an sequence.
  2679.  *
  2680.  * @see asn_build_sequence
  2681.  * 
  2682.  * @param pkt     IN/OUT address of the begining of the buffer.
  2683.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2684.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2685.  * @param r       IN if not zero reallocate the buffer to fit the 
  2686.  *                needed size.
  2687.  * @param type    IN - type of object
  2688.  * @param length IN - length of object
  2689.  *
  2690.  * @return 1 on success, 0 on error
  2691.  */
  2692. int
  2693. asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
  2694.                             size_t * offset, int r,
  2695.                             u_char type, size_t length)
  2696. {
  2697.     return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
  2698.                                      length);
  2699. }
  2700. /**
  2701.  * @internal
  2702.  * builds an ASN object containing an objid.
  2703.  *
  2704.  * @see asn_build_objid
  2705.  * 
  2706.  * @param pkt     IN/OUT address of the begining of the buffer.
  2707.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2708.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2709.  * @param r       IN if not zero reallocate the buffer to fit the 
  2710.  *                needed size.
  2711.  * @param type    IN - type of object
  2712.  * @param objid   IN - pointer to the object id
  2713.  * @param objidlength  IN - length of the input 
  2714.  *
  2715.  * @return 1 on success, 0 on error
  2716.  */
  2717. int
  2718. asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
  2719.                          size_t * offset, int r,
  2720.                          u_char type,
  2721.                          const oid * objid, size_t objidlength)
  2722. {
  2723.     /*
  2724.      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  2725.      * subidentifier ::= {leadingbyte}* lastbyte
  2726.      * leadingbyte ::= 1 7bitvalue
  2727.      * lastbyte ::= 0 7bitvalue
  2728.      */
  2729.     register size_t i;
  2730.     register oid    tmpint;
  2731.     size_t          start_offset = *offset;
  2732.     const char     *errpre = "build objid";
  2733.     /*
  2734.      * Check if there are at least 2 sub-identifiers.  
  2735.      */
  2736.     if (objidlength == 0) {
  2737.         /*
  2738.          * There are not, so make OID have two with value of zero.  
  2739.          */
  2740.         while ((*pkt_len - *offset) < 2) {
  2741.             if (!(r && asn_realloc(pkt, pkt_len))) {
  2742.                 return 0;
  2743.             }
  2744.         }
  2745.         *(*pkt + *pkt_len - (++*offset)) = 0;
  2746.         *(*pkt + *pkt_len - (++*offset)) = 0;
  2747.     } else if (objid[0] > 2) {
  2748.         ERROR_MSG("build objid: bad first subidentifier");
  2749.         return 0;
  2750.     } else if (objidlength == 1) {
  2751.         /*
  2752.          * Encode the first value.  
  2753.          */
  2754.         if (((*pkt_len - *offset) < 1)
  2755.             && !(r && asn_realloc(pkt, pkt_len))) {
  2756.             return 0;
  2757.         }
  2758.         *(*pkt + *pkt_len - (++*offset)) = (u_char) objid[0];
  2759.     } else {
  2760.         for (i = objidlength; i > 2; i--) {
  2761.             tmpint = objid[i - 1];
  2762.             CHECK_OVERFLOW_U(tmpint,12);
  2763.             if (((*pkt_len - *offset) < 1)
  2764.                 && !(r && asn_realloc(pkt, pkt_len))) {
  2765.                 return 0;
  2766.             }
  2767.             *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
  2768.             tmpint >>= 7;
  2769.             while (tmpint > 0) {
  2770.                 if (((*pkt_len - *offset) < 1)
  2771.                     && !(r && asn_realloc(pkt, pkt_len))) {
  2772.                     return 0;
  2773.                 }
  2774.                 *(*pkt + *pkt_len - (++*offset)) =
  2775.                     (u_char) ((tmpint & 0x7f) | 0x80);
  2776.                 tmpint >>= 7;
  2777.             }
  2778.         }
  2779.         /*
  2780.          * Combine the first two values.  
  2781.          */
  2782.         if ((objid[1] > 40) &&
  2783.             (objid[0] < 2)) {
  2784.             ERROR_MSG("build objid: bad second subidentifier");
  2785.             return 0;
  2786.         }
  2787.         tmpint = ((objid[0] * 40) + objid[1]);
  2788.         if (((*pkt_len - *offset) < 1)
  2789.             && !(r && asn_realloc(pkt, pkt_len))) {
  2790.             return 0;
  2791.         }
  2792.         *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
  2793.         tmpint >>= 7;
  2794.         while (tmpint > 0) {
  2795.             if (((*pkt_len - *offset) < 1)
  2796.                 && !(r && asn_realloc(pkt, pkt_len))) {
  2797.                 return 0;
  2798.             }
  2799.             *(*pkt + *pkt_len - (++*offset)) =
  2800.                 (u_char) ((tmpint & 0x7f) | 0x80);
  2801.             tmpint >>= 7;
  2802.         }
  2803.     }
  2804.     tmpint = *offset - start_offset;
  2805.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
  2806.                                   (*offset - start_offset))) {
  2807.         if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
  2808.                                             (*offset - start_offset))) {
  2809.             return 0;
  2810.         } else {
  2811.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2812.                            (*offset - start_offset));
  2813.             DEBUGMSG(("dumpv_send", "  ObjID: "));
  2814.             DEBUGMSGOID(("dumpv_send", objid, objidlength));
  2815.             DEBUGMSG(("dumpv_send", "n"));
  2816.             return 1;
  2817.         }
  2818.     }
  2819.     return 0;
  2820. }
  2821. /**
  2822.  * @internal
  2823.  * builds an ASN object containing an null object.
  2824.  *
  2825.  * @see asn_build_null
  2826.  * 
  2827.  * @param pkt     IN/OUT address of the begining of the buffer.
  2828.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2829.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2830.  * @param r       IN if not zero reallocate the buffer to fit the 
  2831.  *                needed size.
  2832.  * @param type    IN - type of object
  2833.  *
  2834.  * @return 1 on success, 0 on error
  2835.  */
  2836. int
  2837. asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
  2838.                         size_t * offset, int r, u_char type)
  2839. {
  2840.     /*
  2841.      * ASN.1 null ::= 0x05 0x00
  2842.      */
  2843.     size_t          start_offset = *offset;
  2844.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
  2845.         DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2846.                        (*offset - start_offset));
  2847.         DEBUGMSG(("dumpv_send", "  NULLn"));
  2848.         return 1;
  2849.     } else {
  2850.         return 0;
  2851.     }
  2852. }
  2853. /**
  2854.  * @internal
  2855.  * builds an ASN object containing an bitstring.
  2856.  *
  2857.  * @see asn_build_bitstring
  2858.  * 
  2859.  * @param pkt     IN/OUT address of the begining of the buffer.
  2860.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2861.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2862.  * @param r       IN if not zero reallocate the buffer to fit the 
  2863.  *                needed size.
  2864.  * @param type    IN - type of object
  2865.  * @param string   IN - pointer to the string
  2866.  * @param strlength  IN - length of the input 
  2867.  *
  2868.  * @return 1 on success, 0 on error
  2869.  */
  2870. int
  2871. asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
  2872.                              size_t * offset, int r,
  2873.                              u_char type,
  2874.                              const u_char * str, size_t strlength)
  2875. {
  2876.     /*
  2877.      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
  2878.      */
  2879.     static const char *errpre = "build bitstring";
  2880.     size_t          start_offset = *offset;
  2881.     while ((*pkt_len - *offset) < strlength) {
  2882.         if (!(r && asn_realloc(pkt, pkt_len))) {
  2883.             return 0;
  2884.         }
  2885.     }
  2886.     *offset += strlength;
  2887.     memcpy(*pkt + *pkt_len - *offset, str, strlength);
  2888.     if (asn_realloc_rbuild_header
  2889.         (pkt, pkt_len, offset, r, type, strlength)) {
  2890.         if (_asn_realloc_build_header_check
  2891.             (errpre, pkt, pkt_len, strlength)) {
  2892.             return 0;
  2893.         } else {
  2894.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  2895.                            *offset - start_offset);
  2896.             DEBUGIF("dumpv_send") {
  2897.                 if (strlength == 0) {
  2898.                     DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]n"));
  2899.                 } else {
  2900.                     u_char         *buf = (u_char *) malloc(2 * strlength);
  2901.                     size_t          l =
  2902.                         (buf != NULL) ? (2 * strlength) : 0, ol = 0;
  2903.                     if (sprint_realloc_asciistring
  2904.                         (&buf, &l, &ol, 1, str, strlength)) {
  2905.                         DEBUGMSG(("dumpv_send", "  Bitstring:t%sn",
  2906.                                   buf));
  2907.                     } else {
  2908.                         if (buf == NULL) {
  2909.                             DEBUGMSG(("dumpv_send",
  2910.                                       "  Bitstring:t[TRUNCATED]n"));
  2911.                         } else {
  2912.                             DEBUGMSG(("dumpv_send",
  2913.                                       "  Bitstring:t%s [TRUNCATED]n",
  2914.                                       buf));
  2915.                         }
  2916.                     }
  2917.                     if (buf != NULL) {
  2918.                         free(buf);
  2919.                     }
  2920.                 }
  2921.             }
  2922.         }
  2923.         return 1;
  2924.     }
  2925.     return 0;
  2926. }
  2927. /**
  2928.  * @internal
  2929.  * builds an ASN object containing an unsigned int64.
  2930.  *
  2931.  * @see asn_build_unsigned_int64
  2932.  * 
  2933.  * @param pkt     IN/OUT address of the begining of the buffer.
  2934.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  2935.  * @param offset  IN/OUT offset to the start of the buffer where to write
  2936.  * @param r       IN if not zero reallocate the buffer to fit the 
  2937.  *                needed size.
  2938.  * @param type    IN - type of object
  2939.  * @param cp           IN - pointer to counter struct
  2940.  * @param countersize  IN - size of input buffer
  2941.  *
  2942.  * @return 1 on success, 0 on error
  2943.  */
  2944. int
  2945. asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
  2946.                                   size_t * offset, int r,
  2947.                                   u_char type,
  2948.                                const struct counter64 *cp, size_t countersize)
  2949. {
  2950.     /*
  2951.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  2952.      */
  2953.     register u_long low = cp->low, high = cp->high;
  2954.     size_t          intsize, start_offset = *offset;
  2955.     int             count;
  2956.     if (countersize != sizeof(struct counter64)) {
  2957.         _asn_size_err("build uint64", countersize,
  2958.                       sizeof(struct counter64));
  2959.         return 0;
  2960.     }
  2961.     CHECK_OVERFLOW_U(high,13);
  2962.     CHECK_OVERFLOW_U(low,13);
  2963.     /*
  2964.      * Encode the low 4 bytes first.  
  2965.      */
  2966.     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
  2967.         return 0;
  2968.     }
  2969.     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
  2970.     low >>= 8;
  2971.     count = 1;
  2972.     while (low != 0) {
  2973.         count++;
  2974.         if (((*pkt_len - *offset) < 1)
  2975.             && !(r && asn_realloc(pkt, pkt_len))) {
  2976.             return 0;
  2977.         }
  2978.         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
  2979.         low >>= 8;
  2980.     }
  2981.     /*
  2982.      * Then the high byte if present.  
  2983.      */
  2984.     if (high) {
  2985.         /*
  2986.          * Do the rest of the low byte.  
  2987.          */
  2988.         for (; count < 4; count++) {
  2989.             if (((*pkt_len - *offset) < 1)
  2990.                 && !(r && asn_realloc(pkt, pkt_len))) {
  2991.                 return 0;
  2992.             }
  2993.             *(*pkt + *pkt_len - (++*offset)) = 0;
  2994.         }
  2995.         /*
  2996.          * Do high byte.  
  2997.          */
  2998.         if (((*pkt_len - *offset) < 1)
  2999.             && !(r && asn_realloc(pkt, pkt_len))) {
  3000.             return 0;
  3001.         }
  3002.         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
  3003.         high >>= 8;
  3004.         while (high != 0) {
  3005.             if (((*pkt_len - *offset) < 1)
  3006.                 && !(r && asn_realloc(pkt, pkt_len))) {
  3007.                 return 0;
  3008.             }
  3009.             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
  3010.             high >>= 8;
  3011.         }
  3012.     }
  3013.     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
  3014.         /*
  3015.          * Make sure left most bit is representational of the rest of the bits
  3016.          * that aren't encoded.  
  3017.          */
  3018.         if (((*pkt_len - *offset) < 1)
  3019.             && !(r && asn_realloc(pkt, pkt_len))) {
  3020.             return 0;
  3021.         }
  3022.         *(*pkt + *pkt_len - (++*offset)) = 0;
  3023.     }
  3024.     intsize = *offset - start_offset;
  3025. #ifdef OPAQUE_SPECIAL_TYPES
  3026.     /*
  3027.      * Encode a Counter64 as an opaque (it also works in SNMPv1).  
  3028.      */
  3029.     if (type == ASN_OPAQUE_COUNTER64) {
  3030.         while ((*pkt_len - *offset) < 5) {
  3031.             if (!(r && asn_realloc(pkt, pkt_len))) {
  3032.                 return 0;
  3033.             }
  3034.         }
  3035.         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
  3036.         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
  3037.         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
  3038.         /*
  3039.          * Put the tag and length for the Opaque wrapper.  
  3040.          */
  3041.         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
  3042.                                       ASN_OPAQUE, intsize + 3)) {
  3043.             if (_asn_realloc_build_header_check
  3044.                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
  3045.                 return 0;
  3046.             }
  3047.         } else {
  3048.             return 0;
  3049.         }
  3050.     } else if (type == ASN_OPAQUE_U64) {
  3051.         /*
  3052.          * Encode the Unsigned int64 in an opaque.  
  3053.          */
  3054.         while ((*pkt_len - *offset) < 5) {
  3055.             if (!(r && asn_realloc(pkt, pkt_len))) {
  3056.                 return 0;
  3057.             }
  3058.         }
  3059.         *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
  3060.         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
  3061.         *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
  3062.         /*
  3063.          * Put the tag and length for the Opaque wrapper.  
  3064.          */
  3065.         if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
  3066.                                       ASN_OPAQUE, intsize + 3)) {
  3067.             if (_asn_realloc_build_header_check
  3068.                 ("build counter u64", pkt, pkt_len, intsize + 3)) {
  3069.                 return 0;
  3070.             }
  3071.         } else {
  3072.             return 0;
  3073.         }
  3074.     } else {
  3075. #endif                          /* OPAQUE_SPECIAL_TYPES */
  3076.         if (asn_realloc_rbuild_header
  3077.             (pkt, pkt_len, offset, r, type, intsize)) {
  3078.             if (_asn_realloc_build_header_check
  3079.                 ("build uint64", pkt, pkt_len, intsize)) {
  3080.                 return 0;
  3081.             }
  3082.         } else {
  3083.             return 0;
  3084.         }
  3085. #ifdef OPAQUE_SPECIAL_TYPES
  3086.     }
  3087. #endif                          /* OPAQUE_SPECIAL_TYPES */
  3088.     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
  3089.     DEBUGMSG(("dumpv_send", "  U64:t%lu %lun", cp->high, cp->low));
  3090.     return 1;
  3091. }
  3092. #ifdef OPAQUE_SPECIAL_TYPES
  3093. /**
  3094.  * @internal
  3095.  * builds an ASN object containing an signed int64.
  3096.  *
  3097.  * @see asn_build_signed_int64
  3098.  * 
  3099.  * @param pkt     IN/OUT address of the begining of the buffer.
  3100.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  3101.  * @param offset  IN/OUT offset to the start of the buffer where to write
  3102.  * @param r       IN if not zero reallocate the buffer to fit the 
  3103.  *                needed size.
  3104.  * @param type    IN - type of object
  3105.  * @param cp           IN - pointer to counter struct
  3106.  * @param countersize  IN - size of input buffer
  3107.  *
  3108.  * @return 1 on success, 0 on error
  3109.  */
  3110. int
  3111. asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
  3112.                                 size_t * offset, int r,
  3113.                                 u_char type,
  3114.                                 const struct counter64 *cp, size_t countersize)
  3115. {
  3116.     /*
  3117.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  3118.      */
  3119.     register u_long low = cp->low, high = cp->high;
  3120.     size_t          intsize, start_offset = *offset;
  3121.     int             count, testvalue = (high & 0x80000000) ? -1 : 0;
  3122.     if (countersize != sizeof(struct counter64)) {
  3123.         _asn_size_err("build uint64", countersize,
  3124.                       sizeof(struct counter64));
  3125.         return 0;
  3126.     }
  3127.     CHECK_OVERFLOW_S(high,14);
  3128.     CHECK_OVERFLOW_U(low,14);
  3129.     /*
  3130.      * Encode the low 4 bytes first.  
  3131.      */
  3132.     if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
  3133.         return 0;
  3134.     }
  3135.     *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
  3136.     low >>= 8;
  3137.     count = 1;
  3138.     while ((int) low != testvalue) {
  3139.         count++;
  3140.         if (((*pkt_len - *offset) < 1)
  3141.             && !(r && asn_realloc(pkt, pkt_len))) {
  3142.             return 0;
  3143.         }
  3144.         *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
  3145.         low >>= 8;
  3146.     }
  3147.     /*
  3148.      * Then the high byte if present.  
  3149.      */
  3150.     if (high) {
  3151.         /*
  3152.          * Do the rest of the low byte.  
  3153.          */
  3154.         for (; count < 4; count++) {
  3155.             if (((*pkt_len - *offset) < 1)
  3156.                 && !(r && asn_realloc(pkt, pkt_len))) {
  3157.                 return 0;
  3158.             }
  3159.             *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
  3160.         }
  3161.         /*
  3162.          * Do high byte.  
  3163.          */
  3164.         if (((*pkt_len - *offset) < 1)
  3165.             && !(r && asn_realloc(pkt, pkt_len))) {
  3166.             return 0;
  3167.         }
  3168.         *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
  3169.         high >>= 8;
  3170.         while ((int) high != testvalue) {
  3171.             if (((*pkt_len - *offset) < 1)
  3172.                 && !(r && asn_realloc(pkt, pkt_len))) {
  3173.                 return 0;
  3174.             }
  3175.             *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
  3176.             high >>= 8;
  3177.         }
  3178.     }
  3179.     if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
  3180.         /*
  3181.          * Make sure left most bit is representational of the rest of the bits
  3182.          * that aren't encoded.  
  3183.          */
  3184.         if (((*pkt_len - *offset) < 1)
  3185.             && !(r && asn_realloc(pkt, pkt_len))) {
  3186.             return 0;
  3187.         }
  3188.         *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
  3189.     }
  3190.     intsize = *offset - start_offset;
  3191.     while ((*pkt_len - *offset) < 5) {
  3192.         if (!(r && asn_realloc(pkt, pkt_len))) {
  3193.             return 0;
  3194.         }
  3195.     }
  3196.     *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
  3197.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
  3198.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
  3199.     /*
  3200.      * Put the tag and length for the Opaque wrapper.  
  3201.      */
  3202.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
  3203.                                   ASN_OPAQUE, intsize + 3)) {
  3204.         if (_asn_realloc_build_header_check
  3205.             ("build counter u64", pkt, pkt_len, intsize + 3)) {
  3206.             return 0;
  3207.         }
  3208.     } else {
  3209.         return 0;
  3210.     }
  3211.     DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
  3212.     DEBUGMSG(("dumpv_send", "  UInt64:t%lu %lun", cp->high, cp->low));
  3213.     return 1;
  3214. }
  3215. /**
  3216.  * @internal
  3217.  * builds an ASN object containing an float.
  3218.  *
  3219.  * @see asn_build_float
  3220.  * 
  3221.  * @param pkt     IN/OUT address of the begining of the buffer.
  3222.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  3223.  * @param offset  IN/OUT offset to the start of the buffer where to write
  3224.  * @param r       IN if not zero reallocate the buffer to fit the 
  3225.  *                needed size.
  3226.  * @param type       IN - type of object
  3227.  * @param floatp     IN - pointer to the float
  3228.  * @param floatsize  IN - size of input buffer
  3229.  *
  3230.  * @return 1 on success, 0 on error
  3231.  */
  3232. int
  3233. asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
  3234.                          size_t * offset, int r,
  3235.                          u_char type, const float *floatp, size_t floatsize)
  3236. {
  3237.     size_t          start_offset = *offset;
  3238.     union {
  3239.         float           floatVal;
  3240.         int             intVal;
  3241.         u_char          c[sizeof(float)];
  3242.     } fu;
  3243.     /*
  3244.      * Floatsize better not be larger than realistic.  
  3245.      */
  3246.     if (floatsize != sizeof(float) || floatsize > 122) {
  3247.         return 0;
  3248.     }
  3249.     while ((*pkt_len - *offset) < floatsize + 3) {
  3250.         if (!(r && asn_realloc(pkt, pkt_len))) {
  3251.             return 0;
  3252.         }
  3253.     }
  3254.     /*
  3255.      * Correct for endian differences and copy value.  
  3256.      */
  3257.     fu.floatVal = *floatp;
  3258.     fu.intVal = htonl(fu.intVal);
  3259.     *offset += floatsize;
  3260.     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
  3261.     /*
  3262.      * Put the special tag and length (3 bytes).  
  3263.      */
  3264.     *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
  3265.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
  3266.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
  3267.     /*
  3268.      * Put the tag and length for the Opaque wrapper.  
  3269.      */
  3270.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
  3271.                                   ASN_OPAQUE, floatsize + 3)) {
  3272.         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
  3273.                                             floatsize + 3)) {
  3274.             return 0;
  3275.         } else {
  3276.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  3277.                            *offset - start_offset);
  3278.             DEBUGMSG(("dumpv_send", "Opaque Float:t%fn", *floatp));
  3279.             return 1;
  3280.         }
  3281.     }
  3282.     return 0;
  3283. }
  3284. /**
  3285.  * @internal
  3286.  * builds an ASN object containing an double.
  3287.  *
  3288.  * @see asn_build_double
  3289.  * 
  3290.  * @param pkt     IN/OUT address of the begining of the buffer.
  3291.  * @param pkt_len IN/OUT address to an integer containing the size of pkt.
  3292.  * @param offset  IN/OUT offset to the start of the buffer where to write
  3293.  * @param r       IN if not zero reallocate the buffer to fit the 
  3294.  *                needed size.
  3295.  * @param type    IN - type of object
  3296.  * @param doublep           IN - pointer to double
  3297.  * @param doublesize  IN - size of input buffer
  3298.  *
  3299.  * @return 1 on success, 0 on error
  3300.  */
  3301. int
  3302. asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
  3303.                           size_t * offset, int r,
  3304.                           u_char type, const double *doublep, size_t doublesize)
  3305. {
  3306.     size_t          start_offset = *offset;
  3307.     long            tmp;
  3308.     union {
  3309.         double          doubleVal;
  3310.         int             intVal[2];
  3311.         u_char          c[sizeof(double)];
  3312.     } fu;
  3313.     /*
  3314.      * Doublesize better not be larger than realistic.  
  3315.      */
  3316.     if (doublesize != sizeof(double) || doublesize > 122) {
  3317.         return 0;
  3318.     }
  3319.     while ((*pkt_len - *offset) < doublesize + 3) {
  3320.         if (!(r && asn_realloc(pkt, pkt_len))) {
  3321.             return 0;
  3322.         }
  3323.     }
  3324.     /*
  3325.      * Correct for endian differences and copy value.  
  3326.      */
  3327.     fu.doubleVal = *doublep;
  3328.     tmp = htonl(fu.intVal[0]);
  3329.     fu.intVal[0] = htonl(fu.intVal[1]);
  3330.     fu.intVal[1] = tmp;
  3331.     *offset += doublesize;
  3332.     memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
  3333.     /*
  3334.      * Put the special tag and length (3 bytes).  
  3335.      */
  3336.     *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
  3337.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
  3338.     *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
  3339.     /*
  3340.      * Put the tag and length for the Opaque wrapper.  
  3341.      */
  3342.     if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
  3343.                                   ASN_OPAQUE, doublesize + 3)) {
  3344.         if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
  3345.                                             doublesize + 3)) {
  3346.             return 0;
  3347.         } else {
  3348.             DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
  3349.                            *offset - start_offset);
  3350.             DEBUGMSG(("dumpv_send", "  Opaque Double:t%fn", *doublep));
  3351.             return 1;
  3352.         }
  3353.     }
  3354.     return 0;
  3355. }
  3356. #endif                          /* OPAQUE_SPECIAL_TYPES */
  3357. #endif                          /*  USE_REVERSE_ASNENCODING  */
  3358. /**
  3359.  * @}
  3360.  */