00001 /* 00002 * Abstract Syntax Notation One, ASN.1 00003 * As defined in ISO/IS 8824 and ISO/IS 8825 00004 * This implements a subset of the above International Standards that 00005 * is sufficient to implement SNMP. 00006 * 00007 * Encodes abstract data types into a machine independent stream of bytes. 00008 * 00009 */ 00010 /********************************************************************** 00011 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University 00012 00013 All Rights Reserved 00014 00015 Permission to use, copy, modify, and distribute this software and its 00016 documentation for any purpose and without fee is hereby granted, 00017 provided that the above copyright notice appear in all copies and that 00018 both that copyright notice and this permission notice appear in 00019 supporting documentation, and that the name of CMU not be 00020 used in advertising or publicity pertaining to distribution of the 00021 software without specific, written prior permission. 00022 00023 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 00024 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 00025 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 00026 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 00027 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 00028 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 00029 SOFTWARE. 00030 ******************************************************************/ 00156 #include <net-snmp/net-snmp-config.h> 00157 00158 #ifdef KINETICS 00159 #include "gw.h" 00160 #endif 00161 00162 #if HAVE_STRING_H 00163 #include <string.h> 00164 #else 00165 #include <strings.h> 00166 #endif 00167 00168 #include <sys/types.h> 00169 #include <stdio.h> 00170 #ifdef HAVE_STDLIB_H 00171 #include <stdlib.h> 00172 #endif 00173 #if HAVE_WINSOCK_H 00174 #include <winsock.h> 00175 #endif 00176 #if HAVE_NETINET_IN_H 00177 #include <netinet/in.h> 00178 #endif 00179 00180 #ifdef vms 00181 #include <in.h> 00182 #endif 00183 00184 #if HAVE_DMALLOC_H 00185 #include <dmalloc.h> 00186 #endif 00187 00188 #include <net-snmp/output_api.h> 00189 #include <net-snmp/utilities.h> 00190 00191 #include <net-snmp/library/asn1.h> 00192 #include <net-snmp/library/int64.h> 00193 #include <net-snmp/library/mib.h> 00194 00195 #ifndef NULL 00196 #define NULL 0 00197 #endif 00198 00199 #include <net-snmp/library/snmp_api.h> 00200 00201 #ifndef INT32_MAX 00202 # define INT32_MAX 2147483647 00203 #endif 00204 00205 #ifndef INT32_MIN 00206 # define INT32_MIN (0 - INT32_MAX - 1) 00207 #endif 00208 00209 00210 #if SIZEOF_LONG == 4 00211 # define CHECK_OVERFLOW_S(x,y) 00212 # define CHECK_OVERFLOW_U(x,y) 00213 #else 00214 # define CHECK_OVERFLOW_S(x,y) do { int trunc = 0; \ 00215 if (x > INT32_MAX) { \ 00216 trunc = 1; \ 00217 x &= 0xffffffff; \ 00218 } else if (x < INT32_MIN) { \ 00219 trunc = 1; \ 00220 x = 0 - (x & 0xffffffff); \ 00221 } \ 00222 if (trunc) \ 00223 DEBUGMSG(("asn","truncating signed value to 32 bits (%d)\n",y)); \ 00224 } while(0) 00225 00226 # define CHECK_OVERFLOW_U(x,y) do { \ 00227 if (x > UINT32_MAX) { \ 00228 x &= 0xffffffff; \ 00229 DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \ 00230 } \ 00231 } while(0) 00232 #endif 00233 00242 static 00243 void 00244 _asn_size_err(const char *str, size_t wrongsize, size_t rightsize) 00245 { 00246 char ebuf[128]; 00247 00248 snprintf(ebuf, sizeof(ebuf), 00249 "%s size %lu: s/b %lu", str, 00250 (unsigned long)wrongsize, (unsigned long)rightsize); 00251 ebuf[ sizeof(ebuf)-1 ] = 0; 00252 ERROR_MSG(ebuf); 00253 } 00254 00263 static 00264 void 00265 _asn_length_err(const char *str, size_t wrongsize, size_t rightsize) 00266 { 00267 char ebuf[128]; 00268 00269 snprintf(ebuf, sizeof(ebuf), 00270 "%s length %lu too large: exceeds %lu", str, 00271 (unsigned long)wrongsize, (unsigned long)rightsize); 00272 ebuf[ sizeof(ebuf)-1 ] = 0; 00273 ERROR_MSG(ebuf); 00274 } 00275 00288 static 00289 int 00290 _asn_parse_length_check(const char *str, 00291 const u_char * bufp, const u_char * data, 00292 u_long plen, size_t dlen) 00293 { 00294 char ebuf[128]; 00295 size_t header_len; 00296 00297 if (bufp == NULL) { 00298 /* 00299 * error message is set 00300 */ 00301 return 1; 00302 } 00303 header_len = bufp - data; 00304 if (plen > 0x7fffffff || header_len > 0x7fffffff || 00305 ((size_t) plen + header_len) > dlen) { 00306 snprintf(ebuf, sizeof(ebuf), 00307 "%s: message overflow: %d len + %d delta > %d len", 00308 str, (int) plen, (int) header_len, (int) dlen); 00309 ebuf[ sizeof(ebuf)-1 ] = 0; 00310 ERROR_MSG(ebuf); 00311 return 1; 00312 } 00313 return 0; 00314 } 00315 00316 00328 static 00329 int 00330 _asn_build_header_check(const char *str, const u_char * data, 00331 size_t datalen, size_t typedlen) 00332 { 00333 char ebuf[128]; 00334 00335 if (data == NULL) { 00336 /* 00337 * error message is set 00338 */ 00339 return 1; 00340 } 00341 if (datalen < typedlen) { 00342 snprintf(ebuf, sizeof(ebuf), 00343 "%s: bad header, length too short: %lu < %lu", str, 00344 (unsigned long)datalen, (unsigned long)typedlen); 00345 ebuf[ sizeof(ebuf)-1 ] = 0; 00346 ERROR_MSG(ebuf); 00347 return 1; 00348 } 00349 return 0; 00350 } 00351 00363 static 00364 int 00365 _asn_realloc_build_header_check(const char *str, 00366 u_char ** pkt, 00367 const size_t * pkt_len, size_t typedlen) 00368 { 00369 char ebuf[128]; 00370 00371 if (pkt == NULL || *pkt == NULL) { 00372 /* 00373 * Error message is set. 00374 */ 00375 return 1; 00376 } 00377 00378 if (*pkt_len < typedlen) { 00379 snprintf(ebuf, sizeof(ebuf), 00380 "%s: bad header, length too short: %lu < %lu", str, 00381 (unsigned long)*pkt_len, (unsigned long)typedlen); 00382 ebuf[ sizeof(ebuf)-1 ] = 0; 00383 ERROR_MSG(ebuf); 00384 return 1; 00385 } 00386 return 0; 00387 } 00388 00398 int 00399 asn_check_packet(u_char * pkt, size_t len) 00400 { 00401 u_long asn_length; 00402 00403 if (len < 2) 00404 return 0; /* always too short */ 00405 00406 if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR)) 00407 return -1; /* wrong type */ 00408 00409 if (*(pkt + 1) & 0x80) { 00410 /* 00411 * long length 00412 */ 00413 if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2) 00414 return 0; /* still to short, incomplete length */ 00415 asn_parse_length(pkt + 1, &asn_length); 00416 return (asn_length + 2 + (*(pkt + 1) & ~0x80)); 00417 } else { 00418 /* 00419 * short length 00420 */ 00421 return (*(pkt + 1) + 2); 00422 } 00423 } 00424 00425 static 00426 int 00427 _asn_bitstring_check(const char *str, size_t asn_length, u_char datum) 00428 { 00429 char ebuf[128]; 00430 00431 if (asn_length < 1) { 00432 snprintf(ebuf, sizeof(ebuf), 00433 "%s: length %d too small", str, (int) asn_length); 00434 ebuf[ sizeof(ebuf)-1 ] = 0; 00435 ERROR_MSG(ebuf); 00436 return 1; 00437 } 00438 /* 00439 * if (datum > 7){ 00440 * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum)); 00441 * ERROR_MSG(ebuf); 00442 * return 1; 00443 * } 00444 */ 00445 return 0; 00446 } 00447 00469 u_char * 00470 asn_parse_int(u_char * data, 00471 size_t * datalength, 00472 u_char * type, long *intp, size_t intsize) 00473 { 00474 /* 00475 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 00476 */ 00477 static const char *errpre = "parse int"; 00478 register u_char *bufp = data; 00479 u_long asn_length; 00480 register long value = 0; 00481 00482 if (intsize != sizeof(long)) { 00483 _asn_size_err(errpre, intsize, sizeof(long)); 00484 return NULL; 00485 } 00486 *type = *bufp++; 00487 bufp = asn_parse_length(bufp, &asn_length); 00488 if (_asn_parse_length_check 00489 (errpre, bufp, data, asn_length, *datalength)) 00490 return NULL; 00491 00492 if ((size_t) asn_length > intsize) { 00493 _asn_length_err(errpre, (size_t) asn_length, intsize); 00494 return NULL; 00495 } 00496 00497 *datalength -= (int) asn_length + (bufp - data); 00498 if (*bufp & 0x80) 00499 value = -1; /* integer is negative */ 00500 00501 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 00502 00503 while (asn_length--) 00504 value = (value << 8) | *bufp++; 00505 00506 CHECK_OVERFLOW_S(value,1); 00507 00508 DEBUGMSG(("dumpv_recv", " Integer:\t%ld (0x%.2lX)\n", value, value)); 00509 00510 *intp = value; 00511 return bufp; 00512 } 00513 00514 00536 u_char * 00537 asn_parse_unsigned_int(u_char * data, 00538 size_t * datalength, 00539 u_char * type, u_long * intp, size_t intsize) 00540 { 00541 /* 00542 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 00543 */ 00544 static const char *errpre = "parse uint"; 00545 register u_char *bufp = data; 00546 u_long asn_length; 00547 register u_long value = 0; 00548 00549 if (intsize != sizeof(long)) { 00550 _asn_size_err(errpre, intsize, sizeof(long)); 00551 return NULL; 00552 } 00553 *type = *bufp++; 00554 bufp = asn_parse_length(bufp, &asn_length); 00555 if (_asn_parse_length_check 00556 (errpre, bufp, data, asn_length, *datalength)) 00557 return NULL; 00558 00559 if (((int) asn_length > (intsize + 1)) || 00560 (((int) asn_length == intsize + 1) && *bufp != 0x00)) { 00561 _asn_length_err(errpre, (size_t) asn_length, intsize); 00562 return NULL; 00563 } 00564 *datalength -= (int) asn_length + (bufp - data); 00565 if (*bufp & 0x80) 00566 value = ~value; /* integer is negative */ 00567 00568 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 00569 00570 while (asn_length--) 00571 value = (value << 8) | *bufp++; 00572 00573 CHECK_OVERFLOW_U(value,2); 00574 00575 DEBUGMSG(("dumpv_recv", " UInteger:\t%ld (0x%.2lX)\n", value, value)); 00576 00577 *intp = value; 00578 return bufp; 00579 } 00580 00581 00605 u_char * 00606 asn_build_int(u_char * data, 00607 size_t * datalength, u_char type, const long *intp, size_t intsize) 00608 { 00609 /* 00610 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 00611 */ 00612 static const char *errpre = "build int"; 00613 register long integer; 00614 register u_long mask; 00615 #ifndef NETSNMP_NO_DEBUGGING 00616 u_char *initdatap = data; 00617 #endif 00618 00619 if (intsize != sizeof(long)) { 00620 _asn_size_err(errpre, intsize, sizeof(long)); 00621 return NULL; 00622 } 00623 integer = *intp; 00624 CHECK_OVERFLOW_S(integer,3); 00625 /* 00626 * Truncate "unnecessary" bytes off of the most significant end of this 00627 * 2's complement integer. There should be no sequence of 9 00628 * consecutive 1's or 0's at the most significant end of the 00629 * integer. 00630 */ 00631 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1); 00632 /* 00633 * mask is 0xFF800000 on a big-endian machine 00634 */ 00635 while ((((integer & mask) == 0) || ((integer & mask) == mask)) 00636 && intsize > 1) { 00637 intsize--; 00638 integer <<= 8; 00639 } 00640 data = asn_build_header(data, datalength, type, intsize); 00641 if (_asn_build_header_check(errpre, data, *datalength, intsize)) 00642 return NULL; 00643 00644 *datalength -= intsize; 00645 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1)); 00646 /* 00647 * mask is 0xFF000000 on a big-endian machine 00648 */ 00649 while (intsize--) { 00650 *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))); 00651 integer <<= 8; 00652 } 00653 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 00654 DEBUGMSG(("dumpv_send", " Integer:\t%ld (0x%.2lX)\n", *intp, *intp)); 00655 return data; 00656 } 00657 00658 00659 00683 u_char * 00684 asn_build_unsigned_int(u_char * data, 00685 size_t * datalength, 00686 u_char type, const u_long * intp, size_t intsize) 00687 { 00688 /* 00689 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 00690 */ 00691 static const char *errpre = "build uint"; 00692 register u_long integer; 00693 register u_long mask; 00694 int add_null_byte = 0; 00695 #ifndef NETSNMP_NO_DEBUGGING 00696 u_char *initdatap = data; 00697 #endif 00698 00699 if (intsize != sizeof(long)) { 00700 _asn_size_err(errpre, intsize, sizeof(long)); 00701 return NULL; 00702 } 00703 integer = *intp; 00704 CHECK_OVERFLOW_U(integer,4); 00705 00706 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1)); 00707 /* 00708 * mask is 0xFF000000 on a big-endian machine 00709 */ 00710 if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) { 00711 /* 00712 * if MSB is set 00713 */ 00714 add_null_byte = 1; 00715 intsize++; 00716 } else { 00717 /* 00718 * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer. 00719 * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the 00720 * integer. 00721 */ 00722 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1); 00723 /* 00724 * mask is 0xFF800000 on a big-endian machine 00725 */ 00726 while ((((integer & mask) == 0) || ((integer & mask) == mask)) 00727 && intsize > 1) { 00728 intsize--; 00729 integer <<= 8; 00730 } 00731 } 00732 data = asn_build_header(data, datalength, type, intsize); 00733 if (_asn_build_header_check(errpre, data, *datalength, intsize)) 00734 return NULL; 00735 00736 *datalength -= intsize; 00737 if (add_null_byte == 1) { 00738 *data++ = '\0'; 00739 intsize--; 00740 } 00741 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1)); 00742 /* 00743 * mask is 0xFF000000 on a big-endian machine 00744 */ 00745 while (intsize--) { 00746 *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))); 00747 integer <<= 8; 00748 } 00749 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 00750 DEBUGMSG(("dumpv_send", " UInteger:\t%ld (0x%.2lX)\n", *intp, *intp)); 00751 return data; 00752 } 00753 00754 00783 u_char * 00784 asn_parse_string(u_char * data, 00785 size_t * datalength, 00786 u_char * type, u_char * str, size_t * strlength) 00787 { 00788 static const char *errpre = "parse string"; 00789 u_char *bufp = data; 00790 u_long asn_length; 00791 00792 *type = *bufp++; 00793 bufp = asn_parse_length(bufp, &asn_length); 00794 if (_asn_parse_length_check 00795 (errpre, bufp, data, asn_length, *datalength)) { 00796 return NULL; 00797 } 00798 00799 if ((int) asn_length > *strlength) { 00800 _asn_length_err(errpre, (size_t) asn_length, *strlength); 00801 return NULL; 00802 } 00803 00804 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 00805 00806 memmove(str, bufp, asn_length); 00807 if (*strlength > (int) asn_length) 00808 str[asn_length] = 0; 00809 *strlength = (int) asn_length; 00810 *datalength -= (int) asn_length + (bufp - data); 00811 00812 DEBUGIF("dumpv_recv") { 00813 u_char *buf = (u_char *) malloc(1 + asn_length); 00814 size_t l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0; 00815 00816 if (sprint_realloc_asciistring 00817 (&buf, &l, &ol, 1, str, asn_length)) { 00818 DEBUGMSG(("dumpv_recv", " String:\t%s\n", buf)); 00819 } else { 00820 if (buf == NULL) { 00821 DEBUGMSG(("dumpv_recv", " String:\t[TRUNCATED]\n")); 00822 } else { 00823 DEBUGMSG(("dumpv_recv", " String:\t%s [TRUNCATED]\n", 00824 buf)); 00825 } 00826 } 00827 if (buf != NULL) { 00828 free(buf); 00829 } 00830 } 00831 00832 return bufp + asn_length; 00833 } 00834 00835 00858 u_char * 00859 asn_build_string(u_char * data, 00860 size_t * datalength, 00861 u_char type, const u_char * str, size_t strlength) 00862 { 00863 /* 00864 * ASN.1 octet string ::= primstring | cmpdstring 00865 * primstring ::= 0x04 asnlength byte {byte}* 00866 * cmpdstring ::= 0x24 asnlength string {string}* 00867 * This code will never send a compound string. 00868 */ 00869 #ifndef NETSNMP_NO_DEBUGGING 00870 u_char *initdatap = data; 00871 #endif 00872 data = asn_build_header(data, datalength, type, strlength); 00873 if (_asn_build_header_check 00874 ("build string", data, *datalength, strlength)) 00875 return NULL; 00876 00877 if (strlength) { 00878 if (str == NULL) { 00879 memset(data, 0, strlength); 00880 } else { 00881 memmove(data, str, strlength); 00882 } 00883 } 00884 *datalength -= strlength; 00885 DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength); 00886 DEBUGIF("dumpv_send") { 00887 u_char *buf = (u_char *) malloc(1 + strlength); 00888 size_t l = (buf != NULL) ? (1 + strlength) : 0, ol = 0; 00889 00890 if (sprint_realloc_asciistring 00891 (&buf, &l, &ol, 1, str, strlength)) { 00892 DEBUGMSG(("dumpv_send", " String:\t%s\n", buf)); 00893 } else { 00894 if (buf == NULL) { 00895 DEBUGMSG(("dumpv_send", " String:\t[TRUNCATED]\n")); 00896 } else { 00897 DEBUGMSG(("dumpv_send", " String:\t%s [TRUNCATED]\n", 00898 buf)); 00899 } 00900 } 00901 if (buf != NULL) { 00902 free(buf); 00903 } 00904 } 00905 return data + strlength; 00906 } 00907 00908 00909 00929 u_char * 00930 asn_parse_header(u_char * data, size_t * datalength, u_char * type) 00931 { 00932 register u_char *bufp; 00933 u_long asn_length; 00934 00935 if (!data || !datalength || !type) { 00936 ERROR_MSG("parse header: NULL pointer"); 00937 return NULL; 00938 } 00939 bufp = data; 00940 /* 00941 * this only works on data types < 30, i.e. no extension octets 00942 */ 00943 if (IS_EXTENSION_ID(*bufp)) { 00944 ERROR_MSG("can't process ID >= 30"); 00945 return NULL; 00946 } 00947 *type = *bufp; 00948 bufp = asn_parse_length(bufp + 1, &asn_length); 00949 00950 if (_asn_parse_length_check 00951 ("parse header", bufp, data, asn_length, *datalength)) 00952 return NULL; 00953 00954 #ifdef DUMP_PRINT_HEADERS 00955 DEBUGDUMPSETUP("recv", data, (bufp - data)); 00956 DEBUGMSG(("dumpv_recv", " Header: 0x%.2X, len = %d (0x%X)\n", *data, 00957 asn_length, asn_length)); 00958 #else 00959 /* 00960 * DEBUGMSGHEXTLI(("recv",data,(bufp-data))); 00961 * DEBUGMSG(("dumpH_recv","\n")); 00962 */ 00963 #endif 00964 00965 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 00966 00967 if ((*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) { 00968 00969 /* 00970 * check if 64-but counter 00971 */ 00972 switch (*(bufp + 1)) { 00973 case ASN_OPAQUE_COUNTER64: 00974 case ASN_OPAQUE_U64: 00975 case ASN_OPAQUE_FLOAT: 00976 case ASN_OPAQUE_DOUBLE: 00977 case ASN_OPAQUE_I64: 00978 *type = *(bufp + 1); 00979 break; 00980 00981 default: 00982 /* 00983 * just an Opaque 00984 */ 00985 *datalength = (int) asn_length; 00986 return bufp; 00987 } 00988 /* 00989 * value is encoded as special format 00990 */ 00991 bufp = asn_parse_length(bufp + 2, &asn_length); 00992 if (_asn_parse_length_check("parse opaque header", bufp, data, 00993 asn_length, *datalength)) 00994 return NULL; 00995 } 00996 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 00997 00998 *datalength = (int) asn_length; 00999 01000 return bufp; 01001 } 01002 01017 u_char * 01018 asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type, /* must be this type */ 01019 const char *estr) 01020 { /* error message prefix */ 01021 data = asn_parse_header(data, datalength, type); 01022 if (data && (*type != expected_type)) { 01023 char ebuf[128]; 01024 snprintf(ebuf, sizeof(ebuf), 01025 "%s header type %02X: s/b %02X", estr, 01026 (u_char) * type, (u_char) expected_type); 01027 ebuf[ sizeof(ebuf)-1 ] = 0; 01028 ERROR_MSG(ebuf); 01029 return NULL; 01030 } 01031 return data; 01032 } 01033 01034 01035 01058 u_char * 01059 asn_build_header(u_char * data, 01060 size_t * datalength, u_char type, size_t length) 01061 { 01062 char ebuf[128]; 01063 01064 if (*datalength < 1) { 01065 snprintf(ebuf, sizeof(ebuf), 01066 "bad header length < 1 :%lu, %lu", 01067 (unsigned long)*datalength, (unsigned long)length); 01068 ebuf[ sizeof(ebuf)-1 ] = 0; 01069 ERROR_MSG(ebuf); 01070 return NULL; 01071 } 01072 *data++ = type; 01073 (*datalength)--; 01074 return asn_build_length(data, datalength, length); 01075 } 01076 01100 u_char * 01101 asn_build_sequence(u_char * data, 01102 size_t * datalength, u_char type, size_t length) 01103 { 01104 static const char *errpre = "build seq"; 01105 char ebuf[128]; 01106 01107 if (*datalength < 4) { 01108 snprintf(ebuf, sizeof(ebuf), 01109 "%s: length %d < 4: PUNT", errpre, 01110 (int) *datalength); 01111 ebuf[ sizeof(ebuf)-1 ] = 0; 01112 ERROR_MSG(ebuf); 01113 return NULL; 01114 } 01115 *datalength -= 4; 01116 *data++ = type; 01117 *data++ = (u_char) (0x02 | ASN_LONG_LEN); 01118 *data++ = (u_char) ((length >> 8) & 0xFF); 01119 *data++ = (u_char) (length & 0xFF); 01120 return data; 01121 } 01122 01140 u_char * 01141 asn_parse_length(u_char * data, u_long * length) 01142 { 01143 static const char *errpre = "parse length"; 01144 char ebuf[128]; 01145 register u_char lengthbyte; 01146 01147 if (!data || !length) { 01148 ERROR_MSG("parse length: NULL pointer"); 01149 return NULL; 01150 } 01151 lengthbyte = *data; 01152 01153 if (lengthbyte & ASN_LONG_LEN) { 01154 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */ 01155 if (lengthbyte == 0) { 01156 snprintf(ebuf, sizeof(ebuf), 01157 "%s: indefinite length not supported", errpre); 01158 ebuf[ sizeof(ebuf)-1 ] = 0; 01159 ERROR_MSG(ebuf); 01160 return NULL; 01161 } 01162 if (lengthbyte > sizeof(long)) { 01163 snprintf(ebuf, sizeof(ebuf), 01164 "%s: data length %d > %lu not supported", errpre, 01165 lengthbyte, (unsigned long)sizeof(long)); 01166 ebuf[ sizeof(ebuf)-1 ] = 0; 01167 ERROR_MSG(ebuf); 01168 return NULL; 01169 } 01170 data++; 01171 *length = 0; /* protect against short lengths */ 01172 while (lengthbyte--) { 01173 *length <<= 8; 01174 *length |= *data++; 01175 } 01176 if ((long) *length < 0) { 01177 snprintf(ebuf, sizeof(ebuf), 01178 "%s: negative data length %ld\n", errpre, 01179 (long) *length); 01180 ebuf[ sizeof(ebuf)-1 ] = 0; 01181 ERROR_MSG(ebuf); 01182 return NULL; 01183 } 01184 return data; 01185 } else { /* short asnlength */ 01186 *length = (long) lengthbyte; 01187 return data + 1; 01188 } 01189 } 01190 01211 u_char * 01212 asn_build_length(u_char * data, size_t * datalength, size_t length) 01213 { 01214 static const char *errpre = "build length"; 01215 char ebuf[128]; 01216 01217 u_char *start_data = data; 01218 01219 /* 01220 * no indefinite lengths sent 01221 */ 01222 if (length < 0x80) { 01223 if (*datalength < 1) { 01224 snprintf(ebuf, sizeof(ebuf), 01225 "%s: bad length < 1 :%lu, %lu", errpre, 01226 (unsigned long)*datalength, (unsigned long)length); 01227 ebuf[ sizeof(ebuf)-1 ] = 0; 01228 ERROR_MSG(ebuf); 01229 return NULL; 01230 } 01231 *data++ = (u_char) length; 01232 } else if (length <= 0xFF) { 01233 if (*datalength < 2) { 01234 snprintf(ebuf, sizeof(ebuf), 01235 "%s: bad length < 2 :%lu, %lu", errpre, 01236 (unsigned long)*datalength, (unsigned long)length); 01237 ebuf[ sizeof(ebuf)-1 ] = 0; 01238 ERROR_MSG(ebuf); 01239 return NULL; 01240 } 01241 *data++ = (u_char) (0x01 | ASN_LONG_LEN); 01242 *data++ = (u_char) length; 01243 } else { /* 0xFF < length <= 0xFFFF */ 01244 if (*datalength < 3) { 01245 snprintf(ebuf, sizeof(ebuf), 01246 "%s: bad length < 3 :%lu, %lu", errpre, 01247 (unsigned long)*datalength, (unsigned long)length); 01248 ebuf[ sizeof(ebuf)-1 ] = 0; 01249 ERROR_MSG(ebuf); 01250 return NULL; 01251 } 01252 *data++ = (u_char) (0x02 | ASN_LONG_LEN); 01253 *data++ = (u_char) ((length >> 8) & 0xFF); 01254 *data++ = (u_char) (length & 0xFF); 01255 } 01256 *datalength -= (data - start_data); 01257 return data; 01258 01259 } 01260 01286 u_char * 01287 asn_parse_objid(u_char * data, 01288 size_t * datalength, 01289 u_char * type, oid * objid, size_t * objidlength) 01290 { 01291 /* 01292 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* 01293 * subidentifier ::= {leadingbyte}* lastbyte 01294 * leadingbyte ::= 1 7bitvalue 01295 * lastbyte ::= 0 7bitvalue 01296 */ 01297 register u_char *bufp = data; 01298 register oid *oidp = objid + 1; 01299 register u_long subidentifier; 01300 register long length; 01301 u_long asn_length; 01302 size_t original_length = *objidlength; 01303 01304 *type = *bufp++; 01305 bufp = asn_parse_length(bufp, &asn_length); 01306 if (_asn_parse_length_check("parse objid", bufp, data, 01307 asn_length, *datalength)) 01308 return NULL; 01309 01310 *datalength -= (int) asn_length + (bufp - data); 01311 01312 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 01313 01314 /* 01315 * Handle invalid object identifier encodings of the form 06 00 robustly 01316 */ 01317 if (asn_length == 0) 01318 objid[0] = objid[1] = 0; 01319 01320 length = asn_length; 01321 (*objidlength)--; /* account for expansion of first byte */ 01322 01323 while (length > 0 && (*objidlength)-- > 0) { 01324 subidentifier = 0; 01325 do { /* shift and add in low order 7 bits */ 01326 subidentifier = 01327 (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8); 01328 length--; 01329 } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0)); /* last byte has high bit clear */ 01330 01331 if (length == 0) { 01332 u_char *last_byte = bufp - 1; 01333 if (*last_byte & ASN_BIT8) { 01334 /* last byte has high bit set -> wrong BER encoded OID */ 01335 ERROR_MSG("subidentifier syntax error"); 01336 return NULL; 01337 } 01338 } 01339 #if defined(EIGHTBIT_SUBIDS) || (SIZEOF_LONG != 4) 01340 if (subidentifier > (u_long) MAX_SUBID) { 01341 ERROR_MSG("subidentifier too large"); 01342 return NULL; 01343 } 01344 #endif 01345 *oidp++ = (oid) subidentifier; 01346 } 01347 01348 if (0 != length) { 01349 ERROR_MSG("OID length exceeds buffer size"); 01350 *objidlength = original_length; 01351 return NULL; 01352 } 01353 01354 /* 01355 * The first two subidentifiers are encoded into the first component 01356 * with the value (X * 40) + Y, where: 01357 * X is the value of the first subidentifier. 01358 * Y is the value of the second subidentifier. 01359 */ 01360 subidentifier = (u_long) objid[1]; 01361 if (subidentifier == 0x2B) { 01362 objid[0] = 1; 01363 objid[1] = 3; 01364 } else { 01365 if (subidentifier < 40) { 01366 objid[0] = 0; 01367 objid[1] = subidentifier; 01368 } else if (subidentifier < 80) { 01369 objid[0] = 1; 01370 objid[1] = subidentifier - 40; 01371 } else { 01372 objid[0] = 2; 01373 objid[1] = subidentifier - 80; 01374 } 01375 } 01376 01377 *objidlength = (int) (oidp - objid); 01378 01379 DEBUGMSG(("dumpv_recv", " ObjID: ")); 01380 DEBUGMSGOID(("dumpv_recv", objid, *objidlength)); 01381 DEBUGMSG(("dumpv_recv", "\n")); 01382 return bufp; 01383 } 01384 01408 u_char * 01409 asn_build_objid(u_char * data, 01410 size_t * datalength, 01411 u_char type, oid * objid, size_t objidlength) 01412 { 01413 /* 01414 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* 01415 * subidentifier ::= {leadingbyte}* lastbyte 01416 * leadingbyte ::= 1 7bitvalue 01417 * lastbyte ::= 0 7bitvalue 01418 */ 01419 size_t asnlength; 01420 register oid *op = objid; 01421 u_char objid_size[MAX_OID_LEN]; 01422 register u_long objid_val; 01423 u_long first_objid_val; 01424 register int i; 01425 #ifndef NETSNMP_NO_DEBUGGING 01426 u_char *initdatap = data; 01427 #endif 01428 01429 /* 01430 * check if there are at least 2 sub-identifiers 01431 */ 01432 if (objidlength == 0) { 01433 /* 01434 * there are not, so make OID have two with value of zero 01435 */ 01436 objid_val = 0; 01437 objidlength = 2; 01438 } else if (objid[0] > 2) { 01439 ERROR_MSG("build objid: bad first subidentifier"); 01440 return NULL; 01441 } else if (objidlength == 1) { 01442 /* 01443 * encode the first value 01444 */ 01445 objid_val = (op[0] * 40); 01446 objidlength = 2; 01447 op++; 01448 } else { 01449 /* 01450 * combine the first two values 01451 */ 01452 if ((op[1] > 40) && 01453 (op[0] < 2)) { 01454 ERROR_MSG("build objid: bad second subidentifier"); 01455 return NULL; 01456 } 01457 objid_val = (op[0] * 40) + op[1]; 01458 op += 2; 01459 } 01460 first_objid_val = objid_val; 01461 01462 /* 01463 * ditch illegal calls now 01464 */ 01465 if (objidlength > MAX_OID_LEN) 01466 return NULL; 01467 01468 /* 01469 * calculate the number of bytes needed to store the encoded value 01470 */ 01471 for (i = 1, asnlength = 0;;) { 01472 01473 CHECK_OVERFLOW_U(objid_val,5); 01474 if (objid_val < (unsigned) 0x80) { 01475 objid_size[i] = 1; 01476 asnlength += 1; 01477 } else if (objid_val < (unsigned) 0x4000) { 01478 objid_size[i] = 2; 01479 asnlength += 2; 01480 } else if (objid_val < (unsigned) 0x200000) { 01481 objid_size[i] = 3; 01482 asnlength += 3; 01483 } else if (objid_val < (unsigned) 0x10000000) { 01484 objid_size[i] = 4; 01485 asnlength += 4; 01486 } else { 01487 objid_size[i] = 5; 01488 asnlength += 5; 01489 } 01490 i++; 01491 if (i >= (int) objidlength) 01492 break; 01493 objid_val = *op++; /* XXX - doesn't handle 2.X (X > 40) */ 01494 } 01495 01496 /* 01497 * store the ASN.1 tag and length 01498 */ 01499 data = asn_build_header(data, datalength, type, asnlength); 01500 if (_asn_build_header_check 01501 ("build objid", data, *datalength, asnlength)) 01502 return NULL; 01503 01504 /* 01505 * store the encoded OID value 01506 */ 01507 for (i = 1, objid_val = first_objid_val, op = objid + 2; 01508 i < (int) objidlength; i++) { 01509 if (i != 1) { 01510 objid_val = *op++; 01511 #if SIZEOF_LONG != 4 01512 if (objid_val > 0xffffffff) /* already logged warning above */ 01513 objid_val &= 0xffffffff; 01514 #endif 01515 } 01516 switch (objid_size[i]) { 01517 case 1: 01518 *data++ = (u_char) objid_val; 01519 break; 01520 01521 case 2: 01522 *data++ = (u_char) ((objid_val >> 7) | 0x80); 01523 *data++ = (u_char) (objid_val & 0x07f); 01524 break; 01525 01526 case 3: 01527 *data++ = (u_char) ((objid_val >> 14) | 0x80); 01528 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80); 01529 *data++ = (u_char) (objid_val & 0x07f); 01530 break; 01531 01532 case 4: 01533 *data++ = (u_char) ((objid_val >> 21) | 0x80); 01534 *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80); 01535 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80); 01536 *data++ = (u_char) (objid_val & 0x07f); 01537 break; 01538 01539 case 5: 01540 *data++ = (u_char) ((objid_val >> 28) | 0x80); 01541 *data++ = (u_char) ((objid_val >> 21 & 0x7f) | 0x80); 01542 *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80); 01543 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80); 01544 *data++ = (u_char) (objid_val & 0x07f); 01545 break; 01546 } 01547 } 01548 01549 /* 01550 * return the length and data ptr 01551 */ 01552 *datalength -= asnlength; 01553 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 01554 DEBUGMSG(("dumpv_send", " ObjID: ")); 01555 DEBUGMSGOID(("dumpv_send", objid, objidlength)); 01556 DEBUGMSG(("dumpv_send", "\n")); 01557 return data; 01558 } 01559 01579 u_char * 01580 asn_parse_null(u_char * data, size_t * datalength, u_char * type) 01581 { 01582 /* 01583 * ASN.1 null ::= 0x05 0x00 01584 */ 01585 register u_char *bufp = data; 01586 u_long asn_length; 01587 01588 *type = *bufp++; 01589 bufp = asn_parse_length(bufp, &asn_length); 01590 if (bufp == NULL) { 01591 ERROR_MSG("parse null: bad length"); 01592 return NULL; 01593 } 01594 if (asn_length != 0) { 01595 ERROR_MSG("parse null: malformed ASN.1 null"); 01596 return NULL; 01597 } 01598 01599 *datalength -= (bufp - data); 01600 01601 DEBUGDUMPSETUP("recv", data, bufp - data); 01602 DEBUGMSG(("dumpv_recv", " NULL\n")); 01603 01604 return bufp + asn_length; 01605 } 01606 01607 01628 u_char * 01629 asn_build_null(u_char * data, size_t * datalength, u_char type) 01630 { 01631 /* 01632 * ASN.1 null ::= 0x05 0x00 01633 */ 01634 #ifndef NETSNMP_NO_DEBUGGING 01635 u_char *initdatap = data; 01636 #endif 01637 data = asn_build_header(data, datalength, type, 0); 01638 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 01639 DEBUGMSG(("dumpv_send", " NULL\n")); 01640 return data; 01641 } 01642 01666 u_char * 01667 asn_parse_bitstring(u_char * data, 01668 size_t * datalength, 01669 u_char * type, u_char * str, size_t * strlength) 01670 { 01671 /* 01672 * bitstring ::= 0x03 asnlength unused {byte}* 01673 */ 01674 static const char *errpre = "parse bitstring"; 01675 register u_char *bufp = data; 01676 u_long asn_length; 01677 01678 *type = *bufp++; 01679 bufp = asn_parse_length(bufp, &asn_length); 01680 if (_asn_parse_length_check(errpre, bufp, data, 01681 asn_length, *datalength)) 01682 return NULL; 01683 01684 if ((size_t) asn_length > *strlength) { 01685 _asn_length_err(errpre, (size_t) asn_length, *strlength); 01686 return NULL; 01687 } 01688 if (_asn_bitstring_check(errpre, asn_length, *bufp)) 01689 return NULL; 01690 01691 DEBUGDUMPSETUP("recv", data, bufp - data); 01692 DEBUGMSG(("dumpv_recv", " Bitstring: ")); 01693 DEBUGMSGHEX(("dumpv_recv", data, asn_length)); 01694 DEBUGMSG(("dumpv_recv", "\n")); 01695 01696 memmove(str, bufp, asn_length); 01697 *strlength = (int) asn_length; 01698 *datalength -= (int) asn_length + (bufp - data); 01699 return bufp + asn_length; 01700 } 01701 01702 01725 u_char * 01726 asn_build_bitstring(u_char * data, 01727 size_t * datalength, 01728 u_char type, const u_char * str, size_t strlength) 01729 { 01730 /* 01731 * ASN.1 bit string ::= 0x03 asnlength unused {byte}* 01732 */ 01733 static const char *errpre = "build bitstring"; 01734 if (_asn_bitstring_check 01735 (errpre, strlength, (u_char)((str) ? *str : 0))) 01736 return NULL; 01737 01738 data = asn_build_header(data, datalength, type, strlength); 01739 if (_asn_build_header_check(errpre, data, *datalength, strlength)) 01740 return NULL; 01741 01742 if (strlength > 0 && str) 01743 memmove(data, str, strlength); 01744 else if (strlength > 0 && !str) { 01745 ERROR_MSG("no string passed into asn_build_bitstring\n"); 01746 return NULL; 01747 } 01748 01749 *datalength -= strlength; 01750 DEBUGDUMPSETUP("send", data, strlength); 01751 DEBUGMSG(("dumpv_send", " Bitstring: ")); 01752 DEBUGMSGHEX(("dumpv_send", data, strlength)); 01753 DEBUGMSG(("dumpv_send", "\n")); 01754 return data + strlength; 01755 } 01756 01779 u_char * 01780 asn_parse_unsigned_int64(u_char * data, 01781 size_t * datalength, 01782 u_char * type, 01783 struct counter64 * cp, size_t countersize) 01784 { 01785 /* 01786 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 01787 */ 01788 static const char *errpre = "parse uint64"; 01789 const int uint64sizelimit = (4 * 2) + 1; 01790 register u_char *bufp = data; 01791 u_long asn_length; 01792 register u_long low = 0, high = 0; 01793 01794 if (countersize != sizeof(struct counter64)) { 01795 _asn_size_err(errpre, countersize, sizeof(struct counter64)); 01796 return NULL; 01797 } 01798 *type = *bufp++; 01799 bufp = asn_parse_length(bufp, &asn_length); 01800 if (_asn_parse_length_check 01801 (errpre, bufp, data, asn_length, *datalength)) 01802 return NULL; 01803 01804 DEBUGDUMPSETUP("recv", data, bufp - data); 01805 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 01806 /* 01807 * 64 bit counters as opaque 01808 */ 01809 if ((*type == ASN_OPAQUE) && 01810 (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) && 01811 (*bufp == ASN_OPAQUE_TAG1) && 01812 ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) || 01813 (*(bufp + 1) == ASN_OPAQUE_U64))) { 01814 /* 01815 * change type to Counter64 or U64 01816 */ 01817 *type = *(bufp + 1); 01818 /* 01819 * value is encoded as special format 01820 */ 01821 bufp = asn_parse_length(bufp + 2, &asn_length); 01822 if (_asn_parse_length_check("parse opaque uint64", bufp, data, 01823 asn_length, *datalength)) 01824 return NULL; 01825 } 01826 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 01827 if (((int) asn_length > uint64sizelimit) || 01828 (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) { 01829 _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit); 01830 return NULL; 01831 } 01832 *datalength -= (int) asn_length + (bufp - data); 01833 if (*bufp & 0x80) { 01834 low = 0xFFFFFF; /* first byte bit 1 means start the data with 1s */ 01835 high = 0xFFFFFF; 01836 } 01837 01838 while (asn_length--) { 01839 high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000) >> 24); 01840 low = ((low & 0x00FFFFFF) << 8) | *bufp++; 01841 } 01842 01843 CHECK_OVERFLOW_U(high,6); 01844 CHECK_OVERFLOW_U(low,6); 01845 01846 cp->low = low; 01847 cp->high = high; 01848 01849 DEBUGIF("dumpv_recv") { 01850 char i64buf[I64CHARSZ + 1]; 01851 printU64(i64buf, cp); 01852 DEBUGMSG(("dumpv_recv", "Counter64: %s", i64buf)); 01853 } 01854 01855 return bufp; 01856 } 01857 01858 01880 u_char * 01881 asn_build_unsigned_int64(u_char * data, 01882 size_t * datalength, 01883 u_char type, 01884 const struct counter64 * cp, size_t countersize) 01885 { 01886 /* 01887 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 01888 */ 01889 01890 register u_long low, high; 01891 register u_long mask, mask2; 01892 int add_null_byte = 0; 01893 size_t intsize; 01894 #ifndef NETSNMP_NO_DEBUGGING 01895 u_char *initdatap = data; 01896 #endif 01897 01898 if (countersize != sizeof(struct counter64)) { 01899 _asn_size_err("build uint64", countersize, 01900 sizeof(struct counter64)); 01901 return NULL; 01902 } 01903 intsize = 8; 01904 low = cp->low; 01905 high = cp->high; 01906 01907 CHECK_OVERFLOW_U(high,7); 01908 CHECK_OVERFLOW_U(low,7); 01909 01910 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1)); 01911 /* 01912 * mask is 0xFF000000 on a big-endian machine 01913 */ 01914 if ((u_char) ((high & mask) >> (8 * (sizeof(long) - 1))) & 0x80) { 01915 /* 01916 * if MSB is set 01917 */ 01918 add_null_byte = 1; 01919 intsize++; 01920 } else { 01921 /* 01922 * Truncate "unnecessary" bytes off of the most significant end of this 2's 01923 * complement integer. 01924 * There should be no sequence of 9 consecutive 1's or 0's at the most 01925 * significant end of the integer. 01926 */ 01927 mask2 = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1); 01928 /* 01929 * mask2 is 0xFF800000 on a big-endian machine 01930 */ 01931 while ((((high & mask2) == 0) || ((high & mask2) == mask2)) 01932 && intsize > 1) { 01933 intsize--; 01934 high = (high << 8) 01935 | ((low & mask) >> (8 * (sizeof(long) - 1))); 01936 low <<= 8; 01937 } 01938 } 01939 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 01940 /* 01941 * encode a Counter64 as an opaque (it also works in SNMPv1) 01942 */ 01943 /* 01944 * turn into Opaque holding special tagged value 01945 */ 01946 if (type == ASN_OPAQUE_COUNTER64) { 01947 /* 01948 * put the tag and length for the Opaque wrapper 01949 */ 01950 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3); 01951 if (_asn_build_header_check 01952 ("build counter u64", data, *datalength, intsize + 3)) 01953 return NULL; 01954 01955 /* 01956 * put the special tag and length 01957 */ 01958 *data++ = ASN_OPAQUE_TAG1; 01959 *data++ = ASN_OPAQUE_COUNTER64; 01960 *data++ = (u_char) intsize; 01961 *datalength = *datalength - 3; 01962 } else 01963 /* 01964 * Encode the Unsigned int64 in an opaque 01965 */ 01966 /* 01967 * turn into Opaque holding special tagged value 01968 */ 01969 if (type == ASN_OPAQUE_U64) { 01970 /* 01971 * put the tag and length for the Opaque wrapper 01972 */ 01973 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3); 01974 if (_asn_build_header_check 01975 ("build opaque u64", data, *datalength, intsize + 3)) 01976 return NULL; 01977 01978 /* 01979 * put the special tag and length 01980 */ 01981 *data++ = ASN_OPAQUE_TAG1; 01982 *data++ = ASN_OPAQUE_U64; 01983 *data++ = (u_char) intsize; 01984 *datalength = *datalength - 3; 01985 } else { 01986 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 01987 data = asn_build_header(data, datalength, type, intsize); 01988 if (_asn_build_header_check 01989 ("build uint64", data, *datalength, intsize)) 01990 return NULL; 01991 01992 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 01993 } 01994 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 01995 *datalength -= intsize; 01996 if (add_null_byte == 1) { 01997 *data++ = '\0'; 01998 intsize--; 01999 } 02000 while (intsize--) { 02001 *data++ = (u_char) ((high & mask) >> (8 * (sizeof(long) - 1))); 02002 high = (high << 8) 02003 | ((low & mask) >> (8 * (sizeof(long) - 1))); 02004 low <<= 8; 02005 02006 } 02007 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 02008 DEBUGIF("dumpv_send") { 02009 char i64buf[I64CHARSZ + 1]; 02010 printU64(i64buf, cp); 02011 DEBUGMSG(("dumpv_send", "%s", i64buf)); 02012 } 02013 return data; 02014 } 02015 02016 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 02017 02018 02042 u_char * 02043 asn_parse_signed_int64(u_char * data, 02044 size_t * datalength, 02045 u_char * type, 02046 struct counter64 * cp, size_t countersize) 02047 { 02048 static const char *errpre = "parse int64"; 02049 const int int64sizelimit = (4 * 2) + 1; 02050 char ebuf[128]; 02051 register u_char *bufp = data; 02052 u_long asn_length; 02053 register u_int low = 0, high = 0; 02054 02055 if (countersize != sizeof(struct counter64)) { 02056 _asn_size_err(errpre, countersize, sizeof(struct counter64)); 02057 return NULL; 02058 } 02059 *type = *bufp++; 02060 bufp = asn_parse_length(bufp, &asn_length); 02061 if (_asn_parse_length_check 02062 (errpre, bufp, data, asn_length, *datalength)) 02063 return NULL; 02064 02065 DEBUGDUMPSETUP("recv", data, bufp - data); 02066 if ((*type == ASN_OPAQUE) && 02067 (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) && 02068 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) { 02069 /* 02070 * change type to Int64 02071 */ 02072 *type = *(bufp + 1); 02073 /* 02074 * value is encoded as special format 02075 */ 02076 bufp = asn_parse_length(bufp + 2, &asn_length); 02077 if (_asn_parse_length_check("parse opaque int64", bufp, data, 02078 asn_length, *datalength)) 02079 return NULL; 02080 } 02081 /* 02082 * this should always have been true until snmp gets int64 PDU types 02083 */ 02084 else { 02085 snprintf(ebuf, sizeof(ebuf), 02086 "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)", 02087 errpre, *type, (int) asn_length, *bufp, *(bufp + 1)); 02088 ebuf[ sizeof(ebuf)-1 ] = 0; 02089 ERROR_MSG(ebuf); 02090 return NULL; 02091 } 02092 if (((int) asn_length > int64sizelimit) || 02093 (((int) asn_length == int64sizelimit) && *bufp != 0x00)) { 02094 _asn_length_err(errpre, (size_t) asn_length, int64sizelimit); 02095 return NULL; 02096 } 02097 *datalength -= (int) asn_length + (bufp - data); 02098 if (*bufp & 0x80) { 02099 low = 0xFFFFFF; /* first byte bit 1 means start the data with 1s */ 02100 high = 0xFFFFFF; 02101 } 02102 02103 while (asn_length--) { 02104 high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000) >> 24); 02105 low = ((low & 0x00FFFFFF) << 8) | *bufp++; 02106 } 02107 02108 CHECK_OVERFLOW_U(high,8); 02109 CHECK_OVERFLOW_U(low,8); 02110 02111 cp->low = low; 02112 cp->high = high; 02113 02114 DEBUGIF("dumpv_recv") { 02115 char i64buf[I64CHARSZ + 1]; 02116 printI64(i64buf, cp); 02117 DEBUGMSG(("dumpv_recv", "Integer64: %s", i64buf)); 02118 } 02119 02120 return bufp; 02121 } 02122 02123 02124 02146 u_char * 02147 asn_build_signed_int64(u_char * data, 02148 size_t * datalength, 02149 u_char type, 02150 const struct counter64 * cp, size_t countersize) 02151 { 02152 /* 02153 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 02154 */ 02155 02156 struct counter64 c64; 02157 register u_int mask, mask2; 02158 u_long low, high; 02159 size_t intsize; 02160 #ifndef NETSNMP_NO_DEBUGGING 02161 u_char *initdatap = data; 02162 #endif 02163 02164 if (countersize != sizeof(struct counter64)) { 02165 _asn_size_err("build int64", countersize, 02166 sizeof(struct counter64)); 02167 return NULL; 02168 } 02169 intsize = 8; 02170 memcpy(&c64, cp, sizeof(struct counter64)); /* we're may modify it */ 02171 low = c64.low; 02172 high = c64.high; 02173 02174 CHECK_OVERFLOW_S(high,9); 02175 CHECK_OVERFLOW_U(low,9); 02176 02177 /* 02178 * Truncate "unnecessary" bytes off of the most significant end of this 02179 * 2's complement integer. There should be no sequence of 9 02180 * consecutive 1's or 0's at the most significant end of the 02181 * integer. 02182 */ 02183 mask = ((u_int) 0xFF) << (8 * (sizeof(u_int) - 1)); 02184 mask2 = ((u_int) 0x1FF) << ((8 * (sizeof(u_int) - 1)) - 1); 02185 /* 02186 * mask is 0xFF800000 on a big-endian machine 02187 */ 02188 while ((((high & mask2) == 0) || ((high & mask2) == mask2)) 02189 && intsize > 1) { 02190 intsize--; 02191 high = (high << 8) 02192 | ((low & mask) >> (8 * (sizeof(u_int) - 1))); 02193 low <<= 8; 02194 } 02195 /* 02196 * until a real int64 gets incorperated into SNMP, we are going to 02197 * encode it as an opaque instead. First, we build the opaque 02198 * header and then the int64 tag type we use to mark it as an 02199 * int64 in the opaque string. 02200 */ 02201 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3); 02202 if (_asn_build_header_check 02203 ("build int64", data, *datalength, intsize + 3)) 02204 return NULL; 02205 02206 *data++ = ASN_OPAQUE_TAG1; 02207 *data++ = ASN_OPAQUE_I64; 02208 *data++ = (u_char) intsize; 02209 *datalength -= (3 + intsize); 02210 02211 while (intsize--) { 02212 *data++ = (u_char) ((high & mask) >> (8 * (sizeof(u_int) - 1))); 02213 high = (high << 8) 02214 | ((low & mask) >> (8 * (sizeof(u_int) - 1))); 02215 low <<= 8; 02216 } 02217 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 02218 DEBUGIF("dumpv_send") { 02219 char i64buf[I64CHARSZ + 1]; 02220 printU64(i64buf, cp); 02221 DEBUGMSG(("dumpv_send", "%s", i64buf)); 02222 } 02223 return data; 02224 } 02225 02226 02248 u_char * 02249 asn_parse_float(u_char * data, 02250 size_t * datalength, 02251 u_char * type, float *floatp, size_t floatsize) 02252 { 02253 register u_char *bufp = data; 02254 u_long asn_length; 02255 union { 02256 float floatVal; 02257 long longVal; 02258 u_char c[sizeof(float)]; 02259 } fu; 02260 02261 if (floatsize != sizeof(float)) { 02262 _asn_size_err("parse float", floatsize, sizeof(float)); 02263 return NULL; 02264 } 02265 *type = *bufp++; 02266 bufp = asn_parse_length(bufp, &asn_length); 02267 if (_asn_parse_length_check("parse float", bufp, data, 02268 asn_length, *datalength)) 02269 return NULL; 02270 02271 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 02272 /* 02273 * the float is encoded as an opaque 02274 */ 02275 if ((*type == ASN_OPAQUE) && 02276 (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) && 02277 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) { 02278 02279 /* 02280 * value is encoded as special format 02281 */ 02282 bufp = asn_parse_length(bufp + 2, &asn_length); 02283 if (_asn_parse_length_check("parse opaque float", bufp, data, 02284 asn_length, *datalength)) 02285 return NULL; 02286 02287 /* 02288 * change type to Float 02289 */ 02290 *type = ASN_OPAQUE_FLOAT; 02291 } 02292 02293 if (asn_length != sizeof(float)) { 02294 _asn_size_err("parse seq float", asn_length, sizeof(float)); 02295 return NULL; 02296 } 02297 02298 *datalength -= (int) asn_length + (bufp - data); 02299 memcpy(&fu.c[0], bufp, asn_length); 02300 02301 /* 02302 * correct for endian differences 02303 */ 02304 fu.longVal = ntohl(fu.longVal); 02305 02306 *floatp = fu.floatVal; 02307 02308 DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp)); 02309 return bufp; 02310 } 02311 02335 u_char * 02336 asn_build_float(u_char * data, 02337 size_t * datalength, 02338 u_char type, const float *floatp, size_t floatsize) 02339 { 02340 union { 02341 float floatVal; 02342 int intVal; 02343 u_char c[sizeof(float)]; 02344 } fu; 02345 #ifndef NETSNMP_NO_DEBUGGING 02346 u_char *initdatap = data; 02347 #endif 02348 02349 if (floatsize != sizeof(float)) { 02350 _asn_size_err("build float", floatsize, sizeof(float)); 02351 return NULL; 02352 } 02353 /* 02354 * encode the float as an opaque 02355 */ 02356 /* 02357 * turn into Opaque holding special tagged value 02358 */ 02359 02360 /* 02361 * put the tag and length for the Opaque wrapper 02362 */ 02363 data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3); 02364 if (_asn_build_header_check 02365 ("build float", data, *datalength, (floatsize + 3))) 02366 return NULL; 02367 02368 /* 02369 * put the special tag and length 02370 */ 02371 *data++ = ASN_OPAQUE_TAG1; 02372 *data++ = ASN_OPAQUE_FLOAT; 02373 *data++ = (u_char) floatsize; 02374 *datalength = *datalength - 3; 02375 02376 fu.floatVal = *floatp; 02377 /* 02378 * correct for endian differences 02379 */ 02380 fu.intVal = htonl(fu.intVal); 02381 02382 *datalength -= floatsize; 02383 memcpy(data, &fu.c[0], floatsize); 02384 02385 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 02386 DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp)); 02387 data += floatsize; 02388 return data; 02389 } 02390 02391 02413 u_char * 02414 asn_parse_double(u_char * data, 02415 size_t * datalength, 02416 u_char * type, double *doublep, size_t doublesize) 02417 { 02418 register u_char *bufp = data; 02419 u_long asn_length; 02420 long tmp; 02421 union { 02422 double doubleVal; 02423 int intVal[2]; 02424 u_char c[sizeof(double)]; 02425 } fu; 02426 02427 02428 if (doublesize != sizeof(double)) { 02429 _asn_size_err("parse double", doublesize, sizeof(double)); 02430 return NULL; 02431 } 02432 *type = *bufp++; 02433 bufp = asn_parse_length(bufp, &asn_length); 02434 if (_asn_parse_length_check("parse double", bufp, data, 02435 asn_length, *datalength)) 02436 return NULL; 02437 02438 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length); 02439 /* 02440 * the double is encoded as an opaque 02441 */ 02442 if ((*type == ASN_OPAQUE) && 02443 (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) && 02444 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) { 02445 02446 /* 02447 * value is encoded as special format 02448 */ 02449 bufp = asn_parse_length(bufp + 2, &asn_length); 02450 if (_asn_parse_length_check("parse opaque double", bufp, data, 02451 asn_length, *datalength)) 02452 return NULL; 02453 02454 /* 02455 * change type to Double 02456 */ 02457 *type = ASN_OPAQUE_DOUBLE; 02458 } 02459 02460 if (asn_length != sizeof(double)) { 02461 _asn_size_err("parse seq double", asn_length, sizeof(double)); 02462 return NULL; 02463 } 02464 *datalength -= (int) asn_length + (bufp - data); 02465 memcpy(&fu.c[0], bufp, asn_length); 02466 02467 /* 02468 * correct for endian differences 02469 */ 02470 02471 tmp = ntohl(fu.intVal[0]); 02472 fu.intVal[0] = ntohl(fu.intVal[1]); 02473 fu.intVal[1] = tmp; 02474 02475 *doublep = fu.doubleVal; 02476 DEBUGMSG(("dumpv_recv", " Opaque Double:\t%f\n", *doublep)); 02477 02478 return bufp; 02479 } 02480 02481 02504 u_char * 02505 asn_build_double(u_char * data, 02506 size_t * datalength, 02507 u_char type, const double *doublep, size_t doublesize) 02508 { 02509 long tmp; 02510 union { 02511 double doubleVal; 02512 int intVal[2]; 02513 u_char c[sizeof(double)]; 02514 } fu; 02515 #ifndef NETSNMP_NO_DEBUGGING 02516 u_char *initdatap = data; 02517 #endif 02518 02519 if (doublesize != sizeof(double)) { 02520 _asn_size_err("build double", doublesize, sizeof(double)); 02521 return NULL; 02522 } 02523 02524 /* 02525 * encode the double as an opaque 02526 */ 02527 /* 02528 * turn into Opaque holding special tagged value 02529 */ 02530 02531 /* 02532 * put the tag and length for the Opaque wrapper 02533 */ 02534 data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3); 02535 if (_asn_build_header_check 02536 ("build double", data, *datalength, doublesize + 3)) 02537 return NULL; 02538 02539 /* 02540 * put the special tag and length 02541 */ 02542 *data++ = ASN_OPAQUE_TAG1; 02543 *data++ = ASN_OPAQUE_DOUBLE; 02544 *data++ = (u_char) doublesize; 02545 *datalength = *datalength - 3; 02546 02547 fu.doubleVal = *doublep; 02548 /* 02549 * correct for endian differences 02550 */ 02551 tmp = htonl(fu.intVal[0]); 02552 fu.intVal[0] = htonl(fu.intVal[1]); 02553 fu.intVal[1] = tmp; 02554 *datalength -= doublesize; 02555 memcpy(data, &fu.c[0], doublesize); 02556 02557 data += doublesize; 02558 DEBUGDUMPSETUP("send", initdatap, data - initdatap); 02559 DEBUGMSG(("dumpv_send", " Opaque double: %f", *doublep)); 02560 return data; 02561 } 02562 02563 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 02564 02565 02580 int 02581 asn_realloc(u_char ** pkt, size_t * pkt_len) 02582 { 02583 if (pkt != NULL && pkt_len != NULL) { 02584 size_t old_pkt_len = *pkt_len; 02585 02586 DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %lu\n", 02587 *pkt, (unsigned long)old_pkt_len)); 02588 02589 if (snmp_realloc(pkt, pkt_len)) { 02590 DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %lu\n", 02591 *pkt, (unsigned long)*pkt_len)); 02592 DEBUGMSGTL(("asn_realloc", 02593 " memmove(%8p + %08x, %8p, %08x)\n", 02594 *pkt, (unsigned)(*pkt_len - old_pkt_len), 02595 *pkt, (unsigned)old_pkt_len)); 02596 memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len); 02597 memset(*pkt, (int) ' ', *pkt_len - old_pkt_len); 02598 return 1; 02599 } else { 02600 DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n")); 02601 } 02602 } 02603 return 0; 02604 } 02605 02606 #ifdef NETSNMP_USE_REVERSE_ASNENCODING 02607 02622 int 02623 asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len, 02624 size_t * offset, int r, size_t length) 02625 { 02626 static const char *errpre = "build length"; 02627 char ebuf[128]; 02628 int tmp_int; 02629 size_t start_offset = *offset; 02630 02631 if (length <= 0x7f) { 02632 if (((*pkt_len - *offset) < 1) 02633 && !(r && asn_realloc(pkt, pkt_len))) { 02634 snprintf(ebuf, sizeof(ebuf), 02635 "%s: bad length < 1 :%ld, %lu", errpre, 02636 (long)(*pkt_len - *offset), (unsigned long)length); 02637 ebuf[ sizeof(ebuf)-1 ] = 0; 02638 ERROR_MSG(ebuf); 02639 return 0; 02640 } 02641 *(*pkt + *pkt_len - (++*offset)) = length; 02642 } else { 02643 while (length > 0xff) { 02644 if (((*pkt_len - *offset) < 1) 02645 && !(r && asn_realloc(pkt, pkt_len))) { 02646 snprintf(ebuf, sizeof(ebuf), 02647 "%s: bad length < 1 :%ld, %lu", errpre, 02648 (long)(*pkt_len - *offset), (unsigned long)length); 02649 ebuf[ sizeof(ebuf)-1 ] = 0; 02650 ERROR_MSG(ebuf); 02651 return 0; 02652 } 02653 *(*pkt + *pkt_len - (++*offset)) = length & 0xff; 02654 length >>= 8; 02655 } 02656 02657 while ((*pkt_len - *offset) < 2) { 02658 if (!(r && asn_realloc(pkt, pkt_len))) { 02659 snprintf(ebuf, sizeof(ebuf), 02660 "%s: bad length < 1 :%ld, %lu", errpre, 02661 (long)(*pkt_len - *offset), (unsigned long)length); 02662 ebuf[ sizeof(ebuf)-1 ] = 0; 02663 ERROR_MSG(ebuf); 02664 return 0; 02665 } 02666 } 02667 02668 *(*pkt + *pkt_len - (++*offset)) = length & 0xff; 02669 tmp_int = *offset - start_offset; 02670 *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80; 02671 } 02672 02673 return 1; 02674 } 02675 02693 int 02694 asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len, 02695 size_t * offset, int r, 02696 u_char type, size_t length) 02697 { 02698 char ebuf[128]; 02699 02700 if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) { 02701 if (((*pkt_len - *offset) < 1) 02702 && !(r && asn_realloc(pkt, pkt_len))) { 02703 snprintf(ebuf, sizeof(ebuf), 02704 "bad header length < 1 :%ld, %lu", 02705 (long)(*pkt_len - *offset), (unsigned long)length); 02706 ebuf[ sizeof(ebuf)-1 ] = 0; 02707 ERROR_MSG(ebuf); 02708 return 0; 02709 } 02710 *(*pkt + *pkt_len - (++*offset)) = type; 02711 return 1; 02712 } 02713 return 0; 02714 } 02715 02733 int 02734 asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len, 02735 size_t * offset, int r, 02736 u_char type, const long *intp, size_t intsize) 02737 { 02738 static const char *errpre = "build int"; 02739 register long integer = *intp; 02740 int testvalue; 02741 size_t start_offset = *offset; 02742 02743 if (intsize != sizeof(long)) { 02744 _asn_size_err(errpre, intsize, sizeof(long)); 02745 return 0; 02746 } 02747 02748 CHECK_OVERFLOW_S(integer,10); 02749 testvalue = (integer < 0) ? -1 : 0; 02750 02751 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) { 02752 return 0; 02753 } 02754 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer; 02755 integer >>= 8; 02756 02757 while (integer != testvalue) { 02758 if (((*pkt_len - *offset) < 1) 02759 && !(r && asn_realloc(pkt, pkt_len))) { 02760 return 0; 02761 } 02762 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer; 02763 integer >>= 8; 02764 } 02765 02766 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) { 02767 /* 02768 * Make sure left most bit is representational of the rest of the bits 02769 * that aren't encoded. 02770 */ 02771 if (((*pkt_len - *offset) < 1) 02772 && !(r && asn_realloc(pkt, pkt_len))) { 02773 return 0; 02774 } 02775 *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff; 02776 } 02777 02778 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 02779 (*offset - start_offset))) { 02780 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, 02781 (*offset - start_offset))) { 02782 return 0; 02783 } else { 02784 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 02785 (*offset - start_offset)); 02786 DEBUGMSG(("dumpv_send", " Integer:\t%ld (0x%.2lX)\n", *intp, 02787 *intp)); 02788 return 1; 02789 } 02790 } 02791 02792 return 0; 02793 } 02794 02813 int 02814 asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len, 02815 size_t * offset, int r, 02816 u_char type, 02817 const u_char * str, size_t strlength) 02818 { 02819 static const char *errpre = "build string"; 02820 size_t start_offset = *offset; 02821 02822 while ((*pkt_len - *offset) < strlength) { 02823 if (!(r && asn_realloc(pkt, pkt_len))) { 02824 return 0; 02825 } 02826 } 02827 02828 *offset += strlength; 02829 memcpy(*pkt + *pkt_len - *offset, str, strlength); 02830 02831 if (asn_realloc_rbuild_header 02832 (pkt, pkt_len, offset, r, type, strlength)) { 02833 if (_asn_realloc_build_header_check 02834 (errpre, pkt, pkt_len, strlength)) { 02835 return 0; 02836 } else { 02837 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 02838 *offset - start_offset); 02839 DEBUGIF("dumpv_send") { 02840 if (strlength == 0) { 02841 DEBUGMSG(("dumpv_send", " String: [NULL]\n")); 02842 } else { 02843 u_char *buf = (u_char *) malloc(2 * strlength); 02844 size_t l = 02845 (buf != NULL) ? (2 * strlength) : 0, ol = 0; 02846 02847 if (sprint_realloc_asciistring 02848 (&buf, &l, &ol, 1, str, strlength)) { 02849 DEBUGMSG(("dumpv_send", " String:\t%s\n", buf)); 02850 } else { 02851 if (buf == NULL) { 02852 DEBUGMSG(("dumpv_send", 02853 " String:\t[TRUNCATED]\n")); 02854 } else { 02855 DEBUGMSG(("dumpv_send", 02856 " String:\t%s [TRUNCATED]\n", buf)); 02857 } 02858 } 02859 if (buf != NULL) { 02860 free(buf); 02861 } 02862 } 02863 } 02864 } 02865 return 1; 02866 } 02867 02868 return 0; 02869 } 02870 02888 int 02889 asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len, 02890 size_t * offset, int r, 02891 u_char type, const u_long * intp, size_t intsize) 02892 { 02893 static const char *errpre = "build uint"; 02894 register u_long integer = *intp; 02895 size_t start_offset = *offset; 02896 02897 if (intsize != sizeof(unsigned long)) { 02898 _asn_size_err(errpre, intsize, sizeof(unsigned long)); 02899 return 0; 02900 } 02901 02902 CHECK_OVERFLOW_U(integer,11); 02903 02904 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) { 02905 return 0; 02906 } 02907 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer; 02908 integer >>= 8; 02909 02910 while (integer != 0) { 02911 if (((*pkt_len - *offset) < 1) 02912 && !(r && asn_realloc(pkt, pkt_len))) { 02913 return 0; 02914 } 02915 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer; 02916 integer >>= 8; 02917 } 02918 02919 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) { 02920 /* 02921 * Make sure left most bit is representational of the rest of the bits 02922 * that aren't encoded. 02923 */ 02924 if (((*pkt_len - *offset) < 1) 02925 && !(r && asn_realloc(pkt, pkt_len))) { 02926 return 0; 02927 } 02928 *(*pkt + *pkt_len - (++*offset)) = 0; 02929 } 02930 02931 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 02932 (*offset - start_offset))) { 02933 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, 02934 (*offset - start_offset))) { 02935 return 0; 02936 } else { 02937 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 02938 (*offset - start_offset)); 02939 DEBUGMSG(("dumpv_send", " UInteger:\t%lu (0x%.2lX)\n", *intp, 02940 *intp)); 02941 return 1; 02942 } 02943 } 02944 02945 return 0; 02946 } 02947 02965 int 02966 asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len, 02967 size_t * offset, int r, 02968 u_char type, size_t length) 02969 { 02970 return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 02971 length); 02972 } 02973 02992 int 02993 asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len, 02994 size_t * offset, int r, 02995 u_char type, 02996 const oid * objid, size_t objidlength) 02997 { 02998 /* 02999 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* 03000 * subidentifier ::= {leadingbyte}* lastbyte 03001 * leadingbyte ::= 1 7bitvalue 03002 * lastbyte ::= 0 7bitvalue 03003 */ 03004 register size_t i; 03005 register oid tmpint; 03006 size_t start_offset = *offset; 03007 const char *errpre = "build objid"; 03008 03009 /* 03010 * Check if there are at least 2 sub-identifiers. 03011 */ 03012 if (objidlength == 0) { 03013 /* 03014 * There are not, so make OID have two with value of zero. 03015 */ 03016 while ((*pkt_len - *offset) < 2) { 03017 if (!(r && asn_realloc(pkt, pkt_len))) { 03018 return 0; 03019 } 03020 } 03021 03022 *(*pkt + *pkt_len - (++*offset)) = 0; 03023 *(*pkt + *pkt_len - (++*offset)) = 0; 03024 } else if (objid[0] > 2) { 03025 ERROR_MSG("build objid: bad first subidentifier"); 03026 return 0; 03027 } else if (objidlength == 1) { 03028 /* 03029 * Encode the first value. 03030 */ 03031 if (((*pkt_len - *offset) < 1) 03032 && !(r && asn_realloc(pkt, pkt_len))) { 03033 return 0; 03034 } 03035 *(*pkt + *pkt_len - (++*offset)) = (u_char) objid[0]; 03036 } else { 03037 for (i = objidlength; i > 2; i--) { 03038 tmpint = objid[i - 1]; 03039 CHECK_OVERFLOW_U(tmpint,12); 03040 03041 if (((*pkt_len - *offset) < 1) 03042 && !(r && asn_realloc(pkt, pkt_len))) { 03043 return 0; 03044 } 03045 *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f; 03046 tmpint >>= 7; 03047 03048 while (tmpint > 0) { 03049 if (((*pkt_len - *offset) < 1) 03050 && !(r && asn_realloc(pkt, pkt_len))) { 03051 return 0; 03052 } 03053 *(*pkt + *pkt_len - (++*offset)) = 03054 (u_char) ((tmpint & 0x7f) | 0x80); 03055 tmpint >>= 7; 03056 } 03057 } 03058 03059 /* 03060 * Combine the first two values. 03061 */ 03062 if ((objid[1] > 40) && 03063 (objid[0] < 2)) { 03064 ERROR_MSG("build objid: bad second subidentifier"); 03065 return 0; 03066 } 03067 tmpint = ((objid[0] * 40) + objid[1]); 03068 if (((*pkt_len - *offset) < 1) 03069 && !(r && asn_realloc(pkt, pkt_len))) { 03070 return 0; 03071 } 03072 *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f; 03073 tmpint >>= 7; 03074 03075 while (tmpint > 0) { 03076 if (((*pkt_len - *offset) < 1) 03077 && !(r && asn_realloc(pkt, pkt_len))) { 03078 return 0; 03079 } 03080 *(*pkt + *pkt_len - (++*offset)) = 03081 (u_char) ((tmpint & 0x7f) | 0x80); 03082 tmpint >>= 7; 03083 } 03084 } 03085 03086 tmpint = *offset - start_offset; 03087 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 03088 (*offset - start_offset))) { 03089 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, 03090 (*offset - start_offset))) { 03091 return 0; 03092 } else { 03093 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 03094 (*offset - start_offset)); 03095 DEBUGMSG(("dumpv_send", " ObjID: ")); 03096 DEBUGMSGOID(("dumpv_send", objid, objidlength)); 03097 DEBUGMSG(("dumpv_send", "\n")); 03098 return 1; 03099 } 03100 } 03101 03102 return 0; 03103 } 03104 03121 int 03122 asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len, 03123 size_t * offset, int r, u_char type) 03124 { 03125 /* 03126 * ASN.1 null ::= 0x05 0x00 03127 */ 03128 size_t start_offset = *offset; 03129 03130 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) { 03131 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 03132 (*offset - start_offset)); 03133 DEBUGMSG(("dumpv_send", " NULL\n")); 03134 return 1; 03135 } else { 03136 return 0; 03137 } 03138 } 03139 03158 int 03159 asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len, 03160 size_t * offset, int r, 03161 u_char type, 03162 const u_char * str, size_t strlength) 03163 { 03164 /* 03165 * ASN.1 bit string ::= 0x03 asnlength unused {byte}* 03166 */ 03167 static const char *errpre = "build bitstring"; 03168 size_t start_offset = *offset; 03169 03170 while ((*pkt_len - *offset) < strlength) { 03171 if (!(r && asn_realloc(pkt, pkt_len))) { 03172 return 0; 03173 } 03174 } 03175 03176 *offset += strlength; 03177 memcpy(*pkt + *pkt_len - *offset, str, strlength); 03178 03179 if (asn_realloc_rbuild_header 03180 (pkt, pkt_len, offset, r, type, strlength)) { 03181 if (_asn_realloc_build_header_check 03182 (errpre, pkt, pkt_len, strlength)) { 03183 return 0; 03184 } else { 03185 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 03186 *offset - start_offset); 03187 DEBUGIF("dumpv_send") { 03188 if (strlength == 0) { 03189 DEBUGMSG(("dumpv_send", " Bitstring: [NULL]\n")); 03190 } else { 03191 u_char *buf = (u_char *) malloc(2 * strlength); 03192 size_t l = 03193 (buf != NULL) ? (2 * strlength) : 0, ol = 0; 03194 03195 if (sprint_realloc_asciistring 03196 (&buf, &l, &ol, 1, str, strlength)) { 03197 DEBUGMSG(("dumpv_send", " Bitstring:\t%s\n", 03198 buf)); 03199 } else { 03200 if (buf == NULL) { 03201 DEBUGMSG(("dumpv_send", 03202 " Bitstring:\t[TRUNCATED]\n")); 03203 } else { 03204 DEBUGMSG(("dumpv_send", 03205 " Bitstring:\t%s [TRUNCATED]\n", 03206 buf)); 03207 } 03208 } 03209 if (buf != NULL) { 03210 free(buf); 03211 } 03212 } 03213 } 03214 } 03215 return 1; 03216 } 03217 03218 return 0; 03219 } 03220 03238 int 03239 asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len, 03240 size_t * offset, int r, 03241 u_char type, 03242 const struct counter64 *cp, size_t countersize) 03243 { 03244 /* 03245 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 03246 */ 03247 register u_long low = cp->low, high = cp->high; 03248 size_t intsize, start_offset = *offset; 03249 int count; 03250 03251 if (countersize != sizeof(struct counter64)) { 03252 _asn_size_err("build uint64", countersize, 03253 sizeof(struct counter64)); 03254 return 0; 03255 } 03256 03257 CHECK_OVERFLOW_U(high,13); 03258 CHECK_OVERFLOW_U(low,13); 03259 03260 /* 03261 * Encode the low 4 bytes first. 03262 */ 03263 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) { 03264 return 0; 03265 } 03266 *(*pkt + *pkt_len - (++*offset)) = (u_char) low; 03267 low >>= 8; 03268 count = 1; 03269 03270 while (low != 0) { 03271 count++; 03272 if (((*pkt_len - *offset) < 1) 03273 && !(r && asn_realloc(pkt, pkt_len))) { 03274 return 0; 03275 } 03276 *(*pkt + *pkt_len - (++*offset)) = (u_char) low; 03277 low >>= 8; 03278 } 03279 03280 /* 03281 * Then the high byte if present. 03282 */ 03283 if (high) { 03284 /* 03285 * Do the rest of the low byte. 03286 */ 03287 for (; count < 4; count++) { 03288 if (((*pkt_len - *offset) < 1) 03289 && !(r && asn_realloc(pkt, pkt_len))) { 03290 return 0; 03291 } 03292 *(*pkt + *pkt_len - (++*offset)) = 0; 03293 } 03294 03295 /* 03296 * Do high byte. 03297 */ 03298 if (((*pkt_len - *offset) < 1) 03299 && !(r && asn_realloc(pkt, pkt_len))) { 03300 return 0; 03301 } 03302 *(*pkt + *pkt_len - (++*offset)) = (u_char) high; 03303 high >>= 8; 03304 03305 while (high != 0) { 03306 if (((*pkt_len - *offset) < 1) 03307 && !(r && asn_realloc(pkt, pkt_len))) { 03308 return 0; 03309 } 03310 *(*pkt + *pkt_len - (++*offset)) = (u_char) high; 03311 high >>= 8; 03312 } 03313 } 03314 03315 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) { 03316 /* 03317 * Make sure left most bit is representational of the rest of the bits 03318 * that aren't encoded. 03319 */ 03320 if (((*pkt_len - *offset) < 1) 03321 && !(r && asn_realloc(pkt, pkt_len))) { 03322 return 0; 03323 } 03324 *(*pkt + *pkt_len - (++*offset)) = 0; 03325 } 03326 03327 intsize = *offset - start_offset; 03328 03329 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 03330 /* 03331 * Encode a Counter64 as an opaque (it also works in SNMPv1). 03332 */ 03333 if (type == ASN_OPAQUE_COUNTER64) { 03334 while ((*pkt_len - *offset) < 5) { 03335 if (!(r && asn_realloc(pkt, pkt_len))) { 03336 return 0; 03337 } 03338 } 03339 03340 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize; 03341 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64; 03342 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1; 03343 03344 /* 03345 * Put the tag and length for the Opaque wrapper. 03346 */ 03347 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, 03348 ASN_OPAQUE, intsize + 3)) { 03349 if (_asn_realloc_build_header_check 03350 ("build counter u64", pkt, pkt_len, intsize + 3)) { 03351 return 0; 03352 } 03353 } else { 03354 return 0; 03355 } 03356 } else if (type == ASN_OPAQUE_U64) { 03357 /* 03358 * Encode the Unsigned int64 in an opaque. 03359 */ 03360 while ((*pkt_len - *offset) < 5) { 03361 if (!(r && asn_realloc(pkt, pkt_len))) { 03362 return 0; 03363 } 03364 } 03365 03366 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize; 03367 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64; 03368 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1; 03369 03370 /* 03371 * Put the tag and length for the Opaque wrapper. 03372 */ 03373 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, 03374 ASN_OPAQUE, intsize + 3)) { 03375 if (_asn_realloc_build_header_check 03376 ("build counter u64", pkt, pkt_len, intsize + 3)) { 03377 return 0; 03378 } 03379 } else { 03380 return 0; 03381 } 03382 } else { 03383 03384 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 03385 if (asn_realloc_rbuild_header 03386 (pkt, pkt_len, offset, r, type, intsize)) { 03387 if (_asn_realloc_build_header_check 03388 ("build uint64", pkt, pkt_len, intsize)) { 03389 return 0; 03390 } 03391 } else { 03392 return 0; 03393 } 03394 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 03395 } 03396 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 03397 03398 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize); 03399 DEBUGMSG(("dumpv_send", " U64:\t%lu %lu\n", cp->high, cp->low)); 03400 return 1; 03401 } 03402 03403 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES 03404 03405 03423 int 03424 asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len, 03425 size_t * offset, int r, 03426 u_char type, 03427 const struct counter64 *cp, size_t countersize) 03428 { 03429 /* 03430 * ASN.1 integer ::= 0x02 asnlength byte {byte}* 03431 */ 03432 register long low = cp->low, high = cp->high; 03433 size_t intsize, start_offset = *offset; 03434 int count, testvalue = (high & 0x80000000) ? -1 : 0; 03435 03436 if (countersize != sizeof(struct counter64)) { 03437 _asn_size_err("build uint64", countersize, 03438 sizeof(struct counter64)); 03439 return 0; 03440 } 03441 03442 CHECK_OVERFLOW_S(high,14); 03443 CHECK_OVERFLOW_U(low,14); 03444 03445 /* 03446 * Encode the low 4 bytes first. 03447 */ 03448 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) { 03449 return 0; 03450 } 03451 *(*pkt + *pkt_len - (++*offset)) = (u_char) low; 03452 low >>= 8; 03453 count = 1; 03454 03455 while ((int) low != testvalue && count < 4) { 03456 count++; 03457 if (((*pkt_len - *offset) < 1) 03458 && !(r && asn_realloc(pkt, pkt_len))) { 03459 return 0; 03460 } 03461 *(*pkt + *pkt_len - (++*offset)) = (u_char) low; 03462 low >>= 8; 03463 } 03464 03465 /* 03466 * Then the high byte if present. 03467 */ 03468 if (high != testvalue) { 03469 /* 03470 * Do the rest of the low byte. 03471 */ 03472 for (; count < 4; count++) { 03473 if (((*pkt_len - *offset) < 1) 03474 && !(r && asn_realloc(pkt, pkt_len))) { 03475 return 0; 03476 } 03477 *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff; 03478 } 03479 03480 /* 03481 * Do high byte. 03482 */ 03483 if (((*pkt_len - *offset) < 1) 03484 && !(r && asn_realloc(pkt, pkt_len))) { 03485 return 0; 03486 } 03487 *(*pkt + *pkt_len - (++*offset)) = (u_char) high; 03488 high >>= 8; 03489 03490 while ((int) high != testvalue) { 03491 if (((*pkt_len - *offset) < 1) 03492 && !(r && asn_realloc(pkt, pkt_len))) { 03493 return 0; 03494 } 03495 *(*pkt + *pkt_len - (++*offset)) = (u_char) high; 03496 high >>= 8; 03497 } 03498 } 03499 03500 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) { 03501 /* 03502 * Make sure left most bit is representational of the rest of the bits 03503 * that aren't encoded. 03504 */ 03505 if (((*pkt_len - *offset) < 1) 03506 && !(r && asn_realloc(pkt, pkt_len))) { 03507 return 0; 03508 } 03509 *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff; 03510 } 03511 03512 intsize = *offset - start_offset; 03513 03514 while ((*pkt_len - *offset) < 5) { 03515 if (!(r && asn_realloc(pkt, pkt_len))) { 03516 return 0; 03517 } 03518 } 03519 03520 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize; 03521 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64; 03522 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1; 03523 03524 /* 03525 * Put the tag and length for the Opaque wrapper. 03526 */ 03527 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, 03528 ASN_OPAQUE, intsize + 3)) { 03529 if (_asn_realloc_build_header_check 03530 ("build counter u64", pkt, pkt_len, intsize + 3)) { 03531 return 0; 03532 } 03533 } else { 03534 return 0; 03535 } 03536 03537 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize); 03538 DEBUGMSG(("dumpv_send", " UInt64:\t%lu %lu\n", cp->high, cp->low)); 03539 return 1; 03540 } 03541 03560 int 03561 asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len, 03562 size_t * offset, int r, 03563 u_char type, const float *floatp, size_t floatsize) 03564 { 03565 size_t start_offset = *offset; 03566 union { 03567 float floatVal; 03568 int intVal; 03569 u_char c[sizeof(float)]; 03570 } fu; 03571 03572 /* 03573 * Floatsize better not be larger than realistic. 03574 */ 03575 if (floatsize != sizeof(float) || floatsize > 122) { 03576 return 0; 03577 } 03578 03579 while ((*pkt_len - *offset) < floatsize + 3) { 03580 if (!(r && asn_realloc(pkt, pkt_len))) { 03581 return 0; 03582 } 03583 } 03584 03585 /* 03586 * Correct for endian differences and copy value. 03587 */ 03588 fu.floatVal = *floatp; 03589 fu.intVal = htonl(fu.intVal); 03590 *offset += floatsize; 03591 memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize); 03592 03593 /* 03594 * Put the special tag and length (3 bytes). 03595 */ 03596 *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize; 03597 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT; 03598 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1; 03599 03600 /* 03601 * Put the tag and length for the Opaque wrapper. 03602 */ 03603 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, 03604 ASN_OPAQUE, floatsize + 3)) { 03605 if (_asn_realloc_build_header_check("build float", pkt, pkt_len, 03606 floatsize + 3)) { 03607 return 0; 03608 } else { 03609 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 03610 *offset - start_offset); 03611 DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp)); 03612 return 1; 03613 } 03614 } 03615 03616 return 0; 03617 } 03618 03637 int 03638 asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len, 03639 size_t * offset, int r, 03640 u_char type, const double *doublep, size_t doublesize) 03641 { 03642 size_t start_offset = *offset; 03643 long tmp; 03644 union { 03645 double doubleVal; 03646 int intVal[2]; 03647 u_char c[sizeof(double)]; 03648 } fu; 03649 03650 /* 03651 * Doublesize better not be larger than realistic. 03652 */ 03653 if (doublesize != sizeof(double) || doublesize > 122) { 03654 return 0; 03655 } 03656 03657 while ((*pkt_len - *offset) < doublesize + 3) { 03658 if (!(r && asn_realloc(pkt, pkt_len))) { 03659 return 0; 03660 } 03661 } 03662 03663 /* 03664 * Correct for endian differences and copy value. 03665 */ 03666 fu.doubleVal = *doublep; 03667 tmp = htonl(fu.intVal[0]); 03668 fu.intVal[0] = htonl(fu.intVal[1]); 03669 fu.intVal[1] = tmp; 03670 *offset += doublesize; 03671 memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize); 03672 03673 /* 03674 * Put the special tag and length (3 bytes). 03675 */ 03676 *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize; 03677 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE; 03678 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1; 03679 03680 /* 03681 * Put the tag and length for the Opaque wrapper. 03682 */ 03683 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, 03684 ASN_OPAQUE, doublesize + 3)) { 03685 if (_asn_realloc_build_header_check("build float", pkt, pkt_len, 03686 doublesize + 3)) { 03687 return 0; 03688 } else { 03689 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), 03690 *offset - start_offset); 03691 DEBUGMSG(("dumpv_send", " Opaque Double:\t%f\n", *doublep)); 03692 return 1; 03693 } 03694 } 03695 03696 return 0; 03697 } 03698 03699 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ 03700 #endif /* NETSNMP_USE_REVERSE_ASNENCODING */ 03701
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.