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