diff options
Diffstat (limited to 'snmplib/mib.c')
-rw-r--r-- | snmplib/mib.c | 6800 |
1 files changed, 6800 insertions, 0 deletions
diff --git a/snmplib/mib.c b/snmplib/mib.c new file mode 100644 index 0000000..cbabf25 --- /dev/null +++ b/snmplib/mib.c @@ -0,0 +1,6800 @@ +/* + * mib.c + * + * $Id$ + * + * Update: 1998-07-17 <jhy@gsu.edu> + * Added print_oid_report* functions. + * + */ +/* Portions of this file are subject to the following copyrights. See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/********************************************************************** + Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. +******************************************************************/ +/* + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-features.h> + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> + +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_DMALLOC_H +#include <dmalloc.h> +#endif + +#include <net-snmp/types.h> +#include <net-snmp/output_api.h> +#include <net-snmp/config_api.h> +#include <net-snmp/utilities.h> + +#include <net-snmp/library/asn1.h> +#include <net-snmp/library/snmp_api.h> +#include <net-snmp/library/mib.h> +#include <net-snmp/library/parse.h> +#include <net-snmp/library/int64.h> +#include <net-snmp/library/snmp_client.h> + +netsnmp_feature_child_of(mib_api, libnetsnmp) +netsnmp_feature_child_of(mib_strings_all, mib_api) + +netsnmp_feature_child_of(mib_snprint, mib_strings_all) +netsnmp_feature_child_of(mib_snprint_description, mib_strings_all) +netsnmp_feature_child_of(mib_snprint_variable, mib_strings_all) +netsnmp_feature_child_of(mib_string_conversions, mib_strings_all) +netsnmp_feature_child_of(print_mib, mib_strings_all) +netsnmp_feature_child_of(snprint_objid, mib_strings_all) +netsnmp_feature_child_of(snprint_value, mib_strings_all) + +netsnmp_feature_child_of(mib_to_asn_type, mib_api) + +/** @defgroup mib_utilities mib parsing and datatype manipulation routines. + * @ingroup library + * + * @{ + */ + +static char *uptimeString(u_long, char *, size_t); + +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); + +static int print_tree_node(u_char ** buf, size_t * buf_len, + size_t * out_len, int allow_realloc, + struct tree *tp, int width); +static void handle_mibdirs_conf(const char *token, char *line); +static void handle_mibs_conf(const char *token, char *line); +static void handle_mibfile_conf(const char *token, char *line); + +static 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); + +/* + * helper functions for get_module_node + */ +static int node_to_oid(struct tree *, oid *, size_t *); +#ifndef NETSNMP_DISABLE_MIB_LOADING +static int _add_strings_to_oid(struct tree *, char *, + oid *, size_t *, size_t); +#else +static int _add_strings_to_oid(void *, char *, + oid *, size_t *, size_t); +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +#ifndef NETSNMP_DISABLE_MIB_LOADING +NETSNMP_IMPORT struct tree *tree_head; +static struct tree *tree_top; + +NETSNMP_IMPORT struct tree *Mib; +struct tree *Mib; /* Backwards compatibility */ +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +oid RFC1213_MIB[] = { 1, 3, 6, 1, 2, 1 }; +static char Standard_Prefix[] = ".1.3.6.1.2.1"; + +/* + * Set default here as some uses of read_objid require valid pointer. + */ +static char *Prefix = &Standard_Prefix[0]; +typedef struct _PrefixList { + const char *str; + int len; +} *PrefixListPtr, PrefixList; + +/* + * Here are the prefix strings. + * Note that the first one finds the value of Prefix or Standard_Prefix. + * Any of these MAY start with period; all will NOT end with period. + * Period is added where needed. See use of Prefix in this module. + */ +PrefixList mib_prefixes[] = { + {&Standard_Prefix[0]}, /* placeholder for Prefix data */ + {".iso.org.dod.internet.mgmt.mib-2"}, + {".iso.org.dod.internet.experimental"}, + {".iso.org.dod.internet.private"}, + {".iso.org.dod.internet.snmpParties"}, + {".iso.org.dod.internet.snmpSecrets"}, + {NULL, 0} /* end of list */ +}; + +enum inet_address_type { + IPV4 = 1, + IPV6 = 2, + IPV4Z = 3, + IPV6Z = 4, + DNS = 16 +}; + + +/** + * @internal + * Converts timeticks to hours, minutes, seconds string. + * + * @param timeticks The timeticks to convert. + * @param buf Buffer to write to, has to be at + * least 40 Bytes large. + * + * @return The buffer. + */ +static char * +uptimeString(u_long timeticks, char *buf, size_t buflen) +{ + int centisecs, seconds, minutes, hours, days; + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS)) { + snprintf(buf, buflen, "%lu", timeticks); + return buf; + } + + + centisecs = timeticks % 100; + timeticks /= 100; + days = timeticks / (60 * 60 * 24); + timeticks %= (60 * 60 * 24); + + hours = timeticks / (60 * 60); + timeticks %= (60 * 60); + + minutes = timeticks / 60; + seconds = timeticks % 60; + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) + snprintf(buf, buflen, "%d:%d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + else { + if (days == 0) { + snprintf(buf, buflen, "%d:%02d:%02d.%02d", + hours, minutes, seconds, centisecs); + } else if (days == 1) { + snprintf(buf, buflen, "%d day, %d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + } else { + snprintf(buf, buflen, "%d days, %d:%02d:%02d.%02d", + days, hours, minutes, seconds, centisecs); + } + } + return buf; +} + + + +/** + * @internal + * Prints the character pointed to if in human-readable ASCII range, + * otherwise prints a dot. + * + * @param buf Buffer to print the character to. + * @param ch Character to print. + */ +static void +sprint_char(char *buf, const u_char ch) +{ + if (isprint(ch) || isspace(ch)) { + sprintf(buf, "%c", (int) ch); + } else { + sprintf(buf, "."); + } +} + + + +/** + * Prints a hexadecimal string into a buffer. + * + * The characters pointed by *cp are encoded as hexadecimal string. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf address of the buffer to print to. + * @param buf_len address to an integer containing the size of buf. + * @param out_len incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param cp the array of characters to encode. + * @param line_len the array length of cp. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + const u_char *tp; + const u_char *cp2 = cp; + size_t lenleft = line_len; + + /* + * Make sure there's enough room for the hex output.... + */ + while ((*out_len + line_len*3+1) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + + /* + * .... and display the hex values themselves.... + */ + for (; lenleft >= 8; lenleft-=8) { + sprintf((char *) (*buf + *out_len), + "%02X %02X %02X %02X %02X %02X %02X %02X ", cp[0], cp[1], + cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + *out_len += strlen((char *) (*buf + *out_len)); + cp += 8; + } + for (; lenleft > 0; lenleft--) { + sprintf((char *) (*buf + *out_len), "%02X ", *cp++); + *out_len += strlen((char *) (*buf + *out_len)); + } + + /* + * .... plus (optionally) do the same for the ASCII equivalent. + */ + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT)) { + while ((*out_len + line_len+5) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + sprintf((char *) (*buf + *out_len), " ["); + *out_len += strlen((char *) (*buf + *out_len)); + for (tp = cp2; tp < cp; tp++) { + sprint_char((char *) (*buf + *out_len), *tp); + (*out_len)++; + } + sprintf((char *) (*buf + *out_len), "]"); + *out_len += strlen((char *) (*buf + *out_len)); + } + return 1; +} + +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) +{ + int line_len = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH); + if (!line_len) + line_len=len; + + for (; (int)len > line_len; len -= line_len) { + if(!_sprint_hexstring_line(buf, buf_len, out_len, allow_realloc, cp, line_len)) + return 0; + *(*buf + (*out_len)++) = '\n'; + *(*buf + *out_len) = 0; + cp += line_len; + } + if(!_sprint_hexstring_line(buf, buf_len, out_len, allow_realloc, cp, len)) + return 0; + *(*buf + *out_len) = 0; + return 1; +} + + + +/** + * Prints an ascii string into a buffer. + * + * The characters pointed by *cp are encoded as an ascii string. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf address of the buffer to print to. + * @param buf_len address to an integer containing the size of buf. + * @param out_len incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param cp the array of characters to encode. + * @param len the array length of cp. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + int i; + + for (i = 0; i < (int) len; i++) { + if (isprint(*cp) || isspace(*cp)) { + if (*cp == '\\' || *cp == '"') { + if ((*out_len >= *buf_len) && + !(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + *(*buf + (*out_len)++) = '\\'; + } + if ((*out_len >= *buf_len) && + !(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + *(*buf + (*out_len)++) = *cp++; + } else { + if ((*out_len >= *buf_len) && + !(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + *(*buf + (*out_len)++) = '.'; + cp++; + } + } + if ((*out_len >= *buf_len) && + !(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + *(*buf + *out_len) = '\0'; + return 1; +} + +/** + * Prints an octet string into a buffer. + * + * The variable var is encoded as octet string. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + size_t saved_out_len = *out_len; + const char *saved_hint = hint; + int hex = 0, x = 0; + u_char *cp; + int output_format, cnt; + + if ((var->type != ASN_OCTET_STR) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + const char str[] = "Wrong Type (should be OCTET STRING): "; + if (snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + + if (hint) { + int repeat, width = 1; + long value; + char code = 'd', separ = 0, term = 0, ch, intbuf[32]; +#define HEX2DIGIT_NEED_INIT 3 + char hex2digit = HEX2DIGIT_NEED_INIT; + u_char *ecp; + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "STRING: ")) { + return 0; + } + } + cp = var->val.string; + ecp = cp + var->val_len; + + while (cp < ecp) { + repeat = 1; + if (*hint) { + if (*hint == '*') { + repeat = *cp++; + hint++; + } + width = 0; + while ('0' <= *hint && *hint <= '9') + width = (width * 10) + (*hint++ - '0'); + code = *hint++; + if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9') + && (width != 0 + || (ch != 'x' && ch != 'd' && ch != 'o'))) + separ = *hint++; + else + separ = 0; + if ((ch = *hint) && ch != '*' && (ch < '0' || ch > '9') + && (width != 0 + || (ch != 'x' && ch != 'd' && ch != 'o'))) + term = *hint++; + else + term = 0; + if (width == 0) /* Handle malformed hint strings */ + width = 1; + } + + while (repeat && cp < ecp) { + value = 0; + if (code != 'a' && code != 't') { + for (x = 0; x < width; x++) { + value = value * 256 + *cp++; + } + } + switch (code) { + case 'x': + if (HEX2DIGIT_NEED_INIT == hex2digit) + hex2digit = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT); + /* + * if value is < 16, it will be a single hex digit. If the + * width is 1 (we are outputting a byte at a time), pat it + * to 2 digits if NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT is set + * or all of the following are true: + * - we do not have a separation character + * - there is no hint left (or there never was a hint) + * + * e.g. for the data 0xAA01BB, would anyone really ever + * want the string "AA1BB"?? + */ + if (((value < 16) && (1 == width)) && + (hex2digit || ((0 == separ) && (0 == *hint)))) { + sprintf(intbuf, "0%lx", value); + } else { + sprintf(intbuf, "%lx", value); + } + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, intbuf)) { + return 0; + } + break; + case 'd': + sprintf(intbuf, "%ld", value); + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, intbuf)) { + return 0; + } + break; + case 'o': + sprintf(intbuf, "%lo", value); + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, intbuf)) { + return 0; + } + break; + case 't': /* new in rfc 3411 */ + case 'a': + cnt = SNMP_MIN(width, ecp - cp); + if (!sprint_realloc_asciistring(buf, buf_len, out_len, + allow_realloc, cp, cnt)) + return 0; + cp += cnt; + break; + default: + *out_len = saved_out_len; + if (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "(Bad hint ignored: ") + && snmp_cstrcat(buf, buf_len, out_len, + allow_realloc, saved_hint) + && snmp_cstrcat(buf, buf_len, out_len, + allow_realloc, ") ")) { + return sprint_realloc_octet_string(buf, buf_len, + out_len, + allow_realloc, + var, enums, + NULL, NULL); + } else { + return 0; + } + } + + if (cp < ecp && separ) { + while ((*out_len + 1) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = separ; + (*out_len)++; + *(*buf + *out_len) = '\0'; + } + repeat--; + } + + if (term && cp < ecp) { + while ((*out_len + 1) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = term; + (*out_len)++; + *(*buf + *out_len) = '\0'; + } + } + + if (units) { + return (snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, " ") + && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units)); + } + if ((*out_len >= *buf_len) && + !(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + *(*buf + *out_len) = '\0'; + + return 1; + } + + output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT); + if (0 == output_format) { + output_format = NETSNMP_STRING_OUTPUT_GUESS; + } + switch (output_format) { + case NETSNMP_STRING_OUTPUT_GUESS: + hex = 0; + for (cp = var->val.string, x = 0; x < (int) var->val_len; x++, cp++) { + if (!isprint(*cp) && !isspace(*cp)) { + hex = 1; + } + } + break; + + case NETSNMP_STRING_OUTPUT_ASCII: + hex = 0; + break; + + case NETSNMP_STRING_OUTPUT_HEX: + hex = 1; + break; + } + + if (var->val_len == 0) { + return snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\""); + } + + if (hex) { + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) { + return 0; + } + } else { + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Hex-STRING: ")) { + return 0; + } + } + + if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc, + var->val.string, var->val_len)) { + return 0; + } + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) { + return 0; + } + } + } else { + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "STRING: ")) { + return 0; + } + } + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "\"")) { + return 0; + } + if (!sprint_realloc_asciistring + (buf, buf_len, out_len, allow_realloc, var->val.string, + var->val_len)) { + return 0; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"")) { + return 0; + } + } + + if (units) { + return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ") + && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units)); + } + return 1; +} + +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + +/** + * Prints a float into a buffer. + * + * The variable var is encoded as a floating point value. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + if ((var->type != ASN_OPAQUE_FLOAT) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + if (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "Wrong Type (should be Float): ")) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Opaque: Float: ")) { + return 0; + } + } + + + /* + * How much space needed for max. length float? 128 is overkill. + */ + + while ((*out_len + 128 + 1) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + + sprintf((char *) (*buf + *out_len), "%f", *var->val.floatVal); + *out_len += strlen((char *) (*buf + *out_len)); + + if (units) { + return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ") + && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units)); + } + return 1; +} + + +/** + * Prints a double into a buffer. + * + * The variable var is encoded as a double precision floating point value. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + if ((var->type != ASN_OPAQUE_DOUBLE) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + if (snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, + "Wrong Type (should be Double): ")) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Opaque: Float: ")) { + return 0; + } + } + + /* + * How much space needed for max. length double? 128 is overkill. + */ + + while ((*out_len + 128 + 1) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + + sprintf((char *) (*buf + *out_len), "%f", *var->val.doubleVal); + *out_len += strlen((char *) (*buf + *out_len)); + + if (units) { + return (snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, " ") + && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units)); + } + return 1; +} + +#endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ + + +/** + * Prints a counter into a buffer. + * + * The variable var is encoded as a counter value. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char a64buf[I64CHARSZ + 1]; + + if ((var->type != ASN_COUNTER64 +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + && var->type != ASN_OPAQUE_COUNTER64 + && var->type != ASN_OPAQUE_I64 && var->type != ASN_OPAQUE_U64 +#endif + ) && (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + if (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "Wrong Type (should be Counter64): ")) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + if (var->type != ASN_COUNTER64) { + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Opaque: ")) { + return 0; + } + } +#endif +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + switch (var->type) { + case ASN_OPAQUE_U64: + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "UInt64: ")) { + return 0; + } + break; + case ASN_OPAQUE_I64: + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Int64: ")) { + return 0; + } + break; + case ASN_COUNTER64: + case ASN_OPAQUE_COUNTER64: +#endif + if (!snmp_cstrcat + (buf, buf_len, out_len, allow_realloc, "Counter64: ")) { + return 0; + } +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + } +#endif + } +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + if (var->type == ASN_OPAQUE_I64) { + printI64(a64buf, var->val.counter64); + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, a64buf)) { + return 0; + } + } else { +#endif + printU64(a64buf, var->val.counter64); + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, a64buf)) { + return 0; + } +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + } +#endif + + if (units) { + return (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " ") + && snmp_cstrcat(buf, buf_len, out_len, allow_realloc, units)); + } + return 1; +} + + +/** + * Prints an object identifier into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + if ((var->type != ASN_OPAQUE +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + && var->type != ASN_OPAQUE_COUNTER64 + && var->type != ASN_OPAQUE_U64 + && var->type != ASN_OPAQUE_I64 + && var->type != ASN_OPAQUE_FLOAT && var->type != ASN_OPAQUE_DOUBLE +#endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ + ) && (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + if (snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "Wrong Type (should be Opaque): ")) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + switch (var->type) { + case ASN_OPAQUE_COUNTER64: + case ASN_OPAQUE_U64: + case ASN_OPAQUE_I64: + return sprint_realloc_counter64(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + break; + + case ASN_OPAQUE_FLOAT: + return sprint_realloc_float(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + break; + + case ASN_OPAQUE_DOUBLE: + return sprint_realloc_double(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + break; + + case ASN_OPAQUE: +#endif + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "OPAQUE: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc, + var->val.string, var->val_len)) { + return 0; + } +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + } +#endif + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints an object identifier into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + int buf_overflow = 0; + + if ((var->type != ASN_OBJECT_ID) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = + "Wrong Type (should be OBJECT IDENTIFIER): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "OID: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + + netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len, allow_realloc, + &buf_overflow, + (oid *) (var->val.objid), + var->val_len / sizeof(oid)); + + if (buf_overflow) { + return 0; + } + + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + + +/** + * Prints a timetick variable into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char timebuf[40]; + + if ((var->type != ASN_TIMETICKS) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be Timeticks): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS)) { + char str[32]; + sprintf(str, "%lu", *(u_long *) var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) { + return 0; + } + return 1; + } + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + char str[32]; + sprintf(str, "Timeticks: (%lu) ", *(u_long *) var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) { + return 0; + } + } + uptimeString(*(u_long *) (var->val.integer), timebuf, sizeof(timebuf)); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) timebuf)) { + return 0; + } + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints an integer according to the hint into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param val The variable to encode. + * @param decimaltype The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may _NOT_ be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char fmt[10] = "%l@", tmp[256]; + int shift, len; + + if (hint[1] == '-') { + shift = atoi(hint + 2); + } else { + shift = 0; + } + + if (hint[0] == 'd') { + /* + * We might *actually* want a 'u' here. + */ + fmt[2] = decimaltype; + } else { + /* + * DISPLAY-HINT character is 'b', 'o', or 'x'. + */ + fmt[2] = hint[0]; + } + + sprintf(tmp, fmt, val); + if (shift != 0) { + len = strlen(tmp); + if (shift <= len) { + tmp[len + 1] = 0; + while (shift--) { + tmp[len] = tmp[len - 1]; + len--; + } + tmp[len] = '.'; + } else { + tmp[shift + 1] = 0; + while (shift) { + if (len-- > 0) { + tmp[shift] = tmp[len]; + } else { + tmp[shift] = '0'; + } + shift--; + } + tmp[0] = '.'; + } + } + return snmp_strcat(buf, buf_len, out_len, allow_realloc, (u_char *)tmp); +} + + +/** + * Prints an integer into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char *enum_string = NULL; + + if ((var->type != ASN_INTEGER) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be INTEGER): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + for (; enums; enums = enums->next) { + if (enums->value == *var->val.integer) { + enum_string = enums->label; + break; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) "INTEGER: ")) { + return 0; + } + } + + if (enum_string == NULL || + netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) { + if (hint) { + if (!(sprint_realloc_hinted_integer(buf, buf_len, out_len, + allow_realloc, + *var->val.integer, 'd', + hint, units))) { + return 0; + } + } else { + char str[32]; + sprintf(str, "%ld", *var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) str)) { + return 0; + } + } + } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) enum_string)) { + return 0; + } + } else { + char str[32]; + sprintf(str, "(%ld)", *var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) enum_string)) { + return 0; + } + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) { + return 0; + } + } + + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints an unsigned integer into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char *enum_string = NULL; + + if ((var->type != ASN_UINTEGER) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be UInteger32): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + for (; enums; enums = enums->next) { + if (enums->value == *var->val.integer) { + enum_string = enums->label; + break; + } + } + + if (enum_string == NULL || + netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) { + if (hint) { + if (!(sprint_realloc_hinted_integer(buf, buf_len, out_len, + allow_realloc, + *var->val.integer, 'u', + hint, units))) { + return 0; + } + } else { + char str[32]; + sprintf(str, "%lu", *var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) str)) { + return 0; + } + } + } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) enum_string)) { + return 0; + } + } else { + char str[32]; + sprintf(str, "(%lu)", *var->val.integer); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) enum_string)) { + return 0; + } + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) str)) { + return 0; + } + } + + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints a gauge value into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char tmp[32]; + + if ((var->type != ASN_GAUGE) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = + "Wrong Type (should be Gauge32 or Unsigned32): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "Gauge32: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + if (hint) { + if (!sprint_realloc_hinted_integer(buf, buf_len, out_len, + allow_realloc, + *var->val.integer, 'u', hint, + units)) { + return 0; + } + } else { + sprintf(tmp, "%u", (unsigned int)(*var->val.integer & 0xffffffff)); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) tmp)) { + return 0; + } + } + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints a counter value into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + char tmp[32]; + + if ((var->type != ASN_COUNTER) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be Counter32): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "Counter32: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + sprintf(tmp, "%u", (unsigned int)(*var->val.integer & 0xffffffff)); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, (const u_char *) tmp)) { + return 0; + } + if (units) { + return (snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ") + && snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) units)); + } + return 1; +} + + +/** + * Prints a network address into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + size_t i; + + if ((var->type != ASN_IPADDRESS) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be NetworkAddress): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "Network Address: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + + while ((*out_len + (var->val_len * 3) + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + + for (i = 0; i < var->val_len; i++) { + sprintf((char *) (*buf + *out_len), "%02X", var->val.string[i]); + *out_len += 2; + if (i < var->val_len - 1) { + *(*buf + *out_len) = ':'; + (*out_len)++; + } + } + return 1; +} + + +/** + * Prints an ip-address into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + u_char *ip = var->val.string; + + if ((var->type != ASN_IPADDRESS) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be IpAddress): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "IpAddress: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + while ((*out_len + 17) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + if (ip) + sprintf((char *) (*buf + *out_len), "%d.%d.%d.%d", + ip[0], ip[1], ip[2], ip[3]); + *out_len += strlen((char *) (*buf + *out_len)); + return 1; +} + + +/** + * Prints a null value into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + if ((var->type != ASN_NULL) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be NULL): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } else { + u_char str[] = "NULL"; + return snmp_strcat(buf, buf_len, out_len, allow_realloc, str); + } +} + + +/** + * Prints a bit string into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + int len, bit; + u_char *cp; + char *enum_string; + + if ((var->type != ASN_BIT_STR && var->type != ASN_OCTET_STR) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be BITS): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "\""; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } else { + u_char str[] = "BITS: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + if (!sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc, + var->val.bitstring, var->val_len)) { + return 0; + } + + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "\""; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } else { + cp = var->val.bitstring; + for (len = 0; len < (int) var->val_len; len++) { + for (bit = 0; bit < 8; bit++) { + if (*cp & (0x80 >> bit)) { + enum_string = NULL; + for (; enums; enums = enums->next) { + if (enums->value == (len * 8) + bit) { + enum_string = enums->label; + break; + } + } + if (enum_string == NULL || + netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM)) { + char str[32]; + sprintf(str, "%d ", (len * 8) + bit); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) str)) { + return 0; + } + } else { + char str[32]; + sprintf(str, "(%d) ", (len * 8) + bit); + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) enum_string)) { + return 0; + } + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) str)) { + return 0; + } + } + } + } + cp++; + } + } + return 1; +} + +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) +{ + if ((var->type != ASN_NSAP) && + (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT))) { + u_char str[] = "Wrong Type (should be NsapAddress): "; + if (snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, var, NULL, NULL, + NULL); + } else { + return 0; + } + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + u_char str[] = "NsapAddress: "; + if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, str)) { + return 0; + } + } + + return sprint_realloc_hexstring(buf, buf_len, out_len, allow_realloc, + var->val.string, var->val_len); +} + + +/** + * Fallback routine for a bad type, prints "Variable has bad type" into a buffer. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + u_char str[] = "Variable has bad type"; + + return snmp_strcat(buf, buf_len, out_len, allow_realloc, str); +} + + + +/** + * Universal print routine, prints a variable into a buffer according to the variable + * type. + * + * If allow_realloc is true the buffer will be (re)allocated to fit in the + * needed size. (Note: *buf may change due to this.) + * + * @param buf Address of the buffer to print to. + * @param buf_len Address to an integer containing the size of buf. + * @param out_len Incremented by the number of characters printed. + * @param allow_realloc if not zero reallocate the buffer to fit the + * needed size. + * @param var The variable to encode. + * @param enums The enumeration ff this variable is enumerated. may be NULL. + * @param hint Contents of the DISPLAY-HINT clause of the MIB. + * See RFC 1903 Section 3.1 for details. may be NULL. + * @param units Contents of the UNITS clause of the MIB. may be NULL. + * + * @return 1 on success, or 0 on failure (out of memory, or buffer to + * small when not allowed to realloc.) + */ +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) +{ + DEBUGMSGTL(("output", "sprint_by_type, type %d\n", var->type)); + + switch (var->type) { + case ASN_INTEGER: + return sprint_realloc_integer(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_OCTET_STR: + return sprint_realloc_octet_string(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + case ASN_BIT_STR: + return sprint_realloc_bitstring(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + case ASN_OPAQUE: + return sprint_realloc_opaque(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_OBJECT_ID: + return sprint_realloc_object_identifier(buf, buf_len, out_len, + allow_realloc, var, enums, + hint, units); + case ASN_TIMETICKS: + return sprint_realloc_timeticks(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + case ASN_GAUGE: + return sprint_realloc_gauge(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_COUNTER: + return sprint_realloc_counter(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_IPADDRESS: + return sprint_realloc_ipaddress(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + case ASN_NULL: + return sprint_realloc_null(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_UINTEGER: + return sprint_realloc_uinteger(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); + case ASN_COUNTER64: +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_U64: + case ASN_OPAQUE_I64: + case ASN_OPAQUE_COUNTER64: +#endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ + return sprint_realloc_counter64(buf, buf_len, out_len, + allow_realloc, var, enums, hint, + units); +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES + case ASN_OPAQUE_FLOAT: + return sprint_realloc_float(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + case ASN_OPAQUE_DOUBLE: + return sprint_realloc_double(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); +#endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */ + default: + DEBUGMSGTL(("sprint_by_type", "bad type: %d\n", var->type)); + return sprint_realloc_badtype(buf, buf_len, out_len, allow_realloc, + var, enums, hint, units); + } +} + + +#ifndef NETSNMP_DISABLE_MIB_LOADING +/** + * Retrieves the tree head. + * + * @return the tree head. + */ +struct tree * +get_tree_head(void) +{ + return (tree_head); +} + +static char *confmibdir = NULL; +static char *confmibs = NULL; + +static void +handle_mibdirs_conf(const char *token, char *line) +{ + char *ctmp; + + if (confmibdir) { + if ((*line == '+') || (*line == '-')) { + ctmp = (char *) malloc(strlen(confmibdir) + strlen(line) + 2); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", + "mibdir conf malloc failed")); + return; + } + if(*line++ == '+') + sprintf(ctmp, "%s%c%s", confmibdir, ENV_SEPARATOR_CHAR, line); + else + sprintf(ctmp, "%s%c%s", line, ENV_SEPARATOR_CHAR, confmibdir); + } else { + ctmp = strdup(line); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed")); + return; + } + } + SNMP_FREE(confmibdir); + } else { + ctmp = strdup(line); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed")); + return; + } + } + confmibdir = ctmp; + DEBUGMSGTL(("read_config:initmib", "using mibdirs: %s\n", confmibdir)); +} + +static void +handle_mibs_conf(const char *token, char *line) +{ + char *ctmp; + + if (confmibs) { + if ((*line == '+') || (*line == '-')) { + ctmp = (char *) malloc(strlen(confmibs) + strlen(line) + 2); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed")); + return; + } + if(*line++ == '+') + sprintf(ctmp, "%s%c%s", confmibs, ENV_SEPARATOR_CHAR, line); + else + sprintf(ctmp, "%s%c%s", line, ENV_SEPARATOR_CHAR, confmibdir); + } else { + ctmp = strdup(line); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed")); + return; + } + } + SNMP_FREE(confmibs); + } else { + ctmp = strdup(line); + if (!ctmp) { + DEBUGMSGTL(("read_config:initmib", "mibs conf malloc failed")); + return; + } + } + confmibs = ctmp; + DEBUGMSGTL(("read_config:initmib", "using mibs: %s\n", confmibs)); +} + + +static void +handle_mibfile_conf(const char *token, char *line) +{ + DEBUGMSGTL(("read_config:initmib", "reading mibfile: %s\n", line)); + read_mib(line); +} +#endif + +static void +handle_print_numeric(const char *token, char *line) +{ + const char *value; + char *st; + + value = strtok_r(line, " \t\n", &st); + if (value && ( + (strcasecmp(value, "yes") == 0) || + (strcasecmp(value, "true") == 0) || + (*value == '1') )) { + + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + } +} + +char * +snmp_out_toggle_options(char *options) +{ + while (*options) { + switch (*options++) { + case '0': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT); + break; + case 'a': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT, + NETSNMP_STRING_OUTPUT_ASCII); + break; + case 'b': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS); + break; + case 'e': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM); + break; + case 'E': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES); + break; + case 'f': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_FULL); + break; + case 'n': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_NUMERIC); + break; + case 'q': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT); + break; + case 'Q': + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT, 1); + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT); + break; + case 's': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_SUFFIX); + break; + case 'S': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_MODULE); + break; + case 't': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS); + break; + case 'T': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT); + break; + case 'u': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, + NETSNMP_OID_OUTPUT_UCD); + break; + case 'U': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS); + break; + case 'v': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE); + break; + case 'x': + netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT, + NETSNMP_STRING_OUTPUT_HEX); + break; + case 'X': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX); + break; + default: + return options - 1; + } + } + return NULL; +} + +void +snmp_out_toggle_options_usage(const char *lead, FILE * outf) +{ + fprintf(outf, "%s0: print leading 0 for single-digit hex characters\n", lead); + fprintf(outf, "%sa: print all strings in ascii format\n", lead); + fprintf(outf, "%sb: do not break OID indexes down\n", lead); + fprintf(outf, "%se: print enums numerically\n", lead); + fprintf(outf, "%sE: escape quotes in string indices\n", lead); + fprintf(outf, "%sf: print full OIDs on output\n", lead); + fprintf(outf, "%sn: print OIDs numerically\n", lead); + fprintf(outf, "%sq: quick print for easier parsing\n", lead); + fprintf(outf, "%sQ: quick print with equal-signs\n", lead); /* @@JDW */ + fprintf(outf, "%ss: print only last symbolic element of OID\n", lead); + fprintf(outf, "%sS: print MIB module-id plus last element\n", lead); + fprintf(outf, "%st: print timeticks unparsed as numeric integers\n", + lead); + fprintf(outf, + "%sT: print human-readable text along with hex strings\n", + lead); + fprintf(outf, "%su: print OIDs using UCD-style prefix suppression\n", + lead); + fprintf(outf, "%sU: don't print units\n", lead); + fprintf(outf, "%sv: print values only (not OID = value)\n", lead); + fprintf(outf, "%sx: print all strings in hex format\n", lead); + fprintf(outf, "%sX: extended index format\n", lead); +} + +char * +snmp_in_options(char *optarg, int argc, char *const *argv) +{ + char *cp; + + for (cp = optarg; *cp; cp++) { + switch (*cp) { + case 'b': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REGEX_ACCESS); + break; + case 'R': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RANDOM_ACCESS); + break; + case 'r': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE); + break; + case 'h': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT); + break; + case 'u': + netsnmp_ds_toggle_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_READ_UCD_STYLE_OID); + break; + case 's': + /* What if argc/argv are null ? */ + if (!*(++cp)) + cp = argv[optind++]; + netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OIDSUFFIX, + cp); + return NULL; + + case 'S': + /* What if argc/argv are null ? */ + if (!*(++cp)) + cp = argv[optind++]; + netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OIDPREFIX, + cp); + return NULL; + + default: + /* + * Here? Or in snmp_parse_args? + snmp_log(LOG_ERR, "Unknown input option passed to -I: %c.\n", *cp); + */ + return cp; + } + } + return NULL; +} + +char * +snmp_in_toggle_options(char *options) +{ + return snmp_in_options( options, 0, NULL ); +} + + +/** + * Prints out a help usage for the in* toggle options. + * + * @param lead The lead to print for every line. + * @param outf The file descriptor to write to. + * + */ +void +snmp_in_toggle_options_usage(const char *lead, FILE * outf) +{ + fprintf(outf, "%sb: do best/regex matching to find a MIB node\n", lead); + fprintf(outf, "%sh: don't apply DISPLAY-HINTs\n", lead); + fprintf(outf, "%sr: do not check values for range/type legality\n", lead); + fprintf(outf, "%sR: do random access to OID labels\n", lead); + fprintf(outf, + "%su: top-level OIDs must have '.' prefix (UCD-style)\n", lead); + fprintf(outf, + "%ss SUFFIX: Append all textual OIDs with SUFFIX before parsing\n", + lead); + fprintf(outf, + "%sS PREFIX: Prepend all textual OIDs with PREFIX before parsing\n", + lead); +} + +/*** + * + */ +void +register_mib_handlers(void) +{ +#ifndef NETSNMP_DISABLE_MIB_LOADING + register_prenetsnmp_mib_handler("snmp", "mibdirs", + handle_mibdirs_conf, NULL, + "[mib-dirs|+mib-dirs|-mib-dirs]"); + register_prenetsnmp_mib_handler("snmp", "mibs", + handle_mibs_conf, NULL, + "[mib-tokens|+mib-tokens]"); + register_config_handler("snmp", "mibfile", + handle_mibfile_conf, NULL, "mibfile-to-read"); + /* + * register the snmp.conf configuration handlers for default + * parsing behaviour + */ + + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "showMibErrors", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_ERRORS); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "commentToEOL", /* Describes actual behaviour */ + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_COMMENT_TERM); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "strictCommentTerm", /* Backward compatibility */ + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_COMMENT_TERM); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "mibAllowUnderline", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_PARSE_LABEL); + netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "mibWarningLevel", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_WARNINGS); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "mibReplaceWithLatest", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIB_REPLACE); +#endif + + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printNumericEnums", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM); + register_prenetsnmp_mib_handler("snmp", "printNumericOids", + handle_print_numeric, NULL, "(1|yes|true|0|no|false)"); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "escapeQuotes", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "dontBreakdownOids", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "quickPrinting", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "numericTimeticks", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS); + netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "oidOutputFormat", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "suffixPrinting", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "extendedIndex", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printHexText", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_HEX_TEXT); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "printValueOnly", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE); + netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "dontPrintUnits", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS); + netsnmp_ds_register_premib(ASN_INTEGER, "snmp", "hexOutputLength", + NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH); +} + +#ifndef NETSNMP_DISABLE_MIB_LOADING +/* + * function : netsnmp_set_mib_directory + * - This function sets the string of the directories + * from which the MIB modules will be searched or + * loaded. + * arguments: const char *dir, which are the directories + * from which the MIB modules will be searched or + * loaded. + * returns : - + */ +void +netsnmp_set_mib_directory(const char *dir) +{ + const char *newdir; + char *olddir, *tmpdir = NULL; + + DEBUGTRACE; + if (NULL == dir) { + return; + } + + olddir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_MIBDIRS); + if (olddir) { + if ((*dir == '+') || (*dir == '-')) { + /** New dir starts with '+', thus we add it. */ + tmpdir = (char *)malloc(strlen(dir) + strlen(olddir) + 2); + if (!tmpdir) { + DEBUGMSGTL(("read_config:initmib", "set mibdir malloc failed")); + return; + } + if (*dir++ == '+') + sprintf(tmpdir, "%s%c%s", olddir, ENV_SEPARATOR_CHAR, dir); + else + sprintf(tmpdir, "%s%c%s", dir, ENV_SEPARATOR_CHAR, olddir); + newdir = tmpdir; + } else { + newdir = dir; + } + } else { + /** If dir starts with '+' skip '+' it. */ + newdir = ((*dir == '+') ? ++dir : dir); + } + netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS, + newdir); + + /** set_string calls strdup, so if we allocated memory, free it */ + if (tmpdir == newdir) { + SNMP_FREE(tmpdir); + } +} + +/* + * function : netsnmp_get_mib_directory + * - This function returns a string of the directories + * from which the MIB modules will be searched or + * loaded. + * If the value still does not exists, it will be made + * from the evironment variable 'MIBDIRS' and/or the + * default. + * arguments: - + * returns : char * of the directories in which the MIB modules + * will be searched/loaded. + */ + +char * +netsnmp_get_mib_directory(void) +{ + char *dir; + + DEBUGTRACE; + dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS); + if (dir == NULL) { + DEBUGMSGTL(("get_mib_directory", "no mib directories set\n")); + + /** Check if the environment variable is set */ + dir = netsnmp_getenv("MIBDIRS"); + if (dir == NULL) { + DEBUGMSGTL(("get_mib_directory", "no mib directories set by environment\n")); + /** Not set use hard coded path */ + if (confmibdir == NULL) { + DEBUGMSGTL(("get_mib_directory", "no mib directories set by config\n")); + netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS); + } + else if ((*confmibdir == '+') || (*confmibdir == '-')) { + DEBUGMSGTL(("get_mib_directory", "mib directories set by config (but added)\n")); + netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS); + netsnmp_set_mib_directory(confmibdir); + } + else { + DEBUGMSGTL(("get_mib_directory", "mib directories set by config\n")); + netsnmp_set_mib_directory(confmibdir); + } + } else if ((*dir == '+') || (*dir == '-')) { + DEBUGMSGTL(("get_mib_directory", "mib directories set by environment (but added)\n")); + netsnmp_set_mib_directory(NETSNMP_DEFAULT_MIBDIRS); + netsnmp_set_mib_directory(dir); + } else { + DEBUGMSGTL(("get_mib_directory", "mib directories set by environment\n")); + netsnmp_set_mib_directory(dir); + } + dir = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS); + } + DEBUGMSGTL(("get_mib_directory", "mib directories set '%s'\n", dir)); + return(dir); +} + +/* + * function : netsnmp_fixup_mib_directory + * arguments: - + * returns : - + */ +void +netsnmp_fixup_mib_directory(void) +{ + char *homepath = netsnmp_getenv("HOME"); + char *mibpath = netsnmp_get_mib_directory(); + char *oldmibpath = NULL; + char *ptr_home; + char *new_mibpath; + + DEBUGTRACE; + if (homepath && mibpath) { + DEBUGMSGTL(("fixup_mib_directory", "mib directories '%s'\n", mibpath)); + while ((ptr_home = strstr(mibpath, "$HOME"))) { + new_mibpath = (char *)malloc(strlen(mibpath) - strlen("$HOME") + + strlen(homepath)+1); + if (new_mibpath) { + *ptr_home = 0; /* null out the spot where we stop copying */ + sprintf(new_mibpath, "%s%s%s", mibpath, homepath, + ptr_home + strlen("$HOME")); + /** swap in the new value and repeat */ + mibpath = new_mibpath; + if (oldmibpath != NULL) { + SNMP_FREE(oldmibpath); + } + oldmibpath = new_mibpath; + } else { + break; + } + } + + netsnmp_set_mib_directory(mibpath); + + /* The above copies the mibpath for us, so... */ + + if (oldmibpath != NULL) { + SNMP_FREE(oldmibpath); + } + + } + +} + +/** + * Initialises the mib reader. + * + * Reads in all settings from the environment. + */ +void +netsnmp_init_mib(void) +{ + const char *prefix; + char *env_var, *entry; + PrefixListPtr pp = &mib_prefixes[0]; + char *st = NULL; + + if (Mib) + return; + netsnmp_init_mib_internals(); + + /* + * Initialise the MIB directory/ies + */ + netsnmp_fixup_mib_directory(); + env_var = strdup(netsnmp_get_mib_directory()); + netsnmp_mibindex_load(); + + DEBUGMSGTL(("init_mib", + "Seen MIBDIRS: Looking in '%s' for mib dirs ...\n", + env_var)); + + entry = strtok_r(env_var, ENV_SEPARATOR, &st); + while (entry) { + add_mibdir(entry); + entry = strtok_r(NULL, ENV_SEPARATOR, &st); + } + SNMP_FREE(env_var); + + env_var = netsnmp_getenv("MIBFILES"); + if (env_var != NULL) { + if (*env_var == '+') + entry = strtok_r(env_var+1, ENV_SEPARATOR, &st); + else + entry = strtok_r(env_var, ENV_SEPARATOR, &st); + while (entry) { + add_mibfile(entry, NULL, NULL); + entry = strtok_r(NULL, ENV_SEPARATOR, &st); + } + } + + netsnmp_init_mib_internals(); + + /* + * Read in any modules or mibs requested + */ + + env_var = netsnmp_getenv("MIBS"); + if (env_var == NULL) { + if (confmibs != NULL) + env_var = strdup(confmibs); + else + env_var = strdup(NETSNMP_DEFAULT_MIBS); + } else { + env_var = strdup(env_var); + } + if (env_var && ((*env_var == '+') || (*env_var == '-'))) { + entry = + (char *) malloc(strlen(NETSNMP_DEFAULT_MIBS) + strlen(env_var) + 2); + if (!entry) { + DEBUGMSGTL(("init_mib", "env mibs malloc failed")); + SNMP_FREE(env_var); + return; + } else { + if (*env_var == '+') + sprintf(entry, "%s%c%s", NETSNMP_DEFAULT_MIBS, ENV_SEPARATOR_CHAR, + env_var+1); + else + sprintf(entry, "%s%c%s", env_var+1, ENV_SEPARATOR_CHAR, + NETSNMP_DEFAULT_MIBS ); + } + SNMP_FREE(env_var); + env_var = entry; + } + + DEBUGMSGTL(("init_mib", + "Seen MIBS: Looking in '%s' for mib files ...\n", + env_var)); + entry = strtok_r(env_var, ENV_SEPARATOR, &st); + while (entry) { + if (strcasecmp(entry, DEBUG_ALWAYS_TOKEN) == 0) { + read_all_mibs(); + } else if (strstr(entry, "/") != NULL) { + read_mib(entry); + } else { + netsnmp_read_module(entry); + } + entry = strtok_r(NULL, ENV_SEPARATOR, &st); + } + adopt_orphans(); + SNMP_FREE(env_var); + + env_var = netsnmp_getenv("MIBFILES"); + if (env_var != NULL) { + if ((*env_var == '+') || (*env_var == '-')) { +#ifdef NETSNMP_DEFAULT_MIBFILES + entry = + (char *) malloc(strlen(NETSNMP_DEFAULT_MIBFILES) + + strlen(env_var) + 2); + if (!entry) { + DEBUGMSGTL(("init_mib", "env mibfiles malloc failed")); + } else { + if (*env_var++ == '+') + sprintf(entry, "%s%c%s", NETSNMP_DEFAULT_MIBFILES, ENV_SEPARATOR_CHAR, + env_var ); + else + sprintf(entry, "%s%c%s", env_var, ENV_SEPARATOR_CHAR, + NETSNMP_DEFAULT_MIBFILES ); + } + SNMP_FREE(env_var); + env_var = entry; +#else + env_var = strdup(env_var + 1); +#endif + } else { + env_var = strdup(env_var); + } + } else { +#ifdef NETSNMP_DEFAULT_MIBFILES + env_var = strdup(NETSNMP_DEFAULT_MIBFILES); +#endif + } + + if (env_var != NULL) { + DEBUGMSGTL(("init_mib", + "Seen MIBFILES: Looking in '%s' for mib files ...\n", + env_var)); + entry = strtok_r(env_var, ENV_SEPARATOR, &st); + while (entry) { + read_mib(entry); + entry = strtok_r(NULL, ENV_SEPARATOR, &st); + } + SNMP_FREE(env_var); + } + + prefix = netsnmp_getenv("PREFIX"); + + if (!prefix) + prefix = Standard_Prefix; + + Prefix = (char *) malloc(strlen(prefix) + 2); + if (!Prefix) + DEBUGMSGTL(("init_mib", "Prefix malloc failed")); + else + strcpy(Prefix, prefix); + + DEBUGMSGTL(("init_mib", + "Seen PREFIX: Looking in '%s' for prefix ...\n", Prefix)); + + /* + * remove trailing dot + */ + if (Prefix) { + env_var = &Prefix[strlen(Prefix) - 1]; + if (*env_var == '.') + *env_var = '\0'; + } + + pp->str = Prefix; /* fixup first mib_prefix entry */ + /* + * now that the list of prefixes is built, save each string length. + */ + while (pp->str) { + pp->len = strlen(pp->str); + pp++; + } + + Mib = tree_head; /* Backwards compatibility */ + tree_top = (struct tree *) calloc(1, sizeof(struct tree)); + /* + * XX error check ? + */ + if (tree_top) { + tree_top->label = strdup("(top)"); + tree_top->child_list = tree_head; + } +} + +#ifndef NETSNMP_NO_LEGACY_DEFINITIONS +void +init_mib(void) +{ + netsnmp_init_mib(); +} +#endif + + +/* + * Handle MIB indexes centrally + */ +static int _mibindex = 0; /* Last index in use */ +static int _mibindex_max = 0; /* Size of index array */ +char **_mibindexes = NULL; + +int _mibindex_add( const char *dirname, int i ); +void +netsnmp_mibindex_load( void ) +{ + DIR *dir; + struct dirent *file; + FILE *fp; + char tmpbuf[ 300]; + char tmpbuf2[300]; + int i; + char *cp; + + /* + * Open the MIB index directory, or create it (empty) + */ + snprintf( tmpbuf, sizeof(tmpbuf), "%s/mib_indexes", + get_persistent_directory()); + tmpbuf[sizeof(tmpbuf)-1] = 0; + dir = opendir( tmpbuf ); + if ( dir == NULL ) { + DEBUGMSGTL(("mibindex", "load: (new)\n")); + mkdirhier( tmpbuf, NETSNMP_AGENT_DIRECTORY_MODE, 0); + return; + } + + /* + * Create a list of which directory each file refers to + */ + while ((file = readdir( dir ))) { + if ( !isdigit((unsigned char)(file->d_name[0]))) + continue; + i = atoi( file->d_name ); + + snprintf( tmpbuf, sizeof(tmpbuf), "%s/mib_indexes/%d", + get_persistent_directory(), i ); + tmpbuf[sizeof(tmpbuf)-1] = 0; + fp = fopen( tmpbuf, "r" ); + if (!fp) + continue; + cp = fgets( tmpbuf2, sizeof(tmpbuf2), fp ); + if ( !cp ) { + DEBUGMSGTL(("mibindex", "Empty MIB index (%d)\n", i)); + fclose(fp); + continue; + } + tmpbuf2[strlen(tmpbuf2)-1] = 0; + DEBUGMSGTL(("mibindex", "load: (%d) %s\n", i, tmpbuf2)); + (void)_mibindex_add( tmpbuf2+4, i ); /* Skip 'DIR ' */ + fclose( fp ); + } + closedir( dir ); +} + +char * +netsnmp_mibindex_lookup( const char *dirname ) +{ + int i; + static char tmpbuf[300]; + + for (i=0; i<_mibindex; i++) { + if ( _mibindexes[i] && + strcmp( _mibindexes[i], dirname ) == 0) { + snprintf(tmpbuf, sizeof(tmpbuf), "%s/mib_indexes/%d", + get_persistent_directory(), i); + tmpbuf[sizeof(tmpbuf)-1] = 0; + DEBUGMSGTL(("mibindex", "lookup: %s (%d) %s\n", dirname, i, tmpbuf )); + return tmpbuf; + } + } + DEBUGMSGTL(("mibindex", "lookup: (none)\n")); + return NULL; +} + +int +_mibindex_add( const char *dirname, int i ) +{ + const int old_mibindex = _mibindex; + + DEBUGMSGTL(("mibindex", "add: %s (%d)\n", dirname, i )); + if ( i == -1 ) + i = _mibindex++; + if ( i >= _mibindex_max ) { + /* + * If the index array is full (or non-existent) + * then expand (or create) it + */ + _mibindex_max = i + 10; + _mibindexes = realloc(_mibindexes, + _mibindex_max * sizeof(_mibindexes[0])); + netsnmp_assert(_mibindexes); + memset(_mibindexes + old_mibindex, 0, + (i - old_mibindex) * sizeof(_mibindexes[0])); + } + DEBUGMSGTL(("mibindex", "add: %d/%d/%d\n", i, _mibindex, _mibindex_max )); + + _mibindexes[ i ] = strdup( dirname ); + if ( i >= _mibindex ) + _mibindex = i+1; + + return i; +} + +FILE * +netsnmp_mibindex_new( const char *dirname ) +{ + FILE *fp; + char tmpbuf[300]; + char *cp; + int i; + + cp = netsnmp_mibindex_lookup( dirname ); + if (!cp) { + i = _mibindex_add( dirname, -1 ); + snprintf( tmpbuf, sizeof(tmpbuf), "%s/mib_indexes/%d", + get_persistent_directory(), i ); + tmpbuf[sizeof(tmpbuf)-1] = 0; + cp = tmpbuf; + } + DEBUGMSGTL(("mibindex", "new: %s (%s)\n", dirname, cp )); + fp = fopen( cp, "w" ); + if (fp) + fprintf( fp, "DIR %s\n", dirname ); + return fp; +} + + +/** + * Unloads all mibs. + */ +void +shutdown_mib(void) +{ + unload_all_mibs(); + if (tree_top) { + if (tree_top->label) + SNMP_FREE(tree_top->label); + SNMP_FREE(tree_top); + } + tree_head = NULL; + Mib = NULL; + if (_mibindexes) { + int i; + for (i = 0; i < _mibindex; ++i) + SNMP_FREE(_mibindexes[i]); + free(_mibindexes); + _mibindex = 0; + _mibindex_max = 0; + _mibindexes = NULL; + } + if (Prefix != NULL && Prefix != &Standard_Prefix[0]) + SNMP_FREE(Prefix); + if (Prefix) + Prefix = NULL; + SNMP_FREE(confmibs); + SNMP_FREE(confmibdir); +} + +/** + * Prints the MIBs to the file fp. + * + * @param fp The file descriptor to print to. + */ +#ifndef NETSNMP_FEATURE_REMOVE_PRINT_MIB +void +print_mib(FILE * fp) +{ + print_subtree(fp, tree_head, 0); +} +#endif /* NETSNMP_FEATURE_REMOVE_PRINT_MIB */ + +void +print_ascii_dump(FILE * fp) +{ + fprintf(fp, "dump DEFINITIONS ::= BEGIN\n"); + print_ascii_dump_tree(fp, tree_head, 0); + fprintf(fp, "END\n"); +} + + +/** + * Set's the printing function printomat in a subtree according + * it's type + * + * @param subtree The subtree to set. + */ +void +set_function(struct tree *subtree) +{ + subtree->printer = NULL; + switch (subtree->type) { + case TYPE_OBJID: + subtree->printomat = sprint_realloc_object_identifier; + break; + case TYPE_OCTETSTR: + subtree->printomat = sprint_realloc_octet_string; + break; + case TYPE_INTEGER: + subtree->printomat = sprint_realloc_integer; + break; + case TYPE_INTEGER32: + subtree->printomat = sprint_realloc_integer; + break; + case TYPE_NETADDR: + subtree->printomat = sprint_realloc_networkaddress; + break; + case TYPE_IPADDR: + subtree->printomat = sprint_realloc_ipaddress; + break; + case TYPE_COUNTER: + subtree->printomat = sprint_realloc_counter; + break; + case TYPE_GAUGE: + subtree->printomat = sprint_realloc_gauge; + break; + case TYPE_TIMETICKS: + subtree->printomat = sprint_realloc_timeticks; + break; + case TYPE_OPAQUE: + subtree->printomat = sprint_realloc_opaque; + break; + case TYPE_NULL: + subtree->printomat = sprint_realloc_null; + break; + case TYPE_BITSTRING: + subtree->printomat = sprint_realloc_bitstring; + break; + case TYPE_NSAPADDRESS: + subtree->printomat = sprint_realloc_nsapaddress; + break; + case TYPE_COUNTER64: + subtree->printomat = sprint_realloc_counter64; + break; + case TYPE_UINTEGER: + subtree->printomat = sprint_realloc_uinteger; + break; + case TYPE_UNSIGNED32: + subtree->printomat = sprint_realloc_gauge; + break; + case TYPE_OTHER: + default: + subtree->printomat = sprint_realloc_by_type; + break; + } +} + +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +/** + * Reads an object identifier from an input string into internal OID form. + * + * When called, out_len must hold the maximum length of the output array. + * + * @param input the input string. + * @param output the oid wirte. + * @param out_len number of subid's in output. + * + * @return 1 if successful. + * + * If an error occurs, this function returns 0 and MAY set snmp_errno. + * snmp_errno is NOT set if SET_SNMP_ERROR evaluates to nothing. + * This can make multi-threaded use a tiny bit more robust. + */ +int +read_objid(const char *input, oid * output, size_t * out_len) +{ /* number of subid's in "output" */ +#ifndef NETSNMP_DISABLE_MIB_LOADING + struct tree *root = tree_top; +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + char buf[SPRINT_MAX_LEN]; + int ret, max_out_len; + char *name, ch; + const char *cp; + + cp = input; + while ((ch = *cp)) { + if (('0' <= ch && ch <= '9') + || ('a' <= ch && ch <= 'z') + || ('A' <= ch && ch <= 'Z') + || ch == '-') + cp++; + else + break; + } +#ifndef NETSNMP_DISABLE_MIB_LOADING + if (ch == ':') + return get_node(input, output, out_len); +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + + if (*input == '.') + input++; +#ifndef NETSNMP_DISABLE_MIB_LOADING + else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_READ_UCD_STYLE_OID)) { + /* + * get past leading '.', append '.' to Prefix. + */ + if (*Prefix == '.') + strlcpy(buf, Prefix + 1, sizeof(buf)); + else + strlcpy(buf, Prefix, sizeof(buf)); + strlcat(buf, ".", sizeof(buf)); + strlcat(buf, input, sizeof(buf)); + input = buf; + } +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +#ifndef NETSNMP_DISABLE_MIB_LOADING + if ((root == NULL) && (tree_head != NULL)) { + root = tree_head; + } + else if (root == NULL) { + SET_SNMP_ERROR(SNMPERR_NOMIB); + *out_len = 0; + return 0; + } +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + name = strdup(input); + max_out_len = *out_len; + *out_len = 0; +#ifndef NETSNMP_DISABLE_MIB_LOADING + if ((ret = + _add_strings_to_oid(root, name, output, out_len, + max_out_len)) <= 0) +#else + if ((ret = + _add_strings_to_oid(NULL, name, output, out_len, + max_out_len)) <= 0) +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + { + if (ret == 0) + ret = SNMPERR_UNKNOWN_OBJID; + SET_SNMP_ERROR(ret); + SNMP_FREE(name); + return 0; + } + SNMP_FREE(name); + + return 1; +} + +/** + * + */ +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) +{ + u_char *tbuf = NULL, *cp = NULL; + size_t tbuf_len = 256, tout_len = 0; + int tbuf_overflow = 0; + int output_format; + + if ((tbuf = (u_char *) calloc(tbuf_len, 1)) == NULL) { + tbuf_overflow = 1; + } else { + *tbuf = '.'; + tout_len = 1; + } + + _oid_finish_printing(objid, objidlen, + &tbuf, &tbuf_len, &tout_len, + allow_realloc, &tbuf_overflow); + + if (tbuf_overflow) { + if (!*buf_overflow) { + snmp_strcat(buf, buf_len, out_len, allow_realloc, tbuf); + *buf_overflow = 1; + } + SNMP_FREE(tbuf); + return; + } + + output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + if (0 == output_format) { + output_format = NETSNMP_OID_OUTPUT_NUMERIC; + } + switch (output_format) { + case NETSNMP_OID_OUTPUT_FULL: + case NETSNMP_OID_OUTPUT_NUMERIC: + case NETSNMP_OID_OUTPUT_SUFFIX: + case NETSNMP_OID_OUTPUT_MODULE: + cp = tbuf; + break; + + case NETSNMP_OID_OUTPUT_NONE: + default: + cp = NULL; + } + + if (!*buf_overflow && + !snmp_strcat(buf, buf_len, out_len, allow_realloc, cp)) { + *buf_overflow = 1; + } + SNMP_FREE(tbuf); +} + +/** + * + */ +#ifdef NETSNMP_DISABLE_MIB_LOADING +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) +{ + netsnmp_sprint_realloc_objid(buf, buf_len, out_len, allow_realloc, + buf_overflow, objid, objidlen); +} +#else +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) +{ + u_char *tbuf = NULL, *cp = NULL; + size_t tbuf_len = 512, tout_len = 0; + struct tree *subtree = tree_head; + size_t midpoint_offset = 0; + int tbuf_overflow = 0; + int output_format; + + if ((tbuf = (u_char *) calloc(tbuf_len, 1)) == NULL) { + tbuf_overflow = 1; + } else { + *tbuf = '.'; + tout_len = 1; + } + + subtree = _get_realloc_symbol(objid, objidlen, subtree, + &tbuf, &tbuf_len, &tout_len, + allow_realloc, &tbuf_overflow, NULL, + &midpoint_offset); + + if (tbuf_overflow) { + if (!*buf_overflow) { + snmp_strcat(buf, buf_len, out_len, allow_realloc, tbuf); + *buf_overflow = 1; + } + SNMP_FREE(tbuf); + return subtree; + } + + output_format = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + if (0 == output_format) { + output_format = NETSNMP_OID_OUTPUT_MODULE; + } + switch (output_format) { + case NETSNMP_OID_OUTPUT_FULL: + case NETSNMP_OID_OUTPUT_NUMERIC: + cp = tbuf; + break; + + case NETSNMP_OID_OUTPUT_SUFFIX: + case NETSNMP_OID_OUTPUT_MODULE: + for (cp = tbuf; *cp; cp++); + + if (midpoint_offset != 0) { + cp = tbuf + midpoint_offset - 2; /* beyond the '.' */ + } else { + while (cp >= tbuf) { + if (isalpha(*cp)) { + break; + } + cp--; + } + } + + while (cp >= tbuf) { + if (*cp == '.') { + break; + } + cp--; + } + + cp++; + + if ((NETSNMP_OID_OUTPUT_MODULE == output_format) + && cp > tbuf) { + char modbuf[256] = { 0 }, *mod = + module_name(subtree->modid, modbuf); + + /* + * Don't add the module ID if it's just numeric (i.e. we couldn't look + * it up properly. + */ + + if (!*buf_overflow && modbuf[0] != '#') { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) mod) + || !snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) "::")) { + *buf_overflow = 1; + } + } + } + break; + + case NETSNMP_OID_OUTPUT_UCD: + { + PrefixListPtr pp = &mib_prefixes[0]; + size_t ilen, tlen; + const char *testcp; + + cp = tbuf; + tlen = strlen((char *) tbuf); + + while (pp->str) { + ilen = pp->len; + testcp = pp->str; + + if ((tlen > ilen) && memcmp(tbuf, testcp, ilen) == 0) { + cp += (ilen + 1); + break; + } + pp++; + } + break; + } + + case NETSNMP_OID_OUTPUT_NONE: + default: + cp = NULL; + } + + if (!*buf_overflow && + !snmp_strcat(buf, buf_len, out_len, allow_realloc, cp)) { + *buf_overflow = 1; + } + SNMP_FREE(tbuf); + return subtree; +} +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +int +sprint_realloc_objid(u_char ** buf, size_t * buf_len, + size_t * out_len, int allow_realloc, + const oid * objid, size_t objidlen) +{ + int buf_overflow = 0; + + netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len, allow_realloc, + &buf_overflow, objid, objidlen); + return !buf_overflow; +} + +#ifndef NETSNMP_FEATURE_REMOVE_SPRINT_OBJID +int +snprint_objid(char *buf, size_t buf_len, + const oid * objid, size_t objidlen) +{ + size_t out_len = 0; + + if (sprint_realloc_objid((u_char **) & buf, &buf_len, &out_len, 0, + objid, objidlen)) { + return (int) out_len; + } else { + return -1; + } +} +#endif /* NETSNMP_FEATURE_REMOVE_SPRINT_OBJID */ + +/** + * Prints an oid to stdout. + * + * @param objid The oid to print + * @param objidlen The length of oidid. + */ +void +print_objid(const oid * objid, size_t objidlen) +{ /* number of subidentifiers */ + fprint_objid(stdout, objid, objidlen); +} + + +/** + * Prints an oid to a file descriptor. + * + * @param f The file descriptor to print to. + * @param objid The oid to print + * @param objidlen The length of oidid. + */ +void +fprint_objid(FILE * f, const oid * objid, size_t objidlen) +{ /* number of subidentifiers */ + u_char *buf = NULL; + size_t buf_len = 256, out_len = 0; + int buf_overflow = 0; + + if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) { + fprintf(f, "[TRUNCATED]\n"); + return; + } else { + netsnmp_sprint_realloc_objid_tree(&buf, &buf_len, &out_len, 1, + &buf_overflow, objid, objidlen); + if (buf_overflow) { + fprintf(f, "%s [TRUNCATED]\n", buf); + } else { + fprintf(f, "%s\n", buf); + } + } + + SNMP_FREE(buf); +} + +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) +{ + int buf_overflow = 0; + +#ifndef NETSNMP_DISABLE_MIB_LOADING + struct tree *subtree = tree_head; + + subtree = +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + netsnmp_sprint_realloc_objid_tree(buf, buf_len, out_len, + allow_realloc, &buf_overflow, + objid, objidlen); + + if (buf_overflow) { + return 0; + } + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE)) { + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICKE_PRINT)) { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " = ")) { + return 0; + } + } else { + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT)) { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " ")) { + return 0; + } + } else { + if (!snmp_strcat + (buf, buf_len, out_len, allow_realloc, + (const u_char *) " = ")) { + return 0; + } + } /* end if-else NETSNMP_DS_LIB_QUICK_PRINT */ + } /* end if-else NETSNMP_DS_LIB_QUICKE_PRINT */ + } else { + *out_len = 0; + } + + if (variable->type == SNMP_NOSUCHOBJECT) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No Such Object available on this agent at this OID"); + } else if (variable->type == SNMP_NOSUCHINSTANCE) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No Such Instance currently exists at this OID"); + } else if (variable->type == SNMP_ENDOFMIBVIEW) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No more variables left in this MIB View (It is past the end of the MIB tree)"); +#ifndef NETSNMP_DISABLE_MIB_LOADING + } else if (subtree) { + const char *units = NULL; + const char *hint = NULL; + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_DONT_PRINT_UNITS)) { + units = subtree->units; + } + + if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_NO_DISPLAY_HINT)) { + hint = subtree->hint; + } + + if (subtree->printomat) { + return (*subtree->printomat) (buf, buf_len, out_len, + allow_realloc, variable, + subtree->enums, hint, + units); + } else { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, variable, + subtree->enums, hint, + units); + } +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + } else { + /* + * Handle rare case where tree is empty. + */ + return sprint_realloc_by_type(buf, buf_len, out_len, allow_realloc, + variable, NULL, NULL, NULL); + } +} + +#ifndef NETSNMP_FEATURE_REMOVE_SNPRINT_VARABLE +int +snprint_variable(char *buf, size_t buf_len, + const oid * objid, size_t objidlen, + const netsnmp_variable_list * variable) +{ + size_t out_len = 0; + + if (sprint_realloc_variable((u_char **) & buf, &buf_len, &out_len, 0, + objid, objidlen, variable)) { + return (int) out_len; + } else { + return -1; + } +} +#endif /* NETSNMP_FEATURE_REMOVE_SNPRINT_VARABLE */ + +/** + * Prints a variable to stdout. + * + * @param objid The object id. + * @param objidlen The length of teh object id. + * @param variable The variable to print. + */ +void +print_variable(const oid * objid, + size_t objidlen, const netsnmp_variable_list * variable) +{ + fprint_variable(stdout, objid, objidlen, variable); +} + + +/** + * Prints a variable to a file descriptor. + * + * @param f The file descriptor to print to. + * @param objid The object id. + * @param objidlen The length of teh object id. + * @param variable The variable to print. + */ +void +fprint_variable(FILE * f, + const oid * objid, + size_t objidlen, const netsnmp_variable_list * variable) +{ + u_char *buf = NULL; + size_t buf_len = 256, out_len = 0; + + if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) { + fprintf(f, "[TRUNCATED]\n"); + return; + } else { + if (sprint_realloc_variable(&buf, &buf_len, &out_len, 1, + objid, objidlen, variable)) { + fprintf(f, "%s\n", buf); + } else { + fprintf(f, "%s [TRUNCATED]\n", buf); + } + } + + SNMP_FREE(buf); +} + +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) +{ + if (variable->type == SNMP_NOSUCHOBJECT) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No Such Object available on this agent at this OID"); + } else if (variable->type == SNMP_NOSUCHINSTANCE) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No Such Instance currently exists at this OID"); + } else if (variable->type == SNMP_ENDOFMIBVIEW) { + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) + "No more variables left in this MIB View (It is past the end of the MIB tree)"); + } else { +#ifndef NETSNMP_DISABLE_MIB_LOADING + const char *units = NULL; + struct tree *subtree = tree_head; + subtree = get_tree(objid, objidlen, subtree); + if (subtree && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_DONT_PRINT_UNITS)) { + units = subtree->units; + } + if (subtree) { + if(subtree->printomat) { + return (*subtree->printomat) (buf, buf_len, out_len, + allow_realloc, variable, + subtree->enums, subtree->hint, + units); + } else { + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, variable, + subtree->enums, subtree->hint, + units); + } + } +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + return sprint_realloc_by_type(buf, buf_len, out_len, + allow_realloc, variable, + NULL, NULL, NULL); + } +} + +#ifndef NETSNMP_FEATURE_REMOVE_SNPRINT_VALUE +/* used in the perl module */ +int +snprint_value(char *buf, size_t buf_len, + const oid * objid, size_t objidlen, + const netsnmp_variable_list * variable) +{ + size_t out_len = 0; + + if (sprint_realloc_value((u_char **) & buf, &buf_len, &out_len, 0, + objid, objidlen, variable)) { + return (int) out_len; + } else { + return -1; + } +} +#endif /* NETSNMP_FEATURE_REMOVE_SNPRINT_VALUE */ + +void +print_value(const oid * objid, + size_t objidlen, const netsnmp_variable_list * variable) +{ + fprint_value(stdout, objid, objidlen, variable); +} + +void +fprint_value(FILE * f, + const oid * objid, + size_t objidlen, const netsnmp_variable_list * variable) +{ + u_char *buf = NULL; + size_t buf_len = 256, out_len = 0; + + if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) { + fprintf(f, "[TRUNCATED]\n"); + return; + } else { + if (sprint_realloc_value(&buf, &buf_len, &out_len, 1, + objid, objidlen, variable)) { + fprintf(f, "%s\n", buf); + } else { + fprintf(f, "%s [TRUNCATED]\n", buf); + } + } + + SNMP_FREE(buf); +} + + +/** + * Takes the value in VAR and turns it into an OID segment in var->name. + * + * @param var The variable. + * + * @return SNMPERR_SUCCESS or SNMPERR_GENERR + */ +int +build_oid_segment(netsnmp_variable_list * var) +{ + int i; + uint32_t ipaddr; + + if (var->name && var->name != var->name_loc) + SNMP_FREE(var->name); + switch (var->type) { + case ASN_INTEGER: + case ASN_COUNTER: + case ASN_GAUGE: + case ASN_TIMETICKS: + var->name_length = 1; + var->name = var->name_loc; + var->name[0] = *(var->val.integer); + break; + + case ASN_IPADDRESS: + var->name_length = 4; + var->name = var->name_loc; + memcpy(&ipaddr, var->val.string, sizeof(ipaddr)); + var->name[0] = (ipaddr >> 24) & 0xff; + var->name[1] = (ipaddr >> 16) & 0xff; + var->name[2] = (ipaddr >> 8) & 0xff; + var->name[3] = (ipaddr >> 0) & 0xff; + break; + + case ASN_PRIV_IMPLIED_OBJECT_ID: + var->name_length = var->val_len / sizeof(oid); + if (var->name_length > (sizeof(var->name_loc) / sizeof(oid))) + var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); + else + var->name = var->name_loc; + if (var->name == NULL) + return SNMPERR_GENERR; + + for (i = 0; i < (int) var->name_length; i++) + var->name[i] = var->val.objid[i]; + break; + + case ASN_OBJECT_ID: + var->name_length = var->val_len / sizeof(oid) + 1; + if (var->name_length > (sizeof(var->name_loc) / sizeof(oid))) + var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); + else + var->name = var->name_loc; + if (var->name == NULL) + return SNMPERR_GENERR; + + var->name[0] = var->name_length - 1; + for (i = 0; i < (int) var->name_length - 1; i++) + var->name[i + 1] = var->val.objid[i]; + break; + + case ASN_PRIV_IMPLIED_OCTET_STR: + var->name_length = var->val_len; + if (var->name_length > (sizeof(var->name_loc) / sizeof(oid))) + var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); + else + var->name = var->name_loc; + if (var->name == NULL) + return SNMPERR_GENERR; + + for (i = 0; i < (int) var->val_len; i++) + var->name[i] = (oid) var->val.string[i]; + break; + + case ASN_OPAQUE: + case ASN_OCTET_STR: + var->name_length = var->val_len + 1; + if (var->name_length > (sizeof(var->name_loc) / sizeof(oid))) + var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); + else + var->name = var->name_loc; + if (var->name == NULL) + return SNMPERR_GENERR; + + var->name[0] = (oid) var->val_len; + for (i = 0; i < (int) var->val_len; i++) + var->name[i + 1] = (oid) var->val.string[i]; + break; + + default: + DEBUGMSGTL(("build_oid_segment", + "invalid asn type: %d\n", var->type)); + return SNMPERR_GENERR; + } + + if (var->name_length > MAX_OID_LEN) { + DEBUGMSGTL(("build_oid_segment", + "Something terribly wrong, namelen = %lu\n", + (unsigned long)var->name_length)); + return SNMPERR_GENERR; + } + + return SNMPERR_SUCCESS; +} + + +int +build_oid_noalloc(oid * in, size_t in_len, size_t * out_len, + oid * prefix, size_t prefix_len, + netsnmp_variable_list * indexes) +{ + netsnmp_variable_list *var; + + if (prefix) { + if (in_len < prefix_len) + return SNMPERR_GENERR; + memcpy(in, prefix, prefix_len * sizeof(oid)); + *out_len = prefix_len; + } else { + *out_len = 0; + } + + for (var = indexes; var != NULL; var = var->next_variable) { + if (build_oid_segment(var) != SNMPERR_SUCCESS) + return SNMPERR_GENERR; + if (var->name_length + *out_len <= in_len) { + memcpy(&(in[*out_len]), var->name, + sizeof(oid) * var->name_length); + *out_len += var->name_length; + } else { + return SNMPERR_GENERR; + } + } + + DEBUGMSGTL(("build_oid_noalloc", "generated: ")); + DEBUGMSGOID(("build_oid_noalloc", in, *out_len)); + DEBUGMSG(("build_oid_noalloc", "\n")); + return SNMPERR_SUCCESS; +} + +int +build_oid(oid ** out, size_t * out_len, + oid * prefix, size_t prefix_len, netsnmp_variable_list * indexes) +{ + oid tmpout[MAX_OID_LEN]; + + /* + * xxx-rks: inefficent. try only building segments to find index len: + * for (var = indexes; var != NULL; var = var->next_variable) { + * if (build_oid_segment(var) != SNMPERR_SUCCESS) + * return SNMPERR_GENERR; + * *out_len += var->name_length; + * + * then see if it fits in existing buffer, or realloc buffer. + */ + if (build_oid_noalloc(tmpout, sizeof(tmpout), out_len, + prefix, prefix_len, indexes) != SNMPERR_SUCCESS) + return SNMPERR_GENERR; + + /** xxx-rks: should free previous value? */ + snmp_clone_mem((void **) out, (void *) tmpout, *out_len * sizeof(oid)); + + return SNMPERR_SUCCESS; +} + +/* + * vblist_out must contain a pre-allocated string of variables into + * which indexes can be extracted based on the previously existing + * types in the variable chain + * returns: + * SNMPERR_GENERR on error + * SNMPERR_SUCCESS on success + */ + +int +parse_oid_indexes(oid * oidIndex, size_t oidLen, + netsnmp_variable_list * data) +{ + netsnmp_variable_list *var = data; + + while (var && oidLen > 0) { + + if (parse_one_oid_index(&oidIndex, &oidLen, var, 0) != + SNMPERR_SUCCESS) + break; + + var = var->next_variable; + } + + if (var != NULL || oidLen != 0) + return SNMPERR_GENERR; + return SNMPERR_SUCCESS; +} + + +int +parse_one_oid_index(oid ** oidStart, size_t * oidLen, + netsnmp_variable_list * data, int complete) +{ + netsnmp_variable_list *var = data; + oid tmpout[MAX_OID_LEN]; + unsigned int i; + unsigned int uitmp = 0; + + oid *oidIndex = *oidStart; + + if (var == NULL || ((*oidLen == 0) && (complete == 0))) + return SNMPERR_GENERR; + else { + switch (var->type) { + case ASN_INTEGER: + case ASN_COUNTER: + case ASN_GAUGE: + case ASN_TIMETICKS: + if (*oidLen) { + snmp_set_var_value(var, (u_char *) oidIndex++, + sizeof(oid)); + --(*oidLen); + } else { + snmp_set_var_value(var, (u_char *) oidLen, sizeof(long)); + } + DEBUGMSGTL(("parse_oid_indexes", + "Parsed int(%d): %ld\n", var->type, + *var->val.integer)); + break; + + case ASN_IPADDRESS: + if ((4 > *oidLen) && (complete == 0)) + return SNMPERR_GENERR; + + for (i = 0; i < 4 && i < *oidLen; ++i) { + if (oidIndex[i] > 255) { + DEBUGMSGTL(("parse_oid_indexes", + "illegal oid in index: %" NETSNMP_PRIo "d\n", + oidIndex[0])); + return SNMPERR_GENERR; /* sub-identifier too large */ + } + uitmp = uitmp + (oidIndex[i] << (8*(3-i))); + } + if (4 > (int) (*oidLen)) { + oidIndex += *oidLen; + (*oidLen) = 0; + } else { + oidIndex += 4; + (*oidLen) -= 4; + } + uitmp = htonl(uitmp); /* put it in proper order for byte copies */ + uitmp = + snmp_set_var_value(var, (u_char *) &uitmp, 4); + DEBUGMSGTL(("parse_oid_indexes", + "Parsed ipaddr(%d): %d.%d.%d.%d\n", var->type, + var->val.string[0], var->val.string[1], + var->val.string[2], var->val.string[3])); + break; + + case ASN_OBJECT_ID: + case ASN_PRIV_IMPLIED_OBJECT_ID: + if (var->type == ASN_PRIV_IMPLIED_OBJECT_ID) { + /* + * might not be implied, might be fixed len. check if + * caller set up val len, and use it if they did. + */ + if (0 == var->val_len) + uitmp = *oidLen; + else { + DEBUGMSGTL(("parse_oid_indexes:fix", "fixed len oid\n")); + uitmp = var->val_len; + } + } else { + if (*oidLen) { + uitmp = *oidIndex++; + --(*oidLen); + } else { + uitmp = 0; + } + if ((uitmp > *oidLen) && (complete == 0)) + return SNMPERR_GENERR; + } + + if (uitmp > MAX_OID_LEN) + return SNMPERR_GENERR; /* too big and illegal */ + + if (uitmp > *oidLen) { + memcpy(tmpout, oidIndex, sizeof(oid) * (*oidLen)); + memset(&tmpout[*oidLen], 0x00, + sizeof(oid) * (uitmp - *oidLen)); + snmp_set_var_value(var, (u_char *) tmpout, + sizeof(oid) * uitmp); + oidIndex += *oidLen; + (*oidLen) = 0; + } else { + snmp_set_var_value(var, (u_char *) oidIndex, + sizeof(oid) * uitmp); + oidIndex += uitmp; + (*oidLen) -= uitmp; + } + + DEBUGMSGTL(("parse_oid_indexes", "Parsed oid: ")); + DEBUGMSGOID(("parse_oid_indexes", + var->val.objid, var->val_len / sizeof(oid))); + DEBUGMSG(("parse_oid_indexes", "\n")); + break; + + case ASN_OPAQUE: + case ASN_OCTET_STR: + case ASN_PRIV_IMPLIED_OCTET_STR: + if (var->type == ASN_PRIV_IMPLIED_OCTET_STR) { + /* + * might not be implied, might be fixed len. check if + * caller set up val len, and use it if they did. + */ + if (0 == var->val_len) + uitmp = *oidLen; + else { + DEBUGMSGTL(("parse_oid_indexes:fix", "fixed len str\n")); + uitmp = var->val_len; + } + } else { + if (*oidLen) { + uitmp = *oidIndex++; + --(*oidLen); + } else { + uitmp = 0; + } + if ((uitmp > *oidLen) && (complete == 0)) + return SNMPERR_GENERR; + } + + /* + * we handle this one ourselves since we don't have + * pre-allocated memory to copy from using + * snmp_set_var_value() + */ + + if (uitmp == 0) + break; /* zero length strings shouldn't malloc */ + + if (uitmp > MAX_OID_LEN) + return SNMPERR_GENERR; /* too big and illegal */ + + /* + * malloc by size+1 to allow a null to be appended. + */ + var->val_len = uitmp; + var->val.string = (u_char *) calloc(1, uitmp + 1); + if (var->val.string == NULL) + return SNMPERR_GENERR; + + if ((size_t)uitmp > (*oidLen)) { + for (i = 0; i < *oidLen; ++i) + var->val.string[i] = (u_char) * oidIndex++; + for (i = *oidLen; i < uitmp; ++i) + var->val.string[i] = '\0'; + (*oidLen) = 0; + } else { + for (i = 0; i < uitmp; ++i) + var->val.string[i] = (u_char) * oidIndex++; + (*oidLen) -= uitmp; + } + var->val.string[uitmp] = '\0'; + + DEBUGMSGTL(("parse_oid_indexes", + "Parsed str(%d): %s\n", var->type, + var->val.string)); + break; + + default: + DEBUGMSGTL(("parse_oid_indexes", + "invalid asn type: %d\n", var->type)); + return SNMPERR_GENERR; + } + } + (*oidStart) = oidIndex; + return SNMPERR_SUCCESS; +} + +/* + * dump_realloc_oid_to_inetaddress: + * return 0 for failure, + * return 1 for success, + * return 2 for not handled + */ + +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) +{ + if (buf) { + int i, len; + char intbuf[64], * p; + unsigned char *zc; + unsigned long zone; + + memset(intbuf, 0, 64); + + p = intbuf; + *p = quotechar; + p++; + switch (addr_type) { + case IPV4: + case IPV4Z: + if ((addr_type == IPV4 && objidlen != 4) || + (addr_type == IPV4Z && objidlen != 8)) + return 2; + + len = sprintf(p, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u." + "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u", + objid[0], objid[1], objid[2], objid[3]); + p += len; + if (addr_type == IPV4Z) { + zc = (unsigned char*)&zone; + zc[0] = (u_char)(objid[4]); + zc[1] = (u_char)(objid[5]); + zc[2] = (u_char)(objid[6]); + zc[3] = (u_char)(objid[7]); + zone = ntohl(zone); + len = sprintf(p, "%%%lu", zone); + p += len; + } + + break; + + case IPV6: + case IPV6Z: + if ((addr_type == IPV6 && objidlen != 16) || + (addr_type == IPV6Z && objidlen != 20)) + return 2; + + len = 0; + for (i = 0; i < 16; i ++) { + len = snprintf(p, 4, "%02" NETSNMP_PRIo "x:", objid[i]); + p += len; + } + p-- ; /* do not include the last ':' */ + + if (addr_type == IPV6Z) { + zc = (unsigned char*)&zone; + zc[0] = (u_char)(objid[16]); + zc[1] = (u_char)(objid[17]); + zc[2] = (u_char)(objid[18]); + zc[3] = (u_char)(objid[19]); + zone = ntohl(zone); + len = sprintf(p, "%%%lu", zone); + p += len; + } + + break; + + case DNS: + default: + /* DNS can just be handled by dump_realloc_oid_to_string() */ + return 2; + } + + *p = quotechar; + + return snmp_strcat(buf, buf_len, out_len, allow_realloc, + (const u_char *) intbuf); + } + return 1; +} + +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) +{ + if (buf) { + int i, alen; + + for (i = 0, alen = 0; i < (int) objidlen; i++) { + oid tst = objid[i]; + if ((tst > 254) || (!isprint(tst))) { + tst = (oid) '.'; + } + + if (alen == 0) { + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) { + while ((*out_len + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = '\\'; + (*out_len)++; + } + while ((*out_len + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = quotechar; + (*out_len)++; + } + + while ((*out_len + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = (char) tst; + (*out_len)++; + alen++; + } + + if (alen) { + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) { + while ((*out_len + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = '\\'; + (*out_len)++; + } + while ((*out_len + 2) >= *buf_len) { + if (!(allow_realloc && snmp_realloc(buf, buf_len))) { + return 0; + } + } + *(*buf + *out_len) = quotechar; + (*out_len)++; + } + + *(*buf + *out_len) = '\0'; + } + + return 1; +} + +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) { + char intbuf[64]; + if (*buf != NULL && *(*buf + *out_len - 1) != '.') { + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) ".")) { + *buf_overflow = 1; + } + } + + while (objidlen-- > 0) { /* output rest of name, uninterpreted */ + sprintf(intbuf, "%" NETSNMP_PRIo "u.", *objid++); + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) intbuf)) { + *buf_overflow = 1; + } + } + + if (*buf != NULL) { + *(*buf + *out_len - 1) = '\0'; /* remove trailing dot */ + *out_len = *out_len - 1; + } +} + +#ifndef NETSNMP_DISABLE_MIB_LOADING +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) +{ + struct tree *return_tree = NULL; + int extended_index = + netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_EXTENDED_INDEX); + int output_format = + netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT); + char intbuf[64]; + + if (!objid || !buf) { + return NULL; + } + + for (; subtree; subtree = subtree->next_peer) { + if (*objid == subtree->subid) { + while (subtree->next_peer && subtree->next_peer->subid == *objid) + subtree = subtree->next_peer; + if (subtree->indexes) { + in_dices = subtree->indexes; + } else if (subtree->augments) { + struct tree *tp2 = + find_tree_node(subtree->augments, -1); + if (tp2) { + in_dices = tp2->indexes; + } + } + + if (!strncmp(subtree->label, ANON, ANON_LEN) || + (NETSNMP_OID_OUTPUT_NUMERIC == output_format)) { + sprintf(intbuf, "%lu", subtree->subid); + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) + intbuf)) { + *buf_overflow = 1; + } + } else { + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) + subtree->label)) { + *buf_overflow = 1; + } + } + + if (objidlen > 1) { + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) ".")) { + *buf_overflow = 1; + } + + return_tree = _get_realloc_symbol(objid + 1, objidlen - 1, + subtree->child_list, + buf, buf_len, out_len, + allow_realloc, + buf_overflow, in_dices, + end_of_known); + } + + if (return_tree != NULL) { + return return_tree; + } else { + return subtree; + } + } + } + + + if (end_of_known) { + *end_of_known = *out_len; + } + + /* + * Subtree not found. + */ + + while (in_dices && (objidlen > 0) && + (NETSNMP_OID_OUTPUT_NUMERIC != output_format) && + !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS)) { + size_t numids; + struct tree *tp; + + tp = find_tree_node(in_dices->ilabel, -1); + + if (!tp) { + /* + * Can't find an index in the mib tree. Bail. + */ + goto finish_it; + } + + if (extended_index) { + if (*buf != NULL && *(*buf + *out_len - 1) == '.') { + (*out_len)--; + } + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "[")) { + *buf_overflow = 1; + } + } + + switch (tp->type) { + case TYPE_OCTETSTR: + if (extended_index && tp->hint) { + netsnmp_variable_list var; + u_char buffer[1024]; + int i; + + memset(&var, 0, sizeof var); + if (in_dices->isimplied) { + numids = objidlen; + if (numids > objidlen) + goto finish_it; + } else if (tp->ranges && !tp->ranges->next + && tp->ranges->low == tp->ranges->high) { + numids = tp->ranges->low; + if (numids > objidlen) + goto finish_it; + } else { + numids = *objid; + if (numids >= objidlen) + goto finish_it; + objid++; + objidlen--; + } + if (numids > objidlen) + goto finish_it; + for (i = 0; i < (int) numids; i++) + buffer[i] = (u_char) objid[i]; + var.type = ASN_OCTET_STR; + var.val.string = buffer; + var.val_len = numids; + if (!*buf_overflow) { + if (!sprint_realloc_octet_string(buf, buf_len, out_len, + allow_realloc, &var, + NULL, tp->hint, + NULL)) { + *buf_overflow = 1; + } + } + } else if (in_dices->isimplied) { + numids = objidlen; + if (numids > objidlen) + goto finish_it; + + if (!*buf_overflow) { + if (!dump_realloc_oid_to_string + (objid, numids, buf, buf_len, out_len, + allow_realloc, '\'')) { + *buf_overflow = 1; + } + } + } else if (tp->ranges && !tp->ranges->next + && tp->ranges->low == tp->ranges->high) { + /* + * a fixed-length octet string + */ + numids = tp->ranges->low; + if (numids > objidlen) + goto finish_it; + + if (!*buf_overflow) { + if (!dump_realloc_oid_to_string + (objid, numids, buf, buf_len, out_len, + allow_realloc, '\'')) { + *buf_overflow = 1; + } + } + } else { + numids = (size_t) * objid + 1; + if (numids > objidlen) + goto finish_it; + if (numids == 1) { + if (netsnmp_ds_get_boolean + (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) { + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "\\")) { + *buf_overflow = 1; + } + } + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "\"")) { + *buf_overflow = 1; + } + if (netsnmp_ds_get_boolean + (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_ESCAPE_QUOTES)) { + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "\\")) { + *buf_overflow = 1; + } + } + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "\"")) { + *buf_overflow = 1; + } + } else { + if (!*buf_overflow) { + struct tree * next_peer; + int normal_handling = 1; + + if (tp->next_peer) { + next_peer = tp->next_peer; + } + + /* Try handling the InetAddress in the OID, in case of failure, + * use the normal_handling. + */ + if (tp->next_peer && + tp->tc_index != -1 && + next_peer->tc_index != -1 && + strcmp(get_tc_descriptor(tp->tc_index), "InetAddress") == 0 && + strcmp(get_tc_descriptor(next_peer->tc_index), + "InetAddressType") == 0 ) { + + int ret; + int addr_type = *(objid - 1); + + ret = dump_realloc_oid_to_inetaddress(addr_type, + objid + 1, numids - 1, buf, buf_len, out_len, + allow_realloc, '"'); + if (ret != 2) { + normal_handling = 0; + if (ret == 0) { + *buf_overflow = 1; + } + + } + } + if (normal_handling && !dump_realloc_oid_to_string + (objid + 1, numids - 1, buf, buf_len, out_len, + allow_realloc, '"')) { + *buf_overflow = 1; + } + } + } + } + objid += numids; + objidlen -= numids; + break; + + case TYPE_INTEGER32: + case TYPE_UINTEGER: + case TYPE_UNSIGNED32: + case TYPE_GAUGE: + case TYPE_INTEGER: + if (tp->enums) { + struct enum_list *ep = tp->enums; + while (ep && ep->value != (int) (*objid)) { + ep = ep->next; + } + if (ep) { + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) ep->label)) { + *buf_overflow = 1; + } + } else { + sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid); + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) intbuf)) { + *buf_overflow = 1; + } + } + } else { + sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid); + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) + intbuf)) { + *buf_overflow = 1; + } + } + objid++; + objidlen--; + break; + + case TYPE_TIMETICKS: + /* In an index, this is probably a timefilter */ + if (extended_index) { + uptimeString( *objid, intbuf, sizeof( intbuf ) ); + } else { + sprintf(intbuf, "%" NETSNMP_PRIo "u", *objid); + } + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) + intbuf)) { + *buf_overflow = 1; + } + objid++; + objidlen--; + break; + + case TYPE_OBJID: + if (in_dices->isimplied) { + numids = objidlen; + } else { + numids = (size_t) * objid + 1; + } + if (numids > objidlen) + goto finish_it; + if (extended_index) { + if (in_dices->isimplied) { + if (!*buf_overflow + && !netsnmp_sprint_realloc_objid_tree(buf, buf_len, + out_len, + allow_realloc, + buf_overflow, + objid, + numids)) { + *buf_overflow = 1; + } + } else { + if (!*buf_overflow + && !netsnmp_sprint_realloc_objid_tree(buf, buf_len, + out_len, + allow_realloc, + buf_overflow, + objid + 1, + numids - + 1)) { + *buf_overflow = 1; + } + } + } else { + _get_realloc_symbol(objid, numids, NULL, buf, buf_len, + out_len, allow_realloc, buf_overflow, + NULL, NULL); + } + objid += (numids); + objidlen -= (numids); + break; + + case TYPE_IPADDR: + if (objidlen < 4) + goto finish_it; + sprintf(intbuf, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u." + "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u", + objid[0], objid[1], objid[2], objid[3]); + objid += 4; + objidlen -= 4; + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) intbuf)) { + *buf_overflow = 1; + } + break; + + case TYPE_NETADDR:{ + oid ntype = *objid++; + + objidlen--; + sprintf(intbuf, "%" NETSNMP_PRIo "u.", ntype); + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) + intbuf)) { + *buf_overflow = 1; + } + + if (ntype == 1 && objidlen >= 4) { + sprintf(intbuf, "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u." + "%" NETSNMP_PRIo "u.%" NETSNMP_PRIo "u", + objid[0], objid[1], objid[2], objid[3]); + if (!*buf_overflow + && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) intbuf)) { + *buf_overflow = 1; + } + objid += 4; + objidlen -= 4; + } else { + goto finish_it; + } + } + break; + + case TYPE_NSAPADDRESS: + default: + goto finish_it; + break; + } + + if (extended_index) { + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) "]")) { + *buf_overflow = 1; + } + } else { + if (!*buf_overflow && !snmp_strcat(buf, buf_len, out_len, + allow_realloc, + (const u_char *) ".")) { + *buf_overflow = 1; + } + } + in_dices = in_dices->next; + } + + finish_it: + _oid_finish_printing(objid, objidlen, + buf, buf_len, out_len, + allow_realloc, buf_overflow); + return NULL; +} + +struct tree * +get_tree(const oid * objid, size_t objidlen, struct tree *subtree) +{ + struct tree *return_tree = NULL; + + for (; subtree; subtree = subtree->next_peer) { + if (*objid == subtree->subid) + goto found; + } + + return NULL; + + found: + while (subtree->next_peer && subtree->next_peer->subid == *objid) + subtree = subtree->next_peer; + if (objidlen > 1) + return_tree = + get_tree(objid + 1, objidlen - 1, subtree->child_list); + if (return_tree != NULL) + return return_tree; + else + return subtree; +} + +/** + * Prints on oid description on stdout. + * + * @see fprint_description + */ +void +print_description(oid * objid, size_t objidlen, /* number of subidentifiers */ + int width) +{ + fprint_description(stdout, objid, objidlen, width); +} + + +/** + * Prints on oid description into a file descriptor. + * + * @param f The file descriptor to print to. + * @param objid The object identifier. + * @param objidlen The object id length. + * @param width Number of subidentifiers. + */ +void +fprint_description(FILE * f, oid * objid, size_t objidlen, + int width) +{ + u_char *buf = NULL; + size_t buf_len = 256, out_len = 0; + + if ((buf = (u_char *) calloc(buf_len, 1)) == NULL) { + fprintf(f, "[TRUNCATED]\n"); + return; + } else { + if (!sprint_realloc_description(&buf, &buf_len, &out_len, 1, + objid, objidlen, width)) { + fprintf(f, "%s [TRUNCATED]\n", buf); + } else { + fprintf(f, "%s\n", buf); + } + } + + SNMP_FREE(buf); +} + +#ifndef NETSNMP_FEATURE_REMOVE_MIB_SNPRINT_DESCRIPTION +int +snprint_description(char *buf, size_t buf_len, + oid * objid, size_t objidlen, int width) +{ + size_t out_len = 0; + + if (sprint_realloc_description((u_char **) & buf, &buf_len, &out_len, 0, + objid, objidlen, width)) { + return (int) out_len; + } else { + return -1; + } +} +#endif /* NETSNMP_FEATURE_REMOVE_MIB_SNPRINT_DESCRIPTION */ + +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) +{ + struct tree *tp = get_tree(objid, objidlen, tree_head); + struct tree *subtree = tree_head; + int pos, len; + char tmpbuf[128]; + const char *cp; + + if (NULL == tp) + return 0; + + if (tp->type <= TYPE_SIMPLE_LAST) + cp = " OBJECT-TYPE"; + else + switch (tp->type) { + case TYPE_TRAPTYPE: + cp = " TRAP-TYPE"; + break; + case TYPE_NOTIFTYPE: + cp = " NOTIFICATION-TYPE"; + break; + case TYPE_OBJGROUP: + cp = " OBJECT-GROUP"; + break; + case TYPE_AGENTCAP: + cp = " AGENT-CAPABILITIES"; + break; + case TYPE_MODID: + cp = " MODULE-IDENTITY"; + break; + case TYPE_OBJIDENTITY: + cp = " OBJECT-IDENTITY"; + break; + case TYPE_MODCOMP: + cp = " MODULE-COMPLIANCE"; + break; + default: + sprintf(tmpbuf, " type_%d", tp->type); + cp = tmpbuf; + } + + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->label) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) { + return 0; + } + if (!print_tree_node(buf, buf_len, out_len, allow_realloc, tp, width)) + return 0; + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "::= {")) + return 0; + pos = 5; + while (objidlen > 1) { + for (; subtree; subtree = subtree->next_peer) { + if (*objid == subtree->subid) { + while (subtree->next_peer && subtree->next_peer->subid == *objid) + subtree = subtree->next_peer; + if (strncmp(subtree->label, ANON, ANON_LEN)) { + snprintf(tmpbuf, sizeof(tmpbuf), " %s(%lu)", subtree->label, subtree->subid); + tmpbuf[ sizeof(tmpbuf)-1 ] = 0; + } else + sprintf(tmpbuf, " %lu", subtree->subid); + len = strlen(tmpbuf); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, + allow_realloc, "\n ")) + return 0; + pos = 5; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf)) + return 0; + pos += len; + objid++; + objidlen--; + break; + } + } + if (subtree) + subtree = subtree->child_list; + else + break; + } + while (objidlen > 1) { + sprintf(tmpbuf, " %" NETSNMP_PRIo "u", *objid); + len = strlen(tmpbuf); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n ")) + return 0; + pos = 5; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf)) + return 0; + pos += len; + objid++; + objidlen--; + } + sprintf(tmpbuf, " %" NETSNMP_PRIo "u }", *objid); + len = strlen(tmpbuf); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n ")) + return 0; + pos = 5; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tmpbuf)) + return 0; + return 1; +} + +static int +print_tree_node(u_char ** buf, size_t * buf_len, + size_t * out_len, int allow_realloc, + struct tree *tp, int width) +{ + const char *cp; + char str[MAXTOKEN]; + int i, prevmod, pos, len; + + if (tp) { + module_name(tp->modid, str); + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " -- FROM\t") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + pos = 16+strlen(str); + for (i = 1, prevmod = tp->modid; i < tp->number_modules; i++) { + if (prevmod != tp->module_list[i]) { + module_name(tp->module_list[i], str); + len = strlen(str); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + ",\n --\t\t")) + return 0; + pos = 16; + } + else { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", ")) + return 0; + pos += 2; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + pos += len; + } + prevmod = tp->module_list[i]; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) + return 0; + if (tp->tc_index != -1) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " -- TEXTUAL CONVENTION ") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + get_tc_descriptor(tp->tc_index)) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) + return 0; + } + switch (tp->type) { + case TYPE_OBJID: + cp = "OBJECT IDENTIFIER"; + break; + case TYPE_OCTETSTR: + cp = "OCTET STRING"; + break; + case TYPE_INTEGER: + cp = "INTEGER"; + break; + case TYPE_NETADDR: + cp = "NetworkAddress"; + break; + case TYPE_IPADDR: + cp = "IpAddress"; + break; + case TYPE_COUNTER: + cp = "Counter32"; + break; + case TYPE_GAUGE: + cp = "Gauge32"; + break; + case TYPE_TIMETICKS: + cp = "TimeTicks"; + break; + case TYPE_OPAQUE: + cp = "Opaque"; + break; + case TYPE_NULL: + cp = "NULL"; + break; + case TYPE_COUNTER64: + cp = "Counter64"; + break; + case TYPE_BITSTRING: + cp = "BITS"; + break; + case TYPE_NSAPADDRESS: + cp = "NsapAddress"; + break; + case TYPE_UINTEGER: + cp = "UInteger32"; + break; + case TYPE_UNSIGNED32: + cp = "Unsigned32"; + break; + case TYPE_INTEGER32: + cp = "Integer32"; + break; + default: + cp = NULL; + break; + } +#if NETSNMP_ENABLE_TESTING_CODE + if (!cp && (tp->ranges || tp->enums)) { /* ranges without type ? */ + sprintf(str, "?0 with %s %s ?", + tp->ranges ? "Range" : "", tp->enums ? "Enum" : ""); + cp = str; + } +#endif /* NETSNMP_ENABLE_TESTING_CODE */ + if (cp) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " SYNTAX\t") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp)) + return 0; + if (tp->ranges) { + struct range_list *rp = tp->ranges; + int first = 1; + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " (")) + return 0; + while (rp) { + switch (tp->type) { + case TYPE_INTEGER: + case TYPE_INTEGER32: + if (rp->low == rp->high) + sprintf(str, "%s%d", (first ? "" : " | "), rp->low ); + else + sprintf(str, "%s%d..%d", (first ? "" : " | "), + rp->low, rp->high); + break; + case TYPE_UNSIGNED32: + case TYPE_OCTETSTR: + case TYPE_GAUGE: + case TYPE_UINTEGER: + if (rp->low == rp->high) + sprintf(str, "%s%u", (first ? "" : " | "), + (unsigned)rp->low ); + else + sprintf(str, "%s%u..%u", (first ? "" : " | "), + (unsigned)rp->low, (unsigned)rp->high); + break; + default: + /* No other range types allowed */ + break; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + if (first) + first = 0; + rp = rp->next; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ") ")) + return 0; + } + if (tp->enums) { + struct enum_list *ep = tp->enums; + int first = 1; + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " {")) + return 0; + pos = 16 + strlen(cp) + 2; + while (ep) { + if (first) + first = 0; + else + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", ")) + return 0; + snprintf(str, sizeof(str), "%s(%d)", ep->label, ep->value); + str[ sizeof(str)-1 ] = 0; + len = strlen(str); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, + allow_realloc, "\n\t\t ")) + return 0; + pos = 18; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + pos += len + 2; + ep = ep->next; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "} ")) + return 0; + } + if (cp) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) + return 0; + if (tp->hint) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " DISPLAY-HINT\t\"") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->hint) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n")) + return 0; + if (tp->units) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " UNITS\t\t\"") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->units) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n")) + return 0; + switch (tp->access) { + case MIB_ACCESS_READONLY: + cp = "read-only"; + break; + case MIB_ACCESS_READWRITE: + cp = "read-write"; + break; + case MIB_ACCESS_WRITEONLY: + cp = "write-only"; + break; + case MIB_ACCESS_NOACCESS: + cp = "not-accessible"; + break; + case MIB_ACCESS_NOTIFY: + cp = "accessible-for-notify"; + break; + case MIB_ACCESS_CREATE: + cp = "read-create"; + break; + case 0: + cp = NULL; + break; + default: + sprintf(str, "access_%d", tp->access); + cp = str; + } + if (cp) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " MAX-ACCESS\t") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) + return 0; + switch (tp->status) { + case MIB_STATUS_MANDATORY: + cp = "mandatory"; + break; + case MIB_STATUS_OPTIONAL: + cp = "optional"; + break; + case MIB_STATUS_OBSOLETE: + cp = "obsolete"; + break; + case MIB_STATUS_DEPRECATED: + cp = "deprecated"; + break; + case MIB_STATUS_CURRENT: + cp = "current"; + break; + case 0: + cp = NULL; + break; + default: + sprintf(str, "status_%d", tp->status); + cp = str; + } +#if NETSNMP_ENABLE_TESTING_CODE + if (!cp && (tp->indexes)) { /* index without status ? */ + sprintf(str, "?0 with %s ?", tp->indexes ? "Index" : ""); + cp = str; + } +#endif /* NETSNMP_ENABLE_TESTING_CODE */ + if (cp) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " STATUS\t") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, cp) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n")) + return 0; + if (tp->augments) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " AUGMENTS\t{ ") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->augments) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n")) + return 0; + if (tp->indexes) { + struct index_list *ip = tp->indexes; + int first = 1; + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " INDEX\t\t{ ")) + return 0; + pos = 16 + 2; + while (ip) { + if (first) + first = 0; + else + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", ")) + return 0; + snprintf(str, sizeof(str), "%s%s", + ip->isimplied ? "IMPLIED " : "", + ip->ilabel); + str[ sizeof(str)-1 ] = 0; + len = strlen(str); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\n\t\t ")) + return 0; + pos = 16 + 2; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + pos += len + 2; + ip = ip->next; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n")) + return 0; + } + if (tp->varbinds) { + struct varbind_list *vp = tp->varbinds; + int first = 1; + + if (tp->type == TYPE_TRAPTYPE) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " VARIABLES\t{ ")) + return 0; + } else { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " OBJECTS\t{ ")) + return 0; + } + pos = 16 + 2; + while (vp) { + if (first) + first = 0; + else + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, ", ")) + return 0; + strlcpy(str, vp->vblabel, sizeof(str)); + len = strlen(str); + if (pos + len + 2 > width) { + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + "\n\t\t ")) + return 0; + pos = 16 + 2; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, str)) + return 0; + pos += len + 2; + vp = vp->next; + } + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n")) + return 0; + } + if (tp->description) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " DESCRIPTION\t\"") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->description) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "\"\n")) + return 0; + if (tp->defaultValue) + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, + " DEFVAL\t{ ") || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, tp->defaultValue) || + !snmp_cstrcat(buf, buf_len, out_len, allow_realloc, " }\n")) + return 0; + } else + if (!snmp_cstrcat(buf, buf_len, out_len, allow_realloc, "No description\n")) + return 0; + return 1; +} + +int +get_module_node(const char *fname, + const char *module, oid * objid, size_t * objidlen) +{ + int modid, rc = 0; + struct tree *tp; + char *name, *cp; + + if (!strcmp(module, "ANY")) + modid = -1; + else { + netsnmp_read_module(module); + modid = which_module(module); + if (modid == -1) + return 0; + } + + /* + * Isolate the first component of the name ... + */ + name = strdup(fname); + cp = strchr(name, '.'); + if (cp != NULL) { + *cp = '\0'; + cp++; + } + /* + * ... and locate it in the tree. + */ + tp = find_tree_node(name, modid); + if (tp) { + size_t maxlen = *objidlen; + + /* + * Set the first element of the object ID + */ + if (node_to_oid(tp, objid, objidlen)) { + rc = 1; + + /* + * If the name requested was more than one element, + * tag on the rest of the components + */ + if (cp != NULL) + rc = _add_strings_to_oid(tp, cp, objid, objidlen, maxlen); + } + } + + SNMP_FREE(name); + return (rc); +} + + +/** + * @internal + * + * Populates the object identifier from a node in the MIB hierarchy. + * Builds up the object ID, working backwards, + * starting from the end of the objid buffer. + * When the top of the MIB tree is reached, the buffer is adjusted. + * + * The buffer length is set to the number of subidentifiers + * for the object identifier associated with the MIB node. + * + * @return the number of subidentifiers copied. + * + * If 0 is returned, the objid buffer is too small, + * and the buffer contents are indeterminate. + * The buffer length can be used to create a larger buffer. + */ +static int +node_to_oid(struct tree *tp, oid * objid, size_t * objidlen) +{ + int numids, lenids; + oid *op; + + if (!tp || !objid || !objidlen) + return 0; + + lenids = (int) *objidlen; + op = objid + lenids; /* points after the last element */ + + for (numids = 0; tp; tp = tp->parent, numids++) { + if (numids >= lenids) + continue; + --op; + *op = tp->subid; + } + + *objidlen = (size_t) numids; + if (numids > lenids) { + return 0; + } + + if (numids < lenids) + memmove(objid, op, numids * sizeof(oid)); + + return (numids); +} +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +/* + * Replace \x with x stop at eos_marker + * return NULL if eos_marker not found + */ +static char *_apply_escapes(char *src, char eos_marker) +{ + char *dst; + int backslash = 0; + + dst = src; + while (*src) { + if (backslash) { + backslash = 0; + *dst++ = *src; + } else { + if (eos_marker == *src) break; + if ('\\' == *src) { + backslash = 1; + } else { + *dst++ = *src; + } + } + src++; + } + if (!*src) { + /* never found eos_marker */ + return NULL; + } else { + *dst = 0; + return src; + } +} + +static int +#ifndef NETSNMP_DISABLE_MIB_LOADING +_add_strings_to_oid(struct tree *tp, char *cp, + oid * objid, size_t * objidlen, size_t maxlen) +#else +_add_strings_to_oid(void *tp, char *cp, + oid * objid, size_t * objidlen, size_t maxlen) +#endif /* NETSNMP_DISABLE_MIB_LOADING */ +{ + oid subid; + int len_index = 1000000; +#ifndef NETSNMP_DISABLE_MIB_LOADING + struct tree *tp2 = NULL; + struct index_list *in_dices = NULL; +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + char *fcp, *ecp, *cp2 = NULL; + char doingquote; + int len = -1, pos = -1; +#ifndef NETSNMP_DISABLE_MIB_LOADING + int check = + !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE); + int do_hint = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT); + + while (cp && tp && tp->child_list) { + fcp = cp; + tp2 = tp->child_list; + /* + * Isolate the next entry + */ + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = '\0'; + + /* + * Search for the appropriate child + */ + if (isdigit((unsigned char)(*cp))) { + subid = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + while (tp2 && tp2->subid != subid) + tp2 = tp2->next_peer; + } else { + while (tp2 && strcmp(tp2->label, fcp)) + tp2 = tp2->next_peer; + if (!tp2) + goto bad_id; + subid = tp2->subid; + } + if (*objidlen >= maxlen) + goto bad_id; + while (tp2 && tp2->next_peer && tp2->next_peer->subid == subid) + tp2 = tp2->next_peer; + objid[*objidlen] = subid; + (*objidlen)++; + + cp = cp2; + if (!tp2) + break; + tp = tp2; + } + + if (tp && !tp->child_list) { + if ((tp2 = tp->parent)) { + if (tp2->indexes) + in_dices = tp2->indexes; + else if (tp2->augments) { + tp2 = find_tree_node(tp2->augments, -1); + if (tp2) + in_dices = tp2->indexes; + } + } + tp = NULL; + } + + while (cp && in_dices) { + fcp = cp; + + tp = find_tree_node(in_dices->ilabel, -1); + if (!tp) + break; + switch (tp->type) { + case TYPE_INTEGER: + case TYPE_INTEGER32: + case TYPE_UINTEGER: + case TYPE_UNSIGNED32: + case TYPE_TIMETICKS: + /* + * Isolate the next entry + */ + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = '\0'; + if (isdigit((unsigned char)(*cp))) { + subid = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + } else { + if (tp->enums) { + struct enum_list *ep = tp->enums; + while (ep && strcmp(ep->label, cp)) + ep = ep->next; + if (!ep) + goto bad_id; + subid = ep->value; + } else + goto bad_id; + } + if (check && tp->ranges) { + struct range_list *rp = tp->ranges; + int ok = 0; + if (tp->type == TYPE_INTEGER || + tp->type == TYPE_INTEGER32) { + while (!ok && rp) { + if ((rp->low <= (int) subid) + && ((int) subid <= rp->high)) + ok = 1; + else + rp = rp->next; + } + } else { /* check unsigned range */ + while (!ok && rp) { + if (((unsigned int)rp->low <= subid) + && (subid <= (unsigned int)rp->high)) + ok = 1; + else + rp = rp->next; + } + } + if (!ok) + goto bad_id; + } + if (*objidlen >= maxlen) + goto bad_id; + objid[*objidlen] = subid; + (*objidlen)++; + break; + case TYPE_IPADDR: + if (*objidlen + 4 > maxlen) + goto bad_id; + for (subid = 0; cp && subid < 4; subid++) { + fcp = cp; + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + objid[*objidlen] = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (check && objid[*objidlen] > 255) + goto bad_id; + (*objidlen)++; + cp = cp2; + } + break; + case TYPE_OCTETSTR: + if (tp->ranges && !tp->ranges->next + && tp->ranges->low == tp->ranges->high) + len = tp->ranges->low; + else + len = -1; + pos = 0; + if (*cp == '"' || *cp == '\'') { + doingquote = *cp++; + /* + * insert length if requested + */ + if (!in_dices->isimplied && len == -1) { + if (doingquote == '\'') { + snmp_set_detail + ("'-quote is for fixed length strings"); + return 0; + } + if (*objidlen >= maxlen) + goto bad_id; + len_index = *objidlen; + (*objidlen)++; + } else if (doingquote == '"') { + snmp_set_detail + ("\"-quote is for variable length strings"); + return 0; + } + + cp2 = _apply_escapes(cp, doingquote); + if (!cp2) goto bad_id; + else { + unsigned char *new_val; + int new_val_len; + int parsed_hint = 0; + const char *parsed_value; + + if (do_hint && tp->hint) { + parsed_value = parse_octet_hint(tp->hint, cp, + &new_val, &new_val_len); + parsed_hint = parsed_value == NULL; + } + if (parsed_hint) { + int i; + for (i = 0; i < new_val_len; i++) { + if (*objidlen >= maxlen) goto bad_id; + objid[ *objidlen ] = new_val[i]; + (*objidlen)++; + pos++; + } + SNMP_FREE(new_val); + } else { + while(*cp) { + if (*objidlen >= maxlen) goto bad_id; + objid[ *objidlen ] = *cp++; + (*objidlen)++; + pos++; + } + } + } + + cp2++; + if (!*cp2) + cp2 = NULL; + else if (*cp2 != '.') + goto bad_id; + else + cp2++; + if (check) { + if (len == -1) { + struct range_list *rp = tp->ranges; + int ok = 0; + while (rp && !ok) + if (rp->low <= pos && pos <= rp->high) + ok = 1; + else + rp = rp->next; + if (!ok) + goto bad_id; + if (!in_dices->isimplied) + objid[len_index] = pos; + } else if (pos != len) + goto bad_id; + } + else if (len == -1 && !in_dices->isimplied) + objid[len_index] = pos; + } else { + if (!in_dices->isimplied && len == -1) { + fcp = cp; + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + len = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (*objidlen + len + 1 >= maxlen) + goto bad_id; + objid[*objidlen] = len; + (*objidlen)++; + cp = cp2; + } + while (len && cp) { + fcp = cp; + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + objid[*objidlen] = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (check && objid[*objidlen] > 255) + goto bad_id; + (*objidlen)++; + len--; + cp = cp2; + } + } + break; + case TYPE_OBJID: + in_dices = NULL; + cp2 = cp; + break; + case TYPE_NETADDR: + fcp = cp; + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + subid = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (*objidlen + 1 >= maxlen) + goto bad_id; + objid[*objidlen] = subid; + (*objidlen)++; + cp = cp2; + if (subid == 1) { + for (len = 0; cp && len < 4; len++) { + fcp = cp; + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + subid = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (*objidlen + 1 >= maxlen) + goto bad_id; + if (check && subid > 255) + goto bad_id; + objid[*objidlen] = subid; + (*objidlen)++; + cp = cp2; + } + } + else { + in_dices = NULL; + } + break; + default: + snmp_log(LOG_ERR, "Unexpected index type: %d %s %s\n", + tp->type, in_dices->ilabel, cp); + in_dices = NULL; + cp2 = cp; + break; + } + cp = cp2; + if (in_dices) + in_dices = in_dices->next; + } + +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + while (cp) { + fcp = cp; + switch (*cp) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + cp2 = strchr(cp, '.'); + if (cp2) + *cp2++ = 0; + subid = strtoul(cp, &ecp, 0); + if (*ecp) + goto bad_id; + if (*objidlen >= maxlen) + goto bad_id; + objid[*objidlen] = subid; + (*objidlen)++; + break; + case '"': + case '\'': + doingquote = *cp++; + /* + * insert length if requested + */ + if (doingquote == '"') { + if (*objidlen >= maxlen) + goto bad_id; + objid[*objidlen] = len = strchr(cp, doingquote) - cp; + (*objidlen)++; + } + + if (!cp) + goto bad_id; + while (*cp && *cp != doingquote) { + if (*objidlen >= maxlen) + goto bad_id; + objid[*objidlen] = *cp++; + (*objidlen)++; + } + cp2 = cp + 1; + if (!*cp2) + cp2 = NULL; + else if (*cp2 == '.') + cp2++; + else + goto bad_id; + break; + default: + goto bad_id; + } + cp = cp2; + } + return 1; + + bad_id: + { + char buf[256]; +#ifndef NETSNMP_DISABLE_MIB_LOADING + if (in_dices) + snprintf(buf, sizeof(buf), "Index out of range: %s (%s)", + fcp, in_dices->ilabel); + else if (tp) + snprintf(buf, sizeof(buf), "Sub-id not found: %s -> %s", tp->label, fcp); + else +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + snprintf(buf, sizeof(buf), "%s", fcp); + buf[ sizeof(buf)-1 ] = 0; + + snmp_set_detail(buf); + } + return 0; +} + + +#ifndef NETSNMP_DISABLE_MIB_LOADING +/** + * @see comments on find_best_tree_node for usage after first time. + */ +int +get_wild_node(const char *name, oid * objid, size_t * objidlen) +{ + struct tree *tp = find_best_tree_node(name, tree_head, NULL); + if (!tp) + return 0; + return get_node(tp->label, objid, objidlen); +} + +int +get_node(const char *name, oid * objid, size_t * objidlen) +{ + const char *cp; + char ch; + int res; + + cp = name; + while ((ch = *cp)) + if (('0' <= ch && ch <= '9') + || ('a' <= ch && ch <= 'z') + || ('A' <= ch && ch <= 'Z') + || ch == '-') + cp++; + else + break; + if (ch != ':') + if (*name == '.') + res = get_module_node(name + 1, "ANY", objid, objidlen); + else + res = get_module_node(name, "ANY", objid, objidlen); + else { + char *module; + /* + * requested name is of the form + * "module:subidentifier" + */ + module = (char *) malloc((size_t) (cp - name + 1)); + if (!module) + return SNMPERR_GENERR; + sprintf(module, "%.*s", (int) (cp - name), name); + cp++; /* cp now point to the subidentifier */ + if (*cp == ':') + cp++; + + /* + * 'cp' and 'name' *do* go that way round! + */ + res = get_module_node(cp, module, objid, objidlen); + SNMP_FREE(module); + } + if (res == 0) { + SET_SNMP_ERROR(SNMPERR_UNKNOWN_OBJID); + } + + return res; +} +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +#ifdef testing + +main(int argc, char *argv[]) +{ + oid objid[MAX_OID_LEN]; + int objidlen = MAX_OID_LEN; + int count; + netsnmp_variable_list variable; + + netsnmp_init_mib(); + if (argc < 2) + print_subtree(stdout, tree_head, 0); + variable.type = ASN_INTEGER; + variable.val.integer = 3; + variable.val_len = 4; + for (argc--; argc; argc--, argv++) { + objidlen = MAX_OID_LEN; + printf("read_objid(%s) = %d\n", + argv[1], read_objid(argv[1], objid, &objidlen)); + for (count = 0; count < objidlen; count++) + printf("%d.", objid[count]); + printf("\n"); + print_variable(objid, objidlen, &variable); + } +} + +#endif /* testing */ + +#ifndef NETSNMP_DISABLE_MIB_LOADING +/* + * initialize: no peers included in the report. + */ +void +clear_tree_flags(register struct tree *tp) +{ + for (; tp; tp = tp->next_peer) { + tp->reported = 0; + if (tp->child_list) + clear_tree_flags(tp->child_list); + /*RECURSE*/} +} + +/* + * Update: 1998-07-17 <jhy@gsu.edu> + * Added print_oid_report* functions. + */ +static int print_subtree_oid_report_labeledoid = 0; +static int print_subtree_oid_report_oid = 0; +static int print_subtree_oid_report_symbolic = 0; +static int print_subtree_oid_report_mibchildoid = 0; +static int print_subtree_oid_report_suffix = 0; + +/* + * These methods recurse. + */ +static void print_parent_labeledoid(FILE *, struct tree *); +static void print_parent_oid(FILE *, struct tree *); +static void print_parent_mibchildoid(FILE *, struct tree *); +static void print_parent_label(FILE *, struct tree *); +static void print_subtree_oid_report(FILE *, struct tree *, int); + + +void +print_oid_report(FILE * fp) +{ + struct tree *tp; + clear_tree_flags(tree_head); + for (tp = tree_head; tp; tp = tp->next_peer) + print_subtree_oid_report(fp, tp, 0); +} + +void +print_oid_report_enable_labeledoid(void) +{ + print_subtree_oid_report_labeledoid = 1; +} + +void +print_oid_report_enable_oid(void) +{ + print_subtree_oid_report_oid = 1; +} + +void +print_oid_report_enable_suffix(void) +{ + print_subtree_oid_report_suffix = 1; +} + +void +print_oid_report_enable_symbolic(void) +{ + print_subtree_oid_report_symbolic = 1; +} + +void +print_oid_report_enable_mibchildoid(void) +{ + print_subtree_oid_report_mibchildoid = 1; +} + +/* + * helper methods for print_subtree_oid_report() + * each one traverses back up the node tree + * until there is no parent. Then, the label combination + * is output, such that the parent is displayed first. + * + * Warning: these methods are all recursive. + */ + +static void +print_parent_labeledoid(FILE * f, struct tree *tp) +{ + if (tp) { + if (tp->parent) { + print_parent_labeledoid(f, tp->parent); + /*RECURSE*/} + fprintf(f, ".%s(%lu)", tp->label, tp->subid); + } +} + +static void +print_parent_oid(FILE * f, struct tree *tp) +{ + if (tp) { + if (tp->parent) { + print_parent_oid(f, tp->parent); + /*RECURSE*/} + fprintf(f, ".%lu", tp->subid); + } +} + + +static void print_parent_mibchildoid(FILE * f, struct tree *tp) +{ + static struct tree *temp; + unsigned long elems[100]; + int elem_cnt = 0; + int i = 0; + temp = tp; + if (temp) { + while (temp->parent) { + elems[elem_cnt++] = temp->subid; + temp = temp->parent; + } + elems[elem_cnt++] = temp->subid; + } + for (i = elem_cnt - 1; i >= 0; i--) { + if (i == elem_cnt - 1) { + fprintf(f, "%lu", elems[i]); + } else { + fprintf(f, ".%lu", elems[i]); + } + } +} + +static void +print_parent_label(FILE * f, struct tree *tp) +{ + if (tp) { + if (tp->parent) { + print_parent_label(f, tp->parent); + /*RECURSE*/} + fprintf(f, ".%s", tp->label); + } +} + +/** + * @internal + * This methods generates variations on the original print_subtree() report. + * Traverse the tree depth first, from least to greatest sub-identifier. + * Warning: this methods recurses and calls methods that recurse. + * + * @param f File descriptor to print to. + * @param tree ??? + * @param count ??? + */ + +static void +print_subtree_oid_report(FILE * f, struct tree *tree, int count) +{ + struct tree *tp; + + count++; + + /* + * sanity check + */ + if (!tree) { + return; + } + + /* + * find the not reported peer with the lowest sub-identifier. + * if no more, break the loop and cleanup. + * set "reported" flag, and create report for this peer. + * recurse using the children of this peer, if any. + */ + while (1) { + register struct tree *ntp; + + tp = NULL; + for (ntp = tree->child_list; ntp; ntp = ntp->next_peer) { + if (ntp->reported) + continue; + + if (!tp || (tp->subid > ntp->subid)) + tp = ntp; + } + if (!tp) + break; + + tp->reported = 1; + + if (print_subtree_oid_report_labeledoid) { + print_parent_labeledoid(f, tp); + fprintf(f, "\n"); + } + if (print_subtree_oid_report_oid) { + print_parent_oid(f, tp); + fprintf(f, "\n"); + } + if (print_subtree_oid_report_symbolic) { + print_parent_label(f, tp); + fprintf(f, "\n"); + } + if (print_subtree_oid_report_mibchildoid) { + fprintf(f, "\"%s\"\t", tp->label); + fprintf(f, "\t\t\""); + print_parent_mibchildoid(f, tp); + fprintf(f, "\"\n"); + } + if (print_subtree_oid_report_suffix) { + int i; + for (i = 0; i < count; i++) + fprintf(f, " "); + fprintf(f, "%s(%ld) type=%d", tp->label, tp->subid, tp->type); + if (tp->tc_index != -1) + fprintf(f, " tc=%d", tp->tc_index); + if (tp->hint) + fprintf(f, " hint=%s", tp->hint); + if (tp->units) + fprintf(f, " units=%s", tp->units); + + fprintf(f, "\n"); + } + print_subtree_oid_report(f, tp, count); + /*RECURSE*/} +} +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + + +/** + * Converts timeticks to hours, minutes, seconds string. + * + * @param timeticks The timeticks to convert. + * @param buf Buffer to write to, has to be at + * least 40 Bytes large. + * + * @return The buffer + * + * @see uptimeString + */ +char * +uptime_string(u_long timeticks, char *buf) +{ + return uptime_string_n( timeticks, buf, 40); +} + +char * +uptime_string_n(u_long timeticks, char *buf, size_t buflen) +{ + uptimeString(timeticks, buf, buflen); + return buf; +} + +/** + * Given a string, parses an oid out of it (if possible). + * It will try to parse it based on predetermined configuration if + * present or by every method possible otherwise. + * If a suffix has been registered using NETSNMP_DS_LIB_OIDSUFFIX, it + * will be appended to the input string before processing. + * + * @param argv The OID to string parse + * @param root An OID array where the results are stored. + * @param rootlen The max length of the array going in and the data + * length coming out. + * + * @return The root oid pointer if successful, or NULL otherwise. + */ + +oid * +snmp_parse_oid(const char *argv, oid * root, size_t * rootlen) +{ + size_t savlen = *rootlen; + static size_t tmpbuf_len = 0; + static char *tmpbuf; + const char *suffix, *prefix; + + suffix = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OIDSUFFIX); + prefix = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_OIDPREFIX); + if ((suffix && suffix[0]) || (prefix && prefix[0])) { + if (!suffix) + suffix = ""; + if (!prefix) + prefix = ""; + if ((strlen(suffix) + strlen(prefix) + strlen(argv) + 2) > tmpbuf_len) { + tmpbuf_len = strlen(suffix) + strlen(argv) + strlen(prefix) + 2; + tmpbuf = (char *)realloc(tmpbuf, tmpbuf_len); + } + snprintf(tmpbuf, tmpbuf_len, "%s%s%s%s", prefix, argv, + ((suffix[0] == '.' || suffix[0] == '\0') ? "" : "."), + suffix); + argv = tmpbuf; + DEBUGMSGTL(("snmp_parse_oid","Parsing: %s\n",argv)); + } + +#ifndef NETSNMP_DISABLE_MIB_LOADING + if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RANDOM_ACCESS) + || strchr(argv, ':')) { + if (get_node(argv, root, rootlen)) { + return root; + } + } else if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REGEX_ACCESS)) { + clear_tree_flags(tree_head); + if (get_wild_node(argv, root, rootlen)) { + return root; + } + } else { +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + if (read_objid(argv, root, rootlen)) { + return root; + } +#ifndef NETSNMP_DISABLE_MIB_LOADING + *rootlen = savlen; + if (get_node(argv, root, rootlen)) { + return root; + } + *rootlen = savlen; + DEBUGMSGTL(("parse_oid", "wildly parsing\n")); + clear_tree_flags(tree_head); + if (get_wild_node(argv, root, rootlen)) { + return root; + } + } +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + return NULL; +} + +#ifndef NETSNMP_DISABLE_MIB_LOADING +/* + * Use DISPLAY-HINT to parse a value into an octet string. + * + * note that "1d1d", "11" could have come from an octet string that + * looked like { 1, 1 } or an octet string that looked like { 11 } + * because of this, it's doubtful that anyone would use such a display + * string. Therefore, the parser ignores this case. + */ + +struct parse_hints { + int length; + int repeat; + int format; + int separator; + int terminator; + unsigned char *result; + int result_max; + int result_len; +}; + +static void parse_hints_reset(struct parse_hints *ph) +{ + ph->length = 0; + ph->repeat = 0; + ph->format = 0; + ph->separator = 0; + ph->terminator = 0; +} + +static void parse_hints_ctor(struct parse_hints *ph) +{ + parse_hints_reset(ph); + ph->result = NULL; + ph->result_max = 0; + ph->result_len = 0; +} + +static int parse_hints_add_result_octet(struct parse_hints *ph, unsigned char octet) +{ + if (!(ph->result_len < ph->result_max)) { + ph->result_max = ph->result_len + 32; + if (!ph->result) { + ph->result = (unsigned char *)malloc(ph->result_max); + } else { + ph->result = (unsigned char *)realloc(ph->result, ph->result_max); + } + } + + if (!ph->result) { + return 0; /* failed */ + } + + ph->result[ph->result_len++] = octet; + return 1; /* success */ +} + +static int parse_hints_parse(struct parse_hints *ph, const char **v_in_out) +{ + const char *v = *v_in_out; + char *nv; + int base; + int repeats = 0; + int repeat_fixup = ph->result_len; + + if (ph->repeat) { + if (!parse_hints_add_result_octet(ph, 0)) { + return 0; + } + } + do { + base = 0; + switch (ph->format) { + case 'x': base += 6; /* fall through */ + case 'd': base += 2; /* fall through */ + case 'o': base += 8; /* fall through */ + { + int i; + unsigned long number = strtol(v, &nv, base); + if (nv == v) return 0; + v = nv; + for (i = 0; i < ph->length; i++) { + int shift = 8 * (ph->length - 1 - i); + if (!parse_hints_add_result_octet(ph, (u_char)(number >> shift) )) { + return 0; /* failed */ + } + } + } + break; + + case 'a': + { + int i; + + for (i = 0; i < ph->length && *v; i++) { + if (!parse_hints_add_result_octet(ph, *v++)) { + return 0; /* failed */ + } + } + } + break; + } + + repeats++; + + if (ph->separator && *v) { + if (*v == ph->separator) { + v++; + } else { + return 0; /* failed */ + } + } + + if (ph->terminator) { + if (*v == ph->terminator) { + v++; + break; + } + } + } while (ph->repeat && *v); + if (ph->repeat) { + ph->result[repeat_fixup] = repeats; + } + + *v_in_out = v; + return 1; +} + +static void parse_hints_length_add_digit(struct parse_hints *ph, int digit) +{ + ph->length *= 10; + ph->length += digit - '0'; +} + +const char *parse_octet_hint(const char *hint, const char *value, unsigned char **new_val, int *new_val_len) +{ + const char *h = hint; + const char *v = value; + struct parse_hints ph; + int retval = 1; + /* See RFC 1443 */ + enum { + HINT_1_2, + HINT_2_3, + HINT_1_2_4, + HINT_1_2_5 + } state = HINT_1_2; + + parse_hints_ctor(&ph); + while (*h && *v && retval) { + switch (state) { + case HINT_1_2: + if ('*' == *h) { + ph.repeat = 1; + state = HINT_2_3; + } else if (isdigit((unsigned char)(*h))) { + parse_hints_length_add_digit(&ph, *h); + state = HINT_2_3; + } else { + return v; /* failed */ + } + break; + + case HINT_2_3: + if (isdigit((unsigned char)(*h))) { + parse_hints_length_add_digit(&ph, *h); + /* state = HINT_2_3 */ + } else if ('x' == *h || 'd' == *h || 'o' == *h || 'a' == *h) { + ph.format = *h; + state = HINT_1_2_4; + } else { + return v; /* failed */ + } + break; + + case HINT_1_2_4: + if ('*' == *h) { + retval = parse_hints_parse(&ph, &v); + parse_hints_reset(&ph); + + ph.repeat = 1; + state = HINT_2_3; + } else if (isdigit((unsigned char)(*h))) { + retval = parse_hints_parse(&ph, &v); + parse_hints_reset(&ph); + + parse_hints_length_add_digit(&ph, *h); + state = HINT_2_3; + } else { + ph.separator = *h; + state = HINT_1_2_5; + } + break; + + case HINT_1_2_5: + if ('*' == *h) { + retval = parse_hints_parse(&ph, &v); + parse_hints_reset(&ph); + + ph.repeat = 1; + state = HINT_2_3; + } else if (isdigit((unsigned char)(*h))) { + retval = parse_hints_parse(&ph, &v); + parse_hints_reset(&ph); + + parse_hints_length_add_digit(&ph, *h); + state = HINT_2_3; + } else { + ph.terminator = *h; + + retval = parse_hints_parse(&ph, &v); + parse_hints_reset(&ph); + + state = HINT_1_2; + } + break; + } + h++; + } + while (*v && retval) { + retval = parse_hints_parse(&ph, &v); + } + if (retval) { + *new_val = ph.result; + *new_val_len = ph.result_len; + } else { + if (ph.result) { + SNMP_FREE(ph.result); + } + *new_val = NULL; + *new_val_len = 0; + } + return retval ? NULL : v; +} +#endif /* NETSNMP_DISABLE_MIB_LOADING */ + +#ifdef test_display_hint + +int main(int argc, const char **argv) +{ + const char *hint; + const char *value; + unsigned char *new_val; + int new_val_len; + char *r; + + if (argc < 3) { + fprintf(stderr, "usage: dh <hint> <value>\n"); + exit(2); + } + hint = argv[1]; + value = argv[2]; + r = parse_octet_hint(hint, value, &new_val, &new_val_len); + printf("{\"%s\", \"%s\"}: \n\t", hint, value); + if (r) { + *r = 0; + printf("returned failed\n"); + printf("value syntax error at: %s\n", value); + } + else { + int i; + printf("returned success\n"); + for (i = 0; i < new_val_len; i++) { + int c = new_val[i] & 0xFF; + printf("%02X(%c) ", c, isprint(c) ? c : ' '); + } + SNMP_FREE(new_val); + } + printf("\n"); + exit(0); +} + +#endif /* test_display_hint */ + +#ifndef NETSNMP_FEATURE_REMOVE_MIB_TO_ASN_TYPE +u_char +mib_to_asn_type(int mib_type) +{ + switch (mib_type) { + case TYPE_OBJID: + return ASN_OBJECT_ID; + + case TYPE_OCTETSTR: + return ASN_OCTET_STR; + + case TYPE_NETADDR: + case TYPE_IPADDR: + return ASN_IPADDRESS; + + case TYPE_INTEGER32: + case TYPE_INTEGER: + return ASN_INTEGER; + + case TYPE_COUNTER: + return ASN_COUNTER; + + case TYPE_GAUGE: + return ASN_GAUGE; + + case TYPE_TIMETICKS: + return ASN_TIMETICKS; + + case TYPE_OPAQUE: + return ASN_OPAQUE; + + case TYPE_NULL: + return ASN_NULL; + + case TYPE_COUNTER64: + return ASN_COUNTER64; + + case TYPE_BITSTRING: + return ASN_BIT_STR; + + case TYPE_UINTEGER: + case TYPE_UNSIGNED32: + return ASN_UNSIGNED; + + case TYPE_NSAPADDRESS: + return ASN_NSAP; + + } + return -1; +} +#endif /* NETSNMP_FEATURE_REMOVE_MIB_TO_ASN_TYPE */ + +/** + * Converts a string to its OID form. + * in example "hello" = 5 . 'h' . 'e' . 'l' . 'l' . 'o' + * + * @param S The string. + * @param O The oid. + * @param L The length of the oid. + * + * @return 0 on Sucess, 1 on failure. + */ +#ifndef NETSNMP_FEATURE_REMOVE_MIB_STRING_CONVERSIONS +int +netsnmp_str2oid(const char *S, oid * O, int L) +{ + const char *c = S; + oid *o = &O[1]; + + --L; /* leave room for length prefix */ + + for (; *c && L; --L, ++o, ++c) + *o = *c; + + /* + * make sure we got to the end of the string + */ + if (*c != 0) + return 1; + + /* + * set the length of the oid + */ + *O = c - S; + + return 0; +} + +/** + * Converts an OID to its character form. + * in example 5 . 1 . 2 . 3 . 4 . 5 = 12345 + * + * @param C The character buffer. + * @param L The length of the buffer. + * @param O The oid. + * + * @return 0 on Sucess, 1 on failure. + */ +int +netsnmp_oid2chars(char *C, int L, const oid * O) +{ + char *c = C; + const oid *o = &O[1]; + + if (L < (int)*O) + return 1; + + L = *O; /** length */ + for (; L; --L, ++o, ++c) { + if (*o > 0xFF) + return 1; + *c = (char)*o; + } + return 0; +} + +/** + * Converts an OID to its string form. + * in example 5 . 'h' . 'e' . 'l' . 'l' . 'o' = "hello\0" (null terminated) + * + * @param S The character string buffer. + * @param L The length of the string buffer. + * @param O The oid. + * + * @return 0 on Sucess, 1 on failure. + */ +int +netsnmp_oid2str(char *S, int L, oid * O) +{ + int rc; + + if (L <= (int)*O) + return 1; + + rc = netsnmp_oid2chars(S, L, O); + if (rc) + return 1; + + S[ *O ] = 0; + + return 0; +} +#endif /* NETSNMP_FEATURE_REMOVE_MIB_STRING_CONVERSIONS */ + + +#ifndef NETSNMP_FEATURE_REMOVE_MIB_SNPRINT +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) +{ + size_t out_len = 0; + if (sprint_realloc_by_type((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +int +snprint_hexstring(char *buf, size_t buf_len, const u_char * cp, size_t len) +{ + size_t out_len = 0; + if (sprint_realloc_hexstring((u_char **) & buf, &buf_len, &out_len, 0, + cp, len)) + return (int) out_len; + else + return -1; +} + +int +snprint_asciistring(char *buf, size_t buf_len, + const u_char * cp, size_t len) +{ + size_t out_len = 0; + if (sprint_realloc_asciistring + ((u_char **) & buf, &buf_len, &out_len, 0, cp, len)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_octet_string + ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint, + units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_opaque((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_object_identifier + ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint, + units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_timeticks((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +int +snprint_hinted_integer(char *buf, size_t buf_len, + long val, const char *hint, const char *units) +{ + size_t out_len = 0; + if (sprint_realloc_hinted_integer + ((u_char **) & buf, &buf_len, &out_len, 0, val, 'd', hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_integer((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_uinteger((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_gauge((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_counter((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_networkaddress + ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint, + units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_ipaddress((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_null((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_bitstring((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_nsapaddress + ((u_char **) & buf, &buf_len, &out_len, 0, var, enums, hint, + units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_counter64((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_badtype((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES +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) +{ + size_t out_len = 0; + if (sprint_realloc_float((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} + +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) +{ + size_t out_len = 0; + if (sprint_realloc_double((u_char **) & buf, &buf_len, &out_len, 0, + var, enums, hint, units)) + return (int) out_len; + else + return -1; +} +#endif +#endif /* NETSNMP_FEATURE_REMOVE_MIB_SNPRINT */ +/** @} */ + |