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