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