2 //=============================================================================
6 * The Vb class is an encapsulation of the snmp variable binding.
7 * This module contains the class definition for the variable binding (VB)
8 * class. The VB class is an encapsulation of a SNMP VB. A VB object is
9 * composed of one SNMP++ Oid and one SMI value. The Vb class utilizes Oid
10 * objects and thus requires the Oid class. To use this class,
11 * set oid, value then call valid() to be sure object was constructed correctly.
13 * @author S. Waldbusser (assumed)Michael R MacFaden mrm@cisco.com - rework & ACE port
15 //=============================================================================
17 /**********************************************************************
19 * Abstract Syntax Notation One, ASN.1
20 * As defined in ISO/IS 8824 and ISO/IS 8825
21 * This implements a subset of the above International Standards that
22 * is sufficient to implement SNMP.
24 * Encodes abstract data types into a machine independent stream of bytes.
26 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of CMU not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 ******************************************************************/
47 #include "asnmp/asn1.h"
48 #include "asnmp/snmp.h"
49 #include "ace/OS_NS_string.h"
50 #include "ace/Global_Macros.h"
53 * parse_int - pulls a long out of an ASN int type.
54 * On entry, datalength is input as the number of valid bytes following
55 * "data". On exit, it is returned as the number of valid bytes
56 * following the end of this object.
58 * Returns a pointer to the first byte past the end
59 * of this object (i.e. the start of the next object).
60 * Returns 0 on any error.
62 u_char
* asn1::parse_int(u_char
*data
,
68 ACE_TRACE("asn1::parse_int");
70 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
76 if (intsize
!= (int) sizeof (long)){
81 bufp
=asn1::parse_length(bufp
, &asn_length
);
83 ASNERROR("bad length");
86 if ((int)(asn_length
+ (bufp
- data
)) > *datalength
){
87 ASNERROR("overflow of message");
90 if ((int)asn_length
> intsize
){
91 ASNERROR("I don't support such large integers");
94 *datalength
-= (int)asn_length
+ (bufp
- data
);
96 value
= -1; /* integer is negative */
98 value
= (value
<< 8) | *bufp
++;
105 * parse_unsigned_int - pulls an u_long out of an ASN int type.
106 * On entry, datalength is input as the number of valid bytes following
107 * "data". On exit, it is returned as the number of valid bytes
108 * following the end of this object.
110 * Returns a pointer to the first byte past the end
111 * of this object (i.e. the start of the next object).
112 * Returns 0 on any error.
114 u_char
* asn1::parse_unsigned_int( u_char
*data
,
120 ACE_TRACE("asn1::parse_unsigned_int");
122 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
128 if (intsize
!= (int) sizeof (long)){
129 ASNERROR("not long");
133 bufp
= asn1::parse_length(bufp
, &asn_length
);
135 ASNERROR("bad length");
138 if ((int)(asn_length
+ (bufp
- data
)) > *datalength
){
139 ASNERROR("overflow of message");
142 if (((int)asn_length
> (intsize
+ 1)) ||
143 (((int)asn_length
== intsize
+ 1) && *bufp
!= 0x00)){
144 ASNERROR("I don't support such large integers");
147 *datalength
-= (int)asn_length
+ (bufp
- data
);
151 value
= (value
<< 8) | *bufp
++;
158 * build_int - builds an ASN object containing an integer.
159 * On entry, datalength is input as the number of valid bytes following
160 * "data". On exit, it is returned as the number of valid bytes
161 * following the end of this object.
163 * Returns a pointer to the first byte past the end
164 * of this object (i.e. the start of the next object).
165 * Returns 0 on any error.
167 u_char
* asn1::build_int( u_char
*data
,
173 ACE_TRACE("asn1::build_int");
175 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
181 if (intsize
!= (int) sizeof (long))
185 * Truncate "unnecessary" bytes off of the most significant end of this
186 * 2's complement integer. There should be no sequence of 9
187 * consecutive 1's or 0's at the most significant end of the
190 mask
= u_long (0x1FF) << ((8 * (sizeof(u_long
) - 1)) - 1);
191 /* mask is 0xFF800000 on a big-endian machine */
192 while((((integer
& mask
) == 0) || ((integer
& mask
) == mask
))
197 data
= asn1::build_header(data
, datalength
, type
, intsize
);
200 if (*datalength
< intsize
)
202 *datalength
-= intsize
;
203 mask
= u_long (0xFF) << (8 * (sizeof(u_long
) - 1));
204 /* mask is 0xFF000000 on a big-endian machine */
206 *data
++ = (u_char
)((integer
& mask
) >> (8 * (sizeof(long) - 1)));
214 * build_unsigned_int - builds an ASN object containing an integer.
215 * On entry, datalength is input as the number of valid bytes following
216 * "data". On exit, it is returned as the number of valid bytes
217 * following the end of this object.
219 * Returns a pointer to the first byte past the end
220 * of this object (i.e. the start of the next object).
221 * Returns 0 on any error.
223 u_char
* asn1::build_unsigned_int( u_char
*data
,
229 ACE_TRACE("asn1::build_unsigned_int");
231 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
236 int add_null_byte
= 0;
238 if (intsize
!= (int) sizeof (long))
241 mask
= u_long (0xFF) << (8 * (sizeof(u_long
) - 1));
242 /* mask is 0xFF000000 on a big-endian machine */
243 if ((u_char
)((integer
& mask
) >> (8 * (sizeof(long) - 1))) & 0x80){
249 * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
250 * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
253 mask
= u_long (0x1FF) << ((8 * (sizeof(u_long
) - 1)) - 1);
254 /* mask is 0xFF800000 on a big-endian machine */
255 while((((integer
& mask
) == 0) || ((integer
& mask
) == mask
)) && intsize
> 1){
259 data
= asn1::build_header(data
, datalength
, type
, intsize
);
262 if (*datalength
< intsize
)
264 *datalength
-= intsize
;
265 if (add_null_byte
== 1){
269 mask
= u_long (0xFF) << (8 * (sizeof(u_long
) - 1));
270 /* mask is 0xFF000000 on a big-endian machine */
272 *data
++ = (u_char
)((integer
& mask
) >> (8 * (sizeof(long) - 1)));
280 * parse_string - pulls an octet string out of an ASN octet string type.
281 * On entry, datalength is input as the number of valid bytes following
282 * "data". On exit, it is returned as the number of valid bytes
283 * following the beginning of the next object.
285 * "string" is filled with the octet string.
287 * Returns a pointer to the first byte past the end
288 * of this object (i.e. the start of the next object).
289 * Returns 0 on any error.
291 u_char
* asn1::parse_string( u_char
*data
,
297 ACE_TRACE("asn1::parse_string");
299 * ASN.1 octet string ::= primstring | cmpdstring
300 * primstring ::= 0x04 asnlength byte {byte}*
301 * cmpdstring ::= 0x24 asnlength string {string}*
307 bufp
= asn1::parse_length(bufp
, &asn_length
);
310 if ((int)(asn_length
+ (bufp
- data
)) > *datalength
){
311 ASNERROR("overflow of message");
314 if ((int)asn_length
> *strlength
){
315 ASNERROR("I don't support such long strings");
319 ACE_OS::memcpy((char *)string
, (char *)bufp
, (int)asn_length
);
320 *strlength
= (int)asn_length
;
321 *datalength
-= (int)asn_length
+ (bufp
- data
);
322 return bufp
+ asn_length
;
327 * build_string - Builds an ASN octet string object containing the input string.
328 * On entry, datalength is input as the number of valid bytes following
329 * "data". On exit, it is returned as the number of valid bytes
330 * following the beginning of the next object.
332 * Returns a pointer to the first byte past the end
333 * of this object (i.e. the start of the next object).
334 * Returns 0 on any error.
336 u_char
* asn1::build_string( u_char
*data
,
342 ACE_TRACE("asn1::build_string");
344 * ASN.1 octet string ::= primstring | cmpdstring
345 * primstring ::= 0x04 asnlength byte {byte}*
346 * cmpdstring ::= 0x24 asnlength string {string}*
347 * This code will never send a compound string.
349 data
= asn1::build_header(data
, datalength
, type
, strlength
);
352 if (*datalength
< strlength
)
355 ACE_OS::memcpy((u_char
*)data
,(u_char
*)string
, strlength
);
356 *datalength
-= strlength
;
357 return data
+ strlength
;
362 * parse_header - interprets the ID and length of the current object.
363 * On entry, datalength is input as the number of valid bytes following
364 * "data". On exit, it is returned as the number of valid bytes
365 * in this object following the id and length.
367 * Returns a pointer to the first byte of the contents of this object.
368 * Returns 0 on any error.
370 u_char
*asn1::parse_header( u_char
*data
,
374 ACE_TRACE("asn1::parse_header");
379 /* this only works on data types < 30, i.e. no extension octets */
380 if (IS_EXTENSION_ID(*bufp
)){
381 ASNERROR("can't process ID >= 30");
385 bufp
= asn1::parse_length(bufp
+ 1, &asn_length
);
388 header_len
= bufp
- data
;
389 if ((int)(header_len
+ asn_length
) > *datalength
){
390 ASNERROR("asn length too long");
393 *datalength
= (int)asn_length
;
398 * asn1::build_header - builds an ASN header for an object with the ID and
400 * On entry, datalength is input as the number of valid bytes following
401 * "data". On exit, it is returned as the number of valid bytes
402 * in this object following the id and length.
404 * This only works on data types < 30, i.e. no extension octets.
405 * The maximum length is 0xFFFF;
407 * Returns a pointer to the first byte of the contents of this object.
408 * Returns 0 on any error.
410 u_char
* asn1::build_header( u_char
*data
,
415 ACE_TRACE("asn1::build_header");
420 return asn1::build_length(data
, datalength
, length
);
424 * asn_build_sequence - builds an ASN header for a sequence with the ID and
426 * On entry, datalength is input as the number of valid bytes following
427 * "data". On exit, it is returned as the number of valid bytes
428 * in this object following the id and length.
430 * This only works on data types < 30, i.e. no extension octets.
431 * The maximum length is 0xFFFF;
433 * Returns a pointer to the first byte of the contents of this object.
434 * Returns 0 on any error.
436 u_char
* asn1::build_sequence( u_char
*data
,
441 ACE_TRACE("asn1::build_sequence");
443 if (*datalength
< 0){
444 *datalength
+= 4; /* fix up before punting */
448 *data
++ = (u_char
)(0x02 | ASN_LONG_LEN
);
449 *data
++ = (u_char
)((length
>> 8) & 0xFF);
450 *data
++ = (u_char
)(length
& 0xFF);
455 * parse_length - interprets the length of the current object.
456 * On exit, length contains the value of this length field.
458 * Returns a pointer to the first byte after this length
459 * field (aka: the start of the data field).
460 * Returns 0 on any error.
462 u_char
* asn1::parse_length( u_char
*data
,
465 ACE_TRACE("asn1::parse_length");
466 u_char lengthbyte
= *data
;
468 if (lengthbyte
& ASN_LONG_LEN
){
469 lengthbyte
&= ~ASN_LONG_LEN
; /* turn MSb off */
470 if (lengthbyte
== 0){
471 ASNERROR("We don't support indefinite lengths");
474 if (lengthbyte
> sizeof(long)){
475 ASNERROR("we can't support data lengths that long");
479 ACE_OS::memcpy((char *)length
, (char *)data
+ 1, (int)lengthbyte
);
480 *length
= ACE_NTOHL(*length
);
481 *length
>>= (8 * ((sizeof *length
) - lengthbyte
));
482 return data
+ lengthbyte
+ 1;
483 } else { /* short asnlength */
484 *length
= (long)lengthbyte
;
489 u_char
*asn1::build_length( u_char
*data
,
493 ACE_TRACE("asn1::build_length");
494 u_char
*start_data
= data
;
496 /* no indefinite lengths sent */
498 if (*datalength
< 1){
499 ASNERROR("build_length");
502 *data
++ = (u_char
)length
;
503 } else if (length
<= 0xFF){
504 if (*datalength
< 2){
505 ASNERROR("build_length");
508 *data
++ = (u_char
)(0x01 | ASN_LONG_LEN
);
509 *data
++ = (u_char
)length
;
510 } else { /* 0xFF < length <= 0xFFFF */
511 if (*datalength
< 3){
512 ASNERROR("build_length");
515 *data
++ = (u_char
)(0x02 | ASN_LONG_LEN
);
516 *data
++ = (u_char
)((length
>> 8) & 0xFF);
517 *data
++ = (u_char
)(length
& 0xFF);
519 *datalength
-= (data
- start_data
);
524 * parse_objid - pulls an object indentifier out of an ASN object identifier type.
525 * On entry, datalength is input as the number of valid bytes following
526 * "data". On exit, it is returned as the number of valid bytes
527 * following the beginning of the next object.
529 * "objid" is filled with the object identifier.
531 * Returns a pointer to the first byte past the end
532 * of this object (i.e. the start of the next object).
533 * Returns 0 on any error.
535 u_char
*asn1::parse_objid( u_char
*data
,
541 ACE_TRACE("asn1::parse_objid");
543 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
544 * subidentifier ::= {leadingbyte}* lastbyte
545 * leadingbyte ::= 1 7bitvalue
546 * lastbyte ::= 0 7bitvalue
549 oid
*oidp
= objid
+ 1;
550 u_long subidentifier
;
555 bufp
= asn1::parse_length(bufp
, &asn_length
);
558 if ((int)asn_length
+ (bufp
- data
) > *datalength
){
559 ASNERROR("overflow of message");
562 *datalength
-= (int)asn_length
+ (bufp
- data
);
564 /* Handle invalid object identifier encodings of the form 06 00 robustly */
566 objid
[0] = objid
[1] = 0;
569 (*objidlength
)--; /* account for expansion of first byte */
570 while (length
> 0 && (*objidlength
)-- > 0){
572 do { /* shift and add in low order 7 bits */
573 subidentifier
= (subidentifier
<< 7) + (*(u_char
*)bufp
& ~ASN_BIT8
);
575 } while (*(u_char
*)bufp
++ & ASN_BIT8
); /* last byte has high bit clear */
576 if (subidentifier
> (u_long
)MAX_SUBID
){
577 ASNERROR("subidentifier too long");
580 *oidp
++ = (oid
)subidentifier
;
584 * The first two subidentifiers are encoded into the first component
585 * with the value (X * 40) + Y, where:
586 * X is the value of the first subidentifier.
587 * Y is the value of the second subidentifier.
589 subidentifier
= (u_long
)objid
[1];
590 if (subidentifier
== 0x2B){
594 objid
[1] = (u_char
)(subidentifier
% 40);
595 objid
[0] = (u_char
)((subidentifier
- objid
[1]) / 40);
598 *objidlength
= (int)(oidp
- objid
);
603 * build_objid - Builds an ASN object identifier object containing the
605 * On entry, datalength is input as the number of valid bytes following
606 * "data". On exit, it is returned as the number of valid bytes
607 * following the beginning of the next object.
609 * Returns a pointer to the first byte past the end
610 * of this object (i.e. the start of the next object).
611 * Returns 0 on any error.
613 u_char
*asn1::build_objid( u_char
*data
,
619 ACE_TRACE("asn1::build_objid");
621 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
622 * subidentifier ::= {leadingbyte}* lastbyte
623 * leadingbyte ::= 1 7bitvalue
624 * lastbyte ::= 0 7bitvalue
626 u_char buf
[MAX_OID_LEN
];
630 u_long subid
, mask
, testmask
;
633 if (objidlength
< 2){
637 *bp
++ = (u_char
) (op
[1] + (op
[0] * 40));
642 while(objidlength
-- > 0){
644 if (subid
< 127){ /* off by one? */
645 *bp
++ = (u_char
)subid
;
647 mask
= 0x7F; /* handle subid == 0 case */
649 /* testmask *MUST* !!!! be of an u_type */
650 for(testmask
= 0x7F, testbits
= 0; testmask
!= 0;
651 testmask
<<= 7, testbits
+= 7){
652 if (subid
& testmask
){ /* if any bits set */
657 /* mask can't be zero here */
658 for(;mask
!= 0x7F; mask
>>= 7, bits
-= 7){
659 /* fix a mask that got truncated above */
660 if (mask
== 0x1E00000)
662 *bp
++ = (u_char
)(((subid
& mask
) >> bits
) | ASN_BIT8
);
664 *bp
++ = (u_char
)(subid
& mask
);
667 asnlength
= bp
- buf
;
668 data
= asn1::build_header(data
, datalength
, type
, asnlength
);
671 if (*datalength
< asnlength
)
674 ACE_OS::memcpy((char *)data
, (char *)buf
, asnlength
);
675 *datalength
-= asnlength
;
676 return data
+ asnlength
;
680 * parse_null - Interprets an ASN null type.
681 * On entry, datalength is input as the number of valid bytes following
682 * "data". On exit, it is returned as the number of valid bytes
683 * following the beginning of the next object.
685 * Returns a pointer to the first byte past the end
686 * of this object (i.e. the start of the next object).
687 * Returns 0 on any error.
689 u_char
*asn1::parse_null(u_char
*data
,
693 ACE_TRACE("asn1::parse_null");
695 * ASN.1 null ::= 0x05 0x00
701 bufp
= asn1::parse_length(bufp
, &asn_length
);
704 if (asn_length
!= 0){
705 ASNERROR("Malformed 0");
708 *datalength
-= (bufp
- data
);
709 return bufp
+ asn_length
;
714 * build_null - Builds an ASN null object.
715 * On entry, datalength is input as the number of valid bytes following
716 * "data". On exit, it is returned as the number of valid bytes
717 * following the beginning of the next object.
719 * Returns a pointer to the first byte past the end
720 * of this object (i.e. the start of the next object).
721 * Returns 0 on any error.
723 u_char
*asn1::build_null( u_char
*data
,
727 ACE_TRACE("asn1::build_null");
729 * ASN.1 null ::= 0x05 0x00
731 return asn1::build_header(data
, datalength
, type
, 0);
735 * parse_bitstring - pulls a bitstring out of an ASN bitstring type.
736 * On entry, datalength is input as the number of valid bytes following
737 * "data". On exit, it is returned as the number of valid bytes
738 * following the beginning of the next object.
740 * "string" is filled with the bit string.
742 * Returns a pointer to the first byte past the end
743 * of this object (i.e. the start of the next object).
744 * Returns 0 on any error.
746 u_char
*asn1::parse_bitstring( u_char
*data
,
752 ACE_TRACE("asn1::parse_bitstring");
754 * bitstring ::= 0x03 asnlength unused {byte}*
760 bufp
= asn1::parse_length(bufp
, &asn_length
);
763 if ((int)(asn_length
+ (bufp
- data
)) > *datalength
){
764 ASNERROR("overflow of message");
767 if ((int) asn_length
> *strlength
){
768 ASNERROR("I don't support such long bitstrings");
772 ASNERROR("Invalid bitstring");
776 ASNERROR("Invalid bitstring");
780 ACE_OS::memcpy((char *)string
,(char *)bufp
, (int)asn_length
);
781 *strlength
= (int)asn_length
;
782 *datalength
-= (int)asn_length
+ (bufp
- data
);
783 return bufp
+ asn_length
;
788 * build_bitstring - Builds an ASN bit string object containing the
790 * On entry, datalength is input as the number of valid bytes following
791 * "data". On exit, it is returned as the number of valid bytes
792 * following the beginning of the next object.
794 * Returns a pointer to the first byte past the end
795 * of this object (i.e. the start of the next object).
796 * Returns 0 on any error.
798 u_char
*asn1::build_bitstring( u_char
*data
,
804 ACE_TRACE("asn1::build_bitstring");
806 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
808 if (strlength
< 1 || *string
|| *string
> 7){
809 ASNERROR("Building invalid bitstring");
812 data
= asn1::build_header(data
, datalength
, type
, strlength
);
815 if (*datalength
< strlength
)
818 ACE_OS::memcpy((char *)data
,(char *)string
, strlength
);
819 *datalength
-= strlength
;
820 return data
+ strlength
;
825 * parse_unsigned_int64 - pulls a 64 bit u_long out of an ASN int
827 * On entry, datalength is input as the number of valid bytes following
828 * "data". On exit, it is returned as the number of valid bytes
829 * following the end of this object.
831 * Returns a pointer to the first byte past the end
832 * of this object (i.e. the start of the next object).
833 * Returns 0 on any error.
835 u_char
* asn1::parse_unsigned_int64(u_char
*data
,
838 struct counter64
*cp
,
841 ACE_TRACE("asn1::parse_unsigned_int64");
843 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
847 u_long low
= 0, high
= 0;
850 if (countersize
!= (int) sizeof(struct counter64
)){
851 ASNERROR("not right size");
855 bufp
= asn1::parse_length(bufp
, &asn_length
);
857 ASNERROR("bad length");
860 if ((int)(asn_length
+ (bufp
- data
)) > *datalength
){
861 ASNERROR("overflow of message");
864 if (((int)asn_length
> (intsize
* 2 + 1)) ||
865 (((int)asn_length
== (intsize
* 2) + 1) && *bufp
!= 0x00)){
866 ASNERROR("I don't support such large integers");
869 *datalength
-= (int)asn_length
+ (bufp
- data
);
871 low
= (u_long
) -1; // integer is negative
875 high
= (high
<< 8) | ((low
& 0xFF000000) >> 24);
876 low
= (low
<< 8) | *bufp
++;
885 * build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
886 * On entry, datalength is input as the number of valid bytes following
887 * "data". On exit, it is returned as the number of valid bytes
888 * following the end of this object.
890 * Returns a pointer to the first byte past the end
891 * of this object (i.e. the start of the next object).
892 * Returns 0 on any error.
894 u_char
* asn1::build_unsigned_int64( u_char
*data
,
897 struct counter64
*cp
,
900 ACE_TRACE("asn1::build_unsigned_int64");
902 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
907 int add_null_byte
= 0;
910 if (countersize
!= (int) sizeof (struct counter64
))
915 mask
= u_long (0xFF) << (8 * (sizeof(u_long
) - 1));
916 /* mask is 0xFF000000 on a big-endian machine */
917 if ((u_char
)((high
& mask
) >> (8 * (sizeof(long) - 1))) & 0x80){
923 * Truncate "unnecessary" bytes off of the most significant end of this 2's
924 * complement integer.
925 * There should be no sequence of 9 consecutive 1's or 0's at the most
926 * significant end of the integer.
928 mask2
= u_long (0x1FF) << ((8 * (sizeof(u_long
) - 1)) - 1);
929 /* mask2 is 0xFF800000 on a big-endian machine */
930 while((((high
& mask2
) == 0) || ((high
& mask2
) == mask2
))
934 | ((low
& mask
) >> (8 * (sizeof(long) - 1)));
937 data
= asn1::build_header(data
, datalength
, type
, intsize
);
940 if (*datalength
< intsize
)
942 *datalength
-= intsize
;
943 if (add_null_byte
== 1){
948 *data
++ = (u_char
)((high
& mask
) >> (8 * (sizeof(long) - 1)));
950 | ((low
& mask
) >> (8 * (sizeof(long) - 1)));
958 struct snmp_pdu
* cmu_snmp::pdu_create( int command
)
960 ACE_TRACE("cmu_snmp::snmp_pdu_create");
961 struct snmp_pdu
*pdu
;
963 ACE_NEW_RETURN(pdu
, snmp_pdu
, 0);
964 ACE_OS::memset((char *)pdu
, 0,sizeof(struct snmp_pdu
));
965 pdu
->command
= command
;
969 pdu
->enterprise_length
= 0;
974 // release a pdu from memory
975 void cmu_snmp::free_pdu( struct snmp_pdu
*pdu
)
977 ACE_TRACE("cmu_snmp::free_pdu");
978 struct variable_list
*vp
, *ovp
;
982 // release the oid part
985 // if deep data, then release as well
987 delete [] vp
->val
.string
;
989 // go to the next one
990 vp
= vp
->next_variable
;
991 // release up vb itself
994 // if enterprise release it up
996 delete [] pdu
->enterprise
;
997 // release up pdu itself
1002 // add a null var to a pdu
1003 void cmu_snmp::add_var(struct snmp_pdu
*pdu
,
1008 ACE_TRACE("cmu_snmp::add_var");
1010 struct variable_list
*vars
= 0;
1012 // if we don't have a vb list ,create one
1013 if (pdu
->variables
== 0)
1015 ACE_NEW(pdu
->variables
, variable_list
);
1016 vars
= pdu
->variables
;
1019 { // we have one, find the end
1020 for (vars
= pdu
->variables
; vars
->next_variable
; vars
= vars
->next_variable
)
1026 ACE_NEW(vars
->next_variable
, variable_list
);
1028 vars
= vars
->next_variable
;
1031 // add the oid with no data
1032 vars
->next_variable
= 0;
1034 // hook in the Oid portion
1035 ACE_NEW(vars
->name
, oid
[(name_length
)]);
1038 ACE_OS::memcpy((char *)vars
->name
,(char *)name
, name_length
* sizeof(oid
));
1039 vars
->name_length
= name_length
;
1041 // hook in the SMI value
1042 switch( smival
->syntax
)
1044 // null , do nothing
1045 case sNMP_SYNTAX_NULL
:
1046 case sNMP_SYNTAX_NOSUCHOBJECT
:
1047 case sNMP_SYNTAX_NOSUCHINSTANCE
:
1048 case sNMP_SYNTAX_ENDOFMIBVIEW
:
1050 vars
->type
= (u_char
) smival
->syntax
;
1051 vars
->val
.string
= 0;
1057 case sNMP_SYNTAX_OCTETS
:
1058 case sNMP_SYNTAX_OPAQUE
:
1059 case sNMP_SYNTAX_IPADDR
:
1061 vars
->type
= (u_char
) smival
->syntax
;
1062 ACE_NEW(vars
->val
.string
,
1063 u_char
[(unsigned)smival
->value
.string
.len
]);
1064 vars
->val_len
= (int) smival
->value
.string
.len
;
1065 ACE_OS::memcpy( (u_char
*) vars
->val
.string
,
1066 (u_char
*) smival
->value
.string
.ptr
,
1067 (unsigned) smival
->value
.string
.len
);
1072 case sNMP_SYNTAX_OID
:
1074 vars
->type
= (u_char
) smival
->syntax
;
1075 vars
->val_len
= (int) smival
->value
.oid
.len
* sizeof(oid
);
1076 ACE_NEW(vars
->val
.objid
, oid
[(unsigned)vars
->val_len
]);
1077 ACE_OS::memcpy((u_long
*)vars
->val
.objid
,
1078 (u_long
*)smival
->value
.oid
.ptr
,
1079 (unsigned) vars
->val_len
);
1084 case sNMP_SYNTAX_TIMETICKS
:
1085 case sNMP_SYNTAX_CNTR32
:
1086 case sNMP_SYNTAX_GAUGE32
:
1087 case sNMP_SYNTAX_UINT32
:
1090 vars
->type
= (u_char
) smival
->syntax
;
1091 ACE_NEW(vars
->val
.integer
, long);
1092 vars
->val_len
= sizeof(long);
1093 templong
= (long) smival
->value
.uNumber
;
1094 ACE_OS::memcpy( (long*) vars
->val
.integer
,
1100 case sNMP_SYNTAX_INT32
:
1103 vars
->type
= (u_char
) smival
->syntax
;
1104 ACE_NEW(vars
->val
.integer
, long);
1105 vars
->val_len
= sizeof(long);
1106 templong
= (long) smival
->value
.sNumber
;
1107 ACE_OS::memcpy( (long*) vars
->val
.integer
,
1114 case sNMP_SYNTAX_CNTR64
:
1116 vars
->type
= ( u_char
) smival
->syntax
;
1117 ACE_NEW(vars
->val
.counter64
, counter64
);
1118 vars
->val_len
= sizeof(struct counter64
);
1119 ACE_OS::memcpy( (struct counter64
*) vars
->val
.counter64
,
1120 (SmiLPCNTR64
) &(smival
->value
.hNumber
),
1121 sizeof( SmiCNTR64
));
1128 // build the authentication
1129 // works for v1 or v2c
1130 u_char
*cmu_snmp::auth_build( u_char
*data
,
1137 ACE_TRACE("cmu_snmp::auth_build");
1142 plen
= community_len
;
1144 data
= asn1::build_sequence(data
,
1146 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1147 messagelen
+ plen
+ 5);
1149 ASNERROR("buildheader");
1152 data
= asn1::build_int(data
,
1154 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1158 ASNERROR("buildint");
1162 data
= asn1::build_string(data
,
1164 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OCTET_STR
),
1168 ASNERROR("buildstring");
1172 return (u_char
*)data
;
1176 // build a variable binding
1177 u_char
* cmu_snmp::build_var_op(u_char
*data
, oid
* var_name
,
1179 u_char var_val_type
,
1180 int var_val_len
, u_char
*var_val
,
1184 ACE_TRACE("cmu_snmp::build_var_op");
1185 int dummyLen
, headerLen
;
1188 dummyLen
= *listlength
;
1196 headerLen
= data
- dataPtr
;
1197 *listlength
-= headerLen
;
1198 data
= asn1::build_objid( data
, listlength
,
1199 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1200 var_name
, *var_name_len
);
1206 // based on the type...
1207 switch(var_val_type
) {
1209 data
= asn1::build_int( data
, listlength
, var_val_type
, (long *)var_val
,
1217 data
= asn1::build_unsigned_int( data
,
1225 data
= asn1::build_unsigned_int64(data
,
1228 (struct counter64
*)var_val
,
1236 data
= asn1::build_string(data
, listlength
, var_val_type
,
1237 var_val
, var_val_len
);
1241 data
= asn1::build_objid(data
, listlength
, var_val_type
,
1242 (oid
*)var_val
, var_val_len
/ sizeof(oid
));
1246 data
= asn1::build_null(data
, listlength
, var_val_type
);
1250 data
= asn1::build_bitstring(data
, listlength
, var_val_type
,
1251 var_val
, var_val_len
);
1254 case SNMP_NOSUCHOBJECT
:
1255 case SNMP_NOSUCHINSTANCE
:
1256 case SNMP_ENDOFMIBVIEW
:
1257 data
= asn1::build_null(data
, listlength
, var_val_type
);
1261 ASNERROR("wrong type");
1268 dummyLen
= (data
- dataPtr
) - headerLen
;
1270 asn1::build_sequence(dataPtr
, &dummyLen
,
1271 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1277 // serialize the pdu
1278 int cmu_snmp::build( struct snmp_pdu
*pdu
, u_char
*packet
,
1279 int *out_length
, long version
,
1280 u_char
* community
, int community_len
)
1282 ACE_TRACE("cmu_snmp::build");
1283 u_char buf
[SNMP_MSG_LENGTH
];
1285 struct variable_list
*vp
;
1289 length
= *out_length
;
1291 for(vp
= pdu
->variables
; vp
; vp
= vp
->next_variable
) {
1292 cp
= cmu_snmp::build_var_op( cp
, vp
->name
,
1293 &vp
->name_length
, vp
->type
,
1294 vp
->val_len
, (u_char
*)vp
->val
.string
,
1299 totallength
= cp
- packet
;
1301 length
= SNMP_MSG_LENGTH
;
1303 // encode the total len
1304 cp
= asn1::build_header( buf
, &length
,
1305 (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
),
1309 ACE_OS::memcpy( (char *)cp
, (char *)packet
,totallength
);
1310 totallength
+= cp
- buf
;
1312 length
= *out_length
;
1313 if (pdu
->command
!= TRP_REQ_MSG
) {
1315 cp
= asn1::build_int( packet
,
1317 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1318 (long *)&pdu
->reqid
,
1319 sizeof(pdu
->reqid
));
1324 cp
= asn1::build_int(cp
,
1326 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1327 (long *)&pdu
->errstat
, sizeof(pdu
->errstat
));
1332 cp
= asn1::build_int(cp
,
1334 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1335 (long *)&pdu
->errindex
, sizeof(pdu
->errindex
));
1339 else { // this is a trap message
1342 cp
= asn1::build_objid( packet
,
1344 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
1345 (oid
*)pdu
->enterprise
,
1346 pdu
->enterprise_length
);
1351 cp
= asn1::build_string(cp
,
1353 // HDN Fixed to use correct tag
1354 (u_char
)SMI_IPADDRESS
,
1355 //(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
1356 (u_char
*)&pdu
->agent_addr
.sin_addr
.s_addr
,
1357 sizeof(pdu
->agent_addr
.sin_addr
.s_addr
));
1361 long tmp (static_cast <long> (pdu
->trap_type
));
1363 cp
= asn1::build_int(cp
,
1365 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1367 sizeof(pdu
->trap_type
));
1371 tmp
= static_cast <long> (pdu
->specific_type
);
1373 cp
= asn1::build_int( cp
,
1375 (u_char
)(ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
1377 sizeof(pdu
->specific_type
));
1382 cp
= asn1::build_int(cp
,
1384 // HDN Fixed to use correct tag
1385 (u_char
)SMI_TIMETICKS
,
1386 //(u_char )(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
1393 if (length
< totallength
)
1396 ACE_OS::memcpy((char *)cp
, (char *)buf
, totallength
);
1397 totallength
+= cp
- packet
;
1399 length
= SNMP_MSG_LENGTH
;
1400 cp
= asn1::build_header(buf
,
1402 (u_char
)pdu
->command
,
1406 if (length
< totallength
)
1409 ACE_OS::memcpy((char *)cp
, (char *)packet
, totallength
);
1410 totallength
+= cp
- buf
;
1412 length
= *out_length
;
1414 cp
= cmu_snmp::auth_build( packet
,
1422 if ((*out_length
- (cp
- packet
)) < totallength
)
1425 ACE_OS::memcpy((char *)cp
, (char *)buf
, totallength
);
1426 totallength
+= cp
- packet
;
1427 *out_length
= totallength
;
1432 // parse the authentication header
1433 u_char
*cmu_snmp::auth_parse(u_char
*data
,
1434 int *length
, u_char
*sid
,
1435 int *slen
, long *version
)
1437 ACE_TRACE("cmu_snmp::auth_parse");
1441 data
= asn1::parse_header( data
, length
, &type
);
1443 ASNERROR("bad header");
1447 if (type
!= (ASN_SEQUENCE
| ASN_CONSTRUCTOR
)) {
1448 ASNERROR("wrong auth header type");
1453 data
= asn1::parse_int(data
, length
, &type
, version
, sizeof(*version
));
1455 ASNERROR("bad parse of version");
1459 // get the community name
1460 data
= asn1::parse_string(data
, length
, &type
, sid
, slen
);
1462 ASNERROR("bad parse of community");
1466 return (u_char
*)data
;
1469 /* u_char *data, // IN - pointer to the start of object
1470 oid *var_name, // OUT - object id of variable
1471 int *var_name_len, // IN/OUT - length of variable name
1472 u_char *var_val_type, // OUT - type of variable
1473 (int or octet string) (one byte)
1474 int *var_val_len, // OUT - length of variable
1475 u_char **var_val, // OUT - pointer to ASN1 encoded value of variable
1479 cmu_snmp::parse_var_op( u_char
*data
, oid
*var_name
,
1480 int *var_name_len
, u_char
*var_val_type
,
1481 int *var_val_len
, u_char
**var_val
,
1484 ACE_TRACE("cmu_snmp::parse_var_op");
1486 int var_op_len
= *listlength
;
1487 u_char
*var_op_start
= data
;
1489 data
= asn1::parse_header(data
, &var_op_len
, &var_op_type
);
1494 if (var_op_type
!= (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
))
1496 data
= asn1::parse_objid(data
, &var_op_len
, &var_op_type
, var_name
, var_name_len
);
1501 if (var_op_type
!= (u_char
)
1502 (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
))
1504 *var_val
= data
; /* save pointer to this object */
1505 /* find out what type of object this is */
1506 data
= asn1::parse_header(data
, &var_op_len
, var_val_type
);
1511 *var_val_len
= var_op_len
;
1513 *listlength
-= (int)(data
- var_op_start
);
1518 // build a pdu from a data and length
1519 int cmu_snmp::parse( struct snmp_pdu
*pdu
,
1521 u_char
*community_name
,
1522 u_long
&community_len
,
1523 snmp_version
&spp_version
,
1526 ACE_TRACE("cmu_snmp::parse");
1532 u_char community
[256];
1533 int community_length
= 256;
1534 struct variable_list
*vp
= 0;
1535 oid objid
[MAX_NAME_LEN
], *op
;
1537 // authenticates message and returns length if valid
1538 data
= cmu_snmp::auth_parse(data
,
1546 // copy the returned community name
1547 ACE_OS::memcpy( (u_char
*) community_name
,
1548 (u_char
*) community
,
1550 community_len
= (long) community_length
;
1552 if( version
!= SNMP_VERSION_1
&& version
!= SNMP_VERSION_2C
) {
1553 ASNERROR("Wrong version");
1557 spp_version
= (snmp_version
) version
;
1559 data
= asn1::parse_header(data
,
1564 pdu
->command
= msg_type
;
1566 if (pdu
->command
!= TRP_REQ_MSG
){
1568 data
= asn1::parse_int(data
,
1570 (long *)&pdu
->reqid
,
1571 sizeof(pdu
->reqid
));
1574 // get the error status
1575 data
= asn1::parse_int(data
,
1578 (long *)&pdu
->errstat
,
1579 sizeof(pdu
->errstat
));
1582 // get the error index
1583 data
= asn1::parse_int(data
,
1586 (long *)&pdu
->errindex
,
1587 sizeof(pdu
->errindex
));
1593 // get the enterprise
1594 pdu
->enterprise_length
= MAX_NAME_LEN
;
1595 data
= asn1::parse_objid(data
,
1599 &pdu
->enterprise_length
);
1603 ACE_NEW_RETURN(pdu
->enterprise
,
1604 oid
[pdu
->enterprise_length
*sizeof(oid
)],-1);
1607 ACE_OS::memcpy((char *)pdu
->enterprise
,(char *)objid
,
1608 pdu
->enterprise_length
* sizeof(oid
));
1610 // get source address
1612 data
= asn1::parse_string(data
, &length
, &type
,
1613 (u_char
*)&pdu
->agent_addr
.sin_addr
.s_addr
,
1618 long tmp (static_cast <long> (pdu
->trap_type
));
1621 data
= asn1::parse_int(data
, &length
, &type
, &tmp
,
1622 sizeof(pdu
->trap_type
));
1627 tmp
= static_cast <long> (pdu
->specific_type
);
1628 data
= asn1::parse_int(data
, &length
, &type
, &tmp
,
1629 sizeof(pdu
->specific_type
));
1634 data
= asn1::parse_int(data
, &length
, &type
, (long *)&pdu
->time
,
1641 data
= asn1::parse_header(data
, &length
, &type
);
1645 if (type
!= (u_char
)(ASN_SEQUENCE
| ASN_CONSTRUCTOR
))
1648 while((int)length
> 0) {
1649 if (pdu
->variables
== 0) {
1650 ACE_NEW_RETURN(pdu
->variables
, variable_list
, -1);
1651 vp
= pdu
->variables
;
1653 ACE_NEW_RETURN(vp
->next_variable
, variable_list
, -1);
1654 vp
= vp
->next_variable
;
1656 vp
->next_variable
= 0;
1659 vp
->name_length
= MAX_NAME_LEN
;
1660 data
= cmu_snmp::parse_var_op( data
, objid
,
1661 &vp
->name_length
, &vp
->type
,
1662 &vp
->val_len
, &var_val
,
1667 ACE_NEW_RETURN(op
, oid
[(unsigned)vp
->name_length
* sizeof(oid
)], -1);
1670 ACE_OS::memcpy((char *)op
, (char *)objid
, vp
->name_length
* sizeof(oid
));
1673 len
= SNMP_MSG_LENGTH
;
1674 switch((short)vp
->type
) {
1680 ACE_NEW_RETURN(vp
->val
.integer
,long, -1);
1681 vp
->val_len
= sizeof(long);
1682 asn1::parse_int(var_val
, &len
, &vp
->type
, (long *)vp
->val
.integer
, sizeof(vp
->val
.integer
));
1685 ACE_NEW_RETURN(vp
->val
.counter64
, counter64
, -1);
1686 vp
->val_len
= sizeof(struct counter64
);
1687 asn1::parse_unsigned_int64(var_val
, &len
, &vp
->type
,
1688 (struct counter64
*)vp
->val
.counter64
,
1689 sizeof(*vp
->val
.counter64
));
1696 ACE_NEW_RETURN(vp
->val
.string
, u_char
[(unsigned)vp
->val_len
+ 1], -1);
1697 asn1::parse_string(var_val
, &len
, &vp
->type
, vp
->val
.string
,
1702 vp
->val_len
= MAX_NAME_LEN
;
1703 asn1::parse_objid(var_val
, &len
, &vp
->type
, objid
, &vp
->val_len
);
1704 //vp->val_len *= sizeof(oid);
1706 ACE_NEW_RETURN(vp
->val
.objid
, oid
[(unsigned)vp
->val_len
*sizeof(oid
)], -1);
1709 ACE_OS::memcpy((char *)vp
->val
.objid
,
1711 vp
->val_len
* sizeof(oid
));
1714 case SNMP_NOSUCHOBJECT
:
1715 case SNMP_NOSUCHINSTANCE
:
1716 case SNMP_ENDOFMIBVIEW
:
1720 ASNERROR("bad type returned ");