Coverage Report

Created: 2023-06-07 06:42

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