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