]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
Clean up the description of "net <net> mask <netmask>" slightly.
[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.49 2001-06-15 21:06:59 fenner 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 oidsize, 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 if (*oidlen < oidsize) {
869 oid[(*oidlen)++] = o/OIDMUX;
870 }
871 o %= OIDMUX;
872 }
873 if (*oidlen < oidsize) {
874 oid[(*oidlen)++] = o;
875 }
876 o = 0;
877 }
878 }
879
880 static int smi_check_type(SmiBasetype basetype, int be)
881 {
882 int i;
883
884 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
885 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
886 return 1;
887 }
888 }
889
890 return 0;
891 }
892
893 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
894 struct be *elem)
895 {
896 int ok = 1;
897
898 switch (smiType->basetype) {
899 case SMI_BASETYPE_OBJECTIDENTIFIER:
900 case SMI_BASETYPE_OCTETSTRING:
901 if (smiRange->minValue.value.unsigned32
902 == smiRange->maxValue.value.unsigned32) {
903 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
904 } else {
905 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
906 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
907 }
908 break;
909
910 case SMI_BASETYPE_INTEGER32:
911 ok = (elem->data.integer >= smiRange->minValue.value.integer32
912 && elem->data.integer <= smiRange->maxValue.value.integer32);
913 break;
914
915 case SMI_BASETYPE_UNSIGNED32:
916 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
917 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
918 break;
919
920 case SMI_BASETYPE_UNSIGNED64:
921 /* XXX */
922 break;
923
924 /* case SMI_BASETYPE_INTEGER64: SMIng */
925 /* case SMI_BASETYPE_FLOAT32: SMIng */
926 /* case SMI_BASETYPE_FLOAT64: SMIng */
927 /* case SMI_BASETYPE_FLOAT128: SMIng */
928
929 case SMI_BASETYPE_ENUM:
930 case SMI_BASETYPE_BITS:
931 case SMI_BASETYPE_UNKNOWN:
932 ok = 1;
933 break;
934 }
935
936 return ok;
937 }
938
939 static int smi_check_range(SmiType *smiType, struct be *elem)
940 {
941 SmiRange *smiRange;
942 int ok = 1;
943
944 for (smiRange = smiGetFirstRange(smiType);
945 smiRange;
946 smiRange = smiGetNextRange(smiRange)) {
947
948 ok = smi_check_a_range(smiType, smiRange, elem);
949
950 if (ok) {
951 break;
952 }
953 }
954
955 if (ok) {
956 SmiType *parentType;
957 parentType = smiGetParentType(smiType);
958 if (parentType) {
959 ok = smi_check_range(parentType, elem);
960 }
961 }
962
963 return ok;
964 }
965
966 static SmiNode *smi_print_variable(struct be *elem)
967 {
968 unsigned int oid[128], oidlen;
969 SmiNode *smiNode = NULL;
970 int i;
971
972 smi_decode_oid(elem, oid, sizeof(oid)/sizeof(unsigned int), &oidlen);
973 smiNode = smiGetNodeByOID(oidlen, oid);
974 if (! smiNode) {
975 asn1_print(elem);
976 return NULL;
977 }
978 if (vflag) {
979 fputs(smiGetNodeModule(smiNode)->name, stdout);
980 fputs("::", stdout);
981 }
982 fputs(smiNode->name, stdout);
983 if (smiNode->oidlen < oidlen) {
984 for (i = smiNode->oidlen; i < oidlen; i++) {
985 printf(".%u", oid[i]);
986 }
987 }
988 return smiNode;
989 }
990
991 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
992 {
993 unsigned int oid[128], oidlen;
994 SmiType *smiType;
995 SmiNamedNumber *nn;
996 int i, done = 0;
997
998 if (! smiNode || ! (smiNode->nodekind
999 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1000 asn1_print(elem);
1001 return;
1002 }
1003
1004 if (elem->type == BE_NOSUCHOBJECT
1005 || elem->type == BE_NOSUCHINST
1006 || elem->type == BE_ENDOFMIBVIEW) {
1007 asn1_print(elem);
1008 return;
1009 }
1010
1011 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1012 fputs("[notNotifyable]", stdout);
1013 }
1014
1015 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1016 fputs("[notReadable]", stdout);
1017 }
1018
1019 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1020 fputs("[notWritable]", stdout);
1021 }
1022
1023 if (RESPONSE_CLASS(pduid)
1024 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1025 fputs("[noAccess]", stdout);
1026 }
1027
1028 smiType = smiGetNodeType(smiNode);
1029 if (! smiType) {
1030 asn1_print(elem);
1031 return;
1032 }
1033
1034 if (! smi_check_type(smiType->basetype, elem->type)) {
1035 fputs("[wrongType]", stdout);
1036 }
1037
1038 if (! smi_check_range(smiType, elem)) {
1039 fputs("[outOfRange]", stdout);
1040 }
1041
1042 /* resolve bits to named bits */
1043
1044 /* check whether instance identifier is valid */
1045
1046 /* apply display hints (integer, octetstring) */
1047
1048 /* convert instance identifier to index type values */
1049
1050 switch (elem->type) {
1051 case BE_OID:
1052 if (smiType->basetype == SMI_BASETYPE_BITS) {
1053 /* print bit labels */
1054 } else {
1055 smi_decode_oid(elem, oid,
1056 sizeof(oid)/sizeof(unsigned int),
1057 &oidlen);
1058 smiNode = smiGetNodeByOID(oidlen, oid);
1059 if (smiNode) {
1060 if (vflag) {
1061 fputs(smiGetNodeModule(smiNode)->name, stdout);
1062 fputs("::", stdout);
1063 }
1064 fputs(smiNode->name, stdout);
1065 if (smiNode->oidlen < oidlen) {
1066 for (i = smiNode->oidlen;
1067 i < oidlen; i++) {
1068 printf(".%u", oid[i]);
1069 }
1070 }
1071 done++;
1072 }
1073 }
1074 break;
1075
1076 case BE_INT:
1077 if (smiType->basetype == SMI_BASETYPE_ENUM) {
1078 for (nn = smiGetFirstNamedNumber(smiType);
1079 nn;
1080 nn = smiGetNextNamedNumber(nn)) {
1081 if (nn->value.value.integer32
1082 == elem->data.integer) {
1083 fputs(nn->name, stdout);
1084 printf("(%d)", elem->data.integer);
1085 done++;
1086 break;
1087 }
1088 }
1089 }
1090 break;
1091 }
1092
1093 if (! done) {
1094 asn1_print(elem);
1095 }
1096 }
1097 #endif
1098
1099 /*
1100 * General SNMP header
1101 * SEQUENCE {
1102 * version INTEGER {version-1(0)},
1103 * community OCTET STRING,
1104 * data ANY -- PDUs
1105 * }
1106 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1107 * SEQUENCE {
1108 * request-id INTEGER,
1109 * error-status INTEGER,
1110 * error-index INTEGER,
1111 * varbindlist SEQUENCE OF
1112 * SEQUENCE {
1113 * name ObjectName,
1114 * value ObjectValue
1115 * }
1116 * }
1117 * PDU for Trap:
1118 * SEQUENCE {
1119 * enterprise OBJECT IDENTIFIER,
1120 * agent-addr NetworkAddress,
1121 * generic-trap INTEGER,
1122 * specific-trap INTEGER,
1123 * time-stamp TimeTicks,
1124 * varbindlist SEQUENCE OF
1125 * SEQUENCE {
1126 * name ObjectName,
1127 * value ObjectValue
1128 * }
1129 * }
1130 */
1131
1132 /*
1133 * Decode SNMP varBind
1134 */
1135 static void
1136 varbind_print(u_char pduid, const u_char *np, u_int length)
1137 {
1138 struct be elem;
1139 int count = 0, ind;
1140 #ifdef LIBSMI
1141 SmiNode *smiNode = NULL;
1142 #endif
1143
1144 /* Sequence of varBind */
1145 if ((count = asn1_parse(np, length, &elem)) < 0)
1146 return;
1147 if (elem.type != BE_SEQ) {
1148 fputs("[!SEQ of varbind]", stdout);
1149 asn1_print(&elem);
1150 return;
1151 }
1152 if (count < length)
1153 printf("[%d extra after SEQ of varbind]", length - count);
1154 /* descend */
1155 length = elem.asnlen;
1156 np = (u_char *)elem.data.raw;
1157
1158 for (ind = 1; length > 0; ind++) {
1159 const u_char *vbend;
1160 u_int vblength;
1161
1162 fputs(" ", stdout);
1163
1164 /* Sequence */
1165 if ((count = asn1_parse(np, length, &elem)) < 0)
1166 return;
1167 if (elem.type != BE_SEQ) {
1168 fputs("[!varbind]", stdout);
1169 asn1_print(&elem);
1170 return;
1171 }
1172 vbend = np + count;
1173 vblength = length - count;
1174 /* descend */
1175 length = elem.asnlen;
1176 np = (u_char *)elem.data.raw;
1177
1178 /* objName (OID) */
1179 if ((count = asn1_parse(np, length, &elem)) < 0)
1180 return;
1181 if (elem.type != BE_OID) {
1182 fputs("[objName!=OID]", stdout);
1183 asn1_print(&elem);
1184 return;
1185 }
1186 #ifdef LIBSMI
1187 smiNode = smi_print_variable(&elem);
1188 #else
1189 asn1_print(&elem);
1190 #endif
1191 length -= count;
1192 np += count;
1193
1194 if (pduid != GETREQ && pduid != GETNEXTREQ
1195 && pduid != GETBULKREQ)
1196 fputs("=", stdout);
1197
1198 /* objVal (ANY) */
1199 if ((count = asn1_parse(np, length, &elem)) < 0)
1200 return;
1201 if (pduid == GETREQ || pduid == GETNEXTREQ
1202 || pduid == GETBULKREQ) {
1203 if (elem.type != BE_NULL) {
1204 fputs("[objVal!=NULL]", stdout);
1205 asn1_print(&elem);
1206 }
1207 } else {
1208 if (elem.type != BE_NULL) {
1209 #ifdef LIBSMI
1210 smi_print_value(smiNode, pduid, &elem);
1211 #else
1212 asn1_print(&elem);
1213 #endif
1214 }
1215 }
1216 length = vblength;
1217 np = vbend;
1218 }
1219 }
1220
1221 /*
1222 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1223 * GetBulk, Inform, V2Trap, and Report
1224 */
1225 static void
1226 snmppdu_print(u_char pduid, const u_char *np, u_int length)
1227 {
1228 struct be elem;
1229 int count = 0, error;
1230
1231 /* reqId (Integer) */
1232 if ((count = asn1_parse(np, length, &elem)) < 0)
1233 return;
1234 if (elem.type != BE_INT) {
1235 fputs("[reqId!=INT]", stdout);
1236 asn1_print(&elem);
1237 return;
1238 }
1239 if (vflag)
1240 printf("R=%d ", elem.data.integer);
1241 length -= count;
1242 np += count;
1243
1244 /* errorStatus (Integer) */
1245 if ((count = asn1_parse(np, length, &elem)) < 0)
1246 return;
1247 if (elem.type != BE_INT) {
1248 fputs("[errorStatus!=INT]", stdout);
1249 asn1_print(&elem);
1250 return;
1251 }
1252 error = 0;
1253 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1254 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1255 && elem.data.integer != 0) {
1256 char errbuf[10];
1257 printf("[errorStatus(%s)!=0]",
1258 DECODE_ErrorStatus(elem.data.integer));
1259 } else if (pduid == GETBULKREQ) {
1260 printf(" N=%d", elem.data.integer);
1261 } else if (elem.data.integer != 0) {
1262 char errbuf[10];
1263 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1264 error = elem.data.integer;
1265 }
1266 length -= count;
1267 np += count;
1268
1269 /* errorIndex (Integer) */
1270 if ((count = asn1_parse(np, length, &elem)) < 0)
1271 return;
1272 if (elem.type != BE_INT) {
1273 fputs("[errorIndex!=INT]", stdout);
1274 asn1_print(&elem);
1275 return;
1276 }
1277 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1278 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1279 && elem.data.integer != 0)
1280 printf("[errorIndex(%d)!=0]", elem.data.integer);
1281 else if (pduid == GETBULKREQ)
1282 printf(" M=%d", elem.data.integer);
1283 else if (elem.data.integer != 0) {
1284 if (!error)
1285 printf("[errorIndex(%d) w/o errorStatus]",
1286 elem.data.integer);
1287 else {
1288 printf("@%d", elem.data.integer);
1289 error = elem.data.integer;
1290 }
1291 } else if (error) {
1292 fputs("[errorIndex==0]", stdout);
1293 error = 0;
1294 }
1295 length -= count;
1296 np += count;
1297
1298 varbind_print(pduid, np, length);
1299 return;
1300 }
1301
1302 /*
1303 * Decode SNMP Trap PDU
1304 */
1305 static void
1306 trappdu_print(const u_char *np, u_int length)
1307 {
1308 struct be elem;
1309 int count = 0, generic;
1310
1311 putchar(' ');
1312
1313 /* enterprise (oid) */
1314 if ((count = asn1_parse(np, length, &elem)) < 0)
1315 return;
1316 if (elem.type != BE_OID) {
1317 fputs("[enterprise!=OID]", stdout);
1318 asn1_print(&elem);
1319 return;
1320 }
1321 asn1_print(&elem);
1322 length -= count;
1323 np += count;
1324
1325 putchar(' ');
1326
1327 /* agent-addr (inetaddr) */
1328 if ((count = asn1_parse(np, length, &elem)) < 0)
1329 return;
1330 if (elem.type != BE_INETADDR) {
1331 fputs("[agent-addr!=INETADDR]", stdout);
1332 asn1_print(&elem);
1333 return;
1334 }
1335 asn1_print(&elem);
1336 length -= count;
1337 np += count;
1338
1339 /* generic-trap (Integer) */
1340 if ((count = asn1_parse(np, length, &elem)) < 0)
1341 return;
1342 if (elem.type != BE_INT) {
1343 fputs("[generic-trap!=INT]", stdout);
1344 asn1_print(&elem);
1345 return;
1346 }
1347 generic = elem.data.integer;
1348 {
1349 char buf[10];
1350 printf(" %s", DECODE_GenericTrap(generic));
1351 }
1352 length -= count;
1353 np += count;
1354
1355 /* specific-trap (Integer) */
1356 if ((count = asn1_parse(np, length, &elem)) < 0)
1357 return;
1358 if (elem.type != BE_INT) {
1359 fputs("[specific-trap!=INT]", stdout);
1360 asn1_print(&elem);
1361 return;
1362 }
1363 if (generic != GT_ENTERPRISE) {
1364 if (elem.data.integer != 0)
1365 printf("[specific-trap(%d)!=0]", elem.data.integer);
1366 } else
1367 printf(" s=%d", elem.data.integer);
1368 length -= count;
1369 np += count;
1370
1371 putchar(' ');
1372
1373 /* time-stamp (TimeTicks) */
1374 if ((count = asn1_parse(np, length, &elem)) < 0)
1375 return;
1376 if (elem.type != BE_UNS) { /* XXX */
1377 fputs("[time-stamp!=TIMETICKS]", stdout);
1378 asn1_print(&elem);
1379 return;
1380 }
1381 asn1_print(&elem);
1382 length -= count;
1383 np += count;
1384
1385 varbind_print (TRAP, np, length);
1386 return;
1387 }
1388
1389 /*
1390 * Decode arbitrary SNMP PDUs.
1391 */
1392 static void
1393 pdu_print(const u_char *np, u_int length, int version)
1394 {
1395 struct be pdu;
1396 int count = 0;
1397
1398 /* PDU (Context) */
1399 if ((count = asn1_parse(np, length, &pdu)) < 0)
1400 return;
1401 if (pdu.type != BE_PDU) {
1402 fputs("[no PDU]", stdout);
1403 return;
1404 }
1405 if (count < length)
1406 printf("[%d extra after PDU]", length - count);
1407 if (vflag) {
1408 fputs("{ ", stdout);
1409 }
1410 asn1_print(&pdu);
1411 fputs(" ", stdout);
1412 /* descend into PDU */
1413 length = pdu.asnlen;
1414 np = (u_char *)pdu.data.raw;
1415
1416 if (version == SNMP_VERSION_1 &&
1417 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1418 pdu.id == V2TRAP || pdu.id == REPORT)) {
1419 printf("[v2 PDU in v1 message]");
1420 return;
1421 }
1422
1423 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1424 printf("[v1 PDU in v2 message]");
1425 return;
1426 }
1427
1428 switch (pdu.id) {
1429 case TRAP:
1430 trappdu_print(np, length);
1431 break;
1432 case GETREQ:
1433 case GETNEXTREQ:
1434 case GETRESP:
1435 case SETREQ:
1436 case GETBULKREQ:
1437 case INFORMREQ:
1438 case V2TRAP:
1439 case REPORT:
1440 snmppdu_print(pdu.id, np, length);
1441 break;
1442 }
1443
1444 if (vflag) {
1445 fputs("} ", stdout);
1446 }
1447 }
1448
1449 /*
1450 * Decode a scoped SNMP PDU.
1451 */
1452 static void
1453 scopedpdu_print(const u_char *np, u_int length, int version)
1454 {
1455 struct be elem;
1456 int i, count = 0;
1457
1458 /* Sequence */
1459 if ((count = asn1_parse(np, length, &elem)) < 0)
1460 return;
1461 if (elem.type != BE_SEQ) {
1462 fputs("[!scoped PDU]", stdout);
1463 asn1_print(&elem);
1464 return;
1465 }
1466 length = elem.asnlen;
1467 np = (u_char *)elem.data.raw;
1468
1469 /* contextEngineID (OCTET STRING) */
1470 if ((count = asn1_parse(np, length, &elem)) < 0)
1471 return;
1472 if (elem.type != BE_STR) {
1473 fputs("[contextEngineID!=STR]", stdout);
1474 asn1_print(&elem);
1475 return;
1476 }
1477 length -= count;
1478 np += count;
1479
1480 fputs("E= ", stdout);
1481 for (i = 0; i < (int)elem.asnlen; i++) {
1482 printf("0x%02X", elem.data.str[i]);
1483 }
1484 fputs(" ", stdout);
1485
1486 /* contextName (OCTET STRING) */
1487 if ((count = asn1_parse(np, length, &elem)) < 0)
1488 return;
1489 if (elem.type != BE_STR) {
1490 fputs("[contextName!=STR]", stdout);
1491 asn1_print(&elem);
1492 return;
1493 }
1494 length -= count;
1495 np += count;
1496
1497 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1498
1499 pdu_print(np, length, version);
1500 }
1501
1502 /*
1503 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1504 */
1505 static void
1506 community_print(const u_char *np, u_int length, int version)
1507 {
1508 struct be elem;
1509 int count = 0;
1510
1511 /* Community (String) */
1512 if ((count = asn1_parse(np, length, &elem)) < 0)
1513 return;
1514 if (elem.type != BE_STR) {
1515 fputs("[comm!=STR]", stdout);
1516 asn1_print(&elem);
1517 return;
1518 }
1519 /* default community */
1520 if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
1521 sizeof(DEF_COMMUNITY) - 1))
1522 /* ! "public" */
1523 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1524 length -= count;
1525 np += count;
1526
1527 pdu_print(np, length, version);
1528 }
1529
1530 /*
1531 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1532 */
1533 static void
1534 usm_print(const u_char *np, u_int length)
1535 {
1536 struct be elem;
1537 int count = 0;
1538
1539 /* Sequence */
1540 if ((count = asn1_parse(np, length, &elem)) < 0)
1541 return;
1542 if (elem.type != BE_SEQ) {
1543 fputs("[!usm]", stdout);
1544 asn1_print(&elem);
1545 return;
1546 }
1547 length = elem.asnlen;
1548 np = (u_char *)elem.data.raw;
1549
1550 /* msgAuthoritativeEngineID (OCTET STRING) */
1551 if ((count = asn1_parse(np, length, &elem)) < 0)
1552 return;
1553 if (elem.type != BE_STR) {
1554 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1555 asn1_print(&elem);
1556 return;
1557 }
1558 length -= count;
1559 np += count;
1560
1561 /* msgAuthoritativeEngineBoots (INTEGER) */
1562 if ((count = asn1_parse(np, length, &elem)) < 0)
1563 return;
1564 if (elem.type != BE_INT) {
1565 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1566 asn1_print(&elem);
1567 return;
1568 }
1569 if (vflag)
1570 printf("B=%d ", elem.data.integer);
1571 length -= count;
1572 np += count;
1573
1574 /* msgAuthoritativeEngineTime (INTEGER) */
1575 if ((count = asn1_parse(np, length, &elem)) < 0)
1576 return;
1577 if (elem.type != BE_INT) {
1578 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1579 asn1_print(&elem);
1580 return;
1581 }
1582 if (vflag)
1583 printf("T=%d ", elem.data.integer);
1584 length -= count;
1585 np += count;
1586
1587 /* msgUserName (OCTET STRING) */
1588 if ((count = asn1_parse(np, length, &elem)) < 0)
1589 return;
1590 if (elem.type != BE_STR) {
1591 fputs("[msgUserName!=STR]", stdout);
1592 asn1_print(&elem);
1593 return;
1594 }
1595 length -= count;
1596 np += count;
1597
1598 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1599
1600 /* msgAuthenticationParameters (OCTET STRING) */
1601 if ((count = asn1_parse(np, length, &elem)) < 0)
1602 return;
1603 if (elem.type != BE_STR) {
1604 fputs("[msgAuthenticationParameters!=STR]", stdout);
1605 asn1_print(&elem);
1606 return;
1607 }
1608 length -= count;
1609 np += count;
1610
1611 /* msgPrivacyParameters (OCTET STRING) */
1612 if ((count = asn1_parse(np, length, &elem)) < 0)
1613 return;
1614 if (elem.type != BE_STR) {
1615 fputs("[msgPrivacyParameters!=STR]", stdout);
1616 asn1_print(&elem);
1617 return;
1618 }
1619 length -= count;
1620 np += count;
1621
1622 if (count < length)
1623 printf("[%d extra after usm SEQ]", length - count);
1624 }
1625
1626 /*
1627 * Decode SNMPv3 Message Header (SNMPv3)
1628 */
1629 static void
1630 v3msg_print(const u_char *np, u_int length)
1631 {
1632 struct be elem;
1633 int count = 0;
1634 u_char flags;
1635 int model;
1636 const u_char *xnp = np;
1637 int xlength = length;
1638
1639 /* Sequence */
1640 if ((count = asn1_parse(np, length, &elem)) < 0)
1641 return;
1642 if (elem.type != BE_SEQ) {
1643 fputs("[!message]", stdout);
1644 asn1_print(&elem);
1645 return;
1646 }
1647 length = elem.asnlen;
1648 np = (u_char *)elem.data.raw;
1649
1650 if (vflag) {
1651 fputs("{ ", stdout);
1652 }
1653
1654 /* msgID (INTEGER) */
1655 if ((count = asn1_parse(np, length, &elem)) < 0)
1656 return;
1657 if (elem.type != BE_INT) {
1658 fputs("[msgID!=INT]", stdout);
1659 asn1_print(&elem);
1660 return;
1661 }
1662 length -= count;
1663 np += count;
1664
1665 /* msgMaxSize (INTEGER) */
1666 if ((count = asn1_parse(np, length, &elem)) < 0)
1667 return;
1668 if (elem.type != BE_INT) {
1669 fputs("[msgMaxSize!=INT]", stdout);
1670 asn1_print(&elem);
1671 return;
1672 }
1673 length -= count;
1674 np += count;
1675
1676 /* msgFlags (OCTET STRING) */
1677 if ((count = asn1_parse(np, length, &elem)) < 0)
1678 return;
1679 if (elem.type != BE_STR) {
1680 fputs("[msgFlags!=STR]", stdout);
1681 asn1_print(&elem);
1682 return;
1683 }
1684 if (elem.asnlen != 1) {
1685 printf("[msgFlags size %d]", elem.asnlen);
1686 return;
1687 }
1688 flags = elem.data.str[0];
1689 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1690 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1691 printf("[msgFlags=0x%02X]", flags);
1692 return;
1693 }
1694 length -= count;
1695 np += count;
1696
1697 fputs("F=", stdout);
1698 if (flags & 0x01) fputs("a", stdout);
1699 if (flags & 0x02) fputs("p", stdout);
1700 if (flags & 0x04) fputs("r", stdout);
1701 fputs(" ", stdout);
1702
1703 /* msgSecurityModel (INTEGER) */
1704 if ((count = asn1_parse(np, length, &elem)) < 0)
1705 return;
1706 if (elem.type != BE_INT) {
1707 fputs("[msgSecurityModel!=INT]", stdout);
1708 asn1_print(&elem);
1709 return;
1710 }
1711 model = elem.data.integer;
1712 length -= count;
1713 np += count;
1714
1715 if (count < length)
1716 printf("[%d extra after message SEQ]", length - count);
1717
1718 if (vflag) {
1719 fputs("} ", stdout);
1720 }
1721
1722 if (model == 3) {
1723 if (vflag) {
1724 fputs("{ USM ", stdout);
1725 }
1726 } else {
1727 printf("[security model %d]", model);
1728 return;
1729 }
1730
1731 np = xnp + (np - xnp);
1732 length = xlength - (np - xnp);
1733
1734 /* msgSecurityParameters (OCTET STRING) */
1735 if ((count = asn1_parse(np, length, &elem)) < 0)
1736 return;
1737 if (elem.type != BE_STR) {
1738 fputs("[msgSecurityParameters!=STR]", stdout);
1739 asn1_print(&elem);
1740 return;
1741 }
1742 length -= count;
1743 np += count;
1744
1745 if (model == 3) {
1746 usm_print(elem.data.str, elem.asnlen);
1747 if (vflag) {
1748 fputs("} ", stdout);
1749 }
1750 }
1751
1752 if (vflag) {
1753 fputs("{ ScopedPDU ", stdout);
1754 }
1755
1756 scopedpdu_print(np, length, 3);
1757
1758 if (vflag) {
1759 fputs("} ", stdout);
1760 }
1761 }
1762
1763 /*
1764 * Decode SNMP header and pass on to PDU printing routines
1765 */
1766 void
1767 snmp_print(const u_char *np, u_int length)
1768 {
1769 struct be elem;
1770 int count = 0;
1771 int version = 0;
1772
1773 truncated = 0;
1774
1775 /* truncated packet? */
1776 if (np + length > snapend) {
1777 truncated = 1;
1778 length = snapend - np;
1779 }
1780
1781 putchar(' ');
1782
1783 /* initial Sequence */
1784 if ((count = asn1_parse(np, length, &elem)) < 0)
1785 return;
1786 if (elem.type != BE_SEQ) {
1787 fputs("[!init SEQ]", stdout);
1788 asn1_print(&elem);
1789 return;
1790 }
1791 if (count < length)
1792 printf("[%d extra after iSEQ]", length - count);
1793 /* descend */
1794 length = elem.asnlen;
1795 np = (u_char *)elem.data.raw;
1796
1797 /* Version (INTEGER) */
1798 if ((count = asn1_parse(np, length, &elem)) < 0)
1799 return;
1800 if (elem.type != BE_INT) {
1801 fputs("[version!=INT]", stdout);
1802 asn1_print(&elem);
1803 return;
1804 }
1805
1806 switch (elem.data.integer) {
1807 case SNMP_VERSION_1:
1808 case SNMP_VERSION_2:
1809 case SNMP_VERSION_3:
1810 if (vflag)
1811 printf("{ %s ", SnmpVersion[elem.data.integer]);
1812 break;
1813 default:
1814 printf("[version = %d]", elem.data.integer);
1815 return;
1816 }
1817 version = elem.data.integer;
1818 length -= count;
1819 np += count;
1820
1821 switch (version) {
1822 case SNMP_VERSION_1:
1823 case SNMP_VERSION_2:
1824 community_print(np, length, version);
1825 break;
1826 case SNMP_VERSION_3:
1827 v3msg_print(np, length);
1828 break;
1829 default:
1830 printf("[version = %d]", elem.data.integer);
1831 break;
1832 }
1833
1834 if (vflag) {
1835 fputs("} ", stdout);
1836 }
1837 }