bsnmpget.c revision 310903
1115013Smarcel/*- 2160157Smarcel * Copyright (c) 2005-2006 The FreeBSD Project 3121642Smarcel * All rights reserved. 4121642Smarcel * 5121642Smarcel * Author: Shteryana Shopova <syrinx@FreeBSD.org> 6121642Smarcel * 7121642Smarcel * Redistribution of this software and documentation and use in source and 8121642Smarcel * binary forms, with or without modification, are permitted provided that 9121642Smarcel * the following conditions are met: 10121642Smarcel * 11115013Smarcel * 1. Redistributions of source code or documentation must retain the above 12121642Smarcel * copyright notice, this list of conditions and the following disclaimer. 13121642Smarcel * 2. Redistributions in binary form must reproduce the above copyright 14121642Smarcel * notice, this list of conditions and the following disclaimer in the 15121642Smarcel * documentation and/or other materials provided with the distribution. 16121642Smarcel * 17121642Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18121642Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19121642Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20121642Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21121642Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22121642Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23121642Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24121642Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25160163Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26115013Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27160163Smarcel * SUCH DAMAGE. 28115013Smarcel * 29115013Smarcel * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents, 30115013Smarcel * bsnmpset can be used to set MIB objects in an agent. 31115013Smarcel * 32115013Smarcel * $FreeBSD: stable/10/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c 310903 2016-12-31 10:34:09Z ngie $ 33160163Smarcel */ 34160163Smarcel 35160163Smarcel#include <sys/queue.h> 36115013Smarcel#include <sys/types.h> 37160163Smarcel 38160163Smarcel#include <assert.h> 39160163Smarcel#include <ctype.h> 40160163Smarcel#include <err.h> 41160163Smarcel#include <errno.h> 42160163Smarcel#include <stdarg.h> 43160163Smarcel#include <stdio.h> 44160163Smarcel#include <stdlib.h> 45160163Smarcel#include <string.h> 46160163Smarcel#include <syslog.h> 47160163Smarcel#include <unistd.h> 48160163Smarcel 49160163Smarcel#include <bsnmp/asn1.h> 50160163Smarcel#include <bsnmp/snmp.h> 51160163Smarcel#include <bsnmp/snmpclient.h> 52160163Smarcel#include "bsnmptc.h" 53160163Smarcel#include "bsnmptools.h" 54160163Smarcel 55160163Smarcelstatic const char *program_name = NULL; 56160163Smarcelstatic enum program_e { 57160163Smarcel BSNMPGET, 58160163Smarcel BSNMPWALK, 59160163Smarcel BSNMPSET 60160163Smarcel} program; 61160157Smarcel 62129059Smarcel/* ***************************************************************************** 63160157Smarcel * Common bsnmptools functions. 64160157Smarcel */ 65160157Smarcelstatic void 66160157Smarcelusage(void) 67160157Smarcel{ 68129059Smarcel fprintf(stderr, 69129059Smarcel"Usage:\n" 70115013Smarcel"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n" 71115013Smarcel"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n" 72115013Smarcel"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n" 73115013Smarcel"\t[-t timeout] [-U options] [-v version]%s\n", 74115013Smarcel program_name, 75115013Smarcel (program == BSNMPGET) ? "[-aDdehnK]" : 76115013Smarcel (program == BSNMPWALK) ? "[-dhnK]" : 77115013Smarcel (program == BSNMPSET) ? "[-adehnK]" : 78115013Smarcel "", 79115013Smarcel (program == BSNMPGET || program == BSNMPWALK) ? 80115013Smarcel " [-M max-repetitions] [-N non-repeaters]" : "", 81115013Smarcel (program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "", 82115013Smarcel (program == BSNMPGET) ? " OID [OID ...]" : 83115013Smarcel (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" : 84115013Smarcel "" 85115013Smarcel ); 86115013Smarcel} 87115013Smarcel 88115013Smarcelstatic int32_t 89115013Smarcelparse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 90115013Smarcel{ 91160157Smarcel uint32_t v; 92115013Smarcel 93115013Smarcel assert(opt_arg != NULL); 94115013Smarcel 95115013Smarcel v = strtoul(opt_arg, (void *) NULL, 10); 96115013Smarcel 97115013Smarcel if (v > SNMP_MAX_BINDINGS) { 98115013Smarcel warnx("Max repetitions value greater than %d maximum allowed.", 99115013Smarcel SNMP_MAX_BINDINGS); 100115013Smarcel return (-1); 101115013Smarcel } 102120925Smarcel 103120925Smarcel SET_MAXREP(snmptoolctx, v); 104115013Smarcel return (2); 105115013Smarcel} 106115013Smarcel 107115013Smarcelstatic int32_t 108160163Smarcelparse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 109115013Smarcel{ 110115013Smarcel uint32_t v; 111115013Smarcel 112115013Smarcel assert(opt_arg != NULL); 113115013Smarcel 114115013Smarcel v = strtoul(opt_arg, (void *) NULL, 10); 115115013Smarcel 116115013Smarcel if (v > SNMP_MAX_BINDINGS) { 117115013Smarcel warnx("Non repeaters value greater than %d maximum allowed.", 118115013Smarcel SNMP_MAX_BINDINGS); 119115013Smarcel return (-1); 120115013Smarcel } 121115013Smarcel 122115013Smarcel SET_NONREP(snmptoolctx, v); 123115013Smarcel return (2); 124115013Smarcel} 125115013Smarcel 126115013Smarcelstatic int32_t 127115013Smarcelparse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 128115013Smarcel{ 129115013Smarcel assert(opt_arg != NULL); 130115013Smarcel 131115013Smarcel if (strcasecmp(opt_arg, "getbulk") == 0) 132115013Smarcel SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK); 133115013Smarcel else if (strcasecmp(opt_arg, "getnext") == 0) 134115013Smarcel SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT); 135115013Smarcel else if (strcasecmp(opt_arg, "get") == 0) 136115013Smarcel SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET); 137115013Smarcel else { 138115013Smarcel warnx("PDU type '%s' not supported.", opt_arg); 139115013Smarcel return (-1); 140115013Smarcel } 141115013Smarcel 142115013Smarcel return (2); 143115013Smarcel} 144115013Smarcel 145115013Smarcelstatic int32_t 146115013Smarcelsnmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv) 147115013Smarcel{ 148115013Smarcel int32_t count, optnum = 0; 149115013Smarcel int ch; 150115013Smarcel const char *opts; 151115013Smarcel 152115013Smarcel switch (program) { 153115013Smarcel case BSNMPWALK: 154115013Smarcel opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; 155115013Smarcel break; 156115013Smarcel case BSNMPGET: 157115013Smarcel opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:"; 158115013Smarcel break; 159115013Smarcel case BSNMPSET: 160115013Smarcel opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:"; 161115013Smarcel break; 162115013Smarcel default: 163115013Smarcel return (-1); 164115013Smarcel } 165115013Smarcel 166115013Smarcel while ((ch = getopt(argc, argv, opts)) != EOF) { 167115013Smarcel switch (ch) { 168115013Smarcel case 'A': 169115013Smarcel count = parse_authentication(snmptoolctx, optarg); 170115013Smarcel break; 171115013Smarcel case 'a': 172115013Smarcel count = parse_skip_access(snmptoolctx); 173115013Smarcel break; 174115013Smarcel case 'b': 175115013Smarcel count = parse_buflen(optarg); 176115013Smarcel break; 177115013Smarcel case 'D': 178115013Smarcel count = parse_discovery(snmptoolctx); 179115013Smarcel break; 180115013Smarcel case 'd': 181115013Smarcel count = parse_debug(); 182115013Smarcel break; 183160163Smarcel case 'e': 184115013Smarcel count = parse_errors(snmptoolctx); 185115013Smarcel break; 186115013Smarcel case 'h': 187115013Smarcel usage(); 188115013Smarcel return (-2); 189115013Smarcel case 'C': 190115013Smarcel count = parse_context(snmptoolctx, optarg); 191115013Smarcel break; 192115013Smarcel case 'I': 193115013Smarcel count = parse_include(snmptoolctx, optarg); 194115013Smarcel break; 195115013Smarcel case 'i': 196115013Smarcel count = parse_file(snmptoolctx, optarg); 197115013Smarcel break; 198115013Smarcel case 'K': 199115013Smarcel count = parse_local_key(snmptoolctx); 200115013Smarcel break; 201115013Smarcel case 'l': 202115013Smarcel count = parse_local_path(optarg); 203115013Smarcel break; 204115013Smarcel case 'M': 205115013Smarcel count = parse_max_repetitions(snmptoolctx, optarg); 206115013Smarcel break; 207115013Smarcel case 'N': 208115013Smarcel count = parse_non_repeaters(snmptoolctx, optarg); 209115013Smarcel break; 210115013Smarcel case 'n': 211115013Smarcel count = parse_num_oids(snmptoolctx); 212115013Smarcel break; 213115013Smarcel case 'o': 214115013Smarcel count = parse_output(snmptoolctx, optarg); 215115013Smarcel break; 216115013Smarcel case 'P': 217115013Smarcel count = parse_privacy(snmptoolctx, optarg); 218115013Smarcel break; 219115013Smarcel case 'p': 220115013Smarcel count = parse_pdu_type(snmptoolctx, optarg); 221115013Smarcel break; 222115013Smarcel case 'r': 223115013Smarcel count = parse_retry(optarg); 224115013Smarcel break; 225115013Smarcel case 's': 226115013Smarcel count = parse_server(optarg); 227115013Smarcel break; 228115013Smarcel case 't': 229115013Smarcel count = parse_timeout(optarg); 230115013Smarcel break; 231115013Smarcel case 'U': 232115013Smarcel count = parse_user_security(snmptoolctx, optarg); 233115013Smarcel break; 234115013Smarcel case 'v': 235115013Smarcel count = parse_version(optarg); 236115013Smarcel break; 237115013Smarcel case '?': 238115013Smarcel default: 239115013Smarcel usage(); 240115013Smarcel return (-1); 241115013Smarcel } 242115013Smarcel if (count < 0) 243115013Smarcel return (-1); 244115013Smarcel optnum += count; 245115013Smarcel } 246115013Smarcel 247115013Smarcel return (optnum); 248115013Smarcel} 249115013Smarcel 250115013Smarcel/* 251115013Smarcel * Read user input OID - one of following formats: 252115013Smarcel * 1) 1.2.1.1.2.1.0 - that is if option numeric was given; 253115013Smarcel * 2) string - in such case append .0 to the asn_oid subs; 254115013Smarcel * 3) string.1 - no additional processing required in such case. 255115013Smarcel */ 256115013Smarcelstatic char * 257115013Smarcelsnmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx, 258115013Smarcel struct snmp_object *obj, char *argv) 259115013Smarcel{ 260115013Smarcel char string[MAXSTR], *str; 261115013Smarcel int32_t i = 0; 262115013Smarcel struct asn_oid in_oid; 263115013Smarcel 264115013Smarcel str = argv; 265115013Smarcel 266115013Smarcel if (*str == '.') 267160163Smarcel str++; 268115013Smarcel 269115013Smarcel while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) { 270115013Smarcel str++; 271115013Smarcel i++; 272115013Smarcel } 273115013Smarcel 274115013Smarcel if (i <= 0 || i >= MAXSTR) 275115013Smarcel return (NULL); 276115013Smarcel 277115013Smarcel memset(&in_oid, 0, sizeof(struct asn_oid)); 278115013Smarcel if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) { 279115013Smarcel warnx("Invalid OID - %s", argv); 280115013Smarcel return (NULL); 281115013Smarcel } 282115013Smarcel 283115013Smarcel strlcpy(string, argv, i + 1); 284115013Smarcel if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) { 285115013Smarcel warnx("No entry for %s in mapping lists", string); 286115013Smarcel return (NULL); 287115013Smarcel } 288115013Smarcel 289115013Smarcel /* If OID given on command line append it. */ 290115013Smarcel if (in_oid.len > 0) 291115013Smarcel asn_append_oid(&(obj->val.var), &in_oid); 292115013Smarcel else if (*str == '[') { 293115013Smarcel if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL) 294115013Smarcel return (NULL); 295115013Smarcel } else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) == 296115013Smarcel SNMP_PDU_GET) { 297115013Smarcel if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0) 298115013Smarcel return (NULL); 299115013Smarcel } 300115013Smarcel 301115013Smarcel return (str); 302115013Smarcel} 303115013Smarcel 304160157Smarcelstatic int32_t 305160157Smarcelsnmptools_parse_oid(struct snmp_toolinfo *snmptoolctx, 306160157Smarcel struct snmp_object *obj, char *argv) 307160157Smarcel{ 308160157Smarcel if (argv == NULL) 309160157Smarcel return (-1); 310115013Smarcel 311115013Smarcel if (ISSET_NUMERIC(snmptoolctx)) { 312115013Smarcel if (snmp_parse_numoid(argv, &(obj->val.var)) < 0) 313115013Smarcel return (-1); 314115013Smarcel } else { 315115013Smarcel if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL && 316 snmp_parse_numoid(argv, &(obj->val.var)) < 0) 317 return (-1); 318 } 319 320 return (1); 321} 322 323static int32_t 324snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj) 325{ 326 if (obj->error > 0) 327 return (0); 328 329 asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var)); 330 pdu->nbindings++; 331 332 return (pdu->nbindings); 333} 334 335/* ***************************************************************************** 336 * bsnmpget private functions. 337 */ 338static int32_t 339snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, 340 struct snmp_object *obj) 341{ 342 if (pdu->version == SNMP_V1 && obj->val.syntax == 343 SNMP_SYNTAX_COUNTER64) { 344 warnx("64-bit counters are not supported in SNMPv1 PDU"); 345 return (-1); 346 } 347 348 if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT || 349 pdu->type == SNMP_PDU_GETBULK) 350 return (1); 351 352 if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) { 353 warnx("Only leaf object values can be added to GET PDU"); 354 return (-1); 355 } 356 357 return (1); 358} 359 360/* 361 * In case of a getbulk PDU, the error_status and error_index fields are used by 362 * libbsnmp to hold the values of the non-repeaters and max-repetitions fields 363 * that are present only in the getbulk - so before sending the PDU make sure 364 * these have correct values as well. 365 */ 366static void 367snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep) 368{ 369 assert(pdu != NULL); 370 371 if (pdu->nbindings < non_rep) 372 pdu->error_status = pdu->nbindings; 373 else 374 pdu->error_status = non_rep; 375 376 if (max_rep > 0) 377 pdu->error_index = max_rep; 378 else 379 pdu->error_index = 1; 380} 381 382static int 383snmptool_get(struct snmp_toolinfo *snmptoolctx) 384{ 385 struct snmp_pdu req, resp; 386 387 snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx)); 388 389 while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind, 390 snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) { 391 392 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK) 393 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 394 GET_NONREP(snmptoolctx)); 395 396 if (snmp_dialog(&req, &resp) == -1) { 397 warnx("Snmp dialog - %s", strerror(errno)); 398 break; 399 } 400 401 if (snmp_parse_resp(&resp, &req) >= 0) { 402 snmp_output_resp(snmptoolctx, &resp, NULL); 403 break; 404 } 405 406 snmp_output_err_resp(snmptoolctx, &resp); 407 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK || 408 !ISSET_RETRY(snmptoolctx)) 409 break; 410 411 /* 412 * Loop through the object list and set object->error to the 413 * varbinding that caused the error. 414 */ 415 if (snmp_object_seterror(snmptoolctx, 416 &(resp.bindings[resp.error_index - 1]), 417 resp.error_status) <= 0) 418 break; 419 420 fprintf(stderr, "Retrying...\n"); 421 snmp_pdu_free(&resp); 422 snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx)); 423 } 424 425 snmp_pdu_free(&resp); 426 427 return (0); 428} 429 430 431/* ***************************************************************************** 432 * bsnmpwalk private functions. 433 */ 434/* The default tree to walk. */ 435static const struct asn_oid snmp_mibII_OID = { 436 6 , { 1, 3, 6, 1, 2, 1 } 437}; 438 439static int32_t 440snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused, 441 struct snmp_object *obj, char *string __unused) 442{ 443 asn_append_oid(&(obj->val.var), &snmp_mibII_OID); 444 return (1); 445} 446 447/* 448 * Prepare the next GetNext/Get PDU to send. 449 */ 450static void 451snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu) 452{ 453 snmp_pdu_create(pdu, op); 454 asn_append_oid(&(pdu->bindings[0].var), var); 455 pdu->nbindings = 1; 456} 457 458static int 459snmptool_walk(struct snmp_toolinfo *snmptoolctx) 460{ 461 struct snmp_pdu req, resp; 462 struct asn_oid root; /* Keep the initial oid. */ 463 int32_t outputs, rc; 464 uint32_t op; 465 466 if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK) 467 op = SNMP_PDU_GETBULK; 468 else 469 op = SNMP_PDU_GETNEXT; 470 471 snmp_pdu_create(&req, op); 472 473 while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL, 474 snmptool_add_vbind, &req, 1)) > 0) { 475 476 /* Remember the root where the walk started from. */ 477 memset(&root, 0, sizeof(struct asn_oid)); 478 asn_append_oid(&root, &(req.bindings[0].var)); 479 480 if (op == SNMP_PDU_GETBULK) 481 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 482 GET_NONREP(snmptoolctx)); 483 484 outputs = 0; 485 while (snmp_dialog(&req, &resp) >= 0) { 486 if ((snmp_parse_resp(&resp, &req)) < 0) { 487 snmp_output_err_resp(snmptoolctx, &resp); 488 snmp_pdu_free(&resp); 489 outputs = -1; 490 break; 491 } 492 493 rc = snmp_output_resp(snmptoolctx, &resp, &root); 494 if (rc < 0) { 495 snmp_pdu_free(&resp); 496 outputs = -1; 497 break; 498 } 499 500 outputs += rc; 501 snmp_pdu_free(&resp); 502 503 if ((u_int)rc < resp.nbindings) 504 break; 505 506 snmpwalk_nextpdu_create(op, 507 &(resp.bindings[resp.nbindings - 1].var), &req); 508 if (op == SNMP_PDU_GETBULK) 509 snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx), 510 GET_NONREP(snmptoolctx)); 511 } 512 513 /* Just in case our root was a leaf. */ 514 if (outputs == 0) { 515 snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req); 516 if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) { 517 if (snmp_parse_resp(&resp,&req) < 0) 518 snmp_output_err_resp(snmptoolctx, &resp); 519 else 520 snmp_output_resp(snmptoolctx, &(resp), NULL); 521 522 snmp_pdu_free(&resp); 523 } else 524 warnx("Snmp dialog - %s", strerror(errno)); 525 } 526 527 if (snmp_object_remove(snmptoolctx, &root) < 0) { 528 warnx("snmp_object_remove"); 529 break; 530 } 531 532 snmp_pdu_create(&req, op); 533 } 534 535 if (rc == 0) 536 return (0); 537 else 538 return (1); 539} 540 541/* ***************************************************************************** 542 * bsnmpset private functions. 543 */ 544 545static int32_t 546parse_oid_numeric(struct snmp_value *value, char *val) 547{ 548 char *endptr; 549 int32_t saved_errno; 550 asn_subid_t suboid; 551 552 do { 553 saved_errno = errno; 554 errno = 0; 555 suboid = strtoul(val, &endptr, 10); 556 if (errno != 0) { 557 warnx("Value %s not supported - %s", val, 558 strerror(errno)); 559 errno = saved_errno; 560 return (-1); 561 } 562 errno = saved_errno; 563 if ((asn_subid_t) suboid > ASN_MAXID) { 564 warnx("Suboid %u > ASN_MAXID", suboid); 565 return (-1); 566 } 567 if (snmp_suboid_append(&(value->v.oid), suboid) < 0) 568 return (-1); 569 val = endptr + 1; 570 } while (*endptr == '.'); 571 572 if (*endptr != '\0') 573 warnx("OID value %s not supported", val); 574 575 value->syntax = SNMP_SYNTAX_OID; 576 return (0); 577} 578 579/* 580 * Allow OID leaf in both forms: 581 * 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs; 582 * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that. 583 */ 584static int32_t 585parse_oid_string(struct snmp_toolinfo *snmptoolctx, 586 struct snmp_value *value, char *string) 587{ 588 struct snmp_object obj; 589 590 if (isdigit(string[0])) 591 return (parse_oid_numeric(value, string)); 592 593 memset(&obj, 0, sizeof(struct snmp_object)); 594 if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) { 595 warnx("Unknown OID enum string - %s", string); 596 return (-1); 597 } 598 599 asn_append_oid(&(value->v.oid), &(obj.val.var)); 600 return (1); 601} 602 603static int32_t 604parse_ip(struct snmp_value * value, char * val) 605{ 606 char *endptr, *str; 607 int32_t i; 608 uint32_t v; 609 610 str = val; 611 for (i = 0; i < 4; i++) { 612 v = strtoul(str, &endptr, 10); 613 if (v > 0xff) 614 return (-1); 615 if (*endptr != '.' && *endptr != '\0' && i != 3) 616 break; 617 str = endptr + 1; 618 value->v.ipaddress[i] = (uint8_t) v; 619 } 620 value->syntax = SNMP_SYNTAX_IPADDRESS; 621 622 return (0); 623} 624 625static int32_t 626parse_int(struct snmp_value *value, char *val) 627{ 628 char *endptr; 629 int32_t v, saved_errno; 630 631 saved_errno = errno; 632 errno = 0; 633 634 v = strtol(val, &endptr, 10); 635 636 if (errno != 0) { 637 warnx("Value %s not supported - %s", val, strerror(errno)); 638 errno = saved_errno; 639 return (-1); 640 } 641 642 value->syntax = SNMP_SYNTAX_INTEGER; 643 value->v.integer = v; 644 errno = saved_errno; 645 646 return (0); 647} 648 649static int32_t 650parse_int_string(struct snmp_object *object, char *val) 651{ 652 int32_t v; 653 654 if (isdigit(val[0])) 655 return ((parse_int(&(object->val), val))); 656 657 if (object->info == NULL) { 658 warnx("Unknown enumerated integer type - %s", val); 659 return (-1); 660 } 661 if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0) 662 warnx("Unknown enumerated integer type - %s", val); 663 664 object->val.v.integer = v; 665 return (1); 666} 667 668/* 669 * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE, 670 * SNMP_SYNTAX_TIMETICKS. 671 */ 672static int32_t 673parse_uint(struct snmp_value *value, char *val) 674{ 675 char *endptr; 676 uint32_t v = 0; 677 int32_t saved_errno; 678 679 saved_errno = errno; 680 errno = 0; 681 682 v = strtoul(val, &endptr, 10); 683 684 if (errno != 0) { 685 warnx("Value %s not supported - %s", val, strerror(errno)); 686 errno = saved_errno; 687 return (-1); 688 } 689 690 value->v.uint32 = v; 691 errno = saved_errno; 692 693 return (0); 694} 695 696static int32_t 697parse_ticks(struct snmp_value *value, char *val) 698{ 699 if (parse_uint(value, val) < 0) 700 return (-1); 701 702 value->syntax = SNMP_SYNTAX_TIMETICKS; 703 return (0); 704} 705 706static int32_t 707parse_gauge(struct snmp_value *value, char *val) 708{ 709 if (parse_uint(value, val) < 0) 710 return (-1); 711 712 value->syntax = SNMP_SYNTAX_GAUGE; 713 return (0); 714} 715 716static int32_t 717parse_counter(struct snmp_value *value, char *val) 718{ 719 if (parse_uint(value, val) < 0) 720 return (-1); 721 722 value->syntax = SNMP_SYNTAX_COUNTER; 723 return (0); 724} 725 726static int32_t 727parse_uint64(struct snmp_value *value, char *val) 728{ 729 char *endptr; 730 int32_t saved_errno; 731 uint64_t v; 732 733 saved_errno = errno; 734 errno = 0; 735 736 v = strtoull(val, &endptr, 10); 737 738 if (errno != 0) { 739 warnx("Value %s not supported - %s", val, strerror(errno)); 740 errno = saved_errno; 741 return (-1); 742 } 743 744 value->syntax = SNMP_SYNTAX_COUNTER64; 745 value->v.counter64 = v; 746 errno = saved_errno; 747 748 return (0); 749} 750 751static int32_t 752parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val) 753{ 754 switch (syntax) { 755 case SNMP_SYNTAX_INTEGER: 756 return (parse_int(value, val)); 757 case SNMP_SYNTAX_IPADDRESS: 758 return (parse_ip(value, val)); 759 case SNMP_SYNTAX_COUNTER: 760 return (parse_counter(value, val)); 761 case SNMP_SYNTAX_GAUGE: 762 return (parse_gauge(value, val)); 763 case SNMP_SYNTAX_TIMETICKS: 764 return (parse_ticks(value, val)); 765 case SNMP_SYNTAX_COUNTER64: 766 return (parse_uint64(value, val)); 767 case SNMP_SYNTAX_OCTETSTRING: 768 return (snmp_tc2oct(SNMP_STRING, value, val)); 769 case SNMP_SYNTAX_OID: 770 return (parse_oid_numeric(value, val)); 771 default: 772 /* NOTREACHED */ 773 break; 774 } 775 776 return (-1); 777} 778 779/* 780 * Parse a command line argument of type OID=syntax:value and fill in whatever 781 * fields can be derived from the input into snmp_value structure. Reads numeric 782 * OIDs. 783 */ 784static int32_t 785parse_pair_numoid_val(char *str, struct snmp_value *snmp_val) 786{ 787 int32_t cnt; 788 char *ptr; 789 enum snmp_syntax syntax; 790 char oid_str[ASN_OIDSTRLEN]; 791 792 ptr = str; 793 for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++) 794 if (ptr[cnt] == '=') 795 break; 796 797 if (cnt >= ASN_OIDSTRLEN) { 798 warnx("OID too long - %s", str); 799 return (-1); 800 } 801 strlcpy(oid_str, ptr, (size_t) (cnt + 1)); 802 803 ptr = str + cnt + 1; 804 for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++) 805 if(ptr[cnt] == ':') 806 break; 807 808 if (cnt >= MAX_CMD_SYNTAX_LEN) { 809 warnx("Unknown syntax in OID - %s", str); 810 return (-1); 811 } 812 813 if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) { 814 warnx("Unknown syntax in OID - %s", ptr); 815 return (-1); 816 } 817 818 ptr = ptr + cnt + 1; 819 for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++) 820 if (ptr[cnt] == '\0') 821 break; 822 823 if (ptr[cnt] != '\0') { 824 warnx("Value string too long - %s",ptr); 825 return (-1); 826 } 827 828 /* 829 * Here try parsing the OIDs and syntaxes and then check values - have 830 * to know syntax to check value boundaries. 831 */ 832 if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) { 833 warnx("Error parsing OID %s",oid_str); 834 return (-1); 835 } 836 837 if (parse_syntax_val(snmp_val, syntax, ptr) < 0) 838 return (-1); 839 840 return (1); 841} 842 843/* XXX-BZ aruments should be swapped. */ 844static int32_t 845parse_syntax_strval(struct snmp_toolinfo *snmptoolctx, char *str, 846 struct snmp_object *object) 847{ 848 uint32_t len; 849 enum snmp_syntax syn; 850 851 /* 852 * Syntax string here not required - still may be present. 853 */ 854 855 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) { 856 for (len = 0 ; *(str + len) != ':'; len++) { 857 if (*(str + len) == '\0') { 858 warnx("Syntax missing in value - %s", str); 859 return (-1); 860 } 861 } 862 if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) { 863 warnx("Unknown syntax in - %s", str); 864 return (-1); 865 } 866 if (syn != object->val.syntax) { 867 if (!ISSET_ERRIGNORE(snmptoolctx)) { 868 warnx("Bad syntax in - %s", str); 869 return (-1); 870 } else 871 object->val.syntax = syn; 872 } 873 len++; 874 } else 875 len = 0; 876 877 switch (object->val.syntax) { 878 case SNMP_SYNTAX_INTEGER: 879 return (parse_int_string(object, str + len)); 880 case SNMP_SYNTAX_IPADDRESS: 881 return (parse_ip(&(object->val), str + len)); 882 case SNMP_SYNTAX_COUNTER: 883 return (parse_counter(&(object->val), str + len)); 884 case SNMP_SYNTAX_GAUGE: 885 return (parse_gauge(&(object->val), str + len)); 886 case SNMP_SYNTAX_TIMETICKS: 887 return (parse_ticks(&(object->val), str + len)); 888 case SNMP_SYNTAX_COUNTER64: 889 return (parse_uint64(&(object->val), str + len)); 890 case SNMP_SYNTAX_OCTETSTRING: 891 return (snmp_tc2oct(object->info->tc, &(object->val), 892 str + len)); 893 case SNMP_SYNTAX_OID: 894 return (parse_oid_string(snmptoolctx, &(object->val), 895 str + len)); 896 default: 897 /* NOTREACHED */ 898 break; 899 } 900 901 return (-1); 902} 903 904static int32_t 905parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx, 906 struct snmp_object *obj, char *argv) 907{ 908 char *ptr; 909 910 if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL) 911 return (-1); 912 913 if (*ptr != '=') { 914 warnx("Value to set expected after OID"); 915 return (-1); 916 } 917 918 if (parse_syntax_strval(snmptoolctx, ptr + 1, obj) < 0) 919 return (-1); 920 921 return (1); 922} 923 924 925static int32_t 926snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx, 927 struct snmp_object *obj, char *argv) 928{ 929 if (argv == NULL) 930 return (-1); 931 932 if (ISSET_NUMERIC(snmptoolctx)) { 933 if (parse_pair_numoid_val(argv, &(obj->val)) < 0) 934 return (-1); 935 } else { 936 if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0) 937 return (-1); 938 } 939 940 return (1); 941} 942 943static int32_t 944add_ip_syntax(struct snmp_value *dst, struct snmp_value *src) 945{ 946 int8_t i; 947 948 dst->syntax = SNMP_SYNTAX_IPADDRESS; 949 for (i = 0; i < 4; i++) 950 dst->v.ipaddress[i] = src->v.ipaddress[i]; 951 952 return (1); 953} 954 955static int32_t 956add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src) 957{ 958 if (src->v.octetstring.len > ASN_MAXOCTETSTRING) { 959 warnx("OctetString len too big - %u",src->v.octetstring.len); 960 return (-1); 961 } 962 963 if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) == 964 NULL) { 965 syslog(LOG_ERR, "malloc() failed - %s", strerror(errno)); 966 return (-1); 967 } 968 969 memcpy(dst->v.octetstring.octets, src->v.octetstring.octets, 970 src->v.octetstring.len); 971 dst->syntax = SNMP_SYNTAX_OCTETSTRING; 972 dst->v.octetstring.len = src->v.octetstring.len; 973 974 return(0); 975} 976 977static int32_t 978add_oid_syntax(struct snmp_value *dst, struct snmp_value *src) 979{ 980 asn_append_oid(&(dst->v.oid), &(src->v.oid)); 981 dst->syntax = SNMP_SYNTAX_OID; 982 return (0); 983} 984 985/* 986 * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT, 987 * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known - 988 * return error. 989 */ 990static int32_t 991snmpset_add_value(struct snmp_value *dst, struct snmp_value *src) 992{ 993 if (dst == NULL || src == NULL) 994 return (-1); 995 996 switch (src->syntax) { 997 case SNMP_SYNTAX_INTEGER: 998 dst->v.integer = src->v.integer; 999 dst->syntax = SNMP_SYNTAX_INTEGER; 1000 break; 1001 case SNMP_SYNTAX_TIMETICKS: 1002 dst->v.uint32 = src->v.uint32; 1003 dst->syntax = SNMP_SYNTAX_TIMETICKS; 1004 break; 1005 case SNMP_SYNTAX_GAUGE: 1006 dst->v.uint32 = src->v.uint32; 1007 dst->syntax = SNMP_SYNTAX_GAUGE; 1008 break; 1009 case SNMP_SYNTAX_COUNTER: 1010 dst->v.uint32 = src->v.uint32; 1011 dst->syntax = SNMP_SYNTAX_COUNTER; 1012 break; 1013 case SNMP_SYNTAX_COUNTER64: 1014 dst->v.counter64 = src->v.counter64; 1015 dst->syntax = SNMP_SYNTAX_COUNTER64; 1016 break; 1017 case SNMP_SYNTAX_IPADDRESS: 1018 add_ip_syntax(dst, src); 1019 break; 1020 case SNMP_SYNTAX_OCTETSTRING: 1021 add_octstring_syntax(dst, src); 1022 break; 1023 case SNMP_SYNTAX_OID: 1024 add_oid_syntax(dst, src); 1025 break; 1026 default: 1027 warnx("Unknown syntax %d", src->syntax); 1028 return (-1); 1029 } 1030 1031 return (0); 1032} 1033 1034static int32_t 1035snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, 1036 struct snmp_object *obj) 1037{ 1038 if (pdu->version == SNMP_V1 && obj->val.syntax == 1039 SNMP_SYNTAX_COUNTER64) { 1040 warnx("64-bit counters are not supported in SNMPv1 PDU"); 1041 return (-1); 1042 } 1043 1044 if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx)) 1045 return (1); 1046 1047 if (obj->info->access < SNMP_ACCESS_SET) { 1048 warnx("Object %s not accessible for set - try 'bsnmpset -a'", 1049 obj->info->string); 1050 return (-1); 1051 } 1052 1053 return (1); 1054} 1055 1056static int32_t 1057snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj) 1058{ 1059 if (pdu->nbindings > SNMP_MAX_BINDINGS) { 1060 warnx("Too many OIDs for one PDU"); 1061 return (-1); 1062 } 1063 1064 if (obj->error > 0) 1065 return (0); 1066 1067 if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val)) 1068 < 0) 1069 return (-1); 1070 1071 asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var)); 1072 pdu->nbindings++; 1073 1074 return (pdu->nbindings); 1075} 1076 1077static int 1078snmptool_set(struct snmp_toolinfo *snmptoolctx) 1079{ 1080 struct snmp_pdu req, resp; 1081 1082 snmp_pdu_create(&req, SNMP_PDU_SET); 1083 1084 while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind, 1085 snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) { 1086 if (snmp_dialog(&req, &resp)) { 1087 warnx("Snmp dialog - %s", strerror(errno)); 1088 break; 1089 } 1090 1091 if (snmp_pdu_check(&req, &resp) > 0) { 1092 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) 1093 snmp_output_resp(snmptoolctx, &resp, NULL); 1094 break; 1095 } 1096 1097 snmp_output_err_resp(snmptoolctx, &resp); 1098 if (!ISSET_RETRY(snmptoolctx)) 1099 break; 1100 1101 if (snmp_object_seterror(snmptoolctx, 1102 &(resp.bindings[resp.error_index - 1]), 1103 resp.error_status) <= 0) 1104 break; 1105 1106 fprintf(stderr, "Retrying...\n"); 1107 snmp_pdu_free(&req); 1108 snmp_pdu_free(&resp); 1109 snmp_pdu_create(&req, SNMP_PDU_SET); 1110 } 1111 1112 snmp_pdu_free(&resp); 1113 1114 return (0); 1115} 1116 1117/* ***************************************************************************** 1118 * main 1119 */ 1120/* 1121 * According to command line options prepare SNMP Get | GetNext | GetBulk PDU. 1122 * Wait for a response and print it. 1123 */ 1124/* 1125 * Do a 'snmp walk' - according to command line options request for values 1126 * lexicographically subsequent and subrooted at a common node. Send a GetNext 1127 * PDU requesting the value for each next variable and print the response. Stop 1128 * when a Response PDU is received that contains the value of a variable not 1129 * subrooted at the variable the walk started. 1130 */ 1131int 1132main(int argc, char ** argv) 1133{ 1134 struct snmp_toolinfo snmptoolctx; 1135 int32_t oid_cnt, last_oid, opt_num; 1136 int rc = 0; 1137 1138 /* Make sure program_name is set and valid. */ 1139 if (*argv == NULL) 1140 program_name = "snmptool"; 1141 else { 1142 program_name = strrchr(*argv, '/'); 1143 if (program_name != NULL) 1144 program_name++; 1145 else 1146 program_name = *argv; 1147 } 1148 1149 if (program_name == NULL) { 1150 fprintf(stderr, "Error: No program name?\n"); 1151 exit (1); 1152 } else if (strcmp(program_name, "bsnmpget") == 0) 1153 program = BSNMPGET; 1154 else if (strcmp(program_name, "bsnmpwalk") == 0) 1155 program = BSNMPWALK; 1156 else if (strcmp(program_name, "bsnmpset") == 0) 1157 program = BSNMPSET; 1158 else { 1159 fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name); 1160 exit (1); 1161 } 1162 1163 /* Initialize. */ 1164 if (snmptool_init(&snmptoolctx) < 0) 1165 exit (1); 1166 1167 if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) { 1168 snmp_tool_freeall(&snmptoolctx); 1169 /* On -h (help) exit without error. */ 1170 if (opt_num == -2) 1171 exit(0); 1172 else 1173 exit(1); 1174 } 1175 1176 oid_cnt = argc - opt_num - 1; 1177 if (oid_cnt == 0) { 1178 switch (program) { 1179 case BSNMPGET: 1180 if (!ISSET_EDISCOVER(&snmptoolctx) && 1181 !ISSET_LOCALKEY(&snmptoolctx)) { 1182 fprintf(stderr, "No OID given.\n"); 1183 usage(); 1184 snmp_tool_freeall(&snmptoolctx); 1185 exit(1); 1186 } 1187 break; 1188 1189 case BSNMPWALK: 1190 if (snmp_object_add(&snmptoolctx, snmpwalk_add_default, 1191 NULL) < 0) { 1192 fprintf(stderr, 1193 "Error setting default subtree.\n"); 1194 snmp_tool_freeall(&snmptoolctx); 1195 exit(1); 1196 } 1197 break; 1198 1199 case BSNMPSET: 1200 fprintf(stderr, "No OID given.\n"); 1201 usage(); 1202 snmp_tool_freeall(&snmptoolctx); 1203 exit(1); 1204 } 1205 } 1206 1207 if (snmp_import_all(&snmptoolctx) < 0) { 1208 snmp_tool_freeall(&snmptoolctx); 1209 exit(1); 1210 } 1211 1212 /* A simple sanity check - can not send GETBULK when using SNMPv1. */ 1213 if (program == BSNMPGET && snmp_client.version == SNMP_V1 && 1214 GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) { 1215 fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n"); 1216 snmp_tool_freeall(&snmptoolctx); 1217 exit(1); 1218 } 1219 1220 for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) { 1221 if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ? 1222 snmpset_parse_oid : snmptools_parse_oid, 1223 argv[last_oid])) < 0) { 1224 fprintf(stderr, "Error parsing OID string '%s'.\n", 1225 argv[last_oid]); 1226 snmp_tool_freeall(&snmptoolctx); 1227 exit(1); 1228 } 1229 } 1230 1231 if (snmp_open(NULL, NULL, NULL, NULL)) { 1232 warnx("Failed to open snmp session: %s.", strerror(errno)); 1233 snmp_tool_freeall(&snmptoolctx); 1234 exit(1); 1235 } 1236 1237 if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0) 1238 SET_EDISCOVER(&snmptoolctx); 1239 1240 if (ISSET_EDISCOVER(&snmptoolctx) && 1241 snmp_discover_engine(snmptoolctx.passwd) < 0) { 1242 warnx("Unknown SNMP Engine ID: %s.", strerror(errno)); 1243 rc = 1; 1244 goto cleanup; 1245 } 1246 1247 if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE || 1248 ISSET_EDISCOVER(&snmptoolctx)) 1249 snmp_output_engine(); 1250 1251 if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) && 1252 !ISSET_EDISCOVER(&snmptoolctx)) { 1253 if (snmp_passwd_to_keys(&snmp_client.user, 1254 snmptoolctx.passwd) != SNMP_CODE_OK || 1255 snmp_get_local_keys(&snmp_client.user, 1256 snmp_client.engine.engine_id, 1257 snmp_client.engine.engine_len) != SNMP_CODE_OK) { 1258 warnx("Failed to get keys: %s.", strerror(errno)); 1259 rc = 1; 1260 goto cleanup; 1261 } 1262 } 1263 1264 if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE || 1265 ISSET_EDISCOVER(&snmptoolctx)) 1266 snmp_output_keys(); 1267 1268 if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0) 1269 goto cleanup; 1270 1271 switch (program) { 1272 case BSNMPGET: 1273 rc = snmptool_get(&snmptoolctx); 1274 break; 1275 case BSNMPWALK: 1276 rc = snmptool_walk(&snmptoolctx); 1277 break; 1278 case BSNMPSET: 1279 rc = snmptool_set(&snmptoolctx); 1280 break; 1281 } 1282 1283 1284cleanup: 1285 snmp_tool_freeall(&snmptoolctx); 1286 snmp_close(); 1287 1288 exit(rc); 1289} 1290