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