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