1 /*
2  * Copyright (c) 1990, by John Robert LoVerso.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by John Robert LoVerso.
11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
12  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
13  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
14  *
15  * This implementaion has been influenced by the CMU SNMP release,
16  * by Steve Waldbusser.  However, this shares no code with that system.
17  * Additional ASN.1 insight gained from Marshall T. Rose's _The_Open_Book_.
18  * Earlier forms of this implemention were derived and/or inspired by an
19  * awk script originally written by C. Philip Wood of LANL (but later
20  * heavily modified by John Robert LoVerso).  The copyright notice for
21  * that work is preserved below, even though it may not rightly apply
22  * to this file.
23  *
24  * This started out as a very simple program, but the incremental decoding
25  * (into the BE structure) complicated things.
26  *
27  #			Los Alamos National Laboratory
28  #
29  #	Copyright, 1990.  The Regents of the University of California.
30  #	This software was produced under a U.S. Government contract
31  #	(W-7405-ENG-36) by Los Alamos National Laboratory, which is
32  #	operated by the	University of California for the U.S. Department
33  #	of Energy.  The U.S. Government is licensed to use, reproduce,
34  #	and distribute this software.  Permission is granted to the
35  #	public to copy and use this software without charge, provided
36  #	that this Notice and any statement of authorship are reproduced
37  #	on all copies.  Neither the Government nor the University makes
38  #	any warranty, express or implied, or assumes any liability or
39  #	responsibility for the use of this software.
40  #	@(#)snmp.awk.x	1.1 (LANL) 1/15/90
41  */
42 #ifndef lint
43 static char rcsid[] =
44     "@(#) $Id: print-snmp.c,v 1.4 1993/04/22 20:32:30 martinh Exp $ (UW)";
45 #endif
46 
47 #include <sys/param.h>
48 #include <sys/types.h>
49 #include <stdio.h>
50 #include <ctype.h>
51 
52 #ifdef TCPVIEW
53 #include "tcpview.h"
54 #endif
55 
56 #include "interface.h"
57 #include "addrtoname.h"
58 #include "snmp.h"
59 
60 /*
61  * Universal ASN.1 types
62  * (we only care about the tag values for those allowed in the Internet SMI)
63  */
64 static char *Universal[] = {
65 	"U-0",
66 	"Boolean",
67 	"Integer",
68 #define INTEGER 2
69 	"Bitstring",
70 	"String",
71 #define STRING 4
72 	"Null",
73 #define ASN_NULL 5
74 	"ObjID",
75 #define OBJECTID 6
76 	"ObjectDes",
77 	"U-8","U-9","U-10","U-11",	/* 8-11 */
78 	"U-12","U-13","U-14","U-15",	/* 12-15 */
79 	"Sequence",
80 #define SEQUENCE 16
81 	"Set"
82 };
83 
84 /*
85  * Application-wide ASN.1 types from the Internet SMI and their tags
86  */
87 static char *Application[] = {
88 	"IpAddress",
89 #define IPADDR 0
90 	"Counter",
91 #define COUNTER 1
92 	"Gauge",
93 #define GAUGE 2
94 	"TimeTicks",
95 #define TIMETICKS 3
96 	"Opaque"
97 };
98 
99 /*
100  * Context-specific ASN.1 types for the SNMP PDUs and their tags
101  */
102 static char *Context[] = {
103 	"GetRequest",
104 /* #define GETREQ 0 */
105 	"GetNextRequest",
106 /* #define GETNEXTREQ 1 */
107 	"GetResponse",
108 /* #define GETRESP 2 */
109 	"SetRequest",
110 /* #define SETREQ 3 */
111 	"Trap"
112 /* #define TRAP 4 */
113 };
114 
115 /*
116  * Private ASN.1 types
117  * The Internet SMI does not specify any
118  */
119 static char *Private[] = {
120 	"P-0"
121 };
122 
123 /*
124  * error-status values for any SNMP PDU
125  */
126 static char *ErrorStatus[] = {
127 	"noError",
128 	"tooBig",
129 	"noSuchName",
130 	"badValue",
131 	"readOnly",
132 	"genErr"
133 };
134 
135 /*
136  * generic-trap values in the SNMP Trap-PDU
137  */
138 static char *GenericTrap[] = {
139 	"coldStart",
140 	"warmStart",
141 	"linkDown",
142 	"linkUp",
143 	"authenticationFailure",
144 	"egpNeighborLoss",
145 	"enterpriseSpecific"
146 };
147 
148 /*
149  * ASN.1 type class table
150  * Ties together the preceding Universal, Application, Context, and Private
151  * type definitions.
152  */
153 #define defineCLASS(x) { "x", x, sizeof(x)/sizeof(x[0]) } /* not ANSI-C */
154 static struct {
155 	char	*name;
156 	char	**Id;
157 	int	numIDs;
158 } Class[] = {
159 	defineCLASS(Universal),
160 #define	UNIVERSAL	0
161 	defineCLASS(Application),
162 #define	APPLICATION	1
163 	defineCLASS(Context),
164 #define	CONTEXT		2
165 	defineCLASS(Private),
166 #define	PRIVATE		3
167 };
168 
169 /*
170  * defined forms for ASN.1 types
171  */
172 static char *Form[] = {
173 	"Primitive",
174 #define PRIMITIVE	0
175 	"Constructed",
176 #define CONSTRUCTED	1
177 };
178 
179 /*
180  * A tree in the format of the tree structure of the MIB.
181  */
182 #define MAXLABEL 64	/* max label length */
183 #define MAXTOKEN 64
184 #define HASHSIZE 255
185 static struct tree {
186     struct tree *child_list;    /* list of children of this node */
187     struct tree *next_peer;     /* Next node in list of peers */
188     struct tree *parent;
189     struct tree *next_hash;     /* next hash entry.  used by parser */
190     char label[MAXLABEL];       /* This node's textual name */
191     u_long subid;               /* This node's integer subidentifier */
192     int type;                   /* This node's object type */
193 };
194 static struct tree *Mib=NULL;
195 static struct tree *objp=NULL;
196 static void init_mib();
197 static struct tree *read_mib();
198 static struct tree *enter();
199 static struct tree *lookup();
200 static int add_child();
201 
202 /*
203  * This defines a list of OIDs which will be abreviated on output.
204  * Currently, this includes the prefixes for the Internet MIB, the
205  * private enterprises tree, and the experimental tree.
206  */
207 static struct obj_abrev {
208 	char *prefix;			/* prefix for this abrev */
209 	struct tree *node;		/* pointer into object table */
210 	char *name;
211 	char *oid;			/* ASN.1 encoded OID */
212 } obj_abrev_list[] = {
213 	/* .iso.org.dod.internet.mgmt.mib */
214 	{ "", 0, "mib", "\53\6\1\2\1" },
215 	/* .iso.org.dod.internet.private.enterprises */
216 	{ "E:",	0, "enterprises",  "\53\6\1\4\1" },
217 	/* .iso.org.dod.internet.experimental */
218 	{ "X:",	0, "experimental", "\53\6\1\3" },
219 	{ 0,0,0,0 }
220 };
221 
222 /*
223  * This is used in the OID print routine to walk down the object tree
224  * rooted at `Mib'.
225  */
226 #define OBJ_PRINT(o, suppressdot) \
227 { \
228 	if (objp) { \
229 		do { \
230 			if ((o) == objp->subid) \
231 				break; \
232 		} while (objp = objp->next_peer); \
233 	} \
234 	if (objp) { \
235 		printf(suppressdot?"%s":".%s", objp->label); \
236 		objp = objp->child_list; \
237 	} else \
238 		printf(suppressdot?"%u":".%u", (o)); \
239 }
240 
241 /*
242  * Defaults for SNMP PDU components
243  */
244 #define DEF_COMMUNITY "public"
245 #define DEF_VERSION 0
246 
247 /*
248  * constants for ASN.1 decoding
249  */
250 #define OIDMUX 40
251 #define ASNLEN_INETADDR 4
252 #define ASN_SHIFT7 7
253 #define ASN_SHIFT8 8
254 #define ASN_BIT8 0x80
255 #define ASN_LONGLEN 0x80
256 
257 #define ASN_ID_BITS 0x1f
258 #define ASN_FORM_BITS 0x20
259 #define ASN_FORM_SHIFT 5
260 #define ASN_CLASS_BITS 0xc0
261 #define ASN_CLASS_SHIFT 6
262 
263 #define ASN_ID_EXT 0x1f		/* extension ID in tag field */
264 
265 #ifdef TCPVIEW
266 #define err_print eprint
267 #else
268 #define err_print printf
269 #endif
270 
271 static char errbuf[10];
272 
DECODE_ErrorStatus(e)273 char *DECODE_ErrorStatus( e )
274      int e;
275 {
276   if( e >= 0 && e <= sizeof(ErrorStatus)/sizeof(ErrorStatus[0]) )
277     return( ErrorStatus[e] );
278   sprintf(errbuf,"err=%d",e);
279     return( errbuf );
280 }
281 
DECODE_GenericTrap(e)282 char *DECODE_GenericTrap( e )
283      int e;
284 {
285   if( e >= 0 && e <= sizeof(GenericTrap)/sizeof(GenericTrap[0]) )
286     return( GenericTrap[e] );
287   sprintf(errbuf,"gt=%d",e);
288     return( errbuf );
289 }
290 
291 /*
292  * truncated==1 means the packet was complete, but we don't have all of
293  * it to decode.
294  */
295 static int truncated;
296 #define ifNotTruncated if (truncated) fputs("[|snmp]", stdout); else
297 
298 /*
299  * This decodes the next ASN.1 object in the stream pointed to by "p"
300  * (and of real-length "len") and stores the intermediate data in the
301  * provided BE object.
302  *
303  * This returns -l if it fails (i.e., the ASN.1 stream is not valid).
304  * O/w, this returns the number of bytes parsed from "p".
305  */
306 int
asn1_parse(p,len,elem)307 asn1_parse(p, len, elem)
308 	register u_char *p;
309 	int len;
310 	struct be *elem;
311 {
312 	unsigned char form, class, id;
313 	int indent=0, i, hdr;
314 	char *classstr;
315 
316 	elem->asnlen = 0;
317 	elem->type = BE_ANY;
318 	if (len < 1) {
319 		ifNotTruncated puts("[nothing to parse], stdout");
320 		return -1;
321 	}
322 
323 	/*
324 	 * it would be nice to use a bit field, but you can't depend on them.
325 	 *  +---+---+---+---+---+---+---+---+
326 	 *  + class |frm|        id         |
327 	 *  +---+---+---+---+---+---+---+---+
328 	 *    7   6   5   4   3   2   1   0
329 	 */
330 	id = *p & ASN_ID_BITS;		/* lower 5 bits, range 00-1f */
331 #ifdef notdef
332 	form = (*p & 0xe0) >> 5;	/* move upper 3 bits to lower 3 */
333 	class = form >> 1;		/* bits 7&6 -> bits 1&0, range 0-3 */
334 	form &= 0x1;			/* bit 5 -> bit 0, range 0-1 */
335 #else
336 	form = (*p & ASN_FORM_BITS) >> ASN_FORM_SHIFT;
337 	class = (*p & ASN_CLASS_BITS) >> ASN_CLASS_SHIFT;
338 #endif
339 	elem->form = form;
340 	elem->class = class;
341 	elem->id = id;
342 	if (vflag)
343 		printf("|%.2x", *p);
344 	p++; len--; hdr = 1;
345 	/* extended tag field */
346 	if (id == ASN_ID_EXT) {
347 		for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
348 			if (vflag)
349 				printf("|%.2x", *p);
350 			id += *p & ~ASN_BIT8;
351 		}
352 		if (len == 0 && *p & ASN_BIT8) {
353 			ifNotTruncated fputs("[Xtagfield?]", stdout);
354 			return -1;
355 		}
356 	}
357 	if (len < 1) {
358 		ifNotTruncated fputs("[no asnlen]", stdout);
359 		return -1;
360 	}
361 	elem->asnlen = *p;
362 	if (vflag)
363 		printf("|%.2x", *p);
364 	p++; len--; hdr++;
365 	if (elem->asnlen & ASN_BIT8) {
366 		int noct = elem->asnlen % ASN_BIT8;
367 		elem->asnlen = 0;
368 		if (len < noct) {
369 			ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
370 			return -1;
371 		}
372 		for (; noct-- > 0; len--, hdr++) {
373 			if (vflag)
374 				printf("|%.2x", *p);
375 			elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
376 		}
377 	}
378 	if (len < elem->asnlen) {
379 		if (!truncated) {
380 			printf("[len%d<asnlen%u]", len, elem->asnlen);
381 			return -1;
382 		}
383 		/* maybe should check at least 4? */
384 		elem->asnlen = len;
385 	}
386 	if (form >= sizeof(Form)/sizeof(Form[0])) {
387 		ifNotTruncated printf("[form?%d]", form);
388 		return -1;
389 	}
390 	if (class >= sizeof(Class)/sizeof(Class[0])) {
391 		ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
392 		return -1;
393 	}
394 	if (id >= Class[class].numIDs) {
395 		ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
396 			Class[class].name, id);
397 		return -1;
398 	}
399 
400 	switch (form) {
401 	case PRIMITIVE:
402 		switch (class) {
403 		case UNIVERSAL:
404 			switch (id) {
405 			case STRING:
406 				elem->type = BE_STR;
407 				elem->data.str = p;
408 				break;
409 
410 			case INTEGER: {
411 				register long data;
412 				elem->type = BE_INT;
413 				data = 0;
414 
415 				if (*p & ASN_BIT8)	/* negative */
416 					data = -1;
417 				for (i = elem->asnlen; i-- > 0; p++)
418 					data = (data << ASN_SHIFT8) | *p;
419 				elem->data.integer = data;
420 				break;
421 			}
422 
423 			case OBJECTID:
424 				elem->type = BE_OID;
425 				elem->data.raw = (caddr_t)p;
426 				break;
427 
428 			case ASN_NULL:
429 				elem->type = BE_NULL;
430 				elem->data.raw = NULL;
431 				break;
432 
433 			default:
434 				elem->type = BE_OCTET;
435 				elem->data.raw = (caddr_t)p;
436 				printf("[P/U/%s]",
437 					Class[class].Id[id]);
438 				break;
439 			}
440 			break;
441 
442 		case APPLICATION:
443 			switch (id) {
444 			case IPADDR:
445 				elem->type = BE_INETADDR;
446 				elem->data.raw = (caddr_t)p;
447 				break;
448 
449 			case COUNTER:
450 			case GAUGE:
451 			case TIMETICKS: {
452 				register unsigned long data;
453 				elem->type = BE_UNS;
454 				data = 0;
455 				for (i = elem->asnlen; i-- > 0; p++)
456 					data = (data << 8) + *p;
457 				elem->data.uns = data;
458 				break;
459 			}
460 
461 			default:
462 				elem->type = BE_OCTET;
463 				elem->data.raw = (caddr_t)p;
464 				printf("[P/A/%s]",
465 					Class[class].Id[id]);
466 				break;
467 			}
468 			break;
469 
470 		default:
471 			elem->type = BE_OCTET;
472 			elem->data.raw = (caddr_t)p;
473 			printf("[P/%s/%s]",
474 				Class[class].name, Class[class].Id[id]);
475 			break;
476 		}
477 		break;
478 
479 	case CONSTRUCTED:
480 		switch (class) {
481 		case UNIVERSAL:
482 			switch (id) {
483 			case SEQUENCE:
484 				elem->type = BE_SEQ;
485 				elem->data.raw = (caddr_t)p;
486 				break;
487 
488 			default:
489 				elem->type = BE_OCTET;
490 				elem->data.raw = (caddr_t)p;
491 				printf("C/U/%s", Class[class].Id[id]);
492 				break;
493 			}
494 			break;
495 
496 		case CONTEXT:
497 			elem->type = BE_PDU;
498 			elem->data.raw = (caddr_t)p;
499 			break;
500 
501 		default:
502 			elem->type = BE_OCTET;
503 			elem->data.raw = (caddr_t)p;
504 			printf("C/%s/%s",
505 				Class[class].name, Class[class].Id[id]);
506 			break;
507 		}
508 		break;
509 	}
510 	p += elem->asnlen;
511 	len -= elem->asnlen;
512 	return elem->asnlen + hdr;
513 }
514 
515 /*
516  * Display the ASN.1 object represented by the BE object.
517  */
asn1_print(elem)518 void asn1_print(elem)
519      struct be *elem;
520 {
521   u_char *p = (u_char *)elem->data.raw;
522   u_long asnlen = elem->asnlen;
523   int i;
524 
525   switch (elem->type) {
526 
527   case BE_OCTET:
528     for (i = asnlen; i-- > 0; p++);
529     printf("_%.2x", *p);
530     break;
531 
532   case BE_NULL:
533     break;
534 
535   case BE_OID: {
536     int o = 0, first = -1, i = asnlen;
537 
538     if (!nflag && asnlen > 2) {
539       struct obj_abrev *a = &obj_abrev_list[0];
540       for (; a->node; a++) {
541 	if (!memcmp(a->oid, p, strlen(a->oid))) {
542 	  objp = a->node->child_list;
543 	  i -= strlen(a->oid);
544 	  p += strlen(a->oid);
545 	  fputs(a->prefix, stdout);
546 	  first = 1;
547 	  break;
548 	}
549       }
550     }
551 
552     for (; i-- > 0; p++) {
553       o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
554       if (*p & ASN_LONGLEN)
555 	continue;
556 
557       /*
558        * first subitem encodes two items with 1st*OIDMUX+2nd
559        */
560       if (first < 0) {
561 	if (!nflag)
562 	  objp = Mib;
563 	first = 0;
564 	OBJ_PRINT(o/OIDMUX, first);
565 	o %= OIDMUX;
566       }
567       OBJ_PRINT(o, first);
568       if (--first < 0)
569 	first = 0;
570       o = 0;
571     }
572     break;
573   }
574 
575   case BE_INT:
576     printf("%ld", elem->data.integer);
577     break;
578 
579   case BE_UNS:
580     printf("%lu", elem->data.uns);
581     break;
582 
583   case BE_STR: {
584     register int printable = 1, first = 1;
585     u_char *p = elem->data.str;
586     for (i = asnlen; printable && i-- > 0; p++)
587       printable = isprint(*p) || isspace(*p);
588     p = elem->data.str;
589     if (printable)
590       (void)printfn(p, p+asnlen);
591     else
592       for (i = asnlen; i-- > 0; p++) {
593 	printf(first ? "%.2x" : "_%.2x", *p);
594 	first = 0;
595       }
596     break;
597   }
598 
599   case BE_SEQ:
600     printf("Seq(%d)", elem->asnlen);
601     break;
602 
603   case BE_INETADDR: {
604     char sep;
605     if (asnlen != ASNLEN_INETADDR)
606       printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
607     sep='[';
608     for (i = asnlen; i-- > 0; p++) {
609       printf("%c%u", sep, *p);
610       sep='.';
611     }
612     putchar(']');
613     break;
614   }
615 
616   case BE_PDU:
617     printf("%s(%d)",
618 	   Class[CONTEXT].Id[elem->id], elem->asnlen);
619     break;
620 
621   case BE_ANY:
622     fputs("[BE_ANY!?]", stdout);
623     break;
624 
625   default:
626     fputs("[be!?]", stdout);
627     break;
628   }
629 }
630 
631 #ifdef notdef
632 /*
633  * This is a brute force ASN.1 printer: recurses to dump an entire structure.
634  * This will work for any ASN.1 stream, not just an SNMP PDU.
635  *
636  * By adding newlines and spaces at the correct places, this would print in
637  * Rose-Normal-Form.
638  *
639  * This is not currently used.
640  */
641 void
asn1_decode(p,length)642 asn1_decode(p, length)
643 	u_char *p;
644 	int length;
645 {
646 	struct be elem;
647 	int i = 0;
648 
649 	while (i >= 0 && length > 0) {
650 		i = asn1_parse(p, length, &elem);
651 		if (i >= 0) {
652 			fputs(" ", stdout);
653 			asn1_print(&elem);
654 			if (elem.type == BE_SEQ || elem.type == BE_PDU) {
655 				fputs(" {", stdout);
656 				asn1_decode(elem.data.raw, elem.asnlen);
657 				fputs(" }", stdout);
658 			}
659 			length -= i;
660 			p += i;
661 		}
662 	}
663 }
664 #endif
665 
666 /*
667  * General SNMP header
668  *	SEQUENCE {
669  *		version INTEGER {version-1(0)},
670  *		community OCTET STRING,
671  *		data ANY 	-- PDUs
672  *	}
673  * PDUs for all but Trap: (see rfc1157 from page 15 on)
674  *	SEQUENCE {
675  *		request-id INTEGER,
676  *		error-status INTEGER,
677  *		error-index INTEGER,
678  *		varbindlist SEQUENCE OF
679  *			SEQUENCE {
680  *				name ObjectName,
681  *				value ObjectValue
682  *			}
683  *	}
684  * PDU for Trap:
685  *	SEQUENCE {
686  *		enterprise OBJECT IDENTIFIER,
687  *		agent-addr NetworkAddress,
688  *		generic-trap INTEGER,
689  *		specific-trap INTEGER,
690  *		time-stamp TimeTicks,
691  *		varbindlist SEQUENCE OF
692  *			SEQUENCE {
693  *				name ObjectName,
694  *				value ObjectValue
695  *			}
696  *	}
697  */
698 
699 /*
700  * Decode SNMP varBind
701  */
702 static void
varbind_print(pduid,np,length,error)703 varbind_print (pduid, np, length, error)
704 	u_char pduid, *np;
705 	int length, error;
706 {
707 	struct be elem;
708 	int count = 0, index;
709 
710 	/* Sequence of varBind */
711 	if ((count = asn1_parse(np, length, &elem)) < 0)
712 		return;
713 	if (elem.type != BE_SEQ) {
714 		fputs("[!SEQ of varbind]", stdout);
715 		asn1_print(&elem);
716 		return;
717 	}
718 	if (count < length)
719 		printf("[%d extra after SEQ of varbind]", length - count);
720 	/* descend */
721 	length = elem.asnlen;
722 	np = (u_char *)elem.data.raw;
723 
724 	for (index = 1; length > 0; index++) {
725 		u_char *vbend;
726 		int vblength;
727 
728 		if (!error || index == error)
729 			fputs(" ", stdout);
730 
731 		/* Sequence */
732 		if ((count = asn1_parse(np, length, &elem)) < 0)
733 			return;
734 		if (elem.type != BE_SEQ) {
735 			fputs("[!varbind]", stdout);
736 			asn1_print(&elem);
737 			return;
738 		}
739 		vbend = np + count;
740 		vblength = length - count;
741 		/* descend */
742 		length = elem.asnlen;
743 		np = (u_char *)elem.data.raw;
744 
745 		/* objName (OID) */
746 		if ((count = asn1_parse(np, length, &elem)) < 0)
747 			return;
748 		if (elem.type != BE_OID) {
749 			fputs("[objName!=OID]", stdout);
750 			asn1_print(&elem);
751 			return;
752 		}
753 		if (!error || index == error)
754 			asn1_print(&elem);
755 		length -= count;
756 		np += count;
757 
758 		if (pduid != GETREQ && pduid != GETNEXTREQ && !error)
759 				fputs("=", stdout);
760 
761 		/* objVal (ANY) */
762 		if ((count = asn1_parse(np, length, &elem)) < 0)
763 			return;
764 		if (pduid == GETREQ || pduid == GETNEXTREQ) {
765 			if (elem.type != BE_NULL) {
766 				fputs("[objVal!=NULL]", stdout);
767 				asn1_print(&elem);
768 			}
769 		} else
770 			if (error && index == error && elem.type != BE_NULL)
771 				fputs("[err objVal!=NULL]", stdout);
772 			if (!error || index == error)
773 				asn1_print(&elem);
774 
775 		length = vblength;
776 		np = vbend;
777 	}
778 }
779 
780 /*
781  * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
782  */
783 static void
snmppdu_print(pduid,np,length)784 snmppdu_print (pduid, np, length)
785 	u_char pduid, *np;
786 	int length;
787 {
788 	struct be elem;
789 	int count = 0, error;
790 
791 	/* reqId (Integer) */
792 	if ((count = asn1_parse(np, length, &elem)) < 0)
793 		return;
794 	if (elem.type != BE_INT) {
795 		fputs("[reqId!=INT]", stdout);
796 		asn1_print(&elem);
797 		return;
798 	}
799 	/* ignore the reqId */
800 	length -= count;
801 	np += count;
802 
803 	/* errorStatus (Integer) */
804 	if ((count = asn1_parse(np, length, &elem)) < 0)
805 		return;
806 	if (elem.type != BE_INT) {
807 		fputs("[errorStatus!=INT]", stdout);
808 		asn1_print(&elem);
809 		return;
810 	}
811 	error = 0;
812 	if ((pduid == GETREQ || pduid == GETNEXTREQ)
813 	    && elem.data.integer != 0) {
814 		printf("[errorStatus(%s)!=0]",
815 			DECODE_ErrorStatus(elem.data.integer));
816 	} else if (elem.data.integer != 0) {
817 		printf(" %s", DECODE_ErrorStatus(elem.data.integer));
818 		error = elem.data.integer;
819 	}
820 	length -= count;
821 	np += count;
822 
823 	/* errorIndex (Integer) */
824 	if ((count = asn1_parse(np, length, &elem)) < 0)
825 		return;
826 	if (elem.type != BE_INT) {
827 		fputs("[errorIndex!=INT]", stdout);
828 		asn1_print(&elem);
829 		return;
830 	}
831 	if ((pduid == GETREQ || pduid == GETNEXTREQ)
832 	    && elem.data.integer != 0)
833 		printf("[errorIndex(%d)!=0]", elem.data.integer);
834 	else if (elem.data.integer != 0) {
835 		if (!error)
836 			printf("[errorIndex(%d) w/o errorStatus]",
837 				elem.data.integer);
838 		else {
839 			printf("@%d", elem.data.integer);
840 			error = elem.data.integer;
841 		}
842 	} else if (error) {
843 		fputs("[errorIndex==0]", stdout);
844 		error = 0;
845 	}
846 	length -= count;
847 	np += count;
848 
849 	varbind_print(pduid, np, length, error);
850 	return;
851 }
852 
853 /*
854  * Decode SNMP Trap PDU
855  */
856 static void
trap_print(np,length)857 trap_print (np, length)
858 	u_char *np;
859 	int length;
860 {
861 	struct be elem;
862 	int count = 0, generic;
863 
864 	putchar(' ');
865 
866 	/* enterprise (oid) */
867 	if ((count = asn1_parse(np, length, &elem)) < 0)
868 		return;
869 	if (elem.type != BE_OID) {
870 		fputs("[enterprise!=OID]", stdout);
871 		asn1_print(&elem);
872 		return;
873 	}
874 	asn1_print(&elem);
875 	length -= count;
876 	np += count;
877 
878 	putchar(' ');
879 
880 	/* agent-addr (inetaddr) */
881 	if ((count = asn1_parse(np, length, &elem)) < 0)
882 		return;
883 	if (elem.type != BE_INETADDR) {
884 		fputs("[agent-addr!=INETADDR]", stdout);
885 		asn1_print(&elem);
886 		return;
887 	}
888 	asn1_print(&elem);
889 	length -= count;
890 	np += count;
891 
892 	/* generic-trap (Integer) */
893 	if ((count = asn1_parse(np, length, &elem)) < 0)
894 		return;
895 	if (elem.type != BE_INT) {
896 		fputs("[generic-trap!=INT]", stdout);
897 		asn1_print(&elem);
898 		return;
899 	}
900 	generic = elem.data.integer;
901 	printf(" %s", DECODE_GenericTrap(generic));
902 
903 	length -= count;
904 	np += count;
905 
906 	/* specific-trap (Integer) */
907 	if ((count = asn1_parse(np, length, &elem)) < 0)
908 		return;
909 	if (elem.type != BE_INT) {
910 		fputs("[specific-trap!=INT]", stdout);
911 		asn1_print(&elem);
912 		return;
913 	}
914 	if (generic != GT_ENTERPRISE) {
915 		if (elem.data.integer != 0)
916 			printf("[specific-trap(%d)!=0]", elem.data.integer);
917 	} else
918 		printf(" s=%d", elem.data.integer);
919 	length -= count;
920 	np += count;
921 
922 	putchar(' ');
923 
924 	/* time-stamp (TimeTicks) */
925 	if ((count = asn1_parse(np, length, &elem)) < 0)
926 		return;
927 	if (elem.type != BE_UNS) {			/* XXX */
928 		fputs("[time-stamp!=TIMETICKS]", stdout);
929 		asn1_print(&elem);
930 		return;
931 	}
932 	asn1_print(&elem);
933 	length -= count;
934 	np += count;
935 
936 	varbind_print (TRAP, np, length, 0);
937 	return;
938 }
939 
940 /*
941  * Decode SNMP header and pass on to PDU printing routines
942  */
943 void
snmp_print(np,length)944 snmp_print (np, length)
945 	u_char *np;
946 	int length;
947 {
948 	struct be elem, pdu;
949 	int count = 0;
950 
951 	if( Mib == NULL )
952 	  init_mib();
953 
954 	truncated = 0;
955 
956 	/* truncated packet? */
957 	if (np + length > snapend) {
958 		truncated = 1;
959 		length = snapend - np;
960 	}
961 
962 	putchar(' ');
963 
964 	/* initial Sequence */
965 	if ((count = asn1_parse(np, length, &elem)) < 0)
966 		return;
967 	if (elem.type != BE_SEQ) {
968 		fputs("[!init SEQ]", stdout);
969 		asn1_print(&elem);
970 		return;
971 	}
972 	if (count < length)
973 		printf("[%d extra after iSEQ]", length - count);
974 	/* descend */
975 	length = elem.asnlen;
976 	np = (u_char *)elem.data.raw;
977 	/* Version (Integer) */
978 	if ((count = asn1_parse(np, length, &elem)) < 0)
979 		return;
980 	if (elem.type != BE_INT) {
981 		fputs("[version!=INT]", stdout);
982 		asn1_print(&elem);
983 		return;
984 	}
985 	/* only handle version==0 */
986 	if (elem.data.integer != DEF_VERSION) {
987 		printf("[version(%d)!=0]", elem.data.integer);
988 		return;
989 	}
990 	length -= count;
991 	np += count;
992 
993 	/* Community (String) */
994 	if ((count = asn1_parse(np, length, &elem)) < 0)
995 		return;
996 	if (elem.type != BE_STR) {
997 		fputs("[comm!=STR]", stdout);
998 		asn1_print(&elem);
999 		return;
1000 	}
1001 	/* default community */
1002 	if (strncmp(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1))
1003 		/* ! "public" */
1004 		printf("C=%.*s ", elem.asnlen, elem.data.str);
1005 	length -= count;
1006 	np += count;
1007 
1008 	/* PDU (Context) */
1009 	if ((count = asn1_parse(np, length, &pdu)) < 0)
1010 		return;
1011 	if (pdu.type != BE_PDU) {
1012 		fputs("[no PDU]", stdout);
1013 		return;
1014 	}
1015 	if (count < length)
1016 		printf("[%d extra after PDU]", length - count);
1017 	asn1_print(&pdu);
1018 	/* descend into PDU */
1019 	length = pdu.asnlen;
1020 	np = (u_char *)pdu.data.raw;
1021 
1022 	switch (pdu.id) {
1023 	case TRAP:
1024 		trap_print(np, length);
1025 		break;
1026 	case GETREQ:
1027 	case GETNEXTREQ:
1028 	case GETRESP:
1029 	case SETREQ:
1030 		snmppdu_print(pdu.id, np, length);
1031 		break;
1032 	}
1033 	return;
1034 }
1035 
init_mib()1036 static void init_mib()
1037 {
1038   char *file, *getenv();
1039   struct obj_abrev *a = &obj_abrev_list[0];
1040 
1041   Mib = 0;
1042   file = getenv("MIBFILE");
1043   if (file)
1044     Mib = read_mib(file);
1045   if (!Mib)
1046     Mib = read_mib("mib.txt");
1047   if (!Mib)
1048     Mib = read_mib("/usr/local/lib/tcpview/mib/mib.txt");
1049   if (!Mib){
1050     err_print("Couldn't find mib file\n");
1051     exit(2);
1052   }
1053 
1054   for (; a->name; a++) {
1055     a->node = lookup(a->name);
1056     if( a->node  == NULL )
1057       err_print("WARNING:  Could not find %s in MIB.\n",a->name);
1058   }
1059 }
1060 
1061 static struct tree *Hashtable[HASHSIZE];
1062 
read_mib(filename)1063 static struct tree *read_mib(filename)
1064      char *filename;
1065 {
1066   FILE *fp;
1067   struct tree *tp;
1068   struct tree *parent, *hp, *iso;
1069   char buf[256], name[64], *ptr, *stp;
1070   int type=0, access=0;
1071 
1072   fp = fopen(filename, "r");
1073   if (fp == NULL)
1074     return NULL;
1075 
1076   /* create iso */
1077   iso = enter("iso");
1078   iso->subid = 1;
1079 
1080   /* read in mosy file */
1081   while(fgets(buf,sizeof(buf),fp)) {
1082     if(*buf == '#' || isspace(*buf) || (buf[0]=='-' && buf[1]=='-'))
1083       continue;
1084     ptr = buf;
1085     while(!isspace(*ptr))
1086       ptr++;
1087     *ptr++ = 0;
1088     strncpy(name,buf,sizeof(name));
1089     name[sizeof(name)-1]='\0';
1090 
1091     while(isspace(*ptr)) ptr++;
1092     stp = ptr;
1093     while(*ptr != '.')
1094       ptr++;
1095     *ptr++ = 0;
1096     parent = lookup(stp);
1097     if(parent==NULL) {
1098       err_print("Couldn't find parent %s of %s\n",stp,name);
1099       exit(0);
1100     }
1101     stp = ptr;
1102     while(!isspace(*ptr)) ptr++;
1103     *ptr++ = 0;
1104 
1105     hp = lookup(name);
1106     if(hp==NULL)
1107       hp = enter(name);
1108     else {  /* name already exists */
1109       if(hp->parent==parent)
1110         if(hp->subid==atoi(stp))
1111           continue;    /* duplicate definition - skip it */
1112         else {
1113           err_print("Error: %s redefined\n",name);
1114           exit(0);
1115         }
1116       else
1117         hp = enter(name);
1118     }
1119     hp->subid = atoi(stp);
1120     add_child(parent,hp);
1121     while(isspace(*ptr)) ptr++;
1122     if(*ptr==0)
1123       continue;
1124     stp = ptr;
1125     while(!isspace(*ptr)) ptr++;
1126     *ptr++ = 0;
1127 
1128     if(!strcmp(stp,"INTEGER"))
1129       type = BE_INT;
1130     else if(!strcmp(stp,"Counter"))
1131       type = BE_UNS;
1132     else if(!strcmp(stp,"DisplayString"))
1133       type = BE_STR;
1134     else if(!strcmp(stp,"Gauge"))
1135       type = BE_UNS;
1136     else if(!strcmp(stp,"TimeTicks"))
1137       type = BE_UNS;
1138     else if(!strcmp(stp,"NetworkAddress"))
1139       type = BE_INETADDR;
1140     else if(!strcmp(stp,"IpAddress"))
1141       type = BE_INETADDR;
1142     else if(!strcmp(stp,"OctetString"))
1143       type = BE_OCTET;
1144     else if(!strcmp(stp,"ObjectID"))
1145       type = BE_OID;
1146     else if(!strcmp(stp,"Aggregate"))
1147       type = BE_ANY;
1148     else if(!strcmp(stp,"PhysAddress"))
1149       type = BE_OCTET;
1150     else {
1151       err_print("type %s not recognized\n",stp);
1152       type = BE_ANY;
1153     }
1154     hp->type = type;
1155   }
1156   fclose(fp);
1157   return (iso);
1158 }
1159 
1160 /*
1161 ** lookup(name) returns a pointer to "name" in the hash table.
1162 ** returns NULL if the name is not found
1163 */
1164 
lookup(name)1165 static struct tree *lookup(name)
1166      char *name;
1167 {
1168   struct tree *hp;
1169   int hash;
1170 
1171   hash = (name[0]+name[1]) & HASHSIZE;
1172   hp = Hashtable[hash];
1173   while(hp) {
1174     if (!strcmp(hp->label,name))
1175       return (hp);
1176     hp = hp->next_hash;
1177   }
1178   return(NULL);
1179 }
1180 
1181 /*
1182 ** enter() enters a new name in the hash table.
1183 ** New entries are put at the beginning of the hash chain.
1184 */
enter(name)1185 static struct tree *enter(name)
1186      char *name;
1187 {
1188   struct tree *hp;
1189   int hash;
1190 
1191   hash = (name[0]+name[1]) & HASHSIZE;
1192   hp = (struct tree *)malloc(sizeof(struct tree));
1193   hp->next_hash = Hashtable[hash];
1194   Hashtable[hash] = hp;
1195   strcpy(hp->label,name);
1196   hp->child_list = hp->next_peer = hp->parent = 0;
1197   hp->type = BE_NONE;
1198   return(hp);
1199 
1200 }
1201 
1202 /* add a child to a node in the tree */
add_child(parent,child)1203 static int add_child(parent, child)
1204      struct tree *parent, *child;
1205 {
1206   struct tree *t = parent->child_list;
1207 
1208 /*  fprintf(stderr,"adding %s to %s (%d)\n",child->label,parent->label,child->subid); */
1209   if(t==NULL) {
1210     parent->child_list = child;
1211     child->next_peer = 0;
1212     child->parent = parent;
1213     return 1;
1214   }
1215 
1216   while(1) {
1217     if(t->subid==child->subid) {
1218       if(!strcmp(t->label,child->label)) {
1219         return 0;
1220       } else {
1221         err_print("Warning: node %s has 2 children with subid %d!\n",parent->label,child->subid);
1222         return 0;
1223       }
1224     }
1225     if(t->next_peer)
1226       t = t->next_peer;
1227     else
1228       break;
1229   }
1230 
1231   t->next_peer = child;
1232   child->next_peer = 0;
1233   child->parent = parent;
1234 
1235   return 1;
1236 }
1237 
1238 
1239 
1240