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