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