Path: blob/main/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
105585 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* Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,29* bsnmpset can be used to set MIB objects in an agent.30*/3132#include <sys/queue.h>33#include <sys/types.h>3435#include <assert.h>36#include <ctype.h>37#include <err.h>38#include <errno.h>39#include <stdarg.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"5152static const char *program_name = NULL;53static enum program_e {54BSNMPGET,55BSNMPWALK,56BSNMPSET57} program;5859/* *****************************************************************************60* Common bsnmptools functions.61*/62static void63usage(void)64{65fprintf(stderr,66"Usage:\n"67"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"68"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"69"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"70"\t[-t timeout] [-U options] [-v version]%s\n",71program_name,72(program == BSNMPGET) ? "[-aDdehnK]" :73(program == BSNMPWALK) ? "[-dhnK]" :74(program == BSNMPSET) ? "[-adehnK]" :75"",76(program == BSNMPGET || program == BSNMPWALK) ?77" [-M max-repetitions] [-N non-repeaters]" : "",78(program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "",79(program == BSNMPGET) ? " OID [OID ...]" :80(program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :81""82);83}8485static int32_t86parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)87{88uint32_t v;8990assert(opt_arg != NULL);9192v = strtoul(opt_arg, (void *) NULL, 10);9394if (v > SNMP_MAX_BINDINGS) {95warnx("Max repetitions value greater than %d maximum allowed.",96SNMP_MAX_BINDINGS);97return (-1);98}99100SET_MAXREP(snmptoolctx, v);101return (2);102}103104static int32_t105parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)106{107uint32_t v;108109assert(opt_arg != NULL);110111v = strtoul(opt_arg, (void *) NULL, 10);112113if (v > SNMP_MAX_BINDINGS) {114warnx("Non repeaters value greater than %d maximum allowed.",115SNMP_MAX_BINDINGS);116return (-1);117}118119SET_NONREP(snmptoolctx, v);120return (2);121}122123static int32_t124parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)125{126assert(opt_arg != NULL);127128if (strcasecmp(opt_arg, "getbulk") == 0)129SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);130else if (strcasecmp(opt_arg, "getnext") == 0)131SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);132else if (strcasecmp(opt_arg, "get") == 0)133SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);134else {135warnx("PDU type '%s' not supported.", opt_arg);136return (-1);137}138139return (2);140}141142static int32_t143snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)144{145int32_t count, optnum = 0;146int ch;147const char *opts;148149switch (program) {150case BSNMPWALK:151opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";152break;153case BSNMPGET:154opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";155break;156case BSNMPSET:157opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";158break;159default:160return (-1);161}162163while ((ch = getopt(argc, argv, opts)) != EOF) {164switch (ch) {165case 'A':166count = parse_authentication(snmptoolctx, optarg);167break;168case 'a':169count = parse_skip_access(snmptoolctx);170break;171case 'b':172count = parse_buflen(optarg);173break;174case 'D':175count = parse_discovery(snmptoolctx);176break;177case 'd':178count = parse_debug();179break;180case 'e':181count = parse_errors(snmptoolctx);182break;183case 'h':184usage();185return (-2);186case 'C':187count = parse_context(snmptoolctx, optarg);188break;189case 'I':190count = parse_include(snmptoolctx, optarg);191break;192case 'i':193count = parse_file(snmptoolctx, optarg);194break;195case 'K':196count = parse_local_key(snmptoolctx);197break;198case 'l':199count = parse_local_path(optarg);200break;201case 'M':202count = parse_max_repetitions(snmptoolctx, optarg);203break;204case 'N':205count = parse_non_repeaters(snmptoolctx, optarg);206break;207case 'n':208count = parse_num_oids(snmptoolctx);209break;210case 'o':211count = parse_output(snmptoolctx, optarg);212break;213case 'P':214count = parse_privacy(snmptoolctx, optarg);215break;216case 'p':217count = parse_pdu_type(snmptoolctx, optarg);218break;219case 'r':220count = parse_retry(optarg);221break;222case 's':223count = parse_server(optarg);224break;225case 't':226count = parse_timeout(optarg);227break;228case 'U':229count = parse_user_security(snmptoolctx, optarg);230break;231case 'v':232count = parse_version(optarg);233break;234case '?':235default:236usage();237return (-1);238}239if (count < 0)240return (-1);241optnum += count;242}243244return (optnum);245}246247/*248* Read user input OID - one of following formats:249* 1) 1.2.1.1.2.1.0 - that is if option numeric was given;250* 2) string - in such case append .0 to the asn_oid subs;251* 3) string.1 - no additional processing required in such case.252*/253static char *254snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,255struct snmp_object *obj, char *argv)256{257char string[MAXSTR], *str;258int32_t i = 0;259struct asn_oid in_oid;260261str = argv;262263if (*str == '.')264str++;265266while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {267str++;268i++;269}270271if (i <= 0 || i >= MAXSTR)272return (NULL);273274memset(&in_oid, 0, sizeof(struct asn_oid));275if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {276warnx("Invalid OID - %s", argv);277return (NULL);278}279280strlcpy(string, argv, i + 1);281if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {282warnx("No entry for %s in mapping lists", string);283return (NULL);284}285286/* If OID given on command line append it. */287if (in_oid.len > 0)288asn_append_oid(&(obj->val.var), &in_oid);289else if (*str == '[') {290if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)291return (NULL);292} else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==293SNMP_PDU_GET) {294if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)295return (NULL);296}297298return (str);299}300301static int32_t302snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,303struct snmp_object *obj, char *argv)304{305if (argv == NULL)306return (-1);307308if (ISSET_NUMERIC(snmptoolctx)) {309if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)310return (-1);311} else {312if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&313snmp_parse_numoid(argv, &(obj->val.var)) < 0)314return (-1);315}316317return (1);318}319320static int32_t321snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)322{323if (obj->error > 0)324return (0);325326asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));327pdu->nbindings++;328329return (pdu->nbindings);330}331332/* *****************************************************************************333* bsnmpget private functions.334*/335static int32_t336snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,337struct snmp_object *obj)338{339if (pdu->version == SNMP_V1 && obj->val.syntax ==340SNMP_SYNTAX_COUNTER64) {341warnx("64-bit counters are not supported in SNMPv1 PDU");342return (-1);343}344345if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||346pdu->type == SNMP_PDU_GETBULK)347return (1);348349if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {350warnx("Only leaf object values can be added to GET PDU");351return (-1);352}353354return (1);355}356357/*358* In case of a getbulk PDU, the error_status and error_index fields are used by359* libbsnmp to hold the values of the non-repeaters and max-repetitions fields360* that are present only in the getbulk - so before sending the PDU make sure361* these have correct values as well.362*/363static void364snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)365{366assert(pdu != NULL);367368if (pdu->nbindings < non_rep)369pdu->error_status = pdu->nbindings;370else371pdu->error_status = non_rep;372373if (max_rep > 0)374pdu->error_index = max_rep;375else376pdu->error_index = 1;377}378379static int380snmptool_get(struct snmp_toolinfo *snmptoolctx)381{382struct snmp_pdu req, resp;383384snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));385386while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,387snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {388389if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)390snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),391GET_NONREP(snmptoolctx));392393if (snmp_dialog(&req, &resp) == -1) {394warn("Snmp dialog");395break;396}397398if (snmp_parse_resp(&resp, &req) >= 0) {399snmp_output_resp(snmptoolctx, &resp, NULL);400snmp_pdu_free(&resp);401break;402}403404snmp_output_err_resp(snmptoolctx, &resp);405if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||406!ISSET_RETRY(snmptoolctx)) {407snmp_pdu_free(&resp);408break;409}410411/*412* Loop through the object list and set object->error to the413* varbinding that caused the error.414*/415if (snmp_object_seterror(snmptoolctx,416&(resp.bindings[resp.error_index - 1]),417resp.error_status) <= 0) {418snmp_pdu_free(&resp);419break;420}421422fprintf(stderr, "Retrying...\n");423snmp_pdu_free(&resp);424snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));425}426427snmp_pdu_free(&req);428429return (0);430}431432433/* *****************************************************************************434* bsnmpwalk private functions.435*/436/* The default tree to walk. */437static const struct asn_oid snmp_mibII_OID = {4386 , { 1, 3, 6, 1, 2, 1 }439};440441static int32_t442snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,443struct snmp_object *obj, char *string __unused)444{445asn_append_oid(&(obj->val.var), &snmp_mibII_OID);446return (1);447}448449/*450* Prepare the next GetNext/Get PDU to send.451*/452static void453snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)454{455snmp_pdu_create(pdu, op);456asn_append_oid(&(pdu->bindings[0].var), var);457pdu->nbindings = 1;458}459460static int461snmptool_walk(struct snmp_toolinfo *snmptoolctx)462{463struct snmp_pdu req, resp;464struct asn_oid root; /* Keep the initial oid. */465int32_t outputs, rc;466uint32_t op;467468if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)469op = SNMP_PDU_GETBULK;470else471op = SNMP_PDU_GETNEXT;472473snmp_pdu_create(&req, op);474475while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,476snmptool_add_vbind, &req, 1)) > 0) {477478/* Remember the root where the walk started from. */479memset(&root, 0, sizeof(struct asn_oid));480asn_append_oid(&root, &(req.bindings[0].var));481482if (op == SNMP_PDU_GETBULK)483snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),484GET_NONREP(snmptoolctx));485486outputs = 0;487while (snmp_dialog(&req, &resp) >= 0) {488if ((snmp_parse_resp(&resp, &req)) < 0) {489snmp_output_err_resp(snmptoolctx, &resp);490snmp_pdu_free(&resp);491outputs = -1;492break;493}494495rc = snmp_output_resp(snmptoolctx, &resp, &root);496if (rc < 0) {497snmp_pdu_free(&resp);498outputs = -1;499break;500}501502outputs += rc;503504if ((u_int)rc < resp.nbindings || resp.nbindings == 0) {505snmp_pdu_free(&resp);506break;507}508509snmpwalk_nextpdu_create(op,510&(resp.bindings[resp.nbindings - 1].var), &req);511if (op == SNMP_PDU_GETBULK)512snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),513GET_NONREP(snmptoolctx));514snmp_pdu_free(&resp);515}516517/* Just in case our root was a leaf. */518if (outputs == 0) {519snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);520if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {521if (snmp_parse_resp(&resp, &req) < 0)522snmp_output_err_resp(snmptoolctx, &resp);523else524snmp_output_resp(snmptoolctx, &resp,525NULL);526snmp_pdu_free(&resp);527} else528warn("Snmp dialog");529}530531if (snmp_object_remove(snmptoolctx, &root) < 0) {532warnx("snmp_object_remove");533break;534}535536snmp_pdu_free(&req);537snmp_pdu_create(&req, op);538}539540snmp_pdu_free(&req);541542if (rc == 0)543return (0);544else545return (1);546}547548/* *****************************************************************************549* bsnmpset private functions.550*/551552static int32_t553parse_oid_numeric(struct snmp_value *value, char *val)554{555char *endptr;556int32_t saved_errno;557asn_subid_t suboid;558559do {560saved_errno = errno;561errno = 0;562suboid = strtoul(val, &endptr, 10);563if (errno != 0) {564warn("Value %s not supported", val);565errno = saved_errno;566return (-1);567}568errno = saved_errno;569if ((asn_subid_t) suboid > ASN_MAXID) {570warnx("Suboid %u > ASN_MAXID", suboid);571return (-1);572}573if (snmp_suboid_append(&(value->v.oid), suboid) < 0)574return (-1);575val = endptr + 1;576} while (*endptr == '.');577578if (*endptr != '\0')579warnx("OID value %s not supported", val);580581value->syntax = SNMP_SYNTAX_OID;582return (0);583}584585/*586* Allow OID leaf in both forms:587* 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs;588* 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.589*/590static int32_t591parse_oid_string(struct snmp_toolinfo *snmptoolctx,592struct snmp_value *value, char *string)593{594struct snmp_object obj;595596if (isdigit(string[0]))597return (parse_oid_numeric(value, string));598599memset(&obj, 0, sizeof(struct snmp_object));600if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {601warnx("Unknown OID enum string - %s", string);602return (-1);603}604605asn_append_oid(&(value->v.oid), &(obj.val.var));606return (1);607}608609static int32_t610parse_ip(struct snmp_value * value, char * val)611{612char *endptr, *str;613int32_t i;614uint32_t v;615616str = val;617for (i = 0; i < 4; i++) {618v = strtoul(str, &endptr, 10);619if (v > 0xff)620return (-1);621if (*endptr != '.' && *endptr != '\0' && i != 3)622break;623str = endptr + 1;624value->v.ipaddress[i] = (uint8_t) v;625}626value->syntax = SNMP_SYNTAX_IPADDRESS;627628return (0);629}630631static int32_t632parse_int(struct snmp_value *value, char *val)633{634char *endptr;635int32_t v, saved_errno;636637saved_errno = errno;638errno = 0;639640v = strtol(val, &endptr, 10);641642if (errno != 0) {643warn("Value %s not supported", val);644errno = saved_errno;645return (-1);646}647648value->syntax = SNMP_SYNTAX_INTEGER;649value->v.integer = v;650errno = saved_errno;651652return (0);653}654655static int32_t656parse_int_string(struct snmp_object *object, char *val)657{658int32_t v;659660if (isdigit(val[0]))661return ((parse_int(&(object->val), val)));662663if (object->info == NULL) {664warnx("Unknown enumerated integer type - %s", val);665return (-1);666}667if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)668warnx("Unknown enumerated integer type - %s", val);669670object->val.v.integer = v;671return (1);672}673674/*675* Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,676* SNMP_SYNTAX_TIMETICKS.677*/678static int32_t679parse_uint(struct snmp_value *value, char *val)680{681char *endptr;682uint32_t v = 0;683int32_t saved_errno;684685saved_errno = errno;686errno = 0;687688v = strtoul(val, &endptr, 10);689690if (errno != 0) {691warn("Value %s not supported", val);692errno = saved_errno;693return (-1);694}695696value->v.uint32 = v;697errno = saved_errno;698699return (0);700}701702static int32_t703parse_ticks(struct snmp_value *value, char *val)704{705if (parse_uint(value, val) < 0)706return (-1);707708value->syntax = SNMP_SYNTAX_TIMETICKS;709return (0);710}711712static int32_t713parse_gauge(struct snmp_value *value, char *val)714{715if (parse_uint(value, val) < 0)716return (-1);717718value->syntax = SNMP_SYNTAX_GAUGE;719return (0);720}721722static int32_t723parse_counter(struct snmp_value *value, char *val)724{725if (parse_uint(value, val) < 0)726return (-1);727728value->syntax = SNMP_SYNTAX_COUNTER;729return (0);730}731732static int32_t733parse_uint64(struct snmp_value *value, char *val)734{735char *endptr;736int32_t saved_errno;737uint64_t v;738739saved_errno = errno;740errno = 0;741742v = strtoull(val, &endptr, 10);743744if (errno != 0) {745warnx("Value %s not supported", val);746errno = saved_errno;747return (-1);748}749750value->syntax = SNMP_SYNTAX_COUNTER64;751value->v.counter64 = v;752errno = saved_errno;753754return (0);755}756757static int32_t758parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)759{760switch (syntax) {761case SNMP_SYNTAX_INTEGER:762return (parse_int(value, val));763case SNMP_SYNTAX_IPADDRESS:764return (parse_ip(value, val));765case SNMP_SYNTAX_COUNTER:766return (parse_counter(value, val));767case SNMP_SYNTAX_GAUGE:768return (parse_gauge(value, val));769case SNMP_SYNTAX_TIMETICKS:770return (parse_ticks(value, val));771case SNMP_SYNTAX_COUNTER64:772return (parse_uint64(value, val));773case SNMP_SYNTAX_OCTETSTRING:774return (snmp_tc2oct(SNMP_STRING, value, val));775case SNMP_SYNTAX_OID:776return (parse_oid_numeric(value, val));777default:778/* NOTREACHED */779break;780}781782return (-1);783}784785/*786* Parse a command line argument of type OID=syntax:value and fill in whatever787* fields can be derived from the input into snmp_value structure. Reads numeric788* OIDs.789*/790static int32_t791parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)792{793int32_t cnt;794char *ptr;795enum snmp_syntax syntax;796char oid_str[ASN_OIDSTRLEN];797798ptr = str;799for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)800if (ptr[cnt] == '=')801break;802803if (cnt >= ASN_OIDSTRLEN) {804warnx("OID too long - %s", str);805return (-1);806}807strlcpy(oid_str, ptr, (size_t) (cnt + 1));808809ptr = str + cnt + 1;810for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)811if(ptr[cnt] == ':')812break;813814if (cnt >= MAX_CMD_SYNTAX_LEN) {815warnx("Unknown syntax in OID - %s", str);816return (-1);817}818819if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {820warnx("Unknown syntax in OID - %s", ptr);821return (-1);822}823824ptr = ptr + cnt + 1;825for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)826if (ptr[cnt] == '\0')827break;828829if (ptr[cnt] != '\0') {830warnx("Value string too long - %s", ptr);831return (-1);832}833834/*835* Here try parsing the OIDs and syntaxes and then check values - have836* to know syntax to check value boundaries.837*/838if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {839warnx("Error parsing OID %s", oid_str);840return (-1);841}842843if (parse_syntax_val(snmp_val, syntax, ptr) < 0)844return (-1);845846return (1);847}848849static int32_t850parse_syntax_strval(struct snmp_toolinfo *snmptoolctx,851struct snmp_object *object, char *str)852{853uint32_t len;854enum snmp_syntax syn;855856/*857* Syntax string here not required - still may be present.858*/859860if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {861for (len = 0 ; *(str + len) != ':'; len++) {862if (*(str + len) == '\0') {863warnx("Syntax missing in value - %s", str);864return (-1);865}866}867if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {868warnx("Unknown syntax in - %s", str);869return (-1);870}871if (syn != object->val.syntax) {872if (!ISSET_ERRIGNORE(snmptoolctx)) {873warnx("Bad syntax in - %s", str);874return (-1);875} else876object->val.syntax = syn;877}878len++;879} else880len = 0;881882switch (object->val.syntax) {883case SNMP_SYNTAX_INTEGER:884return (parse_int_string(object, str + len));885case SNMP_SYNTAX_IPADDRESS:886return (parse_ip(&(object->val), str + len));887case SNMP_SYNTAX_COUNTER:888return (parse_counter(&(object->val), str + len));889case SNMP_SYNTAX_GAUGE:890return (parse_gauge(&(object->val), str + len));891case SNMP_SYNTAX_TIMETICKS:892return (parse_ticks(&(object->val), str + len));893case SNMP_SYNTAX_COUNTER64:894return (parse_uint64(&(object->val), str + len));895case SNMP_SYNTAX_OCTETSTRING:896return (snmp_tc2oct(object->info->tc, &(object->val),897str + len));898case SNMP_SYNTAX_OID:899return (parse_oid_string(snmptoolctx, &(object->val),900str + len));901default:902/* NOTREACHED */903break;904}905906return (-1);907}908909static int32_t910parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,911struct snmp_object *obj, char *argv)912{913char *ptr;914915if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)916return (-1);917918if (*ptr != '=') {919warnx("Value to set expected after OID");920return (-1);921}922923if (parse_syntax_strval(snmptoolctx, obj, ptr + 1) < 0)924return (-1);925926return (1);927}928929930static int32_t931snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,932struct snmp_object *obj, char *argv)933{934if (argv == NULL)935return (-1);936937if (ISSET_NUMERIC(snmptoolctx)) {938if (parse_pair_numoid_val(argv, &(obj->val)) < 0)939return (-1);940} else {941if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)942return (-1);943}944945return (1);946}947948static int32_t949add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)950{951int8_t i;952953dst->syntax = SNMP_SYNTAX_IPADDRESS;954for (i = 0; i < 4; i++)955dst->v.ipaddress[i] = src->v.ipaddress[i];956957return (1);958}959960static int32_t961add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)962{963if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {964warnx("OctetString len too big - %u", src->v.octetstring.len);965return (-1);966}967968if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==969NULL) {970syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));971return (-1);972}973974memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,975src->v.octetstring.len);976dst->syntax = SNMP_SYNTAX_OCTETSTRING;977dst->v.octetstring.len = src->v.octetstring.len;978979return(0);980}981982static int32_t983add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)984{985asn_append_oid(&(dst->v.oid), &(src->v.oid));986dst->syntax = SNMP_SYNTAX_OID;987return (0);988}989990/*991* Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,992* SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -993* return error.994*/995static int32_t996snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)997{998if (dst == NULL || src == NULL)999return (-1);10001001switch (src->syntax) {1002case SNMP_SYNTAX_INTEGER:1003dst->v.integer = src->v.integer;1004dst->syntax = SNMP_SYNTAX_INTEGER;1005break;1006case SNMP_SYNTAX_TIMETICKS:1007dst->v.uint32 = src->v.uint32;1008dst->syntax = SNMP_SYNTAX_TIMETICKS;1009break;1010case SNMP_SYNTAX_GAUGE:1011dst->v.uint32 = src->v.uint32;1012dst->syntax = SNMP_SYNTAX_GAUGE;1013break;1014case SNMP_SYNTAX_COUNTER:1015dst->v.uint32 = src->v.uint32;1016dst->syntax = SNMP_SYNTAX_COUNTER;1017break;1018case SNMP_SYNTAX_COUNTER64:1019dst->v.counter64 = src->v.counter64;1020dst->syntax = SNMP_SYNTAX_COUNTER64;1021break;1022case SNMP_SYNTAX_IPADDRESS:1023add_ip_syntax(dst, src);1024break;1025case SNMP_SYNTAX_OCTETSTRING:1026add_octstring_syntax(dst, src);1027break;1028case SNMP_SYNTAX_OID:1029add_oid_syntax(dst, src);1030break;1031default:1032warnx("Unknown syntax %d", src->syntax);1033return (-1);1034}10351036return (0);1037}10381039static int32_t1040snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,1041struct snmp_object *obj)1042{1043if (pdu->version == SNMP_V1 && obj->val.syntax ==1044SNMP_SYNTAX_COUNTER64) {1045warnx("64-bit counters are not supported in SNMPv1 PDU");1046return (-1);1047}10481049if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))1050return (1);10511052if (obj->info->access < SNMP_ACCESS_SET) {1053warnx("Object %s not accessible for set - try 'bsnmpset -a'",1054obj->info->string);1055return (-1);1056}10571058return (1);1059}10601061static int32_t1062snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)1063{1064if (pdu->nbindings > SNMP_MAX_BINDINGS) {1065warnx("Too many OIDs for one PDU");1066return (-1);1067}10681069if (obj->error > 0)1070return (0);10711072if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))1073< 0)1074return (-1);10751076asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));1077pdu->nbindings++;10781079return (pdu->nbindings);1080}10811082static int1083snmptool_set(struct snmp_toolinfo *snmptoolctx)1084{1085struct snmp_pdu req, resp;10861087snmp_pdu_create(&req, SNMP_PDU_SET);10881089while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,1090snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {1091if (snmp_dialog(&req, &resp)) {1092warn("Snmp dialog");1093break;1094}10951096if (snmp_pdu_check(&req, &resp) > 0) {1097if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)1098snmp_output_resp(snmptoolctx, &resp, NULL);1099snmp_pdu_free(&resp);1100break;1101}11021103snmp_output_err_resp(snmptoolctx, &resp);1104if (!ISSET_RETRY(snmptoolctx)) {1105snmp_pdu_free(&resp);1106break;1107}11081109if (snmp_object_seterror(snmptoolctx,1110&(resp.bindings[resp.error_index - 1]),1111resp.error_status) <= 0) {1112snmp_pdu_free(&resp);1113break;1114}11151116fprintf(stderr, "Retrying...\n");1117snmp_pdu_free(&req);1118snmp_pdu_create(&req, SNMP_PDU_SET);1119}11201121snmp_pdu_free(&req);11221123return (0);1124}11251126/* *****************************************************************************1127* main1128*/1129/*1130* According to command line options prepare SNMP Get | GetNext | GetBulk PDU.1131* Wait for a response and print it.1132*/1133/*1134* Do a 'snmp walk' - according to command line options request for values1135* lexicographically subsequent and subrooted at a common node. Send a GetNext1136* PDU requesting the value for each next variable and print the response. Stop1137* when a Response PDU is received that contains the value of a variable not1138* subrooted at the variable the walk started.1139*/1140int1141main(int argc, char ** argv)1142{1143struct snmp_toolinfo snmptoolctx;1144int32_t oid_cnt, last_oid, opt_num;1145int rc = 0;11461147/* Make sure program_name is set and valid. */1148if (*argv == NULL)1149program_name = "snmptool";1150else {1151program_name = strrchr(*argv, '/');1152if (program_name != NULL)1153program_name++;1154else1155program_name = *argv;1156}11571158if (program_name == NULL) {1159fprintf(stderr, "Error: No program name?\n");1160exit (1);1161} else if (strcmp(program_name, "bsnmpget") == 0)1162program = BSNMPGET;1163else if (strcmp(program_name, "bsnmpwalk") == 0)1164program = BSNMPWALK;1165else if (strcmp(program_name, "bsnmpset") == 0)1166program = BSNMPSET;1167else {1168fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);1169exit (1);1170}11711172/* Initialize. */1173if (snmptool_init(&snmptoolctx) < 0)1174exit (1);11751176if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {1177snmp_tool_freeall(&snmptoolctx);1178/* On -h (help) exit without error. */1179if (opt_num == -2)1180exit(0);1181else {1182fprintf(stderr, "Error: %s\n", snmp_client.error);1183exit(1);1184}1185}11861187oid_cnt = argc - opt_num - 1;1188if (oid_cnt == 0) {1189switch (program) {1190case BSNMPGET:1191if (!ISSET_EDISCOVER(&snmptoolctx) &&1192!ISSET_LOCALKEY(&snmptoolctx)) {1193fprintf(stderr, "No OID given.\n");1194usage();1195snmp_tool_freeall(&snmptoolctx);1196exit(1);1197}1198break;11991200case BSNMPWALK:1201if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,1202NULL) < 0) {1203fprintf(stderr,1204"Error setting default subtree.\n");1205snmp_tool_freeall(&snmptoolctx);1206exit(1);1207}1208break;12091210case BSNMPSET:1211fprintf(stderr, "No OID given.\n");1212usage();1213snmp_tool_freeall(&snmptoolctx);1214exit(1);1215}1216}12171218if (snmp_import_all(&snmptoolctx) < 0) {1219snmp_tool_freeall(&snmptoolctx);1220exit(1);1221}12221223/* A simple sanity check - can not send GETBULK when using SNMPv1. */1224if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&1225GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {1226fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");1227snmp_tool_freeall(&snmptoolctx);1228exit(1);1229}12301231for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {1232if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?1233snmpset_parse_oid : snmptools_parse_oid,1234argv[last_oid])) < 0) {1235fprintf(stderr, "Error parsing OID string '%s'.\n",1236argv[last_oid]);1237snmp_tool_freeall(&snmptoolctx);1238exit(1);1239}1240}12411242if (snmp_open(NULL, NULL, NULL, NULL)) {1243fprintf(stderr, "snmp_open(3): %s\n", snmp_client.error);1244snmp_tool_freeall(&snmptoolctx);1245exit(1);1246}12471248if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)1249SET_EDISCOVER(&snmptoolctx);12501251if (ISSET_EDISCOVER(&snmptoolctx) &&1252snmp_discover_engine(snmptoolctx.passwd) < 0) {1253warn("Unknown SNMP Engine ID");1254rc = 1;1255goto cleanup;1256}12571258if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||1259ISSET_EDISCOVER(&snmptoolctx))1260snmp_output_engine();12611262if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&1263!ISSET_EDISCOVER(&snmptoolctx)) {1264if (snmp_passwd_to_keys(&snmp_client.user,1265snmptoolctx.passwd) != SNMP_CODE_OK ||1266snmp_get_local_keys(&snmp_client.user,1267snmp_client.engine.engine_id,1268snmp_client.engine.engine_len) != SNMP_CODE_OK) {1269warn("Failed to get keys");1270rc = 1;1271goto cleanup;1272}1273}12741275if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||1276ISSET_EDISCOVER(&snmptoolctx))1277snmp_output_keys();12781279if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)1280goto cleanup;12811282switch (program) {1283case BSNMPGET:1284rc = snmptool_get(&snmptoolctx);1285break;1286case BSNMPWALK:1287rc = snmptool_walk(&snmptoolctx);1288break;1289case BSNMPSET:1290rc = snmptool_set(&snmptoolctx);1291break;1292}129312941295cleanup:1296snmp_tool_freeall(&snmptoolctx);1297snmp_close();12981299exit(rc);1300}130113021303