Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/tools.c
Line
Count
Source
1
/*
2
 * tools.c
3
 *
4
 * Portions of this file are copyrighted by:
5
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
6
 * Use is subject to license terms specified in the COPYING file
7
 * distributed with the Net-SNMP package.
8
 */
9
10
#ifdef HAVE_CRTDBG_H
11
/*
12
 * Define _CRTDBG_MAP_ALLOC such that in debug builds (when _DEBUG has been
13
 * defined) e.g. malloc() is rerouted to _malloc_dbg().
14
 */
15
#define _CRTDBG_MAP_ALLOC 1
16
#include <crtdbg.h>
17
#endif
18
19
#include <net-snmp/net-snmp-config.h>
20
#include <net-snmp/net-snmp-features.h>
21
22
#include <ctype.h>
23
#ifdef HAVE_INTTYPES_H
24
#include <inttypes.h>
25
#endif
26
#include <stdio.h>
27
#include <sys/types.h>
28
#ifdef TIME_WITH_SYS_TIME
29
# include <sys/time.h>
30
# include <time.h>
31
#else
32
# ifdef HAVE_SYS_TIME_H
33
#  include <sys/time.h>
34
# else
35
#  include <time.h>
36
# endif
37
#endif
38
#ifdef HAVE_SYS_SOCKET_H
39
#include <sys/socket.h>
40
#endif
41
#ifdef HAVE_SYS_TIME_H
42
#include <sys/time.h>
43
#endif
44
#ifdef HAVE_STDLIB_H
45
#include <stdlib.h>
46
#endif
47
#ifdef HAVE_STRING_H
48
#include <string.h>
49
#else
50
#include <strings.h>
51
#endif
52
#ifdef HAVE_NETINET_IN_H
53
#include <netinet/in.h>
54
#endif
55
#ifdef HAVE_ARPA_INET_H
56
#include <arpa/inet.h>
57
#endif
58
#ifdef HAVE_VALGRIND_MEMCHECK_H
59
#include <valgrind/memcheck.h>
60
#endif
61
#if defined(cygwin) || defined(mingw32)
62
#include <windows.h>
63
#endif
64
65
#ifdef HAVE_UNISTD_H
66
#include <unistd.h>
67
#endif
68
69
#include <net-snmp/types.h>
70
#include <net-snmp/output_api.h>
71
#include <net-snmp/utilities.h>
72
#include <net-snmp/library/tools.h>     /* for "internal" definitions */
73
74
#include <net-snmp/library/snmp_api.h>
75
#include <net-snmp/library/mib.h>
76
#include <net-snmp/library/scapi.h>
77
78
netsnmp_feature_child_of(tools_all, libnetsnmp);
79
80
netsnmp_feature_child_of(memory_wrappers, tools_all);
81
netsnmp_feature_child_of(valgrind, tools_all);
82
netsnmp_feature_child_of(string_time_to_secs, tools_all);
83
netsnmp_feature_child_of(netsnmp_check_definedness, valgrind);
84
85
netsnmp_feature_child_of(uatime_ready, netsnmp_unused);
86
netsnmp_feature_child_of(timeval_tticks, netsnmp_unused);
87
88
netsnmp_feature_child_of(memory_strdup, memory_wrappers);
89
netsnmp_feature_child_of(memory_calloc, memory_wrappers);
90
netsnmp_feature_child_of(memory_malloc, memory_wrappers);
91
netsnmp_feature_child_of(memory_realloc, memory_wrappers);
92
netsnmp_feature_child_of(memory_free, memory_wrappers);
93
94
#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_STRDUP
95
/**
96
 * This function is a wrapper for the strdup function.
97
 *
98
 * @note The strdup() implementation calls _malloc_dbg() when linking with
99
 * MSVCRT??D.dll and malloc() when linking with MSVCRT??.dll
100
 */
101
char * netsnmp_strdup( const char * ptr)
102
0
{
103
0
    return strdup(ptr);
104
0
}
105
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_STRDUP */
106
#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_CALLOC
107
/**
108
 * This function is a wrapper for the calloc function.
109
 */
110
void * netsnmp_calloc(size_t nmemb, size_t size)
111
0
{
112
0
    return calloc(nmemb, size);
113
0
}
114
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_CALLOC */
115
#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_MALLOC
116
/**
117
 * This function is a wrapper for the malloc function.
118
 */
119
void * netsnmp_malloc(size_t size)
120
0
{
121
0
    return malloc(size);
122
0
}
123
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_MALLOC */
124
#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_REALLOC
125
/**
126
 * This function is a wrapper for the realloc function.
127
 */
128
void * netsnmp_realloc( void * ptr, size_t size)
129
0
{
130
0
    return realloc(ptr, size);
131
0
}
132
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_REALLOC */
133
#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_FREE
134
/**
135
 * This function is a wrapper for the free function.
136
 * It calls free only if the calling parameter has a non-zero value.
137
 */
138
void netsnmp_free( void * ptr)
139
0
{
140
0
    if (ptr)
141
0
        free(ptr);
142
0
}
143
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_FREE */
144
145
/**
146
 * This function increase the size of the buffer pointed at by *buf, which is
147
 * initially of size *buf_len.  Contents are preserved **AT THE BOTTOM END OF
148
 * THE BUFFER**.  If memory can be (re-)allocated then it returns 1, else it
149
 * returns 0.
150
 * 
151
 * @param buf  pointer to a buffer pointer
152
 * @param buf_len      pointer to current size of buffer in bytes
153
 * 
154
 * @note
155
 * The current re-allocation algorithm is to increase the buffer size by
156
 * whichever is the greater of 256 bytes or the current buffer size, up to
157
 * a maximum increase of 8192 bytes.  
158
 */
159
int
160
snmp_realloc(u_char ** buf, size_t * buf_len)
161
0
{
162
0
    u_char         *new_buf = NULL;
163
0
    size_t          new_buf_len = 0;
164
165
0
    if (buf == NULL) {
166
0
        return 0;
167
0
    }
168
169
0
    if (*buf_len <= 255) {
170
0
        new_buf_len = *buf_len + 256;
171
0
    } else if (*buf_len > 255 && *buf_len <= 8191) {
172
0
        new_buf_len = *buf_len * 2;
173
0
    } else if (*buf_len > 8191) {
174
0
        new_buf_len = *buf_len + 8192;
175
0
    }
176
177
0
    if (*buf == NULL) {
178
0
        new_buf = malloc(new_buf_len);
179
0
    } else {
180
0
        new_buf = realloc(*buf, new_buf_len);
181
0
    }
182
183
0
    if (new_buf != NULL) {
184
0
        *buf = new_buf;
185
0
        *buf_len = new_buf_len;
186
0
        return 1;
187
0
    } else {
188
0
        return 0;
189
0
    }
190
0
}
191
192
int
193
snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
194
            int allow_realloc, const u_char * s)
195
0
{
196
0
    if (buf == NULL || buf_len == NULL || out_len == NULL) {
197
0
        return 0;
198
0
    }
199
200
0
    if (s == NULL) {
201
        /*
202
         * Appending a NULL string always succeeds since it is a NOP.  
203
         */
204
0
        return 1;
205
0
    }
206
207
0
    while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
208
0
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
209
0
            return 0;
210
0
        }
211
0
    }
212
213
0
    if (!*buf)
214
0
        return 0;
215
216
0
    strcpy((char *) (*buf + *out_len), (const char *) s);
217
0
    *out_len += strlen((char *) (*buf + *out_len));
218
0
    return 1;
219
0
}
220
221
/** zeros memory before freeing it.
222
 *
223
 *  @param *buf Pointer at bytes to free.
224
 *  @param size Number of bytes in buf.
225
 */
226
void
227
free_zero(void *buf, size_t size)
228
0
{
229
0
    if (buf) {
230
0
        memset(buf, 0, size);
231
0
        free(buf);
232
0
    }
233
234
0
}                               /* end free_zero() */
235
236
#ifndef NETSNMP_FEATURE_REMOVE_USM_SCAPI
237
/**
238
 * Returns pointer to allocated & set buffer on success, size contains
239
 * number of random bytes filled.  buf is NULL and *size set to KMT
240
 * error value upon failure.
241
 *
242
 *  @param size Number of bytes to malloc() and fill with random bytes.
243
 *
244
 * @return a malloced buffer
245
 *
246
 */
247
u_char         *
248
malloc_random(size_t * size)
249
0
{
250
0
    int             rval = SNMPERR_SUCCESS;
251
0
    u_char         *buf = calloc(1, *size);
252
253
0
    if (buf) {
254
0
        rval = sc_random(buf, size);
255
256
0
        if (rval < 0) {
257
0
            free_zero(buf, *size);
258
0
            buf = NULL;
259
0
            *size = 0;
260
0
        }
261
0
    }
262
263
0
    return buf;
264
265
0
}                               /* end malloc_random() */
266
#endif /* NETSNMP_FEATURE_REMOVE_USM_SCAPI */
267
268
/**
269
 * Duplicates a memory block.
270
 *
271
 * @param[in] from Pointer to copy memory from.
272
 * @param[in] size Size of the data to be copied.
273
 *      
274
 * @return Pointer to the duplicated memory block, or NULL if memory allocation
275
 * failed.
276
 */
277
void *netsnmp_memdup(const void *from, size_t size)
278
5.81k
{
279
5.81k
    void *to = NULL;
280
281
5.81k
    if (from) {
282
5.81k
        to = malloc(size);
283
5.81k
        if (to)
284
5.81k
            memcpy(to, from, size);
285
5.81k
    }
286
5.81k
    return to;
287
5.81k
}                               /* end netsnmp_memdup() */
288
289
/**
290
 * Duplicates a memory block, adding a NULL at the end.
291
 *
292
 * NOTE: the returned size DOES NOT include the extra byte for the NULL
293
 *       termination, just the raw data (i.e. from_size).
294
 *
295
 * This is mainly to protect against code that uses str* functions on
296
 * a fixed buffer that may not have a terminating NULL.
297
 *
298
 * @param[in] from Pointer to copy memory from.
299
 * @param[in] from_size Size of the data to be copied.
300
 * @param[out] to_size Pointer to size var for new block (OPTIONAL)
301
 *
302
 * @return Pointer to the duplicated memory block, or NULL if memory allocation
303
 * failed.
304
 */
305
void *netsnmp_memdup_nt(const void *from, size_t from_size, size_t *to_size)
306
1.27k
{
307
1.27k
    char *to = NULL;
308
309
1.27k
    if (from) {
310
1.27k
        to = malloc(from_size+1);
311
1.27k
        if (to) {
312
1.27k
            memcpy(to, from, from_size);
313
1.27k
            to[from_size] = 0;
314
1.27k
            if (to_size)
315
1.27k
               *to_size = from_size;
316
1.27k
        }
317
1.27k
    }
318
1.27k
    return to;
319
1.27k
}                               /* end netsnmp_memdupNT() */
320
321
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_CHECK_DEFINEDNESS
322
/**
323
 * When running under Valgrind, check whether all bytes in the range [packet,
324
 * packet+length) are defined. Let Valgrind print a backtrace if one or more
325
 * bytes with uninitialized values have been found. This function can help to
326
 * find the cause of undefined value errors if --track-origins=yes is not
327
 * sufficient. Does nothing when not running under Valgrind.
328
 *
329
 * Note: this requires a fairly recent Valgrind.
330
 */
331
void
332
netsnmp_check_definedness(const void *packet, size_t length)
333
0
{
334
#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
335
    && (__VALGRIND_MAJOR__ > 3                                   \
336
        || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
337
338
    if (RUNNING_ON_VALGRIND) {
339
        int i;
340
        char vbits;
341
342
        for (i = 0; i < length; ++i) {
343
            if (VALGRIND_GET_VBITS((const char *)packet + i, &vbits, 1) == 1
344
                && vbits)
345
                VALGRIND_PRINTF_BACKTRACE("Undefined: byte %d/%d", i,
346
                                          (int)length);
347
        }
348
    }
349
350
#endif
351
0
}
352
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_CHECK_DEFINEDNESS */
353
354
/** copies a (possible) unterminated string of a given length into a
355
 *  new buffer and null terminates it as well (new buffer MAY be one
356
 *  byte longer to account for this */
357
char           *
358
netsnmp_strdup_and_null(const u_char * from, size_t from_len)
359
0
{
360
0
    char         *ret;
361
362
0
    if (from_len > 0 && from[from_len - 1] == '\0')
363
0
        from_len--;
364
0
    ret = malloc(from_len + 1);
365
0
    if (ret) {
366
0
        memcpy(ret, from, from_len);
367
0
        ret[from_len] = '\0';
368
0
    }
369
0
    return ret;
370
0
}
371
372
/** converts binary to hexidecimal
373
 *
374
 *     @param *input            Binary data.
375
 *     @param len               Length of binary data.
376
 *     @param **dest            NULL terminated string equivalent in hex.
377
 *     @param *dest_len         size of destination buffer
378
 *     @param allow_realloc     flag indicating if buffer can be realloc'd
379
 *      
380
 * @return olen Length of output string not including NULL terminator.
381
 */
382
u_int
383
netsnmp_binary_to_hex(u_char ** dest, size_t *dest_len, int allow_realloc, 
384
                      const u_char * input, size_t len)
385
0
{
386
0
    u_int           olen = (len * 2) + 1;
387
0
    u_char         *s, *op;
388
0
    const u_char   *ip = input;
389
390
0
    if (dest == NULL || dest_len == NULL || input == NULL)
391
0
        return 0;
392
393
0
    if (NULL == *dest) {
394
0
        s = calloc(1, olen);
395
0
        if (s == NULL)
396
0
            return 0;
397
0
        *dest = s;
398
0
        *dest_len = olen;
399
0
    } else {
400
0
        if (*dest_len < olen) {
401
0
            if (!allow_realloc)
402
0
                return 0;
403
0
            while (*dest_len < olen) {
404
0
                if (!snmp_realloc(dest, dest_len))
405
0
                    return 0;
406
0
            }
407
0
        }
408
0
        s = *dest;
409
0
    }
410
411
0
    op = s;
412
0
    while (ip - input < (int) len) {
413
0
        *op++ = VAL2HEX((*ip >> 4) & 0xf);
414
0
        *op++ = VAL2HEX(*ip & 0xf);
415
0
        ip++;
416
0
    }
417
0
    *op = '\0';
418
419
0
    *dest_len = olen;
420
421
0
    return olen;
422
423
0
}                               /* end netsnmp_binary_to_hex() */
424
425
/** converts binary to hexidecimal
426
 *
427
 *  @param *input   Binary data.
428
 *  @param len    Length of binary data.
429
 *  @param **output NULL terminated string equivalent in hex.
430
 *      
431
 * @return olen Length of output string not including NULL terminator.
432
 *
433
 * FIX  Is there already one of these in the UCD SNMP codebase?
434
 *  The old one should be used, or this one should be moved to
435
 *  snmplib/snmp_api.c.
436
 */
437
u_int
438
binary_to_hex(const u_char * input, size_t len, char **output)
439
0
{
440
0
    size_t out_len = 0;
441
442
0
    *output = NULL; /* will alloc new buffer */
443
444
0
    return netsnmp_binary_to_hex((u_char**)output, &out_len, 1, input, len);
445
0
}                               /* end binary_to_hex() */
446
447
448
449
450
/**
451
 * hex_to_binary2
452
 *  @param *input   Printable data in base16.
453
 *  @param len    Length in bytes of data.
454
 *  @param **output Binary data equivalent to input.
455
 *      
456
 * @return SNMPERR_GENERR on failure, otherwise length of allocated string.
457
 *
458
 * Input of an odd length is right aligned.
459
 *
460
 * FIX  Another version of "hex-to-binary" which takes odd length input
461
 *  strings.  It also allocates the memory to hold the binary data.
462
 *  Should be integrated with the official hex_to_binary() function.
463
 */
464
int
465
hex_to_binary2(const u_char * input, size_t len, char **output)
466
0
{
467
0
    u_int           olen = (len / 2) + (len % 2);
468
0
    char           *s = calloc(1, olen ? olen : 1), *op = s;
469
0
    const u_char   *ip = input;
470
471
472
0
    *output = NULL;
473
0
    if (!s)
474
0
        goto hex_to_binary2_quit;
475
476
0
    *op = 0;
477
0
    if (len % 2) {
478
0
        if (!isxdigit(*ip))
479
0
            goto hex_to_binary2_quit;
480
0
        *op++ = HEX2VAL(*ip);
481
0
        ip++;
482
0
    }
483
484
0
    while (ip < input + len) {
485
0
        if (!isxdigit(*ip))
486
0
            goto hex_to_binary2_quit;
487
0
        *op = HEX2VAL(*ip) << 4;
488
0
        ip++;
489
490
0
        if (!isxdigit(*ip))
491
0
            goto hex_to_binary2_quit;
492
0
        *op++ += HEX2VAL(*ip);
493
0
        ip++;
494
0
    }
495
496
0
    *output = s;
497
0
    return olen;
498
499
0
  hex_to_binary2_quit:
500
0
    free_zero(s, olen);
501
0
    return -1;
502
503
0
}                               /* end hex_to_binary2() */
504
505
int
506
snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
507
                       int allow_realloc, const char *decimal)
508
0
{
509
0
    int             subid = 0;
510
0
    const char     *cp = decimal;
511
512
0
    if (buf == NULL || buf_len == NULL || out_len == NULL
513
0
        || decimal == NULL) {
514
0
        return 0;
515
0
    }
516
517
0
    while (*cp != '\0') {
518
0
        if (isspace((int) *cp) || *cp == '.') {
519
0
            cp++;
520
0
            continue;
521
0
        }
522
0
        if (!isdigit((int) *cp)) {
523
0
            return 0;
524
0
        }
525
0
        if ((subid = atoi(cp)) > 255) {
526
0
            return 0;
527
0
        }
528
0
        if ((*out_len >= *buf_len) &&
529
0
            !(allow_realloc && snmp_realloc(buf, buf_len))) {
530
0
            return 0;
531
0
        }
532
0
        *(*buf + *out_len) = (u_char) subid;
533
0
        (*out_len)++;
534
0
        while (isdigit((int) *cp)) {
535
0
            cp++;
536
0
        }
537
0
    }
538
0
    return 1;
539
0
}
540
541
/**
542
 * convert an ASCII hex string (with specified delimiters) to binary
543
 *
544
 * @param buf     address of a pointer (pointer to pointer) for the output buffer.
545
 *                If allow_realloc is set, the buffer may be grown via snmp_realloc
546
 *                to accommodate the data.
547
 *
548
 * @param buf_len pointer to a size_t containing the initial size of buf.
549
 *
550
 * @param offset On input, a pointer to a size_t indicating an offset into buf.
551
 *                The  binary data will be stored at this offset.
552
 *                On output, this pointer will have updated the offset to be
553
 *                the first byte after the converted data.
554
 *
555
 * @param allow_realloc If true, the buffer can be reallocated. If false, and
556
 *                      the buffer is not large enough to contain the string,
557
 *                      an error will be returned.
558
 *
559
 * @param hex     pointer to hex string to be converted. May be prefixed by
560
 *                "0x" or "0X".
561
 *
562
 * @param delim   point to a string of allowed delimiters between bytes.
563
 *                If not specified, any non-hex characters will be an error.
564
 *
565
 * @retval 1  success
566
 * @retval 0  error
567
 */
568
int
569
netsnmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * offset,
570
                      int allow_realloc, const char *hex, const char *delim)
571
0
{
572
0
    unsigned int    subid = 0;
573
0
    const char     *cp = hex;
574
575
0
    if (buf == NULL || buf_len == NULL || offset == NULL || hex == NULL) {
576
0
        return 0;
577
0
    }
578
579
0
    if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
580
0
        cp += 2;
581
0
    }
582
583
0
    while (*cp != '\0') {
584
0
        if (!isxdigit((unsigned char)cp[0]) ||
585
0
            !isxdigit((unsigned char)cp[1])) {
586
0
            if ((NULL != delim) && (NULL != strchr(delim, *cp))) {
587
0
                cp++;
588
0
                continue;
589
0
            }
590
0
            return 0;
591
0
        }
592
0
        if (sscanf(cp, "%2x", &subid) == 0) {
593
0
            return 0;
594
0
        }
595
        /*
596
         * if we don't have enough space, realloc.
597
         * (snmp_realloc will adjust buf_len to new size)
598
         */
599
0
        if ((*offset >= *buf_len) &&
600
0
            !(allow_realloc && snmp_realloc(buf, buf_len))) {
601
0
            return 0;
602
0
        }
603
0
        *(*buf + *offset) = (u_char) subid;
604
0
        (*offset)++;
605
0
        if (*++cp == '\0') {
606
            /*
607
             * Odd number of hex digits is an error.  
608
             */
609
0
            return 0;
610
0
        } else {
611
0
            cp++;
612
0
        }
613
0
    }
614
0
    return 1;
615
0
}
616
617
/**
618
 * convert an ASCII hex string to binary
619
 *
620
 * @note This is a wrapper which calls netsnmp_hex_to_binary with a
621
 * delimiter string of " ".
622
 *
623
 * See netsnmp_hex_to_binary for parameter descriptions.
624
 *
625
 * @retval 1  success
626
 * @retval 0  error
627
 */
628
int
629
snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * offset,
630
                   int allow_realloc, const char *hex)
631
0
{
632
0
    return netsnmp_hex_to_binary(buf, buf_len, offset, allow_realloc, hex, " ");
633
0
}
634
635
/*******************************************************************-o-******
636
 * dump_chunk
637
 *
638
 * Parameters:
639
 *  *title  (May be NULL.)
640
 *  *buf
641
 *   size
642
 */
643
void
644
dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
645
           int size)
646
0
{
647
0
    int             printunit = 64;     /* XXX  Make global. */
648
0
    char            chunk[SNMP_MAXBUF], *s, *sp;
649
650
0
    if (title && (*title != '\0')) {
651
0
        DEBUGMSGTL((debugtoken, "%s\n", title));
652
0
    }
653
654
655
0
    memset(chunk, 0, SNMP_MAXBUF);
656
0
    size = binary_to_hex(buf, size, &s);
657
0
    sp = s;
658
659
0
    while (size > 0) {
660
0
        if (size > printunit) {
661
0
            memcpy(chunk, sp, printunit);
662
0
            chunk[printunit] = '\0';
663
0
            DEBUGMSGTL((debugtoken, "\t%s\n", chunk));
664
0
        } else {
665
0
            DEBUGMSGTL((debugtoken, "\t%s\n", sp));
666
0
        }
667
668
0
        sp += printunit;
669
0
        size -= printunit;
670
0
    }
671
672
673
0
    SNMP_FREE(s);
674
675
0
}                               /* end dump_chunk() */
676
677
678
679
680
/*******************************************************************-o-******
681
 * dump_snmpEngineID
682
 *
683
 * Parameters:
684
 *  *estring
685
 *  *estring_len
686
 *      
687
 * Returns:
688
 *  Allocated memory pointing to a string of buflen char representing
689
 *  a printf'able form of the snmpEngineID.
690
 *
691
 *  -OR- NULL on error.
692
 *
693
 *
694
 * Translates the snmpEngineID TC into a printable string.  From RFC 2271,
695
 * Section 5 (pp. 36-37):
696
 *
697
 * First bit: 0 Bit string structured by means non-SNMPv3.
698
 *      1 Structure described by SNMPv3 SnmpEngineID TC.
699
 *  
700
 * Bytes 1-4:   Enterprise ID.  (High bit of first byte is ignored.)
701
 *  
702
 * Byte 5:  0 (RESERVED by IANA.)
703
 *      1 IPv4 address.   (   4 octets)
704
 *      2 IPv6 address.   (  16 octets)
705
 *      3 MAC address.    (   6 octets)
706
 *      4 Locally defined text. (0-27 octets)
707
 *      5 Locally defined octets. (0-27 octets)
708
 *      6-127 (RESERVED for enterprise.)
709
 *  
710
 * Bytes 6-32:    (Determined by byte 5.)
711
 *  
712
 *
713
 * Non-printable characters are given in hex.  Text is given in quotes.
714
 * IP and MAC addresses are given in standard (UN*X) conventions.  Sections
715
 * are comma separated.
716
 *
717
 * esp, remaining_len and s trace the state of the constructed buffer.
718
 * s will be defined if there is something to return, and it will point
719
 * to the end of the constructed buffer.
720
 *
721
 *
722
 * ASSUME  "Text" means printable characters.
723
 *
724
 * XXX  Must the snmpEngineID always have a minimum length of 12?
725
 *  (Cf. part 2 of the TC definition.)
726
 * XXX  Does not enforce upper-bound of 32 bytes.
727
 * XXX  Need a switch to decide whether to use DNS name instead of a simple
728
 *  IP address.
729
 *
730
 * FIX  Use something other than snprint_hexstring which doesn't add 
731
 *  trailing spaces and (sometimes embedded) newlines...
732
 */
733
#ifdef NETSNMP_ENABLE_TESTING_CODE
734
char           *
735
dump_snmpEngineID(const u_char * estring, size_t * estring_len)
736
{
737
#define eb(b) ( *(esp+b) & 0xff )
738
739
    int             gotviolation = 0, slen = 0;
740
    u_int           remaining_len;
741
742
    char            buf[SNMP_MAXBUF], *s = NULL, *t;
743
    const u_char   *esp = estring;
744
745
    struct in_addr  iaddr;
746
747
748
749
    /*
750
     * Sanity check.
751
     */
752
    if (!estring || (*estring_len <= 0)) {
753
        goto dump_snmpEngineID_quit;
754
    }
755
    remaining_len = *estring_len;
756
    memset(buf, 0, SNMP_MAXBUF);
757
758
759
760
    /*
761
     * Test first bit.  Return immediately with a hex string, or
762
     * begin by formatting the enterprise ID.
763
     */
764
    if (!(*esp & 0x80)) {
765
        snprint_hexstring(buf, SNMP_MAXBUF, esp, remaining_len);
766
        s = strchr(buf, '\0');
767
        s -= 1;
768
        goto dump_snmpEngineID_quit;
769
    }
770
771
    s = buf;
772
    s += snprintf(s, sizeof(buf) - (s - buf), "enterprise %d, ",
773
                 ((*(esp + 0) & 0x7f) << 24) |
774
                 ((*(esp + 1) & 0xff) << 16) |
775
                 ((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
776
    /*
777
     * XXX  Ick. 
778
     */
779
780
    if (remaining_len < 5) {    /* XXX  Violating string. */
781
        goto dump_snmpEngineID_quit;
782
    }
783
784
    esp += 4;                   /* Incremented one more in the switch below. */
785
    remaining_len -= 5;
786
787
788
789
    /*
790
     * Act on the fifth byte.
791
     */
792
    switch ((int) *esp++) {
793
    case 1:                    /* IPv4 address. */
794
795
        if (remaining_len < 4)
796
            goto dump_snmpEngineID_violation;
797
        memcpy(&iaddr.s_addr, esp, 4);
798
799
        if (!(t = inet_ntoa(iaddr)))
800
            goto dump_snmpEngineID_violation;
801
        s += snprintf(s, sizeof(buf) - (s - buf), "%s", t);
802
803
        esp += 4;
804
        remaining_len -= 4;
805
        break;
806
807
    case 2:                    /* IPv6 address. */
808
809
        if (remaining_len < 16)
810
            goto dump_snmpEngineID_violation;
811
812
        s += snprintf(s, sizeof(buf) - (s - buf),
813
                     "%02X%02X %02X%02X %02X%02X %02X%02X::"
814
                     "%02X%02X %02X%02X %02X%02X %02X%02X",
815
                     eb(0), eb(1), eb(2), eb(3),
816
                     eb(4), eb(5), eb(6), eb(7),
817
                     eb(8), eb(9), eb(10), eb(11),
818
                     eb(12), eb(13), eb(14), eb(15));
819
820
        esp += 16;
821
        remaining_len -= 16;
822
        break;
823
824
    case 3:                    /* MAC address. */
825
826
        if (remaining_len < 6)
827
            goto dump_snmpEngineID_violation;
828
829
        s += snprintf(s, sizeof(buf) - (s - buf), "%02X:%02X:%02X:%02X:%02X:%02X",
830
                     eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
831
832
        esp += 6;
833
        remaining_len -= 6;
834
        break;
835
836
    case 4:                    /* Text. */
837
838
        s += snprintf(s, sizeof(buf) - (s - buf), "\"%.*s\"", (int) (sizeof(buf)-strlen(buf)-3), esp);
839
        goto dump_snmpEngineID_quit;
840
        break;
841
842
     /*NOTREACHED*/ case 5:    /* Octets. */
843
844
        snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
845
                          esp, remaining_len);
846
        s = strchr(buf, '\0');
847
        s -= 1;
848
        goto dump_snmpEngineID_quit;
849
        break;
850
851
       /*NOTREACHED*/ dump_snmpEngineID_violation:
852
    case 0:                    /* Violation of RESERVED, 
853
                                 * *   -OR- of expected length.
854
                                 */
855
        gotviolation = 1;
856
        s += snprintf(s, sizeof(buf) - (s - buf), "!!! ");
857
        NETSNMP_FALLTHROUGH;
858
859
    default:                   /* Unknown encoding. */
860
861
        if (!gotviolation) {
862
            s += snprintf(s, sizeof(buf) - (s - buf), "??? ");
863
        }
864
        snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
865
                          esp, remaining_len);
866
        s = strchr(buf, '\0');
867
        s -= 1;
868
869
        goto dump_snmpEngineID_quit;
870
871
    }                           /* endswitch */
872
873
874
875
    /*
876
     * Cases 1-3 (IP and MAC addresses) should not have trailing
877
     * octets, but perhaps they do.  Throw them in too.  XXX
878
     */
879
    if (remaining_len > 0) {
880
        s += snprintf(s, sizeof(buf) - (s - buf), " (??? ");
881
882
        snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
883
                          esp, remaining_len);
884
        s = strchr(buf, '\0');
885
        s -= 1;
886
887
        s += snprintf(s, sizeof(buf) - (s - buf), ")");
888
    }
889
890
891
892
  dump_snmpEngineID_quit:
893
    if (s) {
894
        slen = s - buf + 1;
895
        s = calloc(1, slen);
896
        memcpy(s, buf, (slen) - 1);
897
    }
898
899
    memset(buf, 0, SNMP_MAXBUF);        /* XXX -- Overkill? XXX: Yes! */
900
901
    return s;
902
903
#undef eb
904
}                               /* end dump_snmpEngineID() */
905
#endif                          /* NETSNMP_ENABLE_TESTING_CODE */
906
907
908
/**
909
 * Create a new real-time marker.
910
 *
911
 * \deprecated Use netsnmp_set_monotonic_marker() instead.
912
 *
913
 * @note Caller must free time marker when no longer needed.
914
 */
915
marker_t
916
atime_newMarker(void)
917
0
{
918
0
    marker_t        pm = calloc(1, sizeof(struct timeval));
919
0
    gettimeofday((struct timeval *) pm, NULL);
920
0
    return pm;
921
0
}
922
923
/**
924
 * Set a time marker to the current value of the real-time clock.
925
 * \deprecated Use netsnmp_set_monotonic_marker() instead.
926
 */
927
void
928
atime_setMarker(marker_t pm)
929
0
{
930
0
    if (!pm)
931
0
        return;
932
933
0
    gettimeofday((struct timeval *) pm, NULL);
934
0
}
935
936
/**
937
 * Query the current value of the monotonic clock.
938
 *
939
 * Returns the current value of a monotonic clock if such a clock is provided by
940
 * the operating system or the wall clock time if no such clock is provided by
941
 * the operating system. A monotonic clock is a clock that is never adjusted
942
 * backwards and that proceeds at the same rate as wall clock time.
943
 *
944
 * @param[out] tv Pointer to monotonic clock time.
945
 */
946
void netsnmp_get_monotonic_clock(struct timeval* tv)
947
590
{
948
590
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
949
590
    struct timespec ts;
950
590
    int res;
951
952
590
    res = clock_gettime(CLOCK_MONOTONIC, &ts);
953
590
    if (res >= 0) {
954
590
        tv->tv_sec = ts.tv_sec;
955
590
        tv->tv_usec = ts.tv_nsec / 1000;
956
590
    } else {
957
0
        gettimeofday(tv, NULL);
958
0
    }
959
#elif defined(WIN32)
960
    /*
961
     * Windows: return tick count. Note: the rate at which the tick count
962
     * increases is not adjusted by the time synchronization algorithm, so
963
     * expect an error of <= 100 ppm for the rate at which this clock
964
     * increases.
965
     */
966
    typedef ULONGLONG (WINAPI * pfGetTickCount64)(void);
967
    static int s_initialized;
968
    static pfGetTickCount64 s_pfGetTickCount64;
969
    uint64_t now64;
970
971
    if (!s_initialized) {
972
        HMODULE hKernel32 = GetModuleHandle("kernel32");
973
        s_pfGetTickCount64 =
974
            (pfGetTickCount64) GetProcAddress(hKernel32, "GetTickCount64");
975
        s_initialized = TRUE;
976
    }
977
978
    if (s_pfGetTickCount64) {
979
        /* Windows Vista, Windows 2008 or any later Windows version */
980
        now64 = (*s_pfGetTickCount64)();
981
    } else {
982
        /* Windows XP, Windows 2003 or any earlier Windows version */
983
        static uint32_t s_wraps, s_last;
984
        uint32_t now;
985
986
        now = GetTickCount();
987
        if (now < s_last)
988
            s_wraps++;
989
        s_last = now;
990
        now64 = ((uint64_t)s_wraps << 32) | now;
991
    }
992
    tv->tv_sec = now64 / 1000;
993
    tv->tv_usec = (now64 % 1000) * 1000;
994
#else
995
    /* At least FreeBSD 4 doesn't provide monotonic clock support. */
996
#warning Not sure how to query a monotonically increasing clock on your system. \
997
Timers will not work correctly if the system clock is adjusted by e.g. ntpd.
998
    gettimeofday(tv, NULL);
999
#endif
1000
590
}
1001
1002
/**
1003
 * Set a time marker to the current value of the monotonic clock.
1004
 */
1005
void
1006
netsnmp_set_monotonic_marker(marker_t *pm)
1007
0
{
1008
0
    if (!*pm)
1009
0
        *pm = malloc(sizeof(struct timeval));
1010
0
    if (*pm)
1011
0
        netsnmp_get_monotonic_clock(*pm);
1012
0
}
1013
1014
/**
1015
 * Returns the difference (in msec) between the two markers
1016
 *
1017
 * \deprecated Don't use in new code.
1018
 */
1019
long
1020
atime_diff(const_marker_t first, const_marker_t second)
1021
0
{
1022
0
    struct timeval diff;
1023
1024
0
    NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
1025
1026
0
    return (long)(diff.tv_sec * 1000 + diff.tv_usec / 1000);
1027
0
}
1028
1029
/**
1030
 * Returns the difference (in u_long msec) between the two markers
1031
 *
1032
 * \deprecated Don't use in new code.
1033
 */
1034
u_long
1035
uatime_diff(const_marker_t first, const_marker_t second)
1036
0
{
1037
0
    struct timeval diff;
1038
1039
0
    NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
1040
1041
0
    return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
1042
0
}
1043
1044
/**
1045
 * Returns the difference (in u_long 1/100th secs) between the two markers
1046
 * (functionally this is what sysUpTime needs)
1047
 *
1048
 * \deprecated Don't use in new code.
1049
 */
1050
u_long
1051
uatime_hdiff(const_marker_t first, const_marker_t second)
1052
0
{
1053
0
    struct timeval diff;
1054
1055
0
    NETSNMP_TIMERSUB((const struct timeval *) second, (const struct timeval *) first, &diff);
1056
0
    return ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
1057
0
}
1058
1059
/**
1060
 * Test: Has (marked time plus delta) exceeded current time ?
1061
 * Returns 0 if test fails or cannot be tested (no marker).
1062
 *
1063
 * \deprecated Use netsnmp_ready_monotonic() instead.
1064
 */
1065
int
1066
atime_ready(const_marker_t pm, int delta_ms)
1067
0
{
1068
0
    marker_t        now;
1069
0
    long            diff;
1070
0
    if (!pm)
1071
0
        return 0;
1072
1073
0
    now = atime_newMarker();
1074
0
    if (!now)
1075
0
        return 0;
1076
1077
0
    diff = atime_diff(pm, now);
1078
0
    free(now);
1079
0
    if (diff < delta_ms)
1080
0
        return 0;
1081
1082
0
    return 1;
1083
0
}
1084
1085
#ifndef NETSNMP_FEATURE_REMOVE_UATIME_READY
1086
/**
1087
 * Test: Has (marked time plus delta) exceeded current time ?
1088
 * Returns 0 if test fails or cannot be tested (no marker).
1089
 *
1090
 * \deprecated Use netsnmp_ready_monotonic() instead.
1091
 */
1092
int
1093
uatime_ready(const_marker_t pm, unsigned int delta_ms)
1094
0
{
1095
0
    marker_t        now;
1096
0
    u_long          diff;
1097
0
    if (!pm)
1098
0
        return 0;
1099
1100
0
    now = atime_newMarker();
1101
0
    if (!now)
1102
0
        return 0;
1103
1104
0
    diff = uatime_diff(pm, now);
1105
0
    free(now);
1106
0
    if (diff < delta_ms)
1107
0
        return 0;
1108
1109
0
    return 1;
1110
0
}
1111
#endif /* NETSNMP_FEATURE_REMOVE_UATIME_READY */
1112
1113
/**
1114
 * Is the current time past (marked time plus delta) ?
1115
 *
1116
 * @param[in] pm Pointer to marked time as obtained via
1117
 *   netsnmp_set_monotonic_marker().
1118
 * @param[in] delta_ms Time delta in milliseconds.
1119
 *
1120
 * @return pm != NULL && now >= (*pm + delta_ms)
1121
 */
1122
int
1123
netsnmp_ready_monotonic(const_marker_t pm, int delta_ms)
1124
0
{
1125
0
    struct timeval  now, diff, delta;
1126
1127
0
    netsnmp_assert(delta_ms >= 0);
1128
0
    if (pm) {
1129
0
        netsnmp_get_monotonic_clock(&now);
1130
0
        NETSNMP_TIMERSUB(&now, (const struct timeval *) pm, &diff);
1131
0
        delta.tv_sec = delta_ms / 1000;
1132
0
        delta.tv_usec = (delta_ms % 1000) * 1000UL;
1133
0
        return timercmp(&diff, &delta, >=) ? TRUE : FALSE;
1134
0
    } else {
1135
0
        return FALSE;
1136
0
    }
1137
0
}
1138
1139
1140
        /*
1141
         * Time-related utility functions
1142
         */
1143
1144
/**
1145
 * Return the number of timeTicks since the given marker
1146
 *
1147
 * \deprecated Don't use in new code.
1148
 */
1149
int
1150
marker_tticks(const_marker_t pm)
1151
0
{
1152
0
    int             res;
1153
0
    marker_t        now = atime_newMarker();
1154
0
    if (!now)
1155
0
        return 0;
1156
1157
0
    res = atime_diff(pm, now);
1158
0
    free(now);
1159
0
    return res / 10;            /* atime_diff works in msec, not csec */
1160
0
}
1161
1162
#ifndef NETSNMP_FEATURE_REMOVE_TIMEVAL_TTICKS
1163
/**
1164
 * \deprecated Don't use in new code.
1165
 */
1166
int
1167
timeval_tticks(const struct timeval *tv)
1168
0
{
1169
0
    return marker_tticks((const_marker_t) tv);
1170
0
}
1171
#endif /* NETSNMP_FEATURE_REMOVE_TIMEVAL_TTICKS */
1172
1173
/**
1174
 * Non Windows:  Returns a pointer to the desired environment variable  
1175
 *               or NULL if the environment variable does not exist.  
1176
 *               
1177
 * Windows:      Returns a pointer to the desired environment variable  
1178
 *               if it exists.  If it does not, the variable is looked up
1179
 *               in the registry in HKCU\\Net-SNMP or HKLM\\Net-SNMP
1180
 *               (whichever it finds first) and stores the result in the 
1181
 *               environment variable.  It then returns a pointer to 
1182
 *               environment variable.
1183
 */
1184
1185
char *netsnmp_getenv(const char *name)
1186
14
{
1187
14
#if !defined (WIN32) && !defined (cygwin)
1188
14
  return (getenv(name));
1189
#else
1190
  char *temp = NULL;  
1191
  HKEY hKey;
1192
  unsigned char * key_value = NULL;
1193
  DWORD key_value_size = 0;
1194
  DWORD key_value_type = 0;
1195
  DWORD getenv_worked = 0;
1196
1197
  DEBUGMSGTL(("read_config", "netsnmp_getenv called with name: %s\n",name));
1198
1199
  if (!(name))
1200
    return NULL;
1201
  
1202
  /* Try environment variable first */ 
1203
  temp = getenv(name);
1204
  if (temp) {
1205
    getenv_worked = 1;
1206
    DEBUGMSGTL(("read_config", "netsnmp_getenv will return from ENV: %s\n",temp));
1207
  }
1208
  
1209
  /* Next try HKCU */
1210
  if (temp == NULL)
1211
  {
1212
    if (getenv("SNMP_IGNORE_WINDOWS_REGISTRY"))
1213
      return NULL;
1214
1215
    if (RegOpenKeyExA(
1216
          HKEY_CURRENT_USER, 
1217
          "SOFTWARE\\Net-SNMP", 
1218
          0, 
1219
          KEY_QUERY_VALUE, 
1220
          &hKey) == ERROR_SUCCESS) {   
1221
      
1222
      if (RegQueryValueExA(
1223
            hKey, 
1224
            name, 
1225
            NULL, 
1226
            &key_value_type, 
1227
            NULL,               /* Just get the size */
1228
            &key_value_size) == ERROR_SUCCESS) {
1229
1230
        SNMP_FREE(key_value);
1231
1232
        /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
1233
         * string data in registry is missing one (which is unlikely).
1234
         */
1235
        key_value = malloc((sizeof(char) * key_value_size)+sizeof(char));
1236
        
1237
        if (RegQueryValueExA(
1238
              hKey, 
1239
              name, 
1240
              NULL, 
1241
              &key_value_type, 
1242
              key_value, 
1243
              &key_value_size) == ERROR_SUCCESS) {
1244
        }
1245
        temp = (char *) key_value;
1246
      }
1247
      RegCloseKey(hKey);
1248
      if (temp)
1249
        DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKCU: %s\n",temp));
1250
    }
1251
  }
1252
1253
  /* Next try HKLM */
1254
  if (temp == NULL)
1255
  {
1256
    if (RegOpenKeyExA(
1257
          HKEY_LOCAL_MACHINE, 
1258
          "SOFTWARE\\Net-SNMP", 
1259
          0, 
1260
          KEY_QUERY_VALUE, 
1261
          &hKey) == ERROR_SUCCESS) {   
1262
      
1263
      if (RegQueryValueExA(
1264
            hKey, 
1265
            name, 
1266
            NULL, 
1267
            &key_value_type, 
1268
            NULL,               /* Just get the size */
1269
            &key_value_size) == ERROR_SUCCESS) {
1270
1271
        SNMP_FREE(key_value);
1272
1273
        /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
1274
         * string data in registry is missing one (which is unlikely).
1275
         */
1276
        key_value = malloc((sizeof(char) * key_value_size)+sizeof(char));
1277
        
1278
        if (RegQueryValueExA(
1279
              hKey, 
1280
              name, 
1281
              NULL, 
1282
              &key_value_type, 
1283
              key_value, 
1284
              &key_value_size) == ERROR_SUCCESS) {
1285
        }
1286
        temp = (char *) key_value;
1287
1288
      }
1289
      RegCloseKey(hKey);
1290
      if (temp)
1291
        DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKLM: %s\n",temp));
1292
    }
1293
  }
1294
  
1295
  if (temp && !getenv_worked) {
1296
    setenv(name, temp, 1);
1297
    SNMP_FREE(temp);
1298
  }
1299
1300
  DEBUGMSGTL(("read_config", "netsnmp_getenv returning: %s\n",getenv(name)));
1301
1302
  return(getenv(name));
1303
#endif
1304
14
}
1305
1306
/**
1307
 * Set an environment variable.
1308
 *
1309
 * This function is only necessary on Windows for the MSVC and MinGW
1310
 * environments. If the process that uses the Net-SNMP DLL (e.g. a Perl
1311
 * interpreter) and the Net-SNMP have been built with a different compiler
1312
 * version then each will have a separate set of environment variables.
1313
 * This function allows to set an environment variable such that it gets
1314
 * noticed by the Net-SNMP DLL.
1315
 */
1316
int netsnmp_setenv(const char *envname, const char *envval, int overwrite)
1317
0
{
1318
0
    return setenv(envname, envval, overwrite);
1319
0
}
1320
1321
/*
1322
 * swap the order of an inet addr string
1323
 */
1324
int
1325
netsnmp_addrstr_hton(char *ptr, size_t len)
1326
0
{
1327
0
    char tmp[8];
1328
    
1329
0
    if (!NETSNMP_BIGENDIAN) {
1330
0
        if (8 == len) {
1331
0
            tmp[0] = ptr[6];
1332
0
            tmp[1] = ptr[7];
1333
0
            tmp[2] = ptr[4];
1334
0
            tmp[3] = ptr[5];
1335
0
            tmp[4] = ptr[2];
1336
0
            tmp[5] = ptr[3];
1337
0
            tmp[6] = ptr[0];
1338
0
            tmp[7] = ptr[1];
1339
0
            memcpy(ptr, &tmp, 8);
1340
0
        }
1341
0
        else if (32 == len) {
1342
0
            netsnmp_addrstr_hton(ptr,      8);
1343
0
            netsnmp_addrstr_hton(ptr + 8,  8);
1344
0
            netsnmp_addrstr_hton(ptr + 16, 8);
1345
0
            netsnmp_addrstr_hton(ptr + 24, 8);
1346
0
        }
1347
0
        else
1348
0
            return -1;
1349
0
    }
1350
1351
0
    return 0;
1352
0
}
1353
1354
#ifndef NETSNMP_FEATURE_REMOVE_STRING_TIME_TO_SECS
1355
/**
1356
 * Takes a time string like 4h and converts it to seconds.
1357
 * The string time given may end in 's' for seconds (the default
1358
 * anyway if no suffix is specified),
1359
 * 'm' for minutes, 'h' for hours, 'd' for days, or 'w' for weeks.  The
1360
 * upper case versions are also accepted.
1361
 *
1362
 * @param time_string The time string to convert.
1363
 *
1364
 * @return seconds converted from the string
1365
 * @return -1  : on failure
1366
 */
1367
int
1368
0
netsnmp_string_time_to_secs(const char *time_string) {
1369
0
    int secs = -1;
1370
0
    if (!time_string || !time_string[0])
1371
0
        return secs;
1372
1373
0
    secs = atoi(time_string);
1374
1375
0
    if (isdigit((unsigned char)time_string[strlen(time_string)-1]))
1376
0
        return secs; /* no letter specified, it's already in seconds */
1377
    
1378
0
    switch (time_string[strlen(time_string)-1]) {
1379
0
    case 's':
1380
0
    case 'S':
1381
        /* already in seconds */
1382
0
        break;
1383
1384
0
    case 'm':
1385
0
    case 'M':
1386
0
        secs = secs * 60;
1387
0
        break;
1388
1389
0
    case 'h':
1390
0
    case 'H':
1391
0
        secs = secs * 60 * 60;
1392
0
        break;
1393
1394
0
    case 'd':
1395
0
    case 'D':
1396
0
        secs = secs * 60 * 60 * 24;
1397
0
        break;
1398
1399
0
    case 'w':
1400
0
    case 'W':
1401
0
        secs = secs * 60 * 60 * 24 * 7;
1402
0
        break;
1403
1404
0
    default:
1405
0
        snmp_log(LOG_ERR, "time string %s contains an invalid suffix letter\n",
1406
0
                 time_string);
1407
0
        return -1;
1408
0
    }
1409
1410
0
    DEBUGMSGTL(("string_time_to_secs", "Converted time string %s to %d\n",
1411
0
                time_string, secs));
1412
0
    return secs;
1413
0
}
1414
#endif /* NETSNMP_FEATURE_REMOVE_STRING_TIME_TO_SECS */
1415
1416
4
const char *netsnmp_gethomedir(void) {
1417
4
    const char *homepath = netsnmp_getenv("HOME");
1418
#ifdef _WIN32
1419
    if (!homepath)
1420
        homepath = netsnmp_getenv("USERPROFILE");
1421
#endif
1422
4
    return homepath;
1423
4
}