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