Path: blob/main/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
106138 views
/*-1* Copyright (c) 2005-2006 The FreeBSD Project2* All rights reserved.3*4* Author: Shteryana Shopova <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*28* Helper functions for snmp client tools29*/3031#include <sys/param.h>32#include <sys/queue.h>33#include <sys/uio.h>3435#include <assert.h>36#include <ctype.h>37#include <err.h>38#include <errno.h>39#include <fcntl.h>40#include <stdio.h>41#include <stdlib.h>42#include <string.h>43#include <syslog.h>44#include <unistd.h>4546#include <bsnmp/asn1.h>47#include <bsnmp/snmp.h>48#include <bsnmp/snmpclient.h>49#include "bsnmptc.h"50#include "bsnmptools.h"5152/* Internal variable to turn on library debugging for testing and to53* find bugs. It is not exported via the header file.54* XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */55int _bsnmptools_debug = 0;5657/* Default files to import mapping from if none explicitly provided. */58#define bsnmpd_defs "/usr/share/snmp/defs/tree.def"59#define mibII_defs "/usr/share/snmp/defs/mibII_tree.def"6061/*62* The .iso.org.dod oid that has to be prepended to every OID when requesting63* a value.64*/65const struct asn_oid IsoOrgDod_OID = {663, { 1, 3, 6 }67};686970#define SNMP_ERR_UNKNOWN 07172/*73* An array of error strings corresponding to error definitions from libbsnmp.74*/75static const struct {76const char *str;77int32_t error;78} error_strings[] = {79{ "Unknown", SNMP_ERR_UNKNOWN },80{ "Too big ", SNMP_ERR_TOOBIG },81{ "No such Name", SNMP_ERR_NOSUCHNAME },82{ "Bad Value", SNMP_ERR_BADVALUE },83{ "Readonly", SNMP_ERR_READONLY },84{ "General error", SNMP_ERR_GENERR },85{ "No access", SNMP_ERR_NO_ACCESS },86{ "Wrong type", SNMP_ERR_WRONG_TYPE },87{ "Wrong length", SNMP_ERR_WRONG_LENGTH },88{ "Wrong encoding", SNMP_ERR_WRONG_ENCODING },89{ "Wrong value", SNMP_ERR_WRONG_VALUE },90{ "No creation", SNMP_ERR_NO_CREATION },91{ "Inconsistent value", SNMP_ERR_INCONS_VALUE },92{ "Resource unavailable", SNMP_ERR_RES_UNAVAIL },93{ "Commit failed", SNMP_ERR_COMMIT_FAILED },94{ "Undo failed", SNMP_ERR_UNDO_FAILED },95{ "Authorization error", SNMP_ERR_AUTH_ERR },96{ "Not writable", SNMP_ERR_NOT_WRITEABLE },97{ "Inconsistent name", SNMP_ERR_INCONS_NAME },98{ NULL, 0 }99};100101/* This one and any following are exceptions. */102#define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT103104static const struct {105const char *str;106enum snmp_syntax stx;107} syntax_strings[] = {108{ "Null", SNMP_SYNTAX_NULL },109{ "Integer", SNMP_SYNTAX_INTEGER },110{ "OctetString", SNMP_SYNTAX_OCTETSTRING },111{ "OID", SNMP_SYNTAX_OID },112{ "IpAddress", SNMP_SYNTAX_IPADDRESS },113{ "Counter32", SNMP_SYNTAX_COUNTER },114{ "Gauge", SNMP_SYNTAX_GAUGE },115{ "TimeTicks", SNMP_SYNTAX_TIMETICKS },116{ "Counter64", SNMP_SYNTAX_COUNTER64 },117{ "Unknown", SNMP_SYNTAX_UNKNOWN },118};119120int121snmptool_init(struct snmp_toolinfo *snmptoolctx)122{123char *str;124size_t slen;125126memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));127snmptoolctx->objects = 0;128snmptoolctx->mappings = NULL;129snmptoolctx->flags = SNMP_PDU_GET; /* XXX */130SLIST_INIT(&snmptoolctx->filelist);131snmp_client_init(&snmp_client);132SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS);133134if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)135warnx("Error adding file %s to list", bsnmpd_defs);136137if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)138warnx("Error adding file %s to list", mibII_defs);139140/* Read the environment */141if ((str = getenv("SNMPAUTH")) != NULL) {142slen = strlen(str);143if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)144snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;145else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)146snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;147else if (slen != 0)148warnx("Bad authentication type - %s in SNMPAUTH", str);149}150151if ((str = getenv("SNMPPRIV")) != NULL) {152slen = strlen(str);153if (slen == strlen("des") && strcasecmp(str, "des") == 0)154snmp_client.user.priv_proto = SNMP_PRIV_DES;155else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)156snmp_client.user.priv_proto = SNMP_PRIV_AES;157else if (slen != 0)158warnx("Bad privacy type - %s in SNMPPRIV", str);159}160161if ((str = getenv("SNMPUSER")) != NULL) {162if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {163warnx("Username too long - %s in SNMPUSER", str);164return (-1);165}166if (slen > 0) {167strlcpy(snmp_client.user.sec_name, str,168sizeof(snmp_client.user.sec_name));169snmp_client.version = SNMP_V3;170}171}172173if ((str = getenv("SNMPPASSWD")) != NULL) {174if ((slen = strlen(str)) > MAXSTR)175slen = MAXSTR - 1;176if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {177warn("malloc() failed");178return (-1);179}180strlcpy(snmptoolctx->passwd, str, slen + 1);181}182183return (0);184}185186#define OBJECT_IDX_LIST(o) o->info->table_idx->index_list187188/*189* Walk through the file list and import string<->oid mappings from each file.190*/191int32_t192snmp_import_all(struct snmp_toolinfo *snmptoolctx)193{194int32_t fc;195struct fname *tmp;196197if (snmptoolctx == NULL)198return (-1);199200if (ISSET_NUMERIC(snmptoolctx))201return (0);202203if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)204return (-1);205206fc = 0;207if (SLIST_EMPTY(&snmptoolctx->filelist)) {208warnx("No files to read OID <-> string conversions from");209return (-1);210} else {211SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {212if (tmp->done)213continue;214if (snmp_import_file(snmptoolctx, tmp) < 0) {215fc = -1;216break;217}218fc++;219}220}221222snmp_mapping_dump(snmptoolctx);223return (fc);224}225226/*227* Add a filename to the file list - the initial idea of keeping a list with all228* files to read OIDs from was that an application might want to have loaded in229* memory the OIDs from a single file only and when done with them read the OIDs230* from another file. This is not used yet but might be a good idea at some231* point. Size argument is number of bytes in string including trailing '\0',232* not string length.233*/234int32_t235add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,236const struct asn_oid *cut, int32_t done)237{238char *fstring;239struct fname *entry;240241if (snmptoolctx == NULL)242return (-1);243244/* Make sure file was not in list. */245SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {246if (strncmp(entry->name, filename, strlen(entry->name)) == 0)247return (0);248}249250if ((fstring = strdup(filename)) == NULL) {251warn("strdup() failed");252return (-1);253}254255if ((entry = calloc(1, sizeof(struct fname))) == NULL) {256warn("calloc() failed");257free(fstring);258return (-1);259}260261if (cut != NULL)262asn_append_oid(&(entry->cut), cut);263entry->name = fstring;264entry->done = done;265SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);266267return (1);268}269270void271free_filelist(struct snmp_toolinfo *snmptoolctx)272{273struct fname *f;274275if (snmptoolctx == NULL)276return; /* XXX error handling */277278while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {279SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);280if (f->name)281free(f->name);282free(f);283}284}285286static char287isvalid_fchar(char c, int pos)288{289if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||290(pos != 0 && isdigit(c))){291return (c);292}293294if (c == '\0')295return (0);296297if (!isascii(c) || !isprint(c))298warnx("Unexpected character %#2x", (u_int) c);299else300warnx("Illegal character '%c'", c);301302return (-1);303}304305/*306* Re-implement getsubopt from scratch, because the second argument is broken307* and will not compile with WARNS=5.308* Copied from src/contrib/bsnmp/snmpd/main.c.309*/310static int311getsubopt1(char **arg, const char *const *options, char **valp, char **optp)312{313static const char *const delim = ",\t ";314u_int i;315char *ptr;316317*optp = NULL;318319/* Skip leading junk. */320for (ptr = *arg; *ptr != '\0'; ptr++)321if (strchr(delim, *ptr) == NULL)322break;323if (*ptr == '\0') {324*arg = ptr;325return (-1);326}327*optp = ptr;328329/* Find the end of the option. */330while (*++ptr != '\0')331if (strchr(delim, *ptr) != NULL || *ptr == '=')332break;333334if (*ptr != '\0') {335if (*ptr == '=') {336*ptr++ = '\0';337*valp = ptr;338while (*ptr != '\0' && strchr(delim, *ptr) == NULL)339ptr++;340if (*ptr != '\0')341*ptr++ = '\0';342} else343*ptr++ = '\0';344}345346*arg = ptr;347348for (i = 0; *options != NULL; options++, i++)349if (strcmp(*optp, *options) == 0)350return (i);351return (-1);352}353354static int32_t355parse_path(char *value)356{357int32_t i, len;358359if (value == NULL)360return (-1);361362for (len = 0; len < MAXPATHLEN; len++) {363i = isvalid_fchar(*(value + len), len) ;364365if (i == 0)366break;367else if (i < 0)368return (-1);369}370371if (len >= MAXPATHLEN || value[len] != '\0') {372warnx("Bad pathname - '%s'", value);373return (-1);374}375376return (len);377}378379static int32_t380parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,381const struct asn_oid *cut)382{383int32_t namelen;384char filename[MAXPATHLEN + 1];385386if (value == NULL)387return (-1);388389do {390memset(filename, 0, MAXPATHLEN + 1);391392if (isalpha(*value) && (path == NULL || path[0] == '\0')) {393strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);394namelen = strlen(SNMP_DEFS_DIR);395} else if (path != NULL){396strlcpy(filename, path, MAXPATHLEN + 1);397namelen = strlen(path);398} else399namelen = 0;400401for ( ; namelen < MAXPATHLEN; value++) {402if (isvalid_fchar(*value, namelen) > 0) {403filename[namelen++] = *value;404continue;405}406407if (*value == ',' )408value++;409else if (*value == '\0')410;411else {412if (!isascii(*value) || !isprint(*value))413warnx("Unexpected character %#2x in"414" filename", (u_int) *value);415else416warnx("Illegal character '%c' in"417" filename", *value);418return (-1);419}420421filename[namelen]='\0';422break;423}424425if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {426warnx("Filename %s too long", filename);427return (-1);428}429430if (add_filename(snmptoolctx, filename, cut, 0) < 0) {431warnx("Error adding file %s to list", filename);432return (-1);433}434} while (*value != '\0');435436return(1);437}438439static int32_t440parse_ascii(char *ascii, uint8_t *binstr, size_t binlen)441{442char dptr[3];443size_t count;444int32_t alen, i, saved_errno;445uint32_t val;446447/* Filter 0x at the beginning */448if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')449i = 2;450else451i = 0;452453saved_errno = errno;454errno = 0;455for (count = 0; i < alen; i += 2) {456/* XXX: consider strlen(ascii) % 2 != 0 */457dptr[0] = ascii[i];458dptr[1] = ascii[i + 1];459dptr[2] = '\0';460if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {461errno = saved_errno;462return (-1);463}464binstr[count] = (uint8_t) val;465if (++count >= binlen) {466warnx("Key %s too long - truncating to %zu octets",467ascii, binlen);468break;469}470}471472return (count);473}474475/*476* Functions to parse common input options for client tools and fill in the477* snmp_client structure.478*/479int32_t480parse_authentication(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)481{482int32_t /* count, */ subopt;483char *val, *option;484const char *const subopts[] = {485"proto",486"key",487NULL488};489490assert(opt_arg != NULL);491/* count = 1; */492while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {493switch (subopt) {494case 0:495if (val == NULL) {496warnx("Suboption 'proto' requires an argument");497return (-1);498}499if (strlen(val) != 3) {500warnx("Unknown auth protocol - %s", val);501return (-1);502}503if (strncasecmp("md5", val, strlen("md5")) == 0)504snmp_client.user.auth_proto =505SNMP_AUTH_HMAC_MD5;506else if (strncasecmp("sha", val, strlen("sha")) == 0)507snmp_client.user.auth_proto =508SNMP_AUTH_HMAC_SHA;509else {510warnx("Unknown auth protocol - %s", val);511return (-1);512}513break;514case 1:515if (val == NULL) {516warnx("Suboption 'key' requires an argument");517return (-1);518}519if (parse_ascii(val, snmp_client.user.auth_key,520SNMP_AUTH_KEY_SIZ) < 0) {521warnx("Bad authentication key- %s", val);522return (-1);523}524break;525default:526warnx("Unknown suboption - '%s'", suboptarg);527return (-1);528}529/* count += 1; */530}531return (2/* count */);532}533534int32_t535parse_privacy(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)536{537int32_t /* count, */ subopt;538char *val, *option;539const char *const subopts[] = {540"proto",541"key",542NULL543};544545assert(opt_arg != NULL);546/* count = 1; */547while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {548switch (subopt) {549case 0:550if (val == NULL) {551warnx("Suboption 'proto' requires an argument");552return (-1);553}554if (strlen(val) != 3) {555warnx("Unknown privacy protocol - %s", val);556return (-1);557}558if (strncasecmp("aes", val, strlen("aes")) == 0)559snmp_client.user.priv_proto = SNMP_PRIV_AES;560else if (strncasecmp("des", val, strlen("des")) == 0)561snmp_client.user.priv_proto = SNMP_PRIV_DES;562else {563warnx("Unknown privacy protocol - %s", val);564return (-1);565}566break;567case 1:568if (val == NULL) {569warnx("Suboption 'key' requires an argument");570return (-1);571}572if (parse_ascii(val, snmp_client.user.priv_key,573SNMP_PRIV_KEY_SIZ) < 0) {574warnx("Bad privacy key- %s", val);575return (-1);576}577break;578default:579warnx("Unknown suboption - '%s'", suboptarg);580return (-1);581}582/* count += 1; */583}584return (2/* count */);585}586587int32_t588parse_context(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)589{590int32_t /* count, */ subopt;591char *val, *option;592const char *const subopts[] = {593"context",594"context-engine",595NULL596};597598assert(opt_arg != NULL);599/* count = 1; */600while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {601switch (subopt) {602case 0:603if (val == NULL) {604warnx("Suboption 'context' - no argument");605return (-1);606}607strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);608break;609case 1:610if (val == NULL) {611warnx("Suboption 'context-engine' - no argument");612return (-1);613}614if ((int32_t)(snmp_client.clen = parse_ascii(val,615snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) == -1) {616warnx("Bad EngineID - %s", val);617return (-1);618}619break;620default:621warnx("Unknown suboption - '%s'", suboptarg);622return (-1);623}624/* count += 1; */625}626return (2/* count */);627}628629int32_t630parse_user_security(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)631{632int32_t /* count, */ subopt, saved_errno;633char *val, *option;634const char *const subopts[] = {635"engine",636"engine-boots",637"engine-time",638"name",639NULL640};641642assert(opt_arg != NULL);643/* count = 1; */644while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {645switch (subopt) {646case 0:647if (val == NULL) {648warnx("Suboption 'engine' - no argument");649return (-1);650}651snmp_client.engine.engine_len = parse_ascii(val,652snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);653if ((int32_t)snmp_client.engine.engine_len == -1) {654warnx("Bad EngineID - %s", val);655return (-1);656}657break;658case 1:659if (val == NULL) {660warnx("Suboption 'engine-boots' - no argument");661return (-1);662}663saved_errno = errno;664errno = 0;665snmp_client.engine.engine_boots = strtoul(val, NULL, 10);666if (errno != 0) {667warn("Bad 'engine-boots' value %s", val);668errno = saved_errno;669return (-1);670}671errno = saved_errno;672break;673case 2:674if (val == NULL) {675warnx("Suboption 'engine-time' - no argument");676return (-1);677}678saved_errno = errno;679errno = 0;680snmp_client.engine.engine_time = strtoul(val, NULL, 10);681if (errno != 0) {682warn("Bad 'engine-time' value %s", val);683errno = saved_errno;684return (-1);685}686errno = saved_errno;687break;688case 3:689strlcpy(snmp_client.user.sec_name, val,690SNMP_ADM_STR32_SIZ);691break;692default:693warnx("Unknown suboption - '%s'", suboptarg);694return (-1);695}696/* count += 1; */697}698return (2/* count */);699}700701int32_t702parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)703{704assert(opt_arg != NULL);705706if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)707return (-1);708709return (2);710}711712int32_t713parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)714{715char path[MAXPATHLEN + 1];716int32_t cut_dflt, len, subopt;717struct asn_oid cut;718char *val, *option;719const char *const subopts[] = {720"cut",721"path",722"file",723NULL724};725726#define INC_CUT 0727#define INC_PATH 1728#define INC_LIST 2729730assert(opt_arg != NULL);731732/* if (opt == 'i')733free_filelist(snmptoolctx, ); */734/*735* This function should be called only after getopt(3) - otherwise if736* no previous validation of opt_arg strlen() may not return what is737* expected.738*/739740path[0] = '\0';741memset(&cut, 0, sizeof(struct asn_oid));742cut_dflt = -1;743744while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {745switch (subopt) {746case INC_CUT:747if (val == NULL) {748warnx("Suboption 'cut' requires an argument");749return (-1);750} else {751if (snmp_parse_numoid(val, &cut) < 0)752return (-1);753}754cut_dflt = 1;755break;756757case INC_PATH:758if ((len = parse_path(val)) < 0)759return (-1);760strlcpy(path, val, len + 1);761break;762763case INC_LIST:764if (val == NULL)765return (-1);766if (cut_dflt == -1)767len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);768else769len = parse_flist(snmptoolctx, val, path, &cut);770if (len < 0)771return (-1);772break;773774default:775warnx("Unknown suboption - '%s'", suboptarg);776return (-1);777}778}779780/* XXX: Fix me - returning two is wrong here */781return (2);782}783784int32_t785parse_server(char *opt_arg)786{787assert(opt_arg != NULL);788789if (snmp_parse_server(&snmp_client, opt_arg) < 0)790return (-1);791792return (2);793}794795int32_t796parse_timeout(char *opt_arg)797{798int32_t v, saved_errno;799800assert(opt_arg != NULL);801802saved_errno = errno;803errno = 0;804805v = strtol(opt_arg, NULL, 10);806if (errno != 0) {807warn("Error parsing timeout value");808errno = saved_errno;809return (-1);810}811812snmp_client.timeout.tv_sec = v;813errno = saved_errno;814return (2);815}816817int32_t818parse_retry(char *opt_arg)819{820uint32_t v;821int32_t saved_errno;822823assert(opt_arg != NULL);824825saved_errno = errno;826errno = 0;827828v = strtoul(opt_arg, NULL, 10);829if (errno != 0) {830warn("Error parsing retries count");831errno = saved_errno;832return (-1);833}834835snmp_client.retries = v;836errno = saved_errno;837return (2);838}839840int32_t841parse_version(char *opt_arg)842{843uint32_t v;844int32_t saved_errno;845846assert(opt_arg != NULL);847848saved_errno = errno;849errno = 0;850851v = strtoul(opt_arg, NULL, 10);852if (errno != 0) {853warn("Error parsing version");854errno = saved_errno;855return (-1);856}857858switch (v) {859case 1:860snmp_client.version = SNMP_V1;861break;862case 2:863snmp_client.version = SNMP_V2c;864break;865case 3:866snmp_client.version = SNMP_V3;867break;868default:869warnx("Unsupported SNMP version - %u", v);870errno = saved_errno;871return (-1);872}873874errno = saved_errno;875return (2);876}877878int32_t879parse_local_path(char *opt_arg)880{881assert(opt_arg != NULL);882883if (strlcpy(snmp_client.local_path, opt_arg,884sizeof(snmp_client.local_path)) >= sizeof(snmp_client.local_path)) {885warnx("Filename too long - %s", opt_arg);886return (-1);887}888return (2);889}890891int32_t892parse_buflen(char *opt_arg)893{894uint32_t size;895int32_t saved_errno;896897assert(opt_arg != NULL);898899saved_errno = errno;900errno = 0;901902size = strtoul(opt_arg, NULL, 10);903if (errno != 0) {904warn("Error parsing buffer size");905errno = saved_errno;906return (-1);907}908909if (size > MAX_BUFF_SIZE) {910warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);911errno = saved_errno;912return (-1);913}914915snmp_client.txbuflen = snmp_client.rxbuflen = size;916errno = saved_errno;917return (2);918}919920int32_t921parse_debug(void)922{923snmp_client.dump_pdus = 1;924return (1);925}926927int32_t928parse_discovery(struct snmp_toolinfo *snmptoolctx)929{930SET_EDISCOVER(snmptoolctx);931snmp_client.version = SNMP_V3;932return (1);933}934935int32_t936parse_local_key(struct snmp_toolinfo *snmptoolctx)937{938SET_LOCALKEY(snmptoolctx);939snmp_client.version = SNMP_V3;940return (1);941}942943int32_t944parse_num_oids(struct snmp_toolinfo *snmptoolctx)945{946SET_NUMERIC(snmptoolctx);947return (1);948}949950int32_t951parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)952{953assert(opt_arg != NULL);954955if (strlen(opt_arg) > strlen("verbose")) {956warnx( "Invalid output option - %s",opt_arg);957return (-1);958}959960if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)961SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);962else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)963SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);964else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)965SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);966else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)967SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);968else {969warnx( "Invalid output option - %s", opt_arg);970return (-1);971}972973return (2);974}975976int32_t977parse_errors(struct snmp_toolinfo *snmptoolctx)978{979SET_RETRY(snmptoolctx);980return (1);981}982983int32_t984parse_skip_access(struct snmp_toolinfo *snmptoolctx)985{986SET_ERRIGNORE(snmptoolctx);987return (1);988}989990char *991snmp_parse_suboid(char *str, struct asn_oid *oid)992{993char *endptr;994asn_subid_t suboid;995996if (*str == '.')997str++;998999if (*str < '0' || *str > '9')1000return (str);10011002do {1003suboid = strtoul(str, &endptr, 10);1004if ((asn_subid_t) suboid > ASN_MAXID) {1005warnx("Suboid %u > ASN_MAXID", suboid);1006return (NULL);1007}1008if (snmp_suboid_append(oid, suboid) < 0)1009return (NULL);1010str = endptr + 1;1011} while (*endptr == '.');10121013return (endptr);1014}10151016static char *1017snmp_int2asn_oid(char *str, struct asn_oid *oid)1018{1019char *endptr;1020int32_t v, saved_errno;10211022saved_errno = errno;1023errno = 0;10241025v = strtol(str, &endptr, 10);1026if (errno != 0) {1027warn("Integer value %s not supported", str);1028errno = saved_errno;1029return (NULL);1030}1031errno = saved_errno;10321033if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)1034return (NULL);10351036return (endptr);1037}10381039/* It is a bit weird to have a table indexed by OID but still... */1040static char *1041snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,1042struct asn_oid *oid)1043{1044int32_t i;1045char string[MAXSTR + 1], *endptr;1046struct snmp_object obj;10471048for (i = 0; i < MAXSTR; i++)1049if (isalpha (*(str + i)) == 0)1050break;10511052endptr = str + i;1053memset(&obj, 0, sizeof(struct snmp_object));1054if (i == 0) {1055if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)1056return (NULL);1057if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)1058return (NULL);1059} else {1060strlcpy(string, str, i + 1);1061if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {1062warnx("Unknown string - %s", string);1063return (NULL);1064}1065}10661067asn_append_oid(oid, &(obj.val.var));1068return (endptr);1069}10701071static char *1072snmp_ip2asn_oid(char *str, struct asn_oid *oid)1073{1074uint32_t v;1075int32_t i;1076char *endptr, *ptr;10771078ptr = str;10791080for (i = 0; i < 4; i++) {1081v = strtoul(ptr, &endptr, 10);1082if (v > 0xff)1083return (NULL);1084if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)1085return (NULL);1086if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)1087return (NULL);1088ptr = endptr + 1;1089}10901091return (endptr);1092}10931094/* 32-bit counter, gauge, timeticks. */1095static char *1096snmp_uint2asn_oid(char *str, struct asn_oid *oid)1097{1098char *endptr;1099uint32_t v;1100int32_t saved_errno;11011102saved_errno = errno;1103errno = 0;11041105v = strtoul(str, &endptr, 10);1106if (errno != 0) {1107warn("Integer value %s not supported", str);1108errno = saved_errno;1109return (NULL);1110}1111errno = saved_errno;1112if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)1113return (NULL);11141115return (endptr);1116}11171118static char *1119snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)1120{1121char *endptr;1122uint64_t v;1123int32_t saved_errno;11241125saved_errno = errno;1126errno = 0;11271128v = strtoull(str, &endptr, 10);11291130if (errno != 0) {1131warn("Integer value %s not supported", str);1132errno = saved_errno;1133return (NULL);1134}1135errno = saved_errno;1136if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)1137return (NULL);11381139if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)1140return (NULL);11411142return (endptr);1143}11441145enum snmp_syntax1146parse_syntax(char *str)1147{1148int32_t i;11491150for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {1151if (strncmp(syntax_strings[i].str, str,1152strlen(syntax_strings[i].str)) == 0)1153return (syntax_strings[i].stx);1154}11551156return (SNMP_SYNTAX_NULL);1157}11581159static char *1160snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,1161struct index *idx, struct snmp_object *object)1162{1163char *ptr;1164int32_t i;1165enum snmp_syntax stx;1166char syntax[MAX_CMD_SYNTAX_LEN];11671168ptr = str;1169if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {1170for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {1171if (*(ptr + i) == ':')1172break;1173}11741175if (i >= MAX_CMD_SYNTAX_LEN) {1176warnx("Unknown syntax in OID - %s", str);1177return (NULL);1178}1179/* Expect a syntax string here. */1180if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {1181warnx("Invalid syntax - %s",syntax);1182return (NULL);1183}11841185if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {1186warnx("Syntax mismatch - %d expected, %d given",1187idx->syntax, stx);1188return (NULL);1189}1190/*1191* That is where the suboid started + the syntax length + one1192* character for ':'.1193*/1194ptr = str + i + 1;1195} else1196stx = idx->syntax;11971198switch (stx) {1199case SNMP_SYNTAX_INTEGER:1200return (snmp_int2asn_oid(ptr, &(object->val.var)));1201case SNMP_SYNTAX_OID:1202return (snmp_oid2asn_oid(snmptoolctx, ptr,1203&(object->val.var)));1204case SNMP_SYNTAX_IPADDRESS:1205return (snmp_ip2asn_oid(ptr, &(object->val.var)));1206case SNMP_SYNTAX_COUNTER:1207/* FALLTHROUGH */1208case SNMP_SYNTAX_GAUGE:1209/* FALLTHROUGH */1210case SNMP_SYNTAX_TIMETICKS:1211return (snmp_uint2asn_oid(ptr, &(object->val.var)));1212case SNMP_SYNTAX_COUNTER64:1213return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));1214case SNMP_SYNTAX_OCTETSTRING:1215return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));1216default:1217/* NOTREACHED */1218break;1219}12201221return (NULL);1222}12231224char *1225snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,1226struct snmp_object *object)1227{1228char *ptr;1229struct index *temp;12301231if (object->info->table_idx == NULL)1232return (NULL);12331234ptr = NULL;1235STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {1236if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))1237== NULL)1238return (NULL);12391240if (*ptr != ',' && *ptr != ']')1241return (NULL);1242str = ptr + 1;1243}12441245if (ptr == NULL || *ptr != ']') {1246warnx("Mismatching index - %s", str);1247return (NULL);1248}12491250return (ptr + 1);1251}12521253/*1254* Fill in the struct asn_oid member of snmp_value with suboids from input.1255* If an error occurs - print message on stderr and return (-1).1256* If all is ok - return the length of the oid.1257*/1258int32_t1259snmp_parse_numoid(char *argv, struct asn_oid *var)1260{1261char *endptr, *str;1262asn_subid_t suboid;12631264str = argv;12651266if (*str == '.')1267str++;12681269do {1270if (var->len == ASN_MAXOIDLEN) {1271warnx("Oid too long - %u", var->len);1272return (-1);1273}12741275suboid = strtoul(str, &endptr, 10);1276if (suboid > ASN_MAXID) {1277warnx("Oid too long - %u", var->len);1278return (-1);1279}12801281var->subs[var->len++] = suboid;1282str = endptr + 1;1283} while ( *endptr == '.');12841285if (*endptr != '\0') {1286warnx("Invalid oid string - %s", argv);1287return (-1);1288}12891290return (var->len);1291}12921293/* Append a length 1 suboid to an asn_oid structure. */1294int32_t1295snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)1296{1297if (var == NULL)1298return (-1);12991300if (var->len >= ASN_MAXOIDLEN) {1301warnx("Oid too long - %u", var->len);1302return (-1);1303}13041305var->subs[var->len++] = suboid;13061307return (1);1308}13091310/* Pop the last suboid from an asn_oid structure. */1311int32_t1312snmp_suboid_pop(struct asn_oid *var)1313{1314asn_subid_t suboid;13151316if (var == NULL)1317return (-1);13181319if (var->len < 1)1320return (-1);13211322suboid = var->subs[--(var->len)];1323var->subs[var->len] = 0;13241325return (suboid);1326}13271328/*1329* Parse the command-line provided string into an OID - allocate memory for a new1330* snmp object, fill in its fields and insert it in the object list. A1331* (snmp_verify_inoid_f) function must be provided to validate the input string.1332*/1333int32_t1334snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,1335char *string)1336{1337struct snmp_object *obj;13381339if (snmptoolctx == NULL)1340return (-1);13411342/* XXX-BZ does that chack make sense? */1343if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {1344warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);1345return (-1);1346}13471348if ((obj = calloc(1, sizeof(struct snmp_object))) == NULL) {1349syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));1350return (-1);1351}13521353if (func(snmptoolctx, obj, string) < 0) {1354warnx("Invalid OID - %s", string);1355free(obj);1356return (-1);1357}13581359snmptoolctx->objects++;1360SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);13611362return (1);1363}13641365/* Given an OID, find it in the object list and remove it. */1366int32_t1367snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)1368{1369struct snmp_object *temp;13701371if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {1372warnx("Object list already empty");1373return (-1);1374}137513761377SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)1378if (asn_compare_oid(&(temp->val.var), oid) == 0)1379break;13801381if (temp == NULL) {1382warnx("No such object in list");1383return (-1);1384}13851386SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);1387if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&1388temp->val.v.octetstring.octets != NULL)1389free(temp->val.v.octetstring.octets);1390free(temp);13911392return (1);1393}13941395static void1396snmp_object_freeall(struct snmp_toolinfo *snmptoolctx)1397{1398struct snmp_object *o;13991400while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {1401SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);14021403if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&1404o->val.v.octetstring.octets != NULL)1405free(o->val.v.octetstring.octets);1406free(o);1407}1408}14091410/* Do all possible memory release before exit. */1411void1412snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)1413{1414if (snmp_client.chost != NULL) {1415free(snmp_client.chost);1416snmp_client.chost = NULL;1417}14181419if (snmp_client.cport != NULL) {1420free(snmp_client.cport);1421snmp_client.cport = NULL;1422}14231424snmp_mapping_free(snmptoolctx);1425free_filelist(snmptoolctx);1426snmp_object_freeall(snmptoolctx);14271428if (snmptoolctx->passwd != NULL) {1429free(snmptoolctx->passwd);1430snmptoolctx->passwd = NULL;1431}1432}14331434/*1435* Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)1436* function should check whether the variable is consistent in this PDU1437* (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to1438* a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the1439* function actually adds the variable to the PDU and must not be NULL.1440*/1441int32_t1442snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,1443snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,1444struct snmp_pdu *pdu, int32_t maxcount)1445{1446int32_t nbindings, abind;1447struct snmp_object *obj;14481449if (pdu == NULL || afunc == NULL)1450return (-1);14511452/* Return 0 in case of no more work todo. */1453if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))1454return (0);14551456if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {1457warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");1458return (-1);1459}14601461nbindings = 0;1462SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {1463if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {1464nbindings = -1;1465break;1466}1467if ((abind = afunc(pdu, obj)) < 0) {1468nbindings = -1;1469break;1470}14711472if (abind > 0) {1473/* Do not put more varbindings than requested. */1474if (++nbindings >= maxcount)1475break;1476}1477}14781479return (nbindings);1480}14811482/*1483* Locate an object in the object list and set a corresponding error status.1484*/1485int32_t1486snmp_object_seterror(struct snmp_toolinfo *snmptoolctx,1487struct snmp_value *err_value, int32_t error_status)1488{1489struct snmp_object *obj;14901491if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)1492return (-1);14931494SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)1495if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {1496obj->error = error_status;1497return (1);1498}14991500return (0);1501}15021503/*1504* Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request1505* but don't compare syntaxes - when sending a request PDU they must be null.1506* This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes1507* checks and some other checks skipped.1508*/1509int32_t1510snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)1511{1512uint32_t i;15131514for (i = 0; i < req->nbindings; i++) {1515if (asn_compare_oid(&req->bindings[i].var,1516&resp->bindings[i].var) != 0) {1517warnx("Bad OID in response");1518return (-1);1519}15201521if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax1522== SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==1523SNMP_SYNTAX_NOSUCHINSTANCE))1524return (0);1525}15261527return (1);1528}15291530int32_t1531snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)1532{1533int32_t N, R, M, r;15341535if (req->error_status > (int32_t) resp->nbindings) {1536warnx("Bad number of bindings in response");1537return (-1);1538}15391540for (N = 0; N < req->error_status; N++) {1541if (asn_is_suboid(&req->bindings[N].var,1542&resp->bindings[N].var) == 0)1543return (0);1544if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)1545return (0);1546}15471548for (R = N , r = N; R < (int32_t) req->nbindings; R++) {1549for (M = 0; M < req->error_index && (r + M) <1550(int32_t) resp->nbindings; M++) {1551if (asn_is_suboid(&req->bindings[R].var,1552&resp->bindings[r + M].var) == 0)1553return (0);15541555if (resp->bindings[r + M].syntax ==1556SNMP_SYNTAX_ENDOFMIBVIEW) {1557M++;1558break;1559}1560}1561r += M;1562}15631564return (0);1565}15661567int32_t1568snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)1569{1570uint32_t i;15711572for (i = 0; i < req->nbindings; i++) {1573if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)1574== 0)1575return (0);15761577if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==1578SNMP_SYNTAX_ENDOFMIBVIEW)1579return (0);1580}15811582return (1);1583}15841585/*1586* Should be called to check a response to get/getnext/getbulk.1587*/1588int32_t1589snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)1590{1591if (resp == NULL || req == NULL)1592return (-2);15931594if (resp->version != req->version) {1595warnx("Response has wrong version");1596return (-1);1597}15981599if (resp->error_status == SNMP_ERR_NOSUCHNAME) {1600warnx("Error - No Such Name");1601return (0);1602}16031604if (resp->error_status != SNMP_ERR_NOERROR) {1605warnx("Error %d in response", resp->error_status);1606return (-1);1607}16081609if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){1610warnx("Bad number of bindings in response");1611return (-1);1612}16131614switch (req->type) {1615case SNMP_PDU_GET:1616return (snmp_parse_get_resp(resp,req));1617case SNMP_PDU_GETBULK:1618return (snmp_parse_getbulk_resp(resp,req));1619case SNMP_PDU_GETNEXT:1620return (snmp_parse_getnext_resp(resp,req));1621default:1622/* NOTREACHED */1623break;1624}16251626return (-2);1627}16281629static void1630snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,1631uint32_t len, uint8_t *octets)1632{1633char *buf;16341635if (len == 0 || octets == NULL)1636return;16371638if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1639fprintf(stdout, "%s : ",1640syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);16411642if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {1643fprintf(stdout, "%s", buf);1644free(buf);1645}1646}16471648static void1649snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,1650struct asn_oid *oid)1651{1652uint32_t i;1653uint8_t *s;16541655if ((s = malloc(oid->subs[0] + 1)) == NULL)1656syslog(LOG_ERR, "malloc failed - %s", strerror(errno));1657else {1658for (i = 0; i < oid->subs[0]; i++)1659s[i] = (u_char) (oid->subs[i + 1]);16601661snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);1662free(s);1663}1664}16651666/*1667* Check and output syntax type and value.1668*/1669static void1670snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)1671{1672char oid_string[ASN_OIDSTRLEN];1673struct snmp_object obj;16741675if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1676fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);16771678if(!ISSET_NUMERIC(snmptoolctx)) {1679memset(&obj, 0, sizeof(struct snmp_object));1680asn_append_oid(&(obj.val.var), oid);16811682if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)1683fprintf(stdout, "%s" , obj.info->string);1684else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)1685fprintf(stdout, "%s" , obj.info->string);1686else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)1687fprintf(stdout, "%s" , obj.info->string);1688else {1689(void) asn_oid2str_r(oid, oid_string);1690fprintf(stdout, "%s", oid_string);1691}1692} else {1693(void) asn_oid2str_r(oid, oid_string);1694fprintf(stdout, "%s", oid_string);1695}1696}16971698static void1699snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,1700int32_t int_val)1701{1702char *string;17031704if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1705fprintf(stdout, "%s : ",1706syntax_strings[SNMP_SYNTAX_INTEGER].str);17071708if (enums != NULL && (string = enum_string_lookup(enums, int_val))1709!= NULL)1710fprintf(stdout, "%s", string);1711else1712fprintf(stdout, "%d", int_val);1713}17141715static void1716snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)1717{1718if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1719fprintf(stdout, "%s : ",1720syntax_strings[SNMP_SYNTAX_IPADDRESS].str);17211722fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);1723}17241725static void1726snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)1727{1728if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1729fprintf(stdout, "%s : ",1730syntax_strings[SNMP_SYNTAX_COUNTER].str);17311732fprintf(stdout, "%u", counter);1733}17341735static void1736snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)1737{1738if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1739fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);17401741fprintf(stdout, "%u", gauge);1742}17431744static void1745snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)1746{1747if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1748fprintf(stdout, "%s : ",1749syntax_strings[SNMP_SYNTAX_TIMETICKS].str);17501751fprintf(stdout, "%u", ticks);1752}17531754static void1755snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)1756{1757if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)1758fprintf(stdout, "%s : ",1759syntax_strings[SNMP_SYNTAX_COUNTER64].str);17601761fprintf(stdout,"%ju", counter64);1762}17631764int32_t1765snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,1766struct snmp_oid2str *entry)1767{1768if (val == NULL)1769return (-1);17701771if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)1772fprintf(stdout, " = ");17731774switch (val->syntax) {1775case SNMP_SYNTAX_INTEGER:1776if (entry != NULL)1777snmp_output_int(snmptoolctx, entry->snmp_enum,1778val->v.integer);1779else1780snmp_output_int(snmptoolctx, NULL, val->v.integer);1781break;17821783case SNMP_SYNTAX_OCTETSTRING:1784if (entry != NULL)1785snmp_output_octetstring(snmptoolctx, entry->tc,1786val->v.octetstring.len, val->v.octetstring.octets);1787else1788snmp_output_octetstring(snmptoolctx, SNMP_STRING,1789val->v.octetstring.len, val->v.octetstring.octets);1790break;17911792case SNMP_SYNTAX_OID:1793snmp_output_oid_value(snmptoolctx, &(val->v.oid));1794break;17951796case SNMP_SYNTAX_IPADDRESS:1797snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);1798break;17991800case SNMP_SYNTAX_COUNTER:1801snmp_output_counter(snmptoolctx, val->v.uint32);1802break;18031804case SNMP_SYNTAX_GAUGE:1805snmp_output_gauge(snmptoolctx, val->v.uint32);1806break;18071808case SNMP_SYNTAX_TIMETICKS:1809snmp_output_ticks(snmptoolctx, val->v.uint32);1810break;18111812case SNMP_SYNTAX_COUNTER64:1813snmp_output_counter64(snmptoolctx, val->v.counter64);1814break;18151816case SNMP_SYNTAX_NOSUCHOBJECT:1817fprintf(stderr, "No Such Object\n");1818return (val->syntax);18191820case SNMP_SYNTAX_NOSUCHINSTANCE:1821fprintf(stderr, "No Such Instance\n");1822return (val->syntax);18231824case SNMP_SYNTAX_ENDOFMIBVIEW:1825fprintf(stdout, "End of Mib View\n");1826return (val->syntax);18271828case SNMP_SYNTAX_NULL:1829/* NOTREACHED */1830fprintf(stderr, "agent returned NULL Syntax\n");1831return (val->syntax);18321833default:1834/* NOTREACHED - If here - then all went completely wrong. */1835fprintf(stderr, "agent returned unknown syntax\n");1836return (-1);1837}18381839fprintf(stdout, "\n");18401841return (0);1842}18431844static int32_t1845snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,1846struct snmp_value *val)1847{1848int32_t rc;1849asn_subid_t suboid;18501851if (obj == NULL || val == NULL)1852return (-1);18531854if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)1855return (-1);18561857memset(obj, 0, sizeof(struct snmp_object));1858asn_append_oid(&(obj->val.var), &(val->var));1859obj->val.syntax = val->syntax;18601861if (obj->val.syntax > 0)1862rc = snmp_lookup_leafstring(snmptoolctx, obj);1863else1864rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);18651866(void) snmp_suboid_append(&(val->var), suboid);1867(void) snmp_suboid_append(&(obj->val.var), suboid);18681869return (rc);1870}18711872static int32_t1873snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,1874struct asn_oid *oid)1875{1876uint8_t ip[4];1877uint32_t bytes = 1;1878uint64_t cnt64;1879struct asn_oid temp, out;18801881if (oid->len < bytes)1882return (-1);18831884memset(&temp, 0, sizeof(struct asn_oid));1885asn_append_oid(&temp, oid);18861887switch (stx->syntax) {1888case SNMP_SYNTAX_INTEGER:1889snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);1890break;18911892case SNMP_SYNTAX_OCTETSTRING:1893if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >1894ASN_MAXOCTETSTRING))1895return (-1);1896snmp_output_octetindex(snmptoolctx, stx->tc, &temp);1897bytes += temp.subs[0];1898break;18991900case SNMP_SYNTAX_OID:1901if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >1902ASN_MAXOIDLEN))1903return (-1);19041905bytes += temp.subs[0];1906memset(&out, 0, sizeof(struct asn_oid));1907asn_slice_oid(&out, &temp, 1, bytes);1908snmp_output_oid_value(snmptoolctx, &out);1909break;19101911case SNMP_SYNTAX_IPADDRESS:1912if (temp.len < 4)1913return (-1);1914for (bytes = 0; bytes < 4; bytes++)1915ip[bytes] = temp.subs[bytes];19161917snmp_output_ipaddress(snmptoolctx, ip);1918bytes = 4;1919break;19201921case SNMP_SYNTAX_COUNTER:1922snmp_output_counter(snmptoolctx, temp.subs[0]);1923break;19241925case SNMP_SYNTAX_GAUGE:1926snmp_output_gauge(snmptoolctx, temp.subs[0]);1927break;19281929case SNMP_SYNTAX_TIMETICKS:1930snmp_output_ticks(snmptoolctx, temp.subs[0]);1931break;19321933case SNMP_SYNTAX_COUNTER64:1934if (oid->len < 2)1935return (-1);1936bytes = 2;1937memcpy(&cnt64, temp.subs, bytes);1938snmp_output_counter64(snmptoolctx, cnt64);1939break;19401941default:1942return (-1);1943}19441945return (bytes);1946}19471948static int32_t1949snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)1950{1951int32_t i, first, len;1952struct asn_oid oid;1953struct index *temp;19541955if (ISSET_NUMERIC(snmptoolctx))1956return (-1);19571958if (o->info->table_idx == NULL) {1959fprintf(stdout,"%s.%d", o->info->string,1960o->val.var.subs[o->val.var.len - 1]);1961return (1);1962}19631964fprintf(stdout,"%s[", o->info->string);1965memset(&oid, 0, sizeof(struct asn_oid));19661967len = 1;1968asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),1969o->val.var.len);19701971first = 1;1972STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {1973if(first)1974first = 0;1975else1976fprintf(stdout, ", ");1977if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)1978break;1979len += i;1980memset(&oid, 0, sizeof(struct asn_oid));1981asn_slice_oid(&oid, &(o->val.var),1982(o->info->table_idx->var.len + len), o->val.var.len + 1);1983}19841985fprintf(stdout,"]");1986return (1);1987}19881989void1990snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)1991{1992struct snmp_object *object;1993char buf[ASN_OIDSTRLEN];19941995if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {1996fprintf(stdout, "Invalid error index in PDU\n");1997return;1998}19992000if ((object = calloc(1, sizeof(struct snmp_object))) == NULL) {2001fprintf(stdout, "calloc: %s", strerror(errno));2002return;2003}20042005fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,2006snmp_client.cport);20072008if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, object,2009&(pdu->bindings[pdu->error_index - 1])) > 0))2010snmp_output_object(snmptoolctx, object);2011else {2012asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);2013fprintf(stdout,"%s", buf);2014}20152016fprintf(stdout," caused error - ");2017if ((pdu->error_status > 0) && (pdu->error_status <=2018SNMP_ERR_INCONS_NAME))2019fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);2020else2021fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);20222023free(object);2024object = NULL;2025}20262027int32_t2028snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,2029struct asn_oid *root)2030{2031struct snmp_object *object;2032char p[ASN_OIDSTRLEN];2033int32_t error;2034uint32_t i;20352036if ((object = calloc(1, sizeof(struct snmp_object))) == NULL)2037return (-1);20382039i = error = 0;2040while (i < pdu->nbindings) {2041if (root != NULL && !(asn_is_suboid(root,2042&(pdu->bindings[i].var))))2043break;20442045if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {2046if (!ISSET_NUMERIC(snmptoolctx) &&2047(snmp_fill_object(snmptoolctx, object,2048&(pdu->bindings[i])) > 0))2049snmp_output_object(snmptoolctx, object);2050else {2051asn_oid2str_r(&(pdu->bindings[i].var), p);2052fprintf(stdout, "%s", p);2053}2054}2055error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]),2056object->info);2057i++;2058}20592060free(object);2061object = NULL;20622063if (error)2064return (-1);20652066return (i);2067}20682069void2070snmp_output_engine(void)2071{2072uint32_t i;2073char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];20742075cptr = engine;2076for (i = 0; i < snmp_client.engine.engine_len; i++)2077cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);2078*cptr++ = '\0';20792080fprintf(stdout, "Engine ID 0x%s\n", engine);2081fprintf(stdout, "Boots : %u\t\tTime : %d\n",2082snmp_client.engine.engine_boots,2083snmp_client.engine.engine_time);2084}20852086void2087snmp_output_keys(void)2088{2089uint32_t i, keylen = 0;2090char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];20912092fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);2093if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {2094fprintf(stdout, "MD5 : 0x");2095keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;2096} else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {2097fprintf(stdout, "SHA : 0x");2098keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;2099}2100if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {2101cptr = extkey;2102for (i = 0; i < keylen; i++)2103cptr += sprintf(cptr, "%.2x",2104snmp_client.user.auth_key[i]);2105*cptr++ = '\0';2106fprintf(stdout, "%s\n", extkey);2107}21082109if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {2110fprintf(stdout, "DES : 0x");2111keylen = SNMP_PRIV_DES_KEY_SIZ;2112} else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {2113fprintf(stdout, "AES : 0x");2114keylen = SNMP_PRIV_AES_KEY_SIZ;2115}2116if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {2117cptr = extkey;2118for (i = 0; i < keylen; i++)2119cptr += sprintf(cptr, "%.2x",2120snmp_client.user.priv_key[i]);2121*cptr++ = '\0';2122fprintf(stdout, "%s\n", extkey);2123}2124}212521262127