]> The Tcpdump Group git mirrors - tcpdump/blob - print-snmp.c
9b2e7e3a88ca6d4ae6f38ca5cefccaa176d93f5c
[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.41 2000-07-01 03:39:09 assar 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 if (vflag)
432 printf("|%.2x", *p);
433 p++; len--; hdr = 1;
434 /* extended tag field */
435 if (id == ASN_ID_EXT) {
436 for (id = 0; *p & ASN_BIT8 && len > 0; len--, hdr++, p++) {
437 if (vflag)
438 printf("|%.2x", *p);
439 id = (id << 7) | (*p & ~ASN_BIT8);
440 }
441 if (len == 0 && *p & ASN_BIT8) {
442 ifNotTruncated fputs("[Xtagfield?]", stdout);
443 return -1;
444 }
445 elem->id = id = (id << 7) | *p;
446 --len;
447 ++hdr;
448 ++p;
449 }
450 if (len < 1) {
451 ifNotTruncated fputs("[no asnlen]", stdout);
452 return -1;
453 }
454 elem->asnlen = *p;
455 if (vflag)
456 printf("|%.2x", *p);
457 p++; len--; hdr++;
458 if (elem->asnlen & ASN_BIT8) {
459 int noct = elem->asnlen % ASN_BIT8;
460 elem->asnlen = 0;
461 if (len < noct) {
462 ifNotTruncated printf("[asnlen? %d<%d]", len, noct);
463 return -1;
464 }
465 for (; noct-- > 0; len--, hdr++) {
466 if (vflag)
467 printf("|%.2x", *p);
468 elem->asnlen = (elem->asnlen << ASN_SHIFT8) | *p++;
469 }
470 }
471 if (len < elem->asnlen) {
472 if (!truncated) {
473 printf("[len%d<asnlen%u]", len, elem->asnlen);
474 return -1;
475 }
476 /* maybe should check at least 4? */
477 elem->asnlen = len;
478 }
479 if (form >= sizeof(Form)/sizeof(Form[0])) {
480 ifNotTruncated printf("[form?%d]", form);
481 return -1;
482 }
483 if (class >= sizeof(Class)/sizeof(Class[0])) {
484 ifNotTruncated printf("[class?%c/%d]", *Form[form], class);
485 return -1;
486 }
487 if ((int)id >= Class[class].numIDs) {
488 ifNotTruncated printf("[id?%c/%s/%d]", *Form[form],
489 Class[class].name, id);
490 return -1;
491 }
492
493 switch (form) {
494 case PRIMITIVE:
495 switch (class) {
496 case UNIVERSAL:
497 switch (id) {
498 case STRING:
499 elem->type = BE_STR;
500 elem->data.str = p;
501 break;
502
503 case INTEGER: {
504 register int32_t data;
505 elem->type = BE_INT;
506 data = 0;
507
508 if (*p & ASN_BIT8) /* negative */
509 data = -1;
510 for (i = elem->asnlen; i-- > 0; p++)
511 data = (data << ASN_SHIFT8) | *p;
512 elem->data.integer = data;
513 break;
514 }
515
516 case OBJECTID:
517 elem->type = BE_OID;
518 elem->data.raw = (caddr_t)p;
519 break;
520
521 case ASN_NULL:
522 elem->type = BE_NULL;
523 elem->data.raw = NULL;
524 break;
525
526 default:
527 elem->type = BE_OCTET;
528 elem->data.raw = (caddr_t)p;
529 printf("[P/U/%s]",
530 Class[class].Id[id]);
531 break;
532 }
533 break;
534
535 case APPLICATION:
536 switch (id) {
537 case IPADDR:
538 elem->type = BE_INETADDR;
539 elem->data.raw = (caddr_t)p;
540 break;
541
542 case COUNTER:
543 case GAUGE:
544 case TIMETICKS: {
545 register u_int32_t data;
546 elem->type = BE_UNS;
547 data = 0;
548 for (i = elem->asnlen; i-- > 0; p++)
549 data = (data << 8) + *p;
550 elem->data.uns = data;
551 break;
552 }
553
554 case COUNTER64: {
555 register u_int32_t high, low;
556 elem->type = BE_UNS64;
557 high = 0, low = 0;
558 for (i = elem->asnlen; i-- > 0; p++) {
559 high = (high << 8) |
560 ((low & 0xFF000000) >> 24);
561 low = (low << 8) | *p;
562 }
563 elem->data.uns64.high = high;
564 elem->data.uns64.low = low;
565 break;
566 }
567
568 default:
569 elem->type = BE_OCTET;
570 elem->data.raw = (caddr_t)p;
571 printf("[P/A/%s]",
572 Class[class].Id[id]);
573 break;
574 }
575 break;
576
577 case CONTEXT:
578 switch (id) {
579 case NOSUCHOBJECT:
580 elem->type = BE_NOSUCHOBJECT;
581 elem->data.raw = NULL;
582 break;
583
584 case NOSUCHINSTANCE:
585 elem->type = BE_NOSUCHINST;
586 elem->data.raw = NULL;
587 break;
588
589 case ENDOFMIBVIEW:
590 elem->type = BE_ENDOFMIBVIEW;
591 elem->data.raw = NULL;
592 break;
593 }
594 break;
595
596 default:
597 elem->type = BE_OCTET;
598 elem->data.raw = (caddr_t)p;
599 printf("[P/%s/%s]",
600 Class[class].name, Class[class].Id[id]);
601 break;
602 }
603 break;
604
605 case CONSTRUCTED:
606 switch (class) {
607 case UNIVERSAL:
608 switch (id) {
609 case SEQUENCE:
610 elem->type = BE_SEQ;
611 elem->data.raw = (caddr_t)p;
612 break;
613
614 default:
615 elem->type = BE_OCTET;
616 elem->data.raw = (caddr_t)p;
617 printf("C/U/%s", Class[class].Id[id]);
618 break;
619 }
620 break;
621
622 case CONTEXT:
623 elem->type = BE_PDU;
624 elem->data.raw = (caddr_t)p;
625 break;
626
627 default:
628 elem->type = BE_OCTET;
629 elem->data.raw = (caddr_t)p;
630 printf("C/%s/%s",
631 Class[class].name, Class[class].Id[id]);
632 break;
633 }
634 break;
635 }
636 p += elem->asnlen;
637 len -= elem->asnlen;
638 return elem->asnlen + hdr;
639 }
640
641 /*
642 * Display the ASN.1 object represented by the BE object.
643 * This used to be an integral part of asn1_parse() before the intermediate
644 * BE form was added.
645 */
646 static void
647 asn1_print(struct be *elem)
648 {
649 u_char *p = (u_char *)elem->data.raw;
650 u_int32_t asnlen = elem->asnlen;
651 int i;
652
653 switch (elem->type) {
654
655 case BE_OCTET:
656 for (i = asnlen; i-- > 0; p++);
657 printf("_%.2x", *p);
658 break;
659
660 case BE_NULL:
661 break;
662
663 case BE_OID: {
664 int o = 0, first = -1, i = asnlen;
665
666 if (!sflag && !nflag && asnlen > 2) {
667 struct obj_abrev *a = &obj_abrev_list[0];
668 for (; a->node; a++) {
669 if (!memcmp(a->oid, (char *)p,
670 strlen(a->oid))) {
671 objp = a->node->child;
672 i -= strlen(a->oid);
673 p += strlen(a->oid);
674 fputs(a->prefix, stdout);
675 first = 1;
676 break;
677 }
678 }
679 }
680
681 for (; !sflag && i-- > 0; p++) {
682 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
683 if (*p & ASN_LONGLEN)
684 continue;
685
686 /*
687 * first subitem encodes two items with 1st*OIDMUX+2nd
688 */
689 if (first < 0) {
690 if (!nflag)
691 objp = mibroot;
692 first = 0;
693 OBJ_PRINT(o/OIDMUX, first);
694 o %= OIDMUX;
695 }
696 OBJ_PRINT(o, first);
697 if (--first < 0)
698 first = 0;
699 o = 0;
700 }
701 break;
702 }
703
704 case BE_INT:
705 printf("%d", elem->data.integer);
706 break;
707
708 case BE_UNS:
709 printf("%u", elem->data.uns);
710 break;
711
712 case BE_UNS64: { /* idea borrowed from by Marshall Rose */
713 double d;
714 int j, carry;
715 char *cpf, *cpl, last[6], first[30];
716 if (elem->data.uns64.high == 0) {
717 printf("%u", elem->data.uns64.low);
718 break;
719 }
720 d = elem->data.uns64.high * 4294967296.0; /* 2^32 */
721 if (elem->data.uns64.high <= 0x1fffff) {
722 d += elem->data.uns64.low;
723 #if 0 /*is looks illegal, but what is the intention???*/
724 printf("%.f", d);
725 #else
726 printf("%f", d);
727 #endif
728 break;
729 }
730 d += (elem->data.uns64.low & 0xfffff000);
731 #if 0 /*is looks illegal, but what is the intention???*/
732 snprintf(first, sizeof(first), "%.f", d);
733 #else
734 snprintf(first, sizeof(first), "%f", d);
735 #endif
736 snprintf(last, sizeof(last), "%5.5d",
737 elem->data.uns64.low & 0xfff);
738 for (carry = 0, cpf = first+strlen(first)-1, cpl = last+4;
739 cpl >= last;
740 cpf--, cpl--) {
741 j = carry + (*cpf - '0') + (*cpl - '0');
742 if (j > 9) {
743 j -= 10;
744 carry = 1;
745 } else {
746 carry = 0;
747 }
748 *cpf = j + '0';
749 }
750 fputs(first, stdout);
751 break;
752 }
753
754 case BE_STR: {
755 register int printable = 1, first = 1;
756 const u_char *p = elem->data.str;
757 for (i = asnlen; printable && i-- > 0; p++)
758 printable = isprint(*p) || isspace(*p);
759 p = elem->data.str;
760 if (printable) {
761 putchar('"');
762 (void)fn_print(p, p + asnlen);
763 putchar('"');
764 } else
765 for (i = asnlen; i-- > 0; p++) {
766 printf(first ? "%.2x" : "_%.2x", *p);
767 first = 0;
768 }
769 break;
770 }
771
772 case BE_SEQ:
773 printf("Seq(%u)", elem->asnlen);
774 break;
775
776 case BE_INETADDR:
777 if (asnlen != ASNLEN_INETADDR)
778 printf("[inetaddr len!=%d]", ASNLEN_INETADDR);
779 for (i = asnlen; i-- > 0; p++) {
780 printf((i == asnlen-1) ? "%u" : ".%u", *p);
781 }
782 break;
783
784 case BE_NOSUCHOBJECT:
785 case BE_NOSUCHINST:
786 case BE_ENDOFMIBVIEW:
787 printf("[%s]", Class[EXCEPTIONS].Id[elem->id]);
788 break;
789
790 case BE_PDU:
791 printf("%s(%u)",
792 Class[CONTEXT].Id[elem->id], elem->asnlen);
793 break;
794
795 case BE_ANY:
796 fputs("[BE_ANY!?]", stdout);
797 break;
798
799 default:
800 fputs("[be!?]", stdout);
801 break;
802 }
803 }
804
805 #ifdef notdef
806 /*
807 * This is a brute force ASN.1 printer: recurses to dump an entire structure.
808 * This will work for any ASN.1 stream, not just an SNMP PDU.
809 *
810 * By adding newlines and spaces at the correct places, this would print in
811 * Rose-Normal-Form.
812 *
813 * This is not currently used.
814 */
815 static void
816 asn1_decode(u_char *p, u_int length)
817 {
818 struct be elem;
819 int i = 0;
820
821 while (i >= 0 && length > 0) {
822 i = asn1_parse(p, length, &elem);
823 if (i >= 0) {
824 fputs(" ", stdout);
825 asn1_print(&elem);
826 if (elem.type == BE_SEQ || elem.type == BE_PDU) {
827 fputs(" {", stdout);
828 asn1_decode(elem.data.raw, elem.asnlen);
829 fputs(" }", stdout);
830 }
831 length -= i;
832 p += i;
833 }
834 }
835 }
836 #endif
837
838 #ifdef LIBSMI
839
840 struct smi2be {
841 SmiBasetype basetype;
842 int be;
843 };
844
845 struct smi2be smi2betab[] = {
846 { SMI_BASETYPE_INTEGER32, BE_INT },
847 { SMI_BASETYPE_OCTETSTRING, BE_STR },
848 { SMI_BASETYPE_OCTETSTRING, BE_INETADDR },
849 { SMI_BASETYPE_OBJECTIDENTIFIER, BE_OID },
850 { SMI_BASETYPE_UNSIGNED32, BE_UNS },
851 { SMI_BASETYPE_INTEGER64, BE_NONE },
852 { SMI_BASETYPE_UNSIGNED64, BE_UNS64 },
853 { SMI_BASETYPE_FLOAT32, BE_NONE },
854 { SMI_BASETYPE_FLOAT64, BE_NONE },
855 { SMI_BASETYPE_FLOAT128, BE_NONE },
856 { SMI_BASETYPE_ENUM, BE_INT },
857 { SMI_BASETYPE_BITS, BE_STR },
858 { SMI_BASETYPE_UNKNOWN, BE_NONE }
859 };
860
861 static void smi_decode_oid(struct be *elem, unsigned int *oid,
862 unsigned int *oidlen)
863 {
864 u_char *p = (u_char *)elem->data.raw;
865 u_int32_t asnlen = elem->asnlen;
866 int o = 0, first = -1, i = asnlen;
867
868 for (*oidlen = 0; sflag && i-- > 0; p++) {
869 o = (o << ASN_SHIFT7) + (*p & ~ASN_BIT8);
870 if (*p & ASN_LONGLEN)
871 continue;
872
873 /*
874 * first subitem encodes two items with 1st*OIDMUX+2nd
875 */
876 if (first < 0) {
877 first = 0;
878 oid[(*oidlen)++] = o/OIDMUX;
879 o %= OIDMUX;
880 }
881 oid[(*oidlen)++] = o;
882 o = 0;
883 }
884 }
885
886 static int smi_check_type(SmiBasetype basetype, int be)
887 {
888 int i;
889
890 for (i = 0; smi2betab[i].basetype != SMI_BASETYPE_UNKNOWN; i++) {
891 if (smi2betab[i].basetype == basetype && smi2betab[i].be == be) {
892 return 1;
893 }
894 }
895
896 return 0;
897 }
898
899 static int smi_check_a_range(SmiType *smiType, SmiRange *smiRange,
900 struct be *elem)
901 {
902 int ok;
903
904 switch (smiType->basetype) {
905 case SMI_BASETYPE_OBJECTIDENTIFIER:
906 case SMI_BASETYPE_OCTETSTRING:
907 if (smiRange->minValue.value.unsigned32
908 == smiRange->maxValue.value.unsigned32) {
909 ok = (elem->asnlen == smiRange->minValue.value.unsigned32);
910 } else {
911 ok = (elem->asnlen >= smiRange->minValue.value.unsigned32
912 && elem->asnlen <= smiRange->maxValue.value.unsigned32);
913 }
914 break;
915
916 case SMI_BASETYPE_INTEGER32:
917 ok = (elem->data.integer >= smiRange->minValue.value.integer32
918 && elem->data.integer <= smiRange->maxValue.value.integer32);
919 break;
920
921 case SMI_BASETYPE_UNSIGNED32:
922 ok = (elem->data.uns >= smiRange->minValue.value.unsigned32
923 && elem->data.uns <= smiRange->maxValue.value.unsigned32);
924 break;
925
926 case SMI_BASETYPE_UNSIGNED64:
927 /* XXX */
928 break;
929
930 /* case SMI_BASETYPE_INTEGER64: SMIng */
931 /* case SMI_BASETYPE_FLOAT32: SMIng */
932 /* case SMI_BASETYPE_FLOAT64: SMIng */
933 /* case SMI_BASETYPE_FLOAT128: SMIng */
934
935 case SMI_BASETYPE_ENUM:
936 case SMI_BASETYPE_BITS:
937 case SMI_BASETYPE_UNKNOWN:
938 ok = 1;
939 break;
940 }
941
942 return ok;
943 }
944
945 static int smi_check_range(SmiType *smiType, struct be *elem)
946 {
947 SmiRange *smiRange;
948 int ok = 1;
949
950 for (smiRange = smiGetFirstRange(smiType->module, smiType->name);
951 smiRange;
952 smiRange = smiGetNextRange(smiRange)) {
953
954 ok = smi_check_a_range(smiType, smiRange, elem);
955
956 if (ok) {
957 smiFreeRange(smiRange);
958 break;
959 }
960 }
961
962 if (ok && smiType->parentmodule && smiType->parentname) {
963 SmiType *parentType;
964 parentType = smiGetType(smiType->parentmodule,
965 smiType->parentname);
966 if (parentType) {
967 ok = smi_check_range(parentType, elem);
968 smiFreeType(parentType);
969 }
970 }
971
972 return ok;
973 }
974
975 static SmiNode *smi_print_variable(struct be *elem)
976 {
977 unsigned int oid[128], oidlen;
978 SmiNode *smiNode = NULL;
979 int i;
980
981 smi_decode_oid(elem, oid, &oidlen);
982 smiNode = smiGetNodeByOID(oidlen, oid);
983 if (! smiNode) {
984 asn1_print(elem);
985 return NULL;
986 }
987 if (vflag) {
988 fputs(smiNode->module, stdout);
989 fputs("::", stdout);
990 }
991 fputs(smiNode->name, stdout);
992 if (smiNode->oidlen < oidlen) {
993 for (i = smiNode->oidlen; i < oidlen; i++) {
994 printf(".%u", oid[i]);
995 }
996 }
997 return smiNode;
998 }
999
1000 static void smi_print_value(SmiNode *smiNode, u_char pduid, struct be *elem)
1001 {
1002 unsigned int oid[128], oidlen;
1003 SmiType *smiType;
1004 SmiNamedNumber *nn;
1005 int i, done = 0;
1006
1007 if (! smiNode || ! (smiNode->nodekind
1008 & (SMI_NODEKIND_SCALAR | SMI_NODEKIND_COLUMN))) {
1009 asn1_print(elem);
1010 return;
1011 }
1012
1013 if (NOTIFY_CLASS(pduid) && smiNode->access < SMI_ACCESS_NOTIFY) {
1014 fputs("[notNotifyable]", stdout);
1015 }
1016
1017 if (READ_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_ONLY) {
1018 fputs("[notReadable]", stdout);
1019 }
1020
1021 if (WRITE_CLASS(pduid) && smiNode->access < SMI_ACCESS_READ_WRITE) {
1022 fputs("[notWritable]", stdout);
1023 }
1024
1025 if (RESPONSE_CLASS(pduid)
1026 && smiNode->access == SMI_ACCESS_NOT_ACCESSIBLE) {
1027 fputs("[noAccess]", stdout);
1028 }
1029
1030 if (! smi_check_type(smiNode->basetype, elem->type)) {
1031 fputs("[wrongType]", stdout);
1032 }
1033
1034 smiType = smiGetType(smiNode->typemodule, smiNode->typename);
1035 if (! smiType) {
1036 asn1_print(elem);
1037 return;
1038 }
1039
1040 if (! smi_check_range(smiType, elem)) {
1041 fputs("[wrongLength]", stdout);
1042 }
1043
1044 /* resolve bits to named bits */
1045
1046 /* check whether instance identifier is valid */
1047
1048 /* apply display hints (integer, octetstring) */
1049
1050 /* convert instance identifier to index type values */
1051
1052 switch (elem->type) {
1053 case BE_OID:
1054 if (smiNode->basetype == SMI_BASETYPE_BITS
1055 && smiNode->typemodule && smiNode->typename) {
1056 /* print bit labels */
1057 } else {
1058 smi_decode_oid(elem, oid, &oidlen);
1059 smiNode = smiGetNodeByOID(oidlen, oid);
1060 if (smiNode) {
1061 if (vflag) {
1062 fputs(smiNode->module, stdout);
1063 fputs("::", stdout);
1064 }
1065 fputs(smiNode->name, stdout);
1066 if (smiNode->oidlen < oidlen) {
1067 for (i = smiNode->oidlen;
1068 i < oidlen; i++) {
1069 printf(".%u", oid[i]);
1070 }
1071 }
1072 done++;
1073 }
1074 }
1075 break;
1076
1077 case BE_INT:
1078 if (smiNode->basetype == SMI_BASETYPE_ENUM
1079 && smiNode->typemodule && smiNode->typename) {
1080 for (nn = smiGetFirstNamedNumber(smiNode->typemodule,
1081 smiNode->typename);
1082 nn;
1083 nn = smiGetNextNamedNumber(nn)) {
1084 if (nn->value.value.integer32
1085 == elem->data.integer) {
1086 fputs(nn->name, stdout);
1087 printf("(%d)", elem->data.integer);
1088 done++;
1089 break;
1090 }
1091 }
1092 }
1093 break;
1094 }
1095
1096 if (! done) {
1097 asn1_print(elem);
1098 }
1099
1100 if (smiType) {
1101 smiFreeType(smiType);
1102 }
1103 }
1104 #endif
1105
1106 /*
1107 * General SNMP header
1108 * SEQUENCE {
1109 * version INTEGER {version-1(0)},
1110 * community OCTET STRING,
1111 * data ANY -- PDUs
1112 * }
1113 * PDUs for all but Trap: (see rfc1157 from page 15 on)
1114 * SEQUENCE {
1115 * request-id INTEGER,
1116 * error-status INTEGER,
1117 * error-index INTEGER,
1118 * varbindlist SEQUENCE OF
1119 * SEQUENCE {
1120 * name ObjectName,
1121 * value ObjectValue
1122 * }
1123 * }
1124 * PDU for Trap:
1125 * SEQUENCE {
1126 * enterprise OBJECT IDENTIFIER,
1127 * agent-addr NetworkAddress,
1128 * generic-trap INTEGER,
1129 * specific-trap INTEGER,
1130 * time-stamp TimeTicks,
1131 * varbindlist SEQUENCE OF
1132 * SEQUENCE {
1133 * name ObjectName,
1134 * value ObjectValue
1135 * }
1136 * }
1137 */
1138
1139 /*
1140 * Decode SNMP varBind
1141 */
1142 static void
1143 varbind_print(u_char pduid, const u_char *np, u_int length)
1144 {
1145 struct be elem;
1146 int count = 0, ind;
1147 #ifdef LIBSMI
1148 SmiNode *smiNode = NULL;
1149 #endif
1150
1151 /* Sequence of varBind */
1152 if ((count = asn1_parse(np, length, &elem)) < 0)
1153 return;
1154 if (elem.type != BE_SEQ) {
1155 fputs("[!SEQ of varbind]", stdout);
1156 asn1_print(&elem);
1157 return;
1158 }
1159 if (count < length)
1160 printf("[%d extra after SEQ of varbind]", length - count);
1161 /* descend */
1162 length = elem.asnlen;
1163 np = (u_char *)elem.data.raw;
1164
1165 for (ind = 1; length > 0; ind++) {
1166 const u_char *vbend;
1167 u_int vblength;
1168
1169 fputs(" ", stdout);
1170
1171 /* Sequence */
1172 if ((count = asn1_parse(np, length, &elem)) < 0)
1173 return;
1174 if (elem.type != BE_SEQ) {
1175 fputs("[!varbind]", stdout);
1176 asn1_print(&elem);
1177 return;
1178 }
1179 vbend = np + count;
1180 vblength = length - count;
1181 /* descend */
1182 length = elem.asnlen;
1183 np = (u_char *)elem.data.raw;
1184
1185 /* objName (OID) */
1186 if ((count = asn1_parse(np, length, &elem)) < 0)
1187 return;
1188 if (elem.type != BE_OID) {
1189 fputs("[objName!=OID]", stdout);
1190 asn1_print(&elem);
1191 return;
1192 }
1193 #ifdef LIBSMI
1194 smiNode = smi_print_variable(&elem);
1195 #else
1196 asn1_print(&elem);
1197 #endif
1198 length -= count;
1199 np += count;
1200
1201 if (pduid != GETREQ && pduid != GETNEXTREQ
1202 && pduid != GETBULKREQ)
1203 fputs("=", stdout);
1204
1205 /* objVal (ANY) */
1206 if ((count = asn1_parse(np, length, &elem)) < 0)
1207 return;
1208 if (pduid == GETREQ || pduid == GETNEXTREQ
1209 || pduid == GETBULKREQ) {
1210 if (elem.type != BE_NULL) {
1211 fputs("[objVal!=NULL]", stdout);
1212 asn1_print(&elem);
1213 }
1214 } else {
1215 if (elem.type != BE_NULL) {
1216 #ifdef LIBSMI
1217 smi_print_value(smiNode, pduid, &elem);
1218 smiFreeNode(smiNode);
1219 #else
1220 asn1_print(&elem);
1221 #endif
1222 }
1223 }
1224 length = vblength;
1225 np = vbend;
1226 }
1227 }
1228
1229 /*
1230 * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, SetRequest,
1231 * GetBulk, Inform, V2Trap, and Report
1232 */
1233 static void
1234 snmppdu_print(u_char pduid, const u_char *np, u_int length)
1235 {
1236 struct be elem;
1237 int count = 0, error;
1238
1239 /* reqId (Integer) */
1240 if ((count = asn1_parse(np, length, &elem)) < 0)
1241 return;
1242 if (elem.type != BE_INT) {
1243 fputs("[reqId!=INT]", stdout);
1244 asn1_print(&elem);
1245 return;
1246 }
1247 /* ignore the reqId */
1248 length -= count;
1249 np += count;
1250
1251 /* errorStatus (Integer) */
1252 if ((count = asn1_parse(np, length, &elem)) < 0)
1253 return;
1254 if (elem.type != BE_INT) {
1255 fputs("[errorStatus!=INT]", stdout);
1256 asn1_print(&elem);
1257 return;
1258 }
1259 error = 0;
1260 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1261 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1262 && elem.data.integer != 0) {
1263 char errbuf[10];
1264 printf("[errorStatus(%s)!=0]",
1265 DECODE_ErrorStatus(elem.data.integer));
1266 } else if (pduid == GETBULKREQ) {
1267 printf(" N=%d", elem.data.integer);
1268 } else if (elem.data.integer != 0) {
1269 char errbuf[10];
1270 printf(" %s", DECODE_ErrorStatus(elem.data.integer));
1271 error = elem.data.integer;
1272 }
1273 length -= count;
1274 np += count;
1275
1276 /* errorIndex (Integer) */
1277 if ((count = asn1_parse(np, length, &elem)) < 0)
1278 return;
1279 if (elem.type != BE_INT) {
1280 fputs("[errorIndex!=INT]", stdout);
1281 asn1_print(&elem);
1282 return;
1283 }
1284 if ((pduid == GETREQ || pduid == GETNEXTREQ || pduid == SETREQ
1285 || pduid == INFORMREQ || pduid == V2TRAP || pduid == REPORT)
1286 && elem.data.integer != 0)
1287 printf("[errorIndex(%d)!=0]", elem.data.integer);
1288 else if (pduid == GETBULKREQ)
1289 printf(" M=%d", elem.data.integer);
1290 else if (elem.data.integer != 0) {
1291 if (!error)
1292 printf("[errorIndex(%d) w/o errorStatus]",
1293 elem.data.integer);
1294 else {
1295 printf("@%d", elem.data.integer);
1296 error = elem.data.integer;
1297 }
1298 } else if (error) {
1299 fputs("[errorIndex==0]", stdout);
1300 error = 0;
1301 }
1302 length -= count;
1303 np += count;
1304
1305 varbind_print(pduid, np, length);
1306 return;
1307 }
1308
1309 /*
1310 * Decode SNMP Trap PDU
1311 */
1312 static void
1313 trappdu_print(const u_char *np, u_int length)
1314 {
1315 struct be elem;
1316 int count = 0, generic;
1317
1318 putchar(' ');
1319
1320 /* enterprise (oid) */
1321 if ((count = asn1_parse(np, length, &elem)) < 0)
1322 return;
1323 if (elem.type != BE_OID) {
1324 fputs("[enterprise!=OID]", stdout);
1325 asn1_print(&elem);
1326 return;
1327 }
1328 asn1_print(&elem);
1329 length -= count;
1330 np += count;
1331
1332 putchar(' ');
1333
1334 /* agent-addr (inetaddr) */
1335 if ((count = asn1_parse(np, length, &elem)) < 0)
1336 return;
1337 if (elem.type != BE_INETADDR) {
1338 fputs("[agent-addr!=INETADDR]", stdout);
1339 asn1_print(&elem);
1340 return;
1341 }
1342 asn1_print(&elem);
1343 length -= count;
1344 np += count;
1345
1346 /* generic-trap (Integer) */
1347 if ((count = asn1_parse(np, length, &elem)) < 0)
1348 return;
1349 if (elem.type != BE_INT) {
1350 fputs("[generic-trap!=INT]", stdout);
1351 asn1_print(&elem);
1352 return;
1353 }
1354 generic = elem.data.integer;
1355 {
1356 char buf[10];
1357 printf(" %s", DECODE_GenericTrap(generic));
1358 }
1359 length -= count;
1360 np += count;
1361
1362 /* specific-trap (Integer) */
1363 if ((count = asn1_parse(np, length, &elem)) < 0)
1364 return;
1365 if (elem.type != BE_INT) {
1366 fputs("[specific-trap!=INT]", stdout);
1367 asn1_print(&elem);
1368 return;
1369 }
1370 if (generic != GT_ENTERPRISE) {
1371 if (elem.data.integer != 0)
1372 printf("[specific-trap(%d)!=0]", elem.data.integer);
1373 } else
1374 printf(" s=%d", elem.data.integer);
1375 length -= count;
1376 np += count;
1377
1378 putchar(' ');
1379
1380 /* time-stamp (TimeTicks) */
1381 if ((count = asn1_parse(np, length, &elem)) < 0)
1382 return;
1383 if (elem.type != BE_UNS) { /* XXX */
1384 fputs("[time-stamp!=TIMETICKS]", stdout);
1385 asn1_print(&elem);
1386 return;
1387 }
1388 asn1_print(&elem);
1389 length -= count;
1390 np += count;
1391
1392 varbind_print (TRAP, np, length);
1393 return;
1394 }
1395
1396 /*
1397 * Decode arbitrary SNMP PDUs.
1398 */
1399 static void
1400 pdu_print(const u_char *np, u_int length, int version)
1401 {
1402 struct be pdu;
1403 int count = 0;
1404
1405 /* PDU (Context) */
1406 if ((count = asn1_parse(np, length, &pdu)) < 0)
1407 return;
1408 if (pdu.type != BE_PDU) {
1409 fputs("[no PDU]", stdout);
1410 return;
1411 }
1412 if (count < length)
1413 printf("[%d extra after PDU]", length - count);
1414 asn1_print(&pdu);
1415 /* descend into PDU */
1416 length = pdu.asnlen;
1417 np = (u_char *)pdu.data.raw;
1418
1419 if (version == SNMP_VERSION_1 &&
1420 (pdu.id == GETBULKREQ || pdu.id == INFORMREQ ||
1421 pdu.id == V2TRAP || pdu.id == REPORT)) {
1422 printf("[v2 PDU in v1 message]");
1423 return;
1424 }
1425
1426 if (version == SNMP_VERSION_2 && pdu.id == TRAP) {
1427 printf("[v1 PDU in v2 message]");
1428 return;
1429 }
1430
1431 switch (pdu.id) {
1432 case TRAP:
1433 trappdu_print(np, length);
1434 break;
1435 case GETREQ:
1436 case GETNEXTREQ:
1437 case GETRESP:
1438 case SETREQ:
1439 case GETBULKREQ:
1440 case INFORMREQ:
1441 case V2TRAP:
1442 case REPORT:
1443 snmppdu_print(pdu.id, np, length);
1444 break;
1445 }
1446 }
1447
1448 /*
1449 * Decode a scoped SNMP PDU.
1450 */
1451 static void
1452 scopedpdu_print(const u_char *np, u_int length, int version)
1453 {
1454 struct be elem;
1455 int i, count = 0;
1456
1457 /* Sequence */
1458 if ((count = asn1_parse(np, length, &elem)) < 0)
1459 return;
1460 if (elem.type != BE_SEQ) {
1461 fputs("[!scoped PDU]", stdout);
1462 asn1_print(&elem);
1463 return;
1464 }
1465 length = elem.asnlen;
1466 np = (u_char *)elem.data.raw;
1467
1468 /* contextEngineID (OCTET STRING) */
1469 if ((count = asn1_parse(np, length, &elem)) < 0)
1470 return;
1471 if (elem.type != BE_STR) {
1472 fputs("[contextEngineID!=STR]", stdout);
1473 asn1_print(&elem);
1474 return;
1475 }
1476 length -= count;
1477 np += count;
1478
1479 fputs("E= ", stdout);
1480 for (i = 0; i < (int)elem.asnlen; i++) {
1481 printf("0x%02X", elem.data.str[i]);
1482 }
1483 fputs(" ", stdout);
1484
1485 /* contextName (OCTET STRING) */
1486 if ((count = asn1_parse(np, length, &elem)) < 0)
1487 return;
1488 if (elem.type != BE_STR) {
1489 fputs("[contextName!=STR]", stdout);
1490 asn1_print(&elem);
1491 return;
1492 }
1493 length -= count;
1494 np += count;
1495
1496 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1497
1498 pdu_print(np, length, version);
1499 }
1500
1501 /*
1502 * Decode SNMP Community Header (SNMPv1 and SNMPv2c)
1503 */
1504 static void
1505 community_print(const u_char *np, u_int length, int version)
1506 {
1507 struct be elem;
1508 int count = 0;
1509
1510 /* Community (String) */
1511 if ((count = asn1_parse(np, length, &elem)) < 0)
1512 return;
1513 if (elem.type != BE_STR) {
1514 fputs("[comm!=STR]", stdout);
1515 asn1_print(&elem);
1516 return;
1517 }
1518 /* default community */
1519 if (strncmp((char *)elem.data.str, DEF_COMMUNITY,
1520 sizeof(DEF_COMMUNITY) - 1))
1521 /* ! "public" */
1522 printf("C=%.*s ", (int)elem.asnlen, elem.data.str);
1523 length -= count;
1524 np += count;
1525
1526 pdu_print(np, length, version);
1527 }
1528
1529 /*
1530 * Decode SNMPv3 User-based Security Message Header (SNMPv3)
1531 */
1532 static void
1533 usm_print(const u_char *np, u_int length)
1534 {
1535 struct be elem;
1536 int count = 0;
1537
1538 /* Sequence */
1539 if ((count = asn1_parse(np, length, &elem)) < 0)
1540 return;
1541 if (elem.type != BE_SEQ) {
1542 fputs("[!usm]", stdout);
1543 asn1_print(&elem);
1544 return;
1545 }
1546 length = elem.asnlen;
1547 np = (u_char *)elem.data.raw;
1548
1549 /* msgAuthoritativeEngineID (OCTET STRING) */
1550 if ((count = asn1_parse(np, length, &elem)) < 0)
1551 return;
1552 if (elem.type != BE_STR) {
1553 fputs("[msgAuthoritativeEngineID!=STR]", stdout);
1554 asn1_print(&elem);
1555 return;
1556 }
1557 length -= count;
1558 np += count;
1559
1560 /* msgAuthoritativeEngineBoots (INTEGER) */
1561 if ((count = asn1_parse(np, length, &elem)) < 0)
1562 return;
1563 if (elem.type != BE_INT) {
1564 fputs("[msgAuthoritativeEngineBoots!=INT]", stdout);
1565 asn1_print(&elem);
1566 return;
1567 }
1568 if (vflag)
1569 printf("B=%d ", elem.data.integer);
1570 length -= count;
1571 np += count;
1572
1573 /* msgAuthoritativeEngineTime (INTEGER) */
1574 if ((count = asn1_parse(np, length, &elem)) < 0)
1575 return;
1576 if (elem.type != BE_INT) {
1577 fputs("[msgAuthoritativeEngineTime!=INT]", stdout);
1578 asn1_print(&elem);
1579 return;
1580 }
1581 if (vflag)
1582 printf("T=%d ", elem.data.integer);
1583 length -= count;
1584 np += count;
1585
1586 /* msgUserName (OCTET STRING) */
1587 if ((count = asn1_parse(np, length, &elem)) < 0)
1588 return;
1589 if (elem.type != BE_STR) {
1590 fputs("[msgUserName!=STR]", stdout);
1591 asn1_print(&elem);
1592 return;
1593 }
1594 length -= count;
1595 np += count;
1596
1597 printf("U=%.*s ", (int)elem.asnlen, elem.data.str);
1598
1599 /* msgAuthenticationParameters (OCTET STRING) */
1600 if ((count = asn1_parse(np, length, &elem)) < 0)
1601 return;
1602 if (elem.type != BE_STR) {
1603 fputs("[msgAuthenticationParameters!=STR]", stdout);
1604 asn1_print(&elem);
1605 return;
1606 }
1607 length -= count;
1608 np += count;
1609
1610 /* msgPrivacyParameters (OCTET STRING) */
1611 if ((count = asn1_parse(np, length, &elem)) < 0)
1612 return;
1613 if (elem.type != BE_STR) {
1614 fputs("[msgPrivacyParameters!=STR]", stdout);
1615 asn1_print(&elem);
1616 return;
1617 }
1618 length -= count;
1619 np += count;
1620
1621 if (count < length)
1622 printf("[%d extra after usm SEQ]", length - count);
1623 }
1624
1625 /*
1626 * Decode SNMPv3 Message Header (SNMPv3)
1627 */
1628 static void
1629 v3msg_print(const u_char *np, u_int length)
1630 {
1631 struct be elem;
1632 int count = 0;
1633 u_char flags;
1634 int model;
1635 const u_char *xnp = np;
1636 int xlength = length;
1637
1638 /* Sequence */
1639 if ((count = asn1_parse(np, length, &elem)) < 0)
1640 return;
1641 if (elem.type != BE_SEQ) {
1642 fputs("[!message]", stdout);
1643 asn1_print(&elem);
1644 return;
1645 }
1646 length = elem.asnlen;
1647 np = (u_char *)elem.data.raw;
1648
1649 /* msgID (INTEGER) */
1650 if ((count = asn1_parse(np, length, &elem)) < 0)
1651 return;
1652 if (elem.type != BE_INT) {
1653 fputs("[msgID!=INT]", stdout);
1654 asn1_print(&elem);
1655 return;
1656 }
1657 length -= count;
1658 np += count;
1659
1660 /* msgMaxSize (INTEGER) */
1661 if ((count = asn1_parse(np, length, &elem)) < 0)
1662 return;
1663 if (elem.type != BE_INT) {
1664 fputs("[msgMaxSize!=INT]", stdout);
1665 asn1_print(&elem);
1666 return;
1667 }
1668 length -= count;
1669 np += count;
1670
1671 /* msgFlags (OCTET STRING) */
1672 if ((count = asn1_parse(np, length, &elem)) < 0)
1673 return;
1674 if (elem.type != BE_STR) {
1675 fputs("[msgFlags!=STR]", stdout);
1676 asn1_print(&elem);
1677 return;
1678 }
1679 if (elem.asnlen != 1) {
1680 printf("[msgFlags size %d]", elem.asnlen);
1681 return;
1682 }
1683 flags = elem.data.str[0];
1684 if (flags != 0x00 && flags != 0x01 && flags != 0x03
1685 && flags != 0x04 && flags != 0x05 && flags != 0x07) {
1686 printf("[msgFlags=0x%02X]", flags);
1687 return;
1688 }
1689 length -= count;
1690 np += count;
1691
1692 fputs("F=", stdout);
1693 if (flags & 0x01) fputs("a", stdout);
1694 if (flags & 0x02) fputs("p", stdout);
1695 if (flags & 0x04) fputs("r", stdout);
1696 fputs(" ", stdout);
1697
1698 /* msgSecurityModel (INTEGER) */
1699 if ((count = asn1_parse(np, length, &elem)) < 0)
1700 return;
1701 if (elem.type != BE_INT) {
1702 fputs("[msgSecurityModel!=INT]", stdout);
1703 asn1_print(&elem);
1704 return;
1705 }
1706 model = elem.data.integer;
1707 length -= count;
1708 np += count;
1709
1710 if (count < length)
1711 printf("[%d extra after message SEQ]", length - count);
1712
1713 if (model == 3) {
1714 if (vflag) {
1715 fputs("USM ", stdout);
1716 }
1717 } else {
1718 printf("[security model %d]", model);
1719 return;
1720 }
1721
1722 np = xnp + (np - xnp);
1723 length = xlength - (np - xnp);
1724
1725 /* msgSecurityParameters (OCTET STRING) */
1726 if ((count = asn1_parse(np, length, &elem)) < 0)
1727 return;
1728 if (elem.type != BE_STR) {
1729 fputs("[msgSecurityParameters!=STR]", stdout);
1730 asn1_print(&elem);
1731 return;
1732 }
1733 length -= count;
1734 np += count;
1735
1736 if (model == 3) {
1737 usm_print(elem.data.str, elem.asnlen);
1738 }
1739
1740 if (vflag) {
1741 fputs("ScopedPDU ", stdout);
1742 }
1743
1744 scopedpdu_print(np, length, 3);
1745 }
1746
1747 /*
1748 * Decode SNMP header and pass on to PDU printing routines
1749 */
1750 void
1751 snmp_print(const u_char *np, u_int length)
1752 {
1753 struct be elem;
1754 int count = 0;
1755 int version = 0;
1756
1757 truncated = 0;
1758
1759 /* truncated packet? */
1760 if (np + length > snapend) {
1761 truncated = 1;
1762 length = snapend - np;
1763 }
1764
1765 putchar(' ');
1766
1767 /* initial Sequence */
1768 if ((count = asn1_parse(np, length, &elem)) < 0)
1769 return;
1770 if (elem.type != BE_SEQ) {
1771 fputs("[!init SEQ]", stdout);
1772 asn1_print(&elem);
1773 return;
1774 }
1775 if (count < length)
1776 printf("[%d extra after iSEQ]", length - count);
1777 /* descend */
1778 length = elem.asnlen;
1779 np = (u_char *)elem.data.raw;
1780
1781 /* Version (INTEGER) */
1782 if ((count = asn1_parse(np, length, &elem)) < 0)
1783 return;
1784 if (elem.type != BE_INT) {
1785 fputs("[version!=INT]", stdout);
1786 asn1_print(&elem);
1787 return;
1788 }
1789
1790 switch (elem.data.integer) {
1791 case SNMP_VERSION_1:
1792 case SNMP_VERSION_2:
1793 case SNMP_VERSION_3:
1794 if (vflag)
1795 printf("%s ", SnmpVersion[elem.data.integer]);
1796 break;
1797 default:
1798 printf("[version = %d]", elem.data.integer);
1799 return;
1800 }
1801 version = elem.data.integer;
1802 length -= count;
1803 np += count;
1804
1805 switch (version) {
1806 case SNMP_VERSION_1:
1807 case SNMP_VERSION_2:
1808 community_print(np, length, version);
1809 break;
1810 case SNMP_VERSION_3:
1811 v3msg_print(np, length);
1812 break;
1813 default:
1814 printf("[version = %d]", elem.data.integer);
1815 break;
1816 }
1817 }