134689Sbde/*- 250476Speter * Copyright (c) 2005-2006 The FreeBSD Project 31573Srgrimes * All rights reserved. 4156813Sru * 5156813Sru * Author: Shteryana Shopova <syrinx@FreeBSD.org> 634689Sbde * 734689Sbde * Redistribution of this software and documentation and use in source and 834689Sbde * binary forms, with or without modification, are permitted provided that 938752Sbde * the following conditions are met: 10173017Sru * 11186647Srwatson * 1. Redistributions of source code or documentation must retain the above 12204738Simp * copyright notice, this list of conditions and the following disclaimer. 13204738Simp * 2. Redistributions in binary form must reproduce the above copyright 1481133Stmm * notice, this list of conditions and the following disclaimer in the 1559897Sjoe * documentation and/or other materials provided with the distribution. 1679471Smarkm * 17166131Srafan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18122568Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1959353Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2041257Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2182355Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2294690Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2341257Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2456081Sbde * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2594690Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26181344Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2734689Sbde * SUCH DAMAGE. 2834689Sbde * 29204738Simp * Helper functions for snmp client tools 30204738Simp * 3134689Sbde * $FreeBSD$ 32205113Simp */ 33205113Simp 34205113Simp#include <sys/param.h> 35205113Simp#include <sys/queue.h> 36205113Simp#include <sys/uio.h> 37205113Simp 38205113Simp#include <assert.h> 39205113Simp#include <ctype.h> 40205113Simp#include <err.h> 41205113Simp#include <errno.h> 42205113Simp#include <fcntl.h> 43205113Simp#include <stdio.h> 44205113Simp#include <stdlib.h> 45205113Simp#include <string.h> 46205113Simp#include <syslog.h> 47205113Simp#include <unistd.h> 48205113Simp 49205113Simp#include <bsnmp/asn1.h> 50205113Simp#include <bsnmp/snmp.h> 51205113Simp#include <bsnmp/snmpclient.h> 52205113Simp#include "bsnmptc.h" 53205113Simp#include "bsnmptools.h" 54205113Simp 55205113Simp/* Internal varibale to turn on library debugging for testing and to 56205113Simp * find bugs. It is not exported via the header file. 57205113Simp * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */ 58205113Simpint _bsnmptools_debug = 0; 59205113Simp 60205113Simp/* Default files to import mapping from if none explicitly provided. */ 61205113Simp#define bsnmpd_defs "/usr/share/snmp/defs/tree.def" 62205113Simp#define mibII_defs "/usr/share/snmp/defs/mibII_tree.def" 63205113Simp 64205113Simp/* 65205113Simp * The .iso.org.dod oid that has to be prepended to every OID when requesting 66205113Simp * a value. 67205113Simp */ 68205113Simpconst struct asn_oid IsoOrgDod_OID = { 69205113Simp 3, { 1, 3, 6 } 70205113Simp}; 71205113Simp 72205113Simp 73205113Simp#define SNMP_ERR_UNKNOWN 0 74205113Simp 75205113Simp/* 76205113Simp * An array of error strings corresponding to error definitions from libbsnmp. 77205113Simp */ 78205113Simpstatic const struct { 79205113Simp const char *str; 80205113Simp int32_t error; 81205113Simp} error_strings[] = { 82205113Simp { "Unknown", SNMP_ERR_UNKNOWN }, 83205113Simp { "Too big ", SNMP_ERR_TOOBIG }, 84205113Simp { "No such Name", SNMP_ERR_NOSUCHNAME }, 85205113Simp { "Bad Value", SNMP_ERR_BADVALUE }, 86205113Simp { "Readonly", SNMP_ERR_READONLY }, 87205113Simp { "General error", SNMP_ERR_GENERR }, 88205113Simp { "No access", SNMP_ERR_NO_ACCESS }, 89205113Simp { "Wrong type", SNMP_ERR_WRONG_TYPE }, 90205113Simp { "Wrong length", SNMP_ERR_WRONG_LENGTH }, 91205113Simp { "Wrong encoding", SNMP_ERR_WRONG_ENCODING }, 92205113Simp { "Wrong value", SNMP_ERR_WRONG_VALUE }, 93205113Simp { "No creation", SNMP_ERR_NO_CREATION }, 94205113Simp { "Inconsistent value", SNMP_ERR_INCONS_VALUE }, 95205113Simp { "Resource unavailable", SNMP_ERR_RES_UNAVAIL }, 96205113Simp { "Commit failed", SNMP_ERR_COMMIT_FAILED }, 97205113Simp { "Undo failed", SNMP_ERR_UNDO_FAILED }, 98205113Simp { "Authorization error", SNMP_ERR_AUTH_ERR }, 99205113Simp { "Not writable", SNMP_ERR_NOT_WRITEABLE }, 100205113Simp { "Inconsistent name", SNMP_ERR_INCONS_NAME }, 101205113Simp { NULL, 0 } 102205113Simp}; 103205113Simp 104205113Simp/* This one and any following are exceptions. */ 105205113Simp#define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT 106205113Simp 107205113Simpstatic const struct { 108205113Simp const char *str; 109200413Sed enum snmp_syntax stx; 11034689Sbde} syntax_strings[] = { 111103436Speter { "Null", SNMP_SYNTAX_NULL }, 112103436Speter { "Integer", SNMP_SYNTAX_INTEGER }, 11372309Sobrien { "OctetString", SNMP_SYNTAX_OCTETSTRING }, 11434689Sbde { "OID", SNMP_SYNTAX_OID }, 11572309Sobrien { "IpAddress", SNMP_SYNTAX_IPADDRESS }, 11672309Sobrien { "Counter32", SNMP_SYNTAX_COUNTER }, 1171573Srgrimes { "Gauge", SNMP_SYNTAX_GAUGE }, 1181573Srgrimes { "TimeTicks", SNMP_SYNTAX_TIMETICKS }, 119183242Ssam { "Counter64", SNMP_SYNTAX_COUNTER64 }, 120183242Ssam { "Unknown", SNMP_SYNTAX_UNKNOWN }, 121156813Sru}; 122121340Sharti 123119508Sphkint 124119508Sphksnmptool_init(struct snmp_toolinfo *snmptoolctx) 125156813Sru{ 126135549Sdes char *str; 12753922Speter size_t slen; 12853922Speter 129156813Sru memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo)); 130125123Semax snmptoolctx->objects = 0; 131125123Semax snmptoolctx->mappings = NULL; 132125123Semax snmptoolctx->flags = SNMP_PDU_GET; /* XXX */ 133131768Semax SLIST_INIT(&snmptoolctx->filelist); 134183242Ssam snmp_client_init(&snmp_client); 135183242Ssam SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS); 136183242Ssam 137183242Ssam if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0) 138183242Ssam warnx("Error adding file %s to list", bsnmpd_defs); 139183242Ssam 140183242Ssam if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0) 141183242Ssam warnx("Error adding file %s to list", mibII_defs); 142174548Sru 143174519Sdougb /* Read the environment */ 144181344Sdfr if ((str = getenv("SNMPAUTH")) != NULL) { 145174519Sdougb slen = strlen(str); 146174519Sdougb if (slen == strlen("md5") && strcasecmp(str, "md5") == 0) 147156905Sru snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5; 148156905Sru else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0) 149156905Sru snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA; 150156905Sru else if (slen != 0) 151183242Ssam warnx("Bad authentication type - %s in SNMPAUTH", str); 152183242Ssam } 153183242Ssam 154183242Ssam if ((str = getenv("SNMPPRIV")) != NULL) { 155183242Ssam slen = strlen(str); 156183242Ssam if (slen == strlen("des") && strcasecmp(str, "des") == 0) 157183242Ssam snmp_client.user.priv_proto = SNMP_PRIV_DES; 158183242Ssam else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0) 159183242Ssam snmp_client.user.priv_proto = SNMP_PRIV_AES; 160183242Ssam else if (slen != 0) 161183242Ssam warnx("Bad privacy type - %s in SNMPPRIV", str); 162183242Ssam } 163131768Semax 164156905Sru if ((str = getenv("SNMPUSER")) != NULL) { 16552228Sbp if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) { 166156905Sru warnx("Username too long - %s in SNMPUSER", str); 16787960Ssheldonh return (-1); 16834689Sbde } 16936026Sjb if (slen > 0) { 17034689Sbde strlcpy(snmp_client.user.sec_name, str, 171161524Smarcel sizeof(snmp_client.user.sec_name)); 172203181Smarcel snmp_client.version = SNMP_V3; 173161524Smarcel } 174161524Smarcel } 175161524Smarcel 176117950Speter if ((str = getenv("SNMPPASSWD")) != NULL) { 177156905Sru if ((slen = strlen(str)) > MAXSTR) 178117950Speter slen = MAXSTR - 1; 179156905Sru if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) { 180117950Speter warnx("malloc() failed - %s", strerror(errno)); 181197025Sdelphij return (-1); 182118694Sdeischen } 183118694Sdeischen if (slen > 0) 184150314Simura strlcpy(snmptoolctx->passwd, str, slen + 1); 185150314Simura } 186150314Simura 187150314Simura return (0); 188202982Syongari} 189202982Syongari 190202982Syongari#define OBJECT_IDX_LIST(o) o->info->table_idx->index_list 191202982Syongari 192183242Ssam/* 193183242Ssam * Walk through the file list and import string<->oid mappings from each file. 194117797Smtm */ 195117797Smtmint32_t 196183242Ssamsnmp_import_all(struct snmp_toolinfo *snmptoolctx) 197183242Ssam{ 198129225Scognet int32_t fc; 199129225Scognet struct fname *tmp; 200183242Ssam 201183242Ssam if (snmptoolctx == NULL) 202183242Ssam return (-1); 203183242Ssam 204183242Ssam if (ISSET_NUMERIC(snmptoolctx)) 205126799Sphk return (0); 206126799Sphk 207183242Ssam if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL) 208183242Ssam return (-1); 209141403Sphk 210141403Sphk fc = 0; 211183242Ssam if (SLIST_EMPTY(&snmptoolctx->filelist)) { 212183242Ssam warnx("No files to read OID <-> string conversions from"); 213189589Sthompsa return (-1); 214183242Ssam } else { 215183242Ssam SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) { 2161573Srgrimes if (tmp->done) 217 continue; 218 if (snmp_import_file(snmptoolctx, tmp) < 0) { 219 fc = -1; 220 break; 221 } 222 fc++; 223 } 224 } 225 226 snmp_mapping_dump(snmptoolctx); 227 return (fc); 228} 229 230/* 231 * Add a filename to the file list - the initial idea of keeping a list with all 232 * files to read OIDs from was that an application might want to have loaded in 233 * memory the OIDs from a single file only and when done with them read the OIDs 234 * from another file. This is not used yet but might be a good idea at some 235 * point. Size argument is number of bytes in string including trailing '\0', 236 * not string length. 237 */ 238int32_t 239add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename, 240 const struct asn_oid *cut, int32_t done) 241{ 242 char *fstring; 243 struct fname *entry; 244 245 if (snmptoolctx == NULL) 246 return (-1); 247 248 /* Make sure file was not in list. */ 249 SLIST_FOREACH(entry, &snmptoolctx->filelist, link) { 250 if (strncmp(entry->name, filename, strlen(entry->name)) == 0) 251 return (0); 252 } 253 254 if ((fstring = malloc(strlen(filename) + 1)) == NULL) { 255 warnx("malloc() failed - %s", strerror(errno)); 256 return (-1); 257 } 258 259 if ((entry = malloc(sizeof(struct fname))) == NULL) { 260 warnx("malloc() failed - %s", strerror(errno)); 261 free(fstring); 262 return (-1); 263 } 264 265 memset(entry, 0, sizeof(struct fname)); 266 267 if (cut != NULL) 268 asn_append_oid(&(entry->cut), cut); 269 strlcpy(fstring, filename, strlen(filename) + 1); 270 entry->name = fstring; 271 entry->done = done; 272 SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link); 273 274 return (1); 275} 276 277void 278free_filelist(struct snmp_toolinfo *snmptoolctx) 279{ 280 struct fname *f; 281 282 if (snmptoolctx == NULL) 283 return; /* XXX error handling */ 284 285 while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) { 286 SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link); 287 if (f->name) 288 free(f->name); 289 free(f); 290 } 291} 292 293static char 294isvalid_fchar(char c, int pos) 295{ 296 if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' || 297 (pos != 0 && isdigit(c))){ 298 return (c); 299 } 300 301 if (c == '\0') 302 return (0); 303 304 if (!isascii(c) || !isprint(c)) 305 warnx("Unexpected character %#2x", (u_int) c); 306 else 307 warnx("Illegal character '%c'", c); 308 309 return (-1); 310} 311 312/* 313 * Re-implement getsubopt from scratch, because the second argument is broken 314 * and will not compile with WARNS=5. 315 * Copied from src/contrib/bsnmp/snmpd/main.c. 316 */ 317static int 318getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 319{ 320 static const char *const delim = ",\t "; 321 u_int i; 322 char *ptr; 323 324 *optp = NULL; 325 326 /* Skip leading junk. */ 327 for (ptr = *arg; *ptr != '\0'; ptr++) 328 if (strchr(delim, *ptr) == NULL) 329 break; 330 if (*ptr == '\0') { 331 *arg = ptr; 332 return (-1); 333 } 334 *optp = ptr; 335 336 /* Find the end of the option. */ 337 while (*++ptr != '\0') 338 if (strchr(delim, *ptr) != NULL || *ptr == '=') 339 break; 340 341 if (*ptr != '\0') { 342 if (*ptr == '=') { 343 *ptr++ = '\0'; 344 *valp = ptr; 345 while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 346 ptr++; 347 if (*ptr != '\0') 348 *ptr++ = '\0'; 349 } else 350 *ptr++ = '\0'; 351 } 352 353 *arg = ptr; 354 355 for (i = 0; *options != NULL; options++, i++) 356 if (strcmp(*optp, *options) == 0) 357 return (i); 358 return (-1); 359} 360 361static int32_t 362parse_path(char *value) 363{ 364 int32_t i, len; 365 366 if (value == NULL) 367 return (-1); 368 369 for (len = 0; len < MAXPATHLEN; len++) { 370 i = isvalid_fchar(*(value + len), len) ; 371 372 if (i == 0) 373 break; 374 else if (i < 0) 375 return (-1); 376 } 377 378 if (len >= MAXPATHLEN || value[len] != '\0') { 379 warnx("Bad pathname - '%s'", value); 380 return (-1); 381 } 382 383 return (len); 384} 385 386static int32_t 387parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path, 388 const struct asn_oid *cut) 389{ 390 int32_t namelen; 391 char filename[MAXPATHLEN + 1]; 392 393 if (value == NULL) 394 return (-1); 395 396 do { 397 memset(filename, 0, MAXPATHLEN + 1); 398 399 if (isalpha(*value) && (path == NULL || path[0] == '\0')) { 400 strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1); 401 namelen = strlen(SNMP_DEFS_DIR); 402 } else if (path != NULL){ 403 strlcpy(filename, path, MAXPATHLEN + 1); 404 namelen = strlen(path); 405 } else 406 namelen = 0; 407 408 for ( ; namelen < MAXPATHLEN; value++) { 409 if (isvalid_fchar(*value, namelen) > 0) { 410 filename[namelen++] = *value; 411 continue; 412 } 413 414 if (*value == ',' ) 415 value++; 416 else if (*value == '\0') 417 ; 418 else { 419 if (!isascii(*value) || !isprint(*value)) 420 warnx("Unexpected character %#2x in" 421 " filename", (u_int) *value); 422 else 423 warnx("Illegal character '%c' in" 424 " filename", *value); 425 return (-1); 426 } 427 428 filename[namelen]='\0'; 429 break; 430 } 431 432 if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) { 433 warnx("Filename %s too long", filename); 434 return (-1); 435 } 436 437 if (add_filename(snmptoolctx, filename, cut, 0) < 0) { 438 warnx("Error adding file %s to list", filename); 439 return (-1); 440 } 441 } while (*value != '\0'); 442 443 return(1); 444} 445 446static int32_t 447parse_ascii(char *ascii, uint8_t *binstr, size_t binlen) 448{ 449 int32_t alen, count, saved_errno, i; 450 uint32_t val; 451 char dptr[3]; 452 453 /* Filter 0x at the beginning */ 454 if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x') 455 i = 2; 456 else 457 i = 0; 458 459 saved_errno = errno; 460 errno = 0; 461 for (count = 0; i < alen; i += 2) { 462 /* XXX: consider strlen(ascii) % 2 != 0 */ 463 dptr[0] = ascii[i]; 464 dptr[1] = ascii[i + 1]; 465 dptr[2] = '\0'; 466 if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) { 467 errno = saved_errno; 468 return (-1); 469 } 470 binstr[count] = (uint8_t) val; 471 if (++count >= binlen) { 472 warnx("Key %s too long - truncating to %zu octets", 473 ascii, binlen); 474 break; 475 } 476 } 477 478 return (count); 479} 480 481/* 482 * Functions to parse common input options for client tools and fill in the 483 * snmp_client structure. 484 */ 485int32_t 486parse_authentication(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 487{ 488 int32_t count, subopt; 489 char *val, *option; 490 const char *const subopts[] = { 491 "proto", 492 "key", 493 NULL 494 }; 495 496 assert(opt_arg != NULL); 497 count = 1; 498 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) { 499 switch (subopt) { 500 case 0: 501 if (val == NULL) { 502 warnx("Suboption 'proto' requires an argument"); 503 return (-1); 504 } 505 if (strlen(val) != 3) { 506 warnx("Unknown auth protocol - %s", val); 507 return (-1); 508 } 509 if (strncasecmp("md5", val, strlen("md5")) == 0) 510 snmp_client.user.auth_proto = 511 SNMP_AUTH_HMAC_MD5; 512 else if (strncasecmp("sha", val, strlen("sha")) == 0) 513 snmp_client.user.auth_proto = 514 SNMP_AUTH_HMAC_SHA; 515 else { 516 warnx("Unknown auth protocol - %s", val); 517 return (-1); 518 } 519 break; 520 case 1: 521 if (val == NULL) { 522 warnx("Suboption 'key' requires an argument"); 523 return (-1); 524 } 525 if (parse_ascii(val, snmp_client.user.auth_key, 526 SNMP_AUTH_KEY_SIZ) < 0) { 527 warnx("Bad authentication key- %s", val); 528 return (-1); 529 } 530 break; 531 default: 532 warnx("Unknown suboption - '%s'", suboptarg); 533 return (-1); 534 } 535 count += 1; 536 } 537 return (2/* count */); 538} 539 540int32_t 541parse_privacy(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 542{ 543 int32_t count, subopt; 544 char *val, *option; 545 const char *const subopts[] = { 546 "proto", 547 "key", 548 NULL 549 }; 550 551 assert(opt_arg != NULL); 552 count = 1; 553 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) { 554 switch (subopt) { 555 case 0: 556 if (val == NULL) { 557 warnx("Suboption 'proto' requires an argument"); 558 return (-1); 559 } 560 if (strlen(val) != 3) { 561 warnx("Unknown privacy protocol - %s", val); 562 return (-1); 563 } 564 if (strncasecmp("aes", val, strlen("aes")) == 0) 565 snmp_client.user.priv_proto = SNMP_PRIV_AES; 566 else if (strncasecmp("des", val, strlen("des")) == 0) 567 snmp_client.user.priv_proto = SNMP_PRIV_DES; 568 else { 569 warnx("Unknown privacy protocol - %s", val); 570 return (-1); 571 } 572 break; 573 case 1: 574 if (val == NULL) { 575 warnx("Suboption 'key' requires an argument"); 576 return (-1); 577 } 578 if (parse_ascii(val, snmp_client.user.priv_key, 579 SNMP_PRIV_KEY_SIZ) < 0) { 580 warnx("Bad privacy key- %s", val); 581 return (-1); 582 } 583 break; 584 default: 585 warnx("Unknown suboption - '%s'", suboptarg); 586 return (-1); 587 } 588 count += 1; 589 } 590 return (2/* count */); 591} 592 593int32_t 594parse_context(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 595{ 596 int32_t count, subopt; 597 char *val, *option; 598 const char *const subopts[] = { 599 "context", 600 "context-engine", 601 NULL 602 }; 603 604 assert(opt_arg != NULL); 605 count = 1; 606 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) { 607 switch (subopt) { 608 case 0: 609 if (val == NULL) { 610 warnx("Suboption 'context' - no argument"); 611 return (-1); 612 } 613 strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ); 614 break; 615 case 1: 616 if (val == NULL) { 617 warnx("Suboption 'context-engine' - no argument"); 618 return (-1); 619 } 620 if ((snmp_client.clen = parse_ascii(val, 621 snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) < 0) { 622 warnx("Bad EngineID - %s", val); 623 return (-1); 624 } 625 break; 626 default: 627 warnx("Unknown suboption - '%s'", suboptarg); 628 return (-1); 629 } 630 count += 1; 631 } 632 return (2/* count */); 633} 634 635int32_t 636parse_user_security(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 637{ 638 int32_t count, subopt, saved_errno; 639 char *val, *option; 640 const char *const subopts[] = { 641 "engine", 642 "engine-boots", 643 "engine-time", 644 "name", 645 NULL 646 }; 647 648 assert(opt_arg != NULL); 649 count = 1; 650 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) { 651 switch (subopt) { 652 case 0: 653 if (val == NULL) { 654 warnx("Suboption 'engine' - no argument"); 655 return (-1); 656 } 657 snmp_client.engine.engine_len = parse_ascii(val, 658 snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ); 659 if (snmp_client.engine.engine_len < 0) { 660 warnx("Bad EngineID - %s", val); 661 return (-1); 662 } 663 break; 664 case 1: 665 if (val == NULL) { 666 warnx("Suboption 'engine-boots' - no argument"); 667 return (-1); 668 } 669 saved_errno = errno; 670 errno = 0; 671 snmp_client.engine.engine_boots = strtoul(val, NULL, 10); 672 if (errno != 0) { 673 warnx("Bad 'engine-boots' value %s - %s", val, 674 strerror(errno)); 675 errno = saved_errno; 676 return (-1); 677 } 678 errno = saved_errno; 679 break; 680 case 2: 681 if (val == NULL) { 682 warnx("Suboption 'engine-time' - no argument"); 683 return (-1); 684 } 685 saved_errno = errno; 686 errno = 0; 687 snmp_client.engine.engine_time = strtoul(val, NULL, 10); 688 if (errno != 0) { 689 warnx("Bad 'engine-time' value %s - %s", val, 690 strerror(errno)); 691 errno = saved_errno; 692 return (-1); 693 } 694 errno = saved_errno; 695 break; 696 case 3: 697 strlcpy(snmp_client.user.sec_name, val, 698 SNMP_ADM_STR32_SIZ); 699 break; 700 default: 701 warnx("Unknown suboption - '%s'", suboptarg); 702 return (-1); 703 } 704 count += 1; 705 } 706 return (2/* count */); 707} 708 709int32_t 710parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 711{ 712 assert(opt_arg != NULL); 713 714 if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0) 715 return (-1); 716 717 return (2); 718} 719 720int32_t 721parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 722{ 723 char path[MAXPATHLEN + 1]; 724 int32_t cut_dflt, len, subopt; 725 struct asn_oid cut; 726 char *val, *option; 727 const char *const subopts[] = { 728 "cut", 729 "path", 730 "file", 731 NULL 732 }; 733 734#define INC_CUT 0 735#define INC_PATH 1 736#define INC_LIST 2 737 738 assert(opt_arg != NULL); 739 740 /* if (opt == 'i') 741 free_filelist(snmptoolctx, ); */ 742 /* 743 * This function should be called only after getopt(3) - otherwise if 744 * no previous validation of opt_arg strlen() may not return what is 745 * expected. 746 */ 747 748 path[0] = '\0'; 749 memset(&cut, 0, sizeof(struct asn_oid)); 750 cut_dflt = -1; 751 752 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) { 753 switch (subopt) { 754 case INC_CUT: 755 if (val == NULL) { 756 warnx("Suboption 'cut' requires an argument"); 757 return (-1); 758 } else { 759 if (snmp_parse_numoid(val, &cut) < 0) 760 return (-1); 761 } 762 cut_dflt = 1; 763 break; 764 765 case INC_PATH: 766 if ((len = parse_path(val)) < 0) 767 return (-1); 768 strlcpy(path, val, len + 1); 769 break; 770 771 case INC_LIST: 772 if (val == NULL) 773 return (-1); 774 if (cut_dflt == -1) 775 len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID); 776 else 777 len = parse_flist(snmptoolctx, val, path, &cut); 778 if (len < 0) 779 return (-1); 780 break; 781 782 default: 783 warnx("Unknown suboption - '%s'", suboptarg); 784 return (-1); 785 } 786 } 787 788 /* XXX: Fix me - returning two is wrong here */ 789 return (2); 790} 791 792int32_t 793parse_server(char *opt_arg) 794{ 795 assert(opt_arg != NULL); 796 797 if (snmp_parse_server(&snmp_client, opt_arg) < 0) 798 return (-1); 799 800 if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) { 801 if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL + 1))) 802 == NULL) { 803 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 804 return (-1); 805 } 806 strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL); 807 } 808 809 return (2); 810} 811 812int32_t 813parse_timeout(char *opt_arg) 814{ 815 int32_t v, saved_errno; 816 817 assert(opt_arg != NULL); 818 819 saved_errno = errno; 820 errno = 0; 821 822 v = strtol(opt_arg, NULL, 10); 823 if (errno != 0) { 824 warnx( "Error parsing timeout value - %s", strerror(errno)); 825 errno = saved_errno; 826 return (-1); 827 } 828 829 snmp_client.timeout.tv_sec = v; 830 errno = saved_errno; 831 return (2); 832} 833 834int32_t 835parse_retry(char *opt_arg) 836{ 837 uint32_t v; 838 int32_t saved_errno; 839 840 assert(opt_arg != NULL); 841 842 saved_errno = errno; 843 errno = 0; 844 845 v = strtoul(opt_arg, NULL, 10); 846 if (errno != 0) { 847 warnx("Error parsing retries count - %s", strerror(errno)); 848 errno = saved_errno; 849 return (-1); 850 } 851 852 snmp_client.retries = v; 853 errno = saved_errno; 854 return (2); 855} 856 857int32_t 858parse_version(char *opt_arg) 859{ 860 uint32_t v; 861 int32_t saved_errno; 862 863 assert(opt_arg != NULL); 864 865 saved_errno = errno; 866 errno = 0; 867 868 v = strtoul(opt_arg, NULL, 10); 869 if (errno != 0) { 870 warnx("Error parsing version - %s", strerror(errno)); 871 errno = saved_errno; 872 return (-1); 873 } 874 875 switch (v) { 876 case 1: 877 snmp_client.version = SNMP_V1; 878 break; 879 case 2: 880 snmp_client.version = SNMP_V2c; 881 break; 882 case 3: 883 snmp_client.version = SNMP_V3; 884 break; 885 default: 886 warnx("Unsupported SNMP version - %u", v); 887 errno = saved_errno; 888 return (-1); 889 } 890 891 errno = saved_errno; 892 return (2); 893} 894 895int32_t 896parse_local_path(char *opt_arg) 897{ 898 assert(opt_arg != NULL); 899 900 if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) { 901 warnx("Filename too long - %s", opt_arg); 902 return (-1); 903 } 904 905 strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH)); 906 return (2); 907} 908 909int32_t 910parse_buflen(char *opt_arg) 911{ 912 uint32_t size; 913 int32_t saved_errno; 914 915 assert(opt_arg != NULL); 916 917 saved_errno = errno; 918 errno = 0; 919 920 size = strtoul(opt_arg, NULL, 10); 921 if (errno != 0) { 922 warnx("Error parsing buffer size - %s", strerror(errno)); 923 errno = saved_errno; 924 return (-1); 925 } 926 927 if (size > MAX_BUFF_SIZE) { 928 warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE); 929 errno = saved_errno; 930 return (-1); 931 } 932 933 snmp_client.txbuflen = snmp_client.rxbuflen = size; 934 errno = saved_errno; 935 return (2); 936} 937 938int32_t 939parse_debug(void) 940{ 941 snmp_client.dump_pdus = 1; 942 return (1); 943} 944 945int32_t 946parse_discovery(struct snmp_toolinfo *snmptoolctx) 947{ 948 SET_EDISCOVER(snmptoolctx); 949 snmp_client.version = SNMP_V3; 950 return (1); 951} 952 953int32_t 954parse_local_key(struct snmp_toolinfo *snmptoolctx) 955{ 956 SET_LOCALKEY(snmptoolctx); 957 snmp_client.version = SNMP_V3; 958 return (1); 959} 960 961int32_t 962parse_num_oids(struct snmp_toolinfo *snmptoolctx) 963{ 964 SET_NUMERIC(snmptoolctx); 965 return (1); 966} 967 968int32_t 969parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg) 970{ 971 assert(opt_arg != NULL); 972 973 if (strlen(opt_arg) > strlen("verbose")) { 974 warnx( "Invalid output option - %s",opt_arg); 975 return (-1); 976 } 977 978 if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0) 979 SET_OUTPUT(snmptoolctx, OUTPUT_SHORT); 980 else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0) 981 SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE); 982 else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0) 983 SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR); 984 else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0) 985 SET_OUTPUT(snmptoolctx, OUTPUT_QUIET); 986 else { 987 warnx( "Invalid output option - %s", opt_arg); 988 return (-1); 989 } 990 991 return (2); 992} 993 994int32_t 995parse_errors(struct snmp_toolinfo *snmptoolctx) 996{ 997 SET_RETRY(snmptoolctx); 998 return (1); 999} 1000 1001int32_t 1002parse_skip_access(struct snmp_toolinfo *snmptoolctx) 1003{ 1004 SET_ERRIGNORE(snmptoolctx); 1005 return (1); 1006} 1007 1008char * 1009snmp_parse_suboid(char *str, struct asn_oid *oid) 1010{ 1011 char *endptr; 1012 asn_subid_t suboid; 1013 1014 if (*str == '.') 1015 str++; 1016 1017 if (*str < '0' || *str > '9') 1018 return (str); 1019 1020 do { 1021 suboid = strtoul(str, &endptr, 10); 1022 if ((asn_subid_t) suboid > ASN_MAXID) { 1023 warnx("Suboid %u > ASN_MAXID", suboid); 1024 return (NULL); 1025 } 1026 if (snmp_suboid_append(oid, suboid) < 0) 1027 return (NULL); 1028 str = endptr + 1; 1029 } while (*endptr == '.'); 1030 1031 return (endptr); 1032} 1033 1034static char * 1035snmp_int2asn_oid(char *str, struct asn_oid *oid) 1036{ 1037 char *endptr; 1038 int32_t v, saved_errno; 1039 1040 saved_errno = errno; 1041 errno = 0; 1042 1043 v = strtol(str, &endptr, 10); 1044 if (errno != 0) { 1045 warnx("Integer value %s not supported - %s", str, 1046 strerror(errno)); 1047 errno = saved_errno; 1048 return (NULL); 1049 } 1050 errno = saved_errno; 1051 1052 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1053 return (NULL); 1054 1055 return (endptr); 1056} 1057 1058/* It is a bit weird to have a table indexed by OID but still... */ 1059static char * 1060snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str, 1061 struct asn_oid *oid) 1062{ 1063 int32_t i; 1064 char string[MAXSTR], *endptr; 1065 struct snmp_object obj; 1066 1067 for (i = 0; i < MAXSTR; i++) 1068 if (isalpha (*(str + i)) == 0) 1069 break; 1070 1071 endptr = str + i; 1072 memset(&obj, 0, sizeof(struct snmp_object)); 1073 if (i == 0) { 1074 if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL) 1075 return (NULL); 1076 if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0) 1077 return (NULL); 1078 } else { 1079 strlcpy(string, str, i + 1); 1080 string[i] = '\0'; 1081 if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) { 1082 warnx("Unknown string - %s",string); 1083 return (NULL); 1084 } 1085 free(string); 1086 } 1087 1088 asn_append_oid(oid, &(obj.val.var)); 1089 return (endptr); 1090} 1091 1092static char * 1093snmp_ip2asn_oid(char *str, struct asn_oid *oid) 1094{ 1095 uint32_t v; 1096 int32_t i; 1097 char *endptr, *ptr; 1098 1099 ptr = str; 1100 for (i = 0; i < 4; i++) { 1101 v = strtoul(ptr, &endptr, 10); 1102 if (v > 0xff) 1103 return (NULL); 1104 if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3) 1105 return (NULL); 1106 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1107 return (NULL); 1108 ptr = endptr + 1; 1109 } 1110 1111 return (endptr); 1112} 1113 1114/* 32-bit counter, gauge, timeticks. */ 1115static char * 1116snmp_uint2asn_oid(char *str, struct asn_oid *oid) 1117{ 1118 char *endptr; 1119 uint32_t v; 1120 int32_t saved_errno; 1121 1122 saved_errno = errno; 1123 errno = 0; 1124 1125 v = strtoul(str, &endptr, 10); 1126 if (errno != 0) { 1127 warnx("Integer value %s not supported - %s\n", str, 1128 strerror(errno)); 1129 errno = saved_errno; 1130 return (NULL); 1131 } 1132 errno = saved_errno; 1133 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0) 1134 return (NULL); 1135 1136 return (endptr); 1137} 1138 1139static char * 1140snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid) 1141{ 1142 char *endptr; 1143 uint64_t v; 1144 int32_t saved_errno; 1145 1146 saved_errno = errno; 1147 errno = 0; 1148 1149 v = strtoull(str, &endptr, 10); 1150 1151 if (errno != 0) { 1152 warnx("Integer value %s not supported - %s", str, 1153 strerror(errno)); 1154 errno = saved_errno; 1155 return (NULL); 1156 } 1157 errno = saved_errno; 1158 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0) 1159 return (NULL); 1160 1161 if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0) 1162 return (NULL); 1163 1164 return (endptr); 1165} 1166 1167enum snmp_syntax 1168parse_syntax(char *str) 1169{ 1170 int32_t i; 1171 1172 for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) { 1173 if (strncmp(syntax_strings[i].str, str, 1174 strlen(syntax_strings[i].str)) == 0) 1175 return (syntax_strings[i].stx); 1176 } 1177 1178 return (SNMP_SYNTAX_NULL); 1179} 1180 1181static char * 1182snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str, 1183 struct index *idx, struct snmp_object *object) 1184{ 1185 char *ptr; 1186 int32_t i; 1187 enum snmp_syntax stx; 1188 char syntax[MAX_CMD_SYNTAX_LEN]; 1189 1190 ptr = str; 1191 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) { 1192 for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) { 1193 if (*(ptr + i) == ':') 1194 break; 1195 } 1196 1197 if (i >= MAX_CMD_SYNTAX_LEN) { 1198 warnx("Unknown syntax in OID - %s", str); 1199 return (NULL); 1200 } 1201 /* Expect a syntax string here. */ 1202 if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) { 1203 warnx("Invalid syntax - %s",syntax); 1204 return (NULL); 1205 } 1206 1207 if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) { 1208 warnx("Syntax mismatch - %d expected, %d given", 1209 idx->syntax, stx); 1210 return (NULL); 1211 } 1212 /* 1213 * That is where the suboid started + the syntax length + one 1214 * character for ':'. 1215 */ 1216 ptr = str + i + 1; 1217 } else 1218 stx = idx->syntax; 1219 1220 switch (stx) { 1221 case SNMP_SYNTAX_INTEGER: 1222 return (snmp_int2asn_oid(ptr, &(object->val.var))); 1223 case SNMP_SYNTAX_OID: 1224 return (snmp_oid2asn_oid(snmptoolctx, ptr, 1225 &(object->val.var))); 1226 case SNMP_SYNTAX_IPADDRESS: 1227 return (snmp_ip2asn_oid(ptr, &(object->val.var))); 1228 case SNMP_SYNTAX_COUNTER: 1229 /* FALLTHROUGH */ 1230 case SNMP_SYNTAX_GAUGE: 1231 /* FALLTHROUGH */ 1232 case SNMP_SYNTAX_TIMETICKS: 1233 return (snmp_uint2asn_oid(ptr, &(object->val.var))); 1234 case SNMP_SYNTAX_COUNTER64: 1235 return (snmp_cnt64_2asn_oid(ptr, &(object->val.var))); 1236 case SNMP_SYNTAX_OCTETSTRING: 1237 return (snmp_tc2oid(idx->tc, ptr, &(object->val.var))); 1238 default: 1239 /* NOTREACHED */ 1240 break; 1241 } 1242 1243 return (NULL); 1244} 1245 1246char * 1247snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str, 1248 struct snmp_object *object) 1249{ 1250 char *ptr; 1251 struct index *temp; 1252 1253 if (object->info->table_idx == NULL) 1254 return (NULL); 1255 1256 ptr = NULL; 1257 STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) { 1258 if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object)) 1259 == NULL) 1260 return (NULL); 1261 1262 if (*ptr != ',' && *ptr != ']') 1263 return (NULL); 1264 str = ptr + 1; 1265 } 1266 1267 if (ptr == NULL || *ptr != ']') { 1268 warnx("Mismatching index - %s", str); 1269 return (NULL); 1270 } 1271 1272 return (ptr + 1); 1273} 1274 1275/* 1276 * Fill in the struct asn_oid member of snmp_value with suboids from input. 1277 * If an error occurs - print message on stderr and return (-1). 1278 * If all is ok - return the length of the oid. 1279 */ 1280int32_t 1281snmp_parse_numoid(char *argv, struct asn_oid *var) 1282{ 1283 char *endptr, *str; 1284 asn_subid_t suboid; 1285 1286 str = argv; 1287 1288 if (*str == '.') 1289 str++; 1290 1291 do { 1292 if (var->len == ASN_MAXOIDLEN) { 1293 warnx("Oid too long - %u", var->len); 1294 return (-1); 1295 } 1296 1297 suboid = strtoul(str, &endptr, 10); 1298 if (suboid > ASN_MAXID) { 1299 warnx("Oid too long - %u", var->len); 1300 return (-1); 1301 } 1302 1303 var->subs[var->len++] = suboid; 1304 str = endptr + 1; 1305 } while ( *endptr == '.'); 1306 1307 if (*endptr != '\0') { 1308 warnx("Invalid oid string - %s", argv); 1309 return (-1); 1310 } 1311 1312 return (var->len); 1313} 1314 1315/* Append a length 1 suboid to an asn_oid structure. */ 1316int32_t 1317snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid) 1318{ 1319 if (var == NULL) 1320 return (-1); 1321 1322 if (var->len >= ASN_MAXOIDLEN) { 1323 warnx("Oid too long - %u", var->len); 1324 return (-1); 1325 } 1326 1327 var->subs[var->len++] = suboid; 1328 1329 return (1); 1330} 1331 1332/* Pop the last suboid from an asn_oid structure. */ 1333int32_t 1334snmp_suboid_pop(struct asn_oid *var) 1335{ 1336 asn_subid_t suboid; 1337 1338 if (var == NULL) 1339 return (-1); 1340 1341 if (var->len < 1) 1342 return (-1); 1343 1344 suboid = var->subs[--(var->len)]; 1345 var->subs[var->len] = 0; 1346 1347 return (suboid); 1348} 1349 1350/* 1351 * Parse the command-line provided string into an OID - alocate memory for a new 1352 * snmp object, fill in its fields and insert it in the object list. A 1353 * (snmp_verify_inoid_f) function must be provided to validate the input string. 1354 */ 1355int32_t 1356snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func, 1357 char *string) 1358{ 1359 struct snmp_object *obj; 1360 1361 if (snmptoolctx == NULL) 1362 return (-1); 1363 1364 /* XXX-BZ does that chack make sense? */ 1365 if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) { 1366 warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1); 1367 return (-1); 1368 } 1369 1370 if ((obj = malloc(sizeof(struct snmp_object))) == NULL) { 1371 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno)); 1372 return (-1); 1373 } 1374 1375 memset(obj, 0, sizeof(struct snmp_object)); 1376 if (func(snmptoolctx, obj, string) < 0) { 1377 warnx("Invalid OID - %s", string); 1378 free(obj); 1379 return (-1); 1380 } 1381 1382 snmptoolctx->objects++; 1383 SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link); 1384 1385 return (1); 1386} 1387 1388/* Given an OID, find it in the object list and remove it. */ 1389int32_t 1390snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid) 1391{ 1392 struct snmp_object *temp; 1393 1394 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) { 1395 warnx("Object list already empty"); 1396 return (-1); 1397 } 1398 1399 1400 SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link) 1401 if (asn_compare_oid(&(temp->val.var), oid) == 0) 1402 break; 1403 1404 if (temp == NULL) { 1405 warnx("No such object in list"); 1406 return (-1); 1407 } 1408 1409 SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link); 1410 if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING && 1411 temp->val.v.octetstring.octets != NULL) 1412 free(temp->val.v.octetstring.octets); 1413 free(temp); 1414 1415 return (1); 1416} 1417 1418static void 1419snmp_object_freeall(struct snmp_toolinfo *snmptoolctx) 1420{ 1421 struct snmp_object *o; 1422 1423 while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) { 1424 SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link); 1425 1426 if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING && 1427 o->val.v.octetstring.octets != NULL) 1428 free(o->val.v.octetstring.octets); 1429 free(o); 1430 } 1431} 1432 1433/* Do all possible memory release before exit. */ 1434void 1435snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx) 1436{ 1437 if (snmp_client.chost != NULL) { 1438 free(snmp_client.chost); 1439 snmp_client.chost = NULL; 1440 } 1441 1442 if (snmp_client.cport != NULL) { 1443 free(snmp_client.cport); 1444 snmp_client.cport = NULL; 1445 } 1446 1447 snmp_mapping_free(snmptoolctx); 1448 free_filelist(snmptoolctx); 1449 snmp_object_freeall(snmptoolctx); 1450 1451 if (snmptoolctx->passwd != NULL) { 1452 free(snmptoolctx->passwd); 1453 snmptoolctx->passwd = NULL; 1454 } 1455} 1456 1457/* 1458 * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f) 1459 * function should check whether the variable is consistent in this PDU 1460 * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to 1461 * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the 1462 * function actually adds the variable to the PDU and must not be NULL. 1463 */ 1464int32_t 1465snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx, 1466 snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc, 1467 struct snmp_pdu *pdu, int32_t maxcount) 1468{ 1469 int32_t nbindings, abind; 1470 struct snmp_object *obj; 1471 1472 if (pdu == NULL || afunc == NULL) 1473 return (-1); 1474 1475 /* Return 0 in case of no more work todo. */ 1476 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) 1477 return (0); 1478 1479 if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) { 1480 warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS"); 1481 return (-1); 1482 } 1483 1484 nbindings = 0; 1485 SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) { 1486 if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) { 1487 nbindings = -1; 1488 break; 1489 } 1490 if ((abind = afunc(pdu, obj)) < 0) { 1491 nbindings = -1; 1492 break; 1493 } 1494 1495 if (abind > 0) { 1496 /* Do not put more varbindings than requested. */ 1497 if (++nbindings >= maxcount) 1498 break; 1499 } 1500 } 1501 1502 return (nbindings); 1503} 1504 1505/* 1506 * Locate an object in the object list and set a corresponding error status. 1507 */ 1508int32_t 1509snmp_object_seterror(struct snmp_toolinfo *snmptoolctx, 1510 struct snmp_value *err_value, int32_t error_status) 1511{ 1512 struct snmp_object *obj; 1513 1514 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL) 1515 return (-1); 1516 1517 SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) 1518 if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) { 1519 obj->error = error_status; 1520 return (1); 1521 } 1522 1523 return (0); 1524} 1525 1526/* 1527 * Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request 1528 * but don't compare syntaxes - when sending a request PDU they must be null. 1529 * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes 1530 * checks and some other checks skipped. 1531 */ 1532int32_t 1533snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req) 1534{ 1535 uint32_t i; 1536 1537 for (i = 0; i < req->nbindings; i++) { 1538 if (asn_compare_oid(&req->bindings[i].var, 1539 &resp->bindings[i].var) != 0) { 1540 warnx("Bad OID in response"); 1541 return (-1); 1542 } 1543 1544 if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax 1545 == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax == 1546 SNMP_SYNTAX_NOSUCHINSTANCE)) 1547 return (0); 1548 } 1549 1550 return (1); 1551} 1552 1553int32_t 1554snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req) 1555{ 1556 int32_t N, R, M, r; 1557 1558 if (req->error_status > (int32_t) resp->nbindings) { 1559 warnx("Bad number of bindings in response"); 1560 return (-1); 1561 } 1562 1563 for (N = 0; N < req->error_status; N++) { 1564 if (asn_is_suboid(&req->bindings[N].var, 1565 &resp->bindings[N].var) == 0) 1566 return (0); 1567 if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW) 1568 return (0); 1569 } 1570 1571 for (R = N , r = N; R < (int32_t) req->nbindings; R++) { 1572 for (M = 0; M < req->error_index && (r + M) < 1573 (int32_t) resp->nbindings; M++) { 1574 if (asn_is_suboid(&req->bindings[R].var, 1575 &resp->bindings[r + M].var) == 0) 1576 return (0); 1577 1578 if (resp->bindings[r + M].syntax == 1579 SNMP_SYNTAX_ENDOFMIBVIEW) { 1580 M++; 1581 break; 1582 } 1583 } 1584 r += M; 1585 } 1586 1587 return (0); 1588} 1589 1590int32_t 1591snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req) 1592{ 1593 uint32_t i; 1594 1595 for (i = 0; i < req->nbindings; i++) { 1596 if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var) 1597 == 0) 1598 return (0); 1599 1600 if (resp->version != SNMP_V1 && resp->bindings[i].syntax == 1601 SNMP_SYNTAX_ENDOFMIBVIEW) 1602 return (0); 1603 } 1604 1605 return (1); 1606} 1607 1608/* 1609 * Should be called to check a response to get/getnext/getbulk. 1610 */ 1611int32_t 1612snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req) 1613{ 1614 if (resp == NULL || req == NULL) 1615 return (-2); 1616 1617 if (resp->version != req->version) { 1618 warnx("Response has wrong version"); 1619 return (-1); 1620 } 1621 1622 if (resp->error_status == SNMP_ERR_NOSUCHNAME) { 1623 warnx("Error - No Such Name"); 1624 return (0); 1625 } 1626 1627 if (resp->error_status != SNMP_ERR_NOERROR) { 1628 warnx("Error %d in response", resp->error_status); 1629 return (-1); 1630 } 1631 1632 if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){ 1633 warnx("Bad number of bindings in response"); 1634 return (-1); 1635 } 1636 1637 switch (req->type) { 1638 case SNMP_PDU_GET: 1639 return (snmp_parse_get_resp(resp,req)); 1640 case SNMP_PDU_GETBULK: 1641 return (snmp_parse_getbulk_resp(resp,req)); 1642 case SNMP_PDU_GETNEXT: 1643 return (snmp_parse_getnext_resp(resp,req)); 1644 default: 1645 /* NOTREACHED */ 1646 break; 1647 } 1648 1649 return (-2); 1650} 1651 1652static void 1653snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc, 1654 uint32_t len, uint8_t *octets) 1655{ 1656 char *buf; 1657 1658 if (len == 0 || octets == NULL) 1659 return; 1660 1661 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1662 fprintf(stdout, "%s : ", 1663 syntax_strings[SNMP_SYNTAX_OCTETSTRING].str); 1664 1665 if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) { 1666 fprintf(stdout, "%s", buf); 1667 free(buf); 1668 } 1669} 1670 1671static void 1672snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc, 1673 struct asn_oid *oid) 1674{ 1675 uint32_t i; 1676 uint8_t *s; 1677 1678 if ((s = malloc(oid->subs[0] + 1)) == NULL) 1679 syslog(LOG_ERR, "malloc failed - %s", strerror(errno)); 1680 else { 1681 for (i = 0; i < oid->subs[0]; i++) 1682 s[i] = (u_char) (oid->subs[i + 1]); 1683 1684 snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s); 1685 free(s); 1686 } 1687} 1688 1689/* 1690 * Check and output syntax type and value. 1691 */ 1692static void 1693snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid) 1694{ 1695 char oid_string[ASN_OIDSTRLEN]; 1696 struct snmp_object obj; 1697 1698 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1699 fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str); 1700 1701 if(!ISSET_NUMERIC(snmptoolctx)) { 1702 memset(&obj, 0, sizeof(struct snmp_object)); 1703 asn_append_oid(&(obj.val.var), oid); 1704 1705 if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0) 1706 fprintf(stdout, "%s" , obj.info->string); 1707 else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0) 1708 fprintf(stdout, "%s" , obj.info->string); 1709 else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0) 1710 fprintf(stdout, "%s" , obj.info->string); 1711 else { 1712 (void) asn_oid2str_r(oid, oid_string); 1713 fprintf(stdout, "%s", oid_string); 1714 } 1715 } else { 1716 (void) asn_oid2str_r(oid, oid_string); 1717 fprintf(stdout, "%s", oid_string); 1718 } 1719} 1720 1721static void 1722snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums, 1723 int32_t int_val) 1724{ 1725 char *string; 1726 1727 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1728 fprintf(stdout, "%s : ", 1729 syntax_strings[SNMP_SYNTAX_INTEGER].str); 1730 1731 if (enums != NULL && (string = enum_string_lookup(enums, int_val)) 1732 != NULL) 1733 fprintf(stdout, "%s", string); 1734 else 1735 fprintf(stdout, "%d", int_val); 1736} 1737 1738static void 1739snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip) 1740{ 1741 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1742 fprintf(stdout, "%s : ", 1743 syntax_strings[SNMP_SYNTAX_IPADDRESS].str); 1744 1745 fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); 1746} 1747 1748static void 1749snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter) 1750{ 1751 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1752 fprintf(stdout, "%s : ", 1753 syntax_strings[SNMP_SYNTAX_COUNTER].str); 1754 1755 fprintf(stdout, "%u", counter); 1756} 1757 1758static void 1759snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge) 1760{ 1761 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1762 fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str); 1763 1764 fprintf(stdout, "%u", gauge); 1765} 1766 1767static void 1768snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks) 1769{ 1770 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1771 fprintf(stdout, "%s : ", 1772 syntax_strings[SNMP_SYNTAX_TIMETICKS].str); 1773 1774 fprintf(stdout, "%u", ticks); 1775} 1776 1777static void 1778snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64) 1779{ 1780 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) 1781 fprintf(stdout, "%s : ", 1782 syntax_strings[SNMP_SYNTAX_COUNTER64].str); 1783 1784 fprintf(stdout,"%ju", counter64); 1785} 1786 1787int32_t 1788snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val, 1789 struct snmp_oid2str *entry) 1790{ 1791 if (val == NULL) 1792 return (-1); 1793 1794 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) 1795 fprintf(stdout, " = "); 1796 1797 switch (val->syntax) { 1798 case SNMP_SYNTAX_INTEGER: 1799 if (entry != NULL) 1800 snmp_output_int(snmptoolctx, entry->snmp_enum, 1801 val->v.integer); 1802 else 1803 snmp_output_int(snmptoolctx, NULL, val->v.integer); 1804 break; 1805 1806 case SNMP_SYNTAX_OCTETSTRING: 1807 if (entry != NULL) 1808 snmp_output_octetstring(snmptoolctx, entry->tc, 1809 val->v.octetstring.len, val->v.octetstring.octets); 1810 else 1811 snmp_output_octetstring(snmptoolctx, SNMP_STRING, 1812 val->v.octetstring.len, val->v.octetstring.octets); 1813 break; 1814 1815 case SNMP_SYNTAX_OID: 1816 snmp_output_oid_value(snmptoolctx, &(val->v.oid)); 1817 break; 1818 1819 case SNMP_SYNTAX_IPADDRESS: 1820 snmp_output_ipaddress(snmptoolctx, val->v.ipaddress); 1821 break; 1822 1823 case SNMP_SYNTAX_COUNTER: 1824 snmp_output_counter(snmptoolctx, val->v.uint32); 1825 break; 1826 1827 case SNMP_SYNTAX_GAUGE: 1828 snmp_output_gauge(snmptoolctx, val->v.uint32); 1829 break; 1830 1831 case SNMP_SYNTAX_TIMETICKS: 1832 snmp_output_ticks(snmptoolctx, val->v.uint32); 1833 break; 1834 1835 case SNMP_SYNTAX_COUNTER64: 1836 snmp_output_counter64(snmptoolctx, val->v.counter64); 1837 break; 1838 1839 case SNMP_SYNTAX_NOSUCHOBJECT: 1840 fprintf(stdout, "No Such Object\n"); 1841 return (val->syntax); 1842 1843 case SNMP_SYNTAX_NOSUCHINSTANCE: 1844 fprintf(stdout, "No Such Instance\n"); 1845 return (val->syntax); 1846 1847 case SNMP_SYNTAX_ENDOFMIBVIEW: 1848 fprintf(stdout, "End of Mib View\n"); 1849 return (val->syntax); 1850 1851 case SNMP_SYNTAX_NULL: 1852 /* NOTREACHED */ 1853 fprintf(stdout, "agent returned NULL Syntax\n"); 1854 return (val->syntax); 1855 1856 default: 1857 /* NOTREACHED - If here - then all went completely wrong. */ 1858 fprintf(stdout, "agent returned unknown syntax\n"); 1859 return (-1); 1860 } 1861 1862 fprintf(stdout, "\n"); 1863 1864 return (0); 1865} 1866 1867static int32_t 1868snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj, 1869 struct snmp_value *val) 1870{ 1871 int32_t rc; 1872 asn_subid_t suboid; 1873 1874 if (obj == NULL || val == NULL) 1875 return (-1); 1876 1877 if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID) 1878 return (-1); 1879 1880 memset(obj, 0, sizeof(struct snmp_object)); 1881 asn_append_oid(&(obj->val.var), &(val->var)); 1882 obj->val.syntax = val->syntax; 1883 1884 if (obj->val.syntax > 0) 1885 rc = snmp_lookup_leafstring(snmptoolctx, obj); 1886 else 1887 rc = snmp_lookup_nonleaf_string(snmptoolctx, obj); 1888 1889 (void) snmp_suboid_append(&(val->var), suboid); 1890 (void) snmp_suboid_append(&(obj->val.var), suboid); 1891 1892 return (rc); 1893} 1894 1895static int32_t 1896snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx, 1897 struct asn_oid *oid) 1898{ 1899 uint8_t ip[4]; 1900 uint32_t bytes = 1; 1901 uint64_t cnt64; 1902 struct asn_oid temp, out; 1903 1904 if (oid->len < bytes) 1905 return (-1); 1906 1907 memset(&temp, 0, sizeof(struct asn_oid)); 1908 asn_append_oid(&temp, oid); 1909 1910 switch (stx->syntax) { 1911 case SNMP_SYNTAX_INTEGER: 1912 snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]); 1913 break; 1914 1915 case SNMP_SYNTAX_OCTETSTRING: 1916 if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] > 1917 ASN_MAXOCTETSTRING)) 1918 return (-1); 1919 snmp_output_octetindex(snmptoolctx, stx->tc, &temp); 1920 bytes += temp.subs[0]; 1921 break; 1922 1923 case SNMP_SYNTAX_OID: 1924 if ((temp.subs[0] > temp.len -1) || (temp.subs[0] > 1925 ASN_MAXOIDLEN)) 1926 return (-1); 1927 1928 bytes += temp.subs[0]; 1929 memset(&out, 0, sizeof(struct asn_oid)); 1930 asn_slice_oid(&out, &temp, 1, bytes); 1931 snmp_output_oid_value(snmptoolctx, &out); 1932 break; 1933 1934 case SNMP_SYNTAX_IPADDRESS: 1935 if (temp.len < 4) 1936 return (-1); 1937 for (bytes = 0; bytes < 4; bytes++) 1938 ip[bytes] = temp.subs[bytes]; 1939 1940 snmp_output_ipaddress(snmptoolctx, ip); 1941 bytes = 4; 1942 break; 1943 1944 case SNMP_SYNTAX_COUNTER: 1945 snmp_output_counter(snmptoolctx, temp.subs[0]); 1946 break; 1947 1948 case SNMP_SYNTAX_GAUGE: 1949 snmp_output_gauge(snmptoolctx, temp.subs[0]); 1950 break; 1951 1952 case SNMP_SYNTAX_TIMETICKS: 1953 snmp_output_ticks(snmptoolctx, temp.subs[0]); 1954 break; 1955 1956 case SNMP_SYNTAX_COUNTER64: 1957 if (oid->len < 2) 1958 return (-1); 1959 bytes = 2; 1960 memcpy(&cnt64, temp.subs, bytes); 1961 snmp_output_counter64(snmptoolctx, cnt64); 1962 break; 1963 1964 default: 1965 return (-1); 1966 } 1967 1968 return (bytes); 1969} 1970 1971static int32_t 1972snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o) 1973{ 1974 int32_t i, first, len; 1975 struct asn_oid oid; 1976 struct index *temp; 1977 1978 if (ISSET_NUMERIC(snmptoolctx)) 1979 return (-1); 1980 1981 if (o->info->table_idx == NULL) { 1982 fprintf(stdout,"%s.%d", o->info->string, 1983 o->val.var.subs[o->val.var.len - 1]); 1984 return (1); 1985 } 1986 1987 fprintf(stdout,"%s[", o->info->string); 1988 memset(&oid, 0, sizeof(struct asn_oid)); 1989 1990 len = 1; 1991 asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len), 1992 o->val.var.len); 1993 1994 first = 1; 1995 STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) { 1996 if(first) 1997 first = 0; 1998 else 1999 fprintf(stdout, ", "); 2000 if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0) 2001 break; 2002 len += i; 2003 memset(&oid, 0, sizeof(struct asn_oid)); 2004 asn_slice_oid(&oid, &(o->val.var), 2005 (o->info->table_idx->var.len + len), o->val.var.len + 1); 2006 } 2007 2008 fprintf(stdout,"]"); 2009 return (1); 2010} 2011 2012void 2013snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu) 2014{ 2015 char buf[ASN_OIDSTRLEN]; 2016 struct snmp_object object; 2017 2018 if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) { 2019 fprintf(stdout,"Invalid error index in PDU\n"); 2020 return; 2021 } 2022 2023 fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost, 2024 snmp_client.cport); 2025 2026 if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object, 2027 &(pdu->bindings[pdu->error_index - 1])) > 0)) 2028 snmp_output_object(snmptoolctx, &object); 2029 else { 2030 asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf); 2031 fprintf(stdout,"%s", buf); 2032 } 2033 2034 fprintf(stdout," caused error - "); 2035 if ((pdu->error_status > 0) && (pdu->error_status <= 2036 SNMP_ERR_INCONS_NAME)) 2037 fprintf(stdout, "%s\n", error_strings[pdu->error_status].str); 2038 else 2039 fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str); 2040} 2041 2042int32_t 2043snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu, 2044 struct asn_oid *root) 2045{ 2046 int32_t error; 2047 char p[ASN_OIDSTRLEN]; 2048 uint32_t i; 2049 struct snmp_object object; 2050 2051 i = error = 0; 2052 while (i < pdu->nbindings) { 2053 if (root != NULL && !(asn_is_suboid(root, 2054 &(pdu->bindings[i].var)))) 2055 break; 2056 2057 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) { 2058 if (!ISSET_NUMERIC(snmptoolctx) && 2059 (snmp_fill_object(snmptoolctx, &object, 2060 &(pdu->bindings[i])) > 0)) 2061 snmp_output_object(snmptoolctx, &object); 2062 else { 2063 asn_oid2str_r(&(pdu->bindings[i].var), p); 2064 fprintf(stdout, "%s", p); 2065 } 2066 } 2067 error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info); 2068 i++; 2069 } 2070 2071 if (error) 2072 return (-1); 2073 2074 return (i); 2075} 2076 2077void 2078snmp_output_engine(void) 2079{ 2080 uint32_t i; 2081 char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2]; 2082 2083 cptr = engine; 2084 for (i = 0; i < snmp_client.engine.engine_len; i++) 2085 cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]); 2086 *cptr++ = '\0'; 2087 2088 fprintf(stdout, "Engine ID 0x%s\n", engine); 2089 fprintf(stdout, "Boots : %u\t\tTime : %d\n", 2090 snmp_client.engine.engine_boots, 2091 snmp_client.engine.engine_time); 2092} 2093 2094void 2095snmp_output_keys(void) 2096{ 2097 uint32_t i, keylen = 0; 2098 char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2]; 2099 2100 fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name); 2101 if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) { 2102 fprintf(stdout, "MD5 : 0x"); 2103 keylen = SNMP_AUTH_HMACMD5_KEY_SIZ; 2104 } else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) { 2105 fprintf(stdout, "SHA : 0x"); 2106 keylen = SNMP_AUTH_HMACSHA_KEY_SIZ; 2107 } 2108 if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) { 2109 cptr = extkey; 2110 for (i = 0; i < keylen; i++) 2111 cptr += sprintf(cptr, "%.2x", 2112 snmp_client.user.auth_key[i]); 2113 *cptr++ = '\0'; 2114 fprintf(stdout, "%s\n", extkey); 2115 } 2116 2117 if (snmp_client.user.priv_proto == SNMP_PRIV_DES) { 2118 fprintf(stdout, "DES : 0x"); 2119 keylen = SNMP_PRIV_DES_KEY_SIZ; 2120 } else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) { 2121 fprintf(stdout, "AES : 0x"); 2122 keylen = SNMP_PRIV_AES_KEY_SIZ; 2123 } 2124 if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) { 2125 cptr = extkey; 2126 for (i = 0; i < keylen; i++) 2127 cptr += sprintf(cptr, "%.2x", 2128 snmp_client.user.priv_key[i]); 2129 *cptr++ = '\0'; 2130 fprintf(stdout, "%s\n", extkey); 2131 } 2132} 2133