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.4.2 2002/07/20 23:33:08 guy 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 * (see X.690:1997 clause 8.19 for the details) 692 */ 693 if (first < 0) { 694 int s; 695 if (!nflag) 696 objp = mibroot; 697 first = 0; 698 s = o / OIDMUX; 699 if (s > 2) s = 2; 700 OBJ_PRINT(s, first); 701 o -= s * OIDMUX; 702 } 703 OBJ_PRINT(o, first); 704 if (--first < 0) 705 first = 0; 706 o = 0; 707 } 708 break; 709 } 710 711 case BE_INT: 712 printf("%d", elem->data.integer); 713 break; 714 715 case BE_UNS: 716 printf("%u", elem->data.uns); 717 break; 718 719 case BE_UNS64: { /* idea borrowed from by Marshall Rose */ 720 double d; 721 int j, carry; 722 char *cpf, *cpl, last[6], first[30]; 723 if (elem->data.uns64.high == 0) { 724 printf("%u", elem->data.uns64.low); 725 break; 726 } 727 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */ 728 if (elem->data.uns64.high <= 0x1fffff) { 729 d += elem->data.uns64.low; 730 #if 0 /*is looks illegal, but what is the intention?*/ 731 printf("%.f", d); 732 #else 733 printf("%f", d); 734 #endif 735 break; 736 } 737 d += (elem->data.uns64.low & 0xfffff000); 738 #if 0 /*is looks illegal, but what is the intention?*/ 739 snprintf(first, sizeof(first), "%.f", d); 740 #else 741 snprintf(first, sizeof(first), "%f", d); 742 #endif 743 snprintf(last, sizeof(last), "%5.5d", 744 elem->data.uns64.low & 0xfff); 745 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4; 746 cpl >= last; 747 cpf--, cpl--) { 748 j = carry + (*cpf - '0') + (*cpl - '0'); 749 if (j > 9) { 750 j -= 10; 751 carry = 1; 752 } else { 753 carry = 0; 754 } 755 *cpf = j + '0'; 756 } 757 fputs(first, stdout); 758 break; 759 } 760 761 case BE_STR: { 762 register int printable = 1, first = 1; 763 const u_char *p = elem->data.str; 764 for (i = asnlen; printable && i-- > 0; p++) 765 printable = isprint(*p) || isspace(*p); 766 p = elem->data.str; 767 if (printable) { 768 putchar('"'); 769 (void)fn_print(p, p + asnlen); 770 putchar('"'); 771 } else 772 for (i = asnlen; i-- > 0; p++) { 773 printf(first ? "%.2x" : "_%.2x", *p); 774 first = 0; 775 } 776 break; 777 } 778 779 case BE_SEQ: 780 printf("Seq(%u)", elem->asnlen); 781 break; 782 783 case BE_INETADDR: 784 if (asnlen != ASNLEN_INETADDR) 785 printf("[inetaddr len!=%d]", ASNLEN_INETADDR); 786 for (i = asnlen; i-- > 0; p++) { 787 printf((i == asnlen-1) ? "%u" : ".%u", *p); 788 } 789 break; 790 791 case BE_NOSUCHOBJECT: 792 case BE_NOSUCHINST: 793 case BE_ENDOFMIBVIEW: 794 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]); 795 break; 796 797 case BE_PDU: 798 printf("%s(%u)", 799 Class[CONTEXT].Id[elem->id], elem->asnlen); 800 break; 801 802 case BE_ANY: 803 fputs("[BE_ANY!?]", stdout); 804 break; 805 806 default: 807 fputs("[be!?]", stdout); 808 break; 809 } 810 } 811 812 #ifdef notdef 813 /* 814 * This is a brute force ASN.1 printer: recurses to dump an entire structure. 815 * This will work for any ASN.1 stream, not just an SNMP PDU. 816 * 817 * By adding newlines and spaces at the correct places, this would print in 818 * Rose-Normal-Form. 819 * 820 * This is not currently used. 821 */ 822 static void 823 asn1_decode(u_char *p, u_int length) 824 { 825 struct be elem; 826 int i = 0; 827 828 while (i >= 0 && length > 0) { 829 i = asn1_parse(p, length, &elem); 830 if (i >= 0) { 831 fputs(" ", stdout); 832 asn1_print(&elem); 833 if (elem.type == BE_SEQ || elem.type == BE_PDU) { 834 fputs(" {", stdout); 835 asn1_decode(elem.data.raw, elem.asnlen); 836 fputs(" }", stdout); 837 } 838 length -= i; 839 p += i; 840 } 841 } 842 } 843 #endif 844 845 #ifdef LIBSMI 846 847 struct smi2be { 848 SmiBasetype basetype; 849 int be; 850 }; 851 852 static struct smi2be smi2betab[] = { 853 { SMI_BASETYPE_INTEGER32, BE_INT }, 854 { SMI_BASETYPE_OCTETSTRING, BE_STR }, 855 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR }, 856 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID }, 857 { SMI_BASETYPE_UNSIGNED32, BE_UNS }, 858 { SMI_BASETYPE_INTEGER64, BE_NONE }, 859 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 }, 860 { SMI_BASETYPE_FLOAT32, BE_NONE }, 861 { SMI_BASETYPE_FLOAT64, BE_NONE }, 862 { SMI_BASETYPE_FLOAT128, BE_NONE }, 863 { SMI_BASETYPE_ENUM, BE_INT }, 864 { SMI_BASETYPE_BITS, BE_STR }, 865 { SMI_BASETYPE_UNKNOWN, BE_NONE } 866 }; 867 868 static void smi_decode_oid(struct be *elem, unsigned int *oid, 869 unsigned int oidsize, unsigned int *oidlen) 870 { 871 u_char *p = (u_char *)elem->data.raw; 872 u_int32_t asnlen = elem->asnlen; 873 int o = 0, first = -1, i = asnlen; 874 875 for (*oidlen = 0; sflag && i-- > 0; p++) { 876 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 877 if (*p & ASN_LONGLEN) 878 continue; 879 880 /* 881 * first subitem encodes two items with 1st*OIDMUX+2nd 882 * (see X.690:1997 clause 8.19 for the details) 883 */ 884 if (first < 0) { 885 first = 0; 886 if (*oidlen < oidsize) { 887 oid[*oidlen] = o / OIDMUX; 888 if (oid[*oidlen] > 2) oid[*oidlen] = 2; 889 } 890 o -= oid[*oidlen] * OIDMUX; 891 if (*oidlen < oidsize) (*oidlen)++; 892 } 893 if (*oidlen < oidsize) { 894 oid[(*oidlen)++] = o; 895 } 896 o = 0; 897 } 898 } 899 900 static int smi_check_type(SmiBasetype basetype, int be) 901 { 902 int i; 903 904 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) { 905 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) { 906 return 1; 907 } 908 } 909 910 return 0; 911 } 912 913 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange, 914 struct be *elem) 915 { 916 int ok = 1; 917 918 switch (smiType->basetype) { 919 case SMI_BASETYPE_OBJECTIDENTIFIER: 920 case SMI_BASETYPE_OCTETSTRING: 921 if (smiRange->minValue.value.unsigned32 922 == smiRange->maxValue.value.unsigned32) { 923 ok = (elem->asnlen == smiRange->minValue.value.unsigned32); 924 } else { 925 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32 926 && elem->asnlen <= smiRange->maxValue.value.unsigned32); 927 } 928 break; 929 930 case SMI_BASETYPE_INTEGER32: 931 ok = (elem->data.integer >= smiRange->minValue.value.integer32 932 && elem->data.integer <= smiRange->maxValue.value.integer32); 933 break; 934 935 case SMI_BASETYPE_UNSIGNED32: 936 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32 937 && elem->data.uns <= smiRange->maxValue.value.unsigned32); 938 break; 939 940 case SMI_BASETYPE_UNSIGNED64: 941 /* XXX */ 942 break; 943 944 /* case SMI_BASETYPE_INTEGER64: SMIng */ 945 /* case SMI_BASETYPE_FLOAT32: SMIng */ 946 /* case SMI_BASETYPE_FLOAT64: SMIng */ 947 /* case SMI_BASETYPE_FLOAT128: SMIng */ 948 949 case SMI_BASETYPE_ENUM: 950 case SMI_BASETYPE_BITS: 951 case SMI_BASETYPE_UNKNOWN: 952 ok = 1; 953 break; 954 } 955 956 return ok; 957 } 958 959 static int smi_check_range(SmiType *smiType, struct be *elem) 960 { 961 SmiRange *smiRange; 962 int ok = 1; 963 964 for (smiRange = smiGetFirstRange(smiType); 965 smiRange; 966 smiRange = smiGetNextRange(smiRange)) { 967 968 ok = smi_check_a_range(smiType, smiRange, elem); 969 970 if (ok) { 971 break; 972 } 973 } 974 975 if (ok) { 976 SmiType *parentType; 977 parentType = smiGetParentType(smiType); 978 if (parentType) { 979 ok = smi_check_range(parentType, elem); 980 } 981 } 982 983 return ok; 984 } 985 986 static SmiNode *smi_print_variable(struct be *elem) 987 { 988 unsigned int oid[128], oidlen; 989 SmiNode *smiNode = NULL; 990 int i; 991 992 smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), &oidlen); 993 smiNode = smiGetNodeByOID(oidlen, oid); 994 if (! smiNode) { 995 asn1_print(elem); 996 return NULL; 997 } 998 if (vflag) { 999 fputs(smiGetNodeModule(smiNode)->name, stdout); 1000 fputs("::", stdout); 1001 } 1002 fputs(smiNode->name, stdout); 1003 if (smiNode->oidlen < oidlen) { 1004 for (i = smiNode->oidlen; i < oidlen; i++) { 1005 printf(".%u", oid[i]); 1006 } 1007 } 1008 return smiNode; 1009 } 1010 1011 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem) 1012 { 1013 unsigned int oid[128], oidlen; 1014 SmiType *smiType; 1015 SmiNamedNumber *nn; 1016 int i, done = 0; 1017 1018 if (! smiNode || ! (smiNode->nodekind 1019 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) { 1020 asn1_print(elem); 1021 return; 1022 } 1023 1024 if (elem->type == BE_NOSUCHOBJECT 1025 || elem->type == BE_NOSUCHINST 1026 || elem->type == BE_ENDOFMIBVIEW) { 1027 asn1_print(elem); 1028 return; 1029 } 1030 1031 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) { 1032 fputs("[notNotifyable]", stdout); 1033 } 1034 1035 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) { 1036 fputs("[notReadable]", stdout); 1037 } 1038 1039 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) { 1040 fputs("[notWritable]", stdout); 1041 } 1042 1043 if (RESPONSE_CLASS(pduid) 1044 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) { 1045 fputs("[noAccess]", stdout); 1046 } 1047 1048 smiType = smiGetNodeType(smiNode); 1049 if (! smiType) { 1050 asn1_print(elem); 1051 return; 1052 } 1053 1054 if (! smi_check_type(smiType->basetype, elem->type)) { 1055 fputs("[wrongType]", stdout); 1056 } 1057 1058 if (! smi_check_range(smiType, elem)) { 1059 fputs("[outOfRange]", stdout); 1060 } 1061 1062 /* resolve bits to named bits */ 1063 1064 /* check whether instance identifier is valid */ 1065 1066 /* apply display hints (integer, octetstring) */ 1067 1068 /* convert instance identifier to index type values */ 1069 1070 switch (elem->type) { 1071 case BE_OID: 1072 if (smiType->basetype == SMI_BASETYPE_BITS) { 1073 /* print bit labels */ 1074 } else { 1075 smi_decode_oid(elem, oid, 1076 sizeof(oid)/sizeof(unsigned int), 1077 &oidlen); 1078 smiNode = smiGetNodeByOID(oidlen, oid); 1079 if (smiNode) { 1080 if (vflag) { 1081 fputs(smiGetNodeModule(smiNode)->name, stdout); 1082 fputs("::", stdout); 1083 } 1084 fputs(smiNode->name, stdout); 1085 if (smiNode->oidlen < oidlen) { 1086 for (i = smiNode->oidlen; 1087 i < oidlen; i++) { 1088 printf(".%u", oid[i]); 1089 } 1090 } 1091 done++; 1092 } 1093 } 1094 break; 1095 1096 case BE_INT: 1097 if (smiType->basetype == SMI_BASETYPE_ENUM) { 1098 for (nn = smiGetFirstNamedNumber(smiType); 1099 nn; 1100 nn = smiGetNextNamedNumber(nn)) { 1101 if (nn->value.value.integer32 1102 == elem->data.integer) { 1103 fputs(nn->name, stdout); 1104 printf("(%d)", elem->data.integer); 1105 done++; 1106 break; 1107 } 1108 } 1109 } 1110 break; 1111 } 1112 1113 if (! done) { 1114 asn1_print(elem); 1115 } 1116 } 1117 #endif 1118 1119 /* 1120 * General SNMP header 1121 * SEQUENCE { 1122 * version INTEGER {version-1(0)}, 1123 * community OCTET STRING, 1124 * data ANY -- PDUs 1125 * } 1126 * PDUs for all but Trap: (see rfc1157 from page 15 on) 1127 * SEQUENCE { 1128 * request-id INTEGER, 1129 * error-status INTEGER, 1130 * error-index INTEGER, 1131 * varbindlist SEQUENCE OF 1132 * SEQUENCE { 1133 * name ObjectName, 1134 * value ObjectValue 1135 * } 1136 * } 1137 * PDU for Trap: 1138 * SEQUENCE { 1139 * enterprise OBJECT IDENTIFIER, 1140 * agent-addr NetworkAddress, 1141 * generic-trap INTEGER, 1142 * specific-trap INTEGER, 1143 * time-stamp TimeTicks, 1144 * varbindlist SEQUENCE OF 1145 * SEQUENCE { 1146 * name ObjectName, 1147 * value ObjectValue 1148 * } 1149 * } 1150 */ 1151 1152 /* 1153 * Decode SNMP varBind 1154 */ 1155 static void 1156 varbind_print(u_char pduid, const u_char *np, u_int length) 1157 { 1158 struct be elem; 1159 int count = 0, ind; 1160 #ifdef LIBSMI 1161 SmiNode *smiNode = NULL; 1162 #endif 1163 1164 /* Sequence of varBind */ 1165 if ((count = asn1_parse(np, length, &elem)) < 0) 1166 return; 1167 if (elem.type != BE_SEQ) { 1168 fputs("[!SEQ of varbind]", stdout); 1169 asn1_print(&elem); 1170 return; 1171 } 1172 if (count < length) 1173 printf("[%d extra after SEQ of varbind]", length - count); 1174 /* descend */ 1175 length = elem.asnlen; 1176 np = (u_char *)elem.data.raw; 1177 1178 for (ind = 1; length > 0; ind++) { 1179 const u_char *vbend; 1180 u_int vblength; 1181 1182 fputs(" ", stdout); 1183 1184 /* Sequence */ 1185 if ((count = asn1_parse(np, length, &elem)) < 0) 1186 return; 1187 if (elem.type != BE_SEQ) { 1188 fputs("[!varbind]", stdout); 1189 asn1_print(&elem); 1190 return; 1191 } 1192 vbend = np + count; 1193 vblength = length - count; 1194 /* descend */ 1195 length = elem.asnlen; 1196 np = (u_char *)elem.data.raw; 1197 1198 /* objName (OID) */ 1199 if ((count = asn1_parse(np, length, &elem)) < 0) 1200 return; 1201 if (elem.type != BE_OID) { 1202 fputs("[objName!=OID]", stdout); 1203 asn1_print(&elem); 1204 return; 1205 } 1206 #ifdef LIBSMI 1207 smiNode = smi_print_variable(&elem); 1208 #else 1209 asn1_print(&elem); 1210 #endif 1211 length -= count; 1212 np += count; 1213 1214 if (pduid != GETREQ && pduid != GETNEXTREQ 1215 && pduid != GETBULKREQ) 1216 fputs("=", stdout); 1217 1218 /* objVal (ANY) */ 1219 if ((count = asn1_parse(np, length, &elem)) < 0) 1220 return; 1221 if (pduid == GETREQ || pduid == GETNEXTREQ 1222 || pduid == GETBULKREQ) { 1223 if (elem.type != BE_NULL) { 1224 fputs("[objVal!=NULL]", stdout); 1225 asn1_print(&elem); 1226 } 1227 } else { 1228 if (elem.type != BE_NULL) { 1229 #ifdef LIBSMI 1230 smi_print_value(smiNode, pduid, &elem); 1231 #else 1232 asn1_print(&elem); 1233 #endif 1234 } 1235 } 1236 length = vblength; 1237 np = vbend; 1238 } 1239 } 1240 1241 /* 1242 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest, 1243 * GetBulk, Inform, V2Trap, and Report 1244 */ 1245 static void 1246 snmppdu_print(u_char pduid, const u_char *np, u_int length) 1247 { 1248 struct be elem; 1249 int count = 0, error; 1250 1251 /* reqId (Integer) */ 1252 if ((count = asn1_parse(np, length, &elem)) < 0) 1253 return; 1254 if (elem.type != BE_INT) { 1255 fputs("[reqId!=INT]", stdout); 1256 asn1_print(&elem); 1257 return; 1258 } 1259 if (vflag) 1260 printf("R=%d ", elem.data.integer); 1261 length -= count; 1262 np += count; 1263 1264 /* errorStatus (Integer) */ 1265 if ((count = asn1_parse(np, length, &elem)) < 0) 1266 return; 1267 if (elem.type != BE_INT) { 1268 fputs("[errorStatus!=INT]", stdout); 1269 asn1_print(&elem); 1270 return; 1271 } 1272 error = 0; 1273 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 1274 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 1275 && elem.data.integer != 0) { 1276 char errbuf[10]; 1277 printf("[errorStatus(%s)!=0]", 1278 DECODE_ErrorStatus(elem.data.integer)); 1279 } else if (pduid == GETBULKREQ) { 1280 printf(" N=%d", elem.data.integer); 1281 } else if (elem.data.integer != 0) { 1282 char errbuf[10]; 1283 printf(" %s", DECODE_ErrorStatus(elem.data.integer)); 1284 error = elem.data.integer; 1285 } 1286 length -= count; 1287 np += count; 1288 1289 /* errorIndex (Integer) */ 1290 if ((count = asn1_parse(np, length, &elem)) < 0) 1291 return; 1292 if (elem.type != BE_INT) { 1293 fputs("[errorIndex!=INT]", stdout); 1294 asn1_print(&elem); 1295 return; 1296 } 1297 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 1298 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 1299 && elem.data.integer != 0) 1300 printf("[errorIndex(%d)!=0]", elem.data.integer); 1301 else if (pduid == GETBULKREQ) 1302 printf(" M=%d", elem.data.integer); 1303 else if (elem.data.integer != 0) { 1304 if (!error) 1305 printf("[errorIndex(%d) w/o errorStatus]", 1306 elem.data.integer); 1307 else { 1308 printf("@%d", elem.data.integer); 1309 error = elem.data.integer; 1310 } 1311 } else if (error) { 1312 fputs("[errorIndex==0]", stdout); 1313 error = 0; 1314 } 1315 length -= count; 1316 np += count; 1317 1318 varbind_print(pduid, np, length); 1319 return; 1320 } 1321 1322 /* 1323 * Decode SNMP Trap PDU 1324 */ 1325 static void 1326 trappdu_print(const u_char *np, u_int length) 1327 { 1328 struct be elem; 1329 int count = 0, generic; 1330 1331 putchar(' '); 1332 1333 /* enterprise (oid) */ 1334 if ((count = asn1_parse(np, length, &elem)) < 0) 1335 return; 1336 if (elem.type != BE_OID) { 1337 fputs("[enterprise!=OID]", stdout); 1338 asn1_print(&elem); 1339 return; 1340 } 1341 asn1_print(&elem); 1342 length -= count; 1343 np += count; 1344 1345 putchar(' '); 1346 1347 /* agent-addr (inetaddr) */ 1348 if ((count = asn1_parse(np, length, &elem)) < 0) 1349 return; 1350 if (elem.type != BE_INETADDR) { 1351 fputs("[agent-addr!=INETADDR]", stdout); 1352 asn1_print(&elem); 1353 return; 1354 } 1355 asn1_print(&elem); 1356 length -= count; 1357 np += count; 1358 1359 /* generic-trap (Integer) */ 1360 if ((count = asn1_parse(np, length, &elem)) < 0) 1361 return; 1362 if (elem.type != BE_INT) { 1363 fputs("[generic-trap!=INT]", stdout); 1364 asn1_print(&elem); 1365 return; 1366 } 1367 generic = elem.data.integer; 1368 { 1369 char buf[10]; 1370 printf(" %s", DECODE_GenericTrap(generic)); 1371 } 1372 length -= count; 1373 np += count; 1374 1375 /* specific-trap (Integer) */ 1376 if ((count = asn1_parse(np, length, &elem)) < 0) 1377 return; 1378 if (elem.type != BE_INT) { 1379 fputs("[specific-trap!=INT]", stdout); 1380 asn1_print(&elem); 1381 return; 1382 } 1383 if (generic != GT_ENTERPRISE) { 1384 if (elem.data.integer != 0) 1385 printf("[specific-trap(%d)!=0]", elem.data.integer); 1386 } else 1387 printf(" s=%d", elem.data.integer); 1388 length -= count; 1389 np += count; 1390 1391 putchar(' '); 1392 1393 /* time-stamp (TimeTicks) */ 1394 if ((count = asn1_parse(np, length, &elem)) < 0) 1395 return; 1396 if (elem.type != BE_UNS) { /* XXX */ 1397 fputs("[time-stamp!=TIMETICKS]", stdout); 1398 asn1_print(&elem); 1399 return; 1400 } 1401 asn1_print(&elem); 1402 length -= count; 1403 np += count; 1404 1405 varbind_print (TRAP, np, length); 1406 return; 1407 } 1408 1409 /* 1410 * Decode arbitrary SNMP PDUs. 1411 */ 1412 static void 1413 pdu_print(const u_char *np, u_int length, int version) 1414 { 1415 struct be pdu; 1416 int count = 0; 1417 1418 /* PDU (Context) */ 1419 if ((count = asn1_parse(np, length, &pdu)) < 0) 1420 return; 1421 if (pdu.type != BE_PDU) { 1422 fputs("[no PDU]", stdout); 1423 return; 1424 } 1425 if (count < length) 1426 printf("[%d extra after PDU]", length - count); 1427 if (vflag) { 1428 fputs("{ ", stdout); 1429 } 1430 asn1_print(&pdu); 1431 fputs(" ", stdout); 1432 /* descend into PDU */ 1433 length = pdu.asnlen; 1434 np = (u_char *)pdu.data.raw; 1435 1436 if (version == SNMP_VERSION_1 && 1437 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ || 1438 pdu.id == V2TRAP || pdu.id == REPORT)) { 1439 printf("[v2 PDU in v1 message]"); 1440 return; 1441 } 1442 1443 if (version == SNMP_VERSION_2 && pdu.id == TRAP) { 1444 printf("[v1 PDU in v2 message]"); 1445 return; 1446 } 1447 1448 switch (pdu.id) { 1449 case TRAP: 1450 trappdu_print(np, length); 1451 break; 1452 case GETREQ: 1453 case GETNEXTREQ: 1454 case GETRESP: 1455 case SETREQ: 1456 case GETBULKREQ: 1457 case INFORMREQ: 1458 case V2TRAP: 1459 case REPORT: 1460 snmppdu_print(pdu.id, np, length); 1461 break; 1462 } 1463 1464 if (vflag) { 1465 fputs("} ", stdout); 1466 } 1467 } 1468 1469 /* 1470 * Decode a scoped SNMP PDU. 1471 */ 1472 static void 1473 scopedpdu_print(const u_char *np, u_int length, int version) 1474 { 1475 struct be elem; 1476 int i, count = 0; 1477 1478 /* Sequence */ 1479 if ((count = asn1_parse(np, length, &elem)) < 0) 1480 return; 1481 if (elem.type != BE_SEQ) { 1482 fputs("[!scoped PDU]", stdout); 1483 asn1_print(&elem); 1484 return; 1485 } 1486 length = elem.asnlen; 1487 np = (u_char *)elem.data.raw; 1488 1489 /* contextEngineID (OCTET STRING) */ 1490 if ((count = asn1_parse(np, length, &elem)) < 0) 1491 return; 1492 if (elem.type != BE_STR) { 1493 fputs("[contextEngineID!=STR]", stdout); 1494 asn1_print(&elem); 1495 return; 1496 } 1497 length -= count; 1498 np += count; 1499 1500 fputs("E= ", stdout); 1501 for (i = 0; i < (int)elem.asnlen; i++) { 1502 printf("0x%02X", elem.data.str[i]); 1503 } 1504 fputs(" ", stdout); 1505 1506 /* contextName (OCTET STRING) */ 1507 if ((count = asn1_parse(np, length, &elem)) < 0) 1508 return; 1509 if (elem.type != BE_STR) { 1510 fputs("[contextName!=STR]", stdout); 1511 asn1_print(&elem); 1512 return; 1513 } 1514 length -= count; 1515 np += count; 1516 1517 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1518 1519 pdu_print(np, length, version); 1520 } 1521 1522 /* 1523 * Decode SNMP Community Header (SNMPv1 and SNMPv2c) 1524 */ 1525 static void 1526 community_print(const u_char *np, u_int length, int version) 1527 { 1528 struct be elem; 1529 int count = 0; 1530 1531 /* Community (String) */ 1532 if ((count = asn1_parse(np, length, &elem)) < 0) 1533 return; 1534 if (elem.type != BE_STR) { 1535 fputs("[comm!=STR]", stdout); 1536 asn1_print(&elem); 1537 return; 1538 } 1539 /* default community */ 1540 if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 && 1541 strncmp((char *)elem.data.str, DEF_COMMUNITY, 1542 sizeof(DEF_COMMUNITY) - 1) == 0)) 1543 /* ! "public" */ 1544 printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 1545 length -= count; 1546 np += count; 1547 1548 pdu_print(np, length, version); 1549 } 1550 1551 /* 1552 * Decode SNMPv3 User-based Security Message Header (SNMPv3) 1553 */ 1554 static void 1555 usm_print(const u_char *np, u_int length) 1556 { 1557 struct be elem; 1558 int count = 0; 1559 1560 /* Sequence */ 1561 if ((count = asn1_parse(np, length, &elem)) < 0) 1562 return; 1563 if (elem.type != BE_SEQ) { 1564 fputs("[!usm]", stdout); 1565 asn1_print(&elem); 1566 return; 1567 } 1568 length = elem.asnlen; 1569 np = (u_char *)elem.data.raw; 1570 1571 /* msgAuthoritativeEngineID (OCTET STRING) */ 1572 if ((count = asn1_parse(np, length, &elem)) < 0) 1573 return; 1574 if (elem.type != BE_STR) { 1575 fputs("[msgAuthoritativeEngineID!=STR]", stdout); 1576 asn1_print(&elem); 1577 return; 1578 } 1579 length -= count; 1580 np += count; 1581 1582 /* msgAuthoritativeEngineBoots (INTEGER) */ 1583 if ((count = asn1_parse(np, length, &elem)) < 0) 1584 return; 1585 if (elem.type != BE_INT) { 1586 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout); 1587 asn1_print(&elem); 1588 return; 1589 } 1590 if (vflag) 1591 printf("B=%d ", elem.data.integer); 1592 length -= count; 1593 np += count; 1594 1595 /* msgAuthoritativeEngineTime (INTEGER) */ 1596 if ((count = asn1_parse(np, length, &elem)) < 0) 1597 return; 1598 if (elem.type != BE_INT) { 1599 fputs("[msgAuthoritativeEngineTime!=INT]", stdout); 1600 asn1_print(&elem); 1601 return; 1602 } 1603 if (vflag) 1604 printf("T=%d ", elem.data.integer); 1605 length -= count; 1606 np += count; 1607 1608 /* msgUserName (OCTET STRING) */ 1609 if ((count = asn1_parse(np, length, &elem)) < 0) 1610 return; 1611 if (elem.type != BE_STR) { 1612 fputs("[msgUserName!=STR]", stdout); 1613 asn1_print(&elem); 1614 return; 1615 } 1616 length -= count; 1617 np += count; 1618 1619 printf("U=%.*s ", (int)elem.asnlen, elem.data.str); 1620 1621 /* msgAuthenticationParameters (OCTET STRING) */ 1622 if ((count = asn1_parse(np, length, &elem)) < 0) 1623 return; 1624 if (elem.type != BE_STR) { 1625 fputs("[msgAuthenticationParameters!=STR]", stdout); 1626 asn1_print(&elem); 1627 return; 1628 } 1629 length -= count; 1630 np += count; 1631 1632 /* msgPrivacyParameters (OCTET STRING) */ 1633 if ((count = asn1_parse(np, length, &elem)) < 0) 1634 return; 1635 if (elem.type != BE_STR) { 1636 fputs("[msgPrivacyParameters!=STR]", stdout); 1637 asn1_print(&elem); 1638 return; 1639 } 1640 length -= count; 1641 np += count; 1642 1643 if (count < length) 1644 printf("[%d extra after usm SEQ]", length - count); 1645 } 1646 1647 /* 1648 * Decode SNMPv3 Message Header (SNMPv3) 1649 */ 1650 static void 1651 v3msg_print(const u_char *np, u_int length) 1652 { 1653 struct be elem; 1654 int count = 0; 1655 u_char flags; 1656 int model; 1657 const u_char *xnp = np; 1658 int xlength = length; 1659 1660 /* Sequence */ 1661 if ((count = asn1_parse(np, length, &elem)) < 0) 1662 return; 1663 if (elem.type != BE_SEQ) { 1664 fputs("[!message]", stdout); 1665 asn1_print(&elem); 1666 return; 1667 } 1668 length = elem.asnlen; 1669 np = (u_char *)elem.data.raw; 1670 1671 if (vflag) { 1672 fputs("{ ", stdout); 1673 } 1674 1675 /* msgID (INTEGER) */ 1676 if ((count = asn1_parse(np, length, &elem)) < 0) 1677 return; 1678 if (elem.type != BE_INT) { 1679 fputs("[msgID!=INT]", stdout); 1680 asn1_print(&elem); 1681 return; 1682 } 1683 length -= count; 1684 np += count; 1685 1686 /* msgMaxSize (INTEGER) */ 1687 if ((count = asn1_parse(np, length, &elem)) < 0) 1688 return; 1689 if (elem.type != BE_INT) { 1690 fputs("[msgMaxSize!=INT]", stdout); 1691 asn1_print(&elem); 1692 return; 1693 } 1694 length -= count; 1695 np += count; 1696 1697 /* msgFlags (OCTET STRING) */ 1698 if ((count = asn1_parse(np, length, &elem)) < 0) 1699 return; 1700 if (elem.type != BE_STR) { 1701 fputs("[msgFlags!=STR]", stdout); 1702 asn1_print(&elem); 1703 return; 1704 } 1705 if (elem.asnlen != 1) { 1706 printf("[msgFlags size %d]", elem.asnlen); 1707 return; 1708 } 1709 flags = elem.data.str[0]; 1710 if (flags != 0x00 && flags != 0x01 && flags != 0x03 1711 && flags != 0x04 && flags != 0x05 && flags != 0x07) { 1712 printf("[msgFlags=0x%02X]", flags); 1713 return; 1714 } 1715 length -= count; 1716 np += count; 1717 1718 fputs("F=", stdout); 1719 if (flags & 0x01) fputs("a", stdout); 1720 if (flags & 0x02) fputs("p", stdout); 1721 if (flags & 0x04) fputs("r", stdout); 1722 fputs(" ", stdout); 1723 1724 /* msgSecurityModel (INTEGER) */ 1725 if ((count = asn1_parse(np, length, &elem)) < 0) 1726 return; 1727 if (elem.type != BE_INT) { 1728 fputs("[msgSecurityModel!=INT]", stdout); 1729 asn1_print(&elem); 1730 return; 1731 } 1732 model = elem.data.integer; 1733 length -= count; 1734 np += count; 1735 1736 if (count < length) 1737 printf("[%d extra after message SEQ]", length - count); 1738 1739 if (vflag) { 1740 fputs("} ", stdout); 1741 } 1742 1743 if (model == 3) { 1744 if (vflag) { 1745 fputs("{ USM ", stdout); 1746 } 1747 } else { 1748 printf("[security model %d]", model); 1749 return; 1750 } 1751 1752 np = xnp + (np - xnp); 1753 length = xlength - (np - xnp); 1754 1755 /* msgSecurityParameters (OCTET STRING) */ 1756 if ((count = asn1_parse(np, length, &elem)) < 0) 1757 return; 1758 if (elem.type != BE_STR) { 1759 fputs("[msgSecurityParameters!=STR]", stdout); 1760 asn1_print(&elem); 1761 return; 1762 } 1763 length -= count; 1764 np += count; 1765 1766 if (model == 3) { 1767 usm_print(elem.data.str, elem.asnlen); 1768 if (vflag) { 1769 fputs("} ", stdout); 1770 } 1771 } 1772 1773 if (vflag) { 1774 fputs("{ ScopedPDU ", stdout); 1775 } 1776 1777 scopedpdu_print(np, length, 3); 1778 1779 if (vflag) { 1780 fputs("} ", stdout); 1781 } 1782 } 1783 1784 /* 1785 * Decode SNMP header and pass on to PDU printing routines 1786 */ 1787 void 1788 snmp_print(const u_char *np, u_int length) 1789 { 1790 struct be elem; 1791 int count = 0; 1792 int version = 0; 1793 1794 truncated = 0; 1795 1796 /* truncated packet? */ 1797 if (np + length > snapend) { 1798 truncated = 1; 1799 length = snapend - np; 1800 } 1801 1802 putchar(' '); 1803 1804 /* initial Sequence */ 1805 if ((count = asn1_parse(np, length, &elem)) < 0) 1806 return; 1807 if (elem.type != BE_SEQ) { 1808 fputs("[!init SEQ]", stdout); 1809 asn1_print(&elem); 1810 return; 1811 } 1812 if (count < length) 1813 printf("[%d extra after iSEQ]", length - count); 1814 /* descend */ 1815 length = elem.asnlen; 1816 np = (u_char *)elem.data.raw; 1817 1818 /* Version (INTEGER) */ 1819 if ((count = asn1_parse(np, length, &elem)) < 0) 1820 return; 1821 if (elem.type != BE_INT) { 1822 fputs("[version!=INT]", stdout); 1823 asn1_print(&elem); 1824 return; 1825 } 1826 1827 switch (elem.data.integer) { 1828 case SNMP_VERSION_1: 1829 case SNMP_VERSION_2: 1830 case SNMP_VERSION_3: 1831 if (vflag) 1832 printf("{ %s ", SnmpVersion[elem.data.integer]); 1833 break; 1834 default: 1835 printf("[version = %d]", elem.data.integer); 1836 return; 1837 } 1838 version = elem.data.integer; 1839 length -= count; 1840 np += count; 1841 1842 switch (version) { 1843 case SNMP_VERSION_1: 1844 case SNMP_VERSION_2: 1845 community_print(np, length, version); 1846 break; 1847 case SNMP_VERSION_3: 1848 v3msg_print(np, length); 1849 break; 1850 default: 1851 printf("[version = %d]", elem.data.integer); 1852 break; 1853 } 1854 1855 if (vflag) { 1856 fputs("} ", stdout); 1857 } 1858 } 1859