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