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