117680Spst/* 239297Sfenner * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 398524Sfenner * John Robert LoVerso. All rights reserved. 417680Spst * 598524Sfenner * Redistribution and use in source and binary forms, with or without 698524Sfenner * modification, are permitted provided that the following conditions 798524Sfenner * are met: 817680Spst * 998524Sfenner * 1. Redistributions of source code must retain the above copyright 1098524Sfenner * notice, this list of conditions and the following disclaimer. 1198524Sfenner * 1298524Sfenner * 2. Redistributions in binary form must reproduce the above copyright 1398524Sfenner * notice, this list of conditions and the following disclaimer in the 1498524Sfenner * documentation and/or other materials provided with the distribution. 1598524Sfenner * 1698524Sfenner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1798524Sfenner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1898524Sfenner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1998524Sfenner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2098524Sfenner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2198524Sfenner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2298524Sfenner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2398524Sfenner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2498524Sfenner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2598524Sfenner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2698524Sfenner * 2798524Sfenner * 2817680Spst * This implementation has been influenced by the CMU SNMP release, 2917680Spst * by Steve Waldbusser. However, this shares no code with that system. 3017680Spst * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_. 3117680Spst * Earlier forms of this implementation were derived and/or inspired by an 3217680Spst * awk script originally written by C. Philip Wood of LANL (but later 3317680Spst * heavily modified by John Robert LoVerso). The copyright notice for 3417680Spst * that work is preserved below, even though it may not rightly apply 3517680Spst * to this file. 3617680Spst * 3756893Sfenner * Support for SNMPv2c/SNMPv3 and the ability to link the module against 3856893Sfenner * the libsmi was added by J. Schoenwaelder, Copyright (c) 1999. 3956893Sfenner * 4017680Spst * This started out as a very simple program, but the incremental decoding 4117680Spst * (into the BE structure) complicated things. 4217680Spst * 4317680Spst # Los Alamos National Laboratory 4417680Spst # 4539297Sfenner # Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997 4617680Spst # This software was produced under a U.S. Government contract 4717680Spst # (W-7405-ENG-36) by Los Alamos National Laboratory, which is 4817680Spst # operated by the University of California for the U.S. Department 4917680Spst # of Energy. The U.S. Government is licensed to use, reproduce, 5017680Spst # and distribute this software. Permission is granted to the 5117680Spst # public to copy and use this software without charge, provided 5217680Spst # that this Notice and any statement of authorship are reproduced 5317680Spst # on all copies. Neither the Government nor the University makes 5417680Spst # any warranty, express or implied, or assumes any liability or 5517680Spst # responsibility for the use of this software. 5617680Spst # @(#)snmp.awk.x 1.1 (LANL) 1/15/90 5717680Spst */ 5826180Sfenner 5917680Spst#ifndef lint 60127668Sbmsstatic const char rcsid[] _U_ = 61190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-snmp.c,v 1.64 2005-05-06 07:56:53 guy Exp $ (LBL)"; 6217680Spst#endif 6317680Spst 6456893Sfenner#ifdef HAVE_CONFIG_H 6556893Sfenner#include "config.h" 6656893Sfenner#endif 6756893Sfenner 68127668Sbms#include <tcpdump-stdinc.h> 6917680Spst 7017680Spst#include <stdio.h> 7117680Spst#include <string.h> 7217680Spst 7356893Sfenner#ifdef HAVE_SMI_H 7456893Sfenner#include <smi.h> 7556893Sfenner#endif 7656893Sfenner 7717680Spst#include "interface.h" 7817680Spst#include "addrtoname.h" 7917680Spst 80146773Ssam#undef OPAQUE /* defined in <wingdi.h> */ 81146773Ssam 8217680Spst/* 8317680Spst * Universal ASN.1 types 8417680Spst * (we only care about the tag values for those allowed in the Internet SMI) 8517680Spst */ 86127668Sbmsconst char *Universal[] = { 8717680Spst "U-0", 8817680Spst "Boolean", 8917680Spst "Integer", 9017680Spst#define INTEGER 2 9117680Spst "Bitstring", 9217680Spst "String", 9317680Spst#define STRING 4 9417680Spst "Null", 9517680Spst#define ASN_NULL 5 9617680Spst "ObjID", 9717680Spst#define OBJECTID 6 9817680Spst "ObjectDes", 9917680Spst "U-8","U-9","U-10","U-11", /* 8-11 */ 10017680Spst "U-12","U-13","U-14","U-15", /* 12-15 */ 10117680Spst "Sequence", 10217680Spst#define SEQUENCE 16 10317680Spst "Set" 10417680Spst}; 10517680Spst 10617680Spst/* 10717680Spst * Application-wide ASN.1 types from the Internet SMI and their tags 10817680Spst */ 109127668Sbmsconst char *Application[] = { 11017680Spst "IpAddress", 11117680Spst#define IPADDR 0 11217680Spst "Counter", 11317680Spst#define COUNTER 1 11417680Spst "Gauge", 11517680Spst#define GAUGE 2 11617680Spst "TimeTicks", 11717680Spst#define TIMETICKS 3 11856893Sfenner "Opaque", 11956893Sfenner#define OPAQUE 4 12056893Sfenner "C-5", 12156893Sfenner "Counter64" 12256893Sfenner#define COUNTER64 6 12317680Spst}; 12417680Spst 12517680Spst/* 12617680Spst * Context-specific ASN.1 types for the SNMP PDUs and their tags 12717680Spst */ 128127668Sbmsconst char *Context[] = { 12917680Spst "GetRequest", 13017680Spst#define GETREQ 0 13117680Spst "GetNextRequest", 13217680Spst#define GETNEXTREQ 1 13317680Spst "GetResponse", 13417680Spst#define GETRESP 2 13517680Spst "SetRequest", 13617680Spst#define SETREQ 3 13756893Sfenner "Trap", 13817680Spst#define TRAP 4 13956893Sfenner "GetBulk", 14056893Sfenner#define GETBULKREQ 5 14156893Sfenner "Inform", 14256893Sfenner#define INFORMREQ 6 14356893Sfenner "V2Trap", 14456893Sfenner#define V2TRAP 7 14556893Sfenner "Report" 14656893Sfenner#define REPORT 8 14717680Spst}; 14817680Spst 14956893Sfenner#define NOTIFY_CLASS(x) (x == TRAP || x == V2TRAP || x == INFORMREQ) 15056893Sfenner#define READ_CLASS(x) (x == GETREQ || x == GETNEXTREQ || x == GETBULKREQ) 15156893Sfenner#define WRITE_CLASS(x) (x == SETREQ) 15256893Sfenner#define RESPONSE_CLASS(x) (x == GETRESP) 15356893Sfenner#define INTERNAL_CLASS(x) (x == REPORT) 15456893Sfenner 15517680Spst/* 15656893Sfenner * Context-specific ASN.1 types for the SNMP Exceptions and their tags 15756893Sfenner */ 158127668Sbmsconst char *Exceptions[] = { 15956893Sfenner "noSuchObject", 16056893Sfenner#define NOSUCHOBJECT 0 16156893Sfenner "noSuchInstance", 16256893Sfenner#define NOSUCHINSTANCE 1 16356893Sfenner "endOfMibView", 16456893Sfenner#define ENDOFMIBVIEW 2 16556893Sfenner}; 16656893Sfenner 16756893Sfenner/* 16817680Spst * Private ASN.1 types 16917680Spst * The Internet SMI does not specify any 17017680Spst */ 171127668Sbmsconst char *Private[] = { 17217680Spst "P-0" 17317680Spst}; 17417680Spst 17517680Spst/* 17617680Spst * error-status values for any SNMP PDU 17717680Spst */ 178127668Sbmsconst char *ErrorStatus[] = { 17917680Spst "noError", 18017680Spst "tooBig", 18117680Spst "noSuchName", 18217680Spst "badValue", 18317680Spst "readOnly", 18456893Sfenner "genErr", 18556893Sfenner "noAccess", 18656893Sfenner "wrongType", 18756893Sfenner "wrongLength", 18856893Sfenner "wrongEncoding", 18956893Sfenner "wrongValue", 19056893Sfenner "noCreation", 19156893Sfenner "inconsistentValue", 19256893Sfenner "resourceUnavailable", 19356893Sfenner "commitFailed", 19456893Sfenner "undoFailed", 19556893Sfenner "authorizationError", 19656893Sfenner "notWritable", 19756893Sfenner "inconsistentName" 19817680Spst}; 19917680Spst#define DECODE_ErrorStatus(e) \ 200127668Sbms ( e >= 0 && (size_t)e < sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) \ 20175115Sfenner ? ErrorStatus[e] \ 20275115Sfenner : (snprintf(errbuf, sizeof(errbuf), "err=%u", e), errbuf)) 20317680Spst 20417680Spst/* 20517680Spst * generic-trap values in the SNMP Trap-PDU 20617680Spst */ 207127668Sbmsconst char *GenericTrap[] = { 20817680Spst "coldStart", 20917680Spst "warmStart", 21017680Spst "linkDown", 21117680Spst "linkUp", 21217680Spst "authenticationFailure", 21317680Spst "egpNeighborLoss", 21417680Spst "enterpriseSpecific" 215127668Sbms#define GT_ENTERPRISE 6 21617680Spst}; 21717680Spst#define DECODE_GenericTrap(t) \ 218127668Sbms ( t >= 0 && (size_t)t < sizeof(GenericTrap)/sizeof(GenericTrap[0]) \ 21975115Sfenner ? GenericTrap[t] \ 22075115Sfenner : (snprintf(buf, sizeof(buf), "gt=%d", t), buf)) 22117680Spst 22217680Spst/* 22317680Spst * ASN.1 type class table 22417680Spst * Ties together the preceding Universal, Application, Context, and Private 22517680Spst * type definitions. 22617680Spst */ 22717680Spst#define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */ 22817680Spststruct { 229127668Sbms const char *name; 230127668Sbms const char **Id; 23117680Spst int numIDs; 23217680Spst } Class[] = { 23317680Spst defineCLASS(Universal), 23417680Spst#define UNIVERSAL 0 23517680Spst defineCLASS(Application), 23617680Spst#define APPLICATION 1 23717680Spst defineCLASS(Context), 23817680Spst#define CONTEXT 2 23917680Spst defineCLASS(Private), 24017680Spst#define PRIVATE 3 24156893Sfenner defineCLASS(Exceptions), 24256893Sfenner#define EXCEPTIONS 4 24317680Spst}; 24417680Spst 24517680Spst/* 24617680Spst * defined forms for ASN.1 types 24717680Spst */ 248127668Sbmsconst char *Form[] = { 24917680Spst "Primitive", 25017680Spst#define PRIMITIVE 0 25117680Spst "Constructed", 25217680Spst#define CONSTRUCTED 1 25317680Spst}; 25417680Spst 25517680Spst/* 25617680Spst * A structure for the OID tree for the compiled-in MIB. 25717680Spst * This is stored as a general-order tree. 25817680Spst */ 25917680Spststruct obj { 260127668Sbms const char *desc; /* name of object */ 26117680Spst u_char oid; /* sub-id following parent */ 26217680Spst u_char type; /* object type (unused) */ 26317680Spst struct obj *child, *next; /* child and next sibling pointers */ 26417680Spst} *objp = NULL; 26517680Spst 26617680Spst/* 26717680Spst * Include the compiled in SNMP MIB. "mib.h" is produced by feeding 26817680Spst * RFC-1156 format files into "makemib". "mib.h" MUST define at least 26917680Spst * a value for `mibroot'. 27017680Spst * 27117680Spst * In particular, this is gross, as this is including initialized structures, 27217680Spst * and by right shouldn't be an "include" file. 27317680Spst */ 27417680Spst#include "mib.h" 27517680Spst 27617680Spst/* 27717680Spst * This defines a list of OIDs which will be abbreviated on output. 27817680Spst * Currently, this includes the prefixes for the Internet MIB, the 27917680Spst * private enterprises tree, and the experimental tree. 28017680Spst */ 28117680Spststruct obj_abrev { 282127668Sbms const char *prefix; /* prefix for this abrev */ 28317680Spst struct obj *node; /* pointer into object table */ 284127668Sbms const char *oid; /* ASN.1 encoded OID */ 28517680Spst} obj_abrev_list[] = { 28617680Spst#ifndef NO_ABREV_MIB 28717680Spst /* .iso.org.dod.internet.mgmt.mib */ 28817680Spst { "", &_mib_obj, "\53\6\1\2\1" }, 28917680Spst#endif 29017680Spst#ifndef NO_ABREV_ENTER 29117680Spst /* .iso.org.dod.internet.private.enterprises */ 29217680Spst { "E:", &_enterprises_obj, "\53\6\1\4\1" }, 29317680Spst#endif 29417680Spst#ifndef NO_ABREV_EXPERI 29517680Spst /* .iso.org.dod.internet.experimental */ 29617680Spst { "X:", &_experimental_obj, "\53\6\1\3" }, 29717680Spst#endif 29856893Sfenner#ifndef NO_ABBREV_SNMPMODS 29956893Sfenner /* .iso.org.dod.internet.snmpV2.snmpModules */ 30056893Sfenner { "S:", &_snmpModules_obj, "\53\6\1\6\3" }, 30156893Sfenner#endif 30217680Spst { 0,0,0 } 30317680Spst}; 30417680Spst 30517680Spst/* 30617680Spst * This is used in the OID print routine to walk down the object tree 30717680Spst * rooted at `mibroot'. 30817680Spst */ 30917680Spst#define OBJ_PRINT(o, suppressdot) \ 31017680Spst{ \ 31117680Spst if (objp) { \ 31217680Spst do { \ 31317680Spst if ((o) == objp->oid) \ 31417680Spst break; \ 31517680Spst } while ((objp = objp->next) != NULL); \ 31617680Spst } \ 31717680Spst if (objp) { \ 31817680Spst printf(suppressdot?"%s":".%s", objp->desc); \ 31917680Spst objp = objp->child; \ 32017680Spst } else \ 32117680Spst printf(suppressdot?"%u":".%u", (o)); \ 32217680Spst} 32317680Spst 32417680Spst/* 32517680Spst * This is the definition for the Any-Data-Type storage used purely for 32617680Spst * temporary internal representation while decoding an ASN.1 data stream. 32717680Spst */ 32817680Spststruct be { 32917680Spst u_int32_t asnlen; 33017680Spst union { 33117680Spst caddr_t raw; 33217680Spst int32_t integer; 33317680Spst u_int32_t uns; 33417680Spst const u_char *str; 33556893Sfenner struct { 33656893Sfenner u_int32_t high; 33756893Sfenner u_int32_t low; 33856893Sfenner } uns64; 33917680Spst } data; 34017680Spst u_short id; 34117680Spst u_char form, class; /* tag info */ 34217680Spst u_char type; 34317680Spst#define BE_ANY 255 34417680Spst#define BE_NONE 0 34517680Spst#define BE_NULL 1 34617680Spst#define BE_OCTET 2 34717680Spst#define BE_OID 3 34817680Spst#define BE_INT 4 34917680Spst#define BE_UNS 5 35017680Spst#define BE_STR 6 35117680Spst#define BE_SEQ 7 35217680Spst#define BE_INETADDR 8 35317680Spst#define BE_PDU 9 35456893Sfenner#define BE_UNS64 10 35556893Sfenner#define BE_NOSUCHOBJECT 128 35656893Sfenner#define BE_NOSUCHINST 129 35756893Sfenner#define BE_ENDOFMIBVIEW 130 35817680Spst}; 35917680Spst 36017680Spst/* 36156893Sfenner * SNMP versions recognized by this module 36256893Sfenner */ 363127668Sbmsconst char *SnmpVersion[] = { 36456893Sfenner "SNMPv1", 36556893Sfenner#define SNMP_VERSION_1 0 36656893Sfenner "SNMPv2c", 36756893Sfenner#define SNMP_VERSION_2 1 36856893Sfenner "SNMPv2u", 36956893Sfenner#define SNMP_VERSION_2U 2 37056893Sfenner "SNMPv3" 37156893Sfenner#define SNMP_VERSION_3 3 37256893Sfenner}; 37356893Sfenner 37456893Sfenner/* 37517680Spst * Defaults for SNMP PDU components 37617680Spst */ 37717680Spst#define DEF_COMMUNITY "public" 37817680Spst 37917680Spst/* 38017680Spst * constants for ASN.1 decoding 38117680Spst */ 38217680Spst#define OIDMUX 40 38317680Spst#define ASNLEN_INETADDR 4 38417680Spst#define ASN_SHIFT7 7 38517680Spst#define ASN_SHIFT8 8 38617680Spst#define ASN_BIT8 0x80 38717680Spst#define ASN_LONGLEN 0x80 38817680Spst 38917680Spst#define ASN_ID_BITS 0x1f 39017680Spst#define ASN_FORM_BITS 0x20 39117680Spst#define ASN_FORM_SHIFT 5 39217680Spst#define ASN_CLASS_BITS 0xc0 39317680Spst#define ASN_CLASS_SHIFT 6 39417680Spst 39517680Spst#define ASN_ID_EXT 0x1f /* extension ID in tag field */ 39617680Spst 39717680Spst/* 39817680Spst * This decodes the next ASN.1 object in the stream pointed to by "p" 39917680Spst * (and of real-length "len") and stores the intermediate data in the 40017680Spst * provided BE object. 40117680Spst * 40217680Spst * This returns -l if it fails (i.e., the ASN.1 stream is not valid). 40317680Spst * O/w, this returns the number of bytes parsed from "p". 40417680Spst */ 40517680Spststatic int 40617680Spstasn1_parse(register const u_char *p, u_int len, struct be *elem) 40717680Spst{ 40817680Spst u_char form, class, id; 40917680Spst int i, hdr; 41017680Spst 41117680Spst elem->asnlen = 0; 41217680Spst elem->type = BE_ANY; 41317680Spst if (len < 1) { 414146773Ssam fputs("[nothing to parse]", stdout); 41517680Spst return -1; 41617680Spst } 417146773Ssam TCHECK(*p); 41817680Spst 41917680Spst /* 42017680Spst * it would be nice to use a bit field, but you can't depend on them. 42117680Spst * +---+---+---+---+---+---+---+---+ 42217680Spst * + class |frm| id | 42317680Spst * +---+---+---+---+---+---+---+---+ 42417680Spst * 7 6 5 4 3 2 1 0 42517680Spst */ 42617680Spst id = *p & ASN_ID_BITS; /* lower 5 bits, range 00-1f */ 42717680Spst#ifdef notdef 42817680Spst form = (*p & 0xe0) >> 5; /* move upper 3 bits to lower 3 */ 42917680Spst class = form >> 1; /* bits 7&6 -> bits 1&0, range 0-3 */ 43017680Spst form &= 0x1; /* bit 5 -> bit 0, range 0-1 */ 43117680Spst#else 43226180Sfenner form = (u_char)(*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT; 43326180Sfenner class = (u_char)(*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT; 43417680Spst#endif 43517680Spst elem->form = form; 43617680Spst elem->class = class; 43717680Spst elem->id = id; 43817680Spst p++; len--; hdr = 1; 43917680Spst /* extended tag field */ 44017680Spst if (id == ASN_ID_EXT) { 441146773Ssam /* 442146773Ssam * The ID follows, as a sequence of octets with the 443146773Ssam * 8th bit set and the remaining 7 bits being 444146773Ssam * the next 7 bits of the value, terminated with 445146773Ssam * an octet with the 8th bit not set. 446146773Ssam * 447146773Ssam * First, assemble all the octets with the 8th 448146773Ssam * bit set. XXX - this doesn't handle a value 449146773Ssam * that won't fit in 32 bits. 450146773Ssam */ 451146773Ssam for (id = 0; *p & ASN_BIT8; len--, hdr++, p++) { 452146773Ssam if (len < 1) { 453146773Ssam fputs("[Xtagfield?]", stdout); 454146773Ssam return -1; 455146773Ssam } 456146773Ssam TCHECK(*p); 45717680Spst id = (id << 7) | (*p & ~ASN_BIT8); 458146773Ssam } 459146773Ssam if (len < 1) { 460146773Ssam fputs("[Xtagfield?]", stdout); 46117680Spst return -1; 46217680Spst } 463146773Ssam TCHECK(*p); 46417680Spst elem->id = id = (id << 7) | *p; 46517680Spst --len; 46617680Spst ++hdr; 46717680Spst ++p; 46817680Spst } 46917680Spst if (len < 1) { 470146773Ssam fputs("[no asnlen]", stdout); 47117680Spst return -1; 47217680Spst } 473146773Ssam TCHECK(*p); 47417680Spst elem->asnlen = *p; 47517680Spst p++; len--; hdr++; 47617680Spst if (elem->asnlen & ASN_BIT8) { 477127668Sbms u_int32_t noct = elem->asnlen % ASN_BIT8; 47817680Spst elem->asnlen = 0; 47917680Spst if (len < noct) { 480146773Ssam printf("[asnlen? %d<%d]", len, noct); 48117680Spst return -1; 48217680Spst } 483146773Ssam TCHECK2(*p, noct); 48498524Sfenner for (; noct-- > 0; len--, hdr++) 48517680Spst elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++; 48617680Spst } 48717680Spst if (len < elem->asnlen) { 488146773Ssam printf("[len%d<asnlen%u]", len, elem->asnlen); 489146773Ssam return -1; 49017680Spst } 49117680Spst if (form >= sizeof(Form)/sizeof(Form[0])) { 492146773Ssam printf("[form?%d]", form); 49317680Spst return -1; 49417680Spst } 49517680Spst if (class >= sizeof(Class)/sizeof(Class[0])) { 496146773Ssam printf("[class?%c/%d]", *Form[form], class); 49717680Spst return -1; 49817680Spst } 49926180Sfenner if ((int)id >= Class[class].numIDs) { 500146773Ssam printf("[id?%c/%s/%d]", *Form[form], Class[class].name, id); 50117680Spst return -1; 50217680Spst } 50317680Spst 50417680Spst switch (form) { 50517680Spst case PRIMITIVE: 50617680Spst switch (class) { 50717680Spst case UNIVERSAL: 50817680Spst switch (id) { 50917680Spst case STRING: 51017680Spst elem->type = BE_STR; 51117680Spst elem->data.str = p; 51217680Spst break; 51317680Spst 51417680Spst case INTEGER: { 51517680Spst register int32_t data; 51617680Spst elem->type = BE_INT; 51717680Spst data = 0; 51817680Spst 519146773Ssam TCHECK2(*p, elem->asnlen); 52017680Spst if (*p & ASN_BIT8) /* negative */ 52117680Spst data = -1; 52217680Spst for (i = elem->asnlen; i-- > 0; p++) 52317680Spst data = (data << ASN_SHIFT8) | *p; 52417680Spst elem->data.integer = data; 52517680Spst break; 52617680Spst } 52717680Spst 52817680Spst case OBJECTID: 52917680Spst elem->type = BE_OID; 53017680Spst elem->data.raw = (caddr_t)p; 53117680Spst break; 53217680Spst 53317680Spst case ASN_NULL: 53417680Spst elem->type = BE_NULL; 53517680Spst elem->data.raw = NULL; 53617680Spst break; 53717680Spst 53817680Spst default: 53917680Spst elem->type = BE_OCTET; 54017680Spst elem->data.raw = (caddr_t)p; 54117680Spst printf("[P/U/%s]", 54217680Spst Class[class].Id[id]); 54317680Spst break; 54417680Spst } 54517680Spst break; 54617680Spst 54717680Spst case APPLICATION: 54817680Spst switch (id) { 54917680Spst case IPADDR: 55017680Spst elem->type = BE_INETADDR; 55117680Spst elem->data.raw = (caddr_t)p; 55217680Spst break; 55317680Spst 55417680Spst case COUNTER: 55517680Spst case GAUGE: 55617680Spst case TIMETICKS: { 55717680Spst register u_int32_t data; 558146773Ssam TCHECK2(*p, elem->asnlen); 55917680Spst elem->type = BE_UNS; 56017680Spst data = 0; 56117680Spst for (i = elem->asnlen; i-- > 0; p++) 56217680Spst data = (data << 8) + *p; 56317680Spst elem->data.uns = data; 56417680Spst break; 56517680Spst } 56617680Spst 56756893Sfenner case COUNTER64: { 56856893Sfenner register u_int32_t high, low; 569146773Ssam TCHECK2(*p, elem->asnlen); 57056893Sfenner elem->type = BE_UNS64; 57156893Sfenner high = 0, low = 0; 57256893Sfenner for (i = elem->asnlen; i-- > 0; p++) { 573127668Sbms high = (high << 8) | 57456893Sfenner ((low & 0xFF000000) >> 24); 57556893Sfenner low = (low << 8) | *p; 57656893Sfenner } 57756893Sfenner elem->data.uns64.high = high; 57856893Sfenner elem->data.uns64.low = low; 57956893Sfenner break; 58056893Sfenner } 58156893Sfenner 58217680Spst default: 58317680Spst elem->type = BE_OCTET; 58417680Spst elem->data.raw = (caddr_t)p; 58517680Spst printf("[P/A/%s]", 58617680Spst Class[class].Id[id]); 58717680Spst break; 58817680Spst } 58917680Spst break; 59017680Spst 59156893Sfenner case CONTEXT: 59256893Sfenner switch (id) { 59356893Sfenner case NOSUCHOBJECT: 59456893Sfenner elem->type = BE_NOSUCHOBJECT; 59556893Sfenner elem->data.raw = NULL; 59656893Sfenner break; 59756893Sfenner 59856893Sfenner case NOSUCHINSTANCE: 59956893Sfenner elem->type = BE_NOSUCHINST; 60056893Sfenner elem->data.raw = NULL; 60156893Sfenner break; 60256893Sfenner 60356893Sfenner case ENDOFMIBVIEW: 60456893Sfenner elem->type = BE_ENDOFMIBVIEW; 60556893Sfenner elem->data.raw = NULL; 60656893Sfenner break; 60756893Sfenner } 60856893Sfenner break; 60956893Sfenner 61017680Spst default: 611146773Ssam printf("[P/%s/%s]", 612146773Ssam Class[class].name, Class[class].Id[id]); 613146773Ssam TCHECK2(*p, elem->asnlen); 61417680Spst elem->type = BE_OCTET; 61517680Spst elem->data.raw = (caddr_t)p; 61617680Spst break; 61717680Spst } 61817680Spst break; 61917680Spst 62017680Spst case CONSTRUCTED: 62117680Spst switch (class) { 62217680Spst case UNIVERSAL: 62317680Spst switch (id) { 62417680Spst case SEQUENCE: 62517680Spst elem->type = BE_SEQ; 62617680Spst elem->data.raw = (caddr_t)p; 62717680Spst break; 62817680Spst 62917680Spst default: 63017680Spst elem->type = BE_OCTET; 63117680Spst elem->data.raw = (caddr_t)p; 63217680Spst printf("C/U/%s", Class[class].Id[id]); 63317680Spst break; 63417680Spst } 63517680Spst break; 63617680Spst 63717680Spst case CONTEXT: 63817680Spst elem->type = BE_PDU; 63917680Spst elem->data.raw = (caddr_t)p; 64017680Spst break; 64117680Spst 64217680Spst default: 64317680Spst elem->type = BE_OCTET; 64417680Spst elem->data.raw = (caddr_t)p; 64517680Spst printf("C/%s/%s", 64617680Spst Class[class].name, Class[class].Id[id]); 64717680Spst break; 64817680Spst } 64917680Spst break; 65017680Spst } 65117680Spst p += elem->asnlen; 65217680Spst len -= elem->asnlen; 65317680Spst return elem->asnlen + hdr; 654146773Ssam 655146773Ssamtrunc: 656146773Ssam fputs("[|snmp]", stdout); 657146773Ssam return -1; 65817680Spst} 65917680Spst 66017680Spst/* 66117680Spst * Display the ASN.1 object represented by the BE object. 66217680Spst * This used to be an integral part of asn1_parse() before the intermediate 66317680Spst * BE form was added. 66417680Spst */ 665146773Ssamstatic int 66617680Spstasn1_print(struct be *elem) 66717680Spst{ 66817680Spst u_char *p = (u_char *)elem->data.raw; 66917680Spst u_int32_t asnlen = elem->asnlen; 670127668Sbms u_int32_t i; 67117680Spst 67217680Spst switch (elem->type) { 67317680Spst 67417680Spst case BE_OCTET: 675146773Ssam TCHECK2(*p, asnlen); 67675115Sfenner for (i = asnlen; i-- > 0; p++) 67717680Spst printf("_%.2x", *p); 67817680Spst break; 67917680Spst 68017680Spst case BE_NULL: 68117680Spst break; 68217680Spst 68317680Spst case BE_OID: { 684146773Ssam int o = 0, first = -1, i = asnlen; 68517680Spst 68656893Sfenner if (!sflag && !nflag && asnlen > 2) { 68717680Spst struct obj_abrev *a = &obj_abrev_list[0]; 688146773Ssam size_t a_len = strlen(a->oid); 68917680Spst for (; a->node; a++) { 690146773Ssam TCHECK2(*p, a_len); 691146773Ssam if (memcmp(a->oid, (char *)p, a_len) == 0) { 69217680Spst objp = a->node->child; 69317680Spst i -= strlen(a->oid); 69417680Spst p += strlen(a->oid); 69517680Spst fputs(a->prefix, stdout); 69617680Spst first = 1; 69717680Spst break; 69817680Spst } 69917680Spst } 70017680Spst } 70156893Sfenner 70256893Sfenner for (; !sflag && i-- > 0; p++) { 703146773Ssam TCHECK(*p); 70417680Spst o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 70517680Spst if (*p & ASN_LONGLEN) 70656893Sfenner continue; 707127668Sbms 70817680Spst /* 70917680Spst * first subitem encodes two items with 1st*OIDMUX+2nd 710111726Sfenner * (see X.690:1997 clause 8.19 for the details) 71117680Spst */ 71217680Spst if (first < 0) { 713111726Sfenner int s; 71417680Spst if (!nflag) 71517680Spst objp = mibroot; 71617680Spst first = 0; 717111726Sfenner s = o / OIDMUX; 718111726Sfenner if (s > 2) s = 2; 719111726Sfenner OBJ_PRINT(s, first); 720111726Sfenner o -= s * OIDMUX; 72117680Spst } 72217680Spst OBJ_PRINT(o, first); 72317680Spst if (--first < 0) 72417680Spst first = 0; 72517680Spst o = 0; 72617680Spst } 72717680Spst break; 72817680Spst } 72917680Spst 73017680Spst case BE_INT: 73117680Spst printf("%d", elem->data.integer); 73217680Spst break; 73317680Spst 73417680Spst case BE_UNS: 73556893Sfenner printf("%u", elem->data.uns); 73617680Spst break; 73717680Spst 73856893Sfenner case BE_UNS64: { /* idea borrowed from by Marshall Rose */ 73956893Sfenner double d; 74056893Sfenner int j, carry; 74156893Sfenner char *cpf, *cpl, last[6], first[30]; 74256893Sfenner if (elem->data.uns64.high == 0) { 74356893Sfenner printf("%u", elem->data.uns64.low); 74456893Sfenner break; 74556893Sfenner } 74656893Sfenner d = elem->data.uns64.high * 4294967296.0; /* 2^32 */ 747127668Sbms if (elem->data.uns64.high <= 0x1fffff) { 74856893Sfenner d += elem->data.uns64.low; 74998524Sfenner#if 0 /*is looks illegal, but what is the intention?*/ 75056893Sfenner printf("%.f", d); 75156893Sfenner#else 75256893Sfenner printf("%f", d); 75356893Sfenner#endif 75456893Sfenner break; 75556893Sfenner } 75656893Sfenner d += (elem->data.uns64.low & 0xfffff000); 75798524Sfenner#if 0 /*is looks illegal, but what is the intention?*/ 75875115Sfenner snprintf(first, sizeof(first), "%.f", d); 75956893Sfenner#else 76075115Sfenner snprintf(first, sizeof(first), "%f", d); 76156893Sfenner#endif 76275115Sfenner snprintf(last, sizeof(last), "%5.5d", 76375115Sfenner elem->data.uns64.low & 0xfff); 76456893Sfenner for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4; 76556893Sfenner cpl >= last; 76656893Sfenner cpf--, cpl--) { 76756893Sfenner j = carry + (*cpf - '0') + (*cpl - '0'); 76856893Sfenner if (j > 9) { 76956893Sfenner j -= 10; 77056893Sfenner carry = 1; 77156893Sfenner } else { 77256893Sfenner carry = 0; 77356893Sfenner } 77456893Sfenner *cpf = j + '0'; 77556893Sfenner } 77656893Sfenner fputs(first, stdout); 77756893Sfenner break; 77856893Sfenner } 77956893Sfenner 78017680Spst case BE_STR: { 78117680Spst register int printable = 1, first = 1; 78217680Spst const u_char *p = elem->data.str; 783146773Ssam TCHECK2(*p, asnlen); 78417680Spst for (i = asnlen; printable && i-- > 0; p++) 78517680Spst printable = isprint(*p) || isspace(*p); 78617680Spst p = elem->data.str; 78717680Spst if (printable) { 78817680Spst putchar('"'); 789147899Ssam if (fn_printn(p, asnlen, snapend)) { 790147899Ssam putchar('"'); 791147899Ssam goto trunc; 792147899Ssam } 79317680Spst putchar('"'); 79417680Spst } else 79517680Spst for (i = asnlen; i-- > 0; p++) { 79617680Spst printf(first ? "%.2x" : "_%.2x", *p); 79717680Spst first = 0; 79817680Spst } 79917680Spst break; 80017680Spst } 80117680Spst 80217680Spst case BE_SEQ: 80317680Spst printf("Seq(%u)", elem->asnlen); 80417680Spst break; 80517680Spst 80656893Sfenner case BE_INETADDR: 80717680Spst if (asnlen != ASNLEN_INETADDR) 80817680Spst printf("[inetaddr len!=%d]", ASNLEN_INETADDR); 809146773Ssam TCHECK2(*p, asnlen); 810127668Sbms for (i = asnlen; i-- != 0; p++) { 81156893Sfenner printf((i == asnlen-1) ? "%u" : ".%u", *p); 81217680Spst } 81317680Spst break; 81417680Spst 81556893Sfenner case BE_NOSUCHOBJECT: 81656893Sfenner case BE_NOSUCHINST: 81756893Sfenner case BE_ENDOFMIBVIEW: 81856893Sfenner printf("[%s]", Class[EXCEPTIONS].Id[elem->id]); 81956893Sfenner break; 82056893Sfenner 82117680Spst case BE_PDU: 82217680Spst printf("%s(%u)", 82317680Spst Class[CONTEXT].Id[elem->id], elem->asnlen); 82417680Spst break; 82517680Spst 82617680Spst case BE_ANY: 82717680Spst fputs("[BE_ANY!?]", stdout); 82817680Spst break; 82917680Spst 83017680Spst default: 83117680Spst fputs("[be!?]", stdout); 83217680Spst break; 83317680Spst } 834146773Ssam return 0; 835146773Ssam 836146773Ssamtrunc: 837146773Ssam fputs("[|snmp]", stdout); 838146773Ssam return -1; 83917680Spst} 84017680Spst 84117680Spst#ifdef notdef 84217680Spst/* 84317680Spst * This is a brute force ASN.1 printer: recurses to dump an entire structure. 84417680Spst * This will work for any ASN.1 stream, not just an SNMP PDU. 84517680Spst * 84617680Spst * By adding newlines and spaces at the correct places, this would print in 84717680Spst * Rose-Normal-Form. 84817680Spst * 84917680Spst * This is not currently used. 85017680Spst */ 85117680Spststatic void 85217680Spstasn1_decode(u_char *p, u_int length) 85317680Spst{ 85417680Spst struct be elem; 85517680Spst int i = 0; 85617680Spst 85717680Spst while (i >= 0 && length > 0) { 85817680Spst i = asn1_parse(p, length, &elem); 85917680Spst if (i >= 0) { 86017680Spst fputs(" ", stdout); 861146773Ssam if (asn1_print(&elem) < 0) 862146773Ssam return; 86317680Spst if (elem.type == BE_SEQ || elem.type == BE_PDU) { 86417680Spst fputs(" {", stdout); 86517680Spst asn1_decode(elem.data.raw, elem.asnlen); 86617680Spst fputs(" }", stdout); 86717680Spst } 86817680Spst length -= i; 86917680Spst p += i; 87017680Spst } 87117680Spst } 87217680Spst} 87317680Spst#endif 87417680Spst 87556893Sfenner#ifdef LIBSMI 87656893Sfenner 87756893Sfennerstruct smi2be { 87856893Sfenner SmiBasetype basetype; 87956893Sfenner int be; 88056893Sfenner}; 88156893Sfenner 88275115Sfennerstatic struct smi2be smi2betab[] = { 88356893Sfenner { SMI_BASETYPE_INTEGER32, BE_INT }, 88456893Sfenner { SMI_BASETYPE_OCTETSTRING, BE_STR }, 88556893Sfenner { SMI_BASETYPE_OCTETSTRING, BE_INETADDR }, 88656893Sfenner { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID }, 88756893Sfenner { SMI_BASETYPE_UNSIGNED32, BE_UNS }, 88856893Sfenner { SMI_BASETYPE_INTEGER64, BE_NONE }, 88956893Sfenner { SMI_BASETYPE_UNSIGNED64, BE_UNS64 }, 89056893Sfenner { SMI_BASETYPE_FLOAT32, BE_NONE }, 89156893Sfenner { SMI_BASETYPE_FLOAT64, BE_NONE }, 89256893Sfenner { SMI_BASETYPE_FLOAT128, BE_NONE }, 89356893Sfenner { SMI_BASETYPE_ENUM, BE_INT }, 89456893Sfenner { SMI_BASETYPE_BITS, BE_STR }, 89556893Sfenner { SMI_BASETYPE_UNKNOWN, BE_NONE } 89656893Sfenner}; 89756893Sfenner 898146773Ssamstatic int 899146773Ssamsmi_decode_oid(struct be *elem, unsigned int *oid, 900146773Ssam unsigned int oidsize, unsigned int *oidlen) 90156893Sfenner{ 90256893Sfenner u_char *p = (u_char *)elem->data.raw; 90356893Sfenner u_int32_t asnlen = elem->asnlen; 90456893Sfenner int o = 0, first = -1, i = asnlen; 90556893Sfenner 90656893Sfenner for (*oidlen = 0; sflag && i-- > 0; p++) { 907146773Ssam TCHECK(*p); 90856893Sfenner o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8); 90956893Sfenner if (*p & ASN_LONGLEN) 91056893Sfenner continue; 911127668Sbms 91256893Sfenner /* 91356893Sfenner * first subitem encodes two items with 1st*OIDMUX+2nd 914111726Sfenner * (see X.690:1997 clause 8.19 for the details) 91556893Sfenner */ 91656893Sfenner if (first < 0) { 91756893Sfenner first = 0; 91898524Sfenner if (*oidlen < oidsize) { 919111726Sfenner oid[*oidlen] = o / OIDMUX; 920111726Sfenner if (oid[*oidlen] > 2) oid[*oidlen] = 2; 92198524Sfenner } 922111726Sfenner o -= oid[*oidlen] * OIDMUX; 923111726Sfenner if (*oidlen < oidsize) (*oidlen)++; 92456893Sfenner } 92598524Sfenner if (*oidlen < oidsize) { 926111726Sfenner oid[(*oidlen)++] = o; 92798524Sfenner } 92856893Sfenner o = 0; 92956893Sfenner } 930146773Ssam return 0; 931146773Ssam 932146773Ssamtrunc: 933146773Ssam fputs("[|snmp]", stdout); 934146773Ssam return -1; 93556893Sfenner} 93656893Sfenner 93756893Sfennerstatic int smi_check_type(SmiBasetype basetype, int be) 93856893Sfenner{ 93956893Sfenner int i; 94056893Sfenner 94156893Sfenner for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) { 94256893Sfenner if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) { 94356893Sfenner return 1; 94456893Sfenner } 94556893Sfenner } 94656893Sfenner 94756893Sfenner return 0; 94856893Sfenner} 94956893Sfenner 95056893Sfennerstatic int smi_check_a_range(SmiType *smiType, SmiRange *smiRange, 95156893Sfenner struct be *elem) 95256893Sfenner{ 95375115Sfenner int ok = 1; 954127668Sbms 95556893Sfenner switch (smiType->basetype) { 95656893Sfenner case SMI_BASETYPE_OBJECTIDENTIFIER: 95756893Sfenner case SMI_BASETYPE_OCTETSTRING: 95856893Sfenner if (smiRange->minValue.value.unsigned32 95956893Sfenner == smiRange->maxValue.value.unsigned32) { 96056893Sfenner ok = (elem->asnlen == smiRange->minValue.value.unsigned32); 96156893Sfenner } else { 96256893Sfenner ok = (elem->asnlen >= smiRange->minValue.value.unsigned32 96356893Sfenner && elem->asnlen <= smiRange->maxValue.value.unsigned32); 96456893Sfenner } 96556893Sfenner break; 96656893Sfenner 96756893Sfenner case SMI_BASETYPE_INTEGER32: 96856893Sfenner ok = (elem->data.integer >= smiRange->minValue.value.integer32 96956893Sfenner && elem->data.integer <= smiRange->maxValue.value.integer32); 97056893Sfenner break; 971127668Sbms 97256893Sfenner case SMI_BASETYPE_UNSIGNED32: 97356893Sfenner ok = (elem->data.uns >= smiRange->minValue.value.unsigned32 97456893Sfenner && elem->data.uns <= smiRange->maxValue.value.unsigned32); 97556893Sfenner break; 976127668Sbms 97756893Sfenner case SMI_BASETYPE_UNSIGNED64: 97856893Sfenner /* XXX */ 97956893Sfenner break; 98056893Sfenner 98156893Sfenner /* case SMI_BASETYPE_INTEGER64: SMIng */ 98256893Sfenner /* case SMI_BASETYPE_FLOAT32: SMIng */ 98356893Sfenner /* case SMI_BASETYPE_FLOAT64: SMIng */ 98456893Sfenner /* case SMI_BASETYPE_FLOAT128: SMIng */ 98556893Sfenner 98656893Sfenner case SMI_BASETYPE_ENUM: 98756893Sfenner case SMI_BASETYPE_BITS: 98856893Sfenner case SMI_BASETYPE_UNKNOWN: 98956893Sfenner ok = 1; 99056893Sfenner break; 991146773Ssam 992146773Ssam default: 993146773Ssam ok = 0; 994146773Ssam break; 99556893Sfenner } 99656893Sfenner 99756893Sfenner return ok; 99856893Sfenner} 99956893Sfenner 100056893Sfennerstatic int smi_check_range(SmiType *smiType, struct be *elem) 100156893Sfenner{ 100256893Sfenner SmiRange *smiRange; 100356893Sfenner int ok = 1; 100456893Sfenner 100575115Sfenner for (smiRange = smiGetFirstRange(smiType); 100656893Sfenner smiRange; 100756893Sfenner smiRange = smiGetNextRange(smiRange)) { 100856893Sfenner 100956893Sfenner ok = smi_check_a_range(smiType, smiRange, elem); 101075115Sfenner 101156893Sfenner if (ok) { 101256893Sfenner break; 101356893Sfenner } 101456893Sfenner } 101556893Sfenner 101698524Sfenner if (ok) { 101756893Sfenner SmiType *parentType; 101875115Sfenner parentType = smiGetParentType(smiType); 101956893Sfenner if (parentType) { 102056893Sfenner ok = smi_check_range(parentType, elem); 102156893Sfenner } 102256893Sfenner } 102356893Sfenner 102456893Sfenner return ok; 102556893Sfenner} 102656893Sfenner 1027146773Ssamstatic SmiNode *smi_print_variable(struct be *elem, int *status) 102856893Sfenner{ 102956893Sfenner unsigned int oid[128], oidlen; 103056893Sfenner SmiNode *smiNode = NULL; 1031146773Ssam unsigned int i; 103256893Sfenner 1033146773Ssam *status = smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), 1034146773Ssam &oidlen); 1035146773Ssam if (*status < 0) 1036146773Ssam return NULL; 103756893Sfenner smiNode = smiGetNodeByOID(oidlen, oid); 103856893Sfenner if (! smiNode) { 1039146773Ssam *status = asn1_print(elem); 104056893Sfenner return NULL; 104156893Sfenner } 104256893Sfenner if (vflag) { 104375115Sfenner fputs(smiGetNodeModule(smiNode)->name, stdout); 104456893Sfenner fputs("::", stdout); 104556893Sfenner } 104656893Sfenner fputs(smiNode->name, stdout); 104756893Sfenner if (smiNode->oidlen < oidlen) { 104856893Sfenner for (i = smiNode->oidlen; i < oidlen; i++) { 104956893Sfenner printf(".%u", oid[i]); 105056893Sfenner } 105156893Sfenner } 1052146773Ssam *status = 0; 105356893Sfenner return smiNode; 105456893Sfenner} 105556893Sfenner 1056146773Ssamstatic int 1057146773Ssamsmi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem) 105856893Sfenner{ 1059146773Ssam unsigned int i, oid[128], oidlen; 106056893Sfenner SmiType *smiType; 106156893Sfenner SmiNamedNumber *nn; 1062146773Ssam int done = 0; 106356893Sfenner 106456893Sfenner if (! smiNode || ! (smiNode->nodekind 106556893Sfenner & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) { 1066146773Ssam return asn1_print(elem); 106756893Sfenner } 106856893Sfenner 106975115Sfenner if (elem->type == BE_NOSUCHOBJECT 107075115Sfenner || elem->type == BE_NOSUCHINST 107175115Sfenner || elem->type == BE_ENDOFMIBVIEW) { 1072146773Ssam return asn1_print(elem); 107375115Sfenner } 107475115Sfenner 107556893Sfenner if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) { 107656893Sfenner fputs("[notNotifyable]", stdout); 107756893Sfenner } 107856893Sfenner 107956893Sfenner if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) { 108056893Sfenner fputs("[notReadable]", stdout); 108156893Sfenner } 108256893Sfenner 108356893Sfenner if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) { 108456893Sfenner fputs("[notWritable]", stdout); 108556893Sfenner } 108656893Sfenner 108756893Sfenner if (RESPONSE_CLASS(pduid) 108856893Sfenner && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) { 108956893Sfenner fputs("[noAccess]", stdout); 109056893Sfenner } 109156893Sfenner 109275115Sfenner smiType = smiGetNodeType(smiNode); 109356893Sfenner if (! smiType) { 1094146773Ssam return asn1_print(elem); 109556893Sfenner } 109656893Sfenner 109775115Sfenner if (! smi_check_type(smiType->basetype, elem->type)) { 109875115Sfenner fputs("[wrongType]", stdout); 109975115Sfenner } 110075115Sfenner 110156893Sfenner if (! smi_check_range(smiType, elem)) { 110298524Sfenner fputs("[outOfRange]", stdout); 110356893Sfenner } 110456893Sfenner 110556893Sfenner /* resolve bits to named bits */ 110656893Sfenner 110756893Sfenner /* check whether instance identifier is valid */ 110856893Sfenner 110956893Sfenner /* apply display hints (integer, octetstring) */ 111056893Sfenner 111156893Sfenner /* convert instance identifier to index type values */ 1112127668Sbms 111356893Sfenner switch (elem->type) { 111456893Sfenner case BE_OID: 111575115Sfenner if (smiType->basetype == SMI_BASETYPE_BITS) { 111656893Sfenner /* print bit labels */ 111756893Sfenner } else { 111898524Sfenner smi_decode_oid(elem, oid, 111998524Sfenner sizeof(oid)/sizeof(unsigned int), 112098524Sfenner &oidlen); 112156893Sfenner smiNode = smiGetNodeByOID(oidlen, oid); 112256893Sfenner if (smiNode) { 112356893Sfenner if (vflag) { 112475115Sfenner fputs(smiGetNodeModule(smiNode)->name, stdout); 112556893Sfenner fputs("::", stdout); 112656893Sfenner } 112756893Sfenner fputs(smiNode->name, stdout); 112856893Sfenner if (smiNode->oidlen < oidlen) { 1129127668Sbms for (i = smiNode->oidlen; 113056893Sfenner i < oidlen; i++) { 113156893Sfenner printf(".%u", oid[i]); 113256893Sfenner } 113356893Sfenner } 113456893Sfenner done++; 113556893Sfenner } 113656893Sfenner } 113756893Sfenner break; 113856893Sfenner 113956893Sfenner case BE_INT: 114075115Sfenner if (smiType->basetype == SMI_BASETYPE_ENUM) { 114175115Sfenner for (nn = smiGetFirstNamedNumber(smiType); 114256893Sfenner nn; 114356893Sfenner nn = smiGetNextNamedNumber(nn)) { 114456893Sfenner if (nn->value.value.integer32 114556893Sfenner == elem->data.integer) { 114656893Sfenner fputs(nn->name, stdout); 114756893Sfenner printf("(%d)", elem->data.integer); 114856893Sfenner done++; 114956893Sfenner break; 115056893Sfenner } 115156893Sfenner } 115256893Sfenner } 115356893Sfenner break; 115456893Sfenner } 115556893Sfenner 115656893Sfenner if (! done) { 1157146773Ssam return asn1_print(elem); 115856893Sfenner } 1159146773Ssam return 0; 116056893Sfenner} 116156893Sfenner#endif 116256893Sfenner 116317680Spst/* 116417680Spst * General SNMP header 116517680Spst * SEQUENCE { 116617680Spst * version INTEGER {version-1(0)}, 116717680Spst * community OCTET STRING, 116817680Spst * data ANY -- PDUs 116917680Spst * } 117017680Spst * PDUs for all but Trap: (see rfc1157 from page 15 on) 117117680Spst * SEQUENCE { 117217680Spst * request-id INTEGER, 117317680Spst * error-status INTEGER, 117417680Spst * error-index INTEGER, 117517680Spst * varbindlist SEQUENCE OF 117617680Spst * SEQUENCE { 117717680Spst * name ObjectName, 117817680Spst * value ObjectValue 117917680Spst * } 118017680Spst * } 118117680Spst * PDU for Trap: 118217680Spst * SEQUENCE { 118317680Spst * enterprise OBJECT IDENTIFIER, 118417680Spst * agent-addr NetworkAddress, 118517680Spst * generic-trap INTEGER, 118617680Spst * specific-trap INTEGER, 118717680Spst * time-stamp TimeTicks, 118817680Spst * varbindlist SEQUENCE OF 118917680Spst * SEQUENCE { 119017680Spst * name ObjectName, 119117680Spst * value ObjectValue 119217680Spst * } 119317680Spst * } 119417680Spst */ 119517680Spst 119617680Spst/* 119717680Spst * Decode SNMP varBind 119817680Spst */ 119917680Spststatic void 120056893Sfennervarbind_print(u_char pduid, const u_char *np, u_int length) 120117680Spst{ 120217680Spst struct be elem; 120317680Spst int count = 0, ind; 120456893Sfenner#ifdef LIBSMI 120556893Sfenner SmiNode *smiNode = NULL; 120656893Sfenner#endif 1207146773Ssam int status; 120817680Spst 120917680Spst /* Sequence of varBind */ 121017680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 121117680Spst return; 121217680Spst if (elem.type != BE_SEQ) { 121317680Spst fputs("[!SEQ of varbind]", stdout); 121417680Spst asn1_print(&elem); 121517680Spst return; 121617680Spst } 1217127668Sbms if ((u_int)count < length) 121817680Spst printf("[%d extra after SEQ of varbind]", length - count); 121917680Spst /* descend */ 122017680Spst length = elem.asnlen; 122117680Spst np = (u_char *)elem.data.raw; 122217680Spst 122317680Spst for (ind = 1; length > 0; ind++) { 122417680Spst const u_char *vbend; 122517680Spst u_int vblength; 122617680Spst 122756893Sfenner fputs(" ", stdout); 122817680Spst 122917680Spst /* Sequence */ 123017680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 123117680Spst return; 123217680Spst if (elem.type != BE_SEQ) { 123317680Spst fputs("[!varbind]", stdout); 123417680Spst asn1_print(&elem); 123517680Spst return; 123617680Spst } 123717680Spst vbend = np + count; 123817680Spst vblength = length - count; 123917680Spst /* descend */ 124017680Spst length = elem.asnlen; 124117680Spst np = (u_char *)elem.data.raw; 124217680Spst 124317680Spst /* objName (OID) */ 124417680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 124517680Spst return; 124617680Spst if (elem.type != BE_OID) { 124717680Spst fputs("[objName!=OID]", stdout); 124817680Spst asn1_print(&elem); 124917680Spst return; 125017680Spst } 125156893Sfenner#ifdef LIBSMI 1252146773Ssam smiNode = smi_print_variable(&elem, &status); 125356893Sfenner#else 1254146773Ssam status = asn1_print(&elem); 125556893Sfenner#endif 1256146773Ssam if (status < 0) 1257146773Ssam return; 125817680Spst length -= count; 125917680Spst np += count; 126017680Spst 126156893Sfenner if (pduid != GETREQ && pduid != GETNEXTREQ 126256893Sfenner && pduid != GETBULKREQ) 1263146773Ssam fputs("=", stdout); 126417680Spst 126517680Spst /* objVal (ANY) */ 126617680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 126717680Spst return; 126856893Sfenner if (pduid == GETREQ || pduid == GETNEXTREQ 126956893Sfenner || pduid == GETBULKREQ) { 127017680Spst if (elem.type != BE_NULL) { 127117680Spst fputs("[objVal!=NULL]", stdout); 1272146773Ssam if (asn1_print(&elem) < 0) 1273146773Ssam return; 127417680Spst } 127556893Sfenner } else { 127656893Sfenner if (elem.type != BE_NULL) { 127756893Sfenner#ifdef LIBSMI 1278146773Ssam status = smi_print_value(smiNode, pduid, &elem); 127956893Sfenner#else 1280146773Ssam status = asn1_print(&elem); 128156893Sfenner#endif 128256893Sfenner } 1283146773Ssam if (status < 0) 1284146773Ssam return; 128556893Sfenner } 128617680Spst length = vblength; 128717680Spst np = vbend; 128817680Spst } 128917680Spst} 129017680Spst 129117680Spst/* 129256893Sfenner * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest, 129356893Sfenner * GetBulk, Inform, V2Trap, and Report 129417680Spst */ 129517680Spststatic void 1296146773Ssamsnmppdu_print(u_short pduid, const u_char *np, u_int length) 129717680Spst{ 129817680Spst struct be elem; 129917680Spst int count = 0, error; 130017680Spst 130117680Spst /* reqId (Integer) */ 130217680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 130317680Spst return; 130417680Spst if (elem.type != BE_INT) { 130517680Spst fputs("[reqId!=INT]", stdout); 130617680Spst asn1_print(&elem); 130717680Spst return; 130817680Spst } 130975115Sfenner if (vflag) 131075115Sfenner printf("R=%d ", elem.data.integer); 131117680Spst length -= count; 131217680Spst np += count; 131317680Spst 131417680Spst /* errorStatus (Integer) */ 131517680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 131617680Spst return; 131717680Spst if (elem.type != BE_INT) { 131817680Spst fputs("[errorStatus!=INT]", stdout); 131917680Spst asn1_print(&elem); 132017680Spst return; 132117680Spst } 132217680Spst error = 0; 132356893Sfenner if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 132456893Sfenner || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 132517680Spst && elem.data.integer != 0) { 1326147899Ssam char errbuf[20]; 132717680Spst printf("[errorStatus(%s)!=0]", 132817680Spst DECODE_ErrorStatus(elem.data.integer)); 132956893Sfenner } else if (pduid == GETBULKREQ) { 133056893Sfenner printf(" N=%d", elem.data.integer); 133117680Spst } else if (elem.data.integer != 0) { 1332147899Ssam char errbuf[20]; 133317680Spst printf(" %s", DECODE_ErrorStatus(elem.data.integer)); 133417680Spst error = elem.data.integer; 133517680Spst } 133617680Spst length -= count; 133717680Spst np += count; 133817680Spst 133917680Spst /* errorIndex (Integer) */ 134017680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 134117680Spst return; 134217680Spst if (elem.type != BE_INT) { 134317680Spst fputs("[errorIndex!=INT]", stdout); 134417680Spst asn1_print(&elem); 134517680Spst return; 134617680Spst } 134756893Sfenner if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ 134856893Sfenner || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT) 134917680Spst && elem.data.integer != 0) 135017680Spst printf("[errorIndex(%d)!=0]", elem.data.integer); 135156893Sfenner else if (pduid == GETBULKREQ) 135256893Sfenner printf(" M=%d", elem.data.integer); 135317680Spst else if (elem.data.integer != 0) { 135417680Spst if (!error) 135517680Spst printf("[errorIndex(%d) w/o errorStatus]", 135617680Spst elem.data.integer); 135717680Spst else { 135817680Spst printf("@%d", elem.data.integer); 135917680Spst error = elem.data.integer; 136017680Spst } 136117680Spst } else if (error) { 136217680Spst fputs("[errorIndex==0]", stdout); 136317680Spst error = 0; 136417680Spst } 136517680Spst length -= count; 136617680Spst np += count; 136717680Spst 136856893Sfenner varbind_print(pduid, np, length); 136917680Spst return; 137017680Spst} 137117680Spst 137217680Spst/* 137317680Spst * Decode SNMP Trap PDU 137417680Spst */ 137517680Spststatic void 137656893Sfennertrappdu_print(const u_char *np, u_int length) 137717680Spst{ 137817680Spst struct be elem; 137917680Spst int count = 0, generic; 138017680Spst 138117680Spst putchar(' '); 138217680Spst 138317680Spst /* enterprise (oid) */ 138417680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 138517680Spst return; 138617680Spst if (elem.type != BE_OID) { 138717680Spst fputs("[enterprise!=OID]", stdout); 138817680Spst asn1_print(&elem); 138917680Spst return; 139017680Spst } 1391146773Ssam if (asn1_print(&elem) < 0) 1392146773Ssam return; 139317680Spst length -= count; 139417680Spst np += count; 139517680Spst 139617680Spst putchar(' '); 139717680Spst 139817680Spst /* agent-addr (inetaddr) */ 139917680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 140017680Spst return; 140117680Spst if (elem.type != BE_INETADDR) { 140217680Spst fputs("[agent-addr!=INETADDR]", stdout); 140317680Spst asn1_print(&elem); 140417680Spst return; 140517680Spst } 1406146773Ssam if (asn1_print(&elem) < 0) 1407146773Ssam return; 140817680Spst length -= count; 140917680Spst np += count; 141017680Spst 141117680Spst /* generic-trap (Integer) */ 141217680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 141317680Spst return; 141417680Spst if (elem.type != BE_INT) { 141517680Spst fputs("[generic-trap!=INT]", stdout); 141617680Spst asn1_print(&elem); 141717680Spst return; 141817680Spst } 141917680Spst generic = elem.data.integer; 142017680Spst { 1421147899Ssam char buf[20]; 142217680Spst printf(" %s", DECODE_GenericTrap(generic)); 142317680Spst } 142417680Spst length -= count; 142517680Spst np += count; 142617680Spst 142717680Spst /* specific-trap (Integer) */ 142817680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 142917680Spst return; 143017680Spst if (elem.type != BE_INT) { 143117680Spst fputs("[specific-trap!=INT]", stdout); 143217680Spst asn1_print(&elem); 143317680Spst return; 143417680Spst } 143517680Spst if (generic != GT_ENTERPRISE) { 143617680Spst if (elem.data.integer != 0) 143717680Spst printf("[specific-trap(%d)!=0]", elem.data.integer); 143817680Spst } else 143917680Spst printf(" s=%d", elem.data.integer); 144017680Spst length -= count; 144117680Spst np += count; 144217680Spst 144317680Spst putchar(' '); 144417680Spst 144517680Spst /* time-stamp (TimeTicks) */ 144617680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 144717680Spst return; 144817680Spst if (elem.type != BE_UNS) { /* XXX */ 144917680Spst fputs("[time-stamp!=TIMETICKS]", stdout); 145017680Spst asn1_print(&elem); 145117680Spst return; 145217680Spst } 1453146773Ssam if (asn1_print(&elem) < 0) 1454146773Ssam return; 145517680Spst length -= count; 145617680Spst np += count; 145717680Spst 145856893Sfenner varbind_print (TRAP, np, length); 145917680Spst return; 146017680Spst} 146117680Spst 146217680Spst/* 146356893Sfenner * Decode arbitrary SNMP PDUs. 146417680Spst */ 146556893Sfennerstatic void 146656893Sfennerpdu_print(const u_char *np, u_int length, int version) 146717680Spst{ 146856893Sfenner struct be pdu; 146917680Spst int count = 0; 147017680Spst 147156893Sfenner /* PDU (Context) */ 147256893Sfenner if ((count = asn1_parse(np, length, &pdu)) < 0) 147356893Sfenner return; 147456893Sfenner if (pdu.type != BE_PDU) { 147556893Sfenner fputs("[no PDU]", stdout); 147656893Sfenner return; 147756893Sfenner } 1478127668Sbms if ((u_int)count < length) 147956893Sfenner printf("[%d extra after PDU]", length - count); 148075115Sfenner if (vflag) { 148175115Sfenner fputs("{ ", stdout); 148275115Sfenner } 1483146773Ssam if (asn1_print(&pdu) < 0) 1484146773Ssam return; 148575115Sfenner fputs(" ", stdout); 148656893Sfenner /* descend into PDU */ 148756893Sfenner length = pdu.asnlen; 148856893Sfenner np = (u_char *)pdu.data.raw; 148917680Spst 149056893Sfenner if (version == SNMP_VERSION_1 && 1491127668Sbms (pdu.id == GETBULKREQ || pdu.id == INFORMREQ || 149256893Sfenner pdu.id == V2TRAP || pdu.id == REPORT)) { 149356893Sfenner printf("[v2 PDU in v1 message]"); 149456893Sfenner return; 149517680Spst } 149617680Spst 149756893Sfenner if (version == SNMP_VERSION_2 && pdu.id == TRAP) { 149856893Sfenner printf("[v1 PDU in v2 message]"); 149956893Sfenner return; 150056893Sfenner } 150117680Spst 150256893Sfenner switch (pdu.id) { 150356893Sfenner case TRAP: 150456893Sfenner trappdu_print(np, length); 150556893Sfenner break; 150656893Sfenner case GETREQ: 150756893Sfenner case GETNEXTREQ: 150856893Sfenner case GETRESP: 150956893Sfenner case SETREQ: 151056893Sfenner case GETBULKREQ: 151156893Sfenner case INFORMREQ: 151256893Sfenner case V2TRAP: 151356893Sfenner case REPORT: 151456893Sfenner snmppdu_print(pdu.id, np, length); 151556893Sfenner break; 151656893Sfenner } 151775115Sfenner 151875115Sfenner if (vflag) { 1519127668Sbms fputs(" } ", stdout); 152075115Sfenner } 152156893Sfenner} 152256893Sfenner 152356893Sfenner/* 152456893Sfenner * Decode a scoped SNMP PDU. 152556893Sfenner */ 152656893Sfennerstatic void 152756893Sfennerscopedpdu_print(const u_char *np, u_int length, int version) 152856893Sfenner{ 152956893Sfenner struct be elem; 153056893Sfenner int i, count = 0; 153156893Sfenner 153256893Sfenner /* Sequence */ 153317680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 153417680Spst return; 153517680Spst if (elem.type != BE_SEQ) { 153656893Sfenner fputs("[!scoped PDU]", stdout); 153717680Spst asn1_print(&elem); 153817680Spst return; 153917680Spst } 154017680Spst length = elem.asnlen; 154117680Spst np = (u_char *)elem.data.raw; 154256893Sfenner 154356893Sfenner /* contextEngineID (OCTET STRING) */ 154417680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 154517680Spst return; 154656893Sfenner if (elem.type != BE_STR) { 154756893Sfenner fputs("[contextEngineID!=STR]", stdout); 154817680Spst asn1_print(&elem); 154917680Spst return; 155017680Spst } 155156893Sfenner length -= count; 155256893Sfenner np += count; 155356893Sfenner 155456893Sfenner fputs("E= ", stdout); 155556893Sfenner for (i = 0; i < (int)elem.asnlen; i++) { 155656893Sfenner printf("0x%02X", elem.data.str[i]); 155756893Sfenner } 155856893Sfenner fputs(" ", stdout); 155956893Sfenner 156056893Sfenner /* contextName (OCTET STRING) */ 156156893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 156217680Spst return; 156356893Sfenner if (elem.type != BE_STR) { 156456893Sfenner fputs("[contextName!=STR]", stdout); 156556893Sfenner asn1_print(&elem); 156656893Sfenner return; 156717680Spst } 156817680Spst length -= count; 156917680Spst np += count; 157017680Spst 157156893Sfenner printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 157256893Sfenner 157356893Sfenner pdu_print(np, length, version); 157456893Sfenner} 157556893Sfenner 157656893Sfenner/* 157756893Sfenner * Decode SNMP Community Header (SNMPv1 and SNMPv2c) 157856893Sfenner */ 157956893Sfennerstatic void 158056893Sfennercommunity_print(const u_char *np, u_int length, int version) 158156893Sfenner{ 158256893Sfenner struct be elem; 158356893Sfenner int count = 0; 158456893Sfenner 158517680Spst /* Community (String) */ 158617680Spst if ((count = asn1_parse(np, length, &elem)) < 0) 158717680Spst return; 158817680Spst if (elem.type != BE_STR) { 158917680Spst fputs("[comm!=STR]", stdout); 159017680Spst asn1_print(&elem); 159117680Spst return; 159217680Spst } 159317680Spst /* default community */ 1594111726Sfenner if (!(elem.asnlen == sizeof(DEF_COMMUNITY) - 1 && 1595111726Sfenner strncmp((char *)elem.data.str, DEF_COMMUNITY, 1596111726Sfenner sizeof(DEF_COMMUNITY) - 1) == 0)) 159717680Spst /* ! "public" */ 159817680Spst printf("C=%.*s ", (int)elem.asnlen, elem.data.str); 159917680Spst length -= count; 160017680Spst np += count; 160117680Spst 160256893Sfenner pdu_print(np, length, version); 160356893Sfenner} 160456893Sfenner 160556893Sfenner/* 160656893Sfenner * Decode SNMPv3 User-based Security Message Header (SNMPv3) 160756893Sfenner */ 160856893Sfennerstatic void 160956893Sfennerusm_print(const u_char *np, u_int length) 161056893Sfenner{ 161156893Sfenner struct be elem; 161256893Sfenner int count = 0; 161356893Sfenner 161456893Sfenner /* Sequence */ 161556893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 161617680Spst return; 161756893Sfenner if (elem.type != BE_SEQ) { 161856893Sfenner fputs("[!usm]", stdout); 161956893Sfenner asn1_print(&elem); 162017680Spst return; 162117680Spst } 162256893Sfenner length = elem.asnlen; 162356893Sfenner np = (u_char *)elem.data.raw; 162456893Sfenner 162556893Sfenner /* msgAuthoritativeEngineID (OCTET STRING) */ 162656893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 162756893Sfenner return; 162856893Sfenner if (elem.type != BE_STR) { 162956893Sfenner fputs("[msgAuthoritativeEngineID!=STR]", stdout); 163056893Sfenner asn1_print(&elem); 163156893Sfenner return; 163256893Sfenner } 163356893Sfenner length -= count; 163456893Sfenner np += count; 163556893Sfenner 163656893Sfenner /* msgAuthoritativeEngineBoots (INTEGER) */ 163756893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 163856893Sfenner return; 163956893Sfenner if (elem.type != BE_INT) { 164056893Sfenner fputs("[msgAuthoritativeEngineBoots!=INT]", stdout); 164156893Sfenner asn1_print(&elem); 164256893Sfenner return; 164356893Sfenner } 1644127668Sbms if (vflag) 164556893Sfenner printf("B=%d ", elem.data.integer); 164656893Sfenner length -= count; 164756893Sfenner np += count; 164856893Sfenner 164956893Sfenner /* msgAuthoritativeEngineTime (INTEGER) */ 165056893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 165156893Sfenner return; 165256893Sfenner if (elem.type != BE_INT) { 165356893Sfenner fputs("[msgAuthoritativeEngineTime!=INT]", stdout); 165456893Sfenner asn1_print(&elem); 165556893Sfenner return; 165656893Sfenner } 1657127668Sbms if (vflag) 165856893Sfenner printf("T=%d ", elem.data.integer); 165956893Sfenner length -= count; 166056893Sfenner np += count; 166156893Sfenner 166256893Sfenner /* msgUserName (OCTET STRING) */ 166356893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 166456893Sfenner return; 166556893Sfenner if (elem.type != BE_STR) { 166656893Sfenner fputs("[msgUserName!=STR]", stdout); 166756893Sfenner asn1_print(&elem); 166856893Sfenner return; 166956893Sfenner } 167056893Sfenner length -= count; 167156893Sfenner np += count; 167256893Sfenner 167356893Sfenner printf("U=%.*s ", (int)elem.asnlen, elem.data.str); 167456893Sfenner 167556893Sfenner /* msgAuthenticationParameters (OCTET STRING) */ 167656893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 167756893Sfenner return; 167856893Sfenner if (elem.type != BE_STR) { 167956893Sfenner fputs("[msgAuthenticationParameters!=STR]", stdout); 168056893Sfenner asn1_print(&elem); 168156893Sfenner return; 168256893Sfenner } 168356893Sfenner length -= count; 168456893Sfenner np += count; 168556893Sfenner 168656893Sfenner /* msgPrivacyParameters (OCTET STRING) */ 168756893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 168856893Sfenner return; 168956893Sfenner if (elem.type != BE_STR) { 169056893Sfenner fputs("[msgPrivacyParameters!=STR]", stdout); 169156893Sfenner asn1_print(&elem); 169256893Sfenner return; 169356893Sfenner } 169456893Sfenner length -= count; 169556893Sfenner np += count; 169656893Sfenner 1697127668Sbms if ((u_int)count < length) 169856893Sfenner printf("[%d extra after usm SEQ]", length - count); 169956893Sfenner} 170017680Spst 170156893Sfenner/* 170256893Sfenner * Decode SNMPv3 Message Header (SNMPv3) 170356893Sfenner */ 170456893Sfennerstatic void 170556893Sfennerv3msg_print(const u_char *np, u_int length) 170656893Sfenner{ 170756893Sfenner struct be elem; 170856893Sfenner int count = 0; 170956893Sfenner u_char flags; 171056893Sfenner int model; 171156893Sfenner const u_char *xnp = np; 171256893Sfenner int xlength = length; 171356893Sfenner 171456893Sfenner /* Sequence */ 171556893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 171656893Sfenner return; 171756893Sfenner if (elem.type != BE_SEQ) { 171856893Sfenner fputs("[!message]", stdout); 171956893Sfenner asn1_print(&elem); 172056893Sfenner return; 172156893Sfenner } 172256893Sfenner length = elem.asnlen; 172356893Sfenner np = (u_char *)elem.data.raw; 172456893Sfenner 172575115Sfenner if (vflag) { 172675115Sfenner fputs("{ ", stdout); 172775115Sfenner } 172875115Sfenner 172956893Sfenner /* msgID (INTEGER) */ 173056893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 173156893Sfenner return; 173256893Sfenner if (elem.type != BE_INT) { 173356893Sfenner fputs("[msgID!=INT]", stdout); 173456893Sfenner asn1_print(&elem); 173556893Sfenner return; 173656893Sfenner } 173756893Sfenner length -= count; 173856893Sfenner np += count; 173956893Sfenner 174056893Sfenner /* msgMaxSize (INTEGER) */ 174156893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 174256893Sfenner return; 174356893Sfenner if (elem.type != BE_INT) { 174456893Sfenner fputs("[msgMaxSize!=INT]", stdout); 174556893Sfenner asn1_print(&elem); 174656893Sfenner return; 174756893Sfenner } 174856893Sfenner length -= count; 174956893Sfenner np += count; 175056893Sfenner 175156893Sfenner /* msgFlags (OCTET STRING) */ 175256893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 175356893Sfenner return; 175456893Sfenner if (elem.type != BE_STR) { 175556893Sfenner fputs("[msgFlags!=STR]", stdout); 175656893Sfenner asn1_print(&elem); 175756893Sfenner return; 175856893Sfenner } 175956893Sfenner if (elem.asnlen != 1) { 176056893Sfenner printf("[msgFlags size %d]", elem.asnlen); 176156893Sfenner return; 176256893Sfenner } 176356893Sfenner flags = elem.data.str[0]; 1764127668Sbms if (flags != 0x00 && flags != 0x01 && flags != 0x03 176556893Sfenner && flags != 0x04 && flags != 0x05 && flags != 0x07) { 176656893Sfenner printf("[msgFlags=0x%02X]", flags); 176756893Sfenner return; 176856893Sfenner } 176956893Sfenner length -= count; 177056893Sfenner np += count; 177156893Sfenner 177256893Sfenner fputs("F=", stdout); 177356893Sfenner if (flags & 0x01) fputs("a", stdout); 177456893Sfenner if (flags & 0x02) fputs("p", stdout); 177556893Sfenner if (flags & 0x04) fputs("r", stdout); 177656893Sfenner fputs(" ", stdout); 177756893Sfenner 177856893Sfenner /* msgSecurityModel (INTEGER) */ 177956893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 178056893Sfenner return; 178156893Sfenner if (elem.type != BE_INT) { 178256893Sfenner fputs("[msgSecurityModel!=INT]", stdout); 178356893Sfenner asn1_print(&elem); 178456893Sfenner return; 178556893Sfenner } 178656893Sfenner model = elem.data.integer; 178756893Sfenner length -= count; 178856893Sfenner np += count; 178956893Sfenner 1790127668Sbms if ((u_int)count < length) 179156893Sfenner printf("[%d extra after message SEQ]", length - count); 179256893Sfenner 179375115Sfenner if (vflag) { 179475115Sfenner fputs("} ", stdout); 179575115Sfenner } 179675115Sfenner 179756893Sfenner if (model == 3) { 179856893Sfenner if (vflag) { 179975115Sfenner fputs("{ USM ", stdout); 180056893Sfenner } 180156893Sfenner } else { 180256893Sfenner printf("[security model %d]", model); 180356893Sfenner return; 180456893Sfenner } 180556893Sfenner 180656893Sfenner np = xnp + (np - xnp); 180756893Sfenner length = xlength - (np - xnp); 180856893Sfenner 180956893Sfenner /* msgSecurityParameters (OCTET STRING) */ 181056893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 181156893Sfenner return; 181256893Sfenner if (elem.type != BE_STR) { 181356893Sfenner fputs("[msgSecurityParameters!=STR]", stdout); 181456893Sfenner asn1_print(&elem); 181556893Sfenner return; 181656893Sfenner } 181756893Sfenner length -= count; 181856893Sfenner np += count; 181956893Sfenner 182056893Sfenner if (model == 3) { 182156893Sfenner usm_print(elem.data.str, elem.asnlen); 182275115Sfenner if (vflag) { 182375115Sfenner fputs("} ", stdout); 182475115Sfenner } 182556893Sfenner } 182656893Sfenner 182756893Sfenner if (vflag) { 182875115Sfenner fputs("{ ScopedPDU ", stdout); 182956893Sfenner } 183056893Sfenner 183156893Sfenner scopedpdu_print(np, length, 3); 183275115Sfenner 183375115Sfenner if (vflag) { 183475115Sfenner fputs("} ", stdout); 183575115Sfenner } 183656893Sfenner} 183756893Sfenner 183856893Sfenner/* 183956893Sfenner * Decode SNMP header and pass on to PDU printing routines 184056893Sfenner */ 184156893Sfennervoid 184256893Sfennersnmp_print(const u_char *np, u_int length) 184356893Sfenner{ 184456893Sfenner struct be elem; 184556893Sfenner int count = 0; 184656893Sfenner int version = 0; 184756893Sfenner 184856893Sfenner putchar(' '); 184956893Sfenner 185056893Sfenner /* initial Sequence */ 185156893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 185256893Sfenner return; 185356893Sfenner if (elem.type != BE_SEQ) { 185456893Sfenner fputs("[!init SEQ]", stdout); 185556893Sfenner asn1_print(&elem); 185656893Sfenner return; 185756893Sfenner } 1858127668Sbms if ((u_int)count < length) 185956893Sfenner printf("[%d extra after iSEQ]", length - count); 186056893Sfenner /* descend */ 186156893Sfenner length = elem.asnlen; 186256893Sfenner np = (u_char *)elem.data.raw; 186356893Sfenner 186456893Sfenner /* Version (INTEGER) */ 186556893Sfenner if ((count = asn1_parse(np, length, &elem)) < 0) 186656893Sfenner return; 186756893Sfenner if (elem.type != BE_INT) { 186856893Sfenner fputs("[version!=INT]", stdout); 186956893Sfenner asn1_print(&elem); 187056893Sfenner return; 187156893Sfenner } 187256893Sfenner 187356893Sfenner switch (elem.data.integer) { 187456893Sfenner case SNMP_VERSION_1: 187556893Sfenner case SNMP_VERSION_2: 187656893Sfenner case SNMP_VERSION_3: 187756893Sfenner if (vflag) 187875115Sfenner printf("{ %s ", SnmpVersion[elem.data.integer]); 187917680Spst break; 188056893Sfenner default: 188156893Sfenner printf("[version = %d]", elem.data.integer); 188256893Sfenner return; 188356893Sfenner } 188456893Sfenner version = elem.data.integer; 188556893Sfenner length -= count; 188656893Sfenner np += count; 188756893Sfenner 188856893Sfenner switch (version) { 188956893Sfenner case SNMP_VERSION_1: 189056893Sfenner case SNMP_VERSION_2: 189156893Sfenner community_print(np, length, version); 189217680Spst break; 189356893Sfenner case SNMP_VERSION_3: 189456893Sfenner v3msg_print(np, length); 189556893Sfenner break; 189656893Sfenner default: 189756893Sfenner printf("[version = %d]", elem.data.integer); 189856893Sfenner break; 189917680Spst } 190075115Sfenner 190175115Sfenner if (vflag) { 190275115Sfenner fputs("} ", stdout); 190375115Sfenner } 190417680Spst} 1905