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