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