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