]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/asn1.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / asn1.cpp
1 /*_############################################################################
2   _## 
3   _##  asn1.cpp  
4   _##
5   _##  SNMP++v3.2.25
6   _##  -----------------------------------------------
7   _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
8   _##
9   _##  This software is based on SNMP++2.6 from Hewlett Packard:
10   _##  
11   _##    Copyright (c) 1996
12   _##    Hewlett-Packard Company
13   _##  
14   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15   _##  Permission to use, copy, modify, distribute and/or sell this software 
16   _##  and/or its documentation is hereby granted without fee. User agrees 
17   _##  to display the above copyright notice and this license notice in all 
18   _##  copies of the software and any documentation of the software. User 
19   _##  agrees to assume all liability for the use of the software; 
20   _##  Hewlett-Packard and Jochen Katz make no representations about the 
21   _##  suitability of this software for any purpose. It is provided 
22   _##  "AS-IS" without warranty of any kind, either express or implied. User 
23   _##  hereby grants a royalty-free license to any and all derivatives based
24   _##  upon this software code base. 
25   _##  
26   _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
27   _##  
28   _##########################################################################*/
29
30 /*===================================================================
31   Copyright (c) 1999
32   Hewlett-Packard Company
33
34   ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35   Permission to use, copy, modify, distribute and/or sell this software
36   and/or its documentation is hereby granted without fee. User agrees
37   to display the above copyright notice and this license notice in all
38   copies of the software and any documentation of the software. User
39   agrees to assume all liability for the use of the software; Hewlett-Packard
40   makes no representations about the suitability of this software for any
41   purpose. It is provided "AS-IS" without warranty of any kind,either express
42   or implied. User hereby grants a royalty-free license to any and all
43   derivatives based upon this software code base.
44
45   A S N 1. C P P
46
47   ASN encoder / decoder implementation
48
49   DESIGN + AUTHOR:  Peter E. Mellquist
50 =====================================================================*/
51 char asn1_cpp_version[]="#(@) SNMP++ $Id: asn1.cpp 1557 2009-07-03 20:16:09Z katz $";
52
53 #ifdef __unix
54 #include /**/ <sys/types.h>
55 #include /**/ <netinet/in.h>
56 #endif
57
58 #include /**/ <stdlib.h>
59
60 #include "snmp_pp/config_snmp_pp.h"
61 #include "snmp_pp/asn1.h"
62 #include "snmp_pp/v3.h"
63 #include "snmp_pp/snmperrs.h"
64 #include "snmp_pp/log.h"
65
66 #ifdef SNMP_PP_NAMESPACE
67 namespace Snmp_pp {
68 #endif
69
70 #ifndef NULL
71 #define NULL    0
72 #endif
73
74 /*
75  * asn_parse_int - pulls a long out of an ASN int type.
76  *  On entry, datalength is input as the number of valid bytes following
77  *   "data".  On exit, it is returned as the number of valid bytes
78  *   following the end of this object.
79  *
80  *  Returns a pointer to the first byte past the end
81  *   of this object (i.e. the start of the next object).
82  *  Returns NULL on any error.
83  */
84 unsigned char *asn_parse_int(unsigned char *data,
85                              int *datalength,
86                              unsigned char *type,
87                              long *intp)
88 {
89   /*
90    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
91    *       timestamp   0x43 asnlength byte {byte}*
92    */
93   unsigned char *bufp = data;
94   unsigned long  asn_length;
95   long value = 0;
96
97   *type = *bufp++;
98   if ((*type != 0x02) && (*type != 0x43) &&
99       (*type != 0x41)) {
100     ASNERROR("Wrong Type. Not an integer");
101     return NULL;
102   }
103   bufp = asn_parse_length(bufp, &asn_length);
104   if (bufp == NULL) {
105     ASNERROR("bad length");
106     return NULL;
107   }
108   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
109     ASNERROR("overflow of message (int)");
110     return NULL;
111   }
112   if (asn_length > sizeof(*intp)) {
113     ASNERROR("I don't support such large integers");
114     return NULL;
115   }
116   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
117   if (*bufp & 0x80)
118     value = -1; /* integer is negative */
119   while(asn_length--)
120     value = (value << 8) | *bufp++;
121   *intp = value;
122   return bufp;
123 }
124
125
126 /*
127  * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
128  *  On entry, datalength is input as the number of valid bytes following
129  *   "data".  On exit, it is returned as the number of valid bytes
130  *   following the end of this object.
131  *
132  *  Returns a pointer to the first byte past the end
133  *   of this object (i.e. the start of the next object).
134  *  Returns NULL on any error.
135  */
136 unsigned char *asn_parse_unsigned_int(unsigned char *data,      
137                                       int *datalength,
138                                       unsigned char *type,
139                                       unsigned long *intp)
140 {
141   /*
142    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
143    *                   0x43 asnlength byte {byte}*
144    */
145   unsigned char *bufp = data;
146   unsigned long asn_length;
147   unsigned long value = 0;
148
149   // get the type
150   *type = *bufp++;
151   if ((*type != 0x02) && (*type != 0x43) &&
152       (*type != 0x41) && (*type != 0x42) &&
153       (*type != 0x47)) {
154     ASNERROR("Wrong Type. Not an unsigned integer");
155     return NULL;
156   }
157
158   // pick up the len
159   bufp = asn_parse_length(bufp, &asn_length);
160   if (bufp == NULL) {
161     ASNERROR("bad length");
162     return NULL;
163   }
164
165   // check the len for message overflow
166   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
167     ASNERROR("overflow of message (uint)");
168     return NULL;
169   }
170
171   // check for legal uint size
172   if ((asn_length > 5) || ((asn_length > 4) && (*bufp != 0x00))) {
173     ASNERROR("I don't support such large integers");
174     return NULL;
175   }
176
177   // check for leading  0 octet
178   if (*bufp == 0x00) {
179     bufp++;
180     asn_length--;
181   }
182
183   // fix the returned data length value
184   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
185
186   // calculate the value
187   for (long i=0;i<(long)asn_length;i++)
188     value = (value << 8) + (unsigned long) *bufp++;
189
190   *intp = value;  // assign return value
191
192   return bufp;   // return the bumped pointer
193 }
194
195
196 /*
197  * asn_build_int - builds an ASN object containing an integer.
198  *  On entry, datalength is input as the number of valid bytes following
199  *   "data".  On exit, it is returned as the number of valid bytes
200  *   following the end of this object.
201  *
202  *  Returns a pointer to the first byte past the end
203  *   of this object (i.e. the start of the next object).
204  *  Returns NULL on any error.
205  */
206 unsigned char *asn_build_int(unsigned char *data, int *datalength,
207                              const unsigned char type,
208                              const long *intp)
209 {
210   /*
211    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
212    */
213   long integer = *intp;
214   unsigned long mask;
215   int intsize = sizeof(long);
216
217   /* Truncate "unnecessary" bytes off of the most significant end of this
218    * 2's complement integer.  There should be no sequence of 9
219    * consecutive 1's or 0's at the most significant end of the
220    * integer.
221    */
222   mask = 0x1FFul << ((8 * (sizeof(long) - 1)) - 1);
223   /* mask is 0xFF800000 on a big-endian machine */
224   while((((integer & mask) == 0) || ((integer & mask) == mask))
225         && intsize > 1) {
226     intsize--;
227     integer <<= 8;
228   }
229   data = asn_build_header(data, datalength, type, intsize);
230   if (data == NULL)          return NULL;
231   if (*datalength < intsize) return NULL;
232   *datalength -= intsize;
233   mask = 0xFFul << (8 * (sizeof(long) - 1));
234   /* mask is 0xFF000000 on a big-endian machine */
235   while(intsize--) {
236     *data++ = (unsigned char)((integer & mask) >> (8 * (sizeof(long) - 1)));
237     integer <<= 8;
238   }
239   return data;
240 }
241
242
243 /*
244  * asn_build_unsigned_int - builds an ASN object containing an integer.
245  *  On entry, datalength is input as the number of valid bytes following
246  *   "data".  On exit, it is returned as the number of valid bytes
247  *   following the end of this object.
248  *
249  *  Returns a pointer to the first byte past the end
250  *   of this object (i.e. the start of the next object).
251  *  Returns NULL on any error.
252  */
253 unsigned char *asn_build_unsigned_int(unsigned char *data, // modified data
254                                       int *datalength,     // returned buffer length
255                                       unsigned char type,  // SMI type
256                                       unsigned long *intp) // Uint to encode
257 {
258   /*
259    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
260    */
261   unsigned long u_integer = *intp;
262   long u_integer_len;
263   long x;
264
265   // figure out the len
266   if (((u_integer >> 24) & 0xFF) != 0)
267     u_integer_len = 4;
268   else if (((u_integer >> 16) & 0xFF) !=0)
269     u_integer_len = 3;
270   else if (((u_integer >> 8) & 0xFF) !=0)
271     u_integer_len = 2;
272   else
273     u_integer_len = 1;
274
275   // check for 5 byte len where first byte will be a null
276   if (((u_integer >> (8 * (u_integer_len -1))) & 0x080) !=0)    {
277     u_integer_len++;
278   }
279
280   // build up the header
281   data = asn_build_header(data, datalength, type, u_integer_len);
282   if (data == NULL)                return NULL;
283   if (*datalength < u_integer_len) return NULL;
284
285   // special case, add a null byte for len of 5
286   if (u_integer_len == 5) {
287     *data++ = 0;
288     for (x=1;x<u_integer_len;x++)
289       *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
290   }
291   else
292   {
293     for (x=0;x<u_integer_len;x++)
294       *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
295   }
296   *datalength -= u_integer_len;
297   return data;
298 }
299
300
301 /*
302  * asn_parse_string - pulls an octet string out of an ASN octet string type.
303  *  On entry, datalength is input as the number of valid bytes following
304  *   "data".  On exit, it is returned as the number of valid bytes
305  *   following the beginning of the next object.
306  *
307  *  "string" is filled with the octet string.
308  *
309  *  Returns a pointer to the first byte past the end
310  *   of this object (i.e. the start of the next object).
311  *  Returns NULL on any error.
312  */
313 unsigned char *asn_parse_string(unsigned char   *data,
314                                 int *datalength,
315                                 unsigned char *type,
316                                 unsigned char *str,
317                                 int *strlength)
318 {
319   /*
320    * ASN.1 octet string ::= primstring | cmpdstring
321    * primstring ::= 0x04 asnlength byte {byte}*
322    * cmpdstring ::= 0x24 asnlength string {string}*
323    * ipaddress  ::= 0x40 4 byte byte byte byte
324    */
325   unsigned char *bufp = data;
326   unsigned long  asn_length;
327
328   *type = *bufp++;
329   if ((*type != 0x04) && (*type != 0x24) &&
330       (*type != 0x40) && (*type != 0x44) &&
331       (*type != 0x45)) {
332     ASNERROR("asn parse string: Wrong Type. Not a string");
333     return NULL;
334   }
335   bufp = asn_parse_length(bufp, &asn_length);
336   if (bufp == NULL)
337     return NULL;
338   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
339     ASNERROR("asn parse string: overflow of message");
340     return NULL;
341   }
342   if ((int)asn_length > *strlength) {
343     ASNERROR("asn parse string: String to parse is longer than buffer, aborting parsing.");
344     return NULL;
345   }
346
347   memcpy(str, bufp, asn_length);
348   *strlength = (int)asn_length;
349   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
350   return bufp + asn_length;
351 }
352
353
354 /*
355  * asn_build_string - Builds an ASN octet string object containing the input string.
356  *  On entry, datalength is input as the number of valid bytes following
357  *   "data".  On exit, it is returned as the number of valid bytes
358  *   following the beginning of the next object.
359  *
360  *  Returns a pointer to the first byte past the end
361  *   of this object (i.e. the start of the next object).
362  *  Returns NULL on any error.
363  */
364 unsigned char *asn_build_string(unsigned char *data,
365                                 int *datalength,
366                                 const unsigned char type,
367                                 const unsigned char *string,
368                                 const int strlength)
369 {
370   /*
371    * ASN.1 octet string ::= primstring | cmpdstring
372    * primstring ::= 0x04 asnlength byte {byte}*
373    * cmpdstring ::= 0x24 asnlength string {string}*
374    * This code will never send a compound string.
375    */
376   data = asn_build_header(data, datalength, type, strlength);
377   if (data == NULL)            return NULL;
378   if (*datalength < strlength) return NULL;
379
380   memcpy(data, string, strlength);
381   *datalength -= strlength;
382   return data + strlength;
383 }
384
385
386 /*
387  * asn_parse_header - interprets the ID and length of the current object.
388  *  On entry, datalength is input as the number of valid bytes following
389  *   "data".  On exit, it is returned as the number of valid bytes
390  *   in this object following the id and length.
391  *
392  *  Returns a pointer to the first byte of the contents of this object.
393  *  Returns NULL on any error.
394  */
395 unsigned char *asn_parse_header(unsigned char *data,
396                                 int *datalength,
397                                 unsigned char *type)
398 {
399   unsigned char *bufp = data;
400   register int header_len;
401   unsigned long asn_length;
402
403   /* this only works on data types < 30, i.e. no extension octets */
404   if (IS_EXTENSION_ID(*bufp)) {
405     ASNERROR("can't process ID >= 30");
406     return NULL;
407   }
408   *type = *bufp;
409   bufp = asn_parse_length(bufp + 1, &asn_length);
410   if (bufp == NULL)
411     return NULL;
412   header_len = SAFE_INT_CAST(bufp - data);
413   if ((unsigned long)(header_len + asn_length) > (unsigned long)*datalength) {
414     ASNERROR("asn length too long");
415     return NULL;
416   }
417   *datalength = (int)asn_length;
418   return bufp;
419 }
420
421 /*
422  * asn_build_header - builds an ASN header for an object with the ID and
423  * length specified.
424  *  On entry, datalength is input as the number of valid bytes following
425  *   "data".  On exit, it is returned as the number of valid bytes
426  *   in this object following the id and length.
427  *
428  *  This only works on data types < 30, i.e. no extension octets.
429  *  The maximum length is 0xFFFF;
430  *
431  *  Returns a pointer to the first byte of the contents of this object.
432  *  Returns NULL on any error.
433  */
434 unsigned char *asn_build_header(unsigned char *data,
435                                 int *datalength,
436                                 unsigned char type,
437                                 int length)
438 {
439   if (*datalength < 1)
440     return NULL;
441   *data++ = type;
442   (*datalength)--;
443   return asn_build_length(data, datalength, length);
444 }
445
446 /*
447  * asn_build_sequence - builds an ASN header for a sequence with the ID and
448  * length specified.
449  *
450  *  This only works on data types < 30, i.e. no extension octets.
451  *
452  *  Returns a pointer to the first byte of the contents of this object.
453  *  Returns NULL on any error.
454  */
455 unsigned char *asn_build_sequence(unsigned char *data,
456                                   int *datalength,
457                                   unsigned char type,
458                                   int length)
459 {
460   if (*datalength < 2) /* need at least two octets for a sequence */
461   {
462     ASNERROR("build_sequence");
463     return NULL;
464   }
465   *data++ = type;
466   (*datalength)--;
467
468   unsigned char *data_with_length = asn_build_length(data, datalength, length);
469   if (data_with_length == NULL)
470   {
471     (*datalength)++; /* correct datalength to emulate old behavior of build_sequence */
472     return NULL;
473   }
474      
475   return data_with_length;
476 }
477
478 /*
479  * asn_parse_length - interprets the length of the current object.
480  *  On exit, length contains the value of this length field.
481  *
482  *  Returns a pointer to the first byte after this length
483  *  field (aka: the start of the data field).
484  *  Returns NULL on any error.
485  */
486 unsigned char * asn_parse_length(unsigned char *data,
487                                  unsigned long *length)
488 {
489   unsigned char lengthbyte = *data;
490   *length = 0;
491   if (lengthbyte & ASN_LONG_LEN) {
492     lengthbyte &= ~ASN_LONG_LEN;        /* turn MSb off */
493     if (lengthbyte == 0) {
494       ASNERROR("We don't support indefinite lengths");
495       return NULL;
496     }
497     if (lengthbyte > sizeof(int)) {
498       ASNERROR("we can't support data lengths that long");
499       return NULL;
500     }
501     for (int i=0 ; i < lengthbyte ; i++)
502     {
503       *length = (*length << 8) + *(data + 1 + i);
504     }
505     // check for length greater than 2^31
506     if (*length > 0x80000000ul) {
507       ASNERROR("SNMP does not support data lengths > 2^31");
508       return NULL;
509     }
510     return data + lengthbyte + 1;
511   } else { /* short asnlength */
512     *length = (long)lengthbyte;
513     return data + 1;
514   }
515 }
516
517 unsigned char *asn_build_length(unsigned char *data,
518                                 int *datalength,
519                                 int length)
520 {
521   unsigned char *start_data = data;
522
523   /* no indefinite lengths sent */
524   if (length < 0x80) {
525     if (*datalength < 1) {
526       ASNERROR("build_length");
527       return NULL;
528     }   
529     *data++ = (unsigned char)length;
530   }
531   else if (length <= 0xFF) {
532     if (*datalength < 2) {
533       ASNERROR("build_length");
534       return NULL;
535     }   
536     *data++ = (unsigned char)(0x01 | ASN_LONG_LEN);
537     *data++ = (unsigned char)length;
538   }
539   else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
540     if (*datalength < 3) {
541       ASNERROR("build_length");
542       return NULL;
543     }   
544     *data++ = (unsigned char)(0x02 | ASN_LONG_LEN);
545     *data++ = (unsigned char)((length >> 8) & 0xFF);
546     *data++ = (unsigned char)(length & 0xFF);
547   }
548   else if (length <= 0xFFFFFF) { /* 0xFF < length <= 0xFFFF */
549     if (*datalength < 4) {
550       ASNERROR("build_length");
551       return NULL;
552     }   
553     *data++ = (unsigned char)(0x03 | ASN_LONG_LEN);
554     *data++ = (unsigned char)((length >> 16) & 0xFF);
555     *data++ = (unsigned char)((length >> 8) & 0xFF);
556     *data++ = (unsigned char)(length & 0xFF);
557   }
558   else {
559     if (*datalength < 5) {
560       ASNERROR("build_length");
561       return NULL;
562     }   
563     *data++ = (unsigned char)(0x04 | ASN_LONG_LEN);
564     *data++ = (unsigned char)((length >> 24) & 0xFF);
565     *data++ = (unsigned char)((length >> 16) & 0xFF);
566     *data++ = (unsigned char)((length >> 8) & 0xFF);
567     *data++ = (unsigned char)(length & 0xFF);
568   }
569   *datalength -= SAFE_INT_CAST(data - start_data);
570   return data;
571 }
572
573 /*
574  * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
575  *  On entry, datalength is input as the number of valid bytes following
576  *   "data".  On exit, it is returned as the number of valid bytes
577  *   following the beginning of the next object.
578  *
579  *  "objid" is filled with the object identifier.
580  *
581  *  Returns a pointer to the first byte past the end
582  *   of this object (i.e. the start of the next object).
583  *  Returns NULL on any error.
584  */
585 unsigned char *asn_parse_objid(unsigned char *data,
586                                int *datalength,
587                                unsigned char *type,
588                                oid *objid,
589                                int *objidlength)
590 {
591   /*
592    * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
593    * subidentifier ::= {leadingbyte}* lastbyte
594    * leadingbyte ::= 1 7bitvalue
595    * lastbyte ::= 0 7bitvalue
596    */
597   unsigned char *bufp = data;
598   oid *oidp = objid + 1;
599   unsigned long subidentifier;
600   long length;
601   unsigned long asn_length;
602
603   *type = *bufp++;
604   if (*type != 0x06) {
605     ASNERROR("Wrong Type. Not an oid");
606     return NULL;
607   }
608   bufp = asn_parse_length(bufp, &asn_length);
609   if (bufp == NULL)
610     return NULL;
611   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
612     ASNERROR("overflow of message (objid)");
613     return NULL;
614   }
615   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
616
617   /* Handle invalid object identifier encodings of the form 06 00 robustly */
618   if (asn_length == 0)
619     objid[0] = objid[1] = 0;
620
621   length = asn_length;
622   (*objidlength)--;     /* account for expansion of first byte */
623   while (length > 0 && (*objidlength)-- > 0) {
624     subidentifier = 0;
625     do {        /* shift and add in low order 7 bits */
626       subidentifier = (subidentifier << 7) + (*(unsigned char *)bufp & ~ASN_BIT8);
627       length--;
628     } while (*(unsigned char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
629     if (subidentifier > (unsigned long)MAX_SUBID) {
630       ASNERROR("subidentifier too long");
631       return NULL;
632     }
633     *oidp++ = (oid)subidentifier;
634   }
635
636   /*
637    * The first two subidentifiers are encoded into the first component
638    * with the value (X * 40) + Y, where:
639    *    X is the value of the first subidentifier.
640    *  Y is the value of the second subidentifier.
641    */
642   subidentifier = (unsigned long)objid[1];
643   if (subidentifier == 0x2B) {
644     objid[0] = 1;
645     objid[1] = 3;
646   } else {
647     objid[1] = (unsigned char)(subidentifier % 40);
648     objid[0] = (unsigned char)((subidentifier - objid[1]) / 40);
649   }
650
651   *objidlength = (int)(oidp - objid);
652   return bufp;
653 }
654
655 /*
656  * asn_build_objid - Builds an ASN object identifier object containing the
657  * input string.
658  *  On entry, datalength is input as the number of valid bytes following
659  *   "data".  On exit, it is returned as the number of valid bytes
660  *   following the beginning of the next object.
661  *
662  *  Returns a pointer to the first byte past the end
663  *   of this object (i.e. the start of the next object).
664  *  Returns NULL on any error.
665  */
666 unsigned char *asn_build_objid(unsigned char *data,
667                                 int *datalength,
668                                 unsigned char type,
669                                 oid *objid,
670                                 int objidlength)
671 {
672   /*
673    * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
674    * subidentifier ::= {leadingbyte}* lastbyte
675    * leadingbyte ::= 1 7bitvalue
676    * lastbyte ::= 0 7bitvalue
677    */
678   // F.Fock correct buffer size must be 5*8bit*MAX_OID_LEN
679   unsigned char buf[MAX_OID_LEN*5];
680   unsigned char *bp = buf;
681   oid *op = objid;
682   int    asnlength;
683   unsigned long subid, mask, testmask;
684   int bits, testbits;
685
686   if (objidlength < 2) {
687     *bp++ = 0;
688     objidlength = 0;
689   } else {
690     *bp++ = (unsigned char) (op[1] + (op[0] * 40));
691     objidlength -= 2;
692     op += 2;
693   }
694
695   while(objidlength-- > 0) {
696     subid = *op++;
697     if (subid < 127) { /* off by one? */
698       *bp++ = (unsigned char)subid;
699     } else {
700       mask = 0x7F; /* handle subid == 0 case */
701       bits = 0;
702       /* testmask *MUST* !!!! be of an unsigned type */
703       for(testmask = 0x7F, testbits = 0; testmask != 0;
704           testmask <<= 7, testbits += 7) {
705         if (subid & testmask) { /* if any bits set */
706           mask = testmask;
707           bits = testbits;
708         }
709       }
710       /* mask can't be zero here */
711       for(;mask != 0x7F; mask >>= 7, bits -= 7) {
712         /* fix a mask that got truncated above */
713         if (mask == 0x1E00000)
714           mask = 0xFE00000;
715         *bp++ = (unsigned char)(((subid & mask) >> bits) | ASN_BIT8);
716       }
717       *bp++ = (unsigned char)(subid & mask);
718     }
719   }
720   asnlength = SAFE_INT_CAST(bp - buf);
721   data = asn_build_header(data, datalength, type, asnlength);
722   if (data == NULL)            return NULL;
723   if (*datalength < asnlength) return NULL;
724
725   memcpy((char *)data, (char *)buf,  asnlength);
726   *datalength -= asnlength;
727   return data + asnlength;
728 }
729
730 /*
731  * asn_parse_null - Interprets an ASN null type.
732  *  On entry, datalength is input as the number of valid bytes following
733  *   "data".  On exit, it is returned as the number of valid bytes
734  *   following the beginning of the next object.
735  *
736  *  Returns a pointer to the first byte past the end
737  *   of this object (i.e. the start of the next object).
738  *  Returns NULL on any error.
739  */
740 unsigned char *asn_parse_null(unsigned char     *data,
741                               int *datalength,
742                               unsigned char *type)
743 {
744   /*
745    * ASN.1 null ::= 0x05 0x00
746    */
747   unsigned char   *bufp = data;
748   unsigned long     asn_length;
749
750   *type = *bufp++;
751   if (*type != 0x05) {
752     ASNERROR("Wrong Type. Not a null");
753     return NULL;
754   }
755   bufp = asn_parse_length(bufp, &asn_length);
756   if (bufp == NULL)
757     return NULL;
758   if (asn_length != 0) {
759     ASNERROR("Malformed NULL");
760     return NULL;
761   }
762   *datalength -= SAFE_INT_CAST(bufp - data);
763   return bufp + asn_length;
764 }
765
766
767 /*
768  * asn_build_null - Builds an ASN null object.
769  *  On entry, datalength is input as the number of valid bytes following
770  *   "data".  On exit, it is returned as the number of valid bytes
771  *   following the beginning of the next object.
772  *
773  *  Returns a pointer to the first byte past the end
774  *   of this object (i.e. the start of the next object).
775  *  Returns NULL on any error.
776  */
777 unsigned char *asn_build_null(unsigned char *data,
778                                int *datalength,
779                                unsigned char type)
780 {
781   /*
782    * ASN.1 null ::= 0x05 0x00
783    */
784   return asn_build_header(data, datalength, type, 0);
785 }
786
787 /*
788  * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
789  *  On entry, datalength is input as the number of valid bytes following
790  *   "data".  On exit, it is returned as the number of valid bytes
791  *   following the beginning of the next object.
792  *
793  *  "string" is filled with the bit string.
794  *
795  *  Returns a pointer to the first byte past the end
796  *   of this object (i.e. the start of the next object).
797  *  Returns NULL on any error.
798  */
799 unsigned char *asn_parse_bitstring(unsigned char *data,
800                                     int *datalength,
801                                     unsigned char *type,
802                                     unsigned char *string,
803                                     int *strlength)
804 {
805   /*
806    * bitstring ::= 0x03 asnlength unused {byte}*
807    */
808   unsigned char *bufp = data;
809   unsigned long     asn_length;
810
811   *type = *bufp++;
812   if (*type != 0x03) {
813     ASNERROR("Wrong Type. Not a bitstring");
814     return NULL;
815   }
816   bufp = asn_parse_length(bufp, &asn_length);
817   if (bufp == NULL)
818     return NULL;
819   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
820     ASNERROR("overflow of message (bitstring)");
821     return NULL;
822   }
823   if ((int) asn_length > *strlength) {
824     ASNERROR("I don't support such long bitstrings");
825     return NULL;
826   }
827   if (asn_length < 1) {
828     ASNERROR("Invalid bitstring");
829     return NULL;
830   }
831   if (*bufp > 7) {
832     ASNERROR("Invalid bitstring");
833     return NULL;
834   }
835
836   memcpy((char *)string,(char *)bufp,  (int)asn_length);
837   *strlength = (int)asn_length;
838   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
839   return bufp + asn_length;
840 }
841
842
843 /*
844  * asn_build_bitstring - Builds an ASN bit string object containing the
845  * input string.
846  *  On entry, datalength is input as the number of valid bytes following
847  *   "data".  On exit, it is returned as the number of valid bytes
848  *   following the beginning of the next object.
849  *
850  *  Returns a pointer to the first byte past the end
851  *   of this object (i.e. the start of the next object).
852  *  Returns NULL on any error.
853  */
854 unsigned char *asn_build_bitstring(unsigned char *data,
855                                     int *datalength,
856                                     unsigned char type, 
857                                     unsigned char *string,
858                                     int strlength)
859 {
860   /*
861    * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
862    */
863   if (strlength < 1 || *string > 7) {
864     ASNERROR("Building invalid bitstring");
865     return NULL;
866   }
867   data = asn_build_header(data, datalength, type, strlength);
868   if (data == NULL)            return NULL;
869   if (*datalength < strlength) return NULL;
870
871   memcpy((char *)data,(char *)string, strlength);
872   *datalength -= strlength;
873   return data + strlength;
874 }
875
876
877 /*
878  * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
879  * type.
880  *  On entry, datalength is input as the number of valid bytes following
881  *   "data".  On exit, it is returned as the number of valid bytes
882  *   following the end of this object.
883  *
884  *  Returns a pointer to the first byte past the end
885  *   of this object (i.e. the start of the next object).
886  *  Returns NULL on any error.
887  */
888 unsigned char *asn_parse_unsigned_int64(unsigned char *data,
889                                         int *datalength,
890                                         unsigned char *type,
891                                         struct counter64 *cp)
892 {
893   /*
894    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
895    */
896   unsigned char *bufp = data;
897   unsigned long     asn_length;
898   unsigned long low = 0, high = 0;
899
900   *type = *bufp++;
901   if ((*type != 0x02) && (*type != 0x46)) {
902     ASNERROR("Wrong Type. Not an integer 64");
903     return NULL;
904   }
905   bufp = asn_parse_length(bufp, &asn_length);
906   if (bufp == NULL) {
907     ASNERROR("bad length");
908     return NULL;
909   }
910   if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
911     ASNERROR("overflow of message (uint64)");
912     return NULL;
913   }
914   if (((int)asn_length > 9) ||
915       (((int)asn_length == 9) && *bufp != 0x00)) {
916     ASNERROR("I don't support such large integers");
917     return NULL;
918   }
919   *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
920   if (*bufp & 0x80) {
921     low = (unsigned long) -1; // integer is negative
922     high = (unsigned long) -1;
923   }
924   while(asn_length--) {
925     high = (high << 8) | ((low & 0xFF000000) >> 24);
926     low = ((low << 8) | *bufp++) & 0xFFFFFFFF;
927   }
928   cp->low = low;
929   cp->high = high;
930
931   return bufp;
932 }
933
934
935 /*
936  * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
937  *  On entry, datalength is input as the number of valid bytes following
938  *   "data".  On exit, it is returned as the number of valid bytes
939  *   following the end of this object.
940  *
941  *  Returns a pointer to the first byte past the end
942  *   of this object (i.e. the start of the next object).
943  *  Returns NULL on any error.
944  */
945 unsigned char *asn_build_unsigned_int64(unsigned char *data,
946                                         int *datalength,
947                                         unsigned char type,
948                                         struct counter64 *cp)
949 {
950   /*
951    * ASN.1 integer ::= 0x02 asnlength byte {byte}*
952    */
953   unsigned long low = cp->low;
954   unsigned long high = cp->high;
955   unsigned long mask = 0xFF000000ul;
956   int add_null_byte = 0;
957   int intsize = 8;
958
959   if (((high & mask) >> 24) & 0x80) {
960     /* if MSB is set */
961     add_null_byte = 1;
962     intsize++;
963   }
964   else {
965     /*
966      * Truncate "unnecessary" bytes off of the most significant end of this 2's
967      * complement integer.
968      * There should be no sequence of 9 consecutive 1's or 0's at the most
969      * significant end of the integer.
970      */
971     unsigned long mask2 = 0xFF800000ul;
972     while ((((high & mask2) == 0) || ((high & mask2) == mask2)) &&
973            (intsize > 1)) {
974       intsize--;
975       high = (high << 8) | ((low & mask) >> 24);
976       low <<= 8;
977     }
978   }
979   data = asn_build_header(data, datalength, type, intsize);
980   if (data == NULL)          return NULL;
981   if (*datalength < intsize) return NULL;
982   *datalength -= intsize;
983   if (add_null_byte == 1) {
984     *data++ = 0;
985     intsize--;
986   }
987   while(intsize--) {
988     *data++ = (unsigned char)((high & mask) >> 24);
989     high = (high << 8) | ((low & mask) >> 24);
990     low <<= 8;
991   }
992   return data;
993 }
994
995
996 // create a pdu
997 struct snmp_pdu *snmp_pdu_create(int command)
998 {
999   struct snmp_pdu *pdu;
1000
1001   pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
1002   if (!pdu) return pdu;
1003   memset((char *)pdu, 0,sizeof(struct snmp_pdu));
1004   pdu->command = command;
1005 #ifdef _SNMPv3
1006   pdu->msgid = 0;
1007 #endif
1008   pdu->errstat = 0;
1009   pdu->errindex = 0;
1010   pdu->enterprise = NULL;
1011   pdu->enterprise_length = 0;
1012   pdu->variables = NULL;
1013   return pdu;
1014 }
1015
1016 // free content and clear pointers
1017 void clear_pdu(struct snmp_pdu *pdu, bool clear_all)
1018 {
1019   struct variable_list *vp, *ovp;
1020
1021   vp = pdu->variables;
1022   while (vp)
1023   {
1024     if (vp->name) free((char *)vp->name);  // free the oid part
1025     if (vp->val.string) free((char *)vp->val.string);  // free deep data
1026     ovp = vp;
1027     vp = vp->next_variable;     // go to the next one
1028     free((char *)ovp);     // free up vb itself
1029   }
1030   pdu->variables = NULL;
1031
1032   // if enterprise free it up
1033   if (pdu->enterprise)
1034     free((char *)pdu->enterprise);
1035   pdu->enterprise = NULL;
1036
1037   if (!clear_all) return;
1038
1039   pdu->command = 0;
1040   pdu->reqid   = 0;
1041 #ifdef _SNMPv3
1042   pdu->msgid   = 0;
1043   pdu->maxsize_scopedpdu = 0;
1044 #endif
1045   pdu->errstat = 0;
1046   pdu->errindex = 0;
1047
1048   pdu->enterprise_length = 0;
1049   pdu->trap_type = 0;
1050   pdu->specific_type = 0;
1051   pdu->time = 0;
1052 }
1053
1054 // free a pdu
1055 void snmp_free_pdu(struct snmp_pdu *pdu)
1056 {
1057   clear_pdu(pdu); // clear and free content
1058   free(pdu);   // free up pdu itself
1059 }
1060
1061
1062 // add a null var to a pdu
1063 void snmp_add_var(struct snmp_pdu *pdu,
1064                   oid *name,
1065                   int name_length,
1066                   SmiVALUE *smival)
1067 {
1068   struct variable_list *vars;
1069
1070   // if we don't have a vb list ,create one
1071   if (pdu->variables == NULL)
1072     pdu->variables = vars = (struct variable_list *)malloc(sizeof(struct variable_list));
1073   else
1074   {
1075     // we have one, find the end
1076     vars = pdu->variables;
1077     while (vars->next_variable) vars = vars->next_variable;
1078
1079     // create a new one
1080     vars->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
1081     // bump ptr
1082     vars = vars->next_variable;
1083   }
1084
1085   // add the oid with no data
1086   vars->next_variable = NULL;
1087
1088   // hook in the Oid portion
1089   vars->name = (oid *)malloc(name_length * sizeof(oid));
1090
1091   memcpy((char *)vars->name,(char *)name, name_length * sizeof(oid));
1092   vars->name_length = name_length;
1093
1094   // hook in the SMI value
1095   switch(smival->syntax)
1096     {
1097       // null , do nothing
1098     case sNMP_SYNTAX_NULL:
1099     case sNMP_SYNTAX_NOSUCHOBJECT:
1100     case sNMP_SYNTAX_NOSUCHINSTANCE:
1101     case sNMP_SYNTAX_ENDOFMIBVIEW:
1102       {
1103         vars->type = (unsigned char) smival->syntax;
1104         vars->val.string = NULL;
1105         vars->val_len = 0;
1106       }
1107       break;
1108
1109       // octects
1110     case sNMP_SYNTAX_OCTETS:
1111     case sNMP_SYNTAX_OPAQUE:
1112     case sNMP_SYNTAX_IPADDR:
1113       {
1114         vars->type = (unsigned char) smival->syntax;
1115         vars->val.string = (unsigned char *)malloc((unsigned)smival->value.string.len);
1116         vars->val_len = (int) smival->value.string.len;
1117         memcpy((unsigned char *) vars->val.string,
1118                 (unsigned char *) smival->value.string.ptr,
1119                 (unsigned) smival->value.string.len);
1120       }
1121       break;
1122
1123       // oid
1124     case sNMP_SYNTAX_OID:
1125       {
1126         vars->type = (unsigned char) smival->syntax;
1127         vars->val_len = (int) smival->value.oid.len * sizeof(oid);
1128         vars->val.objid = (oid *)malloc((unsigned)vars->val_len);
1129         memcpy((unsigned long *)vars->val.objid,
1130                (unsigned long *)smival->value.oid.ptr,
1131                (unsigned) vars->val_len);
1132       }
1133       break;
1134
1135
1136         
1137     case sNMP_SYNTAX_TIMETICKS:
1138     case sNMP_SYNTAX_CNTR32:
1139     case sNMP_SYNTAX_GAUGE32:
1140       //    case sNMP_SYNTAX_UINT32:
1141       {
1142         long templong;
1143         vars->type = (unsigned char) smival->syntax;
1144         vars->val.integer = (long *)malloc(sizeof(long));
1145         vars->val_len = sizeof(long);
1146         templong = (long) smival->value.uNumber;
1147         memcpy((long*) vars->val.integer,
1148                 (long*) &templong,
1149                 sizeof(long));
1150       }
1151       break;
1152
1153     case sNMP_SYNTAX_INT32:
1154       {
1155         long templong;
1156         vars->type = (unsigned char) smival->syntax;
1157         vars->val.integer = (long *)malloc(sizeof(long));
1158         vars->val_len = sizeof(long);
1159         templong = (long) smival->value.sNumber;
1160         memcpy((long*) vars->val.integer,
1161                 (long*) &templong,
1162                 sizeof(long));
1163       }
1164       break;
1165
1166       // 64 bit counter
1167     case sNMP_SYNTAX_CNTR64:
1168       {
1169         vars->type = (unsigned char) smival->syntax;
1170         vars->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
1171         vars->val_len = sizeof(struct counter64);
1172         memcpy((struct counter64*) vars->val.counter64,
1173                 (SmiLPCNTR64) &(smival->value.hNumber),
1174                 sizeof(SmiCNTR64));
1175       }
1176       break;
1177
1178     } // end switch
1179
1180 }
1181
1182 // build the authentication, works for v1 or v2c
1183 static unsigned char *snmp_auth_build(unsigned char *data,
1184                                       int *length,
1185                                       const long int version,
1186                                       const unsigned char *community,
1187                                       const int community_len,
1188                                       const int messagelen)
1189 {
1190   // 5 is 3 octets for version and 2 for community header + len
1191   // This assumes that community will not be longer than 0x7f chars.
1192   data = asn_build_sequence(data, length, ASN_SEQ_CON,
1193                             messagelen + community_len + 5);
1194   if (data == NULL) { 
1195     ASNERROR("buildheader");
1196     return NULL;
1197   }
1198   data = asn_build_int(data, length, ASN_UNI_PRIM | ASN_INTEGER, &version);
1199   if (data == NULL) {
1200     ASNERROR("buildint");
1201     return NULL;
1202   }
1203
1204   data = asn_build_string(data, length, ASN_UNI_PRIM | ASN_OCTET_STR,
1205                           community, community_len);
1206   if (data == NULL) {
1207     ASNERROR("buildstring");
1208     return NULL;
1209   }
1210
1211   return data;
1212 }
1213
1214
1215 // build a variable binding
1216 unsigned char * snmp_build_var_op(unsigned char *data,
1217                                   oid * var_name,
1218                                   int *var_name_len,
1219                                   unsigned char var_val_type,
1220                                   int var_val_len,
1221                                   unsigned char *var_val,
1222                                   int *listlength)
1223 {
1224   int valueLen;
1225   Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
1226   unsigned char *buffer_pos = buffer.get_ptr();
1227   int bufferLen = MAX_SNMP_PACKET;
1228
1229   buffer_pos = asn_build_objid(buffer_pos, &bufferLen,
1230                                ASN_UNI_PRIM | ASN_OBJECT_ID,
1231                                var_name, *var_name_len);
1232   if (buffer_pos == NULL) {
1233     ASNERROR("build_var_op: build_objid failed");
1234     return NULL;
1235   }
1236
1237   // based on the type...
1238   switch(var_val_type) {
1239   case ASN_INTEGER:
1240     if (var_val_len != sizeof(long))
1241     {
1242       ASNERROR("build_var_op: Illegal size of integer");
1243       return NULL;
1244     }
1245     buffer_pos = asn_build_int(buffer_pos, &bufferLen,
1246                                var_val_type, (long *)var_val);
1247     break;
1248
1249   case SMI_GAUGE:
1250   case SMI_COUNTER:
1251   case SMI_TIMETICKS:
1252   case SMI_UINTEGER:
1253     if (var_val_len != sizeof(unsigned long))
1254     {
1255       ASNERROR("build_var_op: Illegal size of unsigned integer");
1256       return NULL;
1257     }
1258     buffer_pos = asn_build_unsigned_int(buffer_pos, &bufferLen,
1259                                         var_val_type, (unsigned long *)var_val);
1260     break;
1261
1262   case SMI_COUNTER64:
1263     if (var_val_len != sizeof(counter64))
1264     {
1265       ASNERROR("build_var_op: Illegal size of counter64");
1266       return NULL;
1267     }
1268     buffer_pos = asn_build_unsigned_int64(buffer_pos, &bufferLen,
1269                                           var_val_type,
1270                                           (struct counter64 *)var_val);
1271     break;
1272
1273   case ASN_OCTET_STR:
1274   case SMI_IPADDRESS:
1275   case SMI_OPAQUE:
1276   case SMI_NSAP:
1277     buffer_pos = asn_build_string(buffer_pos, &bufferLen, var_val_type,
1278                                   var_val, var_val_len);
1279     break;
1280
1281   case ASN_OBJECT_ID:
1282     buffer_pos = asn_build_objid(buffer_pos, &bufferLen, var_val_type,
1283                                  (oid *)var_val, var_val_len / sizeof(oid));
1284     break;
1285
1286   case ASN_NULL:
1287     buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
1288     break;
1289
1290   case ASN_BIT_STR:
1291     buffer_pos = asn_build_bitstring(buffer_pos, &bufferLen, var_val_type,
1292                                      var_val, var_val_len);
1293     break;
1294
1295   case SNMP_NOSUCHOBJECT:
1296   case SNMP_NOSUCHINSTANCE:
1297   case SNMP_ENDOFMIBVIEW:
1298     buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
1299     break;
1300
1301   default:
1302     ASNERROR("build_var_op: wrong type");
1303     return NULL;
1304   }
1305   if (buffer_pos == NULL) {
1306     ASNERROR("build_var_op: value build failed");
1307     return NULL;
1308   }
1309
1310   valueLen = SAFE_INT_CAST(buffer_pos - buffer.get_ptr());
1311
1312   data = asn_build_sequence(data, listlength, ASN_SEQ_CON, valueLen);
1313
1314   if(data == NULL || *listlength < valueLen)
1315   {
1316     ASNERROR("build_var_op");
1317     data = NULL;
1318   }
1319   else
1320   {
1321     memcpy(data, buffer.get_ptr(), valueLen);
1322     data += valueLen;
1323     (*listlength)-=valueLen;
1324   }
1325   return data;
1326 }
1327
1328
1329 unsigned char *build_vb(struct snmp_pdu *pdu,
1330                         unsigned char *buf, int *buf_len)
1331 {
1332   Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
1333   unsigned char *cp = tmp_buf.get_ptr();
1334   struct   variable_list *vp;
1335   int vb_length;
1336   int length = MAX_SNMP_PACKET;
1337
1338   // build varbinds into packet buffer
1339   for(vp = pdu->variables; vp; vp = vp->next_variable)
1340   {
1341     cp = snmp_build_var_op(cp, vp->name, &vp->name_length,
1342                             vp->type, vp->val_len,
1343                             (unsigned char *)vp->val.string,
1344                             &length);
1345     if (cp == NULL) return 0;
1346   }
1347   vb_length = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
1348   *buf_len -= vb_length;
1349   if (*buf_len <= 0) return 0;
1350
1351   // encode the length of encoded varbinds into buf
1352   cp = asn_build_header(buf, buf_len, ASN_SEQ_CON, vb_length);
1353   if (cp == NULL) return 0;
1354
1355   // copy varbinds from packet behind header in buf
1356   memcpy(cp, tmp_buf.get_ptr(), vb_length);
1357
1358   return (cp + vb_length);
1359 }
1360
1361 unsigned char *build_data_pdu(struct snmp_pdu *pdu,
1362                               unsigned char *buf, int *buf_len,
1363                               unsigned char *vb_buf, int vb_buf_len)
1364 {
1365   Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
1366   unsigned char *cp = tmp_buf.get_ptr();
1367   int totallength;
1368   int length = MAX_SNMP_PACKET;
1369
1370   // build data of pdu into tmp_buf
1371   if (pdu->command != TRP_REQ_MSG)
1372   {
1373     // request id
1374     cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->reqid);
1375     if (cp == NULL) return 0;
1376
1377     // error status
1378     cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errstat);
1379     if (cp == NULL) return 0;
1380
1381     // error index
1382     cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errindex);
1383     if (cp == NULL) return 0;
1384   }
1385   else
1386   { // this is a trap message
1387     // enterprise
1388     cp = asn_build_objid(cp, &length, ASN_UNI_PRIM | ASN_OBJECT_ID,
1389                           (oid *)pdu->enterprise, pdu->enterprise_length);
1390     if (cp == NULL) return 0;
1391
1392     // agent-addr ; must be IPADDRESS changed by Frank Fock
1393     cp = asn_build_string(cp, &length, SMI_IPADDRESS,
1394                           (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
1395                           sizeof(pdu->agent_addr.sin_addr.s_addr));
1396     if (cp == NULL) return 0;
1397
1398     long dummy = pdu->trap_type;
1399     // generic trap
1400     cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
1401     if (cp == NULL) return 0;
1402
1403     dummy = pdu->specific_type;
1404     // specific trap
1405     cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
1406     if (cp == NULL) return 0;
1407
1408     // timestamp
1409     cp = asn_build_unsigned_int(cp, &length, SMI_TIMETICKS, &pdu->time);
1410     if (cp == NULL) return 0;
1411   }
1412
1413   if (length < vb_buf_len) return 0;
1414
1415   // save relative position of varbinds
1416   int vb_rel_pos = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
1417   totallength = SAFE_INT_CAST(cp - tmp_buf.get_ptr()) + vb_buf_len;
1418
1419   // build header for datapdu into buf
1420   cp = asn_build_header(buf, buf_len,
1421                         (unsigned char)pdu->command, totallength);
1422   if (cp == NULL) return 0;
1423   if (*buf_len < totallength) return 0;
1424
1425   // copy data behind header
1426   memcpy(cp, tmp_buf.get_ptr(), totallength - vb_buf_len);
1427   memcpy((char *)cp + vb_rel_pos, (char *)vb_buf, vb_buf_len);
1428   *buf_len -= totallength;
1429   return (cp + totallength);
1430 }
1431
1432 // serialize the pdu
1433 int snmp_build(struct snmp_pdu  *pdu,
1434                unsigned char *packet,          int *out_length,
1435                const long version,
1436                const unsigned char* community, const int community_len)
1437 {
1438   Buffer<unsigned char> buf(MAX_SNMP_PACKET);
1439   unsigned char  *cp;
1440   int        length;
1441   int    totallength;
1442
1443   // encode vbs with header into packet
1444   length = *out_length;
1445   cp = build_vb(pdu, packet, &length);
1446   if (cp == 0) return -1;
1447   totallength = SAFE_INT_CAST(cp - packet);
1448   if (totallength >= *out_length) return -1;
1449
1450   // encode datadpu into buf
1451   length = MAX_SNMP_PACKET;
1452   cp = build_data_pdu(pdu, buf.get_ptr(), &length,
1453                       packet, totallength);
1454   if (cp == 0) return -1;
1455   totallength = SAFE_INT_CAST(cp - buf.get_ptr());
1456   if (totallength >= *out_length) return -1;
1457
1458   // build SNMP header
1459   length = *out_length;
1460   cp = snmp_auth_build(packet, &length, version,
1461                         community, community_len, totallength);
1462   if (cp == NULL) return -1;
1463   if ((*out_length - (cp - packet)) < totallength) return -1;
1464
1465   // copy data
1466   memcpy(cp, buf.get_ptr(), totallength);
1467   totallength += SAFE_INT_CAST(cp - packet);
1468   *out_length = totallength;
1469
1470   return 0;
1471 }
1472
1473 // parse the authentication header
1474 static unsigned char *snmp_auth_parse(unsigned char *data,
1475                                       int *length,
1476                                       unsigned char *community,
1477                                       int *community_len,
1478                                       long      *version)
1479 {
1480   unsigned char type;
1481
1482   // get the type
1483   data = asn_parse_header(data, length, &type);
1484   if (data == NULL) {
1485     ASNERROR("bad header");
1486     return NULL;
1487   }
1488
1489   if (type != ASN_SEQ_CON) {
1490     ASNERROR("wrong auth header type");
1491     return NULL;
1492   }
1493
1494   // get the version
1495   data = asn_parse_int(data, length, &type, version);
1496   if (data == NULL) {
1497     ASNERROR("bad parse of version");
1498     return NULL;
1499   }
1500
1501   // get the community name
1502   data = asn_parse_string(data, length, &type, community, community_len);
1503   if (data == NULL) {
1504     ASNERROR("bad parse of community");
1505     return NULL;
1506   }
1507
1508   return (unsigned char *)data;
1509 }
1510
1511 unsigned char *
1512 snmp_parse_var_op(unsigned char *data,  // IN - pointer to the start of object
1513                    oid      *var_name,           // OUT - object id of variable
1514                    int      *var_name_len,       // IN/OUT - length of variable name
1515                    unsigned char  *var_val_type, // OUT - type of variable (int or octet string) (one byte)
1516                    int      *var_val_len,        // OUT - length of variable
1517                    unsigned char  **var_val,     // OUT - pointer to ASN1 encoded value of variable
1518                    int      *listlength)         // IN/OUT - number of valid bytes left in var_op_list
1519 {
1520   unsigned char var_op_type;
1521   int   var_op_len = *listlength;
1522   unsigned char *var_op_start = data;
1523
1524   data = asn_parse_header(data, &var_op_len, &var_op_type);
1525   if (data == NULL) {
1526     ASNERROR("Error snmp_parse_var_op: 1");
1527     return NULL;
1528   }
1529   if (var_op_type != ASN_SEQ_CON)
1530     return NULL;
1531   data = asn_parse_objid(data, &var_op_len, &var_op_type, var_name, var_name_len);
1532   if (data == NULL) {
1533     ASNERROR("Error snmp_parse_var_op: 2");
1534     return NULL;
1535   }
1536   if (var_op_type != (ASN_UNI_PRIM | ASN_OBJECT_ID))
1537     return NULL;
1538   *var_val = data;      /* save pointer to this object */
1539   /* find out what type of object this is */
1540   data = asn_parse_header(data, &var_op_len, var_val_type);
1541   if (data == NULL) {
1542     ASNERROR("Error snmp_parse_var_op: 3");
1543     return NULL;
1544   }
1545   if (((unsigned long)var_op_len + (data - var_op_start)) > (unsigned long)(*listlength)) {
1546     ASNERROR("Error snmp_parse_var_op: 4");
1547     return NULL;
1548   }
1549   *var_val_len = (int)var_op_len;
1550   data += var_op_len;
1551   *listlength -= (int)(data - var_op_start);
1552   return data;
1553 }
1554
1555
1556 int snmp_parse_vb(struct snmp_pdu *pdu, unsigned char *&data, int &data_len)
1557 {
1558   unsigned char  *var_val;
1559   int len;
1560   struct variable_list *vp = 0;
1561   oid       objid[ASN_MAX_NAME_LEN], *op;
1562   unsigned char type;
1563
1564   // get the vb list from received data
1565   data = asn_parse_header(data, &data_len, &type);
1566   if (data == NULL)
1567     return SNMP_CLASS_ASN1ERROR;
1568   if (type != ASN_SEQ_CON)
1569     return SNMP_CLASS_ASN1ERROR;
1570   pdu->variables = NULL;
1571   while(data_len > 0) {
1572     if (pdu->variables == NULL) {
1573       pdu->variables = vp = (struct variable_list *)malloc(sizeof(struct variable_list));
1574     } else {
1575       vp->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
1576       vp = vp->next_variable;
1577     }
1578     vp->next_variable = NULL;
1579     vp->val.string = NULL;
1580     vp->name = NULL;
1581     vp->name_length = ASN_MAX_NAME_LEN;
1582     data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
1583                               &vp->val_len, &var_val, &data_len);
1584     if (data == NULL)
1585       return SNMP_CLASS_ASN1ERROR;
1586     op = (oid *)malloc((unsigned)vp->name_length * sizeof(oid));
1587
1588     memcpy((char *)op, (char *)objid, vp->name_length * sizeof(oid));
1589     vp->name = op;
1590
1591     len = MAX_SNMP_PACKET;
1592     switch((short)vp->type) {
1593     case ASN_INTEGER:
1594       vp->val.integer = (long *)malloc(sizeof(long));
1595       vp->val_len = sizeof(long);
1596       asn_parse_int(var_val, &len, &vp->type, vp->val.integer);
1597       break;
1598
1599     case SMI_COUNTER:
1600     case SMI_GAUGE:
1601     case SMI_TIMETICKS:
1602     case SMI_UINTEGER:
1603       vp->val.integer = (long *)malloc(sizeof(long));
1604       vp->val_len = sizeof(long);
1605       asn_parse_unsigned_int(var_val, &len, &vp->type, vp->val.integer);
1606       break;
1607
1608     case SMI_COUNTER64:
1609       vp->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
1610       vp->val_len = sizeof(struct counter64);
1611       asn_parse_unsigned_int64(var_val, &len, &vp->type,
1612                                vp->val.counter64);
1613       break;
1614         
1615     case ASN_OCTET_STR:
1616     case SMI_IPADDRESS:
1617     case SMI_OPAQUE:
1618     case SMI_NSAP:
1619       vp->val.string = (unsigned char *)malloc((unsigned)vp->val_len);
1620       asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
1621       break;
1622
1623     case ASN_OBJECT_ID:
1624       vp->val_len = ASN_MAX_NAME_LEN;
1625       asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
1626       //vp->val_len *= sizeof(oid);
1627       vp->val.objid = (oid *)malloc((unsigned)vp->val_len * sizeof(oid));
1628
1629       memcpy((char *)vp->val.objid,
1630              (char *)objid,
1631              vp->val_len * sizeof(oid));
1632       break;
1633
1634     case SNMP_NOSUCHOBJECT:
1635     case SNMP_NOSUCHINSTANCE:
1636     case SNMP_ENDOFMIBVIEW:
1637     case ASN_NULL:
1638       break;
1639
1640     default:
1641       ASNERROR("bad type returned ");
1642       return SNMP_CLASS_ASN1ERROR;
1643     }
1644   }
1645   return SNMP_CLASS_SUCCESS;
1646 }
1647
1648
1649 int snmp_parse_data_pdu(snmp_pdu *pdu, unsigned char *&data, int &length)
1650 {
1651   oid       objid[ASN_MAX_NAME_LEN];
1652   int       four = 4;
1653   unsigned char  type;
1654
1655   data = asn_parse_header(data, &length, &type);
1656   if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1657
1658   pdu->command = type;
1659
1660   if (pdu->command != TRP_REQ_MSG)
1661   {
1662     // get the rid error status and error index
1663     data = asn_parse_int(data, &length, &type, &pdu->reqid);
1664     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1665
1666     data = asn_parse_int(data, &length, &type, &pdu->errstat);
1667     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1668
1669     data = asn_parse_int(data, &length, &type, &pdu->errindex);
1670     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1671   }
1672   else
1673   {  // is a trap
1674
1675     // get the enterprise
1676     pdu->enterprise_length = ASN_MAX_NAME_LEN;
1677     data = asn_parse_objid(data, &length, &type,
1678                            objid, &pdu->enterprise_length);
1679     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1680
1681     pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
1682
1683     memcpy((char *)pdu->enterprise,(char *)objid,
1684            pdu->enterprise_length * sizeof(oid));
1685
1686     // get source address
1687     data = asn_parse_string(data, &length, &type,
1688                             (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
1689                             &four);
1690     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1691
1692     // get trap type
1693     long dummy = 0;
1694     data = asn_parse_int(data, &length, &type, &dummy);
1695     pdu->trap_type = dummy;
1696
1697     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1698
1699     // trap specific type
1700     dummy = 0;
1701     data = asn_parse_int(data, &length, &type, &dummy);
1702     pdu->specific_type = dummy;
1703     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1704
1705     // timestamp
1706     data = asn_parse_unsigned_int(data, &length, &type, &pdu->time);
1707     if (data == NULL) return SNMP_CLASS_ASN1ERROR;
1708   }
1709   return SNMP_CLASS_SUCCESS;
1710 }
1711
1712
1713 // parse a pdu
1714 int snmp_parse(struct snmp_pdu *pdu,
1715                 unsigned char *data, int data_length,
1716                 unsigned char *community_name,
1717                 int &community_len,
1718                 snmp_version &spp_version)
1719 {
1720   long    version = -1;
1721
1722   // authenticates message and returns length if valid
1723   data = snmp_auth_parse(data, &data_length,
1724                          community_name, &community_len,
1725                          &version);
1726   if (data == NULL)
1727     return SNMP_CLASS_ASN1ERROR;
1728
1729   if(version != SNMP_VERSION_1 && version != SNMP_VERSION_2C) {
1730     ASNERROR("Wrong version");
1731     return SNMP_CLASS_BADVERSION;
1732   }
1733
1734   spp_version = (snmp_version) version;
1735
1736   int res = snmp_parse_data_pdu(pdu, data, data_length);
1737   if (res != SNMP_CLASS_SUCCESS)
1738     return res;
1739
1740   return snmp_parse_vb(pdu, data, data_length);
1741 }
1742
1743
1744 #ifdef _SNMPv3
1745 // Parse the field HeaderData of a SNMPv3 message and return the values.
1746 unsigned char *asn1_parse_header_data(unsigned char *buf, int *buf_len,
1747                                       long *msg_id, long *msg_max_size,
1748                                       unsigned char *msg_flags,
1749                                       long *msg_security_model)
1750 {
1751   unsigned char *buf_ptr = buf;
1752   int length = *buf_len;
1753   unsigned char type;
1754
1755   buf = asn_parse_header(buf, &length, &type);
1756   if (!buf)
1757   {
1758     debugprintf(0, "Parse error in header HeaderData");
1759     return 0;
1760   }
1761
1762   if (type != ASN_SEQ_CON) {
1763     debugprintf(0, "wrong type in header of msgHeaderData");
1764     return 0;
1765   }
1766
1767   buf = asn_parse_int(buf, &length, &type, msg_id);
1768   if (!buf) {
1769     debugprintf(0, "Parse error: msg_id");
1770     return 0;
1771   }
1772
1773   buf = asn_parse_int(buf, &length, &type, msg_max_size);
1774   if (!buf) {
1775     debugprintf(0, "Parse error: msg_max_size");
1776     return 0;
1777   }
1778
1779   int dummy = 1;
1780   buf = asn_parse_string(buf, &length, &type, msg_flags, &dummy);
1781
1782   if ((dummy !=1) || (!buf)) {
1783     debugprintf(0, "Parse error: msg_flags");
1784     return 0;
1785   }
1786
1787   buf = asn_parse_int(buf, &length, &type, msg_security_model);
1788   if (!buf) {
1789     debugprintf(0, "Parse error: msg_security_model");
1790     return 0;
1791   }
1792
1793   if (length) {
1794     debugprintf(0, "Parse error: wrong length in header of HeaderData");
1795     return 0;
1796   }
1797
1798   debugprintf(3, "Parsed HeaderData: globalDataLength(0x%x), msg_id(%ld), "
1799              "msg_max_size(0x%lx), msg_flags(0x%x), msg_security_model(0x%lx)",
1800               length, *msg_id, *msg_max_size, *msg_flags, *msg_security_model);
1801
1802   *buf_len -= SAFE_INT_CAST(buf - buf_ptr);
1803   return buf;
1804 }
1805
1806 // Encode the given values for the HeaderData into the buffer.
1807 unsigned char *asn1_build_header_data(unsigned char *outBuf, int *maxLength,
1808                                        long msgID,
1809                                        long maxMessageSize,
1810                                        unsigned char msgFlags,
1811                                        long securityModel)
1812
1813 {
1814   unsigned char buf[MAXLENGTH_GLOBALDATA];
1815   unsigned char *bufPtr = (unsigned char*)&buf;
1816   unsigned char *outBufPtr = outBuf;
1817   int length = *maxLength;
1818   int totalLength;
1819
1820 #ifdef INVALID_MAXMSGSIZE
1821   debugprintf(-10, "\nWARNING: Using constant MaxMessageSize!\n");
1822   maxMessageSize = 65535;
1823 #endif
1824
1825   debugprintf(3, "Coding msgID(%ld), maxMessageSize(0x%lx), "
1826               "msgFlags(0x%x), securityModel(0x%lx)",
1827               msgID, maxMessageSize, msgFlags, securityModel);
1828
1829   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER, &msgID);
1830   if (bufPtr == NULL) {
1831     debugprintf(0, "asn_build_header_data: Error coding msgID");
1832     return NULL;
1833   }
1834   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
1835                          &maxMessageSize);
1836   if (bufPtr == NULL) {
1837     debugprintf(0, "asn_build_header_data: Error coding maxMessageSize");
1838     return NULL;
1839   }
1840
1841   bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
1842                             &msgFlags, 1);
1843   if (bufPtr == NULL) {
1844     debugprintf(0, "asn_build_header_data: Error coding msgFlags");
1845     return NULL;
1846   }
1847
1848   bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
1849                          &securityModel);
1850   if (bufPtr == NULL) {
1851     debugprintf(0, "asn_build_header_data: Error coding securityModel");
1852     return NULL;
1853   }
1854
1855   totalLength = SAFE_INT_CAST(bufPtr - (unsigned char*)&buf);
1856
1857   debugprintf(3, "Coding sequence (headerdata), length = 0x%x", totalLength);
1858   outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
1859                                  totalLength);
1860
1861   if (outBufPtr == NULL) {
1862     debugprintf(0, "asn_build_header_data: Error coding seq headerdata");
1863     return NULL;
1864   }
1865
1866   if (*maxLength < totalLength) {
1867     debugprintf(0, "asn_build_header_data: Length error");
1868     return NULL;
1869   }
1870
1871   memcpy(outBufPtr, (unsigned char*)&buf, totalLength);
1872   outBufPtr += totalLength;
1873   *maxLength -= totalLength;
1874
1875   debugprintf(21, "bufHeaderData:");
1876   debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
1877
1878   return outBufPtr;
1879 }
1880 #endif
1881
1882 // Parse the ScopedPDU and return the encoded values.
1883 unsigned char *asn1_parse_scoped_pdu(
1884          unsigned char *scoped_pdu, int *scoped_pdu_len,
1885          unsigned char *context_engine_id, int *context_engine_id_len,
1886          unsigned char *context_name, int *context_name_len)
1887 {
1888   unsigned char type;
1889
1890   scoped_pdu = asn_parse_header(scoped_pdu, scoped_pdu_len, &type);
1891   if (!scoped_pdu) {
1892     debugprintf(0, "Parse error: Wrong header in scoped_pdu.");
1893     return 0;
1894   }
1895
1896   if (type != ASN_SEQ_CON) {
1897     debugprintf(0, "Parse error: Wrong header type in scoped_pdu.");
1898     return 0;
1899   }
1900
1901   scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
1902                                 context_engine_id, context_engine_id_len);
1903   if (!scoped_pdu) {
1904     debugprintf(0, "Parse error: context_engine_id");
1905     return 0;
1906   }
1907
1908   scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
1909                                 context_name, context_name_len);
1910   if (!scoped_pdu) {
1911     debugprintf(0, "mpParseScopedPDU: bad parse of context_name");
1912     return 0;
1913   }
1914
1915   debugprintf(3, "Parsed scoped_pdu: context_engine_id length(0x%x), "
1916               "context_name length(0x%x)",
1917               *context_engine_id_len, *context_name_len);
1918
1919   return scoped_pdu;
1920 }
1921
1922 // Encode the given values for the scopedPDU into the buffer.
1923 unsigned char *asn1_build_scoped_pdu(
1924                    unsigned char *outBuf, int *max_len,
1925                    unsigned char *contextEngineID, long contextEngineIDLength,
1926                    unsigned char *contextName, long contextNameLength,
1927                    unsigned char *data, long dataLength)
1928 {
1929   Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
1930   unsigned char *bufPtr = buffer.get_ptr();
1931   unsigned char *outBufPtr = outBuf;
1932
1933   LOG_BEGIN(DEBUG_LOG | 10);
1934   LOG("ASN1: coding (context engine id) (context name)");
1935   LOG(OctetStr(contextEngineID, contextEngineIDLength).get_printable());
1936   LOG(OctetStr(contextName, contextNameLength).get_printable());
1937   LOG_END;
1938
1939   bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
1940                             contextEngineID, contextEngineIDLength);
1941   if (!bufPtr)
1942   {
1943     LOG_BEGIN(ERROR_LOG | 1);
1944     LOG("ASN1: Error encoding contextEngineID");
1945     LOG_END;
1946
1947     return 0;
1948   }
1949
1950   bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
1951                             contextName, contextNameLength);
1952   if (!bufPtr)
1953   {
1954     LOG_BEGIN(ERROR_LOG | 1);
1955     LOG("ASN1: Error encoding contextName");
1956     LOG_END;
1957
1958     return 0;
1959   }
1960
1961   long bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
1962
1963   memcpy((char *)bufPtr, (char *)data, dataLength);
1964   bufLength += dataLength;
1965
1966   LOG_BEGIN(DEBUG_LOG | 10);
1967   LOG("ASN1: Encoding scoped PDU sequence (len)");
1968   LOG(bufLength);
1969   LOG_END;
1970
1971   outBufPtr = asn_build_sequence(outBufPtr, max_len, ASN_SEQ_CON, bufLength);
1972   if (!outBufPtr)
1973   {
1974     LOG_BEGIN(ERROR_LOG | 1);
1975     LOG("ASN1: Error encoding scopedPDU sequence");
1976     LOG_END;
1977
1978     return 0;
1979   }
1980
1981   memcpy(outBufPtr, buffer.get_ptr(), bufLength);
1982   outBufPtr += bufLength;
1983
1984 #ifdef __DEBUG
1985   LOG_BEGIN(DEBUG_LOG | 15);
1986   LOG("ASN1: Result of build_scoped_pdu (len) (data)");
1987   LOG(outBufPtr - outBuf);
1988   LOG(OctetStr(outBuf, outBufPtr - outBuf).get_printable_hex());
1989   LOG_END;
1990 #endif
1991
1992   return outBufPtr;
1993 }
1994
1995 #ifdef SNMP_PP_NAMESPACE
1996 }; // end of namespace Snmp_pp
1997 #endif