1 /*
2 * mib.c
3 *
4 * $Id$
5 *
6 * Update: 1998-07-17 <jhy@gsu.edu>
7 * Added print_oid_report* functions.
8 *
9 */
10 /* Portions of this file are subject to the following copyrights. See
11 * the Net-SNMP's COPYING file for more details and other copyrights
12 * that may apply:
13 */
14 /**********************************************************************
15 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
16
17 All Rights Reserved
18
19 Permission to use, copy, modify, and distribute this software and its
20 documentation for any purpose and without fee is hereby granted,
21 provided that the above copyright notice appear in all copies and that
22 both that copyright notice and this permission notice appear in
23 supporting documentation, and that the name of CMU not be
24 used in advertising or publicity pertaining to distribution of the
25 software without specific, written prior permission.
26
27 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
28 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
29 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
30 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
31 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
32 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
33 SOFTWARE.
34 ******************************************************************/
35 /*
36 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
37 * Use is subject to license terms specified in the COPYING file
38 * distributed with the Net-SNMP package.
39 *
40 * Portions of this file are copyrighted by:
41 * Copyright (c) 2016 VMware, Inc. All rights reserved.
42 * Use is subject to license terms specified in the COPYING file
43 * distributed with the Net-SNMP package.
44 */
45 #include <net-snmp/net-snmp-config.h>
46 #include <net-snmp/net-snmp-features.h>
47
48 #include <stdio.h>
49 #include <ctype.h>
50 #include <sys/types.h>
51
52 #if HAVE_DIRENT_H
53 # include <dirent.h>
54 # define NAMLEN(dirent) strlen((dirent)->d_name)
55 #else
56 # define dirent direct
57 # define NAMLEN(dirent) (dirent)->d_namlen
58 # if HAVE_SYS_NDIR_H
59 # include <sys/ndir.h>
60 # endif
61 # if HAVE_SYS_DIR_H
62 # include <sys/dir.h>
63 # endif
64 # if HAVE_NDIR_H
65 # include <ndir.h>
66 # endif
67 #endif
68
69 #ifdef HAVE_INTTYPES_H
70 #include <inttypes.h>
71 #endif
72 #if HAVE_NETINET_IN_H
73 #include <netinet/in.h>
74 #endif
75 #if TIME_WITH_SYS_TIME
76 # include <sys/time.h>
77 # include <time.h>
78 #else
79 # if HAVE_SYS_TIME_H
80 # include <sys/time.h>
81 # else
82 # include <time.h>
83 # endif
84 #endif
85 #if HAVE_STRING_H
86 #include <string.h>
87 #else
88 #include <strings.h>
89 #endif
90 #if HAVE_STDLIB_H
91 #include <stdlib.h>
92 #endif
93 #if HAVE_SYS_SELECT_H
94 #include <sys/select.h>
95 #endif
96
97 #if HAVE_UNISTD_H
98 #include <unistd.h>
99 #endif
100
101 #include <net-snmp/types.h>
102 #include <net-snmp/output_api.h>
103 #include <net-snmp/config_api.h>
104 #include <net-snmp/utilities.h>
105
106 #include <net-snmp/library/asn1.h>
107 #include <net-snmp/library/snmp_api.h>
108 #include <net-snmp/library/mib.h>
109 #include <net-snmp/library/parse.h>
110 #include <net-snmp/library/int64.h>
111 #include <net-snmp/library/snmp_client.h>
112
113 netsnmp_feature_child_of(mib_api, libnetsnmp);
114 netsnmp_feature_child_of(mib_strings_all, mib_api);
115
116 netsnmp_feature_child_of(mib_snprint, mib_strings_all);
117 netsnmp_feature_child_of(mib_snprint_description, mib_strings_all);
118 netsnmp_feature_child_of(mib_snprint_variable, mib_strings_all);
119 netsnmp_feature_child_of(mib_string_conversions, mib_strings_all);
120 netsnmp_feature_child_of(print_mib, mib_strings_all);
121 netsnmp_feature_child_of(snprint_objid, mib_strings_all);
122 netsnmp_feature_child_of(snprint_value, mib_strings_all);
123
124 netsnmp_feature_child_of(mib_to_asn_type, mib_api);
125
126 /** @defgroup mib_utilities mib parsing and datatype manipulation routines.
127 * @ingroup library
128 *
129 * @{
130 */
131
132 static char *uptimeString(u_long, char *, size_t);
133
134 #ifndef NETSNMP_DISABLE_MIB_LOADING
135 static struct tree *_get_realloc_symbol(const oid * objid, size_t objidlen,
136 struct tree *subtree,
137 u_char ** buf, size_t * buf_len,
138 size_t * out_len,
139 int allow_realloc,
140 int *buf_overflow,
141 struct index_list *in_dices,
142 size_t * end_of_known);
143
144 static int print_tree_node(u_char ** buf, size_t * buf_len,
145 size_t * out_len, int allow_realloc,
146 struct tree *tp, int width);
147 static void handle_mibdirs_conf(const char *token, char *line);
148 static void handle_mibs_conf(const char *token, char *line);
149 static void handle_mibfile_conf(const char *token, char *line);
150 #endif /*NETSNMP_DISABLE_MIB_LOADING */
151
152 static void _oid_finish_printing(const oid * objid, size_t objidlen,
153 u_char ** buf, size_t * buf_len,
154 size_t * out_len,
155 int allow_realloc, int *buf_overflow);
156
157 /*
158 * helper functions for get_module_node
159 */
160 #ifndef NETSNMP_DISABLE_MIB_LOADING
161 static int node_to_oid(struct tree *, oid *, size_t *);
162 static int _add_strings_to_oid(struct tree *, char *,
163 oid *, size_t *, size_t);
164 #else
165 static int _add_strings_to_oid(void *, char *,
166 oid *, size_t *, size_t);
167 #endif /* NETSNMP_DISABLE_MIB_LOADING */
168
169 #ifndef NETSNMP_DISABLE_MIB_LOADING
170 NETSNMP_IMPORT struct tree *tree_head;
171 static struct tree *tree_top;
172
173 NETSNMP_IMPORT struct tree *Mib;
174 struct tree *Mib; /* Backwards compatibility */
175 #endif /* NETSNMP_DISABLE_MIB_LOADING */
176
177 static char Standard_Prefix[] = ".1.3.6.1.2.1";
178
179 /*
180 * Set default here as some uses of read_objid require valid pointer.
181 */
182 #ifndef NETSNMP_DISABLE_MIB_LOADING
183 static char *Prefix = &Standard_Prefix[0];
184 #endif /* NETSNMP_DISABLE_MIB_LOADING */
185 typedef struct _PrefixList {
186 const char *str;
187 int len;
188 } *PrefixListPtr, PrefixList;
189
190 /*
191 * Here are the prefix strings.
192 * Note that the first one finds the value of Prefix or Standard_Prefix.
193 * Any of these MAY start with period; all will NOT end with period.
194 * Period is added where needed. See use of Prefix in this module.
195 */
196 PrefixList mib_prefixes[] = {
197 {&Standard_Prefix[0]}, /* placeholder for Prefix data */
198 {".iso.org.dod.internet.mgmt.mib-2"},
199 {".iso.org.dod.internet.experimental"},
200 {".iso.org.dod.internet.private"},
201 {".iso.org.dod.internet.snmpParties"},
202 {".iso.org.dod.internet.snmpSecrets"},
203 {NULL, 0} /* end of list */
204 };
205
206 enum inet_address_type {
207 IPV4 = 1,
208 IPV6 = 2,
209 IPV4Z = 3,
210 IPV6Z = 4,
211 DNS = 16
212 };
213
214
215 /**
216 * @internal
217 * Converts timeticks to hours, minutes, seconds string.
218 *
219 * @param timeticks The timeticks to convert.
220 * @param buf Buffer to write to, has to be at
221 * least 40 Bytes large.
222 *
223 * @return The buffer.
224 */
225 static char *
uptimeString(u_long timeticks,char * buf,size_t buflen)226 uptimeString(u_long timeticks, char *buf, size_t buflen)
227 {
228 int centisecs, seconds, minutes, hours, days;
229
230 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS)) {
231 snprintf(buf, buflen, "%lu", timeticks);
232 return buf;
233 }
234
235
236 centisecs = timeticks % 100;
237 timeticks /= 100;
238 days = timeticks / (60 * 60 * 24);
239 timeticks %= (60 * 60 * 24);
240
241 hours = timeticks / (60 * 60);
242 timeticks %= (60 * 60);
243
244 minutes = timeticks / 60;
245 seconds = timeticks % 60;
246
247 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT))
248 snprintf(buf, buflen, "%d:%d:%02d:%02d.%02d",
249 days, hours, minutes, seconds, centisecs);
250 else {
251 if (days == 0) {
252 snprintf(buf, buflen, "%d:%02d:%02d.%02d",
253 hours, minutes, seconds, centisecs);
254 } else if (days == 1) {
255 snprintf(buf, buflen, "%d day, %d:%02d:%02d.%02d",
256 days, hours, minutes, seconds, centisecs);
257 } else {
258 snprintf(buf, buflen, "%d days, %d:%02d:%02d.%02d",
259 days, hours, minutes, seconds, centisecs);
260 }
261 }
262 return buf;
263 }
264
265
266
267 /**
268 * @internal
269 * Prints the character pointed to if in human-readable ASCII range,
270 * otherwise prints a dot.
271 *
272 * @param buf Buffer to print the character to.
273 * @param ch Character to print.
274 */
275 static void
sprint_char(char * buf,const u_char ch)276 sprint_char(char *buf, const u_char ch)
277 {
278 if (isprint(ch) || isspace(ch)) {
279 sprintf(buf, "%c", (int) ch);
280 } else {
281 sprintf(buf, ".");
282 }
283 }
284
285
286
287 /**
288 * Prints a hexadecimal string into a buffer.
289 *
290 * The characters pointed by *cp are encoded as hexadecimal string.
291 *
292 * If allow_realloc is true the buffer will be (re)allocated to fit in the
293 * needed size. (Note: *buf may change due to this.)
294 *
295 * @param buf address of the buffer to print to.
296 * @param buf_len address to an integer containing the size of buf.
297 * @param out_len incremented by the number of characters printed.
298 * @param allow_realloc if not zero reallocate the buffer to fit the
299 * needed size.
300 * @param cp the array of characters to encode.
301 * @param line_len the array length of cp.
302 *
303 * @return 1 on success, or 0 on failure (out of memory, or buffer to
304 * small when not allowed to realloc.)
305 */
306 int
_sprint_hexstring_line(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const u_char * cp,size_t line_len)307 _sprint_hexstring_line(u_char ** buf, size_t * buf_len, size_t * out_len,
308 int allow_realloc, const u_char * cp, size_t line_len)
309 {
310 const u_char *tp;
311 const u_char *cp2 = cp;
312 size_t lenleft = line_len;
313
314 /*
315 * Make sure there's enough room for the hex output....
316 */
317 while ((*out_len + line_len*3+1) >= *buf_len) {
318 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
319 return 0;
320 }
321 }
322
323 /*
324 * .... and display the hex values themselves....
325 */
326 for (; lenleft >= 8; lenleft-=8) {
327 sprintf((char *) (*buf + *out_len),
328 "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1],
329 cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]);
330 *out_len += strlen((char *) (*buf + *out_len));
331 cp += 8;
332 }
333 for (; lenleft > 0; lenleft--) {
334 sprintf((char *) (*buf + *out_len), "%02X ", *cp++);
335 *out_len += strlen((char *) (*buf + *out_len));
336 }
337
338 /*
339 * .... plus (optionally) do the same for the ASCII equivalent.
340 */
341 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT)) {
342 while ((*out_len + line_len+5) >= *buf_len) {
343 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
344 return 0;
345 }
346 }
347 sprintf((char *) (*buf + *out_len), " [");
348 *out_len += strlen((char *) (*buf + *out_len));
349 for (tp = cp2; tp < cp; tp++) {
350 sprint_char((char *) (*buf + *out_len), *tp);
351 (*out_len)++;
352 }
353 sprintf((char *) (*buf + *out_len), "]");
354 *out_len += strlen((char *) (*buf + *out_len));
355 }
356 return 1;
357 }
358
359 int
sprint_realloc_hexstring(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const u_char * cp,size_t len)360 sprint_realloc_hexstring(u_char ** buf, size_t * buf_len, size_t * out_len,
361 int allow_realloc, const u_char * cp, size_t len)
362 {
363 int line_len = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
364 NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH);
365 if (line_len <= 0)
366 line_len = len;
367
368 for (; (int)len > line_len; len -= line_len) {
369 if(!_sprint_hexstring_line(buf, buf_len, out_len, allow_realloc, cp, line_len))
370 return 0;
371 *(*buf + (*out_len)++) = '\n';
372 *(*buf + *out_len) = 0;
373 cp += line_len;
374 }
375 if(!_sprint_hexstring_line(buf, buf_len, out_len, allow_realloc, cp, len))
376 return 0;
377 *(*buf + *out_len) = 0;
378 return 1;
379 }
380
381
382
383 /**
384 * Prints an ascii string into a buffer.
385 *
386 * The characters pointed by *cp are encoded as an ascii string.
387 *
388 * If allow_realloc is true the buffer will be (re)allocated to fit in the
389 * needed size. (Note: *buf may change due to this.)
390 *
391 * @param buf address of the buffer to print to.
392 * @param buf_len address to an integer containing the size of buf.
393 * @param out_len incremented by the number of characters printed.
394 * @param allow_realloc if not zero reallocate the buffer to fit the
395 * needed size.
396 * @param cp the array of characters to encode.
397 * @param len the array length of cp.
398 *
399 * @return 1 on success, or 0 on failure (out of memory, or buffer to
400 * small when not allowed to realloc.)
401 */
402 int
sprint_realloc_asciistring(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const u_char * cp,size_t len)403 sprint_realloc_asciistring(u_char ** buf, size_t * buf_len,
404 size_t * out_len, int allow_realloc,
405 const u_char * cp, size_t len)
406 {
407 int i;
408
409 for (i = 0; i < (int) len; i++) {
410 if (isprint(*cp) || isspace(*cp)) {
411 if (*cp == '\\' || *cp == '"') {
412 if ((*out_len >= *buf_len) &&
413 !(allow_realloc && snmp_realloc(buf, buf_len))) {
414 return 0;
415 }
416 *(*buf + (*out_len)++) = '\\';
417 }
418 if ((*out_len >= *buf_len) &&
419 !(allow_realloc && snmp_realloc(buf, buf_len))) {
420 return 0;
421 }
422 *(*buf + (*out_len)++) = *cp++;
423 } else {
424 if ((*out_len >= *buf_len) &&
425 !(allow_realloc && snmp_realloc(buf, buf_len))) {
426 return 0;
427 }
428 *(*buf + (*out_len)++) = '.';
429 cp++;
430 }
431 }
432 if ((*out_len >= *buf_len) &&
433 !(allow_realloc && snmp_realloc(buf, buf_len))) {
434 return 0;
435 }
436 *(*buf + *out_len) = '\0';
437 return 1;
438 }
439
440 /**
441 * Prints an octet string into a buffer.
442 *
443 * The variable var is encoded as octet string.
444 *
445 * If allow_realloc is true the buffer will be (re)allocated to fit in the
446 * needed size. (Note: *buf may change due to this.)
447 *
448 * @param buf Address of the buffer to print to.
449 * @param buf_len Address to an integer containing the size of buf.
450 * @param out_len Incremented by the number of characters printed.
451 * @param allow_realloc if not zero reallocate the buffer to fit the
452 * needed size.
453 * @param var The variable to encode.
454 * @param enums The enumeration ff this variable is enumerated. may be NULL.
455 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
456 * See RFC 1903 Section 3.1 for details. may be NULL.
457 * @param units Contents of the UNITS clause of the MIB. may be NULL.
458 *
459 * @return 1 on success, or 0 on failure (out of memory, or buffer to
460 * small when not allowed to realloc.)
461 */
462 int
sprint_realloc_octet_string(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)463 sprint_realloc_octet_string(u_char ** buf, size_t * buf_len,
464 size_t * out_len, int allow_realloc,
465 const netsnmp_variable_list * var,
466 const struct enum_list *enums, const char *hint,
467 const char *units)
468 {
469 size_t saved_out_len = *out_len;
470 const char *saved_hint = hint;
471 int hex = 0, x = 0;
472 u_char *cp;
473 int output_format, cnt;
474
475 if (var->type != ASN_OCTET_STR) {
476 if (!netsnmp_ds_get_boolean(
477 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
478 const char str[] = "Wrong Type (should be OCTET STRING): ";
479 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
480 return 0;
481 }
482 return sprint_realloc_by_type(buf, buf_len, out_len,
483 allow_realloc, var, NULL, NULL,
484 NULL);
485 }
486
487
488 if (hint) {
489 int repeat, width = 1;
490 long value;
491 char code = 'd', separ = 0, term = 0, ch, intbuf[32];
492 #define HEX2DIGIT_NEED_INIT 3
493 char hex2digit = HEX2DIGIT_NEED_INIT;
494 u_char *ecp;
495
496 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
497 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "STRING: ")) {
498 return 0;
499 }
500 }
501 cp = var->val.string;
502 ecp = cp + var->val_len;
503
504 while (cp < ecp) {
505 repeat = 1;
506 if (*hint) {
507 if (*hint == '*') {
508 repeat = *cp++;
509 hint++;
510 }
511 width = 0;
512 while ('0' <= *hint && *hint <= '9')
513 width = (width * 10) + (*hint++ - '0');
514 code = *hint++;
515 if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9')
516 && (width != 0
517 || (ch != 'x' && ch != 'd' && ch != 'o')))
518 separ = *hint++;
519 else
520 separ = 0;
521 if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9')
522 && (width != 0
523 || (ch != 'x' && ch != 'd' && ch != 'o')))
524 term = *hint++;
525 else
526 term = 0;
527 if (width == 0) /* Handle malformed hint strings */
528 width = 1;
529 }
530
531 while (repeat && cp < ecp) {
532 value = 0;
533 if (code != 'a' && code != 't') {
534 for (x = 0; x < width; x++) {
535 value = value * 256 + *cp++;
536 }
537 }
538 switch (code) {
539 case 'x':
540 if (HEX2DIGIT_NEED_INIT == hex2digit)
541 hex2digit = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
542 NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT);
543 /*
544 * if value is < 16, it will be a single hex digit. If the
545 * width is 1 (we are outputting a byte at a time), pat it
546 * to 2 digits if NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT is set
547 * or all of the following are true:
548 * - we do not have a separation character
549 * - there is no hint left (or there never was a hint)
550 *
551 * e.g. for the data 0xAA01BB, would anyone really ever
552 * want the string "AA1BB"??
553 */
554 if (((value < 16) && (1 == width)) &&
555 (hex2digit || ((0 == separ) && (0 == *hint)))) {
556 sprintf(intbuf, "0%lx", value);
557 } else {
558 sprintf(intbuf, "%lx", value);
559 }
560 if (!snmp_cstrcat
561 (buf, buf_len, out_len, allow_realloc, intbuf)) {
562 return 0;
563 }
564 break;
565 case 'd':
566 sprintf(intbuf, "%ld", value);
567 if (!snmp_cstrcat
568 (buf, buf_len, out_len, allow_realloc, intbuf)) {
569 return 0;
570 }
571 break;
572 case 'o':
573 sprintf(intbuf, "%lo", value);
574 if (!snmp_cstrcat
575 (buf, buf_len, out_len, allow_realloc, intbuf)) {
576 return 0;
577 }
578 break;
579 case 't': /* new in rfc 3411 */
580 case 'a':
581 /* A string hint gives the max size - we may not need this much */
582 cnt = SNMP_MIN(width, ecp - cp);
583 while ((*out_len + cnt + 1) > *buf_len) {
584 if (!allow_realloc || !snmp_realloc(buf, buf_len))
585 return 0;
586 }
587 if (memchr(cp, '\0', cnt) == NULL) {
588 /* No embedded '\0' - use memcpy() to preserve UTF-8 */
589 memcpy(*buf + *out_len, cp, cnt);
590 *out_len += cnt;
591 *(*buf + *out_len) = '\0';
592 } else if (!sprint_realloc_asciistring(buf, buf_len,
593 out_len, allow_realloc, cp, cnt)) {
594 return 0;
595 }
596 cp += cnt;
597 break;
598 default:
599 *out_len = saved_out_len;
600 if (snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
601 "(Bad hint ignored: ")
602 && snmp_cstrcat(buf, buf_len, out_len,
603 allow_realloc, saved_hint)
604 && snmp_cstrcat(buf, buf_len, out_len,
605 allow_realloc, ") ")) {
606 return sprint_realloc_octet_string(buf, buf_len,
607 out_len,
608 allow_realloc,
609 var, enums,
610 NULL, NULL);
611 } else {
612 return 0;
613 }
614 }
615
616 if (cp < ecp && separ) {
617 while ((*out_len + 1) >= *buf_len) {
618 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
619 return 0;
620 }
621 }
622 *(*buf + *out_len) = separ;
623 (*out_len)++;
624 *(*buf + *out_len) = '\0';
625 }
626 repeat--;
627 }
628
629 if (term && cp < ecp) {
630 while ((*out_len + 1) >= *buf_len) {
631 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
632 return 0;
633 }
634 }
635 *(*buf + *out_len) = term;
636 (*out_len)++;
637 *(*buf + *out_len) = '\0';
638 }
639 }
640
641 if (units) {
642 return (snmp_cstrcat
643 (buf, buf_len, out_len, allow_realloc, " ")
644 && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units));
645 }
646 if ((*out_len >= *buf_len) &&
647 !(allow_realloc && snmp_realloc(buf, buf_len))) {
648 return 0;
649 }
650 *(*buf + *out_len) = '\0';
651
652 return 1;
653 }
654
655 output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT);
656 if (0 == output_format) {
657 output_format = NETSNMP_STRING_OUTPUT_GUESS;
658 }
659 switch (output_format) {
660 case NETSNMP_STRING_OUTPUT_GUESS:
661 hex = 0;
662 for (cp = var->val.string, x = 0; x < (int) var->val_len; x++, cp++) {
663 if (!isprint(*cp) && !isspace(*cp)) {
664 hex = 1;
665 }
666 }
667 break;
668
669 case NETSNMP_STRING_OUTPUT_ASCII:
670 hex = 0;
671 break;
672
673 case NETSNMP_STRING_OUTPUT_HEX:
674 hex = 1;
675 break;
676 }
677
678 if (var->val_len == 0) {
679 return snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\"");
680 }
681
682 if (hex) {
683 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
684 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) {
685 return 0;
686 }
687 } else {
688 if (!snmp_cstrcat
689 (buf, buf_len, out_len, allow_realloc, "Hex-STRING: ")) {
690 return 0;
691 }
692 }
693
694 if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc,
695 var->val.string, var->val_len)) {
696 return 0;
697 }
698
699 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
700 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) {
701 return 0;
702 }
703 }
704 } else {
705 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
706 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
707 "STRING: ")) {
708 return 0;
709 }
710 }
711 if (!snmp_cstrcat
712 (buf, buf_len, out_len, allow_realloc, "\"")) {
713 return 0;
714 }
715 if (!sprint_realloc_asciistring
716 (buf, buf_len, out_len, allow_realloc, var->val.string,
717 var->val_len)) {
718 return 0;
719 }
720 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) {
721 return 0;
722 }
723 }
724
725 if (units) {
726 return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ")
727 && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units));
728 }
729 return 1;
730 }
731
732 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
733
734 /**
735 * Prints a float into a buffer.
736 *
737 * The variable var is encoded as a floating point value.
738 *
739 * If allow_realloc is true the buffer will be (re)allocated to fit in the
740 * needed size. (Note: *buf may change due to this.)
741 *
742 * @param buf Address of the buffer to print to.
743 * @param buf_len Address to an integer containing the size of buf.
744 * @param out_len Incremented by the number of characters printed.
745 * @param allow_realloc if not zero reallocate the buffer to fit the
746 * needed size.
747 * @param var The variable to encode.
748 * @param enums The enumeration ff this variable is enumerated. may be NULL.
749 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
750 * See RFC 1903 Section 3.1 for details. may be NULL.
751 * @param units Contents of the UNITS clause of the MIB. may be NULL.
752 *
753 * @return 1 on success, or 0 on failure (out of memory, or buffer to
754 * small when not allowed to realloc.)
755 */
756 int
sprint_realloc_float(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)757 sprint_realloc_float(u_char ** buf, size_t * buf_len,
758 size_t * out_len, int allow_realloc,
759 const netsnmp_variable_list * var,
760 const struct enum_list *enums,
761 const char *hint, const char *units)
762 {
763 char *printf_format_string = NULL;
764
765 if (var->type != ASN_OPAQUE_FLOAT) {
766 if (!netsnmp_ds_get_boolean(
767 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
768 u_char str[] = "Wrong Type (should be Float): ";
769 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
770 return 0;
771 }
772 return sprint_realloc_by_type(buf, buf_len, out_len,
773 allow_realloc, var, NULL, NULL,
774 NULL);
775 }
776
777 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
778 if (!snmp_cstrcat
779 (buf, buf_len, out_len, allow_realloc, "Opaque: Float: ")) {
780 return 0;
781 }
782 }
783
784
785 /*
786 * How much space needed for max. length float? 128 is overkill.
787 */
788
789 while ((*out_len + 128 + 1) >= *buf_len) {
790 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
791 return 0;
792 }
793 }
794
795 printf_format_string = make_printf_format_string("%f");
796 if (!printf_format_string) {
797 return 0;
798 }
799 snprintf((char *)(*buf + *out_len), 128, printf_format_string, *var->val.floatVal);
800 free(printf_format_string);
801 *out_len += strlen((char *) (*buf + *out_len));
802
803 if (units) {
804 return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ")
805 && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units));
806 }
807 return 1;
808 }
809
810
811 /**
812 * Prints a double into a buffer.
813 *
814 * The variable var is encoded as a double precision floating point value.
815 *
816 * If allow_realloc is true the buffer will be (re)allocated to fit in the
817 * needed size. (Note: *buf may change due to this.)
818 *
819 * @param buf Address of the buffer to print to.
820 * @param buf_len Address to an integer containing the size of buf.
821 * @param out_len Incremented by the number of characters printed.
822 * @param allow_realloc if not zero reallocate the buffer to fit the
823 * needed size.
824 * @param var The variable to encode.
825 * @param enums The enumeration ff this variable is enumerated. may be NULL.
826 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
827 * See RFC 1903 Section 3.1 for details. may be NULL.
828 * @param units Contents of the UNITS clause of the MIB. may be NULL.
829 *
830 * @return 1 on success, or 0 on failure (out of memory, or buffer to
831 * small when not allowed to realloc.)
832 */
833 int
sprint_realloc_double(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)834 sprint_realloc_double(u_char ** buf, size_t * buf_len,
835 size_t * out_len, int allow_realloc,
836 const netsnmp_variable_list * var,
837 const struct enum_list *enums,
838 const char *hint, const char *units)
839 {
840 char *printf_format_string = NULL;
841
842 if (var->type != ASN_OPAQUE_DOUBLE) {
843 if (!netsnmp_ds_get_boolean(
844 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
845 u_char str[] = "Wrong Type (should be Double): ";
846 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
847 return 0;
848 }
849 return sprint_realloc_by_type(buf, buf_len, out_len,
850 allow_realloc, var, NULL, NULL,
851 NULL);
852 }
853
854 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
855 if (!snmp_cstrcat
856 (buf, buf_len, out_len, allow_realloc, "Opaque: Float: ")) {
857 return 0;
858 }
859 }
860
861 /*
862 * How much space needed for max. length double? 128 is overkill.
863 */
864
865 while ((*out_len + 128 + 1) >= *buf_len) {
866 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
867 return 0;
868 }
869 }
870
871 printf_format_string = make_printf_format_string("%f");
872 if (!printf_format_string) {
873 return 0;
874 }
875 snprintf((char *)(*buf + *out_len), 128, printf_format_string, *var->val.doubleVal);
876 free(printf_format_string);
877 *out_len += strlen((char *) (*buf + *out_len));
878
879 if (units) {
880 return (snmp_cstrcat
881 (buf, buf_len, out_len, allow_realloc, " ")
882 && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units));
883 }
884 return 1;
885 }
886
887 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
888
889
890 /**
891 * Prints a counter into a buffer.
892 *
893 * The variable var is encoded as a counter value.
894 *
895 * If allow_realloc is true the buffer will be (re)allocated to fit in the
896 * needed size. (Note: *buf may change due to this.)
897 *
898 * @param buf Address of the buffer to print to.
899 * @param buf_len Address to an integer containing the size of buf.
900 * @param out_len Incremented by the number of characters printed.
901 * @param allow_realloc if not zero reallocate the buffer to fit the
902 * needed size.
903 * @param var The variable to encode.
904 * @param enums The enumeration ff this variable is enumerated. may be NULL.
905 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
906 * See RFC 1903 Section 3.1 for details. may be NULL.
907 * @param units Contents of the UNITS clause of the MIB. may be NULL.
908 *
909 * @return 1 on success, or 0 on failure (out of memory, or buffer to
910 * small when not allowed to realloc.)
911 */
912 int
sprint_realloc_counter64(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)913 sprint_realloc_counter64(u_char ** buf, size_t * buf_len, size_t * out_len,
914 int allow_realloc,
915 const netsnmp_variable_list * var,
916 const struct enum_list *enums,
917 const char *hint, const char *units)
918 {
919 char a64buf[I64CHARSZ + 1];
920
921 if (var->type != ASN_COUNTER64
922 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
923 && var->type != ASN_OPAQUE_COUNTER64
924 && var->type != ASN_OPAQUE_I64 && var->type != ASN_OPAQUE_U64
925 #endif
926 ) {
927 if (!netsnmp_ds_get_boolean(
928 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
929 u_char str[] = "Wrong Type (should be Counter64): ";
930 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
931 return 0;
932 }
933 return sprint_realloc_by_type(buf, buf_len, out_len,
934 allow_realloc, var, NULL, NULL,
935 NULL);
936 }
937
938 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
939 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
940 if (var->type != ASN_COUNTER64) {
941 if (!snmp_cstrcat
942 (buf, buf_len, out_len, allow_realloc, "Opaque: ")) {
943 return 0;
944 }
945 }
946 #endif
947 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
948 switch (var->type) {
949 case ASN_OPAQUE_U64:
950 if (!snmp_cstrcat
951 (buf, buf_len, out_len, allow_realloc, "UInt64: ")) {
952 return 0;
953 }
954 break;
955 case ASN_OPAQUE_I64:
956 if (!snmp_cstrcat
957 (buf, buf_len, out_len, allow_realloc, "Int64: ")) {
958 return 0;
959 }
960 break;
961 case ASN_COUNTER64:
962 case ASN_OPAQUE_COUNTER64:
963 #endif
964 if (!snmp_cstrcat
965 (buf, buf_len, out_len, allow_realloc, "Counter64: ")) {
966 return 0;
967 }
968 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
969 }
970 #endif
971 }
972 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
973 if (var->type == ASN_OPAQUE_I64) {
974 printI64(a64buf, var->val.counter64);
975 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, a64buf)) {
976 return 0;
977 }
978 } else {
979 #endif
980 printU64(a64buf, var->val.counter64);
981 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, a64buf)) {
982 return 0;
983 }
984 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
985 }
986 #endif
987
988 if (units) {
989 return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ")
990 && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units));
991 }
992 return 1;
993 }
994
995
996 /**
997 * Prints an object identifier into a buffer.
998 *
999 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1000 * needed size. (Note: *buf may change due to this.)
1001 *
1002 * @param buf Address of the buffer to print to.
1003 * @param buf_len Address to an integer containing the size of buf.
1004 * @param out_len Incremented by the number of characters printed.
1005 * @param allow_realloc if not zero reallocate the buffer to fit the
1006 * needed size.
1007 * @param var The variable to encode.
1008 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1009 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1010 * See RFC 1903 Section 3.1 for details. may be NULL.
1011 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1012 *
1013 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1014 * small when not allowed to realloc.)
1015 */
1016 int
sprint_realloc_opaque(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1017 sprint_realloc_opaque(u_char ** buf, size_t * buf_len,
1018 size_t * out_len, int allow_realloc,
1019 const netsnmp_variable_list * var,
1020 const struct enum_list *enums,
1021 const char *hint, const char *units)
1022 {
1023 if (var->type != ASN_OPAQUE
1024 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1025 && var->type != ASN_OPAQUE_COUNTER64
1026 && var->type != ASN_OPAQUE_U64
1027 && var->type != ASN_OPAQUE_I64
1028 && var->type != ASN_OPAQUE_FLOAT && var->type != ASN_OPAQUE_DOUBLE
1029 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1030 ) {
1031 if (!netsnmp_ds_get_boolean(
1032 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1033 u_char str[] = "Wrong Type (should be Opaque): ";
1034 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1035 return 0;
1036 }
1037 return sprint_realloc_by_type(buf, buf_len, out_len,
1038 allow_realloc, var, NULL, NULL,
1039 NULL);
1040 }
1041
1042 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1043 switch (var->type) {
1044 case ASN_OPAQUE_COUNTER64:
1045 case ASN_OPAQUE_U64:
1046 case ASN_OPAQUE_I64:
1047 return sprint_realloc_counter64(buf, buf_len, out_len,
1048 allow_realloc, var, enums, hint,
1049 units);
1050 break;
1051
1052 case ASN_OPAQUE_FLOAT:
1053 return sprint_realloc_float(buf, buf_len, out_len, allow_realloc,
1054 var, enums, hint, units);
1055 break;
1056
1057 case ASN_OPAQUE_DOUBLE:
1058 return sprint_realloc_double(buf, buf_len, out_len, allow_realloc,
1059 var, enums, hint, units);
1060 break;
1061
1062 case ASN_OPAQUE:
1063 #endif
1064 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1065 u_char str[] = "OPAQUE: ";
1066 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1067 return 0;
1068 }
1069 }
1070 if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc,
1071 var->val.string, var->val_len)) {
1072 return 0;
1073 }
1074 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1075 }
1076 #endif
1077 if (units) {
1078 return (snmp_strcat
1079 (buf, buf_len, out_len, allow_realloc,
1080 (const u_char *) " ")
1081 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1082 (const u_char *) units));
1083 }
1084 return 1;
1085 }
1086
1087
1088 /**
1089 * Prints an object identifier into a buffer.
1090 *
1091 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1092 * needed size. (Note: *buf may change due to this.)
1093 *
1094 * @param buf Address of the buffer to print to.
1095 * @param buf_len Address to an integer containing the size of buf.
1096 * @param out_len Incremented by the number of characters printed.
1097 * @param allow_realloc if not zero reallocate the buffer to fit the
1098 * needed size.
1099 * @param var The variable to encode.
1100 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1101 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1102 * See RFC 1903 Section 3.1 for details. may be NULL.
1103 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1104 *
1105 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1106 * small when not allowed to realloc.)
1107 */
1108 int
sprint_realloc_object_identifier(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1109 sprint_realloc_object_identifier(u_char ** buf, size_t * buf_len,
1110 size_t * out_len, int allow_realloc,
1111 const netsnmp_variable_list * var,
1112 const struct enum_list *enums,
1113 const char *hint, const char *units)
1114 {
1115 int buf_overflow = 0;
1116
1117 if (var->type != ASN_OBJECT_ID) {
1118 if (!netsnmp_ds_get_boolean(
1119 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1120 u_char str[] = "Wrong Type (should be OBJECT IDENTIFIER): ";
1121 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1122 return 0;
1123 }
1124 return sprint_realloc_by_type(buf, buf_len, out_len,
1125 allow_realloc, var, NULL, NULL,
1126 NULL);
1127 }
1128
1129 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1130 u_char str[] = "OID: ";
1131 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1132 return 0;
1133 }
1134 }
1135
1136 netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len, allow_realloc,
1137 &buf_overflow,
1138 (oid *) (var->val.objid),
1139 var->val_len / sizeof(oid));
1140
1141 if (buf_overflow) {
1142 return 0;
1143 }
1144
1145 if (units) {
1146 return (snmp_strcat
1147 (buf, buf_len, out_len, allow_realloc,
1148 (const u_char *) " ")
1149 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1150 (const u_char *) units));
1151 }
1152 return 1;
1153 }
1154
1155
1156
1157 /**
1158 * Prints a timetick variable into a buffer.
1159 *
1160 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1161 * needed size. (Note: *buf may change due to this.)
1162 *
1163 * @param buf Address of the buffer to print to.
1164 * @param buf_len Address to an integer containing the size of buf.
1165 * @param out_len Incremented by the number of characters printed.
1166 * @param allow_realloc if not zero reallocate the buffer to fit the
1167 * needed size.
1168 * @param var The variable to encode.
1169 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1170 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1171 * See RFC 1903 Section 3.1 for details. may be NULL.
1172 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1173 *
1174 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1175 * small when not allowed to realloc.)
1176 */
1177 int
sprint_realloc_timeticks(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1178 sprint_realloc_timeticks(u_char ** buf, size_t * buf_len, size_t * out_len,
1179 int allow_realloc,
1180 const netsnmp_variable_list * var,
1181 const struct enum_list *enums,
1182 const char *hint, const char *units)
1183 {
1184 char timebuf[40];
1185
1186 if (var->type != ASN_TIMETICKS) {
1187 if (!netsnmp_ds_get_boolean(
1188 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1189 u_char str[] = "Wrong Type (should be Timeticks): ";
1190 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1191 return 0;
1192 }
1193 return sprint_realloc_by_type(buf, buf_len, out_len,
1194 allow_realloc, var, NULL, NULL,
1195 NULL);
1196 }
1197
1198 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS)) {
1199 char str[32];
1200 sprintf(str, "%lu", *(u_long *) var->val.integer);
1201 if (!snmp_strcat
1202 (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) {
1203 return 0;
1204 }
1205 return 1;
1206 }
1207 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1208 char str[32];
1209 sprintf(str, "Timeticks: (%lu) ", *(u_long *) var->val.integer);
1210 if (!snmp_strcat
1211 (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) {
1212 return 0;
1213 }
1214 }
1215 uptimeString(*(u_long *) (var->val.integer), timebuf, sizeof(timebuf));
1216 if (!snmp_strcat
1217 (buf, buf_len, out_len, allow_realloc, (const u_char *) timebuf)) {
1218 return 0;
1219 }
1220 if (units) {
1221 return (snmp_strcat
1222 (buf, buf_len, out_len, allow_realloc,
1223 (const u_char *) " ")
1224 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1225 (const u_char *) units));
1226 }
1227 return 1;
1228 }
1229
1230
1231 /**
1232 * Prints an integer according to the hint into a buffer.
1233 *
1234 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1235 * needed size. (Note: *buf may change due to this.)
1236 *
1237 * @param buf Address of the buffer to print to.
1238 * @param buf_len Address to an integer containing the size of buf.
1239 * @param out_len Incremented by the number of characters printed.
1240 * @param allow_realloc if not zero reallocate the buffer to fit the
1241 * needed size.
1242 * @param val The variable to encode.
1243 * @param decimaltype 'd' or 'u' depending on integer type
1244 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1245 * See RFC 1903 Section 3.1 for details. may _NOT_ be NULL.
1246 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1247 *
1248 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1249 * small when not allowed to realloc.)
1250 */
1251 int
sprint_realloc_hinted_integer(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,long val,const char decimaltype,const char * hint,const char * units)1252 sprint_realloc_hinted_integer(u_char ** buf, size_t * buf_len,
1253 size_t * out_len, int allow_realloc,
1254 long val, const char decimaltype,
1255 const char *hint, const char *units)
1256 {
1257 char fmt[10] = "%l@", tmp[256];
1258 int shift = 0, len, negative = 0;
1259
1260 if (hint[0] == 'd') {
1261 /*
1262 * We might *actually* want a 'u' here.
1263 */
1264 if (hint[1] == '-')
1265 shift = atoi(hint + 2);
1266 fmt[2] = decimaltype;
1267 if (val < 0) {
1268 negative = 1;
1269 val = -val;
1270 }
1271 } else {
1272 /*
1273 * DISPLAY-HINT character is 'b', 'o', or 'x'.
1274 */
1275 fmt[2] = hint[0];
1276 }
1277
1278 if (hint[0] == 'b') {
1279 unsigned long int bit = 0x80000000LU;
1280 char *bp = tmp;
1281 while (bit) {
1282 *bp++ = val & bit ? '1' : '0';
1283 bit >>= 1;
1284 }
1285 *bp = 0;
1286 }
1287 else
1288 sprintf(tmp, fmt, val);
1289
1290 if (shift != 0) {
1291 len = strlen(tmp);
1292 if (shift <= len) {
1293 tmp[len + 1] = 0;
1294 while (shift--) {
1295 tmp[len] = tmp[len - 1];
1296 len--;
1297 }
1298 tmp[len] = '.';
1299 } else {
1300 tmp[shift + 1] = 0;
1301 while (shift) {
1302 if (len-- > 0) {
1303 tmp[shift] = tmp[len];
1304 } else {
1305 tmp[shift] = '0';
1306 }
1307 shift--;
1308 }
1309 tmp[0] = '.';
1310 }
1311 }
1312 if (negative) {
1313 len = strlen(tmp)+1;
1314 while (len) {
1315 tmp[len] = tmp[len-1];
1316 len--;
1317 }
1318 tmp[0] = '-';
1319 }
1320 return snmp_strcat(buf, buf_len, out_len, allow_realloc, (u_char *)tmp);
1321 }
1322
1323
1324 /**
1325 * Prints an integer into a buffer.
1326 *
1327 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1328 * needed size. (Note: *buf may change due to this.)
1329 *
1330 * @param buf Address of the buffer to print to.
1331 * @param buf_len Address to an integer containing the size of buf.
1332 * @param out_len Incremented by the number of characters printed.
1333 * @param allow_realloc if not zero reallocate the buffer to fit the
1334 * needed size.
1335 * @param var The variable to encode.
1336 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1337 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1338 * See RFC 1903 Section 3.1 for details. may be NULL.
1339 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1340 *
1341 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1342 * small when not allowed to realloc.)
1343 */
1344 int
sprint_realloc_integer(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1345 sprint_realloc_integer(u_char ** buf, size_t * buf_len, size_t * out_len,
1346 int allow_realloc,
1347 const netsnmp_variable_list * var,
1348 const struct enum_list *enums,
1349 const char *hint, const char *units)
1350 {
1351 char *enum_string = NULL;
1352
1353 if (var->type != ASN_INTEGER) {
1354 if (!netsnmp_ds_get_boolean(
1355 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1356 u_char str[] = "Wrong Type (should be INTEGER): ";
1357 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1358 return 0;
1359 }
1360 return sprint_realloc_by_type(buf, buf_len, out_len,
1361 allow_realloc, var, NULL, NULL,
1362 NULL);
1363 }
1364
1365 for (; enums; enums = enums->next) {
1366 if (enums->value == *var->val.integer) {
1367 enum_string = enums->label;
1368 break;
1369 }
1370 }
1371
1372 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1373 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1374 (const u_char *) "INTEGER: ")) {
1375 return 0;
1376 }
1377 }
1378
1379 if (enum_string == NULL ||
1380 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) {
1381 if (hint) {
1382 if (!(sprint_realloc_hinted_integer(buf, buf_len, out_len,
1383 allow_realloc,
1384 *var->val.integer, 'd',
1385 hint, units))) {
1386 return 0;
1387 }
1388 } else {
1389 char str[32];
1390 sprintf(str, "%ld", *var->val.integer);
1391 if (!snmp_strcat
1392 (buf, buf_len, out_len, allow_realloc,
1393 (const u_char *) str)) {
1394 return 0;
1395 }
1396 }
1397 } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1398 if (!snmp_strcat
1399 (buf, buf_len, out_len, allow_realloc,
1400 (const u_char *) enum_string)) {
1401 return 0;
1402 }
1403 } else {
1404 char str[32];
1405 sprintf(str, "(%ld)", *var->val.integer);
1406 if (!snmp_strcat
1407 (buf, buf_len, out_len, allow_realloc,
1408 (const u_char *) enum_string)) {
1409 return 0;
1410 }
1411 if (!snmp_strcat
1412 (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) {
1413 return 0;
1414 }
1415 }
1416
1417 if (units) {
1418 return (snmp_strcat
1419 (buf, buf_len, out_len, allow_realloc,
1420 (const u_char *) " ")
1421 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1422 (const u_char *) units));
1423 }
1424 return 1;
1425 }
1426
1427
1428 /**
1429 * Prints an unsigned integer into a buffer.
1430 *
1431 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1432 * needed size. (Note: *buf may change due to this.)
1433 *
1434 * @param buf Address of the buffer to print to.
1435 * @param buf_len Address to an integer containing the size of buf.
1436 * @param out_len Incremented by the number of characters printed.
1437 * @param allow_realloc if not zero reallocate the buffer to fit the
1438 * needed size.
1439 * @param var The variable to encode.
1440 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1441 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1442 * See RFC 1903 Section 3.1 for details. may be NULL.
1443 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1444 *
1445 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1446 * small when not allowed to realloc.)
1447 */
1448 int
sprint_realloc_uinteger(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1449 sprint_realloc_uinteger(u_char ** buf, size_t * buf_len, size_t * out_len,
1450 int allow_realloc,
1451 const netsnmp_variable_list * var,
1452 const struct enum_list *enums,
1453 const char *hint, const char *units)
1454 {
1455 char *enum_string = NULL;
1456
1457 if (var->type != ASN_UINTEGER) {
1458 if (!netsnmp_ds_get_boolean(
1459 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1460 u_char str[] = "Wrong Type (should be UInteger32): ";
1461 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1462 return 0;
1463 }
1464 return sprint_realloc_by_type(buf, buf_len, out_len,
1465 allow_realloc, var, NULL, NULL,
1466 NULL);
1467 }
1468
1469 for (; enums; enums = enums->next) {
1470 if (enums->value == *var->val.integer) {
1471 enum_string = enums->label;
1472 break;
1473 }
1474 }
1475
1476 if (enum_string == NULL ||
1477 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) {
1478 if (hint) {
1479 if (!(sprint_realloc_hinted_integer(buf, buf_len, out_len,
1480 allow_realloc,
1481 *var->val.integer, 'u',
1482 hint, units))) {
1483 return 0;
1484 }
1485 } else {
1486 char str[32];
1487 sprintf(str, "%lu", *var->val.integer);
1488 if (!snmp_strcat
1489 (buf, buf_len, out_len, allow_realloc,
1490 (const u_char *) str)) {
1491 return 0;
1492 }
1493 }
1494 } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1495 if (!snmp_strcat
1496 (buf, buf_len, out_len, allow_realloc,
1497 (const u_char *) enum_string)) {
1498 return 0;
1499 }
1500 } else {
1501 char str[32];
1502 sprintf(str, "(%lu)", *var->val.integer);
1503 if (!snmp_strcat
1504 (buf, buf_len, out_len, allow_realloc,
1505 (const u_char *) enum_string)) {
1506 return 0;
1507 }
1508 if (!snmp_strcat
1509 (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) {
1510 return 0;
1511 }
1512 }
1513
1514 if (units) {
1515 return (snmp_strcat
1516 (buf, buf_len, out_len, allow_realloc,
1517 (const u_char *) " ")
1518 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1519 (const u_char *) units));
1520 }
1521 return 1;
1522 }
1523
1524
1525 /**
1526 * Prints a gauge value into a buffer.
1527 *
1528 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1529 * needed size. (Note: *buf may change due to this.)
1530 *
1531 * @param buf Address of the buffer to print to.
1532 * @param buf_len Address to an integer containing the size of buf.
1533 * @param out_len Incremented by the number of characters printed.
1534 * @param allow_realloc if not zero reallocate the buffer to fit the
1535 * needed size.
1536 * @param var The variable to encode.
1537 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1538 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1539 * See RFC 1903 Section 3.1 for details. may be NULL.
1540 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1541 *
1542 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1543 * small when not allowed to realloc.)
1544 */
1545 int
sprint_realloc_gauge(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1546 sprint_realloc_gauge(u_char ** buf, size_t * buf_len, size_t * out_len,
1547 int allow_realloc,
1548 const netsnmp_variable_list * var,
1549 const struct enum_list *enums,
1550 const char *hint, const char *units)
1551 {
1552 char tmp[32];
1553
1554 if (var->type != ASN_GAUGE) {
1555 if (!netsnmp_ds_get_boolean(
1556 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1557 u_char str[] = "Wrong Type (should be Gauge32 or Unsigned32): ";
1558 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1559 return 0;
1560 }
1561 return sprint_realloc_by_type(buf, buf_len, out_len,
1562 allow_realloc, var, NULL, NULL,
1563 NULL);
1564 }
1565
1566 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1567 u_char str[] = "Gauge32: ";
1568 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1569 return 0;
1570 }
1571 }
1572 if (hint) {
1573 if (!sprint_realloc_hinted_integer(buf, buf_len, out_len,
1574 allow_realloc,
1575 *var->val.integer, 'u', hint,
1576 units)) {
1577 return 0;
1578 }
1579 } else {
1580 sprintf(tmp, "%u", (unsigned int)(*var->val.integer & 0xffffffff));
1581 if (!snmp_strcat
1582 (buf, buf_len, out_len, allow_realloc, (const u_char *) tmp)) {
1583 return 0;
1584 }
1585 }
1586 if (units) {
1587 return (snmp_strcat
1588 (buf, buf_len, out_len, allow_realloc,
1589 (const u_char *) " ")
1590 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1591 (const u_char *) units));
1592 }
1593 return 1;
1594 }
1595
1596
1597 /**
1598 * Prints a counter value into a buffer.
1599 *
1600 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1601 * needed size. (Note: *buf may change due to this.)
1602 *
1603 * @param buf Address of the buffer to print to.
1604 * @param buf_len Address to an integer containing the size of buf.
1605 * @param out_len Incremented by the number of characters printed.
1606 * @param allow_realloc if not zero reallocate the buffer to fit the
1607 * needed size.
1608 * @param var The variable to encode.
1609 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1610 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1611 * See RFC 1903 Section 3.1 for details. may be NULL.
1612 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1613 *
1614 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1615 * small when not allowed to realloc.)
1616 */
1617 int
sprint_realloc_counter(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1618 sprint_realloc_counter(u_char ** buf, size_t * buf_len, size_t * out_len,
1619 int allow_realloc,
1620 const netsnmp_variable_list * var,
1621 const struct enum_list *enums,
1622 const char *hint, const char *units)
1623 {
1624 char tmp[32];
1625
1626 if (var->type != ASN_COUNTER) {
1627 if (!netsnmp_ds_get_boolean(
1628 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1629 u_char str[] = "Wrong Type (should be Counter32): ";
1630 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1631 return 0;
1632 }
1633 return sprint_realloc_by_type(buf, buf_len, out_len,
1634 allow_realloc, var, NULL, NULL,
1635 NULL);
1636 }
1637
1638 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1639 u_char str[] = "Counter32: ";
1640 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1641 return 0;
1642 }
1643 }
1644 sprintf(tmp, "%u", (unsigned int)(*var->val.integer & 0xffffffff));
1645 if (!snmp_strcat
1646 (buf, buf_len, out_len, allow_realloc, (const u_char *) tmp)) {
1647 return 0;
1648 }
1649 if (units) {
1650 return (snmp_strcat
1651 (buf, buf_len, out_len, allow_realloc,
1652 (const u_char *) " ")
1653 && snmp_strcat(buf, buf_len, out_len, allow_realloc,
1654 (const u_char *) units));
1655 }
1656 return 1;
1657 }
1658
1659
1660 /**
1661 * Prints a network address into a buffer.
1662 *
1663 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1664 * needed size. (Note: *buf may change due to this.)
1665 *
1666 * @param buf Address of the buffer to print to.
1667 * @param buf_len Address to an integer containing the size of buf.
1668 * @param out_len Incremented by the number of characters printed.
1669 * @param allow_realloc if not zero reallocate the buffer to fit the
1670 * needed size.
1671 * @param var The variable to encode.
1672 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1673 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1674 * See RFC 1903 Section 3.1 for details. may be NULL.
1675 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1676 *
1677 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1678 * small when not allowed to realloc.)
1679 */
1680 int
sprint_realloc_networkaddress(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1681 sprint_realloc_networkaddress(u_char ** buf, size_t * buf_len,
1682 size_t * out_len, int allow_realloc,
1683 const netsnmp_variable_list * var,
1684 const struct enum_list *enums, const char *hint,
1685 const char *units)
1686 {
1687 size_t i;
1688
1689 if (var->type != ASN_IPADDRESS) {
1690 if (!netsnmp_ds_get_boolean(
1691 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1692 u_char str[] = "Wrong Type (should be NetworkAddress): ";
1693 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1694 return 0;
1695 }
1696 return sprint_realloc_by_type(buf, buf_len, out_len,
1697 allow_realloc, var, NULL, NULL,
1698 NULL);
1699 }
1700
1701 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1702 u_char str[] = "Network Address: ";
1703 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1704 return 0;
1705 }
1706 }
1707
1708 while ((*out_len + (var->val_len * 3) + 2) >= *buf_len) {
1709 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1710 return 0;
1711 }
1712 }
1713
1714 for (i = 0; i < var->val_len; i++) {
1715 sprintf((char *) (*buf + *out_len), "%02X", var->val.string[i]);
1716 *out_len += 2;
1717 if (i < var->val_len - 1) {
1718 *(*buf + *out_len) = ':';
1719 (*out_len)++;
1720 }
1721 }
1722 return 1;
1723 }
1724
1725
1726 /**
1727 * Prints an ip-address into a buffer.
1728 *
1729 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1730 * needed size. (Note: *buf may change due to this.)
1731 *
1732 * @param buf Address of the buffer to print to.
1733 * @param buf_len Address to an integer containing the size of buf.
1734 * @param out_len Incremented by the number of characters printed.
1735 * @param allow_realloc if not zero reallocate the buffer to fit the
1736 * needed size.
1737 * @param var The variable to encode.
1738 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1739 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1740 * See RFC 1903 Section 3.1 for details. may be NULL.
1741 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1742 *
1743 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1744 * small when not allowed to realloc.)
1745 */
1746 int
sprint_realloc_ipaddress(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1747 sprint_realloc_ipaddress(u_char ** buf, size_t * buf_len, size_t * out_len,
1748 int allow_realloc,
1749 const netsnmp_variable_list * var,
1750 const struct enum_list *enums,
1751 const char *hint, const char *units)
1752 {
1753 u_char *ip = var->val.string;
1754
1755 if (var->type != ASN_IPADDRESS) {
1756 if (!netsnmp_ds_get_boolean(
1757 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1758 u_char str[] = "Wrong Type (should be IpAddress): ";
1759 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1760 return 0;
1761 }
1762 return sprint_realloc_by_type(buf, buf_len, out_len,
1763 allow_realloc, var, NULL, NULL,
1764 NULL);
1765 }
1766
1767 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1768 u_char str[] = "IpAddress: ";
1769 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1770 return 0;
1771 }
1772 }
1773 while ((*out_len + 17) >= *buf_len) {
1774 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1775 return 0;
1776 }
1777 }
1778 if (ip)
1779 sprintf((char *) (*buf + *out_len), "%d.%d.%d.%d",
1780 ip[0], ip[1], ip[2], ip[3]);
1781 *out_len += strlen((char *) (*buf + *out_len));
1782 return 1;
1783 }
1784
1785
1786 /**
1787 * Prints a null value into a buffer.
1788 *
1789 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1790 * needed size. (Note: *buf may change due to this.)
1791 *
1792 * @param buf Address of the buffer to print to.
1793 * @param buf_len Address to an integer containing the size of buf.
1794 * @param out_len Incremented by the number of characters printed.
1795 * @param allow_realloc if not zero reallocate the buffer to fit the
1796 * needed size.
1797 * @param var The variable to encode.
1798 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1799 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1800 * See RFC 1903 Section 3.1 for details. may be NULL.
1801 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1802 *
1803 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1804 * small when not allowed to realloc.)
1805 */
1806 int
sprint_realloc_null(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1807 sprint_realloc_null(u_char ** buf, size_t * buf_len, size_t * out_len,
1808 int allow_realloc,
1809 const netsnmp_variable_list * var,
1810 const struct enum_list *enums,
1811 const char *hint, const char *units)
1812 {
1813 u_char str[] = "NULL";
1814
1815 if (var->type != ASN_NULL) {
1816 if (!netsnmp_ds_get_boolean(
1817 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1818 u_char str[] = "Wrong Type (should be NULL): ";
1819 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1820 return 0;
1821 }
1822 return sprint_realloc_by_type(buf, buf_len, out_len,
1823 allow_realloc, var, NULL, NULL,
1824 NULL);
1825 }
1826
1827 return snmp_strcat(buf, buf_len, out_len, allow_realloc, str);
1828 }
1829
1830
1831 /**
1832 * Prints a bit string into a buffer.
1833 *
1834 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1835 * needed size. (Note: *buf may change due to this.)
1836 *
1837 * @param buf Address of the buffer to print to.
1838 * @param buf_len Address to an integer containing the size of buf.
1839 * @param out_len Incremented by the number of characters printed.
1840 * @param allow_realloc if not zero reallocate the buffer to fit the
1841 * needed size.
1842 * @param var The variable to encode.
1843 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1844 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1845 * See RFC 1903 Section 3.1 for details. may be NULL.
1846 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1847 *
1848 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1849 * small when not allowed to realloc.)
1850 */
1851 int
sprint_realloc_bitstring(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1852 sprint_realloc_bitstring(u_char ** buf, size_t * buf_len, size_t * out_len,
1853 int allow_realloc,
1854 const netsnmp_variable_list * var,
1855 const struct enum_list *enums,
1856 const char *hint, const char *units)
1857 {
1858 int len, bit;
1859 u_char *cp;
1860 char *enum_string;
1861
1862 if (var->type != ASN_BIT_STR && var->type != ASN_OCTET_STR) {
1863 if (!netsnmp_ds_get_boolean(
1864 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1865 u_char str[] = "Wrong Type (should be BITS): ";
1866 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1867 return 0;
1868 }
1869 return sprint_realloc_by_type(buf, buf_len, out_len,
1870 allow_realloc, var, NULL, NULL,
1871 NULL);
1872 }
1873
1874 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1875 u_char str[] = "\"";
1876 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1877 return 0;
1878 }
1879 } else {
1880 u_char str[] = "BITS: ";
1881 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1882 return 0;
1883 }
1884 }
1885 if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc,
1886 var->val.bitstring, var->val_len)) {
1887 return 0;
1888 }
1889
1890 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1891 u_char str[] = "\"";
1892 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1893 return 0;
1894 }
1895 } else {
1896 cp = var->val.bitstring;
1897 for (len = 0; len < (int) var->val_len; len++) {
1898 for (bit = 0; bit < 8; bit++) {
1899 if (*cp & (0x80 >> bit)) {
1900 enum_string = NULL;
1901 for (; enums; enums = enums->next) {
1902 if (enums->value == (len * 8) + bit) {
1903 enum_string = enums->label;
1904 break;
1905 }
1906 }
1907 if (enum_string == NULL ||
1908 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
1909 NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) {
1910 char str[32];
1911 sprintf(str, "%d ", (len * 8) + bit);
1912 if (!snmp_strcat
1913 (buf, buf_len, out_len, allow_realloc,
1914 (const u_char *) str)) {
1915 return 0;
1916 }
1917 } else {
1918 char str[32];
1919 sprintf(str, "(%d) ", (len * 8) + bit);
1920 if (!snmp_strcat
1921 (buf, buf_len, out_len, allow_realloc,
1922 (const u_char *) enum_string)) {
1923 return 0;
1924 }
1925 if (!snmp_strcat
1926 (buf, buf_len, out_len, allow_realloc,
1927 (const u_char *) str)) {
1928 return 0;
1929 }
1930 }
1931 }
1932 }
1933 cp++;
1934 }
1935 }
1936 return 1;
1937 }
1938
1939 int
sprint_realloc_nsapaddress(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1940 sprint_realloc_nsapaddress(u_char ** buf, size_t * buf_len,
1941 size_t * out_len, int allow_realloc,
1942 const netsnmp_variable_list * var,
1943 const struct enum_list *enums, const char *hint,
1944 const char *units)
1945 {
1946 if (var->type != ASN_NSAP) {
1947 if (!netsnmp_ds_get_boolean(
1948 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
1949 u_char str[] = "Wrong Type (should be NsapAddress): ";
1950 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str))
1951 return 0;
1952 }
1953 return sprint_realloc_by_type(buf, buf_len, out_len,
1954 allow_realloc, var, NULL, NULL,
1955 NULL);
1956 }
1957
1958 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
1959 u_char str[] = "NsapAddress: ";
1960 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) {
1961 return 0;
1962 }
1963 }
1964
1965 return sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc,
1966 var->val.string, var->val_len);
1967 }
1968
1969
1970 /**
1971 * Fallback routine for a bad type, prints "Variable has bad type" into a buffer.
1972 *
1973 * If allow_realloc is true the buffer will be (re)allocated to fit in the
1974 * needed size. (Note: *buf may change due to this.)
1975 *
1976 * @param buf Address of the buffer to print to.
1977 * @param buf_len Address to an integer containing the size of buf.
1978 * @param out_len Incremented by the number of characters printed.
1979 * @param allow_realloc if not zero reallocate the buffer to fit the
1980 * needed size.
1981 * @param var The variable to encode.
1982 * @param enums The enumeration ff this variable is enumerated. may be NULL.
1983 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
1984 * See RFC 1903 Section 3.1 for details. may be NULL.
1985 * @param units Contents of the UNITS clause of the MIB. may be NULL.
1986 *
1987 * @return 1 on success, or 0 on failure (out of memory, or buffer to
1988 * small when not allowed to realloc.)
1989 */
1990 int
sprint_realloc_badtype(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)1991 sprint_realloc_badtype(u_char ** buf, size_t * buf_len, size_t * out_len,
1992 int allow_realloc,
1993 const netsnmp_variable_list * var,
1994 const struct enum_list *enums,
1995 const char *hint, const char *units)
1996 {
1997 u_char str[] = "Variable has bad type";
1998
1999 return snmp_strcat(buf, buf_len, out_len, allow_realloc, str);
2000 }
2001
2002
2003
2004 /**
2005 * Universal print routine, prints a variable into a buffer according to the variable
2006 * type.
2007 *
2008 * If allow_realloc is true the buffer will be (re)allocated to fit in the
2009 * needed size. (Note: *buf may change due to this.)
2010 *
2011 * @param buf Address of the buffer to print to.
2012 * @param buf_len Address to an integer containing the size of buf.
2013 * @param out_len Incremented by the number of characters printed.
2014 * @param allow_realloc if not zero reallocate the buffer to fit the
2015 * needed size.
2016 * @param var The variable to encode.
2017 * @param enums The enumeration ff this variable is enumerated. may be NULL.
2018 * @param hint Contents of the DISPLAY-HINT clause of the MIB.
2019 * See RFC 1903 Section 3.1 for details. may be NULL.
2020 * @param units Contents of the UNITS clause of the MIB. may be NULL.
2021 *
2022 * @return 1 on success, or 0 on failure (out of memory, or buffer to
2023 * small when not allowed to realloc.)
2024 */
2025 int
sprint_realloc_by_type(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)2026 sprint_realloc_by_type(u_char ** buf, size_t * buf_len, size_t * out_len,
2027 int allow_realloc,
2028 const netsnmp_variable_list * var,
2029 const struct enum_list *enums,
2030 const char *hint, const char *units)
2031 {
2032 DEBUGMSGTL(("output", "sprint_by_type, type %d\n", var->type));
2033
2034 switch (var->type) {
2035 case ASN_INTEGER:
2036 return sprint_realloc_integer(buf, buf_len, out_len, allow_realloc,
2037 var, enums, hint, units);
2038 case ASN_OCTET_STR:
2039 return sprint_realloc_octet_string(buf, buf_len, out_len,
2040 allow_realloc, var, enums, hint,
2041 units);
2042 case ASN_BIT_STR:
2043 return sprint_realloc_bitstring(buf, buf_len, out_len,
2044 allow_realloc, var, enums, hint,
2045 units);
2046 case ASN_OPAQUE:
2047 return sprint_realloc_opaque(buf, buf_len, out_len, allow_realloc,
2048 var, enums, hint, units);
2049 case ASN_OBJECT_ID:
2050 return sprint_realloc_object_identifier(buf, buf_len, out_len,
2051 allow_realloc, var, enums,
2052 hint, units);
2053 case ASN_TIMETICKS:
2054 return sprint_realloc_timeticks(buf, buf_len, out_len,
2055 allow_realloc, var, enums, hint,
2056 units);
2057 case ASN_GAUGE:
2058 return sprint_realloc_gauge(buf, buf_len, out_len, allow_realloc,
2059 var, enums, hint, units);
2060 case ASN_COUNTER:
2061 return sprint_realloc_counter(buf, buf_len, out_len, allow_realloc,
2062 var, enums, hint, units);
2063 case ASN_IPADDRESS:
2064 return sprint_realloc_ipaddress(buf, buf_len, out_len,
2065 allow_realloc, var, enums, hint,
2066 units);
2067 case ASN_NULL:
2068 return sprint_realloc_null(buf, buf_len, out_len, allow_realloc,
2069 var, enums, hint, units);
2070 case ASN_UINTEGER:
2071 return sprint_realloc_uinteger(buf, buf_len, out_len,
2072 allow_realloc, var, enums, hint,
2073 units);
2074 case ASN_COUNTER64:
2075 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2076 case ASN_OPAQUE_U64:
2077 case ASN_OPAQUE_I64:
2078 case ASN_OPAQUE_COUNTER64:
2079 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2080 return sprint_realloc_counter64(buf, buf_len, out_len,
2081 allow_realloc, var, enums, hint,
2082 units);
2083 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2084 case ASN_OPAQUE_FLOAT:
2085 return sprint_realloc_float(buf, buf_len, out_len, allow_realloc,
2086 var, enums, hint, units);
2087 case ASN_OPAQUE_DOUBLE:
2088 return sprint_realloc_double(buf, buf_len, out_len, allow_realloc,
2089 var, enums, hint, units);
2090 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2091 default:
2092 DEBUGMSGTL(("sprint_by_type", "bad type: %d\n", var->type));
2093 return sprint_realloc_badtype(buf, buf_len, out_len, allow_realloc,
2094 var, enums, hint, units);
2095 }
2096 }
2097
2098 /**
2099 * Generates a prinf format string.
2100 *
2101 * The original format string is combined with the optional
2102 * NETSNMP_DS_LIB_OUTPUT_PRECISION string (the -Op parameter).
2103 *
2104 * Example:
2105 * If the original format string is "%f", and the NETSNMP_DS_LIB_OUTPUT_PRECISION
2106 * is "5.2", the returned format string will be "%5.2f".
2107 *
2108 * The PRECISION string is inserted after the '%' of the original format string.
2109 * To prevent buffer overflow if NETSNMP_DS_LIB_OUTPUT_PRECISION is set to an
2110 * illegal size (e.g. with -Op 10000) snprintf should be used to prevent buffer
2111 * overflow.
2112 *
2113 * @param printf_format_default The format string used by the original printf.
2114 *
2115 * @return The address of of the new allocated format string (which must be freed
2116 * if no longer used), or NULL if any error (malloc).
2117 */
2118 char *
make_printf_format_string(const char * printf_format_default)2119 make_printf_format_string(const char *printf_format_default)
2120 {
2121 const char *cp_printf_format_default;
2122 const char *printf_precision;
2123 const char *cp_printf_precision;
2124 char *printf_format_string;
2125 char *cp_out;
2126 char c;
2127
2128 printf_precision = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION);
2129 if (!printf_precision) {
2130 printf_precision = "";
2131 }
2132
2133 /* reserve new format string buffer */
2134 printf_format_string = (char *) malloc(strlen(printf_format_default)+strlen(printf_precision)+1);
2135 if (!printf_format_string)
2136 {
2137 DEBUGMSGTL(("make_printf_format_string", "malloc failed\n"));
2138 return NULL;
2139 }
2140
2141 /* copy default format string, including the '%' */
2142 cp_out = printf_format_string;
2143 cp_printf_format_default = printf_format_default;
2144 while((c = *cp_printf_format_default) != '\0')
2145 {
2146 *cp_out++ = c;
2147 cp_printf_format_default++;
2148 if (c == '%') break;
2149 }
2150
2151 /* insert the precision string */
2152 cp_printf_precision = printf_precision;
2153 while ((c = *cp_printf_precision++) != '\0')
2154 {
2155 *cp_out++ = c;
2156 }
2157
2158 /* copy the remaining default format string, including the terminating '\0' */
2159 strcpy(cp_out, cp_printf_format_default);
2160
2161 DEBUGMSGTL(("make_printf_format_string", "\"%s\"+\"%s\"->\"%s\"\n",
2162 printf_format_default, printf_precision, printf_format_string));
2163 return printf_format_string;
2164 }
2165
2166
2167 #ifndef NETSNMP_DISABLE_MIB_LOADING
2168 /**
2169 * Retrieves the tree head.
2170 *
2171 * @return the tree head.
2172 */
2173 struct tree *
get_tree_head(void)2174 get_tree_head(void)
2175 {
2176 return (tree_head);
2177 }
2178
2179 static char *confmibdir = NULL;
2180 static char *confmibs = NULL;
2181
2182 static void
handle_mibdirs_conf(const char * token,char * line)2183 handle_mibdirs_conf(const char *token, char *line)
2184 {
2185 char *ctmp;
2186
2187 if (confmibdir) {
2188 if ((*line == '+') || (*line == '-')) {
2189 ctmp = (char *) malloc(strlen(confmibdir) + strlen(line) + 2);
2190 if (!ctmp) {
2191 DEBUGMSGTL(("read_config:initmib",
2192 "mibdir conf malloc failed"));
2193 return;
2194 }
2195 if(*line++ == '+')
2196 sprintf(ctmp, "%s%c%s", confmibdir, ENV_SEPARATOR_CHAR, line);
2197 else
2198 sprintf(ctmp, "%s%c%s", line, ENV_SEPARATOR_CHAR, confmibdir);
2199 } else {
2200 ctmp = strdup(line);
2201 if (!ctmp) {
2202 DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
2203 return;
2204 }
2205 }
2206 SNMP_FREE(confmibdir);
2207 } else {
2208 ctmp = strdup(line);
2209 if (!ctmp) {
2210 DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
2211 return;
2212 }
2213 }
2214 confmibdir = ctmp;
2215 DEBUGMSGTL(("read_config:initmib", "using mibdirs: %s\n", confmibdir));
2216 }
2217
2218 static void
handle_mibs_conf(const char * token,char * line)2219 handle_mibs_conf(const char *token, char *line)
2220 {
2221 char *ctmp;
2222
2223 if (confmibs) {
2224 if ((*line == '+') || (*line == '-')) {
2225 ctmp = (char *) malloc(strlen(confmibs) + strlen(line) + 2);
2226 if (!ctmp) {
2227 DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
2228 return;
2229 }
2230 if(*line++ == '+')
2231 sprintf(ctmp, "%s%c%s", confmibs, ENV_SEPARATOR_CHAR, line);
2232 else
2233 sprintf(ctmp, "%s%c%s", line, ENV_SEPARATOR_CHAR, confmibdir);
2234 } else {
2235 ctmp = strdup(line);
2236 if (!ctmp) {
2237 DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
2238 return;
2239 }
2240 }
2241 SNMP_FREE(confmibs);
2242 } else {
2243 ctmp = strdup(line);
2244 if (!ctmp) {
2245 DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed"));
2246 return;
2247 }
2248 }
2249 confmibs = ctmp;
2250 DEBUGMSGTL(("read_config:initmib", "using mibs: %s\n", confmibs));
2251 }
2252
2253
2254 static void
handle_mibfile_conf(const char * token,char * line)2255 handle_mibfile_conf(const char *token, char *line)
2256 {
2257 DEBUGMSGTL(("read_config:initmib", "reading mibfile: %s\n", line));
2258 read_mib(line);
2259 }
2260 #endif
2261
2262 static void
handle_print_numeric(const char * token,char * line)2263 handle_print_numeric(const char *token, char *line)
2264 {
2265 const char *value;
2266 char *st;
2267
2268 value = strtok_r(line, " \t\n", &st);
2269 if (value && (
2270 (strcasecmp(value, "yes") == 0) ||
2271 (strcasecmp(value, "true") == 0) ||
2272 (*value == '1') )) {
2273
2274 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2275 NETSNMP_OID_OUTPUT_NUMERIC);
2276 }
2277 }
2278
2279 char *
snmp_out_options(char * options,int argc,char * const * argv)2280 snmp_out_options(char *options, int argc, char *const *argv)
2281 {
2282 while (*options) {
2283 switch (*options++) {
2284 case '0':
2285 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID,
2286 NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT);
2287 break;
2288 case 'a':
2289 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT,
2290 NETSNMP_STRING_OUTPUT_ASCII);
2291 break;
2292 case 'b':
2293 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS);
2294 break;
2295 case 'e':
2296 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
2297 break;
2298 case 'E':
2299 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES);
2300 break;
2301 case 'f':
2302 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2303 NETSNMP_OID_OUTPUT_FULL);
2304 break;
2305 case 'n':
2306 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2307 NETSNMP_OID_OUTPUT_NUMERIC);
2308 break;
2309 case 'p':
2310 /* What if argc/argv are null ? */
2311 if (!*(options)) {
2312 options = argv[optind++];
2313 }
2314 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
2315 NETSNMP_DS_LIB_OUTPUT_PRECISION,
2316 options);
2317 return NULL; /* -Op... is a standalone option, so we're done here */
2318 case 'q':
2319 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
2320 break;
2321 case 'Q':
2322 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT, 1);
2323 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
2324 break;
2325 case 's':
2326 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2327 NETSNMP_OID_OUTPUT_SUFFIX);
2328 break;
2329 case 'S':
2330 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2331 NETSNMP_OID_OUTPUT_MODULE);
2332 break;
2333 case 't':
2334 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS);
2335 break;
2336 case 'T':
2337 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT);
2338 break;
2339 case 'u':
2340 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,
2341 NETSNMP_OID_OUTPUT_UCD);
2342 break;
2343 case 'U':
2344 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS);
2345 break;
2346 case 'v':
2347 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE);
2348 break;
2349 case 'x':
2350 netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT,
2351 NETSNMP_STRING_OUTPUT_HEX);
2352 break;
2353 case 'X':
2354 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX);
2355 break;
2356 default:
2357 return options - 1;
2358 }
2359 }
2360 return NULL;
2361 }
2362
2363 char *
snmp_out_toggle_options(char * options)2364 snmp_out_toggle_options(char *options)
2365 {
2366 return snmp_out_options( options, 0, NULL );
2367 }
2368
2369 void
snmp_out_toggle_options_usage(const char * lead,FILE * outf)2370 snmp_out_toggle_options_usage(const char *lead, FILE * outf)
2371 {
2372 fprintf(outf, "%s0: print leading 0 for single-digit hex characters\n", lead);
2373 fprintf(outf, "%sa: print all strings in ascii format\n", lead);
2374 fprintf(outf, "%sb: do not break OID indexes down\n", lead);
2375 fprintf(outf, "%se: print enums numerically\n", lead);
2376 fprintf(outf, "%sE: escape quotes in string indices\n", lead);
2377 fprintf(outf, "%sf: print full OIDs on output\n", lead);
2378 fprintf(outf, "%sn: print OIDs numerically\n", lead);
2379 fprintf(outf, "%sp PRECISION: display floating point values with specified PRECISION (printf format string)\n", lead);
2380 fprintf(outf, "%sq: quick print for easier parsing\n", lead);
2381 fprintf(outf, "%sQ: quick print with equal-signs\n", lead); /* @@JDW */
2382 fprintf(outf, "%ss: print only last symbolic element of OID\n", lead);
2383 fprintf(outf, "%sS: print MIB module-id plus last element\n", lead);
2384 fprintf(outf, "%st: print timeticks unparsed as numeric integers\n",
2385 lead);
2386 fprintf(outf,
2387 "%sT: print human-readable text along with hex strings\n",
2388 lead);
2389 fprintf(outf, "%su: print OIDs using UCD-style prefix suppression\n",
2390 lead);
2391 fprintf(outf, "%sU: don't print units\n", lead);
2392 fprintf(outf, "%sv: print values only (not OID = value)\n", lead);
2393 fprintf(outf, "%sx: print all strings in hex format\n", lead);
2394 fprintf(outf, "%sX: extended index format\n", lead);
2395 }
2396
2397 char *
snmp_in_options(char * optarg,int argc,char * const * argv)2398 snmp_in_options(char *optarg, int argc, char *const *argv)
2399 {
2400 char *cp;
2401
2402 for (cp = optarg; *cp; cp++) {
2403 switch (*cp) {
2404 case 'b':
2405 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REGEX_ACCESS);
2406 break;
2407 case 'R':
2408 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RANDOM_ACCESS);
2409 break;
2410 case 'r':
2411 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
2412 break;
2413 case 'h':
2414 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
2415 break;
2416 case 'u':
2417 netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_READ_UCD_STYLE_OID);
2418 break;
2419 case 's':
2420 /* What if argc/argv are null ? */
2421 if (!*(++cp))
2422 cp = argv[optind++];
2423 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
2424 NETSNMP_DS_LIB_OIDSUFFIX,
2425 cp);
2426 return NULL; /* -Is... is a standalone option, so we're done here */
2427
2428 case 'S':
2429 /* What if argc/argv are null ? */
2430 if (!*(++cp))
2431 cp = argv[optind++];
2432 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
2433 NETSNMP_DS_LIB_OIDPREFIX,
2434 cp);
2435 return NULL; /* -IS... is a standalone option, so we're done here */
2436
2437 default:
2438 /*
2439 * Here? Or in snmp_parse_args?
2440 snmp_log(LOG_ERR, "Unknown input option passed to -I: %c.\n", *cp);
2441 */
2442 return cp;
2443 }
2444 }
2445 return NULL;
2446 }
2447
2448 char *
snmp_in_toggle_options(char * options)2449 snmp_in_toggle_options(char *options)
2450 {
2451 return snmp_in_options( options, 0, NULL );
2452 }
2453
2454
2455 /**
2456 * Prints out a help usage for the in* toggle options.
2457 *
2458 * @param lead The lead to print for every line.
2459 * @param outf The file descriptor to write to.
2460 *
2461 */
2462 void
snmp_in_toggle_options_usage(const char * lead,FILE * outf)2463 snmp_in_toggle_options_usage(const char *lead, FILE * outf)
2464 {
2465 fprintf(outf, "%sb: do best/regex matching to find a MIB node\n", lead);
2466 fprintf(outf, "%sh: don't apply DISPLAY-HINTs\n", lead);
2467 fprintf(outf, "%sr: do not check values for range/type legality\n", lead);
2468 fprintf(outf, "%sR: do random access to OID labels\n", lead);
2469 fprintf(outf,
2470 "%su: top-level OIDs must have '.' prefix (UCD-style)\n", lead);
2471 fprintf(outf,
2472 "%ss SUFFIX: Append all textual OIDs with SUFFIX before parsing\n",
2473 lead);
2474 fprintf(outf,
2475 "%sS PREFIX: Prepend all textual OIDs with PREFIX before parsing\n",
2476 lead);
2477 }
2478
2479 /***
2480 *
2481 */
2482 void
register_mib_handlers(void)2483 register_mib_handlers(void)
2484 {
2485 #ifndef NETSNMP_DISABLE_MIB_LOADING
2486 register_prenetsnmp_mib_handler("snmp", "mibdirs",
2487 handle_mibdirs_conf, NULL,
2488 "[mib-dirs|+mib-dirs|-mib-dirs]");
2489 register_prenetsnmp_mib_handler("snmp", "mibs",
2490 handle_mibs_conf, NULL,
2491 "[mib-tokens|+mib-tokens]");
2492 register_config_handler("snmp", "mibfile",
2493 handle_mibfile_conf, NULL, "mibfile-to-read");
2494 /*
2495 * register the snmp.conf configuration handlers for default
2496 * parsing behaviour
2497 */
2498
2499 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "showMibErrors",
2500 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_ERRORS);
2501 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "commentToEOL", /* Describes actual behaviour */
2502 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_COMMENT_TERM);
2503 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "strictCommentTerm", /* Backward compatibility */
2504 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_COMMENT_TERM);
2505 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "mibAllowUnderline",
2506 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL);
2507 netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "mibWarningLevel",
2508 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_WARNINGS);
2509 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "mibReplaceWithLatest",
2510 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_REPLACE);
2511 #endif
2512
2513 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printNumericEnums",
2514 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM);
2515 register_prenetsnmp_mib_handler("snmp", "printNumericOids",
2516 handle_print_numeric, NULL, "(1|yes|true|0|no|false)");
2517 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "escapeQuotes",
2518 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES);
2519 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "dontBreakdownOids",
2520 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS);
2521 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "quickPrinting",
2522 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT);
2523 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "numericTimeticks",
2524 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS);
2525 netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "oidOutputFormat",
2526 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
2527 netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "suffixPrinting",
2528 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
2529 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "extendedIndex",
2530 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX);
2531 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printHexText",
2532 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT);
2533 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printValueOnly",
2534 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE);
2535 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "dontPrintUnits",
2536 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS);
2537 netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "hexOutputLength",
2538 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH);
2539 }
2540
2541 #ifndef NETSNMP_DISABLE_MIB_LOADING
2542 /*
2543 * function : netsnmp_set_mib_directory
2544 * - This function sets the string of the directories
2545 * from which the MIB modules will be searched or
2546 * loaded.
2547 * arguments: const char *dir, which are the directories
2548 * from which the MIB modules will be searched or
2549 * loaded.
2550 * returns : -
2551 */
2552 void
netsnmp_set_mib_directory(const char * dir)2553 netsnmp_set_mib_directory(const char *dir)
2554 {
2555 const char *newdir;
2556 char *olddir, *tmpdir = NULL;
2557
2558 DEBUGTRACE;
2559 if (NULL == dir) {
2560 return;
2561 }
2562
2563 olddir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
2564 NETSNMP_DS_LIB_MIBDIRS);
2565 if (olddir) {
2566 if ((*dir == '+') || (*dir == '-')) {
2567 /** New dir starts with '+', thus we add it. */
2568 tmpdir = (char *)malloc(strlen(dir) + strlen(olddir) + 2);
2569 if (!tmpdir) {
2570 DEBUGMSGTL(("read_config:initmib", "set mibdir malloc failed"));
2571 return;
2572 }
2573 if (*dir++ == '+')
2574 sprintf(tmpdir, "%s%c%s", olddir, ENV_SEPARATOR_CHAR, dir);
2575 else
2576 sprintf(tmpdir, "%s%c%s", dir, ENV_SEPARATOR_CHAR, olddir);
2577 newdir = tmpdir;
2578 } else {
2579 newdir = dir;
2580 }
2581 } else {
2582 /** If dir starts with '+' skip '+' it. */
2583 newdir = ((*dir == '+') ? ++dir : dir);
2584 }
2585 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS,
2586 newdir);
2587
2588 /** set_string calls strdup, so if we allocated memory, free it */
2589 if (tmpdir == newdir) {
2590 SNMP_FREE(tmpdir);
2591 }
2592 }
2593
2594 /*
2595 * function : netsnmp_get_mib_directory
2596 * - This function returns a string of the directories
2597 * from which the MIB modules will be searched or
2598 * loaded.
2599 * If the value still does not exists, it will be made
2600 * from the evironment variable 'MIBDIRS' and/or the
2601 * default.
2602 * arguments: -
2603 * returns : char * of the directories in which the MIB modules
2604 * will be searched/loaded.
2605 */
2606
2607 char *
netsnmp_get_mib_directory(void)2608 netsnmp_get_mib_directory(void)
2609 {
2610 char *dir;
2611
2612 DEBUGTRACE;
2613 dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS);
2614 if (dir == NULL) {
2615 DEBUGMSGTL(("get_mib_directory", "no mib directories set\n"));
2616
2617 /** Check if the environment variable is set */
2618 dir = netsnmp_getenv("MIBDIRS");
2619 if (dir == NULL) {
2620 DEBUGMSGTL(("get_mib_directory", "no mib directories set by environment\n"));
2621 /** Not set use hard coded path */
2622 if (confmibdir == NULL) {
2623 DEBUGMSGTL(("get_mib_directory", "no mib directories set by config\n"));
2624 netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
2625 }
2626 else if ((*confmibdir == '+') || (*confmibdir == '-')) {
2627 DEBUGMSGTL(("get_mib_directory", "mib directories set by config (but added)\n"));
2628 netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
2629 netsnmp_set_mib_directory(confmibdir);
2630 }
2631 else {
2632 DEBUGMSGTL(("get_mib_directory", "mib directories set by config\n"));
2633 netsnmp_set_mib_directory(confmibdir);
2634 }
2635 } else if ((*dir == '+') || (*dir == '-')) {
2636 DEBUGMSGTL(("get_mib_directory", "mib directories set by environment (but added)\n"));
2637 netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS);
2638 netsnmp_set_mib_directory(dir);
2639 } else {
2640 DEBUGMSGTL(("get_mib_directory", "mib directories set by environment\n"));
2641 netsnmp_set_mib_directory(dir);
2642 }
2643 dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS);
2644 }
2645 DEBUGMSGTL(("get_mib_directory", "mib directories set '%s'\n", dir));
2646 return(dir);
2647 }
2648
2649 /*
2650 * function : netsnmp_fixup_mib_directory
2651 * arguments: -
2652 * returns : -
2653 */
2654 void
netsnmp_fixup_mib_directory(void)2655 netsnmp_fixup_mib_directory(void)
2656 {
2657 char *homepath = netsnmp_getenv("HOME");
2658 char *mibpath = netsnmp_get_mib_directory();
2659 char *oldmibpath = NULL;
2660 char *ptr_home;
2661 char *new_mibpath;
2662
2663 DEBUGTRACE;
2664 if (homepath && mibpath) {
2665 DEBUGMSGTL(("fixup_mib_directory", "mib directories '%s'\n", mibpath));
2666 while ((ptr_home = strstr(mibpath, "$HOME"))) {
2667 new_mibpath = (char *)malloc(strlen(mibpath) - strlen("$HOME") +
2668 strlen(homepath)+1);
2669 if (new_mibpath) {
2670 *ptr_home = 0; /* null out the spot where we stop copying */
2671 sprintf(new_mibpath, "%s%s%s", mibpath, homepath,
2672 ptr_home + strlen("$HOME"));
2673 /** swap in the new value and repeat */
2674 mibpath = new_mibpath;
2675 if (oldmibpath != NULL) {
2676 SNMP_FREE(oldmibpath);
2677 }
2678 oldmibpath = new_mibpath;
2679 } else {
2680 break;
2681 }
2682 }
2683
2684 netsnmp_set_mib_directory(mibpath);
2685
2686 /* The above copies the mibpath for us, so... */
2687
2688 if (oldmibpath != NULL) {
2689 SNMP_FREE(oldmibpath);
2690 }
2691
2692 }
2693
2694 }
2695
2696 /**
2697 * Initialises the mib reader.
2698 *
2699 * Reads in all settings from the environment.
2700 */
2701 void
netsnmp_init_mib(void)2702 netsnmp_init_mib(void)
2703 {
2704 const char *prefix;
2705 char *env_var, *entry;
2706 PrefixListPtr pp = &mib_prefixes[0];
2707 char *st = NULL;
2708
2709 if (Mib)
2710 return;
2711 netsnmp_init_mib_internals();
2712
2713 /*
2714 * Initialise the MIB directory/ies
2715 */
2716 netsnmp_fixup_mib_directory();
2717 env_var = strdup(netsnmp_get_mib_directory());
2718 if (!env_var)
2719 return;
2720
2721 DEBUGMSGTL(("init_mib",
2722 "Seen MIBDIRS: Looking in '%s' for mib dirs ...\n",
2723 env_var));
2724
2725 entry = strtok_r(env_var, ENV_SEPARATOR, &st);
2726 while (entry) {
2727 add_mibdir(entry);
2728 entry = strtok_r(NULL, ENV_SEPARATOR, &st);
2729 }
2730 SNMP_FREE(env_var);
2731
2732 env_var = netsnmp_getenv("MIBFILES");
2733 if (env_var != NULL) {
2734 if (*env_var == '+')
2735 entry = strtok_r(env_var+1, ENV_SEPARATOR, &st);
2736 else
2737 entry = strtok_r(env_var, ENV_SEPARATOR, &st);
2738 while (entry) {
2739 add_mibfile(entry, NULL);
2740 entry = strtok_r(NULL, ENV_SEPARATOR, &st);
2741 }
2742 }
2743
2744 netsnmp_init_mib_internals();
2745
2746 /*
2747 * Read in any modules or mibs requested
2748 */
2749
2750 env_var = netsnmp_getenv("MIBS");
2751 if (env_var == NULL) {
2752 if (confmibs != NULL)
2753 env_var = strdup(confmibs);
2754 else
2755 env_var = strdup(NETSNMP_DEFAULT_MIBS);
2756 } else {
2757 env_var = strdup(env_var);
2758 }
2759 if (env_var && ((*env_var == '+') || (*env_var == '-'))) {
2760 entry =
2761 (char *) malloc(strlen(NETSNMP_DEFAULT_MIBS) + strlen(env_var) + 2);
2762 if (!entry) {
2763 DEBUGMSGTL(("init_mib", "env mibs malloc failed"));
2764 SNMP_FREE(env_var);
2765 return;
2766 } else {
2767 if (*env_var == '+')
2768 sprintf(entry, "%s%c%s", NETSNMP_DEFAULT_MIBS, ENV_SEPARATOR_CHAR,
2769 env_var+1);
2770 else
2771 sprintf(entry, "%s%c%s", env_var+1, ENV_SEPARATOR_CHAR,
2772 NETSNMP_DEFAULT_MIBS );
2773 }
2774 SNMP_FREE(env_var);
2775 env_var = entry;
2776 }
2777
2778 DEBUGMSGTL(("init_mib",
2779 "Seen MIBS: Looking in '%s' for mib files ...\n",
2780 env_var));
2781 entry = strtok_r(env_var, ENV_SEPARATOR, &st);
2782 while (entry) {
2783 if (strcasecmp(entry, DEBUG_ALWAYS_TOKEN) == 0) {
2784 read_all_mibs();
2785 } else if (strstr(entry, "/") != NULL) {
2786 read_mib(entry);
2787 } else {
2788 netsnmp_read_module(entry);
2789 }
2790 entry = strtok_r(NULL, ENV_SEPARATOR, &st);
2791 }
2792 adopt_orphans();
2793 SNMP_FREE(env_var);
2794
2795 env_var = netsnmp_getenv("MIBFILES");
2796 if (env_var != NULL) {
2797 if ((*env_var == '+') || (*env_var == '-')) {
2798 #ifdef NETSNMP_DEFAULT_MIBFILES
2799 entry =
2800 (char *) malloc(strlen(NETSNMP_DEFAULT_MIBFILES) +
2801 strlen(env_var) + 2);
2802 if (!entry) {
2803 DEBUGMSGTL(("init_mib", "env mibfiles malloc failed"));
2804 } else {
2805 if (*env_var++ == '+')
2806 sprintf(entry, "%s%c%s", NETSNMP_DEFAULT_MIBFILES, ENV_SEPARATOR_CHAR,
2807 env_var );
2808 else
2809 sprintf(entry, "%s%c%s", env_var, ENV_SEPARATOR_CHAR,
2810 NETSNMP_DEFAULT_MIBFILES );
2811 }
2812 SNMP_FREE(env_var);
2813 env_var = entry;
2814 #else
2815 env_var = strdup(env_var + 1);
2816 #endif
2817 } else {
2818 env_var = strdup(env_var);
2819 }
2820 } else {
2821 #ifdef NETSNMP_DEFAULT_MIBFILES
2822 env_var = strdup(NETSNMP_DEFAULT_MIBFILES);
2823 #endif
2824 }
2825
2826 if (env_var != NULL) {
2827 DEBUGMSGTL(("init_mib",
2828 "Seen MIBFILES: Looking in '%s' for mib files ...\n",
2829 env_var));
2830 entry = strtok_r(env_var, ENV_SEPARATOR, &st);
2831 while (entry) {
2832 read_mib(entry);
2833 entry = strtok_r(NULL, ENV_SEPARATOR, &st);
2834 }
2835 SNMP_FREE(env_var);
2836 }
2837
2838 prefix = netsnmp_getenv("PREFIX");
2839
2840 if (!prefix)
2841 prefix = Standard_Prefix;
2842
2843 Prefix = (char *) malloc(strlen(prefix) + 2);
2844 if (!Prefix)
2845 DEBUGMSGTL(("init_mib", "Prefix malloc failed"));
2846 else
2847 strcpy(Prefix, prefix);
2848
2849 DEBUGMSGTL(("init_mib",
2850 "Seen PREFIX: Looking in '%s' for prefix ...\n", Prefix));
2851
2852 /*
2853 * remove trailing dot
2854 */
2855 if (Prefix) {
2856 env_var = &Prefix[strlen(Prefix) - 1];
2857 if (*env_var == '.')
2858 *env_var = '\0';
2859 }
2860
2861 pp->str = Prefix; /* fixup first mib_prefix entry */
2862 /*
2863 * now that the list of prefixes is built, save each string length.
2864 */
2865 while (pp->str) {
2866 pp->len = strlen(pp->str);
2867 pp++;
2868 }
2869
2870 Mib = tree_head; /* Backwards compatibility */
2871 tree_top = (struct tree *) calloc(1, sizeof(struct tree));
2872 /*
2873 * XX error check ?
2874 */
2875 if (tree_top) {
2876 tree_top->label = strdup("(top)");
2877 tree_top->child_list = tree_head;
2878 }
2879 }
2880
2881 #ifndef NETSNMP_NO_LEGACY_DEFINITIONS
2882 void
init_mib(void)2883 init_mib(void)
2884 {
2885 netsnmp_init_mib();
2886 }
2887 #endif
2888
2889
2890 /**
2891 * Unloads all mibs.
2892 */
2893 void
shutdown_mib(void)2894 shutdown_mib(void)
2895 {
2896 unload_all_mibs();
2897 if (tree_top) {
2898 if (tree_top->label)
2899 SNMP_FREE(tree_top->label);
2900 SNMP_FREE(tree_top);
2901 }
2902 tree_head = NULL;
2903 Mib = NULL;
2904 if (Prefix != NULL && Prefix != &Standard_Prefix[0])
2905 SNMP_FREE(Prefix);
2906 if (Prefix)
2907 Prefix = NULL;
2908 SNMP_FREE(confmibs);
2909 SNMP_FREE(confmibdir);
2910 }
2911
2912 /**
2913 * Prints the MIBs to the file fp.
2914 *
2915 * @param fp The file descriptor to print to.
2916 */
2917 #ifndef NETSNMP_FEATURE_REMOVE_PRINT_MIB
2918 void
print_mib(FILE * fp)2919 print_mib(FILE * fp)
2920 {
2921 print_subtree(fp, tree_head, 0);
2922 }
2923 #endif /* NETSNMP_FEATURE_REMOVE_PRINT_MIB */
2924
2925 void
print_ascii_dump(FILE * fp)2926 print_ascii_dump(FILE * fp)
2927 {
2928 fprintf(fp, "dump DEFINITIONS ::= BEGIN\n");
2929 print_ascii_dump_tree(fp, tree_head, 0);
2930 fprintf(fp, "END\n");
2931 }
2932
2933
2934 /**
2935 * Set's the printing function printomat in a subtree according
2936 * it's type
2937 *
2938 * @param subtree The subtree to set.
2939 */
2940 void
set_function(struct tree * subtree)2941 set_function(struct tree *subtree)
2942 {
2943 subtree->printer = NULL;
2944 switch (subtree->type) {
2945 case TYPE_OBJID:
2946 subtree->printomat = sprint_realloc_object_identifier;
2947 break;
2948 case TYPE_OCTETSTR:
2949 subtree->printomat = sprint_realloc_octet_string;
2950 break;
2951 case TYPE_INTEGER:
2952 subtree->printomat = sprint_realloc_integer;
2953 break;
2954 case TYPE_INTEGER32:
2955 subtree->printomat = sprint_realloc_integer;
2956 break;
2957 case TYPE_NETADDR:
2958 subtree->printomat = sprint_realloc_networkaddress;
2959 break;
2960 case TYPE_IPADDR:
2961 subtree->printomat = sprint_realloc_ipaddress;
2962 break;
2963 case TYPE_COUNTER:
2964 subtree->printomat = sprint_realloc_counter;
2965 break;
2966 case TYPE_GAUGE:
2967 subtree->printomat = sprint_realloc_gauge;
2968 break;
2969 case TYPE_TIMETICKS:
2970 subtree->printomat = sprint_realloc_timeticks;
2971 break;
2972 case TYPE_OPAQUE:
2973 subtree->printomat = sprint_realloc_opaque;
2974 break;
2975 case TYPE_NULL:
2976 subtree->printomat = sprint_realloc_null;
2977 break;
2978 case TYPE_BITSTRING:
2979 subtree->printomat = sprint_realloc_bitstring;
2980 break;
2981 case TYPE_NSAPADDRESS:
2982 subtree->printomat = sprint_realloc_nsapaddress;
2983 break;
2984 case TYPE_COUNTER64:
2985 subtree->printomat = sprint_realloc_counter64;
2986 break;
2987 case TYPE_UINTEGER:
2988 subtree->printomat = sprint_realloc_uinteger;
2989 break;
2990 case TYPE_UNSIGNED32:
2991 subtree->printomat = sprint_realloc_gauge;
2992 break;
2993 case TYPE_OTHER:
2994 default:
2995 subtree->printomat = sprint_realloc_by_type;
2996 break;
2997 }
2998 }
2999
3000 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3001
3002 /**
3003 * Reads an object identifier from an input string into internal OID form.
3004 *
3005 * When called, out_len must hold the maximum length of the output array.
3006 *
3007 * @param input the input string.
3008 * @param output the oid wirte.
3009 * @param out_len number of subid's in output.
3010 *
3011 * @return 1 if successful.
3012 *
3013 * If an error occurs, this function returns 0 and MAY set snmp_errno.
3014 * snmp_errno is NOT set if SET_SNMP_ERROR evaluates to nothing.
3015 * This can make multi-threaded use a tiny bit more robust.
3016 */
3017 int
read_objid(const char * input,oid * output,size_t * out_len)3018 read_objid(const char *input, oid * output, size_t * out_len)
3019 { /* number of subid's in "output" */
3020 #ifndef NETSNMP_DISABLE_MIB_LOADING
3021 struct tree *root = tree_top;
3022 char buf[SPRINT_MAX_LEN];
3023 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3024 int ret, max_out_len;
3025 char *name, ch;
3026 const char *cp;
3027
3028 cp = input;
3029 while ((ch = *cp)) {
3030 if (('0' <= ch && ch <= '9')
3031 || ('a' <= ch && ch <= 'z')
3032 || ('A' <= ch && ch <= 'Z')
3033 || ch == '-')
3034 cp++;
3035 else
3036 break;
3037 }
3038 #ifndef NETSNMP_DISABLE_MIB_LOADING
3039 if (ch == ':')
3040 return get_node(input, output, out_len);
3041 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3042
3043 if (*input == '.')
3044 input++;
3045 #ifndef NETSNMP_DISABLE_MIB_LOADING
3046 else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_READ_UCD_STYLE_OID)) {
3047 /*
3048 * get past leading '.', append '.' to Prefix.
3049 */
3050 if (*Prefix == '.')
3051 strlcpy(buf, Prefix + 1, sizeof(buf));
3052 else
3053 strlcpy(buf, Prefix, sizeof(buf));
3054 strlcat(buf, ".", sizeof(buf));
3055 strlcat(buf, input, sizeof(buf));
3056 input = buf;
3057 }
3058 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3059
3060 #ifndef NETSNMP_DISABLE_MIB_LOADING
3061 if ((root == NULL) && (tree_head != NULL)) {
3062 root = tree_head;
3063 }
3064 else if (root == NULL) {
3065 SET_SNMP_ERROR(SNMPERR_NOMIB);
3066 *out_len = 0;
3067 return 0;
3068 }
3069 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3070 name = strdup(input);
3071 max_out_len = *out_len;
3072 *out_len = 0;
3073 #ifndef NETSNMP_DISABLE_MIB_LOADING
3074 if ((ret =
3075 _add_strings_to_oid(root, name, output, out_len,
3076 max_out_len)) <= 0)
3077 #else
3078 if ((ret =
3079 _add_strings_to_oid(NULL, name, output, out_len,
3080 max_out_len)) <= 0)
3081 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3082 {
3083 if (ret == 0)
3084 ret = SNMPERR_UNKNOWN_OBJID;
3085 SET_SNMP_ERROR(ret);
3086 SNMP_FREE(name);
3087 return 0;
3088 }
3089 SNMP_FREE(name);
3090
3091 return 1;
3092 }
3093
3094 /**
3095 *
3096 */
3097 void
netsnmp_sprint_realloc_objid(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow,const oid * objid,size_t objidlen)3098 netsnmp_sprint_realloc_objid(u_char ** buf, size_t * buf_len,
3099 size_t * out_len, int allow_realloc,
3100 int *buf_overflow,
3101 const oid * objid, size_t objidlen)
3102 {
3103 u_char *tbuf = NULL, *cp = NULL;
3104 size_t tbuf_len = 256, tout_len = 0;
3105 int tbuf_overflow = 0;
3106 int output_format;
3107
3108 if ((tbuf = (u_char *) calloc(tbuf_len, 1)) == NULL) {
3109 tbuf_overflow = 1;
3110 } else {
3111 *tbuf = '.';
3112 tout_len = 1;
3113 }
3114
3115 _oid_finish_printing(objid, objidlen,
3116 &tbuf, &tbuf_len, &tout_len,
3117 allow_realloc, &tbuf_overflow);
3118
3119 if (tbuf_overflow) {
3120 if (!*buf_overflow) {
3121 snmp_strcat(buf, buf_len, out_len, allow_realloc, tbuf);
3122 *buf_overflow = 1;
3123 }
3124 SNMP_FREE(tbuf);
3125 return;
3126 }
3127
3128 output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
3129 if (0 == output_format) {
3130 output_format = NETSNMP_OID_OUTPUT_NUMERIC;
3131 }
3132 switch (output_format) {
3133 case NETSNMP_OID_OUTPUT_FULL:
3134 case NETSNMP_OID_OUTPUT_NUMERIC:
3135 case NETSNMP_OID_OUTPUT_SUFFIX:
3136 case NETSNMP_OID_OUTPUT_MODULE:
3137 cp = tbuf;
3138 break;
3139
3140 case NETSNMP_OID_OUTPUT_NONE:
3141 default:
3142 cp = NULL;
3143 }
3144
3145 if (!*buf_overflow &&
3146 !snmp_strcat(buf, buf_len, out_len, allow_realloc, cp)) {
3147 *buf_overflow = 1;
3148 }
3149 SNMP_FREE(tbuf);
3150 }
3151
3152 /**
3153 *
3154 */
3155 #ifdef NETSNMP_DISABLE_MIB_LOADING
3156 void
netsnmp_sprint_realloc_objid_tree(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow,const oid * objid,size_t objidlen)3157 netsnmp_sprint_realloc_objid_tree(u_char ** buf, size_t * buf_len,
3158 size_t * out_len, int allow_realloc,
3159 int *buf_overflow,
3160 const oid * objid, size_t objidlen)
3161 {
3162 netsnmp_sprint_realloc_objid(buf, buf_len, out_len, allow_realloc,
3163 buf_overflow, objid, objidlen);
3164 }
3165 #else
3166 struct tree *
netsnmp_sprint_realloc_objid_tree(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow,const oid * objid,size_t objidlen)3167 netsnmp_sprint_realloc_objid_tree(u_char ** buf, size_t * buf_len,
3168 size_t * out_len, int allow_realloc,
3169 int *buf_overflow,
3170 const oid * objid, size_t objidlen)
3171 {
3172 u_char *tbuf = NULL, *cp = NULL;
3173 size_t tbuf_len = 512, tout_len = 0;
3174 struct tree *subtree = tree_head;
3175 size_t midpoint_offset = 0;
3176 int tbuf_overflow = 0;
3177 int output_format;
3178
3179 if ((tbuf = (u_char *) calloc(tbuf_len, 1)) == NULL) {
3180 tbuf_overflow = 1;
3181 } else {
3182 *tbuf = '.';
3183 tout_len = 1;
3184 }
3185
3186 subtree = _get_realloc_symbol(objid, objidlen, subtree,
3187 &tbuf, &tbuf_len, &tout_len,
3188 allow_realloc, &tbuf_overflow, NULL,
3189 &midpoint_offset);
3190
3191 if (tbuf_overflow) {
3192 if (!*buf_overflow) {
3193 snmp_strcat(buf, buf_len, out_len, allow_realloc, tbuf);
3194 *buf_overflow = 1;
3195 }
3196 SNMP_FREE(tbuf);
3197 return subtree;
3198 }
3199
3200 output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
3201 if (0 == output_format) {
3202 output_format = NETSNMP_OID_OUTPUT_MODULE;
3203 }
3204 switch (output_format) {
3205 case NETSNMP_OID_OUTPUT_FULL:
3206 case NETSNMP_OID_OUTPUT_NUMERIC:
3207 cp = tbuf;
3208 break;
3209
3210 case NETSNMP_OID_OUTPUT_SUFFIX:
3211 case NETSNMP_OID_OUTPUT_MODULE:
3212 for (cp = tbuf; *cp; cp++);
3213
3214 if (midpoint_offset != 0) {
3215 cp = tbuf + midpoint_offset - 2; /* beyond the '.' */
3216 } else {
3217 while (cp >= tbuf) {
3218 if (isalpha(*cp)) {
3219 break;
3220 }
3221 cp--;
3222 }
3223 }
3224
3225 while (cp >= tbuf) {
3226 if (*cp == '.') {
3227 break;
3228 }
3229 cp--;
3230 }
3231
3232 cp++;
3233
3234 if ((NETSNMP_OID_OUTPUT_MODULE == output_format)
3235 && cp > tbuf) {
3236 char modbuf[256] = { 0 }, *mod =
3237 module_name(subtree->modid, modbuf);
3238
3239 /*
3240 * Don't add the module ID if it's just numeric (i.e. we couldn't look
3241 * it up properly.
3242 */
3243
3244 if (!*buf_overflow && modbuf[0] != '#') {
3245 if (!snmp_strcat
3246 (buf, buf_len, out_len, allow_realloc,
3247 (const u_char *) mod)
3248 || !snmp_strcat(buf, buf_len, out_len, allow_realloc,
3249 (const u_char *) "::")) {
3250 *buf_overflow = 1;
3251 }
3252 }
3253 }
3254 break;
3255
3256 case NETSNMP_OID_OUTPUT_UCD:
3257 {
3258 PrefixListPtr pp = &mib_prefixes[0];
3259 size_t ilen, tlen;
3260 const char *testcp;
3261
3262 cp = tbuf;
3263 tlen = strlen((char *) tbuf);
3264
3265 while (pp->str) {
3266 ilen = pp->len;
3267 testcp = pp->str;
3268
3269 if ((tlen > ilen) && memcmp(tbuf, testcp, ilen) == 0) {
3270 cp += (ilen + 1);
3271 break;
3272 }
3273 pp++;
3274 }
3275 break;
3276 }
3277
3278 case NETSNMP_OID_OUTPUT_NONE:
3279 default:
3280 cp = NULL;
3281 }
3282
3283 if (!*buf_overflow &&
3284 !snmp_strcat(buf, buf_len, out_len, allow_realloc, cp)) {
3285 *buf_overflow = 1;
3286 }
3287 SNMP_FREE(tbuf);
3288 return subtree;
3289 }
3290 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3291
3292 int
sprint_realloc_objid(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const oid * objid,size_t objidlen)3293 sprint_realloc_objid(u_char ** buf, size_t * buf_len,
3294 size_t * out_len, int allow_realloc,
3295 const oid * objid, size_t objidlen)
3296 {
3297 int buf_overflow = 0;
3298
3299 netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len, allow_realloc,
3300 &buf_overflow, objid, objidlen);
3301 return !buf_overflow;
3302 }
3303
3304 #ifndef NETSNMP_FEATURE_REMOVE_SPRINT_OBJID
3305 int
snprint_objid(char * buf,size_t buf_len,const oid * objid,size_t objidlen)3306 snprint_objid(char *buf, size_t buf_len,
3307 const oid * objid, size_t objidlen)
3308 {
3309 size_t out_len = 0;
3310
3311 if (sprint_realloc_objid((u_char **) & buf, &buf_len, &out_len, 0,
3312 objid, objidlen)) {
3313 return (int) out_len;
3314 } else {
3315 return -1;
3316 }
3317 }
3318 #endif /* NETSNMP_FEATURE_REMOVE_SPRINT_OBJID */
3319
3320 /**
3321 * Prints an oid to stdout.
3322 *
3323 * @param objid The oid to print
3324 * @param objidlen The length of oidid.
3325 */
3326 void
print_objid(const oid * objid,size_t objidlen)3327 print_objid(const oid * objid, size_t objidlen)
3328 { /* number of subidentifiers */
3329 fprint_objid(stdout, objid, objidlen);
3330 }
3331
3332
3333 /**
3334 * Prints an oid to a file descriptor.
3335 *
3336 * @param f The file descriptor to print to.
3337 * @param objid The oid to print
3338 * @param objidlen The length of oidid.
3339 */
3340 void
fprint_objid(FILE * f,const oid * objid,size_t objidlen)3341 fprint_objid(FILE * f, const oid * objid, size_t objidlen)
3342 { /* number of subidentifiers */
3343 u_char *buf = NULL;
3344 size_t buf_len = 256, out_len = 0;
3345 int buf_overflow = 0;
3346
3347 if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) {
3348 fprintf(f, "[TRUNCATED]\n");
3349 return;
3350 } else {
3351 netsnmp_sprint_realloc_objid_tree(&buf, &buf_len, &out_len, 1,
3352 &buf_overflow, objid, objidlen);
3353 if (buf_overflow) {
3354 fprintf(f, "%s [TRUNCATED]\n", buf);
3355 } else {
3356 fprintf(f, "%s\n", buf);
3357 }
3358 }
3359
3360 SNMP_FREE(buf);
3361 }
3362
3363 int
sprint_realloc_variable(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3364 sprint_realloc_variable(u_char ** buf, size_t * buf_len,
3365 size_t * out_len, int allow_realloc,
3366 const oid * objid, size_t objidlen,
3367 const netsnmp_variable_list * variable)
3368 {
3369 int buf_overflow = 0;
3370
3371 #ifndef NETSNMP_DISABLE_MIB_LOADING
3372 struct tree *subtree = tree_head;
3373
3374 subtree =
3375 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3376 netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len,
3377 allow_realloc, &buf_overflow,
3378 objid, objidlen);
3379
3380 if (buf_overflow) {
3381 return 0;
3382 }
3383 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE)) {
3384 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) {
3385 if (!snmp_strcat
3386 (buf, buf_len, out_len, allow_realloc,
3387 (const u_char *) " = ")) {
3388 return 0;
3389 }
3390 } else {
3391 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) {
3392 if (!snmp_strcat
3393 (buf, buf_len, out_len, allow_realloc,
3394 (const u_char *) " ")) {
3395 return 0;
3396 }
3397 } else {
3398 if (!snmp_strcat
3399 (buf, buf_len, out_len, allow_realloc,
3400 (const u_char *) " = ")) {
3401 return 0;
3402 }
3403 } /* end if-else NETSNMP_DS_LIB_QUICK_PRINT */
3404 } /* end if-else NETSNMP_DS_LIB_QUICKE_PRINT */
3405 } else {
3406 *out_len = 0;
3407 }
3408
3409 if (variable->type == SNMP_NOSUCHOBJECT) {
3410 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3411 (const u_char *)
3412 "No Such Object available on this agent at this OID");
3413 } else if (variable->type == SNMP_NOSUCHINSTANCE) {
3414 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3415 (const u_char *)
3416 "No Such Instance currently exists at this OID");
3417 } else if (variable->type == SNMP_ENDOFMIBVIEW) {
3418 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3419 (const u_char *)
3420 "No more variables left in this MIB View (It is past the end of the MIB tree)");
3421 #ifndef NETSNMP_DISABLE_MIB_LOADING
3422 } else if (subtree) {
3423 const char *units = NULL;
3424 const char *hint = NULL;
3425 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3426 NETSNMP_DS_LIB_DONT_PRINT_UNITS)) {
3427 units = subtree->units;
3428 }
3429
3430 if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3431 NETSNMP_DS_LIB_NO_DISPLAY_HINT)) {
3432 hint = subtree->hint;
3433 }
3434
3435 if (subtree->printomat) {
3436 return (*subtree->printomat) (buf, buf_len, out_len,
3437 allow_realloc, variable,
3438 subtree->enums, hint,
3439 units);
3440 } else {
3441 return sprint_realloc_by_type(buf, buf_len, out_len,
3442 allow_realloc, variable,
3443 subtree->enums, hint,
3444 units);
3445 }
3446 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3447 } else {
3448 /*
3449 * Handle rare case where tree is empty.
3450 */
3451 return sprint_realloc_by_type(buf, buf_len, out_len, allow_realloc,
3452 variable, NULL, NULL, NULL);
3453 }
3454 }
3455
3456 #ifndef NETSNMP_FEATURE_REMOVE_SNPRINT_VARABLE
3457 int
snprint_variable(char * buf,size_t buf_len,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3458 snprint_variable(char *buf, size_t buf_len,
3459 const oid * objid, size_t objidlen,
3460 const netsnmp_variable_list * variable)
3461 {
3462 size_t out_len = 0;
3463
3464 if (sprint_realloc_variable((u_char **) & buf, &buf_len, &out_len, 0,
3465 objid, objidlen, variable)) {
3466 return (int) out_len;
3467 } else {
3468 return -1;
3469 }
3470 }
3471 #endif /* NETSNMP_FEATURE_REMOVE_SNPRINT_VARABLE */
3472
3473 /**
3474 * Prints a variable to stdout.
3475 *
3476 * @param objid The object id.
3477 * @param objidlen The length of teh object id.
3478 * @param variable The variable to print.
3479 */
3480 void
print_variable(const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3481 print_variable(const oid * objid,
3482 size_t objidlen, const netsnmp_variable_list * variable)
3483 {
3484 fprint_variable(stdout, objid, objidlen, variable);
3485 }
3486
3487
3488 /**
3489 * Prints a variable to a file descriptor.
3490 *
3491 * @param f The file descriptor to print to.
3492 * @param objid The object id.
3493 * @param objidlen The length of teh object id.
3494 * @param variable The variable to print.
3495 */
3496 void
fprint_variable(FILE * f,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3497 fprint_variable(FILE * f,
3498 const oid * objid,
3499 size_t objidlen, const netsnmp_variable_list * variable)
3500 {
3501 u_char *buf = NULL;
3502 size_t buf_len = 256, out_len = 0;
3503
3504 if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) {
3505 fprintf(f, "[TRUNCATED]\n");
3506 return;
3507 } else {
3508 if (sprint_realloc_variable(&buf, &buf_len, &out_len, 1,
3509 objid, objidlen, variable)) {
3510 fprintf(f, "%s\n", buf);
3511 } else {
3512 fprintf(f, "%s [TRUNCATED]\n", buf);
3513 }
3514 }
3515
3516 SNMP_FREE(buf);
3517 }
3518
3519 int
sprint_realloc_value(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3520 sprint_realloc_value(u_char ** buf, size_t * buf_len,
3521 size_t * out_len, int allow_realloc,
3522 const oid * objid, size_t objidlen,
3523 const netsnmp_variable_list * variable)
3524 {
3525 if (variable->type == SNMP_NOSUCHOBJECT) {
3526 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3527 (const u_char *)
3528 "No Such Object available on this agent at this OID");
3529 } else if (variable->type == SNMP_NOSUCHINSTANCE) {
3530 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3531 (const u_char *)
3532 "No Such Instance currently exists at this OID");
3533 } else if (variable->type == SNMP_ENDOFMIBVIEW) {
3534 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
3535 (const u_char *)
3536 "No more variables left in this MIB View (It is past the end of the MIB tree)");
3537 } else {
3538 #ifndef NETSNMP_DISABLE_MIB_LOADING
3539 const char *units = NULL;
3540 struct tree *subtree = tree_head;
3541 subtree = get_tree(objid, objidlen, subtree);
3542 if (subtree && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3543 NETSNMP_DS_LIB_DONT_PRINT_UNITS)) {
3544 units = subtree->units;
3545 }
3546 if (subtree) {
3547 if(subtree->printomat) {
3548 return (*subtree->printomat) (buf, buf_len, out_len,
3549 allow_realloc, variable,
3550 subtree->enums, subtree->hint,
3551 units);
3552 } else {
3553 return sprint_realloc_by_type(buf, buf_len, out_len,
3554 allow_realloc, variable,
3555 subtree->enums, subtree->hint,
3556 units);
3557 }
3558 }
3559 #endif /* NETSNMP_DISABLE_MIB_LOADING */
3560 return sprint_realloc_by_type(buf, buf_len, out_len,
3561 allow_realloc, variable,
3562 NULL, NULL, NULL);
3563 }
3564 }
3565
3566 #ifndef NETSNMP_FEATURE_REMOVE_SNPRINT_VALUE
3567 /* used in the perl module */
3568 int
snprint_value(char * buf,size_t buf_len,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3569 snprint_value(char *buf, size_t buf_len,
3570 const oid * objid, size_t objidlen,
3571 const netsnmp_variable_list * variable)
3572 {
3573 size_t out_len = 0;
3574
3575 if (sprint_realloc_value((u_char **) & buf, &buf_len, &out_len, 0,
3576 objid, objidlen, variable)) {
3577 return (int) out_len;
3578 } else {
3579 return -1;
3580 }
3581 }
3582 #endif /* NETSNMP_FEATURE_REMOVE_SNPRINT_VALUE */
3583
3584 void
print_value(const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3585 print_value(const oid * objid,
3586 size_t objidlen, const netsnmp_variable_list * variable)
3587 {
3588 fprint_value(stdout, objid, objidlen, variable);
3589 }
3590
3591 void
fprint_value(FILE * f,const oid * objid,size_t objidlen,const netsnmp_variable_list * variable)3592 fprint_value(FILE * f,
3593 const oid * objid,
3594 size_t objidlen, const netsnmp_variable_list * variable)
3595 {
3596 u_char *buf = NULL;
3597 size_t buf_len = 256, out_len = 0;
3598
3599 if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) {
3600 fprintf(f, "[TRUNCATED]\n");
3601 return;
3602 } else {
3603 if (sprint_realloc_value(&buf, &buf_len, &out_len, 1,
3604 objid, objidlen, variable)) {
3605 fprintf(f, "%s\n", buf);
3606 } else {
3607 fprintf(f, "%s [TRUNCATED]\n", buf);
3608 }
3609 }
3610
3611 SNMP_FREE(buf);
3612 }
3613
3614
3615 /**
3616 * Takes the value in VAR and turns it into an OID segment in var->name.
3617 *
3618 * @param var The variable.
3619 *
3620 * @return SNMPERR_SUCCESS or SNMPERR_GENERR
3621 */
3622 int
build_oid_segment(netsnmp_variable_list * var)3623 build_oid_segment(netsnmp_variable_list * var)
3624 {
3625 int i;
3626 uint32_t ipaddr;
3627
3628 if (var->name && var->name != var->name_loc)
3629 SNMP_FREE(var->name);
3630 switch (var->type) {
3631 case ASN_INTEGER:
3632 case ASN_COUNTER:
3633 case ASN_GAUGE:
3634 case ASN_TIMETICKS:
3635 var->name_length = 1;
3636 var->name = var->name_loc;
3637 var->name[0] = *(var->val.integer);
3638 break;
3639
3640 case ASN_IPADDRESS:
3641 var->name_length = 4;
3642 var->name = var->name_loc;
3643 memcpy(&ipaddr, var->val.string, sizeof(ipaddr));
3644 var->name[0] = (ipaddr >> 24) & 0xff;
3645 var->name[1] = (ipaddr >> 16) & 0xff;
3646 var->name[2] = (ipaddr >> 8) & 0xff;
3647 var->name[3] = (ipaddr >> 0) & 0xff;
3648 break;
3649
3650 case ASN_PRIV_IMPLIED_OBJECT_ID:
3651 var->name_length = var->val_len / sizeof(oid);
3652 if (var->name_length > (sizeof(var->name_loc) / sizeof(oid)))
3653 var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
3654 else
3655 var->name = var->name_loc;
3656 if (var->name == NULL)
3657 return SNMPERR_GENERR;
3658
3659 for (i = 0; i < (int) var->name_length; i++)
3660 var->name[i] = var->val.objid[i];
3661 break;
3662
3663 case ASN_OBJECT_ID:
3664 var->name_length = var->val_len / sizeof(oid) + 1;
3665 if (var->name_length > (sizeof(var->name_loc) / sizeof(oid)))
3666 var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
3667 else
3668 var->name = var->name_loc;
3669 if (var->name == NULL)
3670 return SNMPERR_GENERR;
3671
3672 var->name[0] = var->name_length - 1;
3673 for (i = 0; i < (int) var->name_length - 1; i++)
3674 var->name[i + 1] = var->val.objid[i];
3675 break;
3676
3677 case ASN_PRIV_IMPLIED_OCTET_STR:
3678 var->name_length = var->val_len;
3679 if (var->name_length > (sizeof(var->name_loc) / sizeof(oid)))
3680 var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
3681 else
3682 var->name = var->name_loc;
3683 if (var->name == NULL)
3684 return SNMPERR_GENERR;
3685
3686 for (i = 0; i < (int) var->val_len; i++)
3687 var->name[i] = (oid) var->val.string[i];
3688 break;
3689
3690 case ASN_OPAQUE:
3691 case ASN_OCTET_STR:
3692 var->name_length = var->val_len + 1;
3693 if (var->name_length > (sizeof(var->name_loc) / sizeof(oid)))
3694 var->name = (oid *) malloc(sizeof(oid) * (var->name_length));
3695 else
3696 var->name = var->name_loc;
3697 if (var->name == NULL)
3698 return SNMPERR_GENERR;
3699
3700 var->name[0] = (oid) var->val_len;
3701 for (i = 0; i < (int) var->val_len; i++)
3702 var->name[i + 1] = (oid) var->val.string[i];
3703 break;
3704
3705 default:
3706 DEBUGMSGTL(("build_oid_segment",
3707 "invalid asn type: %d\n", var->type));
3708 return SNMPERR_GENERR;
3709 }
3710
3711 if (var->name_length > MAX_OID_LEN) {
3712 DEBUGMSGTL(("build_oid_segment",
3713 "Something terribly wrong, namelen = %lu\n",
3714 (unsigned long)var->name_length));
3715 return SNMPERR_GENERR;
3716 }
3717
3718 return SNMPERR_SUCCESS;
3719 }
3720
3721
3722 /**
3723 * Concatenate a prefix and the OIDs of a variable list.
3724 *
3725 * @param[out] in Output buffer.
3726 * @param[in] in_len Maximum number of OID components that fit in @in.
3727 * @param[out] out_len Number of OID components of the result.
3728 * @param[in] prefix OID to be copied to the start of the output buffer.
3729 * @param[in] prefix_len Number of OID components to copy from @prefix.
3730 * @param[in/out] indexes Variable list for which var->name should be set
3731 * for each variable var in the list and whose OIDs
3732 * should be appended to @in.
3733 */
3734 int
build_oid_noalloc(oid * in,size_t in_len,size_t * out_len,const oid * prefix,size_t prefix_len,netsnmp_variable_list * indexes)3735 build_oid_noalloc(oid * in, size_t in_len, size_t * out_len,
3736 const oid * prefix, size_t prefix_len,
3737 netsnmp_variable_list * indexes)
3738 {
3739 netsnmp_variable_list *var;
3740
3741 if (prefix) {
3742 if (in_len < prefix_len)
3743 return SNMPERR_GENERR;
3744 memcpy(in, prefix, prefix_len * sizeof(oid));
3745 *out_len = prefix_len;
3746 } else {
3747 *out_len = 0;
3748 }
3749
3750 for (var = indexes; var != NULL; var = var->next_variable) {
3751 if (build_oid_segment(var) != SNMPERR_SUCCESS)
3752 return SNMPERR_GENERR;
3753 if (var->name_length + *out_len <= in_len) {
3754 memcpy(&(in[*out_len]), var->name,
3755 sizeof(oid) * var->name_length);
3756 *out_len += var->name_length;
3757 } else {
3758 return SNMPERR_GENERR;
3759 }
3760 }
3761
3762 DEBUGMSGTL(("build_oid_noalloc", "generated: "));
3763 DEBUGMSGOID(("build_oid_noalloc", in, *out_len));
3764 DEBUGMSG(("build_oid_noalloc", "\n"));
3765 return SNMPERR_SUCCESS;
3766 }
3767
3768 int
build_oid(oid ** out,size_t * out_len,oid * prefix,size_t prefix_len,netsnmp_variable_list * indexes)3769 build_oid(oid ** out, size_t * out_len,
3770 oid * prefix, size_t prefix_len, netsnmp_variable_list * indexes)
3771 {
3772 oid tmpout[MAX_OID_LEN];
3773
3774 /*
3775 * xxx-rks: inefficent. try only building segments to find index len:
3776 * for (var = indexes; var != NULL; var = var->next_variable) {
3777 * if (build_oid_segment(var) != SNMPERR_SUCCESS)
3778 * return SNMPERR_GENERR;
3779 * *out_len += var->name_length;
3780 *
3781 * then see if it fits in existing buffer, or realloc buffer.
3782 */
3783 if (build_oid_noalloc(tmpout, sizeof(tmpout) / sizeof(tmpout[0]), out_len,
3784 prefix, prefix_len, indexes) != SNMPERR_SUCCESS)
3785 return SNMPERR_GENERR;
3786
3787 /** xxx-rks: should free previous value? */
3788 snmp_clone_mem((void **) out, (void *) tmpout, *out_len * sizeof(oid));
3789
3790 return SNMPERR_SUCCESS;
3791 }
3792
3793 /*
3794 * vblist_out must contain a pre-allocated string of variables into
3795 * which indexes can be extracted based on the previously existing
3796 * types in the variable chain
3797 * returns:
3798 * SNMPERR_GENERR on error
3799 * SNMPERR_SUCCESS on success
3800 */
3801
3802 int
parse_oid_indexes(oid * oidIndex,size_t oidLen,netsnmp_variable_list * data)3803 parse_oid_indexes(oid * oidIndex, size_t oidLen,
3804 netsnmp_variable_list * data)
3805 {
3806 netsnmp_variable_list *var = data;
3807
3808 while (var && oidLen > 0) {
3809
3810 if (parse_one_oid_index(&oidIndex, &oidLen, var, 0) !=
3811 SNMPERR_SUCCESS)
3812 break;
3813
3814 var = var->next_variable;
3815 }
3816
3817 if (var != NULL || oidLen != 0)
3818 return SNMPERR_GENERR;
3819 return SNMPERR_SUCCESS;
3820 }
3821
3822
3823 int
parse_one_oid_index(oid ** oidStart,size_t * oidLen,netsnmp_variable_list * data,int complete)3824 parse_one_oid_index(oid ** oidStart, size_t * oidLen,
3825 netsnmp_variable_list * data, int complete)
3826 {
3827 netsnmp_variable_list *var = data;
3828 oid tmpout[MAX_OID_LEN];
3829 unsigned int i;
3830 unsigned int uitmp = 0;
3831
3832 oid *oidIndex = *oidStart;
3833
3834 if (var == NULL || ((*oidLen == 0) && (complete == 0)))
3835 return SNMPERR_GENERR;
3836 else {
3837 switch (var->type) {
3838 case ASN_INTEGER:
3839 case ASN_COUNTER:
3840 case ASN_GAUGE:
3841 case ASN_TIMETICKS:
3842 if (*oidLen) {
3843 snmp_set_var_value(var, (u_char *) oidIndex++,
3844 sizeof(oid));
3845 --(*oidLen);
3846 } else {
3847 snmp_set_var_value(var, (u_char *) oidLen, sizeof(long));
3848 }
3849 DEBUGMSGTL(("parse_oid_indexes",
3850 "Parsed int(%d): %ld\n", var->type,
3851 *var->val.integer));
3852 break;
3853
3854 case ASN_IPADDRESS:
3855 if ((4 > *oidLen) && (complete == 0))
3856 return SNMPERR_GENERR;
3857
3858 for (i = 0; i < 4 && i < *oidLen; ++i) {
3859 if (oidIndex[i] > 255) {
3860 DEBUGMSGTL(("parse_oid_indexes",
3861 "illegal oid in index: %" NETSNMP_PRIo "d\n",
3862 oidIndex[0]));
3863 return SNMPERR_GENERR; /* sub-identifier too large */
3864 }
3865 uitmp = uitmp + (oidIndex[i] << (8*(3-i)));
3866 }
3867 if (4 > (int) (*oidLen)) {
3868 oidIndex += *oidLen;
3869 (*oidLen) = 0;
3870 } else {
3871 oidIndex += 4;
3872 (*oidLen) -= 4;
3873 }
3874 uitmp = htonl(uitmp); /* put it in proper order for byte copies */
3875 uitmp =
3876 snmp_set_var_value(var, (u_char *) &uitmp, 4);
3877 DEBUGMSGTL(("parse_oid_indexes",
3878 "Parsed ipaddr(%d): %d.%d.%d.%d\n", var->type,
3879 var->val.string[0], var->val.string[1],
3880 var->val.string[2], var->val.string[3]));
3881 break;
3882
3883 case ASN_OBJECT_ID:
3884 case ASN_PRIV_IMPLIED_OBJECT_ID:
3885 if (var->type == ASN_PRIV_IMPLIED_OBJECT_ID) {
3886 /*
3887 * might not be implied, might be fixed len. check if
3888 * caller set up val len, and use it if they did.
3889 */
3890 if (0 == var->val_len)
3891 uitmp = *oidLen;
3892 else {
3893 DEBUGMSGTL(("parse_oid_indexes:fix", "fixed len oid\n"));
3894 uitmp = var->val_len;
3895 }
3896 } else {
3897 if (*oidLen) {
3898 uitmp = *oidIndex++;
3899 --(*oidLen);
3900 } else {
3901 uitmp = 0;
3902 }
3903 if ((uitmp > *oidLen) && (complete == 0))
3904 return SNMPERR_GENERR;
3905 }
3906
3907 if (uitmp > MAX_OID_LEN)
3908 return SNMPERR_GENERR; /* too big and illegal */
3909
3910 if (uitmp > *oidLen) {
3911 memcpy(tmpout, oidIndex, sizeof(oid) * (*oidLen));
3912 memset(&tmpout[*oidLen], 0x00,
3913 sizeof(oid) * (uitmp - *oidLen));
3914 snmp_set_var_value(var, (u_char *) tmpout,
3915 sizeof(oid) * uitmp);
3916 oidIndex += *oidLen;
3917 (*oidLen) = 0;
3918 } else {
3919 snmp_set_var_value(var, (u_char *) oidIndex,
3920 sizeof(oid) * uitmp);
3921 oidIndex += uitmp;
3922 (*oidLen) -= uitmp;
3923 }
3924
3925 DEBUGMSGTL(("parse_oid_indexes", "Parsed oid: "));
3926 DEBUGMSGOID(("parse_oid_indexes",
3927 var->val.objid, var->val_len / sizeof(oid)));
3928 DEBUGMSG(("parse_oid_indexes", "\n"));
3929 break;
3930
3931 case ASN_OPAQUE:
3932 case ASN_OCTET_STR:
3933 case ASN_PRIV_IMPLIED_OCTET_STR:
3934 if (var->type == ASN_PRIV_IMPLIED_OCTET_STR) {
3935 /*
3936 * might not be implied, might be fixed len. check if
3937 * caller set up val len, and use it if they did.
3938 */
3939 if (0 == var->val_len)
3940 uitmp = *oidLen;
3941 else {
3942 DEBUGMSGTL(("parse_oid_indexes:fix", "fixed len str\n"));
3943 uitmp = var->val_len;
3944 }
3945 } else {
3946 if (*oidLen) {
3947 uitmp = *oidIndex++;
3948 --(*oidLen);
3949 } else {
3950 uitmp = 0;
3951 }
3952 if ((uitmp > *oidLen) && (complete == 0))
3953 return SNMPERR_GENERR;
3954 }
3955
3956 /*
3957 * we handle this one ourselves since we don't have
3958 * pre-allocated memory to copy from using
3959 * snmp_set_var_value()
3960 */
3961
3962 if (uitmp == 0)
3963 break; /* zero length strings shouldn't malloc */
3964
3965 if (uitmp > MAX_OID_LEN)
3966 return SNMPERR_GENERR; /* too big and illegal */
3967
3968 /*
3969 * malloc by size+1 to allow a null to be appended.
3970 */
3971 var->val_len = uitmp;
3972 var->val.string = (u_char *) calloc(1, uitmp + 1);
3973 if (var->val.string == NULL)
3974 return SNMPERR_GENERR;
3975
3976 if ((size_t)uitmp > (*oidLen)) {
3977 for (i = 0; i < *oidLen; ++i)
3978 var->val.string[i] = (u_char) * oidIndex++;
3979 for (i = *oidLen; i < uitmp; ++i)
3980 var->val.string[i] = '\0';
3981 (*oidLen) = 0;
3982 } else {
3983 for (i = 0; i < uitmp; ++i)
3984 var->val.string[i] = (u_char) * oidIndex++;
3985 (*oidLen) -= uitmp;
3986 }
3987 var->val.string[uitmp] = '\0';
3988
3989 DEBUGMSGTL(("parse_oid_indexes",
3990 "Parsed str(%d): %s\n", var->type,
3991 var->val.string));
3992 break;
3993
3994 default:
3995 DEBUGMSGTL(("parse_oid_indexes",
3996 "invalid asn type: %d\n", var->type));
3997 return SNMPERR_GENERR;
3998 }
3999 }
4000 (*oidStart) = oidIndex;
4001 return SNMPERR_SUCCESS;
4002 }
4003
4004 /*
4005 * dump_realloc_oid_to_inetaddress:
4006 * return 0 for failure,
4007 * return 1 for success,
4008 * return 2 for not handled
4009 */
4010
4011 int
dump_realloc_oid_to_inetaddress(const int addr_type,const oid * objid,size_t objidlen,u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,char quotechar)4012 dump_realloc_oid_to_inetaddress(const int addr_type, const oid * objid, size_t objidlen,
4013 u_char ** buf, size_t * buf_len,
4014 size_t * out_len, int allow_realloc,
4015 char quotechar)
4016 {
4017 int i, len;
4018 char intbuf[64], *p;
4019 char *const end = intbuf + sizeof(intbuf);
4020 unsigned char *zc;
4021 unsigned long zone;
4022
4023 if (!buf)
4024 return 1;
4025
4026 for (i = 0; i < objidlen; i++)
4027 if (objid[i] < 0 || objid[i] > 255)
4028 return 2;
4029
4030 p = intbuf;
4031 *p++ = quotechar;
4032
4033 switch (addr_type) {
4034 case IPV4:
4035 case IPV4Z:
4036 if ((addr_type == IPV4 && objidlen != 4) ||
4037 (addr_type == IPV4Z && objidlen != 8))
4038 return 2;
4039
4040 len = snprintf(p, end - p, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u."
4041 "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u",
4042 objid[0], objid[1], objid[2], objid[3]);
4043 p += len;
4044 if (p >= end)
4045 return 2;
4046 if (addr_type == IPV4Z) {
4047 zc = (unsigned char*)&zone;
4048 zc[0] = objid[4];
4049 zc[1] = objid[5];
4050 zc[2] = objid[6];
4051 zc[3] = objid[7];
4052 zone = ntohl(zone);
4053 len = snprintf(p, end - p, "%%%lu", zone);
4054 p += len;
4055 if (p >= end)
4056 return 2;
4057 }
4058
4059 break;
4060
4061 case IPV6:
4062 case IPV6Z:
4063 if ((addr_type == IPV6 && objidlen != 16) ||
4064 (addr_type == IPV6Z && objidlen != 20))
4065 return 2;
4066
4067 len = 0;
4068 for (i = 0; i < 16; i ++) {
4069 len = snprintf(p, end - p, "%s%02" NETSNMP_PRIo "x", i ? ":" : "",
4070 objid[i]);
4071 p += len;
4072 if (p >= end)
4073 return 2;
4074 }
4075
4076 if (addr_type == IPV6Z) {
4077 zc = (unsigned char*)&zone;
4078 zc[0] = objid[16];
4079 zc[1] = objid[17];
4080 zc[2] = objid[18];
4081 zc[3] = objid[19];
4082 zone = ntohl(zone);
4083 len = snprintf(p, end - p, "%%%lu", zone);
4084 p += len;
4085 if (p >= end)
4086 return 2;
4087 }
4088
4089 break;
4090
4091 case DNS:
4092 default:
4093 /* DNS can just be handled by dump_realloc_oid_to_string() */
4094 return 2;
4095 }
4096
4097 *p++ = quotechar;
4098 if (p >= end)
4099 return 2;
4100
4101 *p++ = '\0';
4102 if (p >= end)
4103 return 2;
4104
4105 return snmp_cstrcat(buf, buf_len, out_len, allow_realloc, intbuf);
4106 }
4107
4108 int
dump_realloc_oid_to_string(const oid * objid,size_t objidlen,u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,char quotechar)4109 dump_realloc_oid_to_string(const oid * objid, size_t objidlen,
4110 u_char ** buf, size_t * buf_len,
4111 size_t * out_len, int allow_realloc,
4112 char quotechar)
4113 {
4114 if (buf) {
4115 int i, alen;
4116
4117 for (i = 0, alen = 0; i < (int) objidlen; i++) {
4118 oid tst = objid[i];
4119 if ((tst > 254) || (!isprint(tst))) {
4120 tst = (oid) '.';
4121 }
4122
4123 if (alen == 0) {
4124 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) {
4125 while ((*out_len + 2) >= *buf_len) {
4126 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
4127 return 0;
4128 }
4129 }
4130 *(*buf + *out_len) = '\\';
4131 (*out_len)++;
4132 }
4133 while ((*out_len + 2) >= *buf_len) {
4134 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
4135 return 0;
4136 }
4137 }
4138 *(*buf + *out_len) = quotechar;
4139 (*out_len)++;
4140 }
4141
4142 while ((*out_len + 2) >= *buf_len) {
4143 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
4144 return 0;
4145 }
4146 }
4147 *(*buf + *out_len) = (char) tst;
4148 (*out_len)++;
4149 alen++;
4150 }
4151
4152 if (alen) {
4153 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) {
4154 while ((*out_len + 2) >= *buf_len) {
4155 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
4156 return 0;
4157 }
4158 }
4159 *(*buf + *out_len) = '\\';
4160 (*out_len)++;
4161 }
4162 while ((*out_len + 2) >= *buf_len) {
4163 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
4164 return 0;
4165 }
4166 }
4167 *(*buf + *out_len) = quotechar;
4168 (*out_len)++;
4169 }
4170
4171 *(*buf + *out_len) = '\0';
4172 }
4173
4174 return 1;
4175 }
4176
4177 void
_oid_finish_printing(const oid * objid,size_t objidlen,u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow)4178 _oid_finish_printing(const oid * objid, size_t objidlen,
4179 u_char ** buf, size_t * buf_len, size_t * out_len,
4180 int allow_realloc, int *buf_overflow) {
4181 char intbuf[64];
4182 if (*buf != NULL && *(*buf + *out_len - 1) != '.') {
4183 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4184 allow_realloc,
4185 (const u_char *) ".")) {
4186 *buf_overflow = 1;
4187 }
4188 }
4189
4190 while (objidlen-- > 0) { /* output rest of name, uninterpreted */
4191 sprintf(intbuf, "%" NETSNMP_PRIo "u.", *objid++);
4192 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4193 allow_realloc,
4194 (const u_char *) intbuf)) {
4195 *buf_overflow = 1;
4196 }
4197 }
4198
4199 if (*buf != NULL) {
4200 *(*buf + *out_len - 1) = '\0'; /* remove trailing dot */
4201 *out_len = *out_len - 1;
4202 }
4203 }
4204
4205 #ifndef NETSNMP_DISABLE_MIB_LOADING
4206 static void
_get_realloc_symbol_octet_string(size_t numids,const oid * objid,u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow,struct tree * tp)4207 _get_realloc_symbol_octet_string(size_t numids, const oid * objid,
4208 u_char ** buf, size_t * buf_len,
4209 size_t * out_len, int allow_realloc,
4210 int *buf_overflow, struct tree* tp)
4211 {
4212 netsnmp_variable_list var = { 0 };
4213 u_char buffer[1024];
4214 size_t i;
4215
4216 for (i = 0; i < numids; i++)
4217 buffer[i] = (u_char) objid[i];
4218 var.type = ASN_OCTET_STR;
4219 var.val.string = buffer;
4220 var.val_len = numids;
4221 if (!*buf_overflow) {
4222 if (!sprint_realloc_octet_string(buf, buf_len, out_len,
4223 allow_realloc, &var,
4224 NULL, tp->hint,
4225 NULL)) {
4226 *buf_overflow = 1;
4227 }
4228 }
4229 }
4230
4231 static struct tree *
_get_realloc_symbol(const oid * objid,size_t objidlen,struct tree * subtree,u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,int * buf_overflow,struct index_list * in_dices,size_t * end_of_known)4232 _get_realloc_symbol(const oid * objid, size_t objidlen,
4233 struct tree *subtree,
4234 u_char ** buf, size_t * buf_len, size_t * out_len,
4235 int allow_realloc, int *buf_overflow,
4236 struct index_list *in_dices, size_t * end_of_known)
4237 {
4238 struct tree *return_tree = NULL;
4239 int extended_index =
4240 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX);
4241 int output_format =
4242 netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT);
4243 char intbuf[64];
4244 struct tree *orgtree = subtree;
4245
4246 if (!objid || !buf) {
4247 return NULL;
4248 }
4249
4250 for (; subtree; subtree = subtree->next_peer) {
4251 if (*objid == subtree->subid) {
4252 while (subtree->next_peer && subtree->next_peer->subid == *objid)
4253 subtree = subtree->next_peer;
4254 if (subtree->indexes) {
4255 in_dices = subtree->indexes;
4256 } else if (subtree->augments) {
4257 struct tree *tp2 =
4258 find_tree_node(subtree->augments, -1);
4259 if (tp2) {
4260 in_dices = tp2->indexes;
4261 }
4262 }
4263
4264 if (!strncmp(subtree->label, ANON, ANON_LEN) ||
4265 (NETSNMP_OID_OUTPUT_NUMERIC == output_format)) {
4266 sprintf(intbuf, "%lu", subtree->subid);
4267 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4268 allow_realloc,
4269 (const u_char *)
4270 intbuf)) {
4271 *buf_overflow = 1;
4272 }
4273 } else {
4274 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4275 allow_realloc,
4276 (const u_char *)
4277 subtree->label)) {
4278 *buf_overflow = 1;
4279 }
4280 }
4281
4282 if (objidlen > 1) {
4283 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4284 allow_realloc,
4285 (const u_char *) ".")) {
4286 *buf_overflow = 1;
4287 }
4288
4289 return_tree = _get_realloc_symbol(objid + 1, objidlen - 1,
4290 subtree->child_list,
4291 buf, buf_len, out_len,
4292 allow_realloc,
4293 buf_overflow, in_dices,
4294 end_of_known);
4295 }
4296
4297 if (return_tree != NULL) {
4298 return return_tree;
4299 } else {
4300 return subtree;
4301 }
4302 }
4303 }
4304
4305 if (end_of_known) {
4306 *end_of_known = *out_len;
4307 }
4308
4309 /*
4310 * Subtree not found.
4311 */
4312
4313 if (orgtree && in_dices && objidlen > 0) {
4314 sprintf(intbuf, "%" NETSNMP_PRIo "u.", *objid);
4315 if (!*buf_overflow
4316 && !snmp_strcat(buf, buf_len, out_len,
4317 allow_realloc,
4318 (const u_char *) intbuf)) {
4319 *buf_overflow = 1;
4320 }
4321 objid++;
4322 objidlen--;
4323 }
4324
4325 while (in_dices && (objidlen > 0) &&
4326 (NETSNMP_OID_OUTPUT_NUMERIC != output_format) &&
4327 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS)) {
4328 size_t numids;
4329 struct tree *tp;
4330
4331 tp = find_tree_node(in_dices->ilabel, -1);
4332
4333 if (!tp) {
4334 /*
4335 * Can't find an index in the mib tree. Bail.
4336 */
4337 goto finish_it;
4338 }
4339
4340 if (extended_index) {
4341 if (*buf != NULL && *(*buf + *out_len - 1) == '.') {
4342 (*out_len)--;
4343 }
4344 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4345 allow_realloc,
4346 (const u_char *) "[")) {
4347 *buf_overflow = 1;
4348 }
4349 }
4350
4351 switch (tp->type) {
4352 case TYPE_OCTETSTR:
4353 if (extended_index && tp->hint) {
4354 if (in_dices->isimplied) {
4355 numids = objidlen;
4356 if (numids > objidlen)
4357 goto finish_it;
4358 } else if (tp->ranges && !tp->ranges->next
4359 && tp->ranges->low == tp->ranges->high) {
4360 numids = tp->ranges->low;
4361 if (numids > objidlen)
4362 goto finish_it;
4363 } else {
4364 numids = *objid;
4365 if (numids >= objidlen)
4366 goto finish_it;
4367 objid++;
4368 objidlen--;
4369 }
4370 if (numids > objidlen)
4371 goto finish_it;
4372 _get_realloc_symbol_octet_string(numids, objid, buf, buf_len,
4373 out_len, allow_realloc,
4374 buf_overflow, tp);
4375 } else if (in_dices->isimplied) {
4376 numids = objidlen;
4377 if (numids > objidlen)
4378 goto finish_it;
4379
4380 if (!*buf_overflow) {
4381 if (!dump_realloc_oid_to_string
4382 (objid, numids, buf, buf_len, out_len,
4383 allow_realloc, '\'')) {
4384 *buf_overflow = 1;
4385 }
4386 }
4387 } else if (tp->ranges && !tp->ranges->next
4388 && tp->ranges->low == tp->ranges->high) {
4389 /*
4390 * a fixed-length octet string
4391 */
4392 numids = tp->ranges->low;
4393 if (numids > objidlen)
4394 goto finish_it;
4395
4396 if (!*buf_overflow) {
4397 if (!dump_realloc_oid_to_string
4398 (objid, numids, buf, buf_len, out_len,
4399 allow_realloc, '\'')) {
4400 *buf_overflow = 1;
4401 }
4402 }
4403 } else {
4404 numids = (size_t) * objid + 1;
4405 if (numids > objidlen)
4406 goto finish_it;
4407 if (numids == 1) {
4408 if (netsnmp_ds_get_boolean
4409 (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) {
4410 if (!*buf_overflow
4411 && !snmp_strcat(buf, buf_len, out_len,
4412 allow_realloc,
4413 (const u_char *) "\\")) {
4414 *buf_overflow = 1;
4415 }
4416 }
4417 if (!*buf_overflow
4418 && !snmp_strcat(buf, buf_len, out_len,
4419 allow_realloc,
4420 (const u_char *) "\"")) {
4421 *buf_overflow = 1;
4422 }
4423 if (netsnmp_ds_get_boolean
4424 (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) {
4425 if (!*buf_overflow
4426 && !snmp_strcat(buf, buf_len, out_len,
4427 allow_realloc,
4428 (const u_char *) "\\")) {
4429 *buf_overflow = 1;
4430 }
4431 }
4432 if (!*buf_overflow
4433 && !snmp_strcat(buf, buf_len, out_len,
4434 allow_realloc,
4435 (const u_char *) "\"")) {
4436 *buf_overflow = 1;
4437 }
4438 } else {
4439 if (!*buf_overflow) {
4440 struct tree * next_peer;
4441 int normal_handling = 1;
4442
4443 if (tp->next_peer) {
4444 next_peer = tp->next_peer;
4445 }
4446
4447 /* Try handling the InetAddress in the OID, in case of failure,
4448 * use the normal_handling.
4449 */
4450 if (tp->next_peer &&
4451 tp->tc_index != -1 &&
4452 next_peer->tc_index != -1 &&
4453 strcmp(get_tc_descriptor(tp->tc_index), "InetAddress") == 0 &&
4454 strcmp(get_tc_descriptor(next_peer->tc_index),
4455 "InetAddressType") == 0 ) {
4456
4457 int ret;
4458 int addr_type = *(objid - 1);
4459
4460 ret = dump_realloc_oid_to_inetaddress(addr_type,
4461 objid + 1, numids - 1, buf, buf_len, out_len,
4462 allow_realloc, '"');
4463 if (ret != 2) {
4464 normal_handling = 0;
4465 if (ret == 0) {
4466 *buf_overflow = 1;
4467 }
4468
4469 }
4470 }
4471 if (normal_handling && !dump_realloc_oid_to_string
4472 (objid + 1, numids - 1, buf, buf_len, out_len,
4473 allow_realloc, '"')) {
4474 *buf_overflow = 1;
4475 }
4476 }
4477 }
4478 }
4479 objid += numids;
4480 objidlen -= numids;
4481 break;
4482
4483 case TYPE_INTEGER32:
4484 case TYPE_UINTEGER:
4485 case TYPE_UNSIGNED32:
4486 case TYPE_GAUGE:
4487 case TYPE_INTEGER:
4488 if (tp->enums) {
4489 struct enum_list *ep = tp->enums;
4490 while (ep && ep->value != (int) (*objid)) {
4491 ep = ep->next;
4492 }
4493 if (ep) {
4494 if (!*buf_overflow
4495 && !snmp_strcat(buf, buf_len, out_len,
4496 allow_realloc,
4497 (const u_char *) ep->label)) {
4498 *buf_overflow = 1;
4499 }
4500 } else {
4501 sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid);
4502 if (!*buf_overflow
4503 && !snmp_strcat(buf, buf_len, out_len,
4504 allow_realloc,
4505 (const u_char *) intbuf)) {
4506 *buf_overflow = 1;
4507 }
4508 }
4509 } else {
4510 sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid);
4511 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4512 allow_realloc,
4513 (const u_char *)
4514 intbuf)) {
4515 *buf_overflow = 1;
4516 }
4517 }
4518 objid++;
4519 objidlen--;
4520 break;
4521
4522 case TYPE_TIMETICKS:
4523 /* In an index, this is probably a timefilter */
4524 if (extended_index) {
4525 uptimeString( *objid, intbuf, sizeof( intbuf ) );
4526 } else {
4527 sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid);
4528 }
4529 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4530 allow_realloc,
4531 (const u_char *)
4532 intbuf)) {
4533 *buf_overflow = 1;
4534 }
4535 objid++;
4536 objidlen--;
4537 break;
4538
4539 case TYPE_OBJID:
4540 if (in_dices->isimplied) {
4541 numids = objidlen;
4542 } else {
4543 numids = (size_t) * objid + 1;
4544 }
4545 if (numids > objidlen)
4546 goto finish_it;
4547 if (extended_index) {
4548 if (in_dices->isimplied) {
4549 if (!*buf_overflow
4550 && !netsnmp_sprint_realloc_objid_tree(buf, buf_len,
4551 out_len,
4552 allow_realloc,
4553 buf_overflow,
4554 objid,
4555 numids)) {
4556 *buf_overflow = 1;
4557 }
4558 } else {
4559 if (!*buf_overflow
4560 && !netsnmp_sprint_realloc_objid_tree(buf, buf_len,
4561 out_len,
4562 allow_realloc,
4563 buf_overflow,
4564 objid + 1,
4565 numids -
4566 1)) {
4567 *buf_overflow = 1;
4568 }
4569 }
4570 } else {
4571 _get_realloc_symbol(objid, numids, NULL, buf, buf_len,
4572 out_len, allow_realloc, buf_overflow,
4573 NULL, NULL);
4574 }
4575 objid += (numids);
4576 objidlen -= (numids);
4577 break;
4578
4579 case TYPE_IPADDR:
4580 if (objidlen < 4)
4581 goto finish_it;
4582 sprintf(intbuf, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u."
4583 "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u",
4584 objid[0], objid[1], objid[2], objid[3]);
4585 objid += 4;
4586 objidlen -= 4;
4587 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4588 allow_realloc,
4589 (const u_char *) intbuf)) {
4590 *buf_overflow = 1;
4591 }
4592 break;
4593
4594 case TYPE_NETADDR:{
4595 oid ntype = *objid++;
4596
4597 objidlen--;
4598 sprintf(intbuf, "%" NETSNMP_PRIo "u.", ntype);
4599 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4600 allow_realloc,
4601 (const u_char *)
4602 intbuf)) {
4603 *buf_overflow = 1;
4604 }
4605
4606 if (ntype == 1 && objidlen >= 4) {
4607 sprintf(intbuf, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u."
4608 "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u",
4609 objid[0], objid[1], objid[2], objid[3]);
4610 if (!*buf_overflow
4611 && !snmp_strcat(buf, buf_len, out_len,
4612 allow_realloc,
4613 (const u_char *) intbuf)) {
4614 *buf_overflow = 1;
4615 }
4616 objid += 4;
4617 objidlen -= 4;
4618 } else {
4619 goto finish_it;
4620 }
4621 }
4622 break;
4623
4624 case TYPE_NSAPADDRESS:
4625 default:
4626 goto finish_it;
4627 break;
4628 }
4629
4630 if (extended_index) {
4631 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4632 allow_realloc,
4633 (const u_char *) "]")) {
4634 *buf_overflow = 1;
4635 }
4636 } else {
4637 if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len,
4638 allow_realloc,
4639 (const u_char *) ".")) {
4640 *buf_overflow = 1;
4641 }
4642 }
4643 in_dices = in_dices->next;
4644 }
4645
4646 finish_it:
4647 _oid_finish_printing(objid, objidlen,
4648 buf, buf_len, out_len,
4649 allow_realloc, buf_overflow);
4650 return NULL;
4651 }
4652
4653 struct tree *
get_tree(const oid * objid,size_t objidlen,struct tree * subtree)4654 get_tree(const oid * objid, size_t objidlen, struct tree *subtree)
4655 {
4656 struct tree *return_tree = NULL;
4657
4658 for (; subtree; subtree = subtree->next_peer) {
4659 if (*objid == subtree->subid)
4660 goto found;
4661 }
4662
4663 return NULL;
4664
4665 found:
4666 while (subtree->next_peer && subtree->next_peer->subid == *objid)
4667 subtree = subtree->next_peer;
4668 if (objidlen > 1)
4669 return_tree =
4670 get_tree(objid + 1, objidlen - 1, subtree->child_list);
4671 if (return_tree != NULL)
4672 return return_tree;
4673 else
4674 return subtree;
4675 }
4676
4677 /**
4678 * Prints on oid description on stdout.
4679 *
4680 * @see fprint_description
4681 */
4682 void
print_description(oid * objid,size_t objidlen,int width)4683 print_description(oid * objid, size_t objidlen, /* number of subidentifiers */
4684 int width)
4685 {
4686 fprint_description(stdout, objid, objidlen, width);
4687 }
4688
4689
4690 /**
4691 * Prints on oid description into a file descriptor.
4692 *
4693 * @param f The file descriptor to print to.
4694 * @param objid The object identifier.
4695 * @param objidlen The object id length.
4696 * @param width Number of subidentifiers.
4697 */
4698 void
fprint_description(FILE * f,oid * objid,size_t objidlen,int width)4699 fprint_description(FILE * f, oid * objid, size_t objidlen,
4700 int width)
4701 {
4702 u_char *buf = NULL;
4703 size_t buf_len = 256, out_len = 0;
4704
4705 if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) {
4706 fprintf(f, "[TRUNCATED]\n");
4707 return;
4708 } else {
4709 if (!sprint_realloc_description(&buf, &buf_len, &out_len, 1,
4710 objid, objidlen, width)) {
4711 fprintf(f, "%s [TRUNCATED]\n", buf);
4712 } else {
4713 fprintf(f, "%s\n", buf);
4714 }
4715 }
4716
4717 SNMP_FREE(buf);
4718 }
4719
4720 #ifndef NETSNMP_FEATURE_REMOVE_MIB_SNPRINT_DESCRIPTION
4721 int
snprint_description(char * buf,size_t buf_len,oid * objid,size_t objidlen,int width)4722 snprint_description(char *buf, size_t buf_len,
4723 oid * objid, size_t objidlen, int width)
4724 {
4725 size_t out_len = 0;
4726
4727 if (sprint_realloc_description((u_char **) & buf, &buf_len, &out_len, 0,
4728 objid, objidlen, width)) {
4729 return (int) out_len;
4730 } else {
4731 return -1;
4732 }
4733 }
4734 #endif /* NETSNMP_FEATURE_REMOVE_MIB_SNPRINT_DESCRIPTION */
4735
4736 int
sprint_realloc_description(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,oid * objid,size_t objidlen,int width)4737 sprint_realloc_description(u_char ** buf, size_t * buf_len,
4738 size_t * out_len, int allow_realloc,
4739 oid * objid, size_t objidlen, int width)
4740 {
4741 struct tree *tp = get_tree(objid, objidlen, tree_head);
4742 struct tree *subtree = tree_head;
4743 int pos, len;
4744 char tmpbuf[128];
4745 const char *cp;
4746
4747 if (NULL == tp)
4748 return 0;
4749
4750 if (tp->type <= TYPE_SIMPLE_LAST)
4751 cp = " OBJECT-TYPE";
4752 else
4753 switch (tp->type) {
4754 case TYPE_TRAPTYPE:
4755 cp = " TRAP-TYPE";
4756 break;
4757 case TYPE_NOTIFTYPE:
4758 cp = " NOTIFICATION-TYPE";
4759 break;
4760 case TYPE_OBJGROUP:
4761 cp = " OBJECT-GROUP";
4762 break;
4763 case TYPE_AGENTCAP:
4764 cp = " AGENT-CAPABILITIES";
4765 break;
4766 case TYPE_MODID:
4767 cp = " MODULE-IDENTITY";
4768 break;
4769 case TYPE_OBJIDENTITY:
4770 cp = " OBJECT-IDENTITY";
4771 break;
4772 case TYPE_MODCOMP:
4773 cp = " MODULE-COMPLIANCE";
4774 break;
4775 default:
4776 sprintf(tmpbuf, " type_%d", tp->type);
4777 cp = tmpbuf;
4778 }
4779
4780 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->label) ||
4781 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) ||
4782 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) {
4783 return 0;
4784 }
4785 if (!print_tree_node(buf, buf_len, out_len, allow_realloc, tp, width))
4786 return 0;
4787 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "::= {"))
4788 return 0;
4789 pos = 5;
4790 while (objidlen > 1) {
4791 for (; subtree; subtree = subtree->next_peer) {
4792 if (*objid == subtree->subid) {
4793 while (subtree->next_peer && subtree->next_peer->subid == *objid)
4794 subtree = subtree->next_peer;
4795 if (strncmp(subtree->label, ANON, ANON_LEN)) {
4796 snprintf(tmpbuf, sizeof(tmpbuf), " %s(%lu)", subtree->label, subtree->subid);
4797 tmpbuf[ sizeof(tmpbuf)-1 ] = 0;
4798 } else
4799 sprintf(tmpbuf, " %lu", subtree->subid);
4800 len = strlen(tmpbuf);
4801 if (pos + len + 2 > width) {
4802 if (!snmp_cstrcat(buf, buf_len, out_len,
4803 allow_realloc, "\n "))
4804 return 0;
4805 pos = 5;
4806 }
4807 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf))
4808 return 0;
4809 pos += len;
4810 objid++;
4811 objidlen--;
4812 break;
4813 }
4814 }
4815 if (subtree)
4816 subtree = subtree->child_list;
4817 else
4818 break;
4819 }
4820 while (objidlen > 1) {
4821 sprintf(tmpbuf, " %" NETSNMP_PRIo "u", *objid);
4822 len = strlen(tmpbuf);
4823 if (pos + len + 2 > width) {
4824 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n "))
4825 return 0;
4826 pos = 5;
4827 }
4828 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf))
4829 return 0;
4830 pos += len;
4831 objid++;
4832 objidlen--;
4833 }
4834 sprintf(tmpbuf, " %" NETSNMP_PRIo "u }", *objid);
4835 len = strlen(tmpbuf);
4836 if (pos + len + 2 > width) {
4837 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n "))
4838 return 0;
4839 pos = 5;
4840 }
4841 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf))
4842 return 0;
4843 return 1;
4844 }
4845
4846 static int
print_tree_node(u_char ** buf,size_t * buf_len,size_t * out_len,int allow_realloc,struct tree * tp,int width)4847 print_tree_node(u_char ** buf, size_t * buf_len,
4848 size_t * out_len, int allow_realloc,
4849 struct tree *tp, int width)
4850 {
4851 const char *cp;
4852 char str[MAXTOKEN];
4853 int i, prevmod, pos, len;
4854
4855 if (tp) {
4856 module_name(tp->modid, str);
4857 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " -- FROM\t") ||
4858 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
4859 return 0;
4860 pos = 16+strlen(str);
4861 for (i = 1, prevmod = tp->modid; i < tp->number_modules; i++) {
4862 if (prevmod != tp->module_list[i]) {
4863 module_name(tp->module_list[i], str);
4864 len = strlen(str);
4865 if (pos + len + 2 > width) {
4866 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
4867 ",\n --\t\t"))
4868 return 0;
4869 pos = 16;
4870 }
4871 else {
4872 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", "))
4873 return 0;
4874 pos += 2;
4875 }
4876 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
4877 return 0;
4878 pos += len;
4879 }
4880 prevmod = tp->module_list[i];
4881 }
4882 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n"))
4883 return 0;
4884 if (tp->tc_index != -1) {
4885 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
4886 " -- TEXTUAL CONVENTION ") ||
4887 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
4888 get_tc_descriptor(tp->tc_index)) ||
4889 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n"))
4890 return 0;
4891 }
4892 switch (tp->type) {
4893 case TYPE_OBJID:
4894 cp = "OBJECT IDENTIFIER";
4895 break;
4896 case TYPE_OCTETSTR:
4897 cp = "OCTET STRING";
4898 break;
4899 case TYPE_INTEGER:
4900 cp = "INTEGER";
4901 break;
4902 case TYPE_NETADDR:
4903 cp = "NetworkAddress";
4904 break;
4905 case TYPE_IPADDR:
4906 cp = "IpAddress";
4907 break;
4908 case TYPE_COUNTER:
4909 cp = "Counter32";
4910 break;
4911 case TYPE_GAUGE:
4912 cp = "Gauge32";
4913 break;
4914 case TYPE_TIMETICKS:
4915 cp = "TimeTicks";
4916 break;
4917 case TYPE_OPAQUE:
4918 cp = "Opaque";
4919 break;
4920 case TYPE_NULL:
4921 cp = "NULL";
4922 break;
4923 case TYPE_COUNTER64:
4924 cp = "Counter64";
4925 break;
4926 case TYPE_BITSTRING:
4927 cp = "BITS";
4928 break;
4929 case TYPE_NSAPADDRESS:
4930 cp = "NsapAddress";
4931 break;
4932 case TYPE_UINTEGER:
4933 cp = "UInteger32";
4934 break;
4935 case TYPE_UNSIGNED32:
4936 cp = "Unsigned32";
4937 break;
4938 case TYPE_INTEGER32:
4939 cp = "Integer32";
4940 break;
4941 default:
4942 cp = NULL;
4943 break;
4944 }
4945 #if NETSNMP_ENABLE_TESTING_CODE
4946 if (!cp && (tp->ranges || tp->enums)) { /* ranges without type ? */
4947 sprintf(str, "?0 with %s %s ?",
4948 tp->ranges ? "Range" : "", tp->enums ? "Enum" : "");
4949 cp = str;
4950 }
4951 #endif /* NETSNMP_ENABLE_TESTING_CODE */
4952 if (cp)
4953 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
4954 " SYNTAX\t") ||
4955 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp))
4956 return 0;
4957 if (tp->ranges) {
4958 struct range_list *rp = tp->ranges;
4959 int first = 1;
4960 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ("))
4961 return 0;
4962 while (rp) {
4963 switch (tp->type) {
4964 case TYPE_INTEGER:
4965 case TYPE_INTEGER32:
4966 if (rp->low == rp->high)
4967 sprintf(str, "%s%d", (first ? "" : " | "), rp->low );
4968 else
4969 sprintf(str, "%s%d..%d", (first ? "" : " | "),
4970 rp->low, rp->high);
4971 break;
4972 case TYPE_UNSIGNED32:
4973 case TYPE_OCTETSTR:
4974 case TYPE_GAUGE:
4975 case TYPE_UINTEGER:
4976 if (rp->low == rp->high)
4977 sprintf(str, "%s%u", (first ? "" : " | "),
4978 (unsigned)rp->low );
4979 else
4980 sprintf(str, "%s%u..%u", (first ? "" : " | "),
4981 (unsigned)rp->low, (unsigned)rp->high);
4982 break;
4983 default:
4984 /* No other range types allowed */
4985 break;
4986 }
4987 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
4988 return 0;
4989 if (first)
4990 first = 0;
4991 rp = rp->next;
4992 }
4993 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ") "))
4994 return 0;
4995 }
4996 if (tp->enums) {
4997 struct enum_list *ep = tp->enums;
4998 int first = 1;
4999 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " {"))
5000 return 0;
5001 pos = 16 + strlen(cp) + 2;
5002 while (ep) {
5003 if (first)
5004 first = 0;
5005 else
5006 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", "))
5007 return 0;
5008 snprintf(str, sizeof(str), "%s(%d)", ep->label, ep->value);
5009 str[ sizeof(str)-1 ] = 0;
5010 len = strlen(str);
5011 if (pos + len + 2 > width) {
5012 if (!snmp_cstrcat(buf, buf_len, out_len,
5013 allow_realloc, "\n\t\t "))
5014 return 0;
5015 pos = 18;
5016 }
5017 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
5018 return 0;
5019 pos += len + 2;
5020 ep = ep->next;
5021 }
5022 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "} "))
5023 return 0;
5024 }
5025 if (cp)
5026 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n"))
5027 return 0;
5028 if (tp->hint)
5029 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5030 " DISPLAY-HINT\t\"") ||
5031 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->hint) ||
5032 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n"))
5033 return 0;
5034 if (tp->units)
5035 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5036 " UNITS\t\t\"") ||
5037 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->units) ||
5038 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n"))
5039 return 0;
5040 switch (tp->access) {
5041 case MIB_ACCESS_READONLY:
5042 cp = "read-only";
5043 break;
5044 case MIB_ACCESS_READWRITE:
5045 cp = "read-write";
5046 break;
5047 case MIB_ACCESS_WRITEONLY:
5048 cp = "write-only";
5049 break;
5050 case MIB_ACCESS_NOACCESS:
5051 cp = "not-accessible";
5052 break;
5053 case MIB_ACCESS_NOTIFY:
5054 cp = "accessible-for-notify";
5055 break;
5056 case MIB_ACCESS_CREATE:
5057 cp = "read-create";
5058 break;
5059 case 0:
5060 cp = NULL;
5061 break;
5062 default:
5063 sprintf(str, "access_%d", tp->access);
5064 cp = str;
5065 }
5066 if (cp)
5067 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5068 " MAX-ACCESS\t") ||
5069 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) ||
5070 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n"))
5071 return 0;
5072 switch (tp->status) {
5073 case MIB_STATUS_MANDATORY:
5074 cp = "mandatory";
5075 break;
5076 case MIB_STATUS_OPTIONAL:
5077 cp = "optional";
5078 break;
5079 case MIB_STATUS_OBSOLETE:
5080 cp = "obsolete";
5081 break;
5082 case MIB_STATUS_DEPRECATED:
5083 cp = "deprecated";
5084 break;
5085 case MIB_STATUS_CURRENT:
5086 cp = "current";
5087 break;
5088 case 0:
5089 cp = NULL;
5090 break;
5091 default:
5092 sprintf(str, "status_%d", tp->status);
5093 cp = str;
5094 }
5095 #if NETSNMP_ENABLE_TESTING_CODE
5096 if (!cp && (tp->indexes)) { /* index without status ? */
5097 sprintf(str, "?0 with %s ?", tp->indexes ? "Index" : "");
5098 cp = str;
5099 }
5100 #endif /* NETSNMP_ENABLE_TESTING_CODE */
5101 if (cp)
5102 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5103 " STATUS\t") ||
5104 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) ||
5105 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n"))
5106 return 0;
5107 if (tp->augments)
5108 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5109 " AUGMENTS\t{ ") ||
5110 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->augments) ||
5111 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n"))
5112 return 0;
5113 if (tp->indexes) {
5114 struct index_list *ip = tp->indexes;
5115 int first = 1;
5116 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5117 " INDEX\t\t{ "))
5118 return 0;
5119 pos = 16 + 2;
5120 while (ip) {
5121 if (first)
5122 first = 0;
5123 else
5124 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", "))
5125 return 0;
5126 snprintf(str, sizeof(str), "%s%s",
5127 ip->isimplied ? "IMPLIED " : "",
5128 ip->ilabel);
5129 str[ sizeof(str)-1 ] = 0;
5130 len = strlen(str);
5131 if (pos + len + 2 > width) {
5132 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n\t\t "))
5133 return 0;
5134 pos = 16 + 2;
5135 }
5136 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
5137 return 0;
5138 pos += len + 2;
5139 ip = ip->next;
5140 }
5141 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n"))
5142 return 0;
5143 }
5144 if (tp->varbinds) {
5145 struct varbind_list *vp = tp->varbinds;
5146 int first = 1;
5147
5148 if (tp->type == TYPE_TRAPTYPE) {
5149 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5150 " VARIABLES\t{ "))
5151 return 0;
5152 } else {
5153 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5154 " OBJECTS\t{ "))
5155 return 0;
5156 }
5157 pos = 16 + 2;
5158 while (vp) {
5159 if (first)
5160 first = 0;
5161 else
5162 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", "))
5163 return 0;
5164 strlcpy(str, vp->vblabel, sizeof(str));
5165 len = strlen(str);
5166 if (pos + len + 2 > width) {
5167 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5168 "\n\t\t "))
5169 return 0;
5170 pos = 16 + 2;
5171 }
5172 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str))
5173 return 0;
5174 pos += len + 2;
5175 vp = vp->next;
5176 }
5177 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n"))
5178 return 0;
5179 }
5180 if (tp->description)
5181 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5182 " DESCRIPTION\t\"") ||
5183 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->description) ||
5184 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n"))
5185 return 0;
5186 if (tp->defaultValue)
5187 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc,
5188 " DEFVAL\t{ ") ||
5189 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->defaultValue) ||
5190 !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n"))
5191 return 0;
5192 } else
5193 if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "No description\n"))
5194 return 0;
5195 return 1;
5196 }
5197
5198 int
get_module_node(const char * fname,const char * module,oid * objid,size_t * objidlen)5199 get_module_node(const char *fname,
5200 const char *module, oid * objid, size_t * objidlen)
5201 {
5202 int modid, rc = 0;
5203 struct tree *tp;
5204 char *name, *cp;
5205
5206 if (!strcmp(module, "ANY"))
5207 modid = -1;
5208 else {
5209 netsnmp_read_module(module);
5210 modid = which_module(module);
5211 if (modid == -1)
5212 return 0;
5213 }
5214
5215 /*
5216 * Isolate the first component of the name ...
5217 */
5218 name = strdup(fname);
5219 cp = strchr(name, '.');
5220 if (cp != NULL) {
5221 *cp = '\0';
5222 cp++;
5223 }
5224 /*
5225 * ... and locate it in the tree.
5226 */
5227 tp = find_tree_node(name, modid);
5228 if (tp) {
5229 size_t maxlen = *objidlen;
5230
5231 /*
5232 * Set the first element of the object ID
5233 */
5234 if (node_to_oid(tp, objid, objidlen)) {
5235 rc = 1;
5236
5237 /*
5238 * If the name requested was more than one element,
5239 * tag on the rest of the components
5240 */
5241 if (cp != NULL)
5242 rc = _add_strings_to_oid(tp, cp, objid, objidlen, maxlen);
5243 }
5244 }
5245
5246 SNMP_FREE(name);
5247 return (rc);
5248 }
5249
5250
5251 /**
5252 * @internal
5253 *
5254 * Populates the object identifier from a node in the MIB hierarchy.
5255 * Builds up the object ID, working backwards,
5256 * starting from the end of the objid buffer.
5257 * When the top of the MIB tree is reached, the buffer is adjusted.
5258 *
5259 * The buffer length is set to the number of subidentifiers
5260 * for the object identifier associated with the MIB node.
5261 *
5262 * @return the number of subidentifiers copied.
5263 *
5264 * If 0 is returned, the objid buffer is too small,
5265 * and the buffer contents are indeterminate.
5266 * The buffer length can be used to create a larger buffer.
5267 */
5268 static int
node_to_oid(struct tree * tp,oid * objid,size_t * objidlen)5269 node_to_oid(struct tree *tp, oid * objid, size_t * objidlen)
5270 {
5271 int numids, lenids;
5272 oid *op;
5273
5274 if (!tp || !objid || !objidlen)
5275 return 0;
5276
5277 lenids = (int) *objidlen;
5278 op = objid + lenids; /* points after the last element */
5279
5280 for (numids = 0; tp; tp = tp->parent, numids++) {
5281 if (numids >= lenids)
5282 continue;
5283 --op;
5284 *op = tp->subid;
5285 }
5286
5287 *objidlen = (size_t) numids;
5288 if (numids > lenids) {
5289 return 0;
5290 }
5291
5292 if (numids < lenids)
5293 memmove(objid, op, numids * sizeof(oid));
5294
5295 return (numids);
5296 }
5297
5298 /*
5299 * Replace \x with x stop at eos_marker
5300 * return NULL if eos_marker not found
5301 */
_apply_escapes(char * src,char eos_marker)5302 static char *_apply_escapes(char *src, char eos_marker)
5303 {
5304 char *dst;
5305 int backslash = 0;
5306
5307 dst = src;
5308 while (*src) {
5309 if (backslash) {
5310 backslash = 0;
5311 *dst++ = *src;
5312 } else {
5313 if (eos_marker == *src) break;
5314 if ('\\' == *src) {
5315 backslash = 1;
5316 } else {
5317 *dst++ = *src;
5318 }
5319 }
5320 src++;
5321 }
5322 if (!*src) {
5323 /* never found eos_marker */
5324 return NULL;
5325 } else {
5326 *dst = 0;
5327 return src;
5328 }
5329 }
5330 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5331
5332 static int
5333 #ifndef NETSNMP_DISABLE_MIB_LOADING
_add_strings_to_oid(struct tree * tp,char * cp,oid * objid,size_t * objidlen,size_t maxlen)5334 _add_strings_to_oid(struct tree *tp, char *cp,
5335 oid * objid, size_t * objidlen, size_t maxlen)
5336 #else
5337 _add_strings_to_oid(void *tp, char *cp,
5338 oid * objid, size_t * objidlen, size_t maxlen)
5339 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5340 {
5341 oid subid;
5342 char *fcp, *ecp, *cp2 = NULL;
5343 char doingquote;
5344 int len = -1;
5345 #ifndef NETSNMP_DISABLE_MIB_LOADING
5346 struct tree *tp2 = NULL;
5347 struct index_list *in_dices = NULL;
5348 int pos = -1;
5349 int check =
5350 !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
5351 int do_hint = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
5352 int len_index = 1000000;
5353
5354 while (cp && tp && tp->child_list) {
5355 fcp = cp;
5356 tp2 = tp->child_list;
5357 /*
5358 * Isolate the next entry
5359 */
5360 cp2 = strchr(cp, '.');
5361 if (cp2)
5362 *cp2++ = '\0';
5363
5364 /*
5365 * Search for the appropriate child
5366 */
5367 if (isdigit((unsigned char)(*cp))) {
5368 subid = strtoul(cp, &ecp, 0);
5369 if (*ecp)
5370 goto bad_id;
5371 while (tp2 && tp2->subid != subid)
5372 tp2 = tp2->next_peer;
5373 } else {
5374 while (tp2 && strcmp(tp2->label, fcp))
5375 tp2 = tp2->next_peer;
5376 if (!tp2)
5377 goto bad_id;
5378 subid = tp2->subid;
5379 }
5380 if (*objidlen >= maxlen)
5381 goto bad_id;
5382 while (tp2 && tp2->next_peer && tp2->next_peer->subid == subid)
5383 tp2 = tp2->next_peer;
5384 objid[*objidlen] = subid;
5385 (*objidlen)++;
5386
5387 cp = cp2;
5388 if (!tp2)
5389 break;
5390 tp = tp2;
5391 }
5392
5393 if (tp && !tp->child_list) {
5394 if ((tp2 = tp->parent)) {
5395 if (tp2->indexes)
5396 in_dices = tp2->indexes;
5397 else if (tp2->augments) {
5398 tp2 = find_tree_node(tp2->augments, -1);
5399 if (tp2)
5400 in_dices = tp2->indexes;
5401 }
5402 }
5403 tp = NULL;
5404 }
5405
5406 while (cp && in_dices) {
5407 fcp = cp;
5408
5409 tp = find_tree_node(in_dices->ilabel, -1);
5410 if (!tp)
5411 break;
5412 switch (tp->type) {
5413 case TYPE_INTEGER:
5414 case TYPE_INTEGER32:
5415 case TYPE_UINTEGER:
5416 case TYPE_UNSIGNED32:
5417 case TYPE_TIMETICKS:
5418 /*
5419 * Isolate the next entry
5420 */
5421 cp2 = strchr(cp, '.');
5422 if (cp2)
5423 *cp2++ = '\0';
5424 if (isdigit((unsigned char)(*cp))) {
5425 subid = strtoul(cp, &ecp, 0);
5426 if (*ecp)
5427 goto bad_id;
5428 } else {
5429 if (tp->enums) {
5430 struct enum_list *ep = tp->enums;
5431 while (ep && strcmp(ep->label, cp))
5432 ep = ep->next;
5433 if (!ep)
5434 goto bad_id;
5435 subid = ep->value;
5436 } else
5437 goto bad_id;
5438 }
5439 if (check && tp->ranges) {
5440 struct range_list *rp = tp->ranges;
5441 int ok = 0;
5442 if (tp->type == TYPE_INTEGER ||
5443 tp->type == TYPE_INTEGER32) {
5444 while (!ok && rp) {
5445 if ((rp->low <= (int) subid)
5446 && ((int) subid <= rp->high))
5447 ok = 1;
5448 else
5449 rp = rp->next;
5450 }
5451 } else { /* check unsigned range */
5452 while (!ok && rp) {
5453 if (((unsigned int)rp->low <= subid)
5454 && (subid <= (unsigned int)rp->high))
5455 ok = 1;
5456 else
5457 rp = rp->next;
5458 }
5459 }
5460 if (!ok)
5461 goto bad_id;
5462 }
5463 if (*objidlen >= maxlen)
5464 goto bad_id;
5465 objid[*objidlen] = subid;
5466 (*objidlen)++;
5467 break;
5468 case TYPE_IPADDR:
5469 if (*objidlen + 4 > maxlen)
5470 goto bad_id;
5471 for (subid = 0; cp && subid < 4; subid++) {
5472 fcp = cp;
5473 cp2 = strchr(cp, '.');
5474 if (cp2)
5475 *cp2++ = 0;
5476 objid[*objidlen] = strtoul(cp, &ecp, 0);
5477 if (*ecp)
5478 goto bad_id;
5479 if (check && objid[*objidlen] > 255)
5480 goto bad_id;
5481 (*objidlen)++;
5482 cp = cp2;
5483 }
5484 break;
5485 case TYPE_OCTETSTR:
5486 if (tp->ranges && !tp->ranges->next
5487 && tp->ranges->low == tp->ranges->high)
5488 len = tp->ranges->low;
5489 else
5490 len = -1;
5491 pos = 0;
5492 if (*cp == '"' || *cp == '\'') {
5493 doingquote = *cp++;
5494 /*
5495 * insert length if requested
5496 */
5497 if (!in_dices->isimplied && len == -1) {
5498 if (doingquote == '\'') {
5499 snmp_set_detail
5500 ("'-quote is for fixed length strings");
5501 return 0;
5502 }
5503 if (*objidlen >= maxlen)
5504 goto bad_id;
5505 len_index = *objidlen;
5506 (*objidlen)++;
5507 } else if (doingquote == '"') {
5508 snmp_set_detail
5509 ("\"-quote is for variable length strings");
5510 return 0;
5511 }
5512
5513 cp2 = _apply_escapes(cp, doingquote);
5514 if (!cp2) goto bad_id;
5515 else {
5516 unsigned char *new_val;
5517 int new_val_len;
5518 int parsed_hint = 0;
5519 const char *parsed_value;
5520
5521 if (do_hint && tp->hint) {
5522 parsed_value = parse_octet_hint(tp->hint, cp,
5523 &new_val, &new_val_len);
5524 parsed_hint = parsed_value == NULL;
5525 }
5526 if (parsed_hint) {
5527 int i;
5528 for (i = 0; i < new_val_len; i++) {
5529 if (*objidlen >= maxlen) goto bad_id;
5530 objid[ *objidlen ] = new_val[i];
5531 (*objidlen)++;
5532 pos++;
5533 }
5534 SNMP_FREE(new_val);
5535 } else {
5536 while(*cp) {
5537 if (*objidlen >= maxlen) goto bad_id;
5538 objid[ *objidlen ] = *cp++;
5539 (*objidlen)++;
5540 pos++;
5541 }
5542 }
5543 }
5544
5545 cp2++;
5546 if (!*cp2)
5547 cp2 = NULL;
5548 else if (*cp2 != '.')
5549 goto bad_id;
5550 else
5551 cp2++;
5552 if (check) {
5553 if (len == -1) {
5554 struct range_list *rp = tp->ranges;
5555 int ok = 0;
5556 while (rp && !ok)
5557 if (rp->low <= pos && pos <= rp->high)
5558 ok = 1;
5559 else
5560 rp = rp->next;
5561 if (!ok)
5562 goto bad_id;
5563 if (!in_dices->isimplied)
5564 objid[len_index] = pos;
5565 } else if (pos != len)
5566 goto bad_id;
5567 }
5568 else if (len == -1 && !in_dices->isimplied)
5569 objid[len_index] = pos;
5570 } else {
5571 if (!in_dices->isimplied && len == -1) {
5572 fcp = cp;
5573 cp2 = strchr(cp, '.');
5574 if (cp2)
5575 *cp2++ = 0;
5576 len = strtoul(cp, &ecp, 0);
5577 if (*ecp)
5578 goto bad_id;
5579 if (*objidlen + len + 1 >= maxlen)
5580 goto bad_id;
5581 objid[*objidlen] = len;
5582 (*objidlen)++;
5583 cp = cp2;
5584 }
5585 while (len && cp) {
5586 fcp = cp;
5587 cp2 = strchr(cp, '.');
5588 if (cp2)
5589 *cp2++ = 0;
5590 objid[*objidlen] = strtoul(cp, &ecp, 0);
5591 if (*ecp)
5592 goto bad_id;
5593 if (check && objid[*objidlen] > 255)
5594 goto bad_id;
5595 (*objidlen)++;
5596 len--;
5597 cp = cp2;
5598 }
5599 }
5600 break;
5601 case TYPE_OBJID:
5602 in_dices = NULL;
5603 cp2 = cp;
5604 break;
5605 case TYPE_NETADDR:
5606 fcp = cp;
5607 cp2 = strchr(cp, '.');
5608 if (cp2)
5609 *cp2++ = 0;
5610 subid = strtoul(cp, &ecp, 0);
5611 if (*ecp)
5612 goto bad_id;
5613 if (*objidlen + 1 >= maxlen)
5614 goto bad_id;
5615 objid[*objidlen] = subid;
5616 (*objidlen)++;
5617 cp = cp2;
5618 if (subid == 1) {
5619 for (len = 0; cp && len < 4; len++) {
5620 fcp = cp;
5621 cp2 = strchr(cp, '.');
5622 if (cp2)
5623 *cp2++ = 0;
5624 subid = strtoul(cp, &ecp, 0);
5625 if (*ecp)
5626 goto bad_id;
5627 if (*objidlen + 1 >= maxlen)
5628 goto bad_id;
5629 if (check && subid > 255)
5630 goto bad_id;
5631 objid[*objidlen] = subid;
5632 (*objidlen)++;
5633 cp = cp2;
5634 }
5635 }
5636 else {
5637 in_dices = NULL;
5638 }
5639 break;
5640 default:
5641 snmp_log(LOG_ERR, "Unexpected index type: %d %s %s\n",
5642 tp->type, in_dices->ilabel, cp);
5643 in_dices = NULL;
5644 cp2 = cp;
5645 break;
5646 }
5647 cp = cp2;
5648 if (in_dices)
5649 in_dices = in_dices->next;
5650 }
5651
5652 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5653 while (cp) {
5654 fcp = cp;
5655 switch (*cp) {
5656 case '0':
5657 case '1':
5658 case '2':
5659 case '3':
5660 case '4':
5661 case '5':
5662 case '6':
5663 case '7':
5664 case '8':
5665 case '9':
5666 cp2 = strchr(cp, '.');
5667 if (cp2)
5668 *cp2++ = 0;
5669 subid = strtoul(cp, &ecp, 0);
5670 if (*ecp)
5671 goto bad_id;
5672 if (*objidlen >= maxlen)
5673 goto bad_id;
5674 objid[*objidlen] = subid;
5675 (*objidlen)++;
5676 break;
5677 case '"':
5678 case '\'':
5679 doingquote = *cp++;
5680 /*
5681 * insert length if requested
5682 */
5683 if (doingquote == '"') {
5684 if (*objidlen >= maxlen)
5685 goto bad_id;
5686 objid[*objidlen] = len = strchr(cp, doingquote) - cp;
5687 (*objidlen)++;
5688 }
5689
5690 while (*cp && *cp != doingquote) {
5691 if (*objidlen >= maxlen)
5692 goto bad_id;
5693 objid[*objidlen] = *cp++;
5694 (*objidlen)++;
5695 }
5696 cp2 = cp + 1;
5697 if (!*cp2)
5698 cp2 = NULL;
5699 else if (*cp2 == '.')
5700 cp2++;
5701 else
5702 goto bad_id;
5703 break;
5704 default:
5705 goto bad_id;
5706 }
5707 cp = cp2;
5708 }
5709 return 1;
5710
5711 bad_id:
5712 {
5713 char buf[256];
5714 #ifndef NETSNMP_DISABLE_MIB_LOADING
5715 if (in_dices)
5716 snprintf(buf, sizeof(buf), "Index out of range: %s (%s)",
5717 fcp, in_dices->ilabel);
5718 else if (tp)
5719 snprintf(buf, sizeof(buf), "Sub-id not found: %s -> %s", tp->label, fcp);
5720 else
5721 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5722 snprintf(buf, sizeof(buf), "%s", fcp);
5723 buf[ sizeof(buf)-1 ] = 0;
5724
5725 snmp_set_detail(buf);
5726 }
5727 return 0;
5728 }
5729
5730
5731 #ifndef NETSNMP_DISABLE_MIB_LOADING
5732 /**
5733 * @see comments on find_best_tree_node for usage after first time.
5734 */
5735 int
get_wild_node(const char * name,oid * objid,size_t * objidlen)5736 get_wild_node(const char *name, oid * objid, size_t * objidlen)
5737 {
5738 struct tree *tp = find_best_tree_node(name, tree_head, NULL);
5739 if (!tp)
5740 return 0;
5741 return get_node(tp->label, objid, objidlen);
5742 }
5743
5744 int
get_node(const char * name,oid * objid,size_t * objidlen)5745 get_node(const char *name, oid * objid, size_t * objidlen)
5746 {
5747 const char *cp;
5748 char ch;
5749 int res;
5750
5751 cp = name;
5752 while ((ch = *cp))
5753 if (('0' <= ch && ch <= '9')
5754 || ('a' <= ch && ch <= 'z')
5755 || ('A' <= ch && ch <= 'Z')
5756 || ch == '-')
5757 cp++;
5758 else
5759 break;
5760 if (ch != ':')
5761 if (*name == '.')
5762 res = get_module_node(name + 1, "ANY", objid, objidlen);
5763 else
5764 res = get_module_node(name, "ANY", objid, objidlen);
5765 else {
5766 char *module;
5767 /*
5768 * requested name is of the form
5769 * "module:subidentifier"
5770 */
5771 module = (char *) malloc((size_t) (cp - name + 1));
5772 if (!module)
5773 return SNMPERR_GENERR;
5774 sprintf(module, "%.*s", (int) (cp - name), name);
5775 cp++; /* cp now point to the subidentifier */
5776 if (*cp == ':')
5777 cp++;
5778
5779 /*
5780 * 'cp' and 'name' *do* go that way round!
5781 */
5782 res = get_module_node(cp, module, objid, objidlen);
5783 SNMP_FREE(module);
5784 }
5785 if (res == 0) {
5786 SET_SNMP_ERROR(SNMPERR_UNKNOWN_OBJID);
5787 }
5788
5789 return res;
5790 }
5791 #endif /* NETSNMP_DISABLE_MIB_LOADING */
5792
5793 #ifdef testing
5794
main(int argc,char * argv[])5795 main(int argc, char *argv[])
5796 {
5797 oid objid[MAX_OID_LEN];
5798 int objidlen = MAX_OID_LEN;
5799 int count;
5800 netsnmp_variable_list variable;
5801
5802 netsnmp_init_mib();
5803 if (argc < 2)
5804 print_subtree(stdout, tree_head, 0);
5805 variable.type = ASN_INTEGER;
5806 variable.val.integer = 3;
5807 variable.val_len = 4;
5808 for (argc--; argc; argc--, argv++) {
5809 objidlen = MAX_OID_LEN;
5810 printf("read_objid(%s) = %d\n",
5811 argv[1], read_objid(argv[1], objid, &objidlen));
5812 for (count = 0; count < objidlen; count++)
5813 printf("%d.", objid[count]);
5814 printf("\n");
5815 print_variable(objid, objidlen, &variable);
5816 }
5817 }
5818
5819 #endif /* testing */
5820
5821 #ifndef NETSNMP_DISABLE_MIB_LOADING
5822 /*
5823 * initialize: no peers included in the report.
5824 */
5825 void
clear_tree_flags(register struct tree * tp)5826 clear_tree_flags(register struct tree *tp)
5827 {
5828 for (; tp; tp = tp->next_peer) {
5829 tp->reported = 0;
5830 if (tp->child_list)
5831 clear_tree_flags(tp->child_list);
5832 /*RECURSE*/}
5833 }
5834
5835 /*
5836 * Update: 1998-07-17 <jhy@gsu.edu>
5837 * Added print_oid_report* functions.
5838 */
5839 static int print_subtree_oid_report_labeledoid = 0;
5840 static int print_subtree_oid_report_oid = 0;
5841 static int print_subtree_oid_report_symbolic = 0;
5842 static int print_subtree_oid_report_mibchildoid = 0;
5843 static int print_subtree_oid_report_suffix = 0;
5844
5845 /*
5846 * These methods recurse.
5847 */
5848 static void print_parent_labeledoid(FILE *, struct tree *);
5849 static void print_parent_oid(FILE *, struct tree *);
5850 static void print_parent_mibchildoid(FILE *, struct tree *);
5851 static void print_parent_label(FILE *, struct tree *);
5852 static void print_subtree_oid_report(FILE *, struct tree *, int);
5853
5854
5855 void
print_oid_report(FILE * fp)5856 print_oid_report(FILE * fp)
5857 {
5858 struct tree *tp;
5859 clear_tree_flags(tree_head);
5860 for (tp = tree_head; tp; tp = tp->next_peer)
5861 print_subtree_oid_report(fp, tp, 0);
5862 }
5863
5864 void
print_oid_report_enable_labeledoid(void)5865 print_oid_report_enable_labeledoid(void)
5866 {
5867 print_subtree_oid_report_labeledoid = 1;
5868 }
5869
5870 void
print_oid_report_enable_oid(void)5871 print_oid_report_enable_oid(void)
5872 {
5873 print_subtree_oid_report_oid = 1;
5874 }
5875
5876 void
print_oid_report_enable_suffix(void)5877 print_oid_report_enable_suffix(void)
5878 {
5879 print_subtree_oid_report_suffix = 1;
5880 }
5881
5882 void
print_oid_report_enable_symbolic(void)5883 print_oid_report_enable_symbolic(void)
5884 {
5885 print_subtree_oid_report_symbolic = 1;
5886 }
5887
5888 void
print_oid_report_enable_mibchildoid(void)5889 print_oid_report_enable_mibchildoid(void)
5890 {
5891 print_subtree_oid_report_mibchildoid = 1;
5892 }
5893
5894 /*
5895 * helper methods for print_subtree_oid_report()
5896 * each one traverses back up the node tree
5897 * until there is no parent. Then, the label combination
5898 * is output, such that the parent is displayed first.
5899 *
5900 * Warning: these methods are all recursive.
5901 */
5902
5903 static void
print_parent_labeledoid(FILE * f,struct tree * tp)5904 print_parent_labeledoid(FILE * f, struct tree *tp)
5905 {
5906 if (tp) {
5907 if (tp->parent) {
5908 print_parent_labeledoid(f, tp->parent);
5909 /*RECURSE*/}
5910 fprintf(f, ".%s(%lu)", tp->label, tp->subid);
5911 }
5912 }
5913
5914 static void
print_parent_oid(FILE * f,struct tree * tp)5915 print_parent_oid(FILE * f, struct tree *tp)
5916 {
5917 if (tp) {
5918 if (tp->parent) {
5919 print_parent_oid(f, tp->parent);
5920 /*RECURSE*/}
5921 fprintf(f, ".%lu", tp->subid);
5922 }
5923 }
5924
5925
print_parent_mibchildoid(FILE * f,struct tree * tp)5926 static void print_parent_mibchildoid(FILE * f, struct tree *tp)
5927 {
5928 static struct tree *temp;
5929 unsigned long elems[100];
5930 int elem_cnt = 0;
5931 int i = 0;
5932 temp = tp;
5933 if (temp) {
5934 while (temp->parent) {
5935 elems[elem_cnt++] = temp->subid;
5936 temp = temp->parent;
5937 }
5938 elems[elem_cnt++] = temp->subid;
5939 }
5940 for (i = elem_cnt - 1; i >= 0; i--) {
5941 if (i == elem_cnt - 1) {
5942 fprintf(f, "%lu", elems[i]);
5943 } else {
5944 fprintf(f, ".%lu", elems[i]);
5945 }
5946 }
5947 }
5948
5949 static void
print_parent_label(FILE * f,struct tree * tp)5950 print_parent_label(FILE * f, struct tree *tp)
5951 {
5952 if (tp) {
5953 if (tp->parent) {
5954 print_parent_label(f, tp->parent);
5955 /*RECURSE*/}
5956 fprintf(f, ".%s", tp->label);
5957 }
5958 }
5959
5960 /**
5961 * @internal
5962 * This methods generates variations on the original print_subtree() report.
5963 * Traverse the tree depth first, from least to greatest sub-identifier.
5964 * Warning: this methods recurses and calls methods that recurse.
5965 *
5966 * @param f File descriptor to print to.
5967 * @param tree ???
5968 * @param count ???
5969 */
5970
5971 static void
print_subtree_oid_report(FILE * f,struct tree * tree,int count)5972 print_subtree_oid_report(FILE * f, struct tree *tree, int count)
5973 {
5974 struct tree *tp;
5975
5976 count++;
5977
5978 /*
5979 * sanity check
5980 */
5981 if (!tree) {
5982 return;
5983 }
5984
5985 /*
5986 * find the not reported peer with the lowest sub-identifier.
5987 * if no more, break the loop and cleanup.
5988 * set "reported" flag, and create report for this peer.
5989 * recurse using the children of this peer, if any.
5990 */
5991 while (1) {
5992 register struct tree *ntp;
5993
5994 tp = NULL;
5995 for (ntp = tree->child_list; ntp; ntp = ntp->next_peer) {
5996 if (ntp->reported)
5997 continue;
5998
5999 if (!tp || (tp->subid > ntp->subid))
6000 tp = ntp;
6001 }
6002 if (!tp)
6003 break;
6004
6005 tp->reported = 1;
6006
6007 if (print_subtree_oid_report_labeledoid) {
6008 print_parent_labeledoid(f, tp);
6009 fprintf(f, "\n");
6010 }
6011 if (print_subtree_oid_report_oid) {
6012 print_parent_oid(f, tp);
6013 fprintf(f, "\n");
6014 }
6015 if (print_subtree_oid_report_symbolic) {
6016 print_parent_label(f, tp);
6017 fprintf(f, "\n");
6018 }
6019 if (print_subtree_oid_report_mibchildoid) {
6020 fprintf(f, "\"%s\"\t", tp->label);
6021 fprintf(f, "\t\t\"");
6022 print_parent_mibchildoid(f, tp);
6023 fprintf(f, "\"\n");
6024 }
6025 if (print_subtree_oid_report_suffix) {
6026 int i;
6027 for (i = 0; i < count; i++)
6028 fprintf(f, " ");
6029 fprintf(f, "%s(%ld) type=%d", tp->label, tp->subid, tp->type);
6030 if (tp->tc_index != -1)
6031 fprintf(f, " tc=%d", tp->tc_index);
6032 if (tp->hint)
6033 fprintf(f, " hint=%s", tp->hint);
6034 if (tp->units)
6035 fprintf(f, " units=%s", tp->units);
6036
6037 fprintf(f, "\n");
6038 }
6039 print_subtree_oid_report(f, tp, count);
6040 /*RECURSE*/}
6041 }
6042 #endif /* NETSNMP_DISABLE_MIB_LOADING */
6043
6044
6045 /**
6046 * Converts timeticks to hours, minutes, seconds string.
6047 *
6048 * @param timeticks The timeticks to convert.
6049 * @param buf Buffer to write to, has to be at
6050 * least 40 Bytes large.
6051 *
6052 * @return The buffer
6053 *
6054 * @see uptimeString
6055 */
6056 char *
uptime_string(u_long timeticks,char * buf)6057 uptime_string(u_long timeticks, char *buf)
6058 {
6059 return uptime_string_n( timeticks, buf, 40);
6060 }
6061
6062 char *
uptime_string_n(u_long timeticks,char * buf,size_t buflen)6063 uptime_string_n(u_long timeticks, char *buf, size_t buflen)
6064 {
6065 uptimeString(timeticks, buf, buflen);
6066 return buf;
6067 }
6068
6069 /**
6070 * Given a string, parses an oid out of it (if possible).
6071 * It will try to parse it based on predetermined configuration if
6072 * present or by every method possible otherwise.
6073 * If a suffix has been registered using NETSNMP_DS_LIB_OIDSUFFIX, it
6074 * will be appended to the input string before processing.
6075 *
6076 * @param argv The OID to string parse
6077 * @param root An OID array where the results are stored.
6078 * @param rootlen The max length of the array going in and the data
6079 * length coming out.
6080 *
6081 * @return The root oid pointer if successful, or NULL otherwise.
6082 */
6083
6084 oid *
snmp_parse_oid(const char * argv,oid * root,size_t * rootlen)6085 snmp_parse_oid(const char *argv, oid * root, size_t * rootlen)
6086 {
6087 #ifndef NETSNMP_DISABLE_MIB_LOADING
6088 size_t savlen = *rootlen;
6089 #endif /* NETSNMP_DISABLE_MIB_LOADING */
6090 static size_t tmpbuf_len = 0;
6091 static char *tmpbuf = NULL;
6092 const char *suffix, *prefix;
6093
6094 suffix = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
6095 NETSNMP_DS_LIB_OIDSUFFIX);
6096 prefix = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
6097 NETSNMP_DS_LIB_OIDPREFIX);
6098 if ((suffix && suffix[0]) || (prefix && prefix[0])) {
6099 if (!suffix)
6100 suffix = "";
6101 if (!prefix)
6102 prefix = "";
6103 if ((strlen(suffix) + strlen(prefix) + strlen(argv) + 2) > tmpbuf_len) {
6104 tmpbuf_len = strlen(suffix) + strlen(argv) + strlen(prefix) + 2;
6105 tmpbuf = malloc(tmpbuf_len);
6106 }
6107 snprintf(tmpbuf, tmpbuf_len, "%s%s%s%s", prefix, argv,
6108 ((suffix[0] == '.' || suffix[0] == '\0') ? "" : "."),
6109 suffix);
6110 argv = tmpbuf;
6111 DEBUGMSGTL(("snmp_parse_oid","Parsing: %s\n",argv));
6112 }
6113
6114 #ifndef NETSNMP_DISABLE_MIB_LOADING
6115 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RANDOM_ACCESS)
6116 || strchr(argv, ':')) {
6117 if (get_node(argv, root, rootlen)) {
6118 free(tmpbuf);
6119 return root;
6120 }
6121 } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REGEX_ACCESS)) {
6122 clear_tree_flags(tree_head);
6123 if (get_wild_node(argv, root, rootlen)) {
6124 free(tmpbuf);
6125 return root;
6126 }
6127 } else {
6128 #endif /* NETSNMP_DISABLE_MIB_LOADING */
6129 if (read_objid(argv, root, rootlen)) {
6130 free(tmpbuf);
6131 return root;
6132 }
6133 #ifndef NETSNMP_DISABLE_MIB_LOADING
6134 *rootlen = savlen;
6135 if (get_node(argv, root, rootlen)) {
6136 free(tmpbuf);
6137 return root;
6138 }
6139 *rootlen = savlen;
6140 DEBUGMSGTL(("parse_oid", "wildly parsing\n"));
6141 clear_tree_flags(tree_head);
6142 if (get_wild_node(argv, root, rootlen)) {
6143 free(tmpbuf);
6144 return root;
6145 }
6146 }
6147 #endif /* NETSNMP_DISABLE_MIB_LOADING */
6148 free(tmpbuf);
6149 return NULL;
6150 }
6151
6152 #ifndef NETSNMP_DISABLE_MIB_LOADING
6153 /*
6154 * Use DISPLAY-HINT to parse a value into an octet string.
6155 *
6156 * note that "1d1d", "11" could have come from an octet string that
6157 * looked like { 1, 1 } or an octet string that looked like { 11 }
6158 * because of this, it's doubtful that anyone would use such a display
6159 * string. Therefore, the parser ignores this case.
6160 */
6161
6162 struct parse_hints {
6163 int length;
6164 int repeat;
6165 int format;
6166 int separator;
6167 int terminator;
6168 unsigned char *result;
6169 int result_max;
6170 int result_len;
6171 };
6172
parse_hints_reset(struct parse_hints * ph)6173 static void parse_hints_reset(struct parse_hints *ph)
6174 {
6175 ph->length = 0;
6176 ph->repeat = 0;
6177 ph->format = 0;
6178 ph->separator = 0;
6179 ph->terminator = 0;
6180 }
6181
parse_hints_ctor(struct parse_hints * ph)6182 static void parse_hints_ctor(struct parse_hints *ph)
6183 {
6184 parse_hints_reset(ph);
6185 ph->result = NULL;
6186 ph->result_max = 0;
6187 ph->result_len = 0;
6188 }
6189
parse_hints_add_result_octet(struct parse_hints * ph,unsigned char octet)6190 static int parse_hints_add_result_octet(struct parse_hints *ph, unsigned char octet)
6191 {
6192 if (!(ph->result_len < ph->result_max)) {
6193 ph->result_max = ph->result_len + 32;
6194 if (!ph->result) {
6195 ph->result = (unsigned char *)malloc(ph->result_max);
6196 } else {
6197 ph->result = (unsigned char *)realloc(ph->result, ph->result_max);
6198 }
6199 }
6200
6201 if (!ph->result) {
6202 return 0; /* failed */
6203 }
6204
6205 ph->result[ph->result_len++] = octet;
6206 return 1; /* success */
6207 }
6208
parse_hints_parse(struct parse_hints * ph,const char ** v_in_out)6209 static int parse_hints_parse(struct parse_hints *ph, const char **v_in_out)
6210 {
6211 const char *v = *v_in_out;
6212 char *nv;
6213 int base;
6214 int repeats = 0;
6215 int repeat_fixup = ph->result_len;
6216
6217 if (ph->repeat) {
6218 if (!parse_hints_add_result_octet(ph, 0)) {
6219 return 0;
6220 }
6221 }
6222 do {
6223 base = 0;
6224 switch (ph->format) {
6225 case 'x': base += 6; /* fall through */
6226 case 'd': base += 2; /* fall through */
6227 case 'o': base += 8; /* fall through */
6228 {
6229 int i;
6230 unsigned long number = strtol(v, &nv, base);
6231 if (nv == v) return 0;
6232 v = nv;
6233 for (i = 0; i < ph->length; i++) {
6234 int shift = 8 * (ph->length - 1 - i);
6235 if (!parse_hints_add_result_octet(ph, (u_char)(number >> shift) )) {
6236 return 0; /* failed */
6237 }
6238 }
6239 }
6240 break;
6241
6242 case 'a':
6243 {
6244 int i;
6245
6246 for (i = 0; i < ph->length && *v; i++) {
6247 if (!parse_hints_add_result_octet(ph, *v++)) {
6248 return 0; /* failed */
6249 }
6250 }
6251 }
6252 break;
6253 }
6254
6255 repeats++;
6256
6257 if (ph->separator && *v) {
6258 if (*v == ph->separator) {
6259 v++;
6260 } else {
6261 return 0; /* failed */
6262 }
6263 }
6264
6265 if (ph->terminator) {
6266 if (*v == ph->terminator) {
6267 v++;
6268 break;
6269 }
6270 }
6271 } while (ph->repeat && *v);
6272 if (ph->repeat) {
6273 ph->result[repeat_fixup] = repeats;
6274 }
6275
6276 *v_in_out = v;
6277 return 1;
6278 }
6279
parse_hints_length_add_digit(struct parse_hints * ph,int digit)6280 static void parse_hints_length_add_digit(struct parse_hints *ph, int digit)
6281 {
6282 ph->length *= 10;
6283 ph->length += digit - '0';
6284 }
6285
parse_octet_hint(const char * hint,const char * value,unsigned char ** new_val,int * new_val_len)6286 const char *parse_octet_hint(const char *hint, const char *value, unsigned char **new_val, int *new_val_len)
6287 {
6288 const char *h = hint;
6289 const char *v = value;
6290 struct parse_hints ph;
6291 int retval = 1;
6292 /* See RFC 1443 */
6293 enum {
6294 HINT_1_2,
6295 HINT_2_3,
6296 HINT_1_2_4,
6297 HINT_1_2_5
6298 } state = HINT_1_2;
6299
6300 parse_hints_ctor(&ph);
6301 while (*h && *v && retval) {
6302 switch (state) {
6303 case HINT_1_2:
6304 if ('*' == *h) {
6305 ph.repeat = 1;
6306 state = HINT_2_3;
6307 } else if (isdigit((unsigned char)(*h))) {
6308 parse_hints_length_add_digit(&ph, *h);
6309 state = HINT_2_3;
6310 } else {
6311 return v; /* failed */
6312 }
6313 break;
6314
6315 case HINT_2_3:
6316 if (isdigit((unsigned char)(*h))) {
6317 parse_hints_length_add_digit(&ph, *h);
6318 /* state = HINT_2_3 */
6319 } else if ('x' == *h || 'd' == *h || 'o' == *h || 'a' == *h) {
6320 ph.format = *h;
6321 state = HINT_1_2_4;
6322 } else {
6323 return v; /* failed */
6324 }
6325 break;
6326
6327 case HINT_1_2_4:
6328 if ('*' == *h) {
6329 retval = parse_hints_parse(&ph, &v);
6330 parse_hints_reset(&ph);
6331
6332 ph.repeat = 1;
6333 state = HINT_2_3;
6334 } else if (isdigit((unsigned char)(*h))) {
6335 retval = parse_hints_parse(&ph, &v);
6336 parse_hints_reset(&ph);
6337
6338 parse_hints_length_add_digit(&ph, *h);
6339 state = HINT_2_3;
6340 } else {
6341 ph.separator = *h;
6342 state = HINT_1_2_5;
6343 }
6344 break;
6345
6346 case HINT_1_2_5:
6347 if ('*' == *h) {
6348 retval = parse_hints_parse(&ph, &v);
6349 parse_hints_reset(&ph);
6350
6351 ph.repeat = 1;
6352 state = HINT_2_3;
6353 } else if (isdigit((unsigned char)(*h))) {
6354 retval = parse_hints_parse(&ph, &v);
6355 parse_hints_reset(&ph);
6356
6357 parse_hints_length_add_digit(&ph, *h);
6358 state = HINT_2_3;
6359 } else {
6360 ph.terminator = *h;
6361
6362 retval = parse_hints_parse(&ph, &v);
6363 parse_hints_reset(&ph);
6364
6365 state = HINT_1_2;
6366 }
6367 break;
6368 }
6369 h++;
6370 }
6371 while (*v && retval) {
6372 retval = parse_hints_parse(&ph, &v);
6373 }
6374 if (retval) {
6375 *new_val = ph.result;
6376 *new_val_len = ph.result_len;
6377 } else {
6378 if (ph.result) {
6379 SNMP_FREE(ph.result);
6380 }
6381 *new_val = NULL;
6382 *new_val_len = 0;
6383 }
6384 return retval ? NULL : v;
6385 }
6386 #endif /* NETSNMP_DISABLE_MIB_LOADING */
6387
6388 #ifdef test_display_hint
6389
main(int argc,const char ** argv)6390 int main(int argc, const char **argv)
6391 {
6392 const char *hint;
6393 const char *value;
6394 unsigned char *new_val;
6395 int new_val_len;
6396 char *r;
6397
6398 if (argc < 3) {
6399 fprintf(stderr, "usage: dh <hint> <value>\n");
6400 exit(2);
6401 }
6402 hint = argv[1];
6403 value = argv[2];
6404 r = parse_octet_hint(hint, value, &new_val, &new_val_len);
6405 printf("{\"%s\", \"%s\"}: \n\t", hint, value);
6406 if (r) {
6407 *r = 0;
6408 printf("returned failed\n");
6409 printf("value syntax error at: %s\n", value);
6410 }
6411 else {
6412 int i;
6413 printf("returned success\n");
6414 for (i = 0; i < new_val_len; i++) {
6415 int c = new_val[i] & 0xFF;
6416 printf("%02X(%c) ", c, isprint(c) ? c : ' ');
6417 }
6418 SNMP_FREE(new_val);
6419 }
6420 printf("\n");
6421 exit(0);
6422 }
6423
6424 #endif /* test_display_hint */
6425
6426 #ifndef NETSNMP_FEATURE_REMOVE_MIB_TO_ASN_TYPE
6427 u_char
mib_to_asn_type(int mib_type)6428 mib_to_asn_type(int mib_type)
6429 {
6430 switch (mib_type) {
6431 case TYPE_OBJID:
6432 return ASN_OBJECT_ID;
6433
6434 case TYPE_OCTETSTR:
6435 return ASN_OCTET_STR;
6436
6437 case TYPE_NETADDR:
6438 case TYPE_IPADDR:
6439 return ASN_IPADDRESS;
6440
6441 case TYPE_INTEGER32:
6442 case TYPE_INTEGER:
6443 return ASN_INTEGER;
6444
6445 case TYPE_COUNTER:
6446 return ASN_COUNTER;
6447
6448 case TYPE_GAUGE:
6449 return ASN_GAUGE;
6450
6451 case TYPE_TIMETICKS:
6452 return ASN_TIMETICKS;
6453
6454 case TYPE_OPAQUE:
6455 return ASN_OPAQUE;
6456
6457 case TYPE_NULL:
6458 return ASN_NULL;
6459
6460 case TYPE_COUNTER64:
6461 return ASN_COUNTER64;
6462
6463 case TYPE_BITSTRING:
6464 return ASN_BIT_STR;
6465
6466 case TYPE_UINTEGER:
6467 case TYPE_UNSIGNED32:
6468 return ASN_UNSIGNED;
6469
6470 case TYPE_NSAPADDRESS:
6471 return ASN_NSAP;
6472
6473 }
6474 return -1;
6475 }
6476 #endif /* NETSNMP_FEATURE_REMOVE_MIB_TO_ASN_TYPE */
6477
6478 /**
6479 * Converts a string to its OID form.
6480 * in example "hello" = 5 . 'h' . 'e' . 'l' . 'l' . 'o'
6481 *
6482 * @param S The string.
6483 * @param O The oid.
6484 * @param L The length of the oid.
6485 *
6486 * @return 0 on Sucess, 1 on failure.
6487 */
6488 #ifndef NETSNMP_FEATURE_REMOVE_MIB_STRING_CONVERSIONS
6489 int
netsnmp_str2oid(const char * S,oid * O,int L)6490 netsnmp_str2oid(const char *S, oid * O, int L)
6491 {
6492 const char *c = S;
6493 oid *o = &O[1];
6494
6495 --L; /* leave room for length prefix */
6496
6497 for (; *c && L; --L, ++o, ++c)
6498 *o = *c;
6499
6500 /*
6501 * make sure we got to the end of the string
6502 */
6503 if (*c != 0)
6504 return 1;
6505
6506 /*
6507 * set the length of the oid
6508 */
6509 *O = c - S;
6510
6511 return 0;
6512 }
6513
6514 /**
6515 * Converts an OID to its character form.
6516 * in example 5 . 1 . 2 . 3 . 4 . 5 = 12345
6517 *
6518 * @param C The character buffer.
6519 * @param L The length of the buffer.
6520 * @param O The oid.
6521 *
6522 * @return 0 on Sucess, 1 on failure.
6523 */
6524 int
netsnmp_oid2chars(char * C,int L,const oid * O)6525 netsnmp_oid2chars(char *C, int L, const oid * O)
6526 {
6527 char *c = C;
6528 const oid *o = &O[1];
6529
6530 if (L < (int)*O)
6531 return 1;
6532
6533 L = *O; /** length */
6534 for (; L; --L, ++o, ++c) {
6535 if (*o > 0xFF)
6536 return 1;
6537 *c = (char)*o;
6538 }
6539 return 0;
6540 }
6541
6542 /**
6543 * Converts an OID to its string form.
6544 * in example 5 . 'h' . 'e' . 'l' . 'l' . 'o' = "hello\0" (null terminated)
6545 *
6546 * @param S The character string buffer.
6547 * @param L The length of the string buffer.
6548 * @param O The oid.
6549 *
6550 * @return 0 on Sucess, 1 on failure.
6551 */
6552 int
netsnmp_oid2str(char * S,int L,oid * O)6553 netsnmp_oid2str(char *S, int L, oid * O)
6554 {
6555 int rc;
6556
6557 if (L <= (int)*O)
6558 return 1;
6559
6560 rc = netsnmp_oid2chars(S, L, O);
6561 if (rc)
6562 return 1;
6563
6564 S[ *O ] = 0;
6565
6566 return 0;
6567 }
6568 #endif /* NETSNMP_FEATURE_REMOVE_MIB_STRING_CONVERSIONS */
6569
6570
6571 #ifndef NETSNMP_FEATURE_REMOVE_MIB_SNPRINT
6572 int
snprint_by_type(char * buf,size_t buf_len,netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6573 snprint_by_type(char *buf, size_t buf_len,
6574 netsnmp_variable_list * var,
6575 const struct enum_list *enums,
6576 const char *hint, const char *units)
6577 {
6578 size_t out_len = 0;
6579 if (sprint_realloc_by_type((u_char **) & buf, &buf_len, &out_len, 0,
6580 var, enums, hint, units))
6581 return (int) out_len;
6582 else
6583 return -1;
6584 }
6585
6586 int
snprint_hexstring(char * buf,size_t buf_len,const u_char * cp,size_t len)6587 snprint_hexstring(char *buf, size_t buf_len, const u_char * cp, size_t len)
6588 {
6589 size_t out_len = 0;
6590 if (sprint_realloc_hexstring((u_char **) & buf, &buf_len, &out_len, 0,
6591 cp, len))
6592 return (int) out_len;
6593 else
6594 return -1;
6595 }
6596
6597 int
snprint_asciistring(char * buf,size_t buf_len,const u_char * cp,size_t len)6598 snprint_asciistring(char *buf, size_t buf_len,
6599 const u_char * cp, size_t len)
6600 {
6601 size_t out_len = 0;
6602 if (sprint_realloc_asciistring
6603 ((u_char **) & buf, &buf_len, &out_len, 0, cp, len))
6604 return (int) out_len;
6605 else
6606 return -1;
6607 }
6608
6609 int
snprint_octet_string(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6610 snprint_octet_string(char *buf, size_t buf_len,
6611 const netsnmp_variable_list * var, const struct enum_list *enums,
6612 const char *hint, const char *units)
6613 {
6614 size_t out_len = 0;
6615 if (sprint_realloc_octet_string
6616 ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint,
6617 units))
6618 return (int) out_len;
6619 else
6620 return -1;
6621 }
6622
6623 int
snprint_opaque(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6624 snprint_opaque(char *buf, size_t buf_len,
6625 const netsnmp_variable_list * var, const struct enum_list *enums,
6626 const char *hint, const char *units)
6627 {
6628 size_t out_len = 0;
6629 if (sprint_realloc_opaque((u_char **) & buf, &buf_len, &out_len, 0,
6630 var, enums, hint, units))
6631 return (int) out_len;
6632 else
6633 return -1;
6634 }
6635
6636 int
snprint_object_identifier(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6637 snprint_object_identifier(char *buf, size_t buf_len,
6638 const netsnmp_variable_list * var,
6639 const struct enum_list *enums, const char *hint,
6640 const char *units)
6641 {
6642 size_t out_len = 0;
6643 if (sprint_realloc_object_identifier
6644 ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint,
6645 units))
6646 return (int) out_len;
6647 else
6648 return -1;
6649 }
6650
6651 int
snprint_timeticks(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6652 snprint_timeticks(char *buf, size_t buf_len,
6653 const netsnmp_variable_list * var, const struct enum_list *enums,
6654 const char *hint, const char *units)
6655 {
6656 size_t out_len = 0;
6657 if (sprint_realloc_timeticks((u_char **) & buf, &buf_len, &out_len, 0,
6658 var, enums, hint, units))
6659 return (int) out_len;
6660 else
6661 return -1;
6662 }
6663
6664 int
snprint_hinted_integer(char * buf,size_t buf_len,long val,const char * hint,const char * units)6665 snprint_hinted_integer(char *buf, size_t buf_len,
6666 long val, const char *hint, const char *units)
6667 {
6668 size_t out_len = 0;
6669 if (sprint_realloc_hinted_integer
6670 ((u_char **) & buf, &buf_len, &out_len, 0, val, 'd', hint, units))
6671 return (int) out_len;
6672 else
6673 return -1;
6674 }
6675
6676 int
snprint_integer(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6677 snprint_integer(char *buf, size_t buf_len,
6678 const netsnmp_variable_list * var, const struct enum_list *enums,
6679 const char *hint, const char *units)
6680 {
6681 size_t out_len = 0;
6682 if (sprint_realloc_integer((u_char **) & buf, &buf_len, &out_len, 0,
6683 var, enums, hint, units))
6684 return (int) out_len;
6685 else
6686 return -1;
6687 }
6688
6689 int
snprint_uinteger(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6690 snprint_uinteger(char *buf, size_t buf_len,
6691 const netsnmp_variable_list * var, const struct enum_list *enums,
6692 const char *hint, const char *units)
6693 {
6694 size_t out_len = 0;
6695 if (sprint_realloc_uinteger((u_char **) & buf, &buf_len, &out_len, 0,
6696 var, enums, hint, units))
6697 return (int) out_len;
6698 else
6699 return -1;
6700 }
6701
6702 int
snprint_gauge(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6703 snprint_gauge(char *buf, size_t buf_len,
6704 const netsnmp_variable_list * var, const struct enum_list *enums,
6705 const char *hint, const char *units)
6706 {
6707 size_t out_len = 0;
6708 if (sprint_realloc_gauge((u_char **) & buf, &buf_len, &out_len, 0,
6709 var, enums, hint, units))
6710 return (int) out_len;
6711 else
6712 return -1;
6713 }
6714
6715 int
snprint_counter(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6716 snprint_counter(char *buf, size_t buf_len,
6717 const netsnmp_variable_list * var, const struct enum_list *enums,
6718 const char *hint, const char *units)
6719 {
6720 size_t out_len = 0;
6721 if (sprint_realloc_counter((u_char **) & buf, &buf_len, &out_len, 0,
6722 var, enums, hint, units))
6723 return (int) out_len;
6724 else
6725 return -1;
6726 }
6727
6728 int
snprint_networkaddress(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6729 snprint_networkaddress(char *buf, size_t buf_len,
6730 const netsnmp_variable_list * var,
6731 const struct enum_list *enums, const char *hint,
6732 const char *units)
6733 {
6734 size_t out_len = 0;
6735 if (sprint_realloc_networkaddress
6736 ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint,
6737 units))
6738 return (int) out_len;
6739 else
6740 return -1;
6741 }
6742
6743 int
snprint_ipaddress(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6744 snprint_ipaddress(char *buf, size_t buf_len,
6745 const netsnmp_variable_list * var, const struct enum_list *enums,
6746 const char *hint, const char *units)
6747 {
6748 size_t out_len = 0;
6749 if (sprint_realloc_ipaddress((u_char **) & buf, &buf_len, &out_len, 0,
6750 var, enums, hint, units))
6751 return (int) out_len;
6752 else
6753 return -1;
6754 }
6755
6756 int
snprint_null(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6757 snprint_null(char *buf, size_t buf_len,
6758 const netsnmp_variable_list * var, const struct enum_list *enums,
6759 const char *hint, const char *units)
6760 {
6761 size_t out_len = 0;
6762 if (sprint_realloc_null((u_char **) & buf, &buf_len, &out_len, 0,
6763 var, enums, hint, units))
6764 return (int) out_len;
6765 else
6766 return -1;
6767 }
6768
6769 int
snprint_bitstring(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6770 snprint_bitstring(char *buf, size_t buf_len,
6771 const netsnmp_variable_list * var, const struct enum_list *enums,
6772 const char *hint, const char *units)
6773 {
6774 size_t out_len = 0;
6775 if (sprint_realloc_bitstring((u_char **) & buf, &buf_len, &out_len, 0,
6776 var, enums, hint, units))
6777 return (int) out_len;
6778 else
6779 return -1;
6780 }
6781
6782 int
snprint_nsapaddress(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6783 snprint_nsapaddress(char *buf, size_t buf_len,
6784 const netsnmp_variable_list * var, const struct enum_list *enums,
6785 const char *hint, const char *units)
6786 {
6787 size_t out_len = 0;
6788 if (sprint_realloc_nsapaddress
6789 ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint,
6790 units))
6791 return (int) out_len;
6792 else
6793 return -1;
6794 }
6795
6796 int
snprint_counter64(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6797 snprint_counter64(char *buf, size_t buf_len,
6798 const netsnmp_variable_list * var, const struct enum_list *enums,
6799 const char *hint, const char *units)
6800 {
6801 size_t out_len = 0;
6802 if (sprint_realloc_counter64((u_char **) & buf, &buf_len, &out_len, 0,
6803 var, enums, hint, units))
6804 return (int) out_len;
6805 else
6806 return -1;
6807 }
6808
6809 int
snprint_badtype(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6810 snprint_badtype(char *buf, size_t buf_len,
6811 const netsnmp_variable_list * var, const struct enum_list *enums,
6812 const char *hint, const char *units)
6813 {
6814 size_t out_len = 0;
6815 if (sprint_realloc_badtype((u_char **) & buf, &buf_len, &out_len, 0,
6816 var, enums, hint, units))
6817 return (int) out_len;
6818 else
6819 return -1;
6820 }
6821
6822 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
6823 int
snprint_float(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6824 snprint_float(char *buf, size_t buf_len,
6825 const netsnmp_variable_list * var, const struct enum_list *enums,
6826 const char *hint, const char *units)
6827 {
6828 size_t out_len = 0;
6829 if (sprint_realloc_float((u_char **) & buf, &buf_len, &out_len, 0,
6830 var, enums, hint, units))
6831 return (int) out_len;
6832 else
6833 return -1;
6834 }
6835
6836 int
snprint_double(char * buf,size_t buf_len,const netsnmp_variable_list * var,const struct enum_list * enums,const char * hint,const char * units)6837 snprint_double(char *buf, size_t buf_len,
6838 const netsnmp_variable_list * var, const struct enum_list *enums,
6839 const char *hint, const char *units)
6840 {
6841 size_t out_len = 0;
6842 if (sprint_realloc_double((u_char **) & buf, &buf_len, &out_len, 0,
6843 var, enums, hint, units))
6844 return (int) out_len;
6845 else
6846 return -1;
6847 }
6848 #endif
6849 #endif /* NETSNMP_FEATURE_REMOVE_MIB_SNPRINT */
6850 /** @} */
6851
6852