net-snmp 5.7
tools.c
00001 /*
00002  * tools.c
00003  */
00004 
00005 #define NETSNMP_TOOLS_C 1 /* dont re-define malloc wrappers here */
00006 
00007 #ifdef HAVE_CRTDBG_H
00008 /*
00009  * Define _CRTDBG_MAP_ALLOC such that in debug builds (when _DEBUG has been
00010  * defined) e.g. malloc() is rerouted to _malloc_dbg().
00011  */
00012 #define _CRTDBG_MAP_ALLOC 1
00013 #include <crtdbg.h>
00014 #endif
00015 
00016 #include <net-snmp/net-snmp-config.h>
00017 #include <net-snmp/net-snmp-features.h>
00018 
00019 #include <ctype.h>
00020 #include <stdio.h>
00021 #include <sys/types.h>
00022 #if TIME_WITH_SYS_TIME
00023 # include <sys/time.h>
00024 # include <time.h>
00025 #else
00026 # if HAVE_SYS_TIME_H
00027 #  include <sys/time.h>
00028 # else
00029 #  include <time.h>
00030 # endif
00031 #endif
00032 #ifdef HAVE_SYS_SOCKET_H
00033 #include <sys/socket.h>
00034 #endif
00035 #ifdef HAVE_SYS_TIME_H
00036 #include <sys/time.h>
00037 #endif
00038 #ifdef HAVE_STDLIB_H
00039 #include <stdlib.h>
00040 #endif
00041 #if HAVE_STRING_H
00042 #include <string.h>
00043 #else
00044 #include <strings.h>
00045 #endif
00046 #ifdef HAVE_NETINET_IN_H
00047 #include <netinet/in.h>
00048 #endif
00049 #ifdef HAVE_ARPA_INET_H
00050 #include <arpa/inet.h>
00051 #endif
00052 #ifdef HAVE_VALGRIND_MEMCHECK_H
00053 #include <valgrind/memcheck.h>
00054 #endif
00055 #ifdef cygwin
00056 #include <windows.h>
00057 #endif
00058 
00059 #if HAVE_UNISTD_H
00060 #include <unistd.h>
00061 #endif
00062 #if HAVE_DMALLOC_H
00063 #include <dmalloc.h>
00064 #endif
00065 
00066 #include <net-snmp/types.h>
00067 #include <net-snmp/output_api.h>
00068 #include <net-snmp/utilities.h>
00069 #include <net-snmp/library/tools.h>     /* for "internal" definitions */
00070 
00071 #include <net-snmp/library/snmp_api.h>
00072 #include <net-snmp/library/mib.h>
00073 #include <net-snmp/library/scapi.h>
00074 
00075 netsnmp_feature_child_of(tools_all, libnetsnmp)
00076 
00077 netsnmp_feature_child_of(memory_wrappers, tools_all)
00078 netsnmp_feature_child_of(valgrind, tools_all)
00079 netsnmp_feature_child_of(string_time_to_secs, tools_all)
00080 netsnmp_feature_child_of(netsnmp_check_definedness, valgrind)
00081 
00082 netsnmp_feature_child_of(uatime_ready, netsnmp_unused)
00083 netsnmp_feature_child_of(timeval_tticks, netsnmp_unused)
00084 
00085 netsnmp_feature_child_of(memory_strdup, memory_wrappers)
00086 netsnmp_feature_child_of(memory_calloc, memory_wrappers)
00087 netsnmp_feature_child_of(memory_malloc, memory_wrappers)
00088 netsnmp_feature_child_of(memory_realloc, memory_wrappers)
00089 netsnmp_feature_child_of(memory_free, memory_wrappers)
00090 
00091 #ifndef NETSNMP_FEATURE_REMOVE_MEMORY_WRAPPERS
00092 
00098 char * netsnmp_strdup( const char * ptr)
00099 {
00100     return strdup(ptr);
00101 }
00102 #endif /* NETSNMP_FEATURE_REMOVE_MEMORY_STRDUP */
00103 #ifndef NETSNMP_FEATURE_REMOVE_MEMORY_CALLOC
00104 
00107 void * netsnmp_calloc(size_t nmemb, size_t size)
00108 {
00109     return calloc(nmemb, size);
00110 }
00111 #endif /* NETSNMP_FEATURE_REMOVE_MEMORY_CALLOC */
00112 #ifndef NETSNMP_FEATURE_REMOVE_MEMORY_MALLOC
00113 
00116 void * netsnmp_malloc(size_t size)
00117 {
00118     return malloc(size);
00119 }
00120 #endif /* NETSNMP_FEATURE_REMOVE_MEMORY_MALLOC */
00121 #ifndef NETSNMP_FEATURE_REMOVE_MEMORY_REALLOC
00122 
00125 void * netsnmp_realloc( void * ptr, size_t size)
00126 {
00127     return realloc(ptr, size);
00128 }
00129 #endif /* NETSNMP_FEATURE_REMOVE_MEMORY_REALLOC */
00130 #ifndef NETSNMP_FEATURE_REMOVE_MEMORY_FREE
00131 
00135 void netsnmp_free( void * ptr)
00136 {
00137     if (ptr)
00138         free(ptr);
00139 }
00140 #endif /* NETSNMP_FEATURE_REMOVE_MEMORY_FREE */
00141 
00156 int
00157 snmp_realloc(u_char ** buf, size_t * buf_len)
00158 {
00159     u_char         *new_buf = NULL;
00160     size_t          new_buf_len = 0;
00161 
00162     if (buf == NULL) {
00163         return 0;
00164     }
00165 
00166     if (*buf_len <= 255) {
00167         new_buf_len = *buf_len + 256;
00168     } else if (*buf_len > 255 && *buf_len <= 8191) {
00169         new_buf_len = *buf_len * 2;
00170     } else if (*buf_len > 8191) {
00171         new_buf_len = *buf_len + 8192;
00172     }
00173 
00174     if (*buf == NULL) {
00175         new_buf = (u_char *) malloc(new_buf_len);
00176     } else {
00177         new_buf = (u_char *) realloc(*buf, new_buf_len);
00178     }
00179 
00180     if (new_buf != NULL) {
00181         *buf = new_buf;
00182         *buf_len = new_buf_len;
00183         return 1;
00184     } else {
00185         return 0;
00186     }
00187 }
00188 
00189 int
00190 snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
00191             int allow_realloc, const u_char * s)
00192 {
00193     if (buf == NULL || buf_len == NULL || out_len == NULL) {
00194         return 0;
00195     }
00196 
00197     if (s == NULL) {
00198         /*
00199          * Appending a NULL string always succeeds since it is a NOP.  
00200          */
00201         return 1;
00202     }
00203 
00204     while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
00205         if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
00206             return 0;
00207         }
00208     }
00209 
00210     strcpy((char *) (*buf + *out_len), (const char *) s);
00211     *out_len += strlen((char *) (*buf + *out_len));
00212     return 1;
00213 }
00214 
00220 void
00221 free_zero(void *buf, size_t size)
00222 {
00223     if (buf) {
00224         memset(buf, 0, size);
00225         free(buf);
00226     }
00227 
00228 }                               /* end free_zero() */
00229 
00230 #ifndef NETSNMP_FEATURE_REMOVE_USM_SCAPI
00231 
00241 u_char         *
00242 malloc_random(size_t * size)
00243 {
00244     int             rval = SNMPERR_SUCCESS;
00245     u_char         *buf = (u_char *) calloc(1, *size);
00246 
00247     if (buf) {
00248         rval = sc_random(buf, size);
00249 
00250         if (rval < 0) {
00251             free_zero(buf, *size);
00252             buf = NULL;
00253         } else {
00254             *size = rval;
00255         }
00256     }
00257 
00258     return buf;
00259 
00260 }                               /* end malloc_random() */
00261 #endif /* NETSNMP_FEATURE_REMOVE_USM_SCAPI */
00262 
00273 int
00274 memdup(u_char ** to, const void * from, size_t size)
00275 {
00276     if (to == NULL)
00277         return SNMPERR_GENERR;
00278     if (from == NULL) {
00279         *to = NULL;
00280         return SNMPERR_SUCCESS;
00281     }
00282     if ((*to = (u_char *) malloc(size)) == NULL)
00283         return SNMPERR_GENERR;
00284     memcpy(*to, from, size);
00285     return SNMPERR_SUCCESS;
00286 
00287 }                               /* end memdup() */
00288 
00289 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_CHECK_DEFINEDNESS
00290 
00299 void
00300 netsnmp_check_definedness(const void *packet, size_t length)
00301 {
00302 #if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
00303     && (__VALGRIND_MAJOR__ > 3                                   \
00304         || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
00305 
00306     if (RUNNING_ON_VALGRIND) {
00307         int i;
00308         char vbits;
00309 
00310         for (i = 0; i < length; ++i) {
00311             if (VALGRIND_GET_VBITS((const char *)packet + i, &vbits, 1) == 1
00312                 && vbits)
00313                 VALGRIND_PRINTF_BACKTRACE("Undefined: byte %d/%d", i,
00314                                           (int)length);
00315         }
00316     }
00317 
00318 #endif
00319 }
00320 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_CHECK_DEFINEDNESS */
00321 
00325 char           *
00326 netsnmp_strdup_and_null(const u_char * from, size_t from_len)
00327 {
00328     char         *ret;
00329 
00330     if (from_len == 0 || from[from_len - 1] != '\0') {
00331         ret = (char *)malloc(from_len + 1);
00332         if (!ret)
00333             return NULL;
00334         ret[from_len] = '\0';
00335     } else {
00336         ret = (char *)malloc(from_len);
00337         if (!ret)
00338             return NULL;
00339         ret[from_len - 1] = '\0';
00340     }
00341     memcpy(ret, from, from_len);
00342     return ret;
00343 }
00344 
00355 u_int
00356 netsnmp_binary_to_hex(u_char ** dest, size_t *dest_len, int allow_realloc, 
00357                       const u_char * input, size_t len)
00358 {
00359     u_int           olen = (len * 2) + 1;
00360     u_char         *s, *op;
00361     const u_char   *ip = input;
00362 
00363     if (dest == NULL || dest_len == NULL || input == NULL)
00364         return 0;
00365 
00366     if (NULL == *dest) {
00367         s = (unsigned char *) calloc(1, olen);
00368         *dest_len = olen;
00369     }
00370     else
00371         s = *dest;
00372 
00373     if (*dest_len < olen) {
00374         if (!allow_realloc)
00375             return 0;
00376         *dest_len = olen;
00377         if (snmp_realloc(dest, dest_len))
00378             return 0;
00379     }
00380 
00381     op = s;
00382     while (ip - input < (int) len) {
00383         *op++ = VAL2HEX((*ip >> 4) & 0xf);
00384         *op++ = VAL2HEX(*ip & 0xf);
00385         ip++;
00386     }
00387     *op = '\0';
00388 
00389     if (s != *dest)
00390         *dest = s;
00391     *dest_len = olen;
00392 
00393     return olen;
00394 
00395 }                               /* end netsnmp_binary_to_hex() */
00396 
00409 u_int
00410 binary_to_hex(const u_char * input, size_t len, char **output)
00411 {
00412     size_t out_len = 0;
00413 
00414     *output = NULL; /* will alloc new buffer */
00415 
00416     return netsnmp_binary_to_hex((u_char**)output, &out_len, 1, input, len);
00417 }                               /* end binary_to_hex() */
00418 
00419 
00420 
00421 
00436 int
00437 hex_to_binary2(const u_char * input, size_t len, char **output)
00438 {
00439     u_int           olen = (len / 2) + (len % 2);
00440     char           *s = (char *) calloc(1, (olen) ? olen : 1), *op = s;
00441     const u_char   *ip = input;
00442 
00443 
00444     *output = NULL;
00445     *op = 0;
00446     if (len % 2) {
00447         if (!isxdigit(*ip))
00448             goto hex_to_binary2_quit;
00449         *op++ = HEX2VAL(*ip);
00450         ip++;
00451     }
00452 
00453     while (ip - input < (int) len) {
00454         if (!isxdigit(*ip))
00455             goto hex_to_binary2_quit;
00456         *op = HEX2VAL(*ip) << 4;
00457         ip++;
00458 
00459         if (!isxdigit(*ip))
00460             goto hex_to_binary2_quit;
00461         *op++ += HEX2VAL(*ip);
00462         ip++;
00463     }
00464 
00465     *output = s;
00466     return olen;
00467 
00468   hex_to_binary2_quit:
00469     free_zero(s, olen);
00470     return -1;
00471 
00472 }                               /* end hex_to_binary2() */
00473 
00474 int
00475 snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
00476                        int allow_realloc, const char *decimal)
00477 {
00478     int             subid = 0;
00479     const char     *cp = decimal;
00480 
00481     if (buf == NULL || buf_len == NULL || out_len == NULL
00482         || decimal == NULL) {
00483         return 0;
00484     }
00485 
00486     while (*cp != '\0') {
00487         if (isspace((int) *cp) || *cp == '.') {
00488             cp++;
00489             continue;
00490         }
00491         if (!isdigit((int) *cp)) {
00492             return 0;
00493         }
00494         if ((subid = atoi(cp)) > 255) {
00495             return 0;
00496         }
00497         if ((*out_len >= *buf_len) &&
00498             !(allow_realloc && snmp_realloc(buf, buf_len))) {
00499             return 0;
00500         }
00501         *(*buf + *out_len) = (u_char) subid;
00502         (*out_len)++;
00503         while (isdigit((int) *cp)) {
00504             cp++;
00505         }
00506     }
00507     return 1;
00508 }
00509 
00537 int
00538 netsnmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * offset,
00539                       int allow_realloc, const char *hex, const char *delim)
00540 {
00541     unsigned int    subid = 0;
00542     const char     *cp = hex;
00543 
00544     if (buf == NULL || buf_len == NULL || offset == NULL || hex == NULL) {
00545         return 0;
00546     }
00547 
00548     if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
00549         cp += 2;
00550     }
00551 
00552     while (*cp != '\0') {
00553         if (!isxdigit((int) *cp) ||
00554             !isxdigit((int) *(cp+1))) {
00555             if ((NULL != delim) && (NULL != strchr(delim, *cp))) {
00556                 cp++;
00557                 continue;
00558             }
00559             return 0;
00560         }
00561         if (sscanf(cp, "%2x", &subid) == 0) {
00562             return 0;
00563         }
00564         /*
00565          * if we dont' have enough space, realloc.
00566          * (snmp_realloc will adjust buf_len to new size)
00567          */
00568         if ((*offset >= *buf_len) &&
00569             !(allow_realloc && snmp_realloc(buf, buf_len))) {
00570             return 0;
00571         }
00572         *(*buf + *offset) = (u_char) subid;
00573         (*offset)++;
00574         if (*++cp == '\0') {
00575             /*
00576              * Odd number of hex digits is an error.  
00577              */
00578             return 0;
00579         } else {
00580             cp++;
00581         }
00582     }
00583     return 1;
00584 }
00585 
00597 int
00598 snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * offset,
00599                    int allow_realloc, const char *hex)
00600 {
00601     return netsnmp_hex_to_binary(buf, buf_len, offset, allow_realloc, hex, " ");
00602 }
00603 
00604 /*******************************************************************-o-******
00605  * dump_chunk
00606  *
00607  * Parameters:
00608  *      *title  (May be NULL.)
00609  *      *buf
00610  *       size
00611  */
00612 void
00613 dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
00614            int size)
00615 {
00616     u_int           printunit = 64;     /* XXX  Make global. */
00617     char            chunk[SNMP_MAXBUF], *s, *sp;
00618 
00619     if (title && (*title != '\0')) {
00620         DEBUGMSGTL((debugtoken, "%s\n", title));
00621     }
00622 
00623 
00624     memset(chunk, 0, SNMP_MAXBUF);
00625     size = binary_to_hex(buf, size, &s);
00626     sp = s;
00627 
00628     while (size > 0) {
00629         if (size > (int) printunit) {
00630             strncpy(chunk, sp, printunit);
00631             chunk[printunit] = '\0';
00632             DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
00633         } else {
00634             DEBUGMSGTL((debugtoken, "\t%s\n", sp));
00635         }
00636 
00637         sp += printunit;
00638         size -= printunit;
00639     }
00640 
00641 
00642     SNMP_FREE(s);
00643 
00644 }                               /* end dump_chunk() */
00645 
00646 
00647 
00648 
00649 /*******************************************************************-o-******
00650  * dump_snmpEngineID
00651  *
00652  * Parameters:
00653  *      *estring
00654  *      *estring_len
00655  *      
00656  * Returns:
00657  *      Allocated memory pointing to a string of buflen char representing
00658  *      a printf'able form of the snmpEngineID.
00659  *
00660  *      -OR- NULL on error.
00661  *
00662  *
00663  * Translates the snmpEngineID TC into a printable string.  From RFC 2271,
00664  * Section 5 (pp. 36-37):
00665  *
00666  * First bit:   0       Bit string structured by means non-SNMPv3.
00667  *              1       Structure described by SNMPv3 SnmpEngineID TC.
00668  *  
00669  * Bytes 1-4:           Enterprise ID.  (High bit of first byte is ignored.)
00670  *  
00671  * Byte 5:      0       (RESERVED by IANA.)
00672  *              1       IPv4 address.           (   4 octets)
00673  *              2       IPv6 address.           (  16 octets)
00674  *              3       MAC address.            (   6 octets)
00675  *              4       Locally defined text.   (0-27 octets)
00676  *              5       Locally defined octets. (0-27 octets)
00677  *              6-127   (RESERVED for enterprise.)
00678  *  
00679  * Bytes 6-32:          (Determined by byte 5.)
00680  *  
00681  *
00682  * Non-printable characters are given in hex.  Text is given in quotes.
00683  * IP and MAC addresses are given in standard (UN*X) conventions.  Sections
00684  * are comma separated.
00685  *
00686  * esp, remaining_len and s trace the state of the constructed buffer.
00687  * s will be defined if there is something to return, and it will point
00688  * to the end of the constructed buffer.
00689  *
00690  *
00691  * ASSUME  "Text" means printable characters.
00692  *
00693  * XXX  Must the snmpEngineID always have a minimum length of 12?
00694  *      (Cf. part 2 of the TC definition.)
00695  * XXX  Does not enforce upper-bound of 32 bytes.
00696  * XXX  Need a switch to decide whether to use DNS name instead of a simple
00697  *      IP address.
00698  *
00699  * FIX  Use something other than snprint_hexstring which doesn't add 
00700  *      trailing spaces and (sometimes embedded) newlines...
00701  */
00702 #ifdef NETSNMP_ENABLE_TESTING_CODE
00703 char           *
00704 dump_snmpEngineID(const u_char * estring, size_t * estring_len)
00705 {
00706 #define eb(b)   ( *(esp+b) & 0xff )
00707 
00708     int             rval = SNMPERR_SUCCESS, gotviolation = 0, slen = 0;
00709     u_int           remaining_len;
00710 
00711     char            buf[SNMP_MAXBUF], *s = NULL, *t;
00712     const u_char   *esp = estring;
00713 
00714     struct in_addr  iaddr;
00715 
00716 
00717 
00718     /*
00719      * Sanity check.
00720      */
00721     if (!estring || (*estring_len <= 0)) {
00722         QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
00723     }
00724     remaining_len = *estring_len;
00725     memset(buf, 0, SNMP_MAXBUF);
00726 
00727 
00728 
00729     /*
00730      * Test first bit.  Return immediately with a hex string, or
00731      * begin by formatting the enterprise ID.
00732      */
00733     if (!(*esp & 0x80)) {
00734         snprint_hexstring(buf, SNMP_MAXBUF, esp, remaining_len);
00735         s = strchr(buf, '\0');
00736         s -= 1;
00737         goto dump_snmpEngineID_quit;
00738     }
00739 
00740     s = buf;
00741     s += sprintf(s, "enterprise %d, ", ((*(esp + 0) & 0x7f) << 24) |
00742                  ((*(esp + 1) & 0xff) << 16) |
00743                  ((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
00744     /*
00745      * XXX  Ick. 
00746      */
00747 
00748     if (remaining_len < 5) {    /* XXX  Violating string. */
00749         goto dump_snmpEngineID_quit;
00750     }
00751 
00752     esp += 4;                   /* Incremented one more in the switch below. */
00753     remaining_len -= 5;
00754 
00755 
00756 
00757     /*
00758      * Act on the fifth byte.
00759      */
00760     switch ((int) *esp++) {
00761     case 1:                    /* IPv4 address. */
00762 
00763         if (remaining_len < 4)
00764             goto dump_snmpEngineID_violation;
00765         memcpy(&iaddr.s_addr, esp, 4);
00766 
00767         if (!(t = inet_ntoa(iaddr)))
00768             goto dump_snmpEngineID_violation;
00769         s += sprintf(s, "%s", t);
00770 
00771         esp += 4;
00772         remaining_len -= 4;
00773         break;
00774 
00775     case 2:                    /* IPv6 address. */
00776 
00777         if (remaining_len < 16)
00778             goto dump_snmpEngineID_violation;
00779 
00780         s += sprintf(s,
00781                      "%02X%02X %02X%02X %02X%02X %02X%02X::"
00782                      "%02X%02X %02X%02X %02X%02X %02X%02X",
00783                      eb(0), eb(1), eb(2), eb(3),
00784                      eb(4), eb(5), eb(6), eb(7),
00785                      eb(8), eb(9), eb(10), eb(11),
00786                      eb(12), eb(13), eb(14), eb(15));
00787 
00788         esp += 16;
00789         remaining_len -= 16;
00790         break;
00791 
00792     case 3:                    /* MAC address. */
00793 
00794         if (remaining_len < 6)
00795             goto dump_snmpEngineID_violation;
00796 
00797         s += sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X",
00798                      eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
00799 
00800         esp += 6;
00801         remaining_len -= 6;
00802         break;
00803 
00804     case 4:                    /* Text. */
00805 
00806         /*
00807          * Doesn't exist on all (many) architectures 
00808          */
00809         /*
00810          * s += snprintf(s, remaining_len+3, "\"%s\"", esp); 
00811          */
00812         s += sprintf(s, "\"%.*s\"", sizeof(buf)-strlen(buf)-3, esp);
00813         goto dump_snmpEngineID_quit;
00814         break;
00815      /*NOTREACHED*/ case 5:    /* Octets. */
00816 
00817         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
00818                           esp, remaining_len);
00819         s = strchr(buf, '\0');
00820         s -= 1;
00821         goto dump_snmpEngineID_quit;
00822         break;
00823        /*NOTREACHED*/ dump_snmpEngineID_violation:
00824     case 0:                    /* Violation of RESERVED, 
00825                                  * *   -OR- of expected length.
00826                                  */
00827         gotviolation = 1;
00828         s += sprintf(s, "!!! ");
00829 
00830     default:                   /* Unknown encoding. */
00831 
00832         if (!gotviolation) {
00833             s += sprintf(s, "??? ");
00834         }
00835         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
00836                           esp, remaining_len);
00837         s = strchr(buf, '\0');
00838         s -= 1;
00839 
00840         goto dump_snmpEngineID_quit;
00841 
00842     }                           /* endswitch */
00843 
00844 
00845 
00846     /*
00847      * Cases 1-3 (IP and MAC addresses) should not have trailing
00848      * octets, but perhaps they do.  Throw them in too.  XXX
00849      */
00850     if (remaining_len > 0) {
00851         s += sprintf(s, " (??? ");
00852 
00853         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
00854                           esp, remaining_len);
00855         s = strchr(buf, '\0');
00856         s -= 1;
00857 
00858         s += sprintf(s, ")");
00859     }
00860 
00861 
00862 
00863   dump_snmpEngineID_quit:
00864     if (s) {
00865         slen = s - buf + 1;
00866         s = calloc(1, slen);
00867         memcpy(s, buf, (slen) - 1);
00868     }
00869 
00870     memset(buf, 0, SNMP_MAXBUF);        /* XXX -- Overkill? XXX: Yes! */
00871 
00872     return s;
00873 
00874 #undef eb
00875 }                               /* end dump_snmpEngineID() */
00876 #endif                          /* NETSNMP_ENABLE_TESTING_CODE */
00877 
00878 
00883 marker_t
00884 atime_newMarker(void)
00885 {
00886     marker_t        pm = (marker_t) calloc(1, sizeof(struct timeval));
00887     gettimeofday((struct timeval *) pm, NULL);
00888     return pm;
00889 }
00890 
00894 void
00895 atime_setMarker(marker_t pm)
00896 {
00897     if (!pm)
00898         return;
00899 
00900     gettimeofday((struct timeval *) pm, NULL);
00901 }
00902 
00903 
00907 long
00908 atime_diff(const_marker_t first, const_marker_t second)
00909 {
00910     struct timeval diff;
00911 
00912     NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
00913 
00914     return (long)(diff.tv_sec * 1000 + diff.tv_usec / 1000);
00915 }
00916 
00920 u_long
00921 uatime_diff(const_marker_t first, const_marker_t second)
00922 {
00923     struct timeval diff;
00924 
00925     NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
00926 
00927     return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
00928 }
00929 
00934 u_long
00935 uatime_hdiff(const_marker_t first, const_marker_t second)
00936 {
00937     struct timeval diff;
00938 
00939     NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
00940     return ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
00941 }
00942 
00947 int
00948 atime_ready(const_marker_t pm, int deltaT)
00949 {
00950     marker_t        now;
00951     long            diff;
00952     if (!pm)
00953         return 0;
00954 
00955     now = atime_newMarker();
00956 
00957     diff = atime_diff(pm, now);
00958     free(now);
00959     if (diff < deltaT)
00960         return 0;
00961 
00962     return 1;
00963 }
00964 
00969 #ifndef NETSNMP_FEATURE_REMOVE_UATIME_READY
00970 int
00971 uatime_ready(const_marker_t pm, unsigned int deltaT)
00972 {
00973     marker_t        now;
00974     u_long          diff;
00975     if (!pm)
00976         return 0;
00977 
00978     now = atime_newMarker();
00979 
00980     diff = uatime_diff(pm, now);
00981     free(now);
00982     if (diff < deltaT)
00983         return 0;
00984 
00985     return 1;
00986 }
00987 #endif /* NETSNMP_FEATURE_REMOVE_UATIME_READY */
00988 
00989 
00990         /*
00991          * Time-related utility functions
00992          */
00993 
00997 int
00998 marker_tticks(const_marker_t pm)
00999 {
01000     int             res;
01001     marker_t        now = atime_newMarker();
01002 
01003     res = atime_diff(pm, now);
01004     free(now);
01005     return res / 10;            /* atime_diff works in msec, not csec */
01006 }
01007 
01008 #ifndef NETSNMP_FEATURE_REMOVE_TIMEVAL_TTICKS
01009 int
01010 timeval_tticks(const struct timeval *tv)
01011 {
01012     return marker_tticks((const_marker_t) tv);
01013 }
01014 #endif /* NETSNMP_FEATURE_REMOVE_TIMEVAL_TTICKS */
01015 
01028 char *netsnmp_getenv(const char *name)
01029 {
01030 #if !defined (WIN32) && !defined (cygwin)
01031   return (getenv(name));
01032 #else
01033   char *temp = NULL;  
01034   HKEY hKey;
01035   unsigned char * key_value = NULL;
01036   DWORD key_value_size = 0;
01037   DWORD key_value_type = 0;
01038   DWORD getenv_worked = 0;
01039 
01040   DEBUGMSGTL(("read_config", "netsnmp_getenv called with name: %s\n",name));
01041 
01042   if (!(name))
01043     return NULL;
01044   
01045   /* Try environment variable first */ 
01046   temp = getenv(name);
01047   if (temp) {
01048     getenv_worked = 1;
01049     DEBUGMSGTL(("read_config", "netsnmp_getenv will return from ENV: %s\n",temp));
01050   }
01051   
01052   /* Next try HKCU */
01053   if (temp == NULL)
01054   {
01055     if (getenv("SNMP_IGNORE_WINDOWS_REGISTRY"))
01056       return NULL;
01057 
01058     if (RegOpenKeyExA(
01059           HKEY_CURRENT_USER, 
01060           "SOFTWARE\\Net-SNMP", 
01061           0, 
01062           KEY_QUERY_VALUE, 
01063           &hKey) == ERROR_SUCCESS) {   
01064       
01065       if (RegQueryValueExA(
01066             hKey, 
01067             name, 
01068             NULL, 
01069             &key_value_type, 
01070             NULL,               /* Just get the size */
01071             &key_value_size) == ERROR_SUCCESS) {
01072 
01073         SNMP_FREE(key_value);
01074 
01075         /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
01076          * string data in registry is missing one (which is unlikely).
01077          */
01078         key_value = malloc((sizeof(char) * key_value_size)+sizeof(char));
01079         
01080         if (RegQueryValueExA(
01081               hKey, 
01082               name, 
01083               NULL, 
01084               &key_value_type, 
01085               key_value, 
01086               &key_value_size) == ERROR_SUCCESS) {
01087         }
01088         temp = (char *) key_value;
01089       }
01090       RegCloseKey(hKey);
01091       if (temp)
01092         DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKCU: %s\n",temp));
01093     }
01094   }
01095 
01096   /* Next try HKLM */
01097   if (temp == NULL)
01098   {
01099     if (RegOpenKeyExA(
01100           HKEY_LOCAL_MACHINE, 
01101           "SOFTWARE\\Net-SNMP", 
01102           0, 
01103           KEY_QUERY_VALUE, 
01104           &hKey) == ERROR_SUCCESS) {   
01105       
01106       if (RegQueryValueExA(
01107             hKey, 
01108             name, 
01109             NULL, 
01110             &key_value_type, 
01111             NULL,               /* Just get the size */
01112             &key_value_size) == ERROR_SUCCESS) {
01113 
01114         SNMP_FREE(key_value);
01115 
01116         /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
01117          * string data in registry is missing one (which is unlikely).
01118          */
01119         key_value = malloc((sizeof(char) * key_value_size)+sizeof(char));
01120         
01121         if (RegQueryValueExA(
01122               hKey, 
01123               name, 
01124               NULL, 
01125               &key_value_type, 
01126               key_value, 
01127               &key_value_size) == ERROR_SUCCESS) {
01128         }
01129         temp = (char *) key_value;
01130 
01131       }
01132       RegCloseKey(hKey);
01133       if (temp)
01134         DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKLM: %s\n",temp));
01135     }
01136   }
01137   
01138   if (temp && !getenv_worked) {
01139     setenv(name, temp, 1);
01140     SNMP_FREE(temp);
01141   }
01142 
01143   DEBUGMSGTL(("read_config", "netsnmp_getenv returning: %s\n",getenv(name)));
01144 
01145   return(getenv(name));
01146 #endif
01147 }
01148 
01149 /*
01150  * swap the order of an inet addr string
01151  */
01152 int
01153 netsnmp_addrstr_hton(char *ptr, size_t len)
01154 {
01155 #ifndef WORDS_BIGENDIAN
01156     char tmp[8];
01157     
01158     if (8 == len) {
01159         tmp[0] = ptr[6];
01160         tmp[1] = ptr[7];
01161         tmp[2] = ptr[4];
01162         tmp[3] = ptr[5];
01163         tmp[4] = ptr[2];
01164         tmp[5] = ptr[3];
01165         tmp[6] = ptr[0];
01166         tmp[7] = ptr[1];
01167         memcpy (ptr, &tmp, 8);
01168     }
01169     else if (32 == len) {
01170         netsnmp_addrstr_hton(ptr   , 8);
01171         netsnmp_addrstr_hton(ptr+8 , 8);
01172         netsnmp_addrstr_hton(ptr+16, 8);
01173         netsnmp_addrstr_hton(ptr+24, 8);
01174     }
01175     else
01176         return -1;
01177 #endif
01178 
01179     return 0;
01180 }
01181 
01182 #ifndef NETSNMP_FEATURE_REMOVE_STRING_TIME_TO_SECS
01183 
01195 int
01196 netsnmp_string_time_to_secs(const char *time_string) {
01197     int secs = -1;
01198     if (!time_string || !time_string[0])
01199         return secs;
01200 
01201     secs = atoi(time_string);
01202 
01203     if (isdigit((unsigned char)time_string[strlen(time_string)-1]))
01204         return secs; /* no letter specified, it's already in seconds */
01205     
01206     switch (time_string[strlen(time_string)-1]) {
01207     case 's':
01208     case 'S':
01209         /* already in seconds */
01210         break;
01211 
01212     case 'm':
01213     case 'M':
01214         secs = secs * 60;
01215         break;
01216 
01217     case 'h':
01218     case 'H':
01219         secs = secs * 60 * 60;
01220         break;
01221 
01222     case 'd':
01223     case 'D':
01224         secs = secs * 60 * 60 * 24;
01225         break;
01226 
01227     case 'w':
01228     case 'W':
01229         secs = secs * 60 * 60 * 24 * 7;
01230         break;
01231 
01232     default:
01233         snmp_log(LOG_ERR, "time string %s contains an invalid suffix letter\n",
01234                  time_string);
01235         return -1;
01236     }
01237 
01238     DEBUGMSGTL(("string_time_to_secs", "Converted time string %s to %d\n",
01239                 time_string, secs));
01240     return secs;
01241 }
01242 #endif /* NETSNMP_FEATURE_REMOVE_STRING_TIME_TO_SECS */