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