/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 | } |