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