1216295Ssyrinx/*- 2216295Ssyrinx * Copyright (c) 2005-2006 The FreeBSD Project 3216295Ssyrinx * All rights reserved. 4216295Ssyrinx * 5216295Ssyrinx * Author: Shteryana Shopova <syrinx@FreeBSD.org> 6216295Ssyrinx * 7216295Ssyrinx * Redistribution of this software and documentation and use in source and 8216295Ssyrinx * binary forms, with or without modification, are permitted provided that 9216295Ssyrinx * the following conditions are met: 10216295Ssyrinx * 11216295Ssyrinx * 1. Redistributions of source code or documentation must retain the above 12216295Ssyrinx * copyright notice, this list of conditions and the following disclaimer. 13216295Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 14216295Ssyrinx * notice, this list of conditions and the following disclaimer in the 15216295Ssyrinx * documentation and/or other materials provided with the distribution. 16216295Ssyrinx * 17216295Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18216295Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19216295Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20216295Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21216295Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22216295Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23216295Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24216295Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25216295Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26216295Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27216295Ssyrinx * SUCH DAMAGE. 28216295Ssyrinx * 29216295Ssyrinx * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents, 30216295Ssyrinx * bsnmpset can be used to set MIB objects in an agent. 31216295Ssyrinx * 32216295Ssyrinx * $FreeBSD: stable/10/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c 312050 2017-01-13 08:59:22Z ngie $ 33216295Ssyrinx */ 34216295Ssyrinx 35216295Ssyrinx#include <sys/queue.h> 36216295Ssyrinx#include <sys/types.h> 37216295Ssyrinx 38216295Ssyrinx#include <assert.h> 39216295Ssyrinx#include <ctype.h> 40216295Ssyrinx#include <err.h> 41216295Ssyrinx#include <errno.h> 42216295Ssyrinx#include <stdarg.h> 43216295Ssyrinx#include <stdio.h> 44216295Ssyrinx#include <stdlib.h> 45216295Ssyrinx#include <string.h> 46216295Ssyrinx#include <syslog.h> 47216295Ssyrinx#include <unistd.h> 48216295Ssyrinx 49216295Ssyrinx#include <bsnmp/asn1.h> 50216295Ssyrinx#include <bsnmp/snmp.h> 51216295Ssyrinx#include <bsnmp/snmpclient.h> 52216295Ssyrinx#include "bsnmptc.h" 53216295Ssyrinx#include "bsnmptools.h" 54216295Ssyrinx 55216295Ssyrinxstatic const char *program_name = NULL; 56216295Ssyrinxstatic enum program_e { 57216295Ssyrinx BSNMPGET, 58216295Ssyrinx BSNMPWALK, 59216295Ssyrinx BSNMPSET 60216295Ssyrinx} program; 61216295Ssyrinx 62216295Ssyrinx/* ***************************************************************************** 63216295Ssyrinx * Common bsnmptools functions. 64216295Ssyrinx */ 65216295Ssyrinxstatic void 66216295Ssyrinxusage(void) 67216295Ssyrinx{ 68216295Ssyrinx fprintf(stderr, 69216295Ssyrinx"Usage:\n" 70216295Ssyrinx"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n" 71216295Ssyrinx"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n" 72216295Ssyrinx"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n" 73216295Ssyrinx"\t[-t timeout] [-U options] [-v version]%s\n", 74216295Ssyrinx program_name, 75216295Ssyrinx (program == BSNMPGET) ? "[-aDdehnK]" : 76216295Ssyrinx (program == BSNMPWALK) ? "[-dhnK]" : 77216295Ssyrinx (program == BSNMPSET) ? "[-adehnK]" : 78216295Ssyrinx "", 79229933Ssyrinx (program == BSNMPGET || program == BSNMPWALK) ? 80229933Ssyrinx " [-M max-repetitions] [-N non-repeaters]" : "", 81229933Ssyrinx (program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "", 82216295Ssyrinx (program == BSNMPGET) ? " OID [OID ...]" : 83216295Ssyrinx (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" : 84216295Ssyrinx "" 85216295Ssyrinx ); 86216295Ssyrinx} 87216295Ssyrinx 88216295Ssyrinxstatic int32_t 89216295Ssyrinxparse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 90216295Ssyrinx{ 91216295Ssyrinx uint32_t v; 92216295Ssyrinx 93216295Ssyrinx assert(opt_arg != NULL); 94216295Ssyrinx 95216295Ssyrinx v = strtoul(opt_arg, (void *) NULL, 10); 96216295Ssyrinx 97216295Ssyrinx if (v > SNMP_MAX_BINDINGS) { 98216295Ssyrinx warnx("Max repetitions value greater than %d maximum allowed.", 99216295Ssyrinx SNMP_MAX_BINDINGS); 100216295Ssyrinx return (-1); 101216295Ssyrinx } 102216295Ssyrinx 103216295Ssyrinx SET_MAXREP(snmptoolctx, v); 104216295Ssyrinx return (2); 105216295Ssyrinx} 106216295Ssyrinx 107216295Ssyrinxstatic int32_t 108216295Ssyrinxparse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 109216295Ssyrinx{ 110216295Ssyrinx uint32_t v; 111216295Ssyrinx 112216295Ssyrinx assert(opt_arg != NULL); 113216295Ssyrinx 114216295Ssyrinx v = strtoul(opt_arg, (void *) NULL, 10); 115216295Ssyrinx 116216295Ssyrinx if (v > SNMP_MAX_BINDINGS) { 117216295Ssyrinx warnx("Non repeaters value greater than %d maximum allowed.", 118216295Ssyrinx SNMP_MAX_BINDINGS); 119216295Ssyrinx return (-1); 120216295Ssyrinx } 121216295Ssyrinx 122216295Ssyrinx SET_NONREP(snmptoolctx, v); 123216295Ssyrinx return (2); 124216295Ssyrinx} 125216295Ssyrinx 126216295Ssyrinxstatic int32_t 127216295Ssyrinxparse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 128216295Ssyrinx{ 129216295Ssyrinx assert(opt_arg != NULL); 130216295Ssyrinx 131216295Ssyrinx if (strcasecmp(opt_arg, "getbulk") == 0) 132216295Ssyrinx SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK); 133216295Ssyrinx else if (strcasecmp(opt_arg, "getnext") == 0) 134216295Ssyrinx SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT); 135216295Ssyrinx else if (strcasecmp(opt_arg, "get") == 0) 136216295Ssyrinx SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET); 137216295Ssyrinx else { 138216295Ssyrinx warnx("PDU type '%s' not supported.", opt_arg); 139216295Ssyrinx return (-1); 140216295Ssyrinx } 141216295Ssyrinx 142216295Ssyrinx return (2); 143216295Ssyrinx} 144216295Ssyrinx 145216295Ssyrinxstatic int32_t 146216295Ssyrinxsnmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv) 147216295Ssyrinx{ 148216295Ssyrinx int32_t count, optnum = 0; 149216295Ssyrinx int ch; 150216295Ssyrinx const char *opts; 151216295Ssyrinx 152216295Ssyrinx switch (program) { 153216295Ssyrinx case BSNMPWALK: 154229933Ssyrinx opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; 155216295Ssyrinx break; 156216295Ssyrinx case BSNMPGET: 157216295Ssyrinx opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; 158216295Ssyrinx break; 159216295Ssyrinx case BSNMPSET: 160216295Ssyrinx opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:"; 161216295Ssyrinx break; 162216295Ssyrinx default: 163216295Ssyrinx return (-1); 164216295Ssyrinx } 165216295Ssyrinx 166216295Ssyrinx while ((ch = getopt(argc, argv, opts)) != EOF) { 167216295Ssyrinx switch (ch) { 168216295Ssyrinx case 'A': 169216295Ssyrinx count = parse_authentication(snmptoolctx, optarg); 170216295Ssyrinx break; 171216295Ssyrinx case 'a': 172216295Ssyrinx count = parse_skip_access(snmptoolctx); 173216295Ssyrinx break; 174216295Ssyrinx case 'b': 175216295Ssyrinx count = parse_buflen(optarg); 176216295Ssyrinx break; 177216295Ssyrinx case 'D': 178216295Ssyrinx count = parse_discovery(snmptoolctx); 179216295Ssyrinx break; 180216295Ssyrinx case 'd': 181216295Ssyrinx count = parse_debug(); 182216295Ssyrinx break; 183216295Ssyrinx case 'e': 184216295Ssyrinx count = parse_errors(snmptoolctx); 185216295Ssyrinx break; 186216295Ssyrinx case 'h': 187216295Ssyrinx usage(); 188216295Ssyrinx return (-2); 189216295Ssyrinx case 'C': 190216295Ssyrinx count = parse_context(snmptoolctx, optarg); 191216295Ssyrinx break; 192216295Ssyrinx case 'I': 193216295Ssyrinx count = parse_include(snmptoolctx, optarg); 194216295Ssyrinx break; 195216295Ssyrinx case 'i': 196216295Ssyrinx count = parse_file(snmptoolctx, optarg); 197216295Ssyrinx break; 198216295Ssyrinx case 'K': 199216295Ssyrinx count = parse_local_key(snmptoolctx); 200216295Ssyrinx break; 201216295Ssyrinx case 'l': 202216295Ssyrinx count = parse_local_path(optarg); 203216295Ssyrinx break; 204216295Ssyrinx case 'M': 205216295Ssyrinx count = parse_max_repetitions(snmptoolctx, optarg); 206216295Ssyrinx break; 207216295Ssyrinx case 'N': 208216295Ssyrinx count = parse_non_repeaters(snmptoolctx, optarg); 209216295Ssyrinx break; 210216295Ssyrinx case 'n': 211216295Ssyrinx count = parse_num_oids(snmptoolctx); 212216295Ssyrinx break; 213216295Ssyrinx case 'o': 214216295Ssyrinx count = parse_output(snmptoolctx, optarg); 215216295Ssyrinx break; 216216295Ssyrinx case 'P': 217216295Ssyrinx count = parse_privacy(snmptoolctx, optarg); 218216295Ssyrinx break; 219216295Ssyrinx case 'p': 220216295Ssyrinx count = parse_pdu_type(snmptoolctx, optarg); 221216295Ssyrinx break; 222216295Ssyrinx case 'r': 223216295Ssyrinx count = parse_retry(optarg); 224216295Ssyrinx break; 225216295Ssyrinx case 's': 226216295Ssyrinx count = parse_server(optarg); 227216295Ssyrinx break; 228216295Ssyrinx case 't': 229216295Ssyrinx count = parse_timeout(optarg); 230216295Ssyrinx break; 231216295Ssyrinx case 'U': 232216295Ssyrinx count = parse_user_security(snmptoolctx, optarg); 233216295Ssyrinx break; 234216295Ssyrinx case 'v': 235216295Ssyrinx count = parse_version(optarg); 236216295Ssyrinx break; 237216295Ssyrinx case '?': 238216295Ssyrinx default: 239216295Ssyrinx usage(); 240216295Ssyrinx return (-1); 241216295Ssyrinx } 242216295Ssyrinx if (count < 0) 243216295Ssyrinx return (-1); 244216295Ssyrinx optnum += count; 245216295Ssyrinx } 246216295Ssyrinx 247216295Ssyrinx return (optnum); 248216295Ssyrinx} 249216295Ssyrinx 250216295Ssyrinx/* 251216295Ssyrinx * Read user input OID - one of following formats: 252228990Suqs * 1) 1.2.1.1.2.1.0 - that is if option numeric was given; 253216295Ssyrinx * 2) string - in such case append .0 to the asn_oid subs; 254228990Suqs * 3) string.1 - no additional processing required in such case. 255216295Ssyrinx */ 256216295Ssyrinxstatic char * 257216295Ssyrinxsnmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx, 258216295Ssyrinx struct snmp_object *obj, char *argv) 259216295Ssyrinx{ 260216295Ssyrinx char string[MAXSTR], *str; 261216295Ssyrinx int32_t i = 0; 262216295Ssyrinx struct asn_oid in_oid; 263216295Ssyrinx 264216295Ssyrinx str = argv; 265216295Ssyrinx 266216295Ssyrinx if (*str == '.') 267216295Ssyrinx str++; 268216295Ssyrinx 269216295Ssyrinx while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) { 270216295Ssyrinx str++; 271216295Ssyrinx i++; 272216295Ssyrinx } 273216295Ssyrinx 274216295Ssyrinx if (i <= 0 || i >= MAXSTR) 275216295Ssyrinx return (NULL); 276216295Ssyrinx 277216295Ssyrinx memset(&in_oid, 0, sizeof(struct asn_oid)); 278216295Ssyrinx if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) { 279216295Ssyrinx warnx("Invalid OID - %s", argv); 280216295Ssyrinx return (NULL); 281216295Ssyrinx } 282216295Ssyrinx 283216295Ssyrinx strlcpy(string, argv, i + 1); 284216295Ssyrinx if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) { 285216295Ssyrinx warnx("No entry for %s in mapping lists", string); 286216295Ssyrinx return (NULL); 287216295Ssyrinx } 288216295Ssyrinx 289216295Ssyrinx /* If OID given on command line append it. */ 290216295Ssyrinx if (in_oid.len > 0) 291216295Ssyrinx asn_append_oid(&(obj->val.var), &in_oid); 292216295Ssyrinx else if (*str == '[') { 293216295Ssyrinx if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL) 294216295Ssyrinx return (NULL); 295216295Ssyrinx } else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) == 296216295Ssyrinx SNMP_PDU_GET) { 297216295Ssyrinx if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0) 298216295Ssyrinx return (NULL); 299216295Ssyrinx } 300216295Ssyrinx 301216295Ssyrinx return (str); 302216295Ssyrinx} 303216295Ssyrinx 304216295Ssyrinxstatic int32_t 305216295Ssyrinxsnmptools_parse_oid(struct snmp_toolinfo *snmptoolctx, 306216295Ssyrinx struct snmp_object *obj, char *argv) 307216295Ssyrinx{ 308216295Ssyrinx if (argv == NULL) 309216295Ssyrinx return (-1); 310216295Ssyrinx 311216295Ssyrinx if (ISSET_NUMERIC(snmptoolctx)) { 312216295Ssyrinx if (snmp_parse_numoid(argv, &(obj->val.var)) < 0) 313216295Ssyrinx return (-1); 314216295Ssyrinx } else { 315216295Ssyrinx if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL && 316216295Ssyrinx snmp_parse_numoid(argv, &(obj->val.var)) < 0) 317216295Ssyrinx return (-1); 318216295Ssyrinx } 319216295Ssyrinx 320216295Ssyrinx return (1); 321216295Ssyrinx} 322216295Ssyrinx 323216295Ssyrinxstatic int32_t 324216295Ssyrinxsnmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj) 325216295Ssyrinx{ 326216295Ssyrinx if (obj->error > 0) 327216295Ssyrinx return (0); 328216295Ssyrinx 329216295Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var)); 330216295Ssyrinx pdu->nbindings++; 331216295Ssyrinx 332216295Ssyrinx return (pdu->nbindings); 333216295Ssyrinx} 334216295Ssyrinx 335216295Ssyrinx/* ***************************************************************************** 336216295Ssyrinx * bsnmpget private functions. 337216295Ssyrinx */ 338216295Ssyrinxstatic int32_t 339216295Ssyrinxsnmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, 340216295Ssyrinx struct snmp_object *obj) 341216295Ssyrinx{ 342216295Ssyrinx if (pdu->version == SNMP_V1 && obj->val.syntax == 343216295Ssyrinx SNMP_SYNTAX_COUNTER64) { 344216295Ssyrinx warnx("64-bit counters are not supported in SNMPv1 PDU"); 345216295Ssyrinx return (-1); 346216295Ssyrinx } 347216295Ssyrinx 348216295Ssyrinx if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT || 349216295Ssyrinx pdu->type == SNMP_PDU_GETBULK) 350216295Ssyrinx return (1); 351216295Ssyrinx 352216295Ssyrinx if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) { 353216295Ssyrinx warnx("Only leaf object values can be added to GET PDU"); 354216295Ssyrinx return (-1); 355216295Ssyrinx } 356216295Ssyrinx 357216295Ssyrinx return (1); 358216295Ssyrinx} 359216295Ssyrinx 360216295Ssyrinx/* 361216295Ssyrinx * In case of a getbulk PDU, the error_status and error_index fields are used by 362216295Ssyrinx * libbsnmp to hold the values of the non-repeaters and max-repetitions fields 363216295Ssyrinx * that are present only in the getbulk - so before sending the PDU make sure 364216295Ssyrinx * these have correct values as well. 365216295Ssyrinx */ 366216295Ssyrinxstatic void 367216295Ssyrinxsnmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep) 368216295Ssyrinx{ 369216295Ssyrinx assert(pdu != NULL); 370216295Ssyrinx 371216295Ssyrinx if (pdu->nbindings < non_rep) 372216295Ssyrinx pdu->error_status = pdu->nbindings; 373216295Ssyrinx else 374216295Ssyrinx pdu->error_status = non_rep; 375216295Ssyrinx 376216295Ssyrinx if (max_rep > 0) 377216295Ssyrinx pdu->error_index = max_rep; 378216295Ssyrinx else 379216295Ssyrinx pdu->error_index = 1; 380216295Ssyrinx} 381216295Ssyrinx 382216295Ssyrinxstatic int 383216295Ssyrinxsnmptool_get(struct snmp_toolinfo *snmptoolctx) 384216295Ssyrinx{ 385216295Ssyrinx struct snmp_pdu req, resp; 386216295Ssyrinx 387216295Ssyrinx snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx)); 388216295Ssyrinx 389216295Ssyrinx while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind, 390216295Ssyrinx snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) { 391216295Ssyrinx 392216295Ssyrinx if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK) 393216295Ssyrinx snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 394216295Ssyrinx GET_NONREP(snmptoolctx)); 395216295Ssyrinx 396216295Ssyrinx if (snmp_dialog(&req, &resp) == -1) { 397311595Sngie warn("Snmp dialog"); 398216295Ssyrinx break; 399216295Ssyrinx } 400216295Ssyrinx 401216295Ssyrinx if (snmp_parse_resp(&resp, &req) >= 0) { 402229933Ssyrinx snmp_output_resp(snmptoolctx, &resp, NULL); 403312050Sngie snmp_pdu_free(&resp); 404216295Ssyrinx break; 405216295Ssyrinx } 406216295Ssyrinx 407216295Ssyrinx snmp_output_err_resp(snmptoolctx, &resp); 408216295Ssyrinx if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK || 409312050Sngie !ISSET_RETRY(snmptoolctx)) { 410312050Sngie snmp_pdu_free(&resp); 411216295Ssyrinx break; 412312050Sngie } 413216295Ssyrinx 414216295Ssyrinx /* 415216295Ssyrinx * Loop through the object list and set object->error to the 416216295Ssyrinx * varbinding that caused the error. 417216295Ssyrinx */ 418216295Ssyrinx if (snmp_object_seterror(snmptoolctx, 419216295Ssyrinx &(resp.bindings[resp.error_index - 1]), 420312050Sngie resp.error_status) <= 0) { 421312050Sngie snmp_pdu_free(&resp); 422216295Ssyrinx break; 423312050Sngie } 424216295Ssyrinx 425216295Ssyrinx fprintf(stderr, "Retrying...\n"); 426216295Ssyrinx snmp_pdu_free(&resp); 427216295Ssyrinx snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx)); 428216295Ssyrinx } 429216295Ssyrinx 430312050Sngie snmp_pdu_free(&req); 431216295Ssyrinx 432216295Ssyrinx return (0); 433216295Ssyrinx} 434216295Ssyrinx 435216295Ssyrinx 436216295Ssyrinx/* ***************************************************************************** 437216295Ssyrinx * bsnmpwalk private functions. 438216295Ssyrinx */ 439216295Ssyrinx/* The default tree to walk. */ 440216295Ssyrinxstatic const struct asn_oid snmp_mibII_OID = { 441216295Ssyrinx 6 , { 1, 3, 6, 1, 2, 1 } 442216295Ssyrinx}; 443216295Ssyrinx 444216295Ssyrinxstatic int32_t 445216295Ssyrinxsnmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused, 446216295Ssyrinx struct snmp_object *obj, char *string __unused) 447216295Ssyrinx{ 448216295Ssyrinx asn_append_oid(&(obj->val.var), &snmp_mibII_OID); 449216295Ssyrinx return (1); 450216295Ssyrinx} 451216295Ssyrinx 452216295Ssyrinx/* 453216295Ssyrinx * Prepare the next GetNext/Get PDU to send. 454216295Ssyrinx */ 455216295Ssyrinxstatic void 456216295Ssyrinxsnmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu) 457216295Ssyrinx{ 458216295Ssyrinx snmp_pdu_create(pdu, op); 459216295Ssyrinx asn_append_oid(&(pdu->bindings[0].var), var); 460216295Ssyrinx pdu->nbindings = 1; 461216295Ssyrinx} 462216295Ssyrinx 463216295Ssyrinxstatic int 464216295Ssyrinxsnmptool_walk(struct snmp_toolinfo *snmptoolctx) 465216295Ssyrinx{ 466216295Ssyrinx struct snmp_pdu req, resp; 467228990Suqs struct asn_oid root; /* Keep the initial oid. */ 468216295Ssyrinx int32_t outputs, rc; 469229933Ssyrinx uint32_t op; 470216295Ssyrinx 471229933Ssyrinx if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK) 472229933Ssyrinx op = SNMP_PDU_GETBULK; 473229933Ssyrinx else 474229933Ssyrinx op = SNMP_PDU_GETNEXT; 475216295Ssyrinx 476229933Ssyrinx snmp_pdu_create(&req, op); 477229933Ssyrinx 478216295Ssyrinx while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL, 479216295Ssyrinx snmptool_add_vbind, &req, 1)) > 0) { 480216295Ssyrinx 481216295Ssyrinx /* Remember the root where the walk started from. */ 482216295Ssyrinx memset(&root, 0, sizeof(struct asn_oid)); 483216295Ssyrinx asn_append_oid(&root, &(req.bindings[0].var)); 484216295Ssyrinx 485229933Ssyrinx if (op == SNMP_PDU_GETBULK) 486229933Ssyrinx snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 487229933Ssyrinx GET_NONREP(snmptoolctx)); 488229933Ssyrinx 489216295Ssyrinx outputs = 0; 490216295Ssyrinx while (snmp_dialog(&req, &resp) >= 0) { 491216295Ssyrinx if ((snmp_parse_resp(&resp, &req)) < 0) { 492216295Ssyrinx snmp_output_err_resp(snmptoolctx, &resp); 493216295Ssyrinx snmp_pdu_free(&resp); 494216295Ssyrinx outputs = -1; 495216295Ssyrinx break; 496216295Ssyrinx } 497216295Ssyrinx 498229933Ssyrinx rc = snmp_output_resp(snmptoolctx, &resp, &root); 499229933Ssyrinx if (rc < 0) { 500216295Ssyrinx snmp_pdu_free(&resp); 501229933Ssyrinx outputs = -1; 502216295Ssyrinx break; 503216295Ssyrinx } 504216295Ssyrinx 505229933Ssyrinx outputs += rc; 506216295Ssyrinx 507312050Sngie if ((u_int)rc < resp.nbindings) { 508312050Sngie snmp_pdu_free(&resp); 509229933Ssyrinx break; 510312050Sngie } 511229933Ssyrinx 512229933Ssyrinx snmpwalk_nextpdu_create(op, 513229933Ssyrinx &(resp.bindings[resp.nbindings - 1].var), &req); 514229933Ssyrinx if (op == SNMP_PDU_GETBULK) 515229933Ssyrinx snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 516229933Ssyrinx GET_NONREP(snmptoolctx)); 517312050Sngie snmp_pdu_free(&resp); 518216295Ssyrinx } 519216295Ssyrinx 520216295Ssyrinx /* Just in case our root was a leaf. */ 521216295Ssyrinx if (outputs == 0) { 522216295Ssyrinx snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req); 523216295Ssyrinx if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) { 524312050Sngie if (snmp_parse_resp(&resp, &req) < 0) 525216295Ssyrinx snmp_output_err_resp(snmptoolctx, &resp); 526216295Ssyrinx else 527312050Sngie snmp_output_resp(snmptoolctx, &resp, 528312050Sngie NULL); 529216295Ssyrinx snmp_pdu_free(&resp); 530216295Ssyrinx } else 531311595Sngie warn("Snmp dialog"); 532216295Ssyrinx } 533216295Ssyrinx 534216295Ssyrinx if (snmp_object_remove(snmptoolctx, &root) < 0) { 535216295Ssyrinx warnx("snmp_object_remove"); 536216295Ssyrinx break; 537216295Ssyrinx } 538216295Ssyrinx 539312050Sngie snmp_pdu_free(&req); 540229933Ssyrinx snmp_pdu_create(&req, op); 541216295Ssyrinx } 542216295Ssyrinx 543312050Sngie snmp_pdu_free(&req); 544312050Sngie 545216295Ssyrinx if (rc == 0) 546216295Ssyrinx return (0); 547216295Ssyrinx else 548216295Ssyrinx return (1); 549216295Ssyrinx} 550216295Ssyrinx 551216295Ssyrinx/* ***************************************************************************** 552216295Ssyrinx * bsnmpset private functions. 553216295Ssyrinx */ 554216295Ssyrinx 555216295Ssyrinxstatic int32_t 556216295Ssyrinxparse_oid_numeric(struct snmp_value *value, char *val) 557216295Ssyrinx{ 558216295Ssyrinx char *endptr; 559216295Ssyrinx int32_t saved_errno; 560216295Ssyrinx asn_subid_t suboid; 561216295Ssyrinx 562216295Ssyrinx do { 563216295Ssyrinx saved_errno = errno; 564216295Ssyrinx errno = 0; 565216295Ssyrinx suboid = strtoul(val, &endptr, 10); 566216295Ssyrinx if (errno != 0) { 567311595Sngie warn("Value %s not supported", val); 568216295Ssyrinx errno = saved_errno; 569216295Ssyrinx return (-1); 570216295Ssyrinx } 571216295Ssyrinx errno = saved_errno; 572216295Ssyrinx if ((asn_subid_t) suboid > ASN_MAXID) { 573216295Ssyrinx warnx("Suboid %u > ASN_MAXID", suboid); 574216295Ssyrinx return (-1); 575216295Ssyrinx } 576216295Ssyrinx if (snmp_suboid_append(&(value->v.oid), suboid) < 0) 577216295Ssyrinx return (-1); 578216295Ssyrinx val = endptr + 1; 579216295Ssyrinx } while (*endptr == '.'); 580216295Ssyrinx 581216295Ssyrinx if (*endptr != '\0') 582216295Ssyrinx warnx("OID value %s not supported", val); 583216295Ssyrinx 584216295Ssyrinx value->syntax = SNMP_SYNTAX_OID; 585216295Ssyrinx return (0); 586216295Ssyrinx} 587216295Ssyrinx 588216295Ssyrinx/* 589216295Ssyrinx * Allow OID leaf in both forms: 590216295Ssyrinx * 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs; 591216295Ssyrinx * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that. 592216295Ssyrinx */ 593216295Ssyrinxstatic int32_t 594216295Ssyrinxparse_oid_string(struct snmp_toolinfo *snmptoolctx, 595216295Ssyrinx struct snmp_value *value, char *string) 596216295Ssyrinx{ 597216295Ssyrinx struct snmp_object obj; 598216295Ssyrinx 599216295Ssyrinx if (isdigit(string[0])) 600216295Ssyrinx return (parse_oid_numeric(value, string)); 601216295Ssyrinx 602216295Ssyrinx memset(&obj, 0, sizeof(struct snmp_object)); 603216295Ssyrinx if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) { 604216295Ssyrinx warnx("Unknown OID enum string - %s", string); 605216295Ssyrinx return (-1); 606216295Ssyrinx } 607216295Ssyrinx 608216295Ssyrinx asn_append_oid(&(value->v.oid), &(obj.val.var)); 609216295Ssyrinx return (1); 610216295Ssyrinx} 611216295Ssyrinx 612216295Ssyrinxstatic int32_t 613216295Ssyrinxparse_ip(struct snmp_value * value, char * val) 614216295Ssyrinx{ 615310562Sngie char *endptr, *str; 616310562Sngie int32_t i; 617216295Ssyrinx uint32_t v; 618216295Ssyrinx 619216295Ssyrinx str = val; 620216295Ssyrinx for (i = 0; i < 4; i++) { 621216295Ssyrinx v = strtoul(str, &endptr, 10); 622216295Ssyrinx if (v > 0xff) 623216295Ssyrinx return (-1); 624216295Ssyrinx if (*endptr != '.' && *endptr != '\0' && i != 3) 625216295Ssyrinx break; 626216295Ssyrinx str = endptr + 1; 627216295Ssyrinx value->v.ipaddress[i] = (uint8_t) v; 628216295Ssyrinx } 629310562Sngie value->syntax = SNMP_SYNTAX_IPADDRESS; 630216295Ssyrinx 631216295Ssyrinx return (0); 632216295Ssyrinx} 633216295Ssyrinx 634216295Ssyrinxstatic int32_t 635216295Ssyrinxparse_int(struct snmp_value *value, char *val) 636216295Ssyrinx{ 637216295Ssyrinx char *endptr; 638216295Ssyrinx int32_t v, saved_errno; 639216295Ssyrinx 640216295Ssyrinx saved_errno = errno; 641216295Ssyrinx errno = 0; 642216295Ssyrinx 643216295Ssyrinx v = strtol(val, &endptr, 10); 644216295Ssyrinx 645216295Ssyrinx if (errno != 0) { 646311595Sngie warn("Value %s not supported", val); 647216295Ssyrinx errno = saved_errno; 648216295Ssyrinx return (-1); 649216295Ssyrinx } 650216295Ssyrinx 651216295Ssyrinx value->syntax = SNMP_SYNTAX_INTEGER; 652216295Ssyrinx value->v.integer = v; 653216295Ssyrinx errno = saved_errno; 654216295Ssyrinx 655216295Ssyrinx return (0); 656216295Ssyrinx} 657216295Ssyrinx 658216295Ssyrinxstatic int32_t 659216295Ssyrinxparse_int_string(struct snmp_object *object, char *val) 660216295Ssyrinx{ 661216295Ssyrinx int32_t v; 662216295Ssyrinx 663216295Ssyrinx if (isdigit(val[0])) 664216295Ssyrinx return ((parse_int(&(object->val), val))); 665216295Ssyrinx 666216295Ssyrinx if (object->info == NULL) { 667216295Ssyrinx warnx("Unknown enumerated integer type - %s", val); 668216295Ssyrinx return (-1); 669216295Ssyrinx } 670216295Ssyrinx if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0) 671216295Ssyrinx warnx("Unknown enumerated integer type - %s", val); 672216295Ssyrinx 673216295Ssyrinx object->val.v.integer = v; 674216295Ssyrinx return (1); 675216295Ssyrinx} 676216295Ssyrinx 677216295Ssyrinx/* 678216295Ssyrinx * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE, 679216295Ssyrinx * SNMP_SYNTAX_TIMETICKS. 680216295Ssyrinx */ 681216295Ssyrinxstatic int32_t 682216295Ssyrinxparse_uint(struct snmp_value *value, char *val) 683216295Ssyrinx{ 684216295Ssyrinx char *endptr; 685216295Ssyrinx uint32_t v = 0; 686216295Ssyrinx int32_t saved_errno; 687216295Ssyrinx 688216295Ssyrinx saved_errno = errno; 689216295Ssyrinx errno = 0; 690216295Ssyrinx 691216295Ssyrinx v = strtoul(val, &endptr, 10); 692216295Ssyrinx 693216295Ssyrinx if (errno != 0) { 694311595Sngie warn("Value %s not supported", val); 695216295Ssyrinx errno = saved_errno; 696216295Ssyrinx return (-1); 697216295Ssyrinx } 698216295Ssyrinx 699216295Ssyrinx value->v.uint32 = v; 700216295Ssyrinx errno = saved_errno; 701216295Ssyrinx 702216295Ssyrinx return (0); 703216295Ssyrinx} 704216295Ssyrinx 705216295Ssyrinxstatic int32_t 706216295Ssyrinxparse_ticks(struct snmp_value *value, char *val) 707216295Ssyrinx{ 708216295Ssyrinx if (parse_uint(value, val) < 0) 709216295Ssyrinx return (-1); 710216295Ssyrinx 711216295Ssyrinx value->syntax = SNMP_SYNTAX_TIMETICKS; 712216295Ssyrinx return (0); 713216295Ssyrinx} 714216295Ssyrinx 715216295Ssyrinxstatic int32_t 716216295Ssyrinxparse_gauge(struct snmp_value *value, char *val) 717216295Ssyrinx{ 718216295Ssyrinx if (parse_uint(value, val) < 0) 719216295Ssyrinx return (-1); 720216295Ssyrinx 721216295Ssyrinx value->syntax = SNMP_SYNTAX_GAUGE; 722216295Ssyrinx return (0); 723216295Ssyrinx} 724216295Ssyrinx 725216295Ssyrinxstatic int32_t 726216295Ssyrinxparse_counter(struct snmp_value *value, char *val) 727216295Ssyrinx{ 728216295Ssyrinx if (parse_uint(value, val) < 0) 729216295Ssyrinx return (-1); 730216295Ssyrinx 731216295Ssyrinx value->syntax = SNMP_SYNTAX_COUNTER; 732216295Ssyrinx return (0); 733216295Ssyrinx} 734216295Ssyrinx 735216295Ssyrinxstatic int32_t 736216295Ssyrinxparse_uint64(struct snmp_value *value, char *val) 737216295Ssyrinx{ 738216295Ssyrinx char *endptr; 739216295Ssyrinx int32_t saved_errno; 740216295Ssyrinx uint64_t v; 741216295Ssyrinx 742216295Ssyrinx saved_errno = errno; 743216295Ssyrinx errno = 0; 744216295Ssyrinx 745216295Ssyrinx v = strtoull(val, &endptr, 10); 746216295Ssyrinx 747216295Ssyrinx if (errno != 0) { 748311595Sngie warnx("Value %s not supported", val); 749216295Ssyrinx errno = saved_errno; 750216295Ssyrinx return (-1); 751216295Ssyrinx } 752216295Ssyrinx 753216295Ssyrinx value->syntax = SNMP_SYNTAX_COUNTER64; 754216295Ssyrinx value->v.counter64 = v; 755216295Ssyrinx errno = saved_errno; 756216295Ssyrinx 757216295Ssyrinx return (0); 758216295Ssyrinx} 759216295Ssyrinx 760216295Ssyrinxstatic int32_t 761216295Ssyrinxparse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val) 762216295Ssyrinx{ 763216295Ssyrinx switch (syntax) { 764216295Ssyrinx case SNMP_SYNTAX_INTEGER: 765216295Ssyrinx return (parse_int(value, val)); 766216295Ssyrinx case SNMP_SYNTAX_IPADDRESS: 767216295Ssyrinx return (parse_ip(value, val)); 768216295Ssyrinx case SNMP_SYNTAX_COUNTER: 769216295Ssyrinx return (parse_counter(value, val)); 770216295Ssyrinx case SNMP_SYNTAX_GAUGE: 771216295Ssyrinx return (parse_gauge(value, val)); 772216295Ssyrinx case SNMP_SYNTAX_TIMETICKS: 773216295Ssyrinx return (parse_ticks(value, val)); 774216295Ssyrinx case SNMP_SYNTAX_COUNTER64: 775216295Ssyrinx return (parse_uint64(value, val)); 776216295Ssyrinx case SNMP_SYNTAX_OCTETSTRING: 777216295Ssyrinx return (snmp_tc2oct(SNMP_STRING, value, val)); 778216295Ssyrinx case SNMP_SYNTAX_OID: 779216295Ssyrinx return (parse_oid_numeric(value, val)); 780216295Ssyrinx default: 781216295Ssyrinx /* NOTREACHED */ 782216295Ssyrinx break; 783216295Ssyrinx } 784216295Ssyrinx 785216295Ssyrinx return (-1); 786216295Ssyrinx} 787216295Ssyrinx 788216295Ssyrinx/* 789310903Sngie * Parse a command line argument of type OID=syntax:value and fill in whatever 790216295Ssyrinx * fields can be derived from the input into snmp_value structure. Reads numeric 791216295Ssyrinx * OIDs. 792216295Ssyrinx */ 793216295Ssyrinxstatic int32_t 794216295Ssyrinxparse_pair_numoid_val(char *str, struct snmp_value *snmp_val) 795216295Ssyrinx{ 796216295Ssyrinx int32_t cnt; 797216295Ssyrinx char *ptr; 798216295Ssyrinx enum snmp_syntax syntax; 799216295Ssyrinx char oid_str[ASN_OIDSTRLEN]; 800216295Ssyrinx 801216295Ssyrinx ptr = str; 802216295Ssyrinx for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++) 803216295Ssyrinx if (ptr[cnt] == '=') 804216295Ssyrinx break; 805216295Ssyrinx 806216295Ssyrinx if (cnt >= ASN_OIDSTRLEN) { 807216295Ssyrinx warnx("OID too long - %s", str); 808216295Ssyrinx return (-1); 809216295Ssyrinx } 810216295Ssyrinx strlcpy(oid_str, ptr, (size_t) (cnt + 1)); 811216295Ssyrinx 812216295Ssyrinx ptr = str + cnt + 1; 813216295Ssyrinx for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++) 814216295Ssyrinx if(ptr[cnt] == ':') 815216295Ssyrinx break; 816216295Ssyrinx 817216295Ssyrinx if (cnt >= MAX_CMD_SYNTAX_LEN) { 818216295Ssyrinx warnx("Unknown syntax in OID - %s", str); 819216295Ssyrinx return (-1); 820216295Ssyrinx } 821216295Ssyrinx 822216295Ssyrinx if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) { 823216295Ssyrinx warnx("Unknown syntax in OID - %s", ptr); 824216295Ssyrinx return (-1); 825216295Ssyrinx } 826216295Ssyrinx 827216295Ssyrinx ptr = ptr + cnt + 1; 828216295Ssyrinx for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++) 829216295Ssyrinx if (ptr[cnt] == '\0') 830216295Ssyrinx break; 831216295Ssyrinx 832216295Ssyrinx if (ptr[cnt] != '\0') { 833311595Sngie warnx("Value string too long - %s", ptr); 834216295Ssyrinx return (-1); 835216295Ssyrinx } 836216295Ssyrinx 837216295Ssyrinx /* 838216295Ssyrinx * Here try parsing the OIDs and syntaxes and then check values - have 839216295Ssyrinx * to know syntax to check value boundaries. 840216295Ssyrinx */ 841216295Ssyrinx if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) { 842311595Sngie warnx("Error parsing OID %s", oid_str); 843216295Ssyrinx return (-1); 844216295Ssyrinx } 845216295Ssyrinx 846216295Ssyrinx if (parse_syntax_val(snmp_val, syntax, ptr) < 0) 847216295Ssyrinx return (-1); 848216295Ssyrinx 849216295Ssyrinx return (1); 850216295Ssyrinx} 851216295Ssyrinx 852216295Ssyrinxstatic int32_t 853311466Sngieparse_syntax_strval(struct snmp_toolinfo *snmptoolctx, 854311466Sngie struct snmp_object *object, char *str) 855216295Ssyrinx{ 856216295Ssyrinx uint32_t len; 857216295Ssyrinx enum snmp_syntax syn; 858216295Ssyrinx 859216295Ssyrinx /* 860216295Ssyrinx * Syntax string here not required - still may be present. 861216295Ssyrinx */ 862216295Ssyrinx 863216295Ssyrinx if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) { 864216295Ssyrinx for (len = 0 ; *(str + len) != ':'; len++) { 865216295Ssyrinx if (*(str + len) == '\0') { 866216295Ssyrinx warnx("Syntax missing in value - %s", str); 867216295Ssyrinx return (-1); 868216295Ssyrinx } 869216295Ssyrinx } 870216295Ssyrinx if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) { 871216295Ssyrinx warnx("Unknown syntax in - %s", str); 872216295Ssyrinx return (-1); 873216295Ssyrinx } 874216295Ssyrinx if (syn != object->val.syntax) { 875216295Ssyrinx if (!ISSET_ERRIGNORE(snmptoolctx)) { 876216295Ssyrinx warnx("Bad syntax in - %s", str); 877216295Ssyrinx return (-1); 878216295Ssyrinx } else 879216295Ssyrinx object->val.syntax = syn; 880216295Ssyrinx } 881216295Ssyrinx len++; 882216295Ssyrinx } else 883216295Ssyrinx len = 0; 884216295Ssyrinx 885216295Ssyrinx switch (object->val.syntax) { 886216295Ssyrinx case SNMP_SYNTAX_INTEGER: 887216295Ssyrinx return (parse_int_string(object, str + len)); 888216295Ssyrinx case SNMP_SYNTAX_IPADDRESS: 889216295Ssyrinx return (parse_ip(&(object->val), str + len)); 890216295Ssyrinx case SNMP_SYNTAX_COUNTER: 891216295Ssyrinx return (parse_counter(&(object->val), str + len)); 892216295Ssyrinx case SNMP_SYNTAX_GAUGE: 893216295Ssyrinx return (parse_gauge(&(object->val), str + len)); 894216295Ssyrinx case SNMP_SYNTAX_TIMETICKS: 895216295Ssyrinx return (parse_ticks(&(object->val), str + len)); 896216295Ssyrinx case SNMP_SYNTAX_COUNTER64: 897216295Ssyrinx return (parse_uint64(&(object->val), str + len)); 898216295Ssyrinx case SNMP_SYNTAX_OCTETSTRING: 899216295Ssyrinx return (snmp_tc2oct(object->info->tc, &(object->val), 900216295Ssyrinx str + len)); 901216295Ssyrinx case SNMP_SYNTAX_OID: 902216295Ssyrinx return (parse_oid_string(snmptoolctx, &(object->val), 903216295Ssyrinx str + len)); 904216295Ssyrinx default: 905216295Ssyrinx /* NOTREACHED */ 906216295Ssyrinx break; 907216295Ssyrinx } 908216295Ssyrinx 909216295Ssyrinx return (-1); 910216295Ssyrinx} 911216295Ssyrinx 912216295Ssyrinxstatic int32_t 913216295Ssyrinxparse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx, 914216295Ssyrinx struct snmp_object *obj, char *argv) 915216295Ssyrinx{ 916216295Ssyrinx char *ptr; 917216295Ssyrinx 918216295Ssyrinx if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL) 919216295Ssyrinx return (-1); 920310903Sngie 921216295Ssyrinx if (*ptr != '=') { 922216295Ssyrinx warnx("Value to set expected after OID"); 923216295Ssyrinx return (-1); 924216295Ssyrinx } 925216295Ssyrinx 926311466Sngie if (parse_syntax_strval(snmptoolctx, obj, ptr + 1) < 0) 927216295Ssyrinx return (-1); 928216295Ssyrinx 929216295Ssyrinx return (1); 930216295Ssyrinx} 931216295Ssyrinx 932216295Ssyrinx 933216295Ssyrinxstatic int32_t 934216295Ssyrinxsnmpset_parse_oid(struct snmp_toolinfo *snmptoolctx, 935216295Ssyrinx struct snmp_object *obj, char *argv) 936216295Ssyrinx{ 937216295Ssyrinx if (argv == NULL) 938216295Ssyrinx return (-1); 939216295Ssyrinx 940216295Ssyrinx if (ISSET_NUMERIC(snmptoolctx)) { 941216295Ssyrinx if (parse_pair_numoid_val(argv, &(obj->val)) < 0) 942216295Ssyrinx return (-1); 943216295Ssyrinx } else { 944216295Ssyrinx if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0) 945216295Ssyrinx return (-1); 946216295Ssyrinx } 947216295Ssyrinx 948216295Ssyrinx return (1); 949216295Ssyrinx} 950216295Ssyrinx 951216295Ssyrinxstatic int32_t 952216295Ssyrinxadd_ip_syntax(struct snmp_value *dst, struct snmp_value *src) 953216295Ssyrinx{ 954216295Ssyrinx int8_t i; 955216295Ssyrinx 956216295Ssyrinx dst->syntax = SNMP_SYNTAX_IPADDRESS; 957216295Ssyrinx for (i = 0; i < 4; i++) 958216295Ssyrinx dst->v.ipaddress[i] = src->v.ipaddress[i]; 959216295Ssyrinx 960216295Ssyrinx return (1); 961216295Ssyrinx} 962216295Ssyrinx 963216295Ssyrinxstatic int32_t 964216295Ssyrinxadd_octstring_syntax(struct snmp_value *dst, struct snmp_value *src) 965216295Ssyrinx{ 966216295Ssyrinx if (src->v.octetstring.len > ASN_MAXOCTETSTRING) { 967311595Sngie warnx("OctetString len too big - %u", src->v.octetstring.len); 968216295Ssyrinx return (-1); 969216295Ssyrinx } 970216295Ssyrinx 971216295Ssyrinx if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) == 972216295Ssyrinx NULL) { 973216295Ssyrinx syslog(LOG_ERR, "malloc() failed - %s", strerror(errno)); 974216295Ssyrinx return (-1); 975216295Ssyrinx } 976216295Ssyrinx 977216295Ssyrinx memcpy(dst->v.octetstring.octets, src->v.octetstring.octets, 978216295Ssyrinx src->v.octetstring.len); 979216295Ssyrinx dst->syntax = SNMP_SYNTAX_OCTETSTRING; 980216295Ssyrinx dst->v.octetstring.len = src->v.octetstring.len; 981216295Ssyrinx 982216295Ssyrinx return(0); 983216295Ssyrinx} 984216295Ssyrinx 985216295Ssyrinxstatic int32_t 986216295Ssyrinxadd_oid_syntax(struct snmp_value *dst, struct snmp_value *src) 987216295Ssyrinx{ 988216295Ssyrinx asn_append_oid(&(dst->v.oid), &(src->v.oid)); 989216295Ssyrinx dst->syntax = SNMP_SYNTAX_OID; 990216295Ssyrinx return (0); 991216295Ssyrinx} 992216295Ssyrinx 993216295Ssyrinx/* 994216295Ssyrinx * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT, 995216295Ssyrinx * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known - 996216295Ssyrinx * return error. 997216295Ssyrinx */ 998216295Ssyrinxstatic int32_t 999216295Ssyrinxsnmpset_add_value(struct snmp_value *dst, struct snmp_value *src) 1000216295Ssyrinx{ 1001216295Ssyrinx if (dst == NULL || src == NULL) 1002216295Ssyrinx return (-1); 1003216295Ssyrinx 1004216295Ssyrinx switch (src->syntax) { 1005216295Ssyrinx case SNMP_SYNTAX_INTEGER: 1006216295Ssyrinx dst->v.integer = src->v.integer; 1007216295Ssyrinx dst->syntax = SNMP_SYNTAX_INTEGER; 1008216295Ssyrinx break; 1009216295Ssyrinx case SNMP_SYNTAX_TIMETICKS: 1010216295Ssyrinx dst->v.uint32 = src->v.uint32; 1011216295Ssyrinx dst->syntax = SNMP_SYNTAX_TIMETICKS; 1012216295Ssyrinx break; 1013216295Ssyrinx case SNMP_SYNTAX_GAUGE: 1014216295Ssyrinx dst->v.uint32 = src->v.uint32; 1015216295Ssyrinx dst->syntax = SNMP_SYNTAX_GAUGE; 1016216295Ssyrinx break; 1017216295Ssyrinx case SNMP_SYNTAX_COUNTER: 1018216295Ssyrinx dst->v.uint32 = src->v.uint32; 1019216295Ssyrinx dst->syntax = SNMP_SYNTAX_COUNTER; 1020216295Ssyrinx break; 1021216295Ssyrinx case SNMP_SYNTAX_COUNTER64: 1022216295Ssyrinx dst->v.counter64 = src->v.counter64; 1023216295Ssyrinx dst->syntax = SNMP_SYNTAX_COUNTER64; 1024216295Ssyrinx break; 1025216295Ssyrinx case SNMP_SYNTAX_IPADDRESS: 1026216295Ssyrinx add_ip_syntax(dst, src); 1027216295Ssyrinx break; 1028216295Ssyrinx case SNMP_SYNTAX_OCTETSTRING: 1029216295Ssyrinx add_octstring_syntax(dst, src); 1030216295Ssyrinx break; 1031216295Ssyrinx case SNMP_SYNTAX_OID: 1032216295Ssyrinx add_oid_syntax(dst, src); 1033216295Ssyrinx break; 1034216295Ssyrinx default: 1035216295Ssyrinx warnx("Unknown syntax %d", src->syntax); 1036216295Ssyrinx return (-1); 1037216295Ssyrinx } 1038216295Ssyrinx 1039216295Ssyrinx return (0); 1040216295Ssyrinx} 1041216295Ssyrinx 1042216295Ssyrinxstatic int32_t 1043216295Ssyrinxsnmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, 1044216295Ssyrinx struct snmp_object *obj) 1045216295Ssyrinx{ 1046216295Ssyrinx if (pdu->version == SNMP_V1 && obj->val.syntax == 1047216295Ssyrinx SNMP_SYNTAX_COUNTER64) { 1048216295Ssyrinx warnx("64-bit counters are not supported in SNMPv1 PDU"); 1049216295Ssyrinx return (-1); 1050216295Ssyrinx } 1051216295Ssyrinx 1052216295Ssyrinx if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx)) 1053216295Ssyrinx return (1); 1054216295Ssyrinx 1055216295Ssyrinx if (obj->info->access < SNMP_ACCESS_SET) { 1056216295Ssyrinx warnx("Object %s not accessible for set - try 'bsnmpset -a'", 1057216295Ssyrinx obj->info->string); 1058216295Ssyrinx return (-1); 1059216295Ssyrinx } 1060216295Ssyrinx 1061216295Ssyrinx return (1); 1062216295Ssyrinx} 1063216295Ssyrinx 1064216295Ssyrinxstatic int32_t 1065216295Ssyrinxsnmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj) 1066216295Ssyrinx{ 1067216295Ssyrinx if (pdu->nbindings > SNMP_MAX_BINDINGS) { 1068216295Ssyrinx warnx("Too many OIDs for one PDU"); 1069216295Ssyrinx return (-1); 1070216295Ssyrinx } 1071216295Ssyrinx 1072216295Ssyrinx if (obj->error > 0) 1073216295Ssyrinx return (0); 1074216295Ssyrinx 1075216295Ssyrinx if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val)) 1076216295Ssyrinx < 0) 1077216295Ssyrinx return (-1); 1078216295Ssyrinx 1079216295Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var)); 1080216295Ssyrinx pdu->nbindings++; 1081216295Ssyrinx 1082216295Ssyrinx return (pdu->nbindings); 1083216295Ssyrinx} 1084216295Ssyrinx 1085216295Ssyrinxstatic int 1086216295Ssyrinxsnmptool_set(struct snmp_toolinfo *snmptoolctx) 1087216295Ssyrinx{ 1088216295Ssyrinx struct snmp_pdu req, resp; 1089216295Ssyrinx 1090216295Ssyrinx snmp_pdu_create(&req, SNMP_PDU_SET); 1091216295Ssyrinx 1092216295Ssyrinx while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind, 1093216295Ssyrinx snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) { 1094216295Ssyrinx if (snmp_dialog(&req, &resp)) { 1095311595Sngie warn("Snmp dialog"); 1096216295Ssyrinx break; 1097216295Ssyrinx } 1098216295Ssyrinx 1099216295Ssyrinx if (snmp_pdu_check(&req, &resp) > 0) { 1100216295Ssyrinx if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) 1101229933Ssyrinx snmp_output_resp(snmptoolctx, &resp, NULL); 1102312050Sngie snmp_pdu_free(&resp); 1103216295Ssyrinx break; 1104216295Ssyrinx } 1105216295Ssyrinx 1106216295Ssyrinx snmp_output_err_resp(snmptoolctx, &resp); 1107312050Sngie if (!ISSET_RETRY(snmptoolctx)) { 1108312050Sngie snmp_pdu_free(&resp); 1109216295Ssyrinx break; 1110312050Sngie } 1111216295Ssyrinx 1112216295Ssyrinx if (snmp_object_seterror(snmptoolctx, 1113216295Ssyrinx &(resp.bindings[resp.error_index - 1]), 1114312050Sngie resp.error_status) <= 0) { 1115312050Sngie snmp_pdu_free(&resp); 1116216295Ssyrinx break; 1117312050Sngie } 1118216295Ssyrinx 1119216295Ssyrinx fprintf(stderr, "Retrying...\n"); 1120216295Ssyrinx snmp_pdu_free(&req); 1121216295Ssyrinx snmp_pdu_create(&req, SNMP_PDU_SET); 1122216295Ssyrinx } 1123216295Ssyrinx 1124312050Sngie snmp_pdu_free(&req); 1125216295Ssyrinx 1126216295Ssyrinx return (0); 1127216295Ssyrinx} 1128216295Ssyrinx 1129216295Ssyrinx/* ***************************************************************************** 1130216295Ssyrinx * main 1131216295Ssyrinx */ 1132216295Ssyrinx/* 1133216295Ssyrinx * According to command line options prepare SNMP Get | GetNext | GetBulk PDU. 1134228990Suqs * Wait for a response and print it. 1135216295Ssyrinx */ 1136216295Ssyrinx/* 1137216295Ssyrinx * Do a 'snmp walk' - according to command line options request for values 1138216295Ssyrinx * lexicographically subsequent and subrooted at a common node. Send a GetNext 1139228990Suqs * PDU requesting the value for each next variable and print the response. Stop 1140228990Suqs * when a Response PDU is received that contains the value of a variable not 1141216295Ssyrinx * subrooted at the variable the walk started. 1142216295Ssyrinx */ 1143216295Ssyrinxint 1144216295Ssyrinxmain(int argc, char ** argv) 1145216295Ssyrinx{ 1146216295Ssyrinx struct snmp_toolinfo snmptoolctx; 1147216295Ssyrinx int32_t oid_cnt, last_oid, opt_num; 1148216295Ssyrinx int rc = 0; 1149216295Ssyrinx 1150216295Ssyrinx /* Make sure program_name is set and valid. */ 1151216295Ssyrinx if (*argv == NULL) 1152216295Ssyrinx program_name = "snmptool"; 1153216295Ssyrinx else { 1154216295Ssyrinx program_name = strrchr(*argv, '/'); 1155216295Ssyrinx if (program_name != NULL) 1156216295Ssyrinx program_name++; 1157216295Ssyrinx else 1158216295Ssyrinx program_name = *argv; 1159216295Ssyrinx } 1160216295Ssyrinx 1161216295Ssyrinx if (program_name == NULL) { 1162216295Ssyrinx fprintf(stderr, "Error: No program name?\n"); 1163216295Ssyrinx exit (1); 1164216295Ssyrinx } else if (strcmp(program_name, "bsnmpget") == 0) 1165216295Ssyrinx program = BSNMPGET; 1166216295Ssyrinx else if (strcmp(program_name, "bsnmpwalk") == 0) 1167216295Ssyrinx program = BSNMPWALK; 1168216295Ssyrinx else if (strcmp(program_name, "bsnmpset") == 0) 1169216295Ssyrinx program = BSNMPSET; 1170216295Ssyrinx else { 1171216295Ssyrinx fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name); 1172216295Ssyrinx exit (1); 1173216295Ssyrinx } 1174216295Ssyrinx 1175216295Ssyrinx /* Initialize. */ 1176216295Ssyrinx if (snmptool_init(&snmptoolctx) < 0) 1177216295Ssyrinx exit (1); 1178216295Ssyrinx 1179216295Ssyrinx if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) { 1180216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1181216295Ssyrinx /* On -h (help) exit without error. */ 1182216295Ssyrinx if (opt_num == -2) 1183216295Ssyrinx exit(0); 1184216295Ssyrinx else 1185216295Ssyrinx exit(1); 1186216295Ssyrinx } 1187216295Ssyrinx 1188216295Ssyrinx oid_cnt = argc - opt_num - 1; 1189216295Ssyrinx if (oid_cnt == 0) { 1190216295Ssyrinx switch (program) { 1191216295Ssyrinx case BSNMPGET: 1192216295Ssyrinx if (!ISSET_EDISCOVER(&snmptoolctx) && 1193216295Ssyrinx !ISSET_LOCALKEY(&snmptoolctx)) { 1194216295Ssyrinx fprintf(stderr, "No OID given.\n"); 1195216295Ssyrinx usage(); 1196216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1197216295Ssyrinx exit(1); 1198216295Ssyrinx } 1199216295Ssyrinx break; 1200216295Ssyrinx 1201216295Ssyrinx case BSNMPWALK: 1202216295Ssyrinx if (snmp_object_add(&snmptoolctx, snmpwalk_add_default, 1203216295Ssyrinx NULL) < 0) { 1204216295Ssyrinx fprintf(stderr, 1205216295Ssyrinx "Error setting default subtree.\n"); 1206216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1207216295Ssyrinx exit(1); 1208216295Ssyrinx } 1209216295Ssyrinx break; 1210216295Ssyrinx 1211216295Ssyrinx case BSNMPSET: 1212216295Ssyrinx fprintf(stderr, "No OID given.\n"); 1213216295Ssyrinx usage(); 1214216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1215216295Ssyrinx exit(1); 1216216295Ssyrinx } 1217216295Ssyrinx } 1218216295Ssyrinx 1219216295Ssyrinx if (snmp_import_all(&snmptoolctx) < 0) { 1220216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1221216295Ssyrinx exit(1); 1222216295Ssyrinx } 1223216295Ssyrinx 1224216295Ssyrinx /* A simple sanity check - can not send GETBULK when using SNMPv1. */ 1225216295Ssyrinx if (program == BSNMPGET && snmp_client.version == SNMP_V1 && 1226216295Ssyrinx GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) { 1227216295Ssyrinx fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n"); 1228216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1229216295Ssyrinx exit(1); 1230216295Ssyrinx } 1231216295Ssyrinx 1232216295Ssyrinx for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) { 1233216295Ssyrinx if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ? 1234216295Ssyrinx snmpset_parse_oid : snmptools_parse_oid, 1235216295Ssyrinx argv[last_oid])) < 0) { 1236216295Ssyrinx fprintf(stderr, "Error parsing OID string '%s'.\n", 1237216295Ssyrinx argv[last_oid]); 1238216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1239216295Ssyrinx exit(1); 1240216295Ssyrinx } 1241216295Ssyrinx } 1242216295Ssyrinx 1243216295Ssyrinx if (snmp_open(NULL, NULL, NULL, NULL)) { 1244311595Sngie warn("Failed to open snmp session"); 1245216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1246216295Ssyrinx exit(1); 1247216295Ssyrinx } 1248216295Ssyrinx 1249216295Ssyrinx if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0) 1250216295Ssyrinx SET_EDISCOVER(&snmptoolctx); 1251216295Ssyrinx 1252216295Ssyrinx if (ISSET_EDISCOVER(&snmptoolctx) && 1253216295Ssyrinx snmp_discover_engine(snmptoolctx.passwd) < 0) { 1254311595Sngie warn("Unknown SNMP Engine ID"); 1255216295Ssyrinx rc = 1; 1256216295Ssyrinx goto cleanup; 1257216295Ssyrinx } 1258216295Ssyrinx 1259216295Ssyrinx if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE || 1260216295Ssyrinx ISSET_EDISCOVER(&snmptoolctx)) 1261216295Ssyrinx snmp_output_engine(); 1262216295Ssyrinx 1263216295Ssyrinx if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) && 1264216295Ssyrinx !ISSET_EDISCOVER(&snmptoolctx)) { 1265216295Ssyrinx if (snmp_passwd_to_keys(&snmp_client.user, 1266216295Ssyrinx snmptoolctx.passwd) != SNMP_CODE_OK || 1267216295Ssyrinx snmp_get_local_keys(&snmp_client.user, 1268216295Ssyrinx snmp_client.engine.engine_id, 1269216295Ssyrinx snmp_client.engine.engine_len) != SNMP_CODE_OK) { 1270311595Sngie warn("Failed to get keys"); 1271216295Ssyrinx rc = 1; 1272216295Ssyrinx goto cleanup; 1273216295Ssyrinx } 1274216295Ssyrinx } 1275216295Ssyrinx 1276216295Ssyrinx if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE || 1277216295Ssyrinx ISSET_EDISCOVER(&snmptoolctx)) 1278216295Ssyrinx snmp_output_keys(); 1279216295Ssyrinx 1280216295Ssyrinx if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0) 1281216295Ssyrinx goto cleanup; 1282216295Ssyrinx 1283216295Ssyrinx switch (program) { 1284216295Ssyrinx case BSNMPGET: 1285216295Ssyrinx rc = snmptool_get(&snmptoolctx); 1286216295Ssyrinx break; 1287216295Ssyrinx case BSNMPWALK: 1288216295Ssyrinx rc = snmptool_walk(&snmptoolctx); 1289216295Ssyrinx break; 1290216295Ssyrinx case BSNMPSET: 1291216295Ssyrinx rc = snmptool_set(&snmptoolctx); 1292216295Ssyrinx break; 1293216295Ssyrinx } 1294216295Ssyrinx 1295216295Ssyrinx 1296216295Ssyrinxcleanup: 1297216295Ssyrinx snmp_tool_freeall(&snmptoolctx); 1298216295Ssyrinx snmp_close(); 1299216295Ssyrinx 1300216295Ssyrinx exit(rc); 1301216295Ssyrinx} 1302