]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/snmp/lib/v2_0/src/tools.c
Merge branch 'master' of git+ssh://git.kernelconcepts.de/karo-tx-redboot
[karo-tx-redboot.git] / packages / net / snmp / lib / v2_0 / src / tools.c
1 //==========================================================================
2 //
3 //      ./lib/current/src/tools.c
4 //
5 //
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
40 //
41 // -------------------------------------------
42 //
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation.  Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
48 //
49 // The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50 // -------------------------------------------
51 //
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
55 //
56 // Author(s):    hmt
57 // Contributors: hmt
58 // Date:         2000-05-30
59 // Purpose:      Port of UCD-SNMP distribution to eCos.
60 // Description:  
61 //              
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66 /********************************************************************
67        Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
69                           Derivative Work -
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
72                          All Rights Reserved
73
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
81 permission.
82
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /*
93  * tools.c
94  */
95
96 #include <config.h>
97
98 #include <ctype.h>
99 #include <stdio.h>
100 #include <sys/types.h>
101 #if TIME_WITH_SYS_TIME
102 # ifdef WIN32
103 #  include <sys/timeb.h>
104 # else
105 #  include <sys/time.h>
106 # endif
107 # include <time.h>
108 #else
109 # if HAVE_SYS_TIME_H
110 #  include <sys/time.h> 
111 # else
112 #  include <time.h>
113 # endif
114 #endif
115 #ifdef HAVE_SYS_SOCKET_H
116 #include <sys/socket.h>
117 #endif
118 #if HAVE_WINSOCK_H
119 #include <winsock.h>
120 #endif
121 #ifdef HAVE_STDLIB_H
122 #include <stdlib.h>
123 #endif
124 #if HAVE_STRING_H
125 #include <string.h>
126 #else
127 #include <strings.h>
128 #endif
129 #ifdef HAVE_NETINET_IN_H
130 #include <netinet/in.h>
131 #endif
132 #ifdef HAVE_ARPA_INET_H
133 #include <arpa/inet.h>
134 #endif
135
136 #if HAVE_DMALLOC_H
137 #include <dmalloc.h>
138 #endif
139
140 #include "asn1.h" 
141 #include "system.h"
142 #include "snmp_api.h"
143 #include "snmp_debug.h"
144 #include "snmp_debug.h"
145 #include "tools.h"
146 #include "mib.h"
147 #include "scapi.h" 
148
149
150 /*******************************************************************-o-******
151  * free_zero
152  *
153  * Parameters:
154  *      *buf    Pointer at bytes to free.
155  *      size    Number of bytes in buf.
156  */
157 void
158 free_zero(void *buf, size_t size)
159 {
160         if (buf) {
161                 memset(buf, 0, size);
162                 free(buf);
163         }
164
165 }  /* end free_zero() */
166
167
168
169
170 /*******************************************************************-o-******
171  * malloc_random
172  *
173  * Parameters:
174  *      size    Number of bytes to malloc() and fill with random bytes.
175  *      
176  * Returns pointer to allocaed & set buffer on success, size contains
177  * number of random bytes filled.
178  *
179  * buf is NULL and *size set to KMT error value upon failure.
180  *
181  */
182 u_char *
183 malloc_random(size_t *size)
184 {
185         int      rval   = SNMPERR_SUCCESS;
186         u_char  *buf    = (u_char *)calloc (1, *size);
187
188         if (buf) {
189                 rval = sc_random(buf, size);
190
191                 if (rval < 0) {
192                         free_zero(buf, *size);
193                         buf = NULL;
194                 } else {
195                         *size = rval;
196                 }
197         }
198
199         return buf;
200
201 }  /* end malloc_random() */
202
203
204
205
206 /*******************************************************************-o-******
207  * memdup
208  *
209  * Parameters:
210  *      to       Pointer to allocate and copy memory to.
211  *      from     Pointer to copy memory from.
212  *      size     Size of the data to be copied.
213  *      
214  * Returns
215  *      SNMPERR_SUCCESS On success.
216  *      SNMPERR_GENERR  On failure.
217  */
218 int
219 memdup(u_char **to, const u_char *from, size_t size)
220 {
221   if (to == NULL)
222     return SNMPERR_GENERR;
223   if (from == NULL) {
224     *to = NULL;
225     return SNMPERR_SUCCESS;
226   }
227   if ((*to = (u_char *)malloc(size)) == NULL)
228     return SNMPERR_GENERR;
229   memcpy(*to, from, size);
230   return SNMPERR_SUCCESS;
231
232 }  /* end memdup() */
233
234
235
236
237 /*******************************************************************-o-******
238  * binary_to_hex
239  *
240  * Parameters:
241  *      *input          Binary data.
242  *      len             Length of binary data.
243  *      **output        NULL terminated string equivalent in hex.
244  *      
245  * Returns:
246  *      olen    Length of output string not including NULL terminator.
247  *
248  * FIX  Is there already one of these in the UCD SNMP codebase?
249  *      The old one should be used, or this one should be moved to
250  *      snmplib/snmp_api.c.
251  */
252 u_int
253 binary_to_hex(const u_char *input, size_t len, char **output)
254 {
255         u_int   olen    = (len * 2) + 1;
256         char    *s      = (char *) calloc(1,olen),
257                 *op     = s;
258         const u_char *ip        = input;
259
260
261         while (ip-input < (int)len) {
262                 *op++ = VAL2HEX( (*ip >> 4) & 0xf );
263                 *op++ = VAL2HEX( *ip & 0xf );
264                 ip++;
265         }
266         *op = '\0';
267         
268         *output = s;
269         return olen;
270
271 }  /* end binary_to_hex() */
272
273
274
275
276 /*******************************************************************-o-******
277  * hex_to_binary2
278  *
279  * Parameters:
280  *      *input          Printable data in base16.
281  *      len             Length in bytes of data.
282  *      **output        Binary data equivalent to input.
283  *      
284  * Returns:
285  *      SNMPERR_GENERR  Failure.
286  *      <len>           Otherwise, Length of allocated string.
287  *
288  *
289  * Input of an odd length is right aligned.
290  *
291  * FIX  Another version of "hex-to-binary" which takes odd length input
292  *      strings.  It also allocates the memory to hold the binary data.
293  *      Should be integrated with the official hex_to_binary() function.
294  */
295 int
296 hex_to_binary2(const u_char *input, size_t len, char **output)
297 {
298         u_int   olen    = (len/2) + (len%2);
299         char    *s      = (char *)calloc (1,olen),
300                 *op     = s;
301         const u_char *ip        = input;
302
303
304         *output = NULL;
305         *op = 0;
306         if (len%2) {
307                 if(!isxdigit(*ip)) goto hex_to_binary2_quit;
308                 *op++ = HEX2VAL( *ip );         ip++;
309         }
310
311         while (ip-input < (int)len) {
312                 if(!isxdigit(*ip)) goto hex_to_binary2_quit;
313                 *op = HEX2VAL( *ip ) << 4;      ip++;
314
315                 if(!isxdigit(*ip)) goto hex_to_binary2_quit;
316                 *op++ += HEX2VAL( *ip );        ip++;
317         }
318
319         *output = s;    
320         return olen;
321
322 hex_to_binary2_quit:
323         free_zero(s, olen);
324         return -1;
325
326 }  /* end hex_to_binary2() */
327
328
329
330
331 /*******************************************************************-o-******
332  * dump_chunk
333  *
334  * Parameters:
335  *      *title  (May be NULL.)
336  *      *buf
337  *       size
338  */
339 void
340 dump_chunk(const char *debugtoken, const char *title, const u_char *buf, int size)
341 {
342         u_int           printunit = 64;         /* XXX  Make global. */
343         char            chunk[SNMP_MAXBUF],
344                         *s, *sp;
345
346         if ( title && (*title != '\0') ) {
347           DEBUGMSGTL((debugtoken, "%s\n", title));
348         }
349
350
351         memset(chunk, 0, SNMP_MAXBUF);
352         size = binary_to_hex(buf, size, &s);
353         sp   = s;
354
355         while (size > 0)
356         {
357                 if (size > (int)printunit) {
358                         strncpy(chunk, sp, printunit);  
359                         chunk[printunit] = '\0';
360                         DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
361                 } else {
362                         DEBUGMSGTL((debugtoken, "\t%s\n", sp));
363                 }
364
365                 sp      += printunit;
366                 size    -= printunit;
367         }
368
369
370         SNMP_FREE(s);
371
372 }  /* end dump_chunk() */
373
374
375
376
377 /*******************************************************************-o-******
378  * dump_snmpEngineID
379  *
380  * Parameters:
381  *      *estring
382  *      *estring_len
383  *      
384  * Returns:
385  *      Allocated memory pointing to a string of buflen char representing
386  *      a printf'able form of the snmpEngineID.
387  *
388  *      -OR- NULL on error.
389  *
390  *
391  * Translates the snmpEngineID TC into a printable string.  From RFC 2271,
392  * Section 5 (pp. 36-37):
393  *
394  * First bit:   0       Bit string structured by means non-SNMPv3.
395  *              1       Structure described by SNMPv3 SnmpEngineID TC.
396  *  
397  * Bytes 1-4:           Enterprise ID.  (High bit of first byte is ignored.)
398  *  
399  * Byte 5:      0       (RESERVED by IANA.)
400  *              1       IPv4 address.           (   4 octets)
401  *              2       IPv6 address.           (  16 octets)
402  *              3       MAC address.            (   6 octets)
403  *              4       Locally defined text.   (0-27 octets)
404  *              5       Locally defined octets. (0-27 octets)
405  *              6-127   (RESERVED for enterprise.)
406  *  
407  * Bytes 6-32:          (Determined by byte 5.)
408  *  
409  *
410  * Non-printable characters are given in hex.  Text is given in quotes.
411  * IP and MAC addresses are given in standard (UN*X) conventions.  Sections
412  * are comma separated.
413  *
414  * esp, remaining_len and s trace the state of the constructed buffer.
415  * s will be defined if there is something to return, and it will point
416  * to the end of the constructed buffer.
417  *
418  *
419  * ASSUME  "Text" means printable characters.
420  *
421  * XXX  Must the snmpEngineID always have a minimum length of 12?
422  *      (Cf. part 2 of the TC definition.)
423  * XXX  Does not enforce upper-bound of 32 bytes.
424  * XXX  Need a switch to decide whether to use DNS name instead of a simple
425  *      IP address.
426  *
427  * FIX  Use something other than sprint_hexstring which doesn't add 
428  *      trailing spaces and (sometimes embedded) newlines...
429  */
430 #ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
431 #ifdef SNMP_TESTING_CODE
432 char *
433 dump_snmpEngineID(const u_char *estring, size_t *estring_len)
434 {
435 #define eb(b)   ( *(esp+b) & 0xff )
436
437         int              rval           = SNMPERR_SUCCESS,
438                          gotviolation   = 0,
439                          slen           = 0;
440         u_int            remaining_len;
441
442         char             buf[SNMP_MAXBUF],
443                         *s = NULL,
444                         *t;
445         const u_char    *esp = estring;
446
447         struct  in_addr  iaddr;
448
449
450
451         /*
452          * Sanity check.
453          */
454         if ( !estring || (*estring_len <= 0) ) {
455                 QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
456         }
457         remaining_len = *estring_len;
458         memset(buf, 0, SNMP_MAXBUF);
459
460
461
462         /*
463          * Test first bit.  Return immediately with a hex string, or
464          * begin by formatting the enterprise ID.
465          */
466         if ( !(*esp & 0x80) ) {
467                 sprint_hexstring(buf, esp, remaining_len);
468                 s  = strchr(buf, '\0');
469                 s -= 1;
470                 goto dump_snmpEngineID_quit;
471         }
472
473         s = buf;
474         s += sprintf(s, "enterprise %d, ",      ((*(esp+0)&0x7f) << 24) |
475                                                 ((*(esp+1)&0xff) << 16) |
476                                                 ((*(esp+2)&0xff) <<  8) |
477                                                 ((*(esp+3)&0xff)) );
478                                                 /* XXX  Ick. */
479
480         if (remaining_len < 5) {        /* XXX  Violating string. */
481                 goto dump_snmpEngineID_quit;
482         }
483
484         esp += 4;               /* Incremented one more in the switch below. */
485         remaining_len -= 5;
486
487
488
489         /*
490          * Act on the fifth byte.
491          */
492         switch ((int) *esp++) {
493         case 1:                                 /* IPv4 address. */
494
495                 if (remaining_len < 4) goto dump_snmpEngineID_violation;
496                 memcpy(&iaddr.s_addr, esp, 4);
497
498                 if ( !(t = inet_ntoa(iaddr)) ) goto dump_snmpEngineID_violation;
499                 s += sprintf(s, "%s", t);
500
501                 esp += 4;
502                 remaining_len -= 4;
503                 break;
504
505         case 2:                                 /* IPv6 address. */
506
507                 if (remaining_len < 16) goto dump_snmpEngineID_violation;
508
509                 s += sprintf(   s,
510                                 "%02X%02X %02X%02X %02X%02X %02X%02X::"
511                                 "%02X%02X %02X%02X %02X%02X %02X%02X",
512                                         eb(0),  eb(1),  eb(2),  eb(3),
513                                         eb(4),  eb(5),  eb(6),  eb(7),
514                                         eb(8),  eb(9),  eb(10), eb(11),
515                                         eb(12), eb(13), eb(14), eb(15) );
516
517                 esp += 16;
518                 remaining_len -= 16;
519                 break;
520
521         case 3:                                 /* MAC address. */
522
523                 if (remaining_len < 6) goto dump_snmpEngineID_violation;
524
525                 s += sprintf( s, "%02X:%02X:%02X:%02X:%02X:%02X",
526                         eb(0), eb(1), eb(2), eb(3), eb(4), eb(5) );
527
528                 esp += 6;
529                 remaining_len -= 6;
530                 break;
531
532         case 4:                                 /* Text. */
533
534                 /* Doesn't exist on all (many) architectures */
535                 /* s += snprintf(s, remaining_len+3, "\"%s\"", esp); */
536                 s += sprintf(s, "\"%s\"", esp);
537                 goto dump_snmpEngineID_quit;
538                 break;  /*NOTREACHED*/
539
540         case 5:                                 /* Octets. */
541
542                 sprint_hexstring(s, esp, remaining_len);
543                 s  = strchr(buf, '\0');
544                 s -= 1;
545                 goto dump_snmpEngineID_quit;
546                 break;  /*NOTREACHED*/
547
548
549 dump_snmpEngineID_violation:
550         case 0:                                 /* Violation of RESERVED, 
551                                                  *   -OR- of expected length.
552                                                  */
553                 gotviolation = 1;
554                 s += sprintf(s, "!!! ");
555
556         default:                                /* Unknown encoding. */
557
558                 if ( !gotviolation ) {
559                         s += sprintf(s, "??? ");
560                 }
561                 sprint_hexstring(s, esp, remaining_len);
562                 s  = strchr(buf, '\0');
563                 s -= 1;
564
565                 goto dump_snmpEngineID_quit;
566
567         }  /* endswitch */
568
569
570
571         /*
572          * Cases 1-3 (IP and MAC addresses) should not have trailing
573          * octets, but perhaps they do.  Throw them in too.  XXX
574          */
575         if (remaining_len > 0) {
576                 s += sprintf(s, " (??? ");
577
578                 sprint_hexstring(s, esp, remaining_len);
579                 s  = strchr(buf, '\0');
580                 s -= 1;
581
582                 s += sprintf(s, ")");
583         }
584
585
586
587 dump_snmpEngineID_quit:
588         if (s) {
589                 slen = s-buf+1;
590                 s = calloc(1,slen);
591                 memcpy(s, buf, (slen)-1);
592         }
593
594         memset(buf, 0, SNMP_MAXBUF);    /* XXX -- Overkill? XXX: Yes! */
595
596         return s;
597
598 #undef eb
599 }  /* end dump_snmpEngineID() */
600 #endif /* SNMP_TESTING_CODE */
601 #endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
602
603
604 /*
605  * create a new time marker.
606  * NOTE: Caller must free time marker when no longer needed.
607  */
608 marker_t atime_newMarker(void)
609 {
610   marker_t pm = (marker_t)calloc(1,sizeof(struct timeval));
611   gettimeofday((struct timeval *)pm, 0);
612   return pm;
613 }
614
615 /*
616  * set a time marker.
617  */
618 void atime_setMarker(marker_t pm)
619 {
620   if (! pm) return;
621
622   gettimeofday((struct timeval *)pm, 0);
623 }
624
625 /*
626  * Test: Has (marked time plus delta) exceeded current time ?
627  * Returns 0 if test fails or cannot be tested (no marker).
628  */
629 int atime_ready( marker_t pm, int deltaT)
630 {
631   struct timeval txdelta, txnow;
632   if (! pm) return 0;
633
634   memcpy((void *)&txdelta, pm, sizeof(txdelta));
635   while (deltaT > 1000) {
636      txdelta.tv_sec ++;
637      deltaT -= 1000;
638   }
639   txdelta.tv_usec = (deltaT * 1000) + txdelta.tv_usec;
640
641   gettimeofday(&txnow, 0);
642   if (timercmp(&txnow, &txdelta, <))
643         return 0;
644
645   return 1;
646 }