Revert "Revert "and added files""
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / tools.c
1 /*
2  * tools.c
3  */
4
5 #include <net-snmp/net-snmp-config.h>
6
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <sys/types.h>
10 #if TIME_WITH_SYS_TIME
11 # ifdef WIN32
12 #  include <sys/timeb.h>
13 # else
14 #  include <sys/time.h>
15 # endif
16 # include <time.h>
17 #else
18 # if HAVE_SYS_TIME_H
19 #  include <sys/time.h>
20 # else
21 #  include <time.h>
22 # endif
23 #endif
24 #ifdef HAVE_SYS_SOCKET_H
25 #include <sys/socket.h>
26 #endif
27 #if HAVE_WINSOCK_H
28 #include <winsock.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #if HAVE_STRING_H
34 #include <string.h>
35 #else
36 #include <strings.h>
37 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif
44
45 #if HAVE_DMALLOC_H
46 #include <dmalloc.h>
47 #endif
48
49 #include <net-snmp/types.h>
50 #include <net-snmp/output_api.h>
51 #include <net-snmp/utilities.h>
52 #include <net-snmp/library/tools.h>     /* for "internal" definitions */
53
54 #include <net-snmp/library/snmp_api.h>
55 #include <net-snmp/library/mib.h>
56 #include <net-snmp/library/scapi.h>
57
58
59 /*
60  * snmp_realloc:
61  * 
62  * Parameters:
63  * 
64  * buf  pointer to a buffer pointer
65  * buf_len      pointer to current size of buffer in bytes
66  * 
67  * This function increase the size of the buffer pointed at by *buf, which is
68  * initially of size *buf_len.  Contents are preserved **AT THE BOTTOM END OF
69  * THE BUFFER**.  If memory can be (re-)allocated then it returns 1, else it
70  * returns 0.
71  * 
72  */
73
74 int
75 snmp_realloc(u_char ** buf, size_t * buf_len)
76 {
77     u_char         *new_buf = NULL;
78     size_t          new_buf_len = 0;
79
80     if (buf == NULL) {
81         return 0;
82     }
83
84     /*
85      * The current re-allocation algorithm is to increase the buffer size by
86      * whichever is the greater of 256 bytes or the current buffer size, up to
87      * a maximum increase of 8192 bytes.  
88      */
89
90     if (*buf_len <= 255) {
91         new_buf_len = *buf_len + 256;
92     } else if (*buf_len > 255 && *buf_len <= 8191) {
93         new_buf_len = *buf_len * 2;
94     } else if (*buf_len > 8191) {
95         new_buf_len = *buf_len + 8192;
96     }
97
98     if (*buf == NULL) {
99         new_buf = (u_char *) malloc(new_buf_len);
100     } else {
101         new_buf = (u_char *) realloc(*buf, new_buf_len);
102     }
103
104     if (new_buf != NULL) {
105         *buf = new_buf;
106         *buf_len = new_buf_len;
107         return 1;
108     } else {
109         return 0;
110     }
111 }
112
113 int
114 snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
115             int allow_realloc, const u_char * s)
116 {
117     if (buf == NULL || buf_len == NULL || out_len == NULL) {
118         return 0;
119     }
120
121     if (s == NULL) {
122         /*
123          * Appending a NULL string always succeeds since it is a NOP.  
124          */
125         return 1;
126     }
127
128     while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
129         if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
130             return 0;
131         }
132     }
133
134     strcpy((char *) (*buf + *out_len), (const char *) s);
135     *out_len += strlen((char *) (*buf + *out_len));
136     return 1;
137 }
138
139 /*******************************************************************-o-******
140  * free_zero
141  *
142  * Parameters:
143  *      *buf    Pointer at bytes to free.
144  *      size    Number of bytes in buf.
145  */
146 void
147 free_zero(void *buf, size_t size)
148 {
149     if (buf) {
150         memset(buf, 0, size);
151         free(buf);
152     }
153
154 }                               /* end free_zero() */
155
156
157
158 #if BRCM_SNMP_NOT_USED
159 /*******************************************************************-o-******
160  * malloc_random
161  *
162  * Parameters:
163  *      size    Number of bytes to malloc() and fill with random bytes.
164  *      
165  * Returns pointer to allocaed & set buffer on success, size contains
166  * number of random bytes filled.
167  *
168  * buf is NULL and *size set to KMT error value upon failure.
169  *
170  */
171 u_char         *
172 malloc_random(size_t * size)
173 {
174     int             rval = SNMPERR_SUCCESS;
175     u_char         *buf = (u_char *) calloc(1, *size);
176
177     if (buf) {
178         rval = sc_random(buf, size);
179
180         if (rval < 0) {
181             free_zero(buf, *size);
182             buf = NULL;
183         } else {
184             *size = rval;
185         }
186     }
187
188     return buf;
189
190 }                               /* end malloc_random() */
191
192 #endif /* BRCM_SNMP_NOT_USED */
193
194
195 /*******************************************************************-o-******
196  * memdup
197  *
198  * Parameters:
199  *      to       Pointer to allocate and copy memory to.
200  *      from     Pointer to copy memory from.
201  *      size     Size of the data to be copied.
202  *      
203  * Returns
204  *      SNMPERR_SUCCESS On success.
205  *      SNMPERR_GENERR  On failure.
206  */
207 int
208 memdup(u_char ** to, const u_char * from, size_t size)
209 {
210     if (to == NULL)
211         return SNMPERR_GENERR;
212     if (from == NULL) {
213         *to = NULL;
214         return SNMPERR_SUCCESS;
215     }
216     if ((*to = (u_char *) malloc(size)) == NULL)
217         return SNMPERR_GENERR;
218     memcpy(*to, from, size);
219     return SNMPERR_SUCCESS;
220
221 }                               /* end memdup() */
222
223 /** copies a (possible) unterminated string of a given length into a
224  *  new buffer and null terminates it as well (new buffer MAY be one
225  *  byte longer to account for this */
226 char           *
227 netsnmp_strdup_and_null(const u_char * from, size_t from_len)
228 {
229     u_char         *ret;
230
231     if (from_len == 0 || from[from_len - 1] != '\0') {
232         ret = malloc(from_len + 1);
233         if (!ret)
234             return NULL;
235         ret[from_len] = '\0';
236     } else {
237         ret = malloc(from_len);
238         if (!ret)
239             return NULL;
240         ret[from_len - 1] = '\0';
241     }
242     memcpy(ret, from, from_len);
243     return ret;
244 }
245
246 /*******************************************************************-o-******
247  * binary_to_hex
248  *
249  * Parameters:
250  *      *input          Binary data.
251  *      len             Length of binary data.
252  *      **output        NULL terminated string equivalent in hex.
253  *      
254  * Returns:
255  *      olen    Length of output string not including NULL terminator.
256  *
257  * FIX  Is there already one of these in the UCD SNMP codebase?
258  *      The old one should be used, or this one should be moved to
259  *      snmplib/snmp_api.c.
260  */
261 u_int
262 binary_to_hex(const u_char * input, size_t len, char **output)
263 {
264     u_int           olen = (len * 2) + 1;
265     char           *s = (char *) calloc(1, olen), *op = s;
266     const u_char   *ip = input;
267
268
269     while (ip - input < (int) len) {
270         *op++ = VAL2HEX((*ip >> 4) & 0xf);
271         *op++ = VAL2HEX(*ip & 0xf);
272         ip++;
273     }
274     *op = '\0';
275
276     *output = s;
277     return olen;
278
279 }                               /* end binary_to_hex() */
280
281
282
283
284 /*******************************************************************-o-******
285  * hex_to_binary2
286  *
287  * Parameters:
288  *      *input          Printable data in base16.
289  *      len             Length in bytes of data.
290  *      **output        Binary data equivalent to input.
291  *      
292  * Returns:
293  *      SNMPERR_GENERR  Failure.
294  *      <len>           Otherwise, Length of allocated string.
295  *
296  *
297  * Input of an odd length is right aligned.
298  *
299  * FIX  Another version of "hex-to-binary" which takes odd length input
300  *      strings.  It also allocates the memory to hold the binary data.
301  *      Should be integrated with the official hex_to_binary() function.
302  */
303 int
304 hex_to_binary2(const u_char * input, size_t len, char **output)
305 {
306     u_int           olen = (len / 2) + (len % 2);
307     char           *s = (char *) calloc(1, (olen) ? olen : 1), *op = s;
308     const u_char   *ip = input;
309
310
311     *output = NULL;
312     *op = 0;
313     if (len % 2) {
314         if (!isxdigit(*ip))
315             goto hex_to_binary2_quit;
316         *op++ = HEX2VAL(*ip);
317         ip++;
318     }
319
320     while (ip - input < (int) len) {
321         if (!isxdigit(*ip))
322             goto hex_to_binary2_quit;
323         *op = HEX2VAL(*ip) << 4;
324         ip++;
325
326         if (!isxdigit(*ip))
327             goto hex_to_binary2_quit;
328         *op++ += HEX2VAL(*ip);
329         ip++;
330     }
331
332     *output = s;
333     return olen;
334
335   hex_to_binary2_quit:
336     free_zero(s, olen);
337     return -1;
338
339 }                               /* end hex_to_binary2() */
340
341 int
342 snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
343                        int allow_realloc, const char *decimal)
344 {
345     int             subid = 0;
346     const char     *cp = decimal;
347
348     if (buf == NULL || buf_len == NULL || out_len == NULL
349         || decimal == NULL) {
350         return 0;
351     }
352
353     while (*cp != '\0') {
354         if (isspace((int) *cp) || *cp == '.') {
355             cp++;
356             continue;
357         }
358         if (!isdigit((int) *cp)) {
359             return 0;
360         }
361         if ((subid = atoi(cp)) > 255) {
362             return 0;
363         }
364         if ((*out_len >= *buf_len) &&
365             !(allow_realloc && snmp_realloc(buf, buf_len))) {
366             return 0;
367         }
368         *(*buf + *out_len) = (u_char) subid;
369         (*out_len)++;
370         while (isdigit((int) *cp)) {
371             cp++;
372         }
373     }
374     return 1;
375 }
376
377 int
378 snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
379                    int allow_realloc, const char *hex)
380 {
381     int             subid = 0;
382     const char     *cp = hex;
383
384     if (buf == NULL || buf_len == NULL || out_len == NULL || hex == NULL) {
385         return 0;
386     }
387
388     if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
389         cp += 2;
390     }
391
392     while (*cp != '\0') {
393         if (isspace((int) *cp)) {
394             cp++;
395             continue;
396         }
397         if (!isxdigit((int) *cp)) {
398             return 0;
399         }
400         if (sscanf(cp, "%2x", &subid) == 0) {
401             return 0;
402         }
403         if ((*out_len >= *buf_len) &&
404             !(allow_realloc && snmp_realloc(buf, buf_len))) {
405             return 0;
406         }
407         *(*buf + *out_len) = (u_char) subid;
408         (*out_len)++;
409         if (*++cp == '\0') {
410             /*
411              * Odd number of hex digits is an error.  
412              */
413             return 0;
414         } else {
415             cp++;
416         }
417     }
418     return 1;
419 }
420
421 /*******************************************************************-o-******
422  * dump_chunk
423  *
424  * Parameters:
425  *      *title  (May be NULL.)
426  *      *buf
427  *       size
428  */
429 void
430 dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
431            int size)
432 {
433     u_int           printunit = 64;     /* XXX  Make global. */
434     char            chunk[SNMP_MAXBUF], *s, *sp;
435
436     if (title && (*title != '\0')) {
437         DEBUGMSGTL((debugtoken, "%s\n", title));
438     }
439
440
441     memset(chunk, 0, SNMP_MAXBUF);
442     size = binary_to_hex(buf, size, &s);
443     sp = s;
444
445     while (size > 0) {
446         if (size > (int) printunit) {
447             strncpy(chunk, sp, printunit);
448             chunk[printunit] = '\0';
449             DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
450         } else {
451             DEBUGMSGTL((debugtoken, "\t%s\n", sp));
452         }
453
454         sp += printunit;
455         size -= printunit;
456     }
457
458
459     SNMP_FREE(s);
460
461 }                               /* end dump_chunk() */
462
463
464
465
466 /*******************************************************************-o-******
467  * dump_snmpEngineID
468  *
469  * Parameters:
470  *      *estring
471  *      *estring_len
472  *      
473  * Returns:
474  *      Allocated memory pointing to a string of buflen char representing
475  *      a printf'able form of the snmpEngineID.
476  *
477  *      -OR- NULL on error.
478  *
479  *
480  * Translates the snmpEngineID TC into a printable string.  From RFC 2271,
481  * Section 5 (pp. 36-37):
482  *
483  * First bit:   0       Bit string structured by means non-SNMPv3.
484  *              1       Structure described by SNMPv3 SnmpEngineID TC.
485  *  
486  * Bytes 1-4:           Enterprise ID.  (High bit of first byte is ignored.)
487  *  
488  * Byte 5:      0       (RESERVED by IANA.)
489  *              1       IPv4 address.           (   4 octets)
490  *              2       IPv6 address.           (  16 octets)
491  *              3       MAC address.            (   6 octets)
492  *              4       Locally defined text.   (0-27 octets)
493  *              5       Locally defined octets. (0-27 octets)
494  *              6-127   (RESERVED for enterprise.)
495  *  
496  * Bytes 6-32:          (Determined by byte 5.)
497  *  
498  *
499  * Non-printable characters are given in hex.  Text is given in quotes.
500  * IP and MAC addresses are given in standard (UN*X) conventions.  Sections
501  * are comma separated.
502  *
503  * esp, remaining_len and s trace the state of the constructed buffer.
504  * s will be defined if there is something to return, and it will point
505  * to the end of the constructed buffer.
506  *
507  *
508  * ASSUME  "Text" means printable characters.
509  *
510  * XXX  Must the snmpEngineID always have a minimum length of 12?
511  *      (Cf. part 2 of the TC definition.)
512  * XXX  Does not enforce upper-bound of 32 bytes.
513  * XXX  Need a switch to decide whether to use DNS name instead of a simple
514  *      IP address.
515  *
516  * FIX  Use something other than sprint_hexstring which doesn't add 
517  *      trailing spaces and (sometimes embedded) newlines...
518  */
519 #ifdef SNMP_TESTING_CODE
520 char           *
521 dump_snmpEngineID(const u_char * estring, size_t * estring_len)
522 {
523 #define eb(b)   ( *(esp+b) & 0xff )
524
525     int             rval = SNMPERR_SUCCESS, gotviolation = 0, slen = 0;
526     u_int           remaining_len;
527
528     char            buf[SNMP_MAXBUF], *s = NULL, *t;
529     const u_char   *esp = estring;
530
531     struct in_addr  iaddr;
532
533
534
535     /*
536      * Sanity check.
537      */
538     if (!estring || (*estring_len <= 0)) {
539         QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
540     }
541     remaining_len = *estring_len;
542     memset(buf, 0, SNMP_MAXBUF);
543
544
545
546     /*
547      * Test first bit.  Return immediately with a hex string, or
548      * begin by formatting the enterprise ID.
549      */
550     if (!(*esp & 0x80)) {
551         sprint_hexstring(buf, esp, remaining_len);
552         s = strchr(buf, '\0');
553         s -= 1;
554         goto dump_snmpEngineID_quit;
555     }
556
557     s = buf;
558     s += sprintf(s, "enterprise %d, ", ((*(esp + 0) & 0x7f) << 24) |
559                  ((*(esp + 1) & 0xff) << 16) |
560                  ((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
561     /*
562      * XXX  Ick. 
563      */
564
565     if (remaining_len < 5) {    /* XXX  Violating string. */
566         goto dump_snmpEngineID_quit;
567     }
568
569     esp += 4;                   /* Incremented one more in the switch below. */
570     remaining_len -= 5;
571
572
573
574     /*
575      * Act on the fifth byte.
576      */
577     switch ((int) *esp++) {
578     case 1:                    /* IPv4 address. */
579
580         if (remaining_len < 4)
581             goto dump_snmpEngineID_violation;
582         memcpy(&iaddr.s_addr, esp, 4);
583
584         if (!(t = inet_ntoa(iaddr)))
585             goto dump_snmpEngineID_violation;
586         s += sprintf(s, "%s", t);
587
588         esp += 4;
589         remaining_len -= 4;
590         break;
591
592     case 2:                    /* IPv6 address. */
593
594         if (remaining_len < 16)
595             goto dump_snmpEngineID_violation;
596
597         s += sprintf(s,
598                      "%02X%02X %02X%02X %02X%02X %02X%02X::"
599                      "%02X%02X %02X%02X %02X%02X %02X%02X",
600                      eb(0), eb(1), eb(2), eb(3),
601                      eb(4), eb(5), eb(6), eb(7),
602                      eb(8), eb(9), eb(10), eb(11),
603                      eb(12), eb(13), eb(14), eb(15));
604
605         esp += 16;
606         remaining_len -= 16;
607         break;
608
609     case 3:                    /* MAC address. */
610
611         if (remaining_len < 6)
612             goto dump_snmpEngineID_violation;
613
614         s += sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X",
615                      eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
616
617         esp += 6;
618         remaining_len -= 6;
619         break;
620
621     case 4:                    /* Text. */
622
623         /*
624          * Doesn't exist on all (many) architectures 
625          */
626         /*
627          * s += snprintf(s, remaining_len+3, "\"%s\"", esp); 
628          */
629         s += sprintf(s, "\"%s\"", esp);
630         goto dump_snmpEngineID_quit;
631         break;
632      /*NOTREACHED*/ case 5:    /* Octets. */
633
634         sprint_hexstring(s, esp, remaining_len);
635         s = strchr(buf, '\0');
636         s -= 1;
637         goto dump_snmpEngineID_quit;
638         break;
639        /*NOTREACHED*/ dump_snmpEngineID_violation:
640     case 0:                    /* Violation of RESERVED, 
641                                  * *   -OR- of expected length.
642                                  */
643         gotviolation = 1;
644         s += sprintf(s, "!!! ");
645
646     default:                   /* Unknown encoding. */
647
648         if (!gotviolation) {
649             s += sprintf(s, "??? ");
650         }
651         sprint_hexstring(s, esp, remaining_len);
652         s = strchr(buf, '\0');
653         s -= 1;
654
655         goto dump_snmpEngineID_quit;
656
657     }                           /* endswitch */
658
659
660
661     /*
662      * Cases 1-3 (IP and MAC addresses) should not have trailing
663      * octets, but perhaps they do.  Throw them in too.  XXX
664      */
665     if (remaining_len > 0) {
666         s += sprintf(s, " (??? ");
667
668         sprint_hexstring(s, esp, remaining_len);
669         s = strchr(buf, '\0');
670         s -= 1;
671
672         s += sprintf(s, ")");
673     }
674
675
676
677   dump_snmpEngineID_quit:
678     if (s) {
679         slen = s - buf + 1;
680         s = calloc(1, slen);
681         memcpy(s, buf, (slen) - 1);
682     }
683
684     memset(buf, 0, SNMP_MAXBUF);        /* XXX -- Overkill? XXX: Yes! */
685
686     return s;
687
688 #undef eb
689 }                               /* end dump_snmpEngineID() */
690 #endif                          /* SNMP_TESTING_CODE */
691
692
693 /*
694  * create a new time marker.
695  * NOTE: Caller must free time marker when no longer needed.
696  */
697 marker_t
698 atime_newMarker(void)
699 {
700     marker_t        pm = (marker_t) calloc(1, sizeof(struct timeval));
701     gettimeofday((struct timeval *) pm, 0);
702     return pm;
703 }
704
705 /*
706  * set a time marker.
707  */
708 void
709 atime_setMarker(marker_t pm)
710 {
711     if (!pm)
712         return;
713
714     gettimeofday((struct timeval *) pm, 0);
715 }
716
717
718 /*
719  * Returns the difference (in msec) between the two markers
720  */
721 long
722 atime_diff(marker_t first, marker_t second)
723 {
724     struct timeval *tv1, *tv2, diff;
725
726     tv1 = (struct timeval *) first;
727     tv2 = (struct timeval *) second;
728
729     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
730     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
731
732     return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
733 }
734
735 /*
736  * Returns the difference (in u_long msec) between the two markers
737  */
738 u_long
739 uatime_diff(marker_t first, marker_t second)
740 {
741     struct timeval *tv1, *tv2, diff;
742
743     tv1 = (struct timeval *) first;
744     tv2 = (struct timeval *) second;
745
746     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
747     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
748
749     return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
750 }
751
752 /*
753  * Returns the difference (in u_long 1/100th secs) between the two markers
754  * (functionally this is what sysUpTime needs)
755  */
756 u_long
757 uatime_hdiff(marker_t first, marker_t second)
758 {
759     struct timeval *tv1, *tv2, diff;
760     u_long          res;
761
762     tv1 = (struct timeval *) first;
763     tv2 = (struct timeval *) second;
764
765     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
766     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
767
768     res = ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
769     return res;
770 }
771
772 /*
773  * Test: Has (marked time plus delta) exceeded current time (in msec) ?
774  * Returns 0 if test fails or cannot be tested (no marker).
775  */
776 int
777 atime_ready(marker_t pm, int deltaT)
778 {
779     marker_t        now;
780     long            diff;
781     if (!pm)
782         return 0;
783
784     now = atime_newMarker();
785
786     diff = atime_diff(pm, now);
787     free(now);
788     if (diff < deltaT)
789         return 0;
790
791     return 1;
792 }
793
794 /*
795  * Test: Has (marked time plus delta) exceeded current time (in msec) ?
796  * Returns 0 if test fails or cannot be tested (no marker).
797  */
798 int
799 uatime_ready(marker_t pm, unsigned int deltaT)
800 {
801     marker_t        now;
802     u_long          diff;
803     if (!pm)
804         return 0;
805
806     now = atime_newMarker();
807
808     diff = uatime_diff(pm, now);
809     free(now);
810     if (diff < deltaT)
811         return 0;
812
813     return 1;
814 }
815
816
817         /*
818          * Time-related utility functions
819          */
820
821                 /*
822                  * Return the number of timeTicks since the given marker 
823                  */
824 int
825 marker_tticks(marker_t pm)
826 {
827     int             res;
828     marker_t        now = atime_newMarker();
829
830     res = atime_diff(pm, now);
831     free(now);
832     return res / 10;            /* atime_diff works in msec, not csec */
833 }
834
835 int
836 timeval_tticks(struct timeval *tv)
837 {
838     return marker_tticks((marker_t) tv);
839 }