source: rtems-libbsd/freebsd/contrib/tcpdump/print-snmp.c @ 8440506

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 8440506 was 8440506, checked in by Chris Johns <chrisj@…>, on 06/15/15 at 07:42:23

Add tcpdump and libpcap.

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