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