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