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