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