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