1/* 2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 3 * John Robert LoVerso. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * 28 * This implementation has been influenced by the CMU SNMP release, 29 * by Steve Waldbusser. However, this shares no code with that system. 30 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. 31 * Earlier forms of this implementation were derived and/or inspired by an 32 * awk script originally written by C. Philip Wood of LANL (but later 33 * heavily modified by John Robert LoVerso). The copyright notice for 34 * that work is preserved below, even though it may not rightly apply 35 * to this file. 36 * 37 * Support for SNMPv2c/SNMPv3 and the ability to link the module against 38 * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999. 39 * 40 * This started out as a very simple program, but the incremental decoding 41 * (into the BE structure) complicated things. 42 * 43 # Los Alamos National Laboratory 44 # 45 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 46 # This software was produced under a U.S. Government contract 47 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is 48 # operated by the University of California for the U.S. Department 49 # of Energy. The U.S. Government is licensed to use, reproduce, 50 # and distribute this software. Permission is granted to the 51 # public to copy and use this software without charge, provided 52 # that this Notice and any statement of authorship are reproduced 53 # on all copies. Neither the Government nor the University makes 54 # any warranty, express or implied, or assumes any liability or 55 # responsibility for the use of this software. 56 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90 57 */ 58 59#ifndef lint 60static const char rcsid[] _U_ = 61 "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.64 2005-05-06 07:56:53 guy Exp $ (LBL)"; 62#endif 63 64#ifdef HAVE_CONFIG_H 65#include "config.h" 66#endif 67 68#include <tcpdump-stdinc.h> 69 70#include <stdio.h> 71#include <string.h> 72 73#ifdef HAVE_SMI_H 74#include <smi.h> 75#endif 76 77#include "interface.h" 78#include "addrtoname.h" 79 80#undef OPAQUE /* defined in <wingdi.h> */ 81 82/* 83 * Universal ASN.1 types 84 * (we only care about the tag values for those allowed in the Internet SMI) 85 */ 86const char *Universal[] = { 87 "U-0", 88 "Boolean", 89 "Integer", 90#define INTEGER 2 91 "Bitstring", 92 "String", 93#define STRING 4 94 "Null", 95#define ASN_NULL 5 96 "ObjID", 97#define OBJECTID 6 98 "ObjectDes", 99 "U-8","U-9","U-10","U-11", /* 8-11 */ 100 "U-12","U-13","U-14","U-15", /* 12-15 */ 101 "Sequence", 102#define SEQUENCE 16 103 "Set" 104}; 105 106/* 107 * Application-wide ASN.1 types from the Internet SMI and their tags 108 */ 109const char *Application[] = { 110 "IpAddress", 111#define IPADDR 0 112 "Counter", 113#define COUNTER 1 114 "Gauge", 115#define GAUGE 2 116 "TimeTicks", 117#define TIMETICKS 3 118 "Opaque", 119#define OPAQUE 4 120 "C-5", 121 "Counter64" 122#define COUNTER64 6 123}; 124 125/* 126 * Context-specific ASN.1 types for the SNMP PDUs and their tags 127 */ 128const char *Context[] = { 129 "GetRequest", 130#define GETREQ 0 131 "GetNextRequest", 132#define GETNEXTREQ 1 133 "GetResponse", 134#define GETRESP 2 135 "SetRequest", 136#define SETREQ 3 137 "Trap", 138#define TRAP 4 139 "GetBulk", 140#define GETBULKREQ 5 141 "Inform", 142#define INFORMREQ 6 143 "V2Trap", 144#define V2TRAP 7 145 "Report" 146#define REPORT 8 147}; 148 149#define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ) 150#define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ) 151#define WRITE_CLASS(x) (x == SETREQ) 152#define RESPONSE_CLASS(x) (x == GETRESP) 153#define INTERNAL_CLASS(x) (x == REPORT) 154 155/* 156 * Context-specific ASN.1 types for the SNMP Exceptions and their tags 157 */ 158const char *Exceptions[] = { 159 "noSuchObject", 160#define NOSUCHOBJECT 0 161 "noSuchInstance", 162#define NOSUCHINSTANCE 1 163 "endOfMibView", 164#define ENDOFMIBVIEW 2 165}; 166 167/* 168 * Private ASN.1 types 169 * The Internet SMI does not specify any 170 */ 171const char *Private[] = { 172 "P-0" 173}; 174 175/* 176 * error-status values for any SNMP PDU 177 */ 178const char *ErrorStatus[] = { 179 "noError", 180 "tooBig", 181 "noSuchName", 182 "badValue", 183 "readOnly", 184 "genErr", 185 "noAccess", 186 "wrongType", 187 "wrongLength", 188 "wrongEncoding", 189 "wrongValue", 190 "noCreation", 191 "inconsistentValue", 192 "resourceUnavailable", 193 "commitFailed", 194 "undoFailed", 195 "authorizationError", 196 "notWritable", 197 "inconsistentName" 198}; 199#define DECODE_ErrorStatus(e) \ 200 ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ 201 ? ErrorStatus[e] \ 202 : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf)) 203 204/* 205 * generic-trap values in the SNMP Trap-PDU 206 */ 207const char *GenericTrap[] = { 208 "coldStart", 209 "warmStart", 210 "linkDown", 211 "linkUp", 212 "authenticationFailure", 213 "egpNeighborLoss", 214 "enterpriseSpecific" 215#define GT_ENTERPRISE 6 216}; 217#define DECODE_GenericTrap(t) \ 218 ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ 219 ? GenericTrap[t] \ 220 : (snprintf(buf, sizeof(buf), "gt=%d", t), buf)) 221 222/* 223 * ASN.1 type class table 224 * Ties together the preceding Universal, Application, Context, and Private 225 * type definitions. 226 */ 227#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ 228struct { 229 const char *name; 230 const char **Id; 231 int numIDs; 232 } Class[] = { 233 defineCLASS(Universal), 234#define UNIVERSAL 0 235 defineCLASS(Application), 236#define APPLICATION 1 237 defineCLASS(Context), 238#define CONTEXT 2 239 defineCLASS(Private), 240#define PRIVATE 3 241 defineCLASS(Exceptions), 242#define EXCEPTIONS 4 243}; 244 245/* 246 * defined forms for ASN.1 types 247 */ 248const char *Form[] = { 249 "Primitive", 250#define PRIMITIVE 0 251 "Constructed", 252#define CONSTRUCTED 1 253}; 254 255/* 256 * A structure for the OID tree for the compiled-in MIB. 257 * This is stored as a general-order tree. 258 */ 259struct obj { 260 const char *desc; /* name of object */ 261 u_char oid; /* sub-id following parent */ 262 u_char type; /* object type (unused) */ 263 struct obj *child, *next; /* child and next sibling pointers */ 264} *objp = NULL; 265 266/* 267 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding 268 * RFC-1156 format files into "makemib". "mib.h" MUST define at least 269 * a value for `mibroot'. 270 * 271 * In particular, this is gross, as this is including initialized structures, 272 * and by right shouldn't be an "include" file. 273 */ 274#include "mib.h" 275 276/* 277 * This defines a list of OIDs which will be abbreviated on output. 278 * Currently, this includes the prefixes for the Internet MIB, the 279 * private enterprises tree, and the experimental tree. 280 */ 281struct obj_abrev { 282 const char *prefix; /* prefix for this abrev */ 283 struct obj *node; /* pointer into object table */ 284 const char *oid; /* ASN.1 encoded OID */ 285} obj_abrev_list[] = { 286#ifndef NO_ABREV_MIB 287 /* .iso.org.dod.internet.mgmt.mib */ 288 { "", &_mib_obj, "\53\6\1\2\1" }, 289#endif 290#ifndef NO_ABREV_ENTER 291 /* .iso.org.dod.internet.private.enterprises */ 292 { "E:", &_enterprises_obj, "\53\6\1\4\1" }, 293#endif 294#ifndef NO_ABREV_EXPERI 295 /* .iso.org.dod.internet.experimental */ 296 { "X:", &_experimental_obj, "\53\6\1\3" }, 297#endif 298#ifndef NO_ABBREV_SNMPMODS 299 /* .iso.org.dod.internet.snmpV2.snmpModules */ 300 { "S:", &_snmpModules_obj, "\53\6\1\6\3" }, 301#endif 302 { 0,0,0 } 303}; 304 305/* 306 * This is used in the OID print routine to walk down the object tree 307 * rooted at `mibroot'. 308 */ 309#define OBJ_PRINT(o, suppressdot) \ 310{ \ 311 if (objp) { \ 312 do { \ 313 if ((o) == objp->oid) \ 314 break; \ 315 } while ((objp = objp->next) != NULL); \ 316 } \ 317 if (objp) { \ 318 printf(suppressdot?"%s":".%s", objp->desc); \ 319 objp = objp->child; \ 320 } else \ 321 printf(suppressdot?"%u":".%u", (o)); \ 322} 323 324/* 325 * This is the definition for the Any-Data-Type storage used purely for 326 * temporary internal representation while decoding an ASN.1 data stream. 327 */ 328struct be { 329 u_int32_t asnlen; 330 union { 331 caddr_t raw; 332 int32_t integer; 333 u_int32_t uns; 334 const u_char *str; 335 struct { 336 u_int32_t high; 337 u_int32_t low; 338 } uns64; 339 } data; 340 u_short id; 341 u_char form, class; /* tag info */ 342 u_char type; 343#define BE_ANY 255 344#define BE_NONE 0 345#define BE_NULL 1 346#define BE_OCTET 2 347#define BE_OID 3 348#define BE_INT 4 349#define BE_UNS 5 350#define BE_STR 6 351#define BE_SEQ 7 352#define BE_INETADDR 8 353#define BE_PDU 9 354#define BE_UNS64 10 355#define BE_NOSUCHOBJECT 128 356#define BE_NOSUCHINST 129 357#define BE_ENDOFMIBVIEW 130 358}; 359 360/* 361 * SNMP versions recognized by this module 362 */ 363const char *SnmpVersion[] = { 364 "SNMPv1", 365#define SNMP_VERSION_1 0 366 "SNMPv2c", 367#define SNMP_VERSION_2 1 368 "SNMPv2u", 369#define SNMP_VERSION_2U 2 370 "SNMPv3" 371#define SNMP_VERSION_3 3 372}; 373 374/* 375 * Defaults for SNMP PDU components 376 */ 377#define DEF_COMMUNITY "public" 378 379/* 380 * constants for ASN.1 decoding 381 */ 382#define OIDMUX 40 383#define ASNLEN_INETADDR 4 384#define ASN_SHIFT7 7 385#define ASN_SHIFT8 8 386#define ASN_BIT8 0x80 387#define ASN_LONGLEN 0x80 388 389#define ASN_ID_BITS 0x1f 390#define ASN_FORM_BITS 0x20 391#define ASN_FORM_SHIFT 5 392#define ASN_CLASS_BITS 0xc0 393#define ASN_CLASS_SHIFT 6 394 395#define ASN_ID_EXT 0x1f /* extension ID in tag field */ 396 397/* 398 * This decodes the next ASN.1 object in the stream pointed to by "p" 399 * (and of real-length "len") and stores the intermediate data in the 400 * provided BE object. 401 * 402 * This returns -l if it fails (i.e., the ASN.1 stream is not valid). 403 * O/w, this returns the number of bytes parsed from "p". 404 */ 405static int 406asn1_parse(register const u_char *p, u_int len, struct be *elem) 407{ 408 u_char form, class, id; 409 int i, hdr; 410 411 elem->asnlen = 0; 412 elem->type = BE_ANY; 413 if (len < 1) { 414 fputs("[nothing to parse]", stdout); 415 return -1; 416 } 417 TCHECK(*p); 418 419 /* 420 * it would be nice to use a bit field, but you can't depend on them. 421 * +---+---+---+---+---+---+---+---+ 422 * + class |frm| id | 423 * +---+---+---+---+---+---+---+---+ 424 * 7 6 5 4 3 2 1 0 425 */ 426 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ 427#ifdef notdef 428 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ 429 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ 430 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ 431#else 432 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; 433 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; 434#endif 435 elem->form = form; 436 elem->class = class; 437 elem->id = id; 438 p++; len--; hdr = 1; 439 /* extended tag field */ 440 if (id == ASN_ID_EXT) { 441 /* 442 * The ID follows, as a sequence of octets with the 443 * 8th bit set and the remaining 7 bits being 444 * the next 7 bits of the value, terminated with 445 * an octet with the 8th bit not set. 446 * 447 * First, assemble all the octets with the 8th 448 * bit set. XXX - this doesn't handle a value 449 * that won't fit in 32 bits. 450 */ 451 for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) { 452 if (len < 1) { 453 fputs("[Xtagfield?]", stdout); 454 return -1; 455 } 456 TCHECK(*p); 457 id = (id << 7) | (*p & ~ASN_BIT8); 458 } 459 if (len < 1) { 460 fputs("[Xtagfield?]", stdout); 461 return -1; 462 } 463 TCHECK(*p); 464 elem->id = id = (id << 7) | *p; 465 --len; 466 ++hdr; 467 ++p; 468 } 469 if (len < 1) { 470 fputs("[no asnlen]", stdout); 471 return -1; 472 } 473 TCHECK(*p); 474 elem->asnlen = *p; 475 p++; len--; hdr++; 476 if (elem->asnlen & ASN_BIT8) { 477 u_int32_t noct = elem->asnlen % ASN_BIT8; 478 elem->asnlen = 0; 479 if (len < noct) { 480 printf("[asnlen? %d<%d]", len, noct); 481 return -1; 482 } 483 TCHECK2(*p, noct); 484 for (; noct-- > 0; len--, hdr++) 485 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; 486 } 487 if (len < elem->asnlen) { 488 printf("[len%d<asnlen%u]", len, elem->asnlen); 489 return -1; 490 } 491 if (form >= sizeof(Form)/sizeof(Form[0])) { 492 printf("[form?%d]", form); 493 return -1; 494 } 495 if (class >= sizeof(Class)/sizeof(Class[0])) { 496 printf("[class?%c/%d]", *Form[form], class); 497 return -1; 498 } 499 if ((int)id >= Class[class].numIDs) { 500 printf("[id?%c/%s/%d]", *Form[form], Class[class].name, id); 501 return -1; 502 } 503 504 switch (form) { 505 case PRIMITIVE: 506 switch (class) { 507 case UNIVERSAL: 508 switch (id) { 509 case STRING: 510 elem->type = BE_STR; 511 elem->data.str = p; 512 break; 513 514 case INTEGER: { 515 register int32_t data; 516 elem->type = BE_INT; 517 data = 0; 518 519 TCHECK2(*p, elem->asnlen); 520 if (*p & ASN_BIT8) /* negative */ 521 data = -1; 522 for (i = elem->asnlen; i-- > 0; p++) 523 data = (data << ASN_SHIFT8) | *p; 524 elem->data.integer = data; 525 break; 526 } 527 528 case OBJECTID: 529 elem->type = BE_OID; 530 elem->data.raw = (caddr_t)p; 531 break; 532 533 case ASN_NULL: 534 elem->type = BE_NULL; 535 elem->data.raw = NULL; 536 break; 537 538 default: 539 elem->type = BE_OCTET; 540 elem->data.raw = (caddr_t)p; 541 printf("[P/U/%s]", 542 Class[class].Id[id]); 543 break; 544 } 545 break; 546 547 case APPLICATION: 548 switch (id) { 549 case IPADDR: 550 elem->type = BE_INETADDR; 551 elem->data.raw = (caddr_t)p; 552 break; 553 554 case COUNTER: 555 case GAUGE: 556 case TIMETICKS: { 557 register u_int32_t data; 558 TCHECK2(*p, elem->asnlen); 559 elem->type = BE_UNS; 560 data = 0; 561 for (i = elem->asnlen; i-- > 0; p++) 562 data = (data << 8) + *p; 563 elem->data.uns = data; 564 break; 565 } 566 567 case COUNTER64: { 568 register u_int32_t high, low; 569 TCHECK2(*p, elem->asnlen); 570 elem->type = BE_UNS64; 571 high = 0, low = 0; 572 for (i = elem->asnlen; i-- > 0; p++) { 573 high = (high << 8) | 574 ((low & 0xFF000000) >> 24); 575 low = (low << 8) | *p; 576 } 577 elem->data.uns64.high = high; 578 elem->data.uns64.low = low; 579 break; 580 } 581 582 default: 583 elem->type = BE_OCTET; 584 elem->data.raw = (caddr_t)p; 585 printf("[P/A/%s]", 586 Class[class].Id[id]); 587 break; 588 } 589 break; 590 591 case CONTEXT: 592 switch (id) { 593 case NOSUCHOBJECT: 594 elem->type = BE_NOSUCHOBJECT; 595 elem->data.raw = NULL; 596 break; 597 598 case NOSUCHINSTANCE: 599 elem->type = BE_NOSUCHINST; 600 elem->data.raw = NULL; 601 break; 602 603 case ENDOFMIBVIEW: 604 elem->type = BE_ENDOFMIBVIEW; 605 elem->data.raw = NULL; 606 break; 607 } 608 break; 609 610 default: 611 printf("[P/%s/%s]", 612 Class[class].name, Class[class].Id[id]); 613 TCHECK2(*p, elem->asnlen); 614 elem->type = BE_OCTET; 615 elem->data.raw = (caddr_t)p; 616 break; 617 } 618 break; 619 620 case CONSTRUCTED: 621 switch (class) { 622 case UNIVERSAL: 623 switch (id) { 624 case SEQUENCE: 625 elem->type = BE_SEQ; 626 elem->data.raw = (caddr_t)p; 627 break; 628 629 default: 630 elem->type = BE_OCTET; 631 elem->data.raw = (caddr_t)p; 632 printf("C/U/%s", Class[class].Id[id]); 633 break; 634 } 635 break; 636 637 case CONTEXT: 638 elem->type = BE_PDU; 639 elem->data.raw = (caddr_t)p; 640 break; 641 642 default: 643 elem->type = BE_OCTET; 644 elem->data.raw = (caddr_t)p; 645 printf("C/%s/%s", 646 Class[class].name, Class[class].Id[id]); 647 break; 648 } 649 break; 650 } 651 p += elem->asnlen; 652 len -= elem->asnlen; 653 return elem->asnlen + hdr; 654 655trunc: 656 fputs("[|snmp]", stdout); 657 return -1; 658} 659 660/* 661 * Display the ASN.1 object represented by the BE object. 662 * This used to be an integral part of asn1_parse() before the intermediate 663 * BE form was added. 664 */ 665static int 666asn1_print(struct be *elem) 667{ 668 u_char *p = (u_char *)elem->data.raw; 669 u_int32_t asnlen = elem->asnlen; 670 u_int32_t i; 671 672 switch (elem->type) { 673 674 case BE_OCTET: 675 TCHECK2(*p, asnlen); 676 for (i = asnlen; i-- > 0; p++) 677 printf("_%.2x", *p); 678 break; 679 680 case BE_NULL: 681 break; 682 683 case BE_OID: { 684 int o = 0, first = -1, i = asnlen; 685 686 if (!sflag && !nflag && asnlen > 2) { 687 struct obj_abrev *a = &obj_abrev_list[0]; 688 size_t a_len = strlen(a->oid); 689 for (; a->node; a++) { 690 TCHECK2(*p, a_len); 691 if (memcmp(a->oid, (char *)p, a_len) == 0) { 692 objp = a->node->child; 693 i -= strlen(a->oid); 694 p += strlen(a->oid); 695 fputs(a->prefix, stdout); 696 first = 1; 697 break; 698 } 699 } 700 } 701 702 for (; !sflag && i-- > 0; p++) { 703 TCHECK(*p); 704 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 705 if (*p & ASN_LONGLEN) 706 continue; 707 708 /* 709 * first subitem encodes two items with 1st*OIDMUX+2nd 710 * (see X.690:1997 clause 8.19 for the details) 711 */ 712 if (first < 0) { 713 int s; 714 if (!nflag) 715 objp = mibroot; 716 first = 0; 717 s = o / OIDMUX; 718 if (s > 2) s = 2; 719 OBJ_PRINT(s, first); 720 o -= s * OIDMUX; 721 } 722 OBJ_PRINT(o, first); 723 if (--first < 0) 724 first = 0; 725 o = 0; 726 } 727 break; 728 } 729 730 case BE_INT: 731 printf("%d", elem->data.integer); 732 break; 733 734 case BE_UNS: 735 printf("%u", elem->data.uns); 736 break; 737 738 case BE_UNS64: { /* idea borrowed from by Marshall Rose */ 739 double d; 740 int j, carry; 741 char *cpf, *cpl, last[6], first[30]; 742 if (elem->data.uns64.high == 0) { 743 printf("%u", elem->data.uns64.low); 744 break; 745 } 746 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */ 747 if (elem->data.uns64.high <= 0x1fffff) { 748 d += elem->data.uns64.low; 749#if 0 /*is looks illegal, but what is the intention?*/ 750 printf("%.f", d); 751#else 752 printf("%f", d); 753#endif 754 break; 755 } 756 d += (elem->data.uns64.low & 0xfffff000); 757#if 0 /*is looks illegal, but what is the intention?*/ 758 snprintf(first, sizeof(first), "%.f", d); 759#else 760 snprintf(first, sizeof(first), "%f", d); 761#endif 762 snprintf(last, sizeof(last), "%5.5d", 763 elem->data.uns64.low & 0xfff); 764 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4; 765 cpl >= last; 766 cpf--, cpl--) { 767 j = carry + (*cpf - '0') + (*cpl - '0'); 768 if (j > 9) { 769 j -= 10; 770 carry = 1; 771 } else { 772 carry = 0; 773 } 774 *cpf = j + '0'; 775 } 776 fputs(first, stdout); 777 break; 778 } 779 780 case BE_STR: { 781 register int printable = 1, first = 1; 782 const u_char *p = elem->data.str; 783 TCHECK2(*p, asnlen); 784 for (i = asnlen; printable && i-- > 0; p++) 785 printable = ND_ISPRINT(*p); 786 p = elem->data.str; 787 if (printable) { 788 putchar('"'); 789 if (fn_printn(p, asnlen, snapend)) { 790 putchar('"'); 791 goto trunc; 792 } 793 putchar('"'); 794 } else 795 for (i = asnlen; i-- > 0; p++) { 796 printf(first ? "%.2x" : "_%.2x", *p); 797 first = 0; 798 } 799 break; 800 } 801 802 case BE_SEQ: 803 printf("Seq(%u)", elem->asnlen); 804 break; 805 806 case BE_INETADDR: 807 if (asnlen != ASNLEN_INETADDR) 808 printf("[inetaddr len!=%d]", ASNLEN_INETADDR); 809 TCHECK2(*p, asnlen); 810 for (i = asnlen; i-- != 0; p++) { 811 printf((i == asnlen-1) ? "%u" : ".%u", *p); 812 } 813 break; 814 815 case BE_NOSUCHOBJECT: 816 case BE_NOSUCHINST: 817 case BE_ENDOFMIBVIEW: 818 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]); 819 break; 820 821 case BE_PDU: 822 printf("%s(%u)", 823 Class[CONTEXT].Id[elem->id], elem->asnlen); 824 break; 825 826 case BE_ANY: 827 fputs("[BE_ANY!?]", stdout); 828 break; 829 830 default: 831 fputs("[be!?]", stdout); 832 break; 833 } 834 return 0; 835 836trunc: 837 fputs("[|snmp]", stdout); 838 return -1; 839} 840 841#ifdef notdef 842/* 843 * This is a brute force ASN.1 printer: recurses to dump an entire structure. 844 * This will work for any ASN.1 stream, not just an SNMP PDU. 845 * 846 * By adding newlines and spaces at the correct places, this would print in 847 * Rose-Normal-Form. 848 * 849 * This is not currently used. 850 */ 851static void 852asn1_decode(u_char *p, u_int length) 853{ 854 struct be elem; 855 int i = 0; 856 857 while (i >= 0 && length > 0) { 858 i = asn1_parse(p, length, &elem); 859 if (i >= 0) { 860 fputs(" ", stdout); 861 if (asn1_print(&elem) < 0) 862 return; 863 if (elem.type == BE_SEQ || elem.type == BE_PDU) { 864 fputs(" {", stdout); 865 asn1_decode(elem.data.raw, elem.asnlen); 866 fputs(" }", stdout); 867 } 868 length -= i; 869 p += i; 870 } 871 } 872} 873#endif 874 875#ifdef LIBSMI 876 877struct smi2be { 878 SmiBasetype basetype; 879 int be; 880}; 881 882static struct smi2be smi2betab[] = { 883 { SMI_BASETYPE_INTEGER32, BE_INT }, 884 { SMI_BASETYPE_OCTETSTRING, BE_STR }, 885 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR }, 886 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID }, 887 { SMI_BASETYPE_UNSIGNED32, BE_UNS }, 888 { SMI_BASETYPE_INTEGER64, BE_NONE }, 889 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 }, 890 { SMI_BASETYPE_FLOAT32, BE_NONE }, 891 { SMI_BASETYPE_FLOAT64, BE_NONE }, 892 { SMI_BASETYPE_FLOAT128, BE_NONE }, 893 { SMI_BASETYPE_ENUM, BE_INT }, 894 { SMI_BASETYPE_BITS, BE_STR }, 895 { SMI_BASETYPE_UNKNOWN, BE_NONE } 896}; 897 898static int 899smi_decode_oid(struct be *elem, unsigned int *oid, 900 unsigned int oidsize, unsigned int *oidlen) 901{ 902 u_char *p = (u_char *)elem->data.raw; 903 u_int32_t asnlen = elem->asnlen; 904 int o = 0, first = -1, i = asnlen; 905 906 for (*oidlen = 0; sflag && i-- > 0; p++) { 907 TCHECK(*p); 908 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 909 if (*p & ASN_LONGLEN) 910 continue; 911 912 /* 913 * first subitem encodes two items with 1st*OIDMUX+2nd 914 * (see X.690:1997 clause 8.19 for the details) 915 */ 916 if (first < 0) { 917 first = 0; 918 if (*oidlen < oidsize) { 919 oid[*oidlen] = o / OIDMUX; 920 if (oid[*oidlen] > 2) oid[*oidlen] = 2; 921 } 922 o -= oid[*oidlen] * OIDMUX; 923 if (*oidlen < oidsize) (*oidlen)++; 924 } 925 if (*oidlen < oidsize) { 926 oid[(*oidlen)++] = o; 927 } 928 o = 0; 929 } 930 return 0; 931 932trunc: 933 fputs("[|snmp]", stdout); 934 return -1; 935} 936 937static int smi_check_type(SmiBasetype basetype, int be) 938{ 939 int i; 940 941 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) { 942 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) { 943 return 1; 944 } 945 } 946 947 return 0; 948} 949 950static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange, 951 struct be *elem) 952{ 953 int ok = 1; 954 955 switch (smiType->basetype) { 956 case SMI_BASETYPE_OBJECTIDENTIFIER: 957 case SMI_BASETYPE_OCTETSTRING: 958 if (smiRange->minValue.value.unsigned32 959 == smiRange->maxValue.value.unsigned32) { 960 ok = (elem->asnlen == smiRange->minValue.value.unsigned32); 961 } else { 962 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32 963 && elem->asnlen <= smiRange->maxValue.value.unsigned32); 964 } 965 break; 966 967 case SMI_BASETYPE_INTEGER32: 968 ok = (elem->data.integer >= smiRange->minValue.value.integer32 969 && elem->data.integer <= smiRange->maxValue.value.integer32); 970 break; 971 972 case SMI_BASETYPE_UNSIGNED32: 973 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32 974 && elem->data.uns <= smiRange->maxValue.value.unsigned32); 975 break; 976 977 case SMI_BASETYPE_UNSIGNED64: 978 /* XXX */ 979 break; 980 981 /* case SMI_BASETYPE_INTEGER64: SMIng */ 982 /* case SMI_BASETYPE_FLOAT32: SMIng */ 983 /* case SMI_BASETYPE_FLOAT64: SMIng */ 984 /* case SMI_BASETYPE_FLOAT128: SMIng */ 985 986 case SMI_BASETYPE_ENUM: 987 case SMI_BASETYPE_BITS: 988 case SMI_BASETYPE_UNKNOWN: 989 ok = 1; 990 break; 991 992 default: 993 ok = 0; 994 break; 995 } 996 997 return ok; 998} 999 1000static int smi_check_range(SmiType *smiType, struct be *elem) 1001{ 1002 SmiRange *smiRange; 1003 int ok = 1; 1004 1005 for (smiRange = smiGetFirstRange(smiType); 1006 smiRange; 1007 smiRange = smiGetNextRange(smiRange)) { 1008 1009 ok = smi_check_a_range(smiType, smiRange, elem); 1010 1011 if (ok) { 1012 break; 1013 } 1014 } 1015 1016 if (ok) { 1017 SmiType *parentType; 1018 parentType = smiGetParentType(smiType); 1019 if (parentType) { 1020 ok = smi_check_range(parentType, elem); 1021 } 1022 } 1023 1024 return ok; 1025} 1026 1027static SmiNode *smi_print_variable(struct be *elem, int *status) 1028{ 1029 unsigned int oid[128], oidlen; 1030 SmiNode *smiNode = NULL; 1031 unsigned int i; 1032 1033 *status = smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), 1034 &oidlen); 1035 if (*status < 0) 1036 return NULL; 1037 smiNode = smiGetNodeByOID(oidlen, oid); 1038 if (! smiNode) { 1039 *status = asn1_print(elem); 1040 return NULL; 1041 } 1042 if (vflag) { 1043 fputs(smiGetNodeModule(smiNode)->name, stdout); 1044 fputs("::", stdout); 1045 } 1046 fputs(smiNode->name, stdout); 1047 if (smiNode->oidlen < oidlen) { 1048 for (i = smiNode->oidlen; i < oidlen; i++) { 1049 printf(".%u", oid[i]); 1050 } 1051 } 1052 *status = 0; 1053 return smiNode; 1054} 1055 1056static int 1057smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem) 1058{ 1059 unsigned int i, oid[128], oidlen; 1060 SmiType *smiType; 1061 SmiNamedNumber *nn; 1062 int done = 0; 1063 1064 if (! smiNode || ! (smiNode->nodekind 1065 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) { 1066 return asn1_print(elem); 1067 } 1068 1069 if (elem->type == BE_NOSUCHOBJECT 1070 || elem->type == BE_NOSUCHINST 1071 || elem->type == BE_ENDOFMIBVIEW) { 1072 return asn1_print(elem); 1073 } 1074 1075 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) { 1076 fputs("[notNotifyable]", stdout); 1077 } 1078 1079 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) { 1080 fputs("[notReadable]", stdout); 1081 } 1082 1083 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) { 1084 fputs("[notWritable]", stdout); 1085 } 1086 1087 if (RESPONSE_CLASS(pduid) 1088 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) { 1089 fputs("[noAccess]", stdout); 1090 } 1091 1092 smiType = smiGetNodeType(smiNode); 1093 if (! smiType) { 1094 return asn1_print(elem); 1095 } 1096 1097 if (! smi_check_type(smiType->basetype, elem->type)) { 1098 fputs("[wrongType]", stdout); 1099 } 1100 1101 if (! smi_check_range(smiType, elem)) { 1102 fputs("[outOfRange]", stdout); 1103 } 1104 1105 /* resolve bits to named bits */ 1106 1107 /* check whether instance identifier is valid */ 1108 1109 /* apply display hints (integer, octetstring) */ 1110 1111 /* convert instance identifier to index type values */ 1112 1113 switch (elem->type) { 1114 case BE_OID: 1115 if (smiType->basetype == SMI_BASETYPE_BITS) { 1116 /* print bit labels */ 1117 } else { 1118 smi_decode_oid(elem, oid, 1119 sizeof(oid)/sizeof(unsigned int), 1120 &oidlen); 1121 smiNode = smiGetNodeByOID(oidlen, oid); 1122 if (smiNode) { 1123 if (vflag) { 1124 fputs(smiGetNodeModule(smiNode)->name, stdout); 1125 fputs("::", stdout); 1126 } 1127 fputs(smiNode->name, stdout); 1128 if (smiNode->oidlen < oidlen) { 1129 for (i = smiNode->oidlen; 1130 i < oidlen; i++) { 1131 printf(".%u", oid[i]); 1132 } 1133 } 1134 done++; 1135 } 1136 } 1137 break; 1138 1139 case BE_INT: 1140 if (smiType->basetype == SMI_BASETYPE_ENUM) { 1141 for (nn = smiGetFirstNamedNumber(smiType); 1142 nn; 1143 nn = smiGetNextNamedNumber(nn)) { 1144 if (nn->value.value.integer32 1145 == elem->data.integer) { 1146 fputs(nn->name, stdout); 1147 printf("(%d)", elem->data.integer); 1148 done++; 1149 break; 1150 } 1151 } 1152 } 1153 break; 1154 } 1155 1156 if (! done) { 1157 return asn1_print(elem); 1158 } 1159 return 0; 1160} 1161#endif 1162 1163/* 1164 * General SNMP header 1165 * SEQUENCE { 1166 * version INTEGER {version-1(0)}, 1167 * community OCTET STRING, 1168 * data ANY -- PDUs 1169 * } 1170 * PDUs for all but Trap: (see rfc1157 from page 15 on) 1171 * SEQUENCE { 1172 * request-id INTEGER, 1173 * error-status INTEGER, 1174 * error-index INTEGER, 1175 * varbindlist SEQUENCE OF 1176 * SEQUENCE { 1177 * name ObjectName, 1178 * value ObjectValue 1179 * } 1180 * } 1181 * PDU for Trap: 1182 * SEQUENCE { 1183 * enterprise OBJECT IDENTIFIER, 1184 * agent-addr NetworkAddress, 1185 * generic-trap INTEGER, 1186 * specific-trap INTEGER, 1187 * time-stamp TimeTicks, 1188 * varbindlist SEQUENCE OF 1189 * SEQUENCE { 1190 * name ObjectName, 1191 * value ObjectValue 1192 * } 1193 * } 1194 */ 1195 1196/* 1197 * Decode SNMP varBind 1198 */ 1199static void 1200varbind_print(u_char pduid, const u_char *np, u_int length) 1201{ 1202 struct be elem; 1203 int count = 0, ind; 1204#ifdef LIBSMI 1205 SmiNode *smiNode = NULL; 1206#endif 1207 int status; 1208 1209 /* Sequence of varBind */ 1210 if ((count = asn1_parse(np, length, &elem)) < 0) 1211 return; 1212 if (elem.type != BE_SEQ) { 1213 fputs("[!SEQ of varbind]", stdout); 1214 asn1_print(&elem); 1215 return; 1216 } 1217 if ((u_int)count < length) 1218 printf("[%d extra after SEQ of varbind]", length - count); 1219 /* descend */ 1220 length = elem.asnlen; 1221 np = (u_char *)elem.data.raw; 1222 1223 for (ind = 1; length > 0; ind++) { 1224 const u_char *vbend; 1225 u_int vblength; 1226 1227 fputs(" ", stdout); 1228 1229 /* Sequence */ 1230 if ((count = asn1_parse(np, length, &elem)) < 0) 1231 return; 1232 if (elem.type != BE_SEQ) { 1233 fputs("[!varbind]", stdout); 1234 asn1_print(&elem); 1235 return; 1236 } 1237 vbend = np + count; 1238 vblength = length - count; 1239 /* descend */ 1240 length = elem.asnlen; 1241 np = (u_char *)elem.data.raw; 1242 1243 /* objName (OID) */ 1244 if ((count = asn1_parse(np, length, &elem)) < 0) 1245 return; 1246 if (elem.type != BE_OID) { 1247 fputs("[objName!=OID]", stdout); 1248 asn1_print(&elem); 1249 return; 1250 } 1251#ifdef LIBSMI 1252 smiNode = smi_print_variable(&elem, &status); 1253#else 1254 status = asn1_print(&elem); 1255#endif 1256 if (status < 0) 1257 return; 1258 length -= count; 1259 np += count; 1260 1261 if (pduid != GETREQ && pduid != GETNEXTREQ 1262 && pduid != GETBULKREQ) 1263 fputs("=", stdout); 1264 1265 /* objVal (ANY) */ 1266 if ((count = asn1_parse(np, length, &elem)) < 0) 1267 return; 1268 if (pduid == GETREQ || pduid == GETNEXTREQ 1269 || pduid == GETBULKREQ) { 1270 if (elem.type != BE_NULL) { 1271 fputs("[objVal!=NULL]", stdout); 1272 if (asn1_print(&elem) < 0) 1273 return; 1274 } 1275 } else { 1276 if (elem.type != BE_NULL) { 1277#ifdef LIBSMI 1278 status = smi_print_value(smiNode, pduid, &elem); 1279#else 1280 status = asn1_print(&elem); 1281#endif 1282 } 1283 if (status < 0) 1284 return; 1285 } 1286 length = vblength; 1287 np = vbend; 1288 } 1289} 1290 1291/* 1292 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest, 1293 * GetBulk, Inform, V2Trap, and Report 1294 */ 1295static void 1296snmppdu_print(u_short pduid, const u_char *np, u_int length) 1297{ 1298 struct be elem; 1299 int count = 0, error; 1300 1301 /* reqId (Integer) */ 1302 if ((count = asn1_parse(np, length, &elem)) < 0) 1303 return; 1304 if (elem.type != BE_INT) { 1305 fputs("[reqId!=INT]", stdout); 1306 asn1_print(&elem); 1307 return; 1308 } 1309 if (vflag) 1310 printf("R=%d ", elem.data.integer); 1311 length -= count; 1312 np += count; 1313 1314 /* errorStatus (Integer) */ 1315 if ((count = asn1_parse(np, length, &elem)) < 0) 1316 return; 1317 if (elem.type != BE_INT) { 1318 fputs("[errorStatus!=INT]", stdout); 1319 asn1_print(&elem); 1320 return; 1321 } 1322 error = 0; 1323 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 1324 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 1325 && elem.data.integer != 0) { 1326 char errbuf[20]; 1327 printf("[errorStatus(%s)!=0]", 1328 DECODE_ErrorStatus(elem.data.integer)); 1329 } else if (pduid == GETBULKREQ) { 1330 printf(" N=%d", elem.data.integer); 1331 } else if (elem.data.integer != 0) { 1332 char errbuf[20]; 1333 printf(" %s", DECODE_ErrorStatus(elem.data.integer)); 1334 error = elem.data.integer; 1335 } 1336 length -= count; 1337 np += count; 1338 1339 /* errorIndex (Integer) */ 1340 if ((count = asn1_parse(np, length, &elem)) < 0) 1341 return; 1342 if (elem.type != BE_INT) { 1343 fputs("[errorIndex!=INT]", stdout); 1344 asn1_print(&elem); 1345 return; 1346 } 1347 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 1348 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 1349 && elem.data.integer != 0) 1350 printf("[errorIndex(%d)!=0]", elem.data.integer); 1351 else if (pduid == GETBULKREQ) 1352 printf(" M=%d", elem.data.integer); 1353 else if (elem.data.integer != 0) { 1354 if (!error) 1355 printf("[errorIndex(%d) w/o errorStatus]", 1356 elem.data.integer); 1357 else { 1358 printf("@%d", elem.data.integer); 1359 error = elem.data.integer; 1360 } 1361 } else if (error) { 1362 fputs("[errorIndex==0]", stdout); 1363 error = 0; 1364 } 1365 length -= count; 1366 np += count; 1367 1368 varbind_print(pduid, np, length); 1369 return; 1370} 1371 1372/* 1373 * Decode SNMP Trap PDU 1374 */ 1375static void 1376trappdu_print(const u_char *np, u_int length) 1377{ 1378 struct be elem; 1379 int count = 0, generic; 1380 1381 putchar(' '); 1382 1383 /* enterprise (oid) */ 1384 if ((count = asn1_parse(np, length, &elem)) < 0) 1385 return; 1386 if (elem.type != BE_OID) { 1387 fputs("[enterprise!=OID]", stdout); 1388 asn1_print(&elem); 1389 return; 1390 } 1391 if (asn1_print(&elem) < 0) 1392 return; 1393 length -= count; 1394 np += count; 1395 1396 putchar(' '); 1397 1398 /* agent-addr (inetaddr) */ 1399 if ((count = asn1_parse(np, length, &elem)) < 0) 1400 return; 1401 if (elem.type != BE_INETADDR) { 1402 fputs("[agent-addr!=INETADDR]", stdout); 1403 asn1_print(&elem); 1404 return; 1405 } 1406 if (asn1_print(&elem) < 0) 1407 return; 1408 length -= count; 1409 np += count; 1410 1411 /* generic-trap (Integer) */ 1412 if ((count = asn1_parse(np, length, &elem)) < 0) 1413 return; 1414 if (elem.type != BE_INT) { 1415 fputs("[generic-trap!=INT]", stdout); 1416 asn1_print(&elem); 1417 return; 1418 } 1419 generic = elem.data.integer; 1420 { 1421 char buf[20]; 1422 printf(" %s", DECODE_GenericTrap(generic)); 1423 } 1424 length -= count; 1425 np += count; 1426 1427 /* specific-trap (Integer) */ 1428 if ((count = asn1_parse(np, length, &elem)) < 0) 1429 return; 1430 if (elem.type != BE_INT) { 1431 fputs("[specific-trap!=INT]", stdout); 1432 asn1_print(&elem); 1433 return; 1434 } 1435 if (generic != GT_ENTERPRISE) { 1436 if (elem.data.integer != 0) 1437 printf("[specific-trap(%d)!=0]", elem.data.integer); 1438 } else 1439 printf(" s=%d", elem.data.integer); 1440 length -= count; 1441 np += count; 1442 1443 putchar(' '); 1444 1445 /* time-stamp (TimeTicks) */ 1446 if ((count = asn1_parse(np, length, &elem)) < 0) 1447 return; 1448 if (elem.type != BE_UNS) { /* XXX */ 1449 fputs("[time-stamp!=TIMETICKS]", stdout); 1450 asn1_print(&elem); 1451 return; 1452 } 1453 if (asn1_print(&elem) < 0) 1454 return; 1455 length -= count; 1456 np += count; 1457 1458 varbind_print (TRAP, np, length); 1459 return; 1460} 1461 1462/* 1463 * Decode arbitrary SNMP PDUs. 1464 */ 1465static void 1466pdu_print(const u_char *np, u_int length, int version) 1467{ 1468 struct be pdu; 1469 int count = 0; 1470 1471 /* PDU (Context) */ 1472 if ((count = asn1_parse(np, length, &pdu)) < 0) 1473 return; 1474 if (pdu.type != BE_PDU) { 1475 fputs("[no PDU]", stdout); 1476 return; 1477 } 1478 if ((u_int)count < length) 1479 printf("[%d extra after PDU]", length - count); 1480 if (vflag) { 1481 fputs("{ ", stdout); 1482 } 1483 if (asn1_print(&pdu) < 0) 1484 return; 1485 fputs(" ", stdout); 1486 /* descend into PDU */ 1487 length = pdu.asnlen; 1488 np = (u_char *)pdu.data.raw; 1489 1490 if (version == SNMP_VERSION_1 && 1491 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ || 1492 pdu.id == V2TRAP || pdu.id == REPORT)) { 1493 printf("[v2 PDU in v1 message]"); 1494 return; 1495 } 1496 1497 if (version == SNMP_VERSION_2 && pdu.id == TRAP) { 1498 printf("[v1 PDU in v2 message]"); 1499 return; 1500 } 1501 1502 switch (pdu.id) { 1503 case TRAP: 1504 trappdu_print(np, length); 1505 break; 1506 case GETREQ: 1507 case GETNEXTREQ: 1508 case GETRESP: 1509 case SETREQ: 1510 case GETBULKREQ: 1511 case INFORMREQ: 1512 case V2TRAP: 1513 case REPORT: 1514 snmppdu_print(pdu.id, np, length); 1515 break; 1516 } 1517 1518 if (vflag) { 1519 fputs(" } ", stdout); 1520 } 1521} 1522 1523/* 1524 * Decode a scoped SNMP PDU. 1525 */ 1526static void 1527scopedpdu_print(const u_char *np, u_int length, int version) 1528{ 1529 struct be elem; 1530 int i, count = 0; 1531 1532 /* Sequence */ 1533 if ((count = asn1_parse(np, length, &elem)) < 0) 1534 return; 1535 if (elem.type != BE_SEQ) { 1536 fputs("[!scoped PDU]", stdout); 1537 asn1_print(&elem); 1538 return; 1539 } 1540 length = elem.asnlen; 1541 np = (u_char *)elem.data.raw; 1542 1543 /* contextEngineID (OCTET STRING) */ 1544 if ((count = asn1_parse(np, length, &elem)) < 0) 1545 return; 1546 if (elem.type != BE_STR) { 1547 fputs("[contextEngineID!=STR]", stdout); 1548 asn1_print(&elem); 1549 return; 1550 } 1551 length -= count; 1552 np += count; 1553 1554 fputs("E= ", stdout); 1555 for (i = 0; i < (int)elem.asnlen; i++) { 1556 printf("0x%02X", elem.data.str[i]); 1557 } 1558 fputs(" ", stdout); 1559 1560 /* contextName (OCTET STRING) */ 1561 if ((count = asn1_parse(np, length, &elem)) < 0) 1562 return; 1563 if (elem.type != BE_STR) { 1564 fputs("[contextName!=STR]", stdout); 1565 asn1_print(&elem); 1566 return; 1567 } 1568 length -= count; 1569 np += count; 1570 1571 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1572 1573 pdu_print(np, length, version); 1574} 1575 1576/* 1577 * Decode SNMP Community Header (SNMPv1 and SNMPv2c) 1578 */ 1579static void 1580community_print(const u_char *np, u_int length, int version) 1581{ 1582 struct be elem; 1583 int count = 0; 1584 1585 /* Community (String) */ 1586 if ((count = asn1_parse(np, length, &elem)) < 0) 1587 return; 1588 if (elem.type != BE_STR) { 1589 fputs("[comm!=STR]", stdout); 1590 asn1_print(&elem); 1591 return; 1592 } 1593 /* default community */ 1594 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 && 1595 strncmp((char *)elem.data.str, DEF_COMMUNITY, 1596 sizeof(DEF_COMMUNITY) - 1) == 0)) 1597 /* ! "public" */ 1598 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1599 length -= count; 1600 np += count; 1601 1602 pdu_print(np, length, version); 1603} 1604 1605/* 1606 * Decode SNMPv3 User-based Security Message Header (SNMPv3) 1607 */ 1608static void 1609usm_print(const u_char *np, u_int length) 1610{ 1611 struct be elem; 1612 int count = 0; 1613 1614 /* Sequence */ 1615 if ((count = asn1_parse(np, length, &elem)) < 0) 1616 return; 1617 if (elem.type != BE_SEQ) { 1618 fputs("[!usm]", stdout); 1619 asn1_print(&elem); 1620 return; 1621 } 1622 length = elem.asnlen; 1623 np = (u_char *)elem.data.raw; 1624 1625 /* msgAuthoritativeEngineID (OCTET STRING) */ 1626 if ((count = asn1_parse(np, length, &elem)) < 0) 1627 return; 1628 if (elem.type != BE_STR) { 1629 fputs("[msgAuthoritativeEngineID!=STR]", stdout); 1630 asn1_print(&elem); 1631 return; 1632 } 1633 length -= count; 1634 np += count; 1635 1636 /* msgAuthoritativeEngineBoots (INTEGER) */ 1637 if ((count = asn1_parse(np, length, &elem)) < 0) 1638 return; 1639 if (elem.type != BE_INT) { 1640 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout); 1641 asn1_print(&elem); 1642 return; 1643 } 1644 if (vflag) 1645 printf("B=%d ", elem.data.integer); 1646 length -= count; 1647 np += count; 1648 1649 /* msgAuthoritativeEngineTime (INTEGER) */ 1650 if ((count = asn1_parse(np, length, &elem)) < 0) 1651 return; 1652 if (elem.type != BE_INT) { 1653 fputs("[msgAuthoritativeEngineTime!=INT]", stdout); 1654 asn1_print(&elem); 1655 return; 1656 } 1657 if (vflag) 1658 printf("T=%d ", elem.data.integer); 1659 length -= count; 1660 np += count; 1661 1662 /* msgUserName (OCTET STRING) */ 1663 if ((count = asn1_parse(np, length, &elem)) < 0) 1664 return; 1665 if (elem.type != BE_STR) { 1666 fputs("[msgUserName!=STR]", stdout); 1667 asn1_print(&elem); 1668 return; 1669 } 1670 length -= count; 1671 np += count; 1672 1673 printf("U=%.*s ", (int)elem.asnlen, elem.data.str); 1674 1675 /* msgAuthenticationParameters (OCTET STRING) */ 1676 if ((count = asn1_parse(np, length, &elem)) < 0) 1677 return; 1678 if (elem.type != BE_STR) { 1679 fputs("[msgAuthenticationParameters!=STR]", stdout); 1680 asn1_print(&elem); 1681 return; 1682 } 1683 length -= count; 1684 np += count; 1685 1686 /* msgPrivacyParameters (OCTET STRING) */ 1687 if ((count = asn1_parse(np, length, &elem)) < 0) 1688 return; 1689 if (elem.type != BE_STR) { 1690 fputs("[msgPrivacyParameters!=STR]", stdout); 1691 asn1_print(&elem); 1692 return; 1693 } 1694 length -= count; 1695 np += count; 1696 1697 if ((u_int)count < length) 1698 printf("[%d extra after usm SEQ]", length - count); 1699} 1700 1701/* 1702 * Decode SNMPv3 Message Header (SNMPv3) 1703 */ 1704static void 1705v3msg_print(const u_char *np, u_int length) 1706{ 1707 struct be elem; 1708 int count = 0; 1709 u_char flags; 1710 int model; 1711 const u_char *xnp = np; 1712 int xlength = length; 1713 1714 /* Sequence */ 1715 if ((count = asn1_parse(np, length, &elem)) < 0) 1716 return; 1717 if (elem.type != BE_SEQ) { 1718 fputs("[!message]", stdout); 1719 asn1_print(&elem); 1720 return; 1721 } 1722 length = elem.asnlen; 1723 np = (u_char *)elem.data.raw; 1724 1725 if (vflag) { 1726 fputs("{ ", stdout); 1727 } 1728 1729 /* msgID (INTEGER) */ 1730 if ((count = asn1_parse(np, length, &elem)) < 0) 1731 return; 1732 if (elem.type != BE_INT) { 1733 fputs("[msgID!=INT]", stdout); 1734 asn1_print(&elem); 1735 return; 1736 } 1737 length -= count; 1738 np += count; 1739 1740 /* msgMaxSize (INTEGER) */ 1741 if ((count = asn1_parse(np, length, &elem)) < 0) 1742 return; 1743 if (elem.type != BE_INT) { 1744 fputs("[msgMaxSize!=INT]", stdout); 1745 asn1_print(&elem); 1746 return; 1747 } 1748 length -= count; 1749 np += count; 1750 1751 /* msgFlags (OCTET STRING) */ 1752 if ((count = asn1_parse(np, length, &elem)) < 0) 1753 return; 1754 if (elem.type != BE_STR) { 1755 fputs("[msgFlags!=STR]", stdout); 1756 asn1_print(&elem); 1757 return; 1758 } 1759 if (elem.asnlen != 1) { 1760 printf("[msgFlags size %d]", elem.asnlen); 1761 return; 1762 } 1763 flags = elem.data.str[0]; 1764 if (flags != 0x00 && flags != 0x01 && flags != 0x03 1765 && flags != 0x04 && flags != 0x05 && flags != 0x07) { 1766 printf("[msgFlags=0x%02X]", flags); 1767 return; 1768 } 1769 length -= count; 1770 np += count; 1771 1772 fputs("F=", stdout); 1773 if (flags & 0x01) fputs("a", stdout); 1774 if (flags & 0x02) fputs("p", stdout); 1775 if (flags & 0x04) fputs("r", stdout); 1776 fputs(" ", stdout); 1777 1778 /* msgSecurityModel (INTEGER) */ 1779 if ((count = asn1_parse(np, length, &elem)) < 0) 1780 return; 1781 if (elem.type != BE_INT) { 1782 fputs("[msgSecurityModel!=INT]", stdout); 1783 asn1_print(&elem); 1784 return; 1785 } 1786 model = elem.data.integer; 1787 length -= count; 1788 np += count; 1789 1790 if ((u_int)count < length) 1791 printf("[%d extra after message SEQ]", length - count); 1792 1793 if (vflag) { 1794 fputs("} ", stdout); 1795 } 1796 1797 if (model == 3) { 1798 if (vflag) { 1799 fputs("{ USM ", stdout); 1800 } 1801 } else { 1802 printf("[security model %d]", model); 1803 return; 1804 } 1805 1806 np = xnp + (np - xnp); 1807 length = xlength - (np - xnp); 1808 1809 /* msgSecurityParameters (OCTET STRING) */ 1810 if ((count = asn1_parse(np, length, &elem)) < 0) 1811 return; 1812 if (elem.type != BE_STR) { 1813 fputs("[msgSecurityParameters!=STR]", stdout); 1814 asn1_print(&elem); 1815 return; 1816 } 1817 length -= count; 1818 np += count; 1819 1820 if (model == 3) { 1821 usm_print(elem.data.str, elem.asnlen); 1822 if (vflag) { 1823 fputs("} ", stdout); 1824 } 1825 } 1826 1827 if (vflag) { 1828 fputs("{ ScopedPDU ", stdout); 1829 } 1830 1831 scopedpdu_print(np, length, 3); 1832 1833 if (vflag) { 1834 fputs("} ", stdout); 1835 } 1836} 1837 1838/* 1839 * Decode SNMP header and pass on to PDU printing routines 1840 */ 1841void 1842snmp_print(const u_char *np, u_int length) 1843{ 1844 struct be elem; 1845 int count = 0; 1846 int version = 0; 1847 1848 putchar(' '); 1849 1850 /* initial Sequence */ 1851 if ((count = asn1_parse(np, length, &elem)) < 0) 1852 return; 1853 if (elem.type != BE_SEQ) { 1854 fputs("[!init SEQ]", stdout); 1855 asn1_print(&elem); 1856 return; 1857 } 1858 if ((u_int)count < length) 1859 printf("[%d extra after iSEQ]", length - count); 1860 /* descend */ 1861 length = elem.asnlen; 1862 np = (u_char *)elem.data.raw; 1863 1864 /* Version (INTEGER) */ 1865 if ((count = asn1_parse(np, length, &elem)) < 0) 1866 return; 1867 if (elem.type != BE_INT) { 1868 fputs("[version!=INT]", stdout); 1869 asn1_print(&elem); 1870 return; 1871 } 1872 1873 switch (elem.data.integer) { 1874 case SNMP_VERSION_1: 1875 case SNMP_VERSION_2: 1876 case SNMP_VERSION_3: 1877 if (vflag) 1878 printf("{ %s ", SnmpVersion[elem.data.integer]); 1879 break; 1880 default: 1881 printf("[version = %d]", elem.data.integer); 1882 return; 1883 } 1884 version = elem.data.integer; 1885 length -= count; 1886 np += count; 1887 1888 switch (version) { 1889 case SNMP_VERSION_1: 1890 case SNMP_VERSION_2: 1891 community_print(np, length, version); 1892 break; 1893 case SNMP_VERSION_3: 1894 v3msg_print(np, length); 1895 break; 1896 default: 1897 printf("[version = %d]", elem.data.integer); 1898 break; 1899 } 1900 1901 if (vflag) { 1902 fputs("} ", stdout); 1903 } 1904} 1905