1 /* $OpenBSD: print-snmp.c,v 1.24 2019/01/03 08:22:33 martijn Exp $ */ 2 3 /* 4 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 5 * John Robert LoVerso. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * 30 * This implementation has been influenced by the CMU SNMP release, 31 * by Steve Waldbusser. However, this shares no code with that system. 32 * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. 33 * Earlier forms of this implementation were derived and/or inspired by an 34 * awk script originally written by C. Philip Wood of LANL (but later 35 * heavily modified by John Robert LoVerso). The copyright notice for 36 * that work is preserved below, even though it may not rightly apply 37 * to this file. 38 * 39 * This started out as a very simple program, but the incremental decoding 40 * (into the BE structure) complicated things. 41 * 42 # Los Alamos National Laboratory 43 # 44 # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 45 # This software was produced under a U.S. Government contract 46 # (W-7405-ENG-36) by Los Alamos National Laboratory, which is 47 # operated by the University of California for the U.S. Department 48 # of Energy. The U.S. Government is licensed to use, reproduce, 49 # and distribute this software. Permission is granted to the 50 # public to copy and use this software without charge, provided 51 # that this Notice and any statement of authorship are reproduced 52 # on all copies. Neither the Government nor the University makes 53 # any warranty, express or implied, or assumes any liability or 54 # responsibility for the use of this software. 55 # @(#)snmp.awk.x 1.1 (LANL) 1/15/90 56 */ 57 58 #include <sys/time.h> 59 60 #include <ctype.h> 61 #include <stdio.h> 62 #include <string.h> 63 64 #include "interface.h" 65 #include "addrtoname.h" 66 67 /* 68 * Universal ASN.1 types 69 * (we only care about the tag values for those allowed in the Internet SMI) 70 */ 71 char *Universal[] = { 72 "U-0", 73 "Boolean", 74 "Integer", 75 #define INTEGER 2 76 "Bitstring", 77 "String", 78 #define STRING 4 79 "Null", 80 #define ASN_NULL 5 81 "ObjID", 82 #define OBJECTID 6 83 "ObjectDes", 84 "U-8","U-9","U-10","U-11", /* 8-11 */ 85 "U-12","U-13","U-14","U-15", /* 12-15 */ 86 "Sequence", 87 #define SEQUENCE 16 88 "Set" 89 }; 90 91 /* 92 * Application-wide ASN.1 types from the Internet SMI and their tags 93 */ 94 char *Application[] = { 95 "IpAddress", 96 #define IPADDR 0 97 "Counter", 98 #define COUNTER 1 99 "Gauge", 100 #define GAUGE 2 101 "TimeTicks", 102 #define TIMETICKS 3 103 "Opaque", 104 #define OPAQUE 4 105 "NsapAddress", 106 #define NSAPADDR 5 107 "Counter64", 108 #define COUNTER64 6 109 "UInteger32" 110 #define UINTEGER32 7 111 }; 112 113 /* 114 * Context-specific ASN.1 types for the SNMP PDUs and their tags 115 */ 116 char *Context[] = { 117 "GetRequest", 118 #define GETREQ 0 119 "GetNextRequest", 120 #define GETNEXTREQ 1 121 "GetResponse", 122 #define GETRESP 2 123 "SetRequest", 124 #define SETREQ 3 125 "Trap", 126 #define TRAP 4 127 "GetBulkReq", 128 #define GETBULKREQ 5 129 "InformReq", 130 #define INFORMREQ 6 131 "TrapV2", 132 #define TRAPV2 7 133 "Report" 134 #define REPORT 8 135 }; 136 137 /* 138 * Private ASN.1 types 139 * The Internet SMI does not specify any 140 */ 141 char *Private[] = { 142 "P-0" 143 }; 144 145 /* 146 * error-status values for any SNMP PDU 147 */ 148 char *ErrorStatus[] = { 149 "noError", 150 "tooBig", 151 "noSuchName", 152 "badValue", 153 "readOnly", 154 "genErr", 155 "noAccess", 156 "wrongType", 157 "wrongLength", 158 "wrongEnc", 159 "wrongValue", 160 "noCreation", 161 "inconValue", 162 "resUnavail", 163 "commitFailed", 164 "undoFailed", 165 "authError", 166 "notWritable", 167 "inconName" 168 }; 169 #define DECODE_ErrorStatus(e) \ 170 ( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ 171 ? ErrorStatus[e] : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf)) 172 173 /* 174 * generic-trap values in the SNMP Trap-PDU 175 */ 176 char *GenericTrap[] = { 177 "coldStart", 178 "warmStart", 179 "linkDown", 180 "linkUp", 181 "authenticationFailure", 182 "egpNeighborLoss", 183 "enterpriseSpecific" 184 #define GT_ENTERPRISE 6 185 }; 186 #define DECODE_GenericTrap(t) \ 187 ( t >= 0 && t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ 188 ? GenericTrap[t] : (snprintf(buf, sizeof(buf), "gt=%d", t), buf)) 189 190 /* 191 * ASN.1 type class table 192 * Ties together the preceding Universal, Application, Context, and Private 193 * type definitions. 194 */ 195 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ 196 struct { 197 char *name; 198 char **Id; 199 int numIDs; 200 } Class[] = { 201 defineCLASS(Universal), 202 #define UNIVERSAL 0 203 defineCLASS(Application), 204 #define APPLICATION 1 205 defineCLASS(Context), 206 #define CONTEXT 2 207 defineCLASS(Private), 208 #define PRIVATE 3 209 }; 210 211 /* 212 * defined forms for ASN.1 types 213 */ 214 char *Form[] = { 215 "Primitive", 216 #define PRIMITIVE 0 217 "Constructed", 218 #define CONSTRUCTED 1 219 }; 220 221 /* 222 * A structure for the OID tree for the compiled-in MIB. 223 * This is stored as a general-order tree. 224 */ 225 struct obj { 226 char *desc; /* name of object */ 227 u_int oid; /* sub-id following parent */ 228 u_char type; /* object type (unused) */ 229 struct obj *child, *next; /* child and next sibling pointers */ 230 } *objp = NULL; 231 232 /* 233 * Include the compiled in SNMP MIB. "mib.h" is produced by feeding 234 * RFC-1156 format files into "makemib". "mib.h" MUST define at least 235 * a value for `mibroot'. 236 * 237 * In particular, this is gross, as this is including initialized structures, 238 * and by right shouldn't be an "include" file. 239 */ 240 #include "mib.h" 241 242 /* 243 * This defines a list of OIDs which will be abbreviated on output. 244 * Currently, this includes the prefixes for the Internet MIB, the 245 * private enterprises tree, and the experimental tree. 246 */ 247 struct obj_abrev { 248 char *prefix; /* prefix for this abrev */ 249 struct obj *node; /* pointer into object table */ 250 char *oid; /* ASN.1 encoded OID */ 251 } obj_abrev_list[] = { 252 #ifndef NO_ABREV_MIB 253 /* .iso.org.dod.internet.mgmt.mib */ 254 { "", &_mib_obj, "\53\6\1\2\1" }, 255 #endif 256 #ifndef NO_ABREV_ENTER 257 /* .iso.org.dod.internet.private.enterprises */ 258 { "E:", &_enterprises_obj, "\53\6\1\4\1" }, 259 #endif 260 #ifndef NO_ABREV_EXPERI 261 /* .iso.org.dod.internet.experimental */ 262 { "X:", &_experimental_obj, "\53\6\1\3" }, 263 #endif 264 #ifndef NO_ABREV_SNMPMIBOBJECTS 265 /* .iso.org.dod.internet.snmpV2.snmpModules.snmpMIB.snmpMIBObjects */ 266 { "S:", &_snmpmibobjects_obj, "\53\6\1\6\3\1\1" }, 267 #endif 268 { 0,0,0 } 269 }; 270 271 /* 272 * This is used in the OID print routine to walk down the object tree 273 * rooted at `mibroot'. 274 */ 275 #define OBJ_PRINT(o, suppressdot) \ 276 { \ 277 if (objp) { \ 278 do { \ 279 if ((o) == objp->oid) \ 280 break; \ 281 } while ((objp = objp->next) != NULL); \ 282 } \ 283 if (objp) { \ 284 printf(suppressdot?"%s":".%s", objp->desc); \ 285 objp = objp->child; \ 286 } else \ 287 printf(suppressdot?"%u":".%u", (o)); \ 288 } 289 290 /* 291 * This is the definition for the Any-Data-Type storage used purely for 292 * temporary internal representation while decoding an ASN.1 data stream. 293 */ 294 struct be { 295 u_int32_t asnlen; 296 union { 297 caddr_t raw; 298 int32_t integer; 299 u_int32_t uns; 300 u_int64_t uns64; 301 const u_char *str; 302 } data; 303 u_short id; 304 u_char form, class; /* tag info */ 305 u_char type; 306 #define BE_ANY 255 307 #define BE_NONE 0 308 #define BE_NULL 1 309 #define BE_OCTET 2 310 #define BE_OID 3 311 #define BE_INT 4 312 #define BE_UNS 5 313 #define BE_STR 6 314 #define BE_SEQ 7 315 #define BE_INETADDR 8 316 #define BE_PDU 9 317 #define BE_UNS64 10 318 }; 319 320 321 /* 322 * SNMP components 323 */ 324 static int snmp3_print_usmparams(const u_char *, u_int); 325 326 enum snmp_version { 327 SNMP_V1 = 0, 328 SNMP_V2C = 1, 329 SNMP_V3 = 3 330 }; 331 #define SNMP3_AUTH(f) (f & 0x01) 332 #define SNMP3_PRIV(f) (f & 0x02) 333 #define SNMP3_REPORT(f) (f & 0x04) 334 335 struct snmp3_sm { 336 int id; 337 char *name; 338 int (*parse_params)(const u_char *, u_int); 339 } snmp3_securitymodel[] = { 340 {3, "USM", snmp3_print_usmparams}, 341 {0, NULL, NULL} 342 }; 343 344 /* 345 * Defaults for SNMP PDU components 346 */ 347 #define DEF_COMMUNITY "public" 348 349 /* 350 * constants for ASN.1 decoding 351 */ 352 #define OIDMUX 40 353 #define ASNLEN_INETADDR 4 354 #define ASN_SHIFT7 7 355 #define ASN_SHIFT8 8 356 #define ASN_BIT8 0x80 357 #define ASN_LONGLEN 0x80 358 359 #define ASN_ID_BITS 0x1f 360 #define ASN_FORM_BITS 0x20 361 #define ASN_FORM_SHIFT 5 362 #define ASN_CLASS_BITS 0xc0 363 #define ASN_CLASS_SHIFT 6 364 365 #define ASN_ID_EXT 0x1f /* extension ID in tag field */ 366 367 /* 368 * truncated==1 means the packet was complete, but we don't have all of 369 * it to decode. 370 */ 371 static int truncated; 372 373 /* 374 * This decodes the next ASN.1 object in the stream pointed to by "p" 375 * (and of real-length "len") and stores the intermediate data in the 376 * provided BE object. 377 * 378 * This returns -l if it fails (i.e., the ASN.1 stream is not valid). 379 * O/w, this returns the number of bytes parsed from "p". 380 */ 381 static int 382 asn1_parse(const u_char *p, u_int len, struct be *elem) 383 { 384 u_char form, class, id; 385 int i, hdr; 386 387 elem->asnlen = 0; 388 elem->type = BE_ANY; 389 if (len < 1) { 390 if (truncated) 391 fputs("[|snmp]", stdout); 392 else 393 fputs("[nothing to parse]", stdout); 394 return -1; 395 } 396 397 /* 398 * it would be nice to use a bit field, but you can't depend on them. 399 * +---+---+---+---+---+---+---+---+ 400 * + class |frm| id | 401 * +---+---+---+---+---+---+---+---+ 402 * 7 6 5 4 3 2 1 0 403 */ 404 id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ 405 #ifdef notdef 406 form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ 407 class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ 408 form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ 409 #else 410 form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; 411 class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; 412 #endif 413 elem->form = form; 414 elem->class = class; 415 elem->id = id; 416 if (vflag > 1) 417 printf("|%.2x", *p); 418 p++; len--; hdr = 1; 419 /* extended tag field */ 420 if (id == ASN_ID_EXT) { 421 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) { 422 if (vflag > 1) 423 printf("|%.2x", *p); 424 id = (id << 7) | (*p & ~ASN_BIT8); 425 } 426 if (len == 0 && *p & ASN_BIT8) { 427 if (truncated) 428 fputs("[|snmp]", stdout); 429 else 430 fputs("[Xtagfield?]", stdout); 431 return -1; 432 } 433 elem->id = id = (id << 7) | *p; 434 --len; 435 ++hdr; 436 ++p; 437 } 438 if (len < 1) { 439 if (truncated) 440 fputs("[|snmp]", stdout); 441 else 442 fputs("[no asnlen]", stdout); 443 return -1; 444 } 445 elem->asnlen = *p; 446 if (vflag > 1) 447 printf("|%.2x", *p); 448 p++; len--; hdr++; 449 if (elem->asnlen & ASN_BIT8) { 450 int noct = elem->asnlen % ASN_BIT8; 451 elem->asnlen = 0; 452 if (len < noct) { 453 if (truncated) 454 fputs("[|snmp]", stdout); 455 else 456 printf("[asnlen? %d<%d]", len, noct); 457 return -1; 458 } 459 for (; noct-- > 0; len--, hdr++) { 460 if (vflag > 1) 461 printf("|%.2x", *p); 462 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; 463 } 464 } 465 if (len < elem->asnlen) { 466 if (!truncated) { 467 printf("[len%d<asnlen%u]", len, elem->asnlen); 468 return -1; 469 } 470 /* maybe should check at least 4? */ 471 elem->asnlen = len; 472 } 473 if (form >= sizeof(Form)/sizeof(Form[0])) { 474 if (truncated) 475 fputs("[|snmp]", stdout); 476 else 477 printf("[form?%d]", form); 478 return -1; 479 } 480 if (class >= sizeof(Class)/sizeof(Class[0])) { 481 if (truncated) 482 fputs("[|snmp]", stdout); 483 else 484 printf("[class?%c/%d]", *Form[form], class); 485 return -1; 486 } 487 if ((int)id >= Class[class].numIDs) { 488 if (truncated) 489 fputs("[|snmp]", stdout); 490 else 491 printf("[id?%c/%s/%d]", *Form[form], 492 Class[class].name, id); 493 return -1; 494 } 495 496 switch (form) { 497 case PRIMITIVE: 498 switch (class) { 499 case UNIVERSAL: 500 switch (id) { 501 case STRING: 502 elem->type = BE_STR; 503 elem->data.str = p; 504 break; 505 506 case INTEGER: { 507 int32_t data; 508 elem->type = BE_INT; 509 data = 0; 510 511 if (*p & ASN_BIT8) /* negative */ 512 data = -1; 513 for (i = elem->asnlen; i-- > 0; p++) 514 data = (data << ASN_SHIFT8) | *p; 515 elem->data.integer = data; 516 break; 517 } 518 519 case OBJECTID: 520 elem->type = BE_OID; 521 elem->data.raw = (caddr_t)p; 522 break; 523 524 case ASN_NULL: 525 elem->type = BE_NULL; 526 elem->data.raw = NULL; 527 break; 528 529 default: 530 elem->type = BE_OCTET; 531 elem->data.raw = (caddr_t)p; 532 printf("[P/U/%s]", 533 Class[class].Id[id]); 534 break; 535 } 536 break; 537 538 case APPLICATION: 539 switch (id) { 540 case IPADDR: 541 elem->type = BE_INETADDR; 542 elem->data.raw = (caddr_t)p; 543 break; 544 545 case COUNTER: 546 case GAUGE: 547 case TIMETICKS: 548 case OPAQUE: 549 case NSAPADDR: 550 case UINTEGER32: { 551 u_int32_t data; 552 elem->type = BE_UNS; 553 data = 0; 554 for (i = elem->asnlen; i-- > 0; p++) 555 data = (data << 8) + *p; 556 elem->data.uns = data; 557 break; 558 } 559 560 case COUNTER64: { 561 u_int64_t data; 562 elem->type = BE_UNS64; 563 data = 0; 564 for (i = elem->asnlen; i-- > 0; p++) 565 data = (data << 8) + *p; 566 elem->data.uns64 = data; 567 break; 568 } 569 570 default: 571 elem->type = BE_OCTET; 572 elem->data.raw = (caddr_t)p; 573 printf("[P/A/%s]", 574 Class[class].Id[id]); 575 break; 576 } 577 break; 578 579 default: 580 elem->type = BE_OCTET; 581 elem->data.raw = (caddr_t)p; 582 printf("[P/%s/%s]", 583 Class[class].name, Class[class].Id[id]); 584 break; 585 } 586 break; 587 588 case CONSTRUCTED: 589 switch (class) { 590 case UNIVERSAL: 591 switch (id) { 592 case SEQUENCE: 593 elem->type = BE_SEQ; 594 elem->data.raw = (caddr_t)p; 595 break; 596 597 default: 598 elem->type = BE_OCTET; 599 elem->data.raw = (caddr_t)p; 600 printf("C/U/%s", Class[class].Id[id]); 601 break; 602 } 603 break; 604 605 case CONTEXT: 606 elem->type = BE_PDU; 607 elem->data.raw = (caddr_t)p; 608 break; 609 610 default: 611 elem->type = BE_OCTET; 612 elem->data.raw = (caddr_t)p; 613 printf("C/%s/%s", 614 Class[class].name, Class[class].Id[id]); 615 break; 616 } 617 break; 618 } 619 p += elem->asnlen; 620 len -= elem->asnlen; 621 return elem->asnlen + hdr; 622 } 623 624 /* 625 * Display the ASN.1 object represented by the BE object. 626 * This used to be an integral part of asn1_parse() before the intermediate 627 * BE form was added. 628 */ 629 static void 630 asn1_print(struct be *elem) 631 { 632 u_char *p = (u_char *)elem->data.raw; 633 u_int32_t asnlen = elem->asnlen; 634 int i; 635 636 switch (elem->type) { 637 case BE_OCTET: 638 for (i = asnlen; i-- > 0; p++) 639 printf("_%.2x", *p); 640 break; 641 case BE_NULL: 642 break; 643 case BE_OID: { 644 int o = 0, first = -1, i = asnlen; 645 646 if (!nflag && asnlen > 2) { 647 struct obj_abrev *a = &obj_abrev_list[0]; 648 for (; a->node; a++) { 649 if (!memcmp(a->oid, (char *)p, 650 strlen(a->oid))) { 651 objp = a->node->child; 652 i -= strlen(a->oid); 653 p += strlen(a->oid); 654 fputs(a->prefix, stdout); 655 first = 1; 656 break; 657 } 658 } 659 } 660 for (; i-- > 0; p++) { 661 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 662 if (*p & ASN_LONGLEN) 663 continue; 664 665 /* 666 * first subitem encodes two items with 1st*OIDMUX+2nd 667 */ 668 if (first < 0) { 669 if (!nflag) 670 objp = mibroot; 671 first = 0; 672 OBJ_PRINT(o/OIDMUX, first); 673 o %= OIDMUX; 674 } 675 OBJ_PRINT(o, first); 676 if (--first < 0) 677 first = 0; 678 o = 0; 679 } 680 break; 681 } 682 case BE_INT: 683 printf("%d", elem->data.integer); 684 break; 685 case BE_UNS: 686 printf("%d", elem->data.uns); 687 break; 688 case BE_UNS64: 689 printf("%lld", elem->data.uns64); 690 break; 691 case BE_STR: { 692 int printable = 1, first = 1; 693 const u_char *p = elem->data.str; 694 for (i = asnlen; printable && i-- > 0; p++) 695 printable = isprint(*p) || isspace(*p); 696 p = elem->data.str; 697 if (printable) { 698 putchar('"'); 699 (void)fn_print(p, p + asnlen); 700 putchar('"'); 701 } else 702 for (i = asnlen; i-- > 0; p++) { 703 printf(first ? "%.2x" : "_%.2x", *p); 704 first = 0; 705 } 706 break; 707 } 708 case BE_SEQ: 709 printf("Seq(%u)", elem->asnlen); 710 break; 711 case BE_INETADDR: { 712 char sep; 713 if (asnlen != ASNLEN_INETADDR) 714 printf("[inetaddr len!=%d]", ASNLEN_INETADDR); 715 sep='['; 716 for (i = asnlen; i-- > 0; p++) { 717 printf("%c%u", sep, *p); 718 sep='.'; 719 } 720 putchar(']'); 721 break; 722 } 723 case BE_PDU: 724 printf("%s(%u)", 725 Class[CONTEXT].Id[elem->id], elem->asnlen); 726 break; 727 case BE_ANY: 728 fputs("[BE_ANY!?]", stdout); 729 break; 730 default: 731 fputs("[be!?]", stdout); 732 break; 733 } 734 } 735 736 #ifdef notdef 737 /* 738 * This is a brute force ASN.1 printer: recurses to dump an entire structure. 739 * This will work for any ASN.1 stream, not just an SNMP PDU. 740 * 741 * By adding newlines and spaces at the correct places, this would print in 742 * Rose-Normal-Form. 743 * 744 * This is not currently used. 745 */ 746 static void 747 asn1_decode(u_char *p, u_int length) 748 { 749 struct be elem; 750 int i = 0; 751 752 while (i >= 0 && length > 0) { 753 i = asn1_parse(p, length, &elem); 754 if (i >= 0) { 755 fputs(" ", stdout); 756 asn1_print(&elem); 757 if (elem.type == BE_SEQ || elem.type == BE_PDU) { 758 fputs(" {", stdout); 759 asn1_decode(elem.data.raw, elem.asnlen); 760 fputs(" }", stdout); 761 } 762 length -= i; 763 p += i; 764 } 765 } 766 } 767 #endif 768 769 /* 770 * General SNMP header 771 * SEQUENCE { 772 * version INTEGER {version-1(0)}, 773 * community OCTET STRING, 774 * data ANY -- PDUs 775 * } 776 * PDUs for all but Trap: (see rfc1157 from page 15 on) 777 * SEQUENCE { 778 * request-id INTEGER, 779 * error-status INTEGER, 780 * error-index INTEGER, 781 * varbindlist SEQUENCE OF 782 * SEQUENCE { 783 * name ObjectName, 784 * value ObjectValue 785 * } 786 * } 787 * PDU for Trap: 788 * SEQUENCE { 789 * enterprise OBJECT IDENTIFIER, 790 * agent-addr NetworkAddress, 791 * generic-trap INTEGER, 792 * specific-trap INTEGER, 793 * time-stamp TimeTicks, 794 * varbindlist SEQUENCE OF 795 * SEQUENCE { 796 * name ObjectName, 797 * value ObjectValue 798 * } 799 * } 800 */ 801 802 /* 803 * Decode SNMP varBind 804 */ 805 static void 806 varbind_print(u_char pduid, const u_char *np, u_int length, int error) 807 { 808 struct be elem; 809 int count = 0, ind; 810 811 /* Sequence of varBind */ 812 if ((count = asn1_parse(np, length, &elem)) < 0) 813 return; 814 if (elem.type != BE_SEQ) { 815 fputs("[!SEQ of varbind]", stdout); 816 asn1_print(&elem); 817 return; 818 } 819 if (count < length) 820 printf("[%d extra after SEQ of varbind]", length - count); 821 /* descend */ 822 length = elem.asnlen; 823 np = (u_char *)elem.data.raw; 824 825 for (ind = 1; length > 0; ind++) { 826 const u_char *vbend; 827 u_int vblength; 828 829 putchar(' '); 830 /* Sequence */ 831 if ((count = asn1_parse(np, length, &elem)) < 0) 832 return; 833 if (elem.type != BE_SEQ) { 834 fputs("[!varbind]", stdout); 835 asn1_print(&elem); 836 return; 837 } 838 vbend = np + count; 839 vblength = length - count; 840 /* descend */ 841 length = elem.asnlen; 842 np = (u_char *)elem.data.raw; 843 844 /* objName (OID) */ 845 if ((count = asn1_parse(np, length, &elem)) < 0) 846 return; 847 if (elem.type != BE_OID) { 848 fputs("[objName!=OID]", stdout); 849 asn1_print(&elem); 850 return; 851 } 852 if (!error || ind == error) 853 asn1_print(&elem); 854 length -= count; 855 np += count; 856 857 if (pduid != GETREQ && pduid != GETNEXTREQ && !error) 858 fputs("=", stdout); 859 860 /* objVal (ANY) */ 861 if ((count = asn1_parse(np, length, &elem)) < 0) 862 return; 863 if (pduid == GETREQ || pduid == GETNEXTREQ || pduid == GETBULKREQ) { 864 if (elem.type != BE_NULL) { 865 fputs("[objVal!=NULL]", stdout); 866 asn1_print(&elem); 867 } 868 } else { 869 if (error && ind == error && elem.type != BE_NULL) 870 fputs("[err objVal!=NULL]", stdout); 871 if (!error || ind == error) 872 asn1_print(&elem); 873 } 874 875 length = vblength; 876 np = vbend; 877 } 878 } 879 880 /* 881 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest 882 */ 883 static void 884 snmppdu_print(u_char pduid, const u_char *np, u_int length) 885 { 886 struct be elem; 887 int count = 0, error; 888 889 /* reqId (Integer) */ 890 if ((count = asn1_parse(np, length, &elem)) < 0) 891 return; 892 if (elem.type != BE_INT) { 893 fputs("[reqId!=INT]", stdout); 894 asn1_print(&elem); 895 return; 896 } 897 if (vflag) 898 printf(" reqId=%d", elem.data.integer); 899 length -= count; 900 np += count; 901 902 /* errorStatus (Integer) */ 903 if ((count = asn1_parse(np, length, &elem)) < 0) 904 return; 905 if (elem.type != BE_INT) { 906 fputs("[errorStatus!=INT]", stdout); 907 asn1_print(&elem); 908 return; 909 } 910 error = 0; 911 if ((pduid == GETREQ || pduid == GETNEXTREQ) 912 && elem.data.integer != 0) { 913 char errbuf[20]; 914 printf("[errorStatus(%s)!=0]", 915 DECODE_ErrorStatus(elem.data.integer)); 916 } else if (pduid == GETBULKREQ) 917 printf(" non-repeaters=%d", elem.data.integer); 918 else if (elem.data.integer != 0) { 919 char errbuf[20]; 920 printf(" %s", DECODE_ErrorStatus(elem.data.integer)); 921 error = elem.data.integer; 922 } 923 length -= count; 924 np += count; 925 926 /* errorIndex (Integer) */ 927 if ((count = asn1_parse(np, length, &elem)) < 0) 928 return; 929 if (elem.type != BE_INT) { 930 fputs("[errorIndex!=INT]", stdout); 931 asn1_print(&elem); 932 return; 933 } 934 if ((pduid == GETREQ || pduid == GETNEXTREQ) 935 && elem.data.integer != 0) 936 printf("[errorIndex(%d)!=0]", elem.data.integer); 937 else if (pduid == GETBULKREQ) 938 printf(" max-repetitions=%d", elem.data.integer); 939 else if (elem.data.integer != 0) { 940 if (!error) 941 printf("[errorIndex(%d) w/o errorStatus]", 942 elem.data.integer); 943 else { 944 printf("@%d", elem.data.integer); 945 error = elem.data.integer; 946 } 947 } else if (error) { 948 fputs("[errorIndex==0]", stdout); 949 error = 0; 950 } 951 length -= count; 952 np += count; 953 954 varbind_print(pduid, np, length, error); 955 return; 956 } 957 958 /* 959 * Decode SNMP Trap PDU 960 */ 961 static void 962 trap_print(const u_char *np, u_int length) 963 { 964 struct be elem; 965 int count = 0, generic; 966 967 putchar(' '); 968 969 /* enterprise (oid) */ 970 if ((count = asn1_parse(np, length, &elem)) < 0) 971 return; 972 if (elem.type != BE_OID) { 973 fputs("[enterprise!=OID]", stdout); 974 asn1_print(&elem); 975 return; 976 } 977 asn1_print(&elem); 978 length -= count; 979 np += count; 980 981 putchar(' '); 982 983 /* agent-addr (inetaddr) */ 984 if ((count = asn1_parse(np, length, &elem)) < 0) 985 return; 986 if (elem.type != BE_INETADDR) { 987 fputs("[agent-addr!=INETADDR]", stdout); 988 asn1_print(&elem); 989 return; 990 } 991 asn1_print(&elem); 992 length -= count; 993 np += count; 994 995 /* generic-trap (Integer) */ 996 if ((count = asn1_parse(np, length, &elem)) < 0) 997 return; 998 if (elem.type != BE_INT) { 999 fputs("[generic-trap!=INT]", stdout); 1000 asn1_print(&elem); 1001 return; 1002 } 1003 generic = elem.data.integer; 1004 { 1005 char buf[20]; 1006 printf(" %s", DECODE_GenericTrap(generic)); 1007 } 1008 length -= count; 1009 np += count; 1010 1011 /* specific-trap (Integer) */ 1012 if ((count = asn1_parse(np, length, &elem)) < 0) 1013 return; 1014 if (elem.type != BE_INT) { 1015 fputs("[specific-trap!=INT]", stdout); 1016 asn1_print(&elem); 1017 return; 1018 } 1019 if (generic != GT_ENTERPRISE) { 1020 if (elem.data.integer != 0) 1021 printf("[specific-trap(%d)!=0]", elem.data.integer); 1022 } else 1023 printf(" s=%d", elem.data.integer); 1024 length -= count; 1025 np += count; 1026 1027 putchar(' '); 1028 1029 /* time-stamp (TimeTicks) */ 1030 if ((count = asn1_parse(np, length, &elem)) < 0) 1031 return; 1032 if (elem.type != BE_UNS) { /* XXX */ 1033 fputs("[time-stamp!=TIMETICKS]", stdout); 1034 asn1_print(&elem); 1035 return; 1036 } 1037 asn1_print(&elem); 1038 length -= count; 1039 np += count; 1040 1041 varbind_print (TRAP, np, length, 0); 1042 return; 1043 } 1044 1045 /* 1046 * Decode SNMP header and pass on to PDU printing routines 1047 */ 1048 static void 1049 snmp12_print(const u_char *np, u_int length) 1050 { 1051 struct be elem; 1052 int count; 1053 1054 /* Community (String) */ 1055 if ((count = asn1_parse(np, length, &elem)) < 0) 1056 return; 1057 if (elem.type != BE_STR) { 1058 fputs("[comm!=STR]", stdout); 1059 asn1_print(&elem); 1060 return; 1061 } 1062 /* default community */ 1063 if (strncmp((char *)elem.data.str, DEF_COMMUNITY, 1064 sizeof(DEF_COMMUNITY) - 1)) 1065 /* ! "public" */ 1066 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1067 length -= count; 1068 np += count; 1069 1070 /* PDU (Context) */ 1071 if ((count = asn1_parse(np, length, &elem)) < 0) 1072 return; 1073 if (elem.type != BE_PDU) { 1074 fputs("[no PDU]", stdout); 1075 return; 1076 } 1077 if (count < length) 1078 printf("[%d extra after PDU]", length - count); 1079 asn1_print(&elem); 1080 /* descend into PDU */ 1081 length = elem.asnlen; 1082 np = (u_char *)elem.data.raw; 1083 1084 switch (elem.id) { 1085 case TRAP: 1086 trap_print(np, length); 1087 break; 1088 case GETREQ: 1089 case GETNEXTREQ: 1090 case GETRESP: 1091 case SETREQ: 1092 case GETBULKREQ: 1093 case INFORMREQ: 1094 case TRAPV2: 1095 case REPORT: 1096 snmppdu_print(elem.id, np, length); 1097 break; 1098 } 1099 return; 1100 } 1101 1102 static int 1103 snmp3_print_usmparams(const u_char *np, u_int length) 1104 { 1105 struct be elem; 1106 int count; 1107 int i; 1108 1109 if ((count = asn1_parse(np, length, &elem)) < 0) 1110 return -1; 1111 if (elem.type != BE_SEQ) { 1112 fputs("[!usmSM SEQ]", stdout); 1113 asn1_print(&elem); 1114 return -1; 1115 } 1116 if (count < length) { 1117 printf("[%d extra after usmSM]", length - count); 1118 return -1; 1119 } 1120 /* descend */ 1121 length = elem.asnlen; 1122 np = (u_char *)elem.data.raw; 1123 1124 /* msgAuthoritativeEngineID */ 1125 if ((count = asn1_parse(np, length, &elem)) < 0) 1126 return -1; 1127 if (elem.type != BE_STR) { 1128 fputs("[umsEID!=STR]", stdout); 1129 asn1_print(&elem); 1130 return -1; 1131 } 1132 if (vflag && elem.asnlen > 0) { 1133 fputs("umsEID=0x", stdout); 1134 for (i = 0; i < elem.asnlen; i++) 1135 printf("%02hhX", elem.data.str[i]); 1136 putchar(' '); 1137 } 1138 length -= count; 1139 np += count; 1140 1141 /* msgAuthoritativeEngineBoots */ 1142 if ((count = asn1_parse(np, length, &elem)) < 0) 1143 return -1; 1144 if (elem.type != BE_INT) { 1145 fputs("[EBoots!=INT]", stdout); 1146 asn1_print(&elem); 1147 return -1; 1148 } 1149 if (vflag) 1150 printf("EBoots=%d ", elem.data.integer); 1151 length -= count; 1152 np += count; 1153 1154 /* msgAuthoritativeEngineTime */ 1155 if ((count = asn1_parse(np, length, &elem)) < 0) 1156 return -1; 1157 if (elem.type != BE_INT) { 1158 fputs("[ETime!=INT]", stdout); 1159 asn1_print(&elem); 1160 return -1; 1161 } 1162 if (vflag) 1163 printf("ETime=%d ", elem.data.integer); 1164 length -= count; 1165 np += count; 1166 1167 if ((count = asn1_parse(np, length, &elem)) < 0) 1168 return -1; 1169 if (elem.type != BE_STR) { 1170 fputs("[User!=STR]", stdout); 1171 asn1_print(&elem); 1172 return -1; 1173 } 1174 if (elem.asnlen > 0) { 1175 fputs("User=", stdout); 1176 asn1_print(&elem); 1177 putchar(' '); 1178 } 1179 length -= count; 1180 np += count; 1181 1182 /* msgAuthenticationParameters */ 1183 if ((count = asn1_parse(np, length, &elem)) < 0) 1184 return -1; 1185 if (elem.type != BE_STR) { 1186 fputs("[AuthParam!=STR]", stdout); 1187 asn1_print(&elem); 1188 return -1; 1189 } 1190 /* Can't validate msgAuthenticationParameters without pass */ 1191 length -= count; 1192 np += count; 1193 1194 /* msgPrivacyParameters */ 1195 if ((count = asn1_parse(np, length, &elem)) < 0) 1196 return -1; 1197 if (elem.type != BE_STR) { 1198 fputs("[PrivParam!=STR]", stdout); 1199 asn1_print(&elem); 1200 return -1; 1201 } 1202 /* Salt is not useful if we can't decrypt */ 1203 if (length - count != 0) { 1204 printf("[%d extra after usmSM]", length - count); 1205 return -1; 1206 } 1207 return 0; 1208 } 1209 1210 static void 1211 snmp3_print(const u_char *np, u_int length) 1212 { 1213 struct be elem; 1214 struct snmp3_sm *sm = NULL; 1215 int count; 1216 int sublen; 1217 int i; 1218 int authpriv; 1219 u_char *subnp; 1220 1221 /* Header sequence */ 1222 if ((count = asn1_parse(np, length, &elem)) < 0) 1223 return; 1224 if (elem.type != BE_SEQ) { 1225 fputs("[!header SEQ]", stdout); 1226 asn1_print(&elem); 1227 return; 1228 } 1229 np += count; 1230 length -= count; 1231 /* descend */ 1232 /* msgID */ 1233 sublen = elem.asnlen; 1234 subnp = (u_char *)elem.data.raw; 1235 if ((count = asn1_parse(subnp, sublen, &elem)) < 0) 1236 return; 1237 if (elem.type != BE_INT) { 1238 fputs("[msgID!=INT]", stdout); 1239 asn1_print(&elem); 1240 return; 1241 } 1242 if (vflag) 1243 printf("msgID=%d ", elem.data.integer); 1244 sublen -= count; 1245 subnp += count; 1246 1247 /* msgMaxSize */ 1248 if ((count = asn1_parse(subnp, sublen, &elem)) < 0) 1249 return; 1250 if (elem.type != BE_INT) { 1251 fputs("[msgMS!=INT]", stdout); 1252 asn1_print(&elem); 1253 return; 1254 } 1255 if (vflag) 1256 printf("msgMS=%d ", elem.data.integer); 1257 sublen -= count; 1258 subnp += count; 1259 1260 /* msgFlags */ 1261 if ((count = asn1_parse(subnp, sublen, &elem)) < 0) 1262 return; 1263 if (elem.type != BE_STR) { 1264 fputs("[msgFl!=STR]", stdout); 1265 asn1_print(&elem); 1266 return; 1267 } 1268 if (elem.asnlen != 1) 1269 printf("[%d extra after msgFl]", elem.asnlen - 1); 1270 authpriv = *elem.data.str & 0x3; 1271 if (vflag && (*elem.data.str & 0x7) != 0) { 1272 printf("(%suth%sPriv%s) ", 1273 SNMP3_AUTH(*elem.data.str) ? "a" : "noA", 1274 SNMP3_PRIV(*elem.data.str) ? "" : "No", 1275 SNMP3_REPORT(*elem.data.str) ? "|Reportable" : "" 1276 ); 1277 } 1278 sublen -= count; 1279 subnp += count; 1280 1281 /* msgSecurityModel */ 1282 if ((count = asn1_parse(subnp, sublen, &elem)) < 0) 1283 return; 1284 if (elem.type != BE_INT) { 1285 fputs("[msgSM!=INT]", stdout); 1286 asn1_print(&elem); 1287 return; 1288 } 1289 for (i = 0; snmp3_securitymodel[i].id != 0; i++) { 1290 if (snmp3_securitymodel[i].id == elem.data.integer) { 1291 sm = &(snmp3_securitymodel[i]); 1292 break; 1293 } 1294 } 1295 if (vflag) { 1296 if (sm != NULL && nflag == 0) 1297 printf("msgSM=%s ", sm->name); 1298 else 1299 printf("msgSM=%d ", elem.data.integer); 1300 } 1301 if (sublen - count != 0) { 1302 printf("[%d extra after header]", sublen - count); 1303 return; 1304 } 1305 1306 /* ascend */ 1307 if ((count = asn1_parse(np, length, &elem)) < 0) 1308 return; 1309 if (elem.type != BE_STR) { 1310 fputs("msgSP!=STR]", stdout); 1311 asn1_print(&elem); 1312 return; 1313 } 1314 if (sm != NULL && sm->parse_params != NULL) { 1315 if (sm->parse_params(elem.data.raw, elem.asnlen) == -1) 1316 return; 1317 } 1318 length -= count; 1319 np += count; 1320 1321 if (SNMP3_PRIV(authpriv) != 0) { 1322 fputs("[encrypted PDU]", stdout); 1323 return; 1324 } 1325 1326 /* msgData */ 1327 if ((count = asn1_parse(np, length, &elem)) < 0) 1328 return; 1329 if (elem.type != BE_SEQ) { 1330 fputs("[ScPDU!=SEQ]", stdout); 1331 asn1_print(&elem); 1332 return; 1333 } 1334 if (count < length) 1335 printf("[%d extra after ScPDU]", length - count); 1336 /* descend */ 1337 length = elem.asnlen; 1338 np = (u_char *)elem.data.raw; 1339 1340 /* contextEngineID */ 1341 if ((count = asn1_parse(np, length, &elem)) < 0) 1342 return; 1343 if (elem.type != BE_STR) { 1344 fputs("ctxEID!=STR]", stdout); 1345 asn1_print(&elem); 1346 return; 1347 } 1348 if (vflag && elem.asnlen > 0) { 1349 fputs("ctxEID=0x", stdout); 1350 for (i = 0; i < elem.asnlen; i++) 1351 printf("%02hhX", elem.data.str[i]); 1352 putchar(' '); 1353 } 1354 length -= count; 1355 np += count; 1356 1357 /* contextName */ 1358 if ((count = asn1_parse(np, length, &elem)) < 0) 1359 return; 1360 if (elem.type != BE_STR) { 1361 fputs("[ctxEName!=STR]", stdout); 1362 asn1_print(&elem); 1363 return; 1364 } 1365 if (vflag && elem.asnlen > 0) { 1366 fputs("ctxName=", stdout); 1367 asn1_print(&elem); 1368 putchar(' '); 1369 } 1370 length -= count; 1371 np += count; 1372 1373 /* Data */ 1374 if ((count = asn1_parse(np, length, &elem)) < 0) 1375 return; 1376 if (elem.type != BE_PDU) { 1377 fputs("[data!=PDU]", stdout); 1378 asn1_print(&elem); 1379 return; 1380 } 1381 if (count < length) 1382 printf("[%d extra after PDU]", length - count); 1383 asn1_print(&elem); 1384 /* descend into PDU */ 1385 length = elem.asnlen; 1386 np = (u_char *)elem.data.raw; 1387 switch (elem.id) { 1388 case TRAP: 1389 trap_print(np, length); 1390 break; 1391 case GETREQ: 1392 case GETNEXTREQ: 1393 case GETRESP: 1394 case SETREQ: 1395 case GETBULKREQ: 1396 case INFORMREQ: 1397 case TRAPV2: 1398 case REPORT: 1399 snmppdu_print(elem.id, np, length); 1400 break; 1401 } 1402 } 1403 1404 void 1405 snmp_print(const u_char *np, u_int length) 1406 { 1407 struct be elem; 1408 int count = 0; 1409 1410 truncated = 0; 1411 1412 /* truncated packet? */ 1413 if (np + length > snapend) { 1414 truncated = 1; 1415 length = snapend - np; 1416 } 1417 1418 /* initial Sequence */ 1419 if ((count = asn1_parse(np, length, &elem)) < 0) 1420 return; 1421 if (elem.type != BE_SEQ) { 1422 fputs("[!init SEQ]", stdout); 1423 asn1_print(&elem); 1424 return; 1425 } 1426 if (count < length) 1427 printf("[%d extra after iSEQ]", length - count); 1428 /* descend */ 1429 length = elem.asnlen; 1430 np = (u_char *)elem.data.raw; 1431 /* Version (Integer) */ 1432 if ((count = asn1_parse(np, length, &elem)) < 0) 1433 return; 1434 if (elem.type != BE_INT) { 1435 fputs("[version!=INT]", stdout); 1436 asn1_print(&elem); 1437 return; 1438 } 1439 length -= count; 1440 np += count; 1441 switch (elem.data.integer) { 1442 case SNMP_V1: 1443 case SNMP_V2C: 1444 if (vflag) 1445 printf("SNMPv%s ", elem.data.integer == SNMP_V1 ? 1446 "1" : "2c"); 1447 snmp12_print(np, length); 1448 return; 1449 case SNMP_V3: 1450 if (vflag) 1451 fputs("SNMPv3 ", stdout); 1452 snmp3_print(np, length); 1453 return; 1454 default: 1455 printf("[snmp version(%d)]", elem.data.integer); 1456 return; 1457 } 1458 } 1459