Allow filter names and expressions of arbitrary length, and, in the
[metze/wireshark/wip.git] / packet-snmp.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * D.Jorand (c) 1998
4  *
5  * See RFC 1157 for SNMPv1.
6  *
7  * See RFCs 1901, 1905, and 1906 for SNMPv2c.
8  *
9  * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u.
10  *
11  * $Id: packet-snmp.c,v 1.59 2001/01/30 07:16:28 guy Exp $
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@zing.org>
15  * Copyright 1998 Didier Jorand
16  *
17  * Some stuff from:
18  * 
19  * GXSNMP -- An snmp mangament application
20  * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
21  * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  * 
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  * 
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  */
37
38 #ifdef HAVE_CONFIG_H
39 # include "config.h"
40 #endif
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 #ifdef HAVE_SYS_TYPES_H
47 # include <sys/types.h>
48 #endif
49
50 #ifdef HAVE_NETINET_IN_H
51 # include <netinet/in.h>
52 #endif
53
54 #define MAX_STRING_LEN 2048     /* TBC */
55
56 #ifdef linux
57 #include <dlfcn.h>
58 #endif
59
60 #include <glib.h>
61
62 #include "packet.h"
63 #include "strutil.h"
64 #include "conversation.h"
65 #include "etypes.h"
66 #include "packet-ipx.h"
67
68 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
69  /*
70   * UCD or CMU SNMP?
71   */
72 # if defined(HAVE_UCD_SNMP_SNMP_H)
73    /*
74     * UCD SNMP.
75     */
76 #  include <ucd-snmp/asn1.h>
77 #  include <ucd-snmp/snmp_api.h>
78 #  include <ucd-snmp/snmp_impl.h>
79 #  include <ucd-snmp/mib.h>
80
81    /*
82     * Sigh.  UCD SNMP 4.1.1 makes "snmp_set_suffix_only()" a macro
83     * that calls "ds_set_int()" with the first two arguments
84     * being DS_LIBRARY_ID and DS_LIB_PRINT_SUFFIX_ONLY; this means that,
85     * when building with 4.1.1, we need to arrange that
86     * <ucd-snmp/default_store.h> is included, to define those two values
87     * and to declare "ds_int()".
88     *
89     * However:
90     *
91     *   1) we can't include it on earlier versions (at least not 3.6.2),
92     *      as it doesn't exist in those versions;
93     *
94     *   2) we don't want to include <ucd-snmp/ucd-snmp-includes.h>,
95     *      as that includes <ucd-snmp/snmp.h>, and that defines a whole
96     *      bunch of values that we also define ourselves.
97     *
98     * So we only include it if "snmp_set_suffix_only" is defined as
99     * a macro.
100     */
101 #  ifdef snmp_set_suffix_only
102 #   include <ucd-snmp/default_store.h>
103 #  endif
104
105    /*
106     * XXX - for now, we assume all versions of UCD SNMP have it.
107     */
108 #  define HAVE_SPRINT_VALUE
109
110    /*
111     * Define values "sprint_value()" expects.
112     */
113 #  define VALTYPE_INTEGER       ASN_INTEGER
114 #  define VALTYPE_COUNTER       ASN_COUNTER
115 #  define VALTYPE_GAUGE         ASN_GAUGE
116 #  define VALTYPE_TIMETICKS     ASN_TIMETICKS
117 #  define VALTYPE_STRING        ASN_OCTET_STR
118 #  define VALTYPE_IPADDR        ASN_IPADDRESS
119 #  define VALTYPE_OPAQUE        ASN_OPAQUE
120 #  define VALTYPE_NSAP          ASN_NSAP
121 #  define VALTYPE_OBJECTID      ASN_OBJECT_ID
122 #  define VALTYPE_BITSTR        ASN_BIT_STR
123 #  define VALTYPE_COUNTER64     ASN_COUNTER64
124 # elif defined(HAVE_SNMP_SNMP_H)
125    /*
126     * CMU SNMP.
127     */
128 #  include <snmp/snmp.h>
129
130    /*
131     * Some older versions of CMU SNMP may lack these values (e.g., the
132     * "libsnmp3.6" package for Debian, which is based on some old
133     * CMU SNMP, perhaps 1.0); for now, we assume they also lack
134     * "sprint_value()".
135     */
136 #  ifdef SMI_INTEGER
137 #   define HAVE_SPRINT_VALUE
138     /*
139      * Define values "sprint_value()" expects.
140      */
141 #   define VALTYPE_INTEGER      SMI_INTEGER
142 #   define VALTYPE_COUNTER      SMI_COUNTER32
143 #   define VALTYPE_GAUGE        SMI_GAUGE32
144 #   define VALTYPE_TIMETICKS    SMI_TIMETICKS
145 #   define VALTYPE_STRING       SMI_STRING
146 #   define VALTYPE_IPADDR       SMI_IPADDRESS
147 #   define VALTYPE_OPAQUE       SMI_OPAQUE
148 #   define VALTYPE_NSAP         SMI_STRING
149 #   define VALTYPE_OBJECTID     SMI_OBJID
150 #   define VALTYPE_BITSTR       ASN_BIT_STR
151 #   define VALTYPE_COUNTER64    SMI_COUNTER64
152 #  endif
153   /*
154    * Now undo all the definitions they "helpfully" gave us, so we don't get
155    * complaints about redefining them.
156    *
157    * Why, oh why, is there no library that provides code to
158    *
159    *    1) read MIB files;
160    *
161    *    2) translate object IDs into names;
162    *
163    *    3) let you find out, for a given object ID, what the type, enum
164    *       values, display hint, etc. are;
165    *
166    * in a *simple* fashion, without assuming that your code is part of an
167    * SNMP agent or client that wants a pile of definitions of PDU types,
168    * etc.?  Is it just that 99 44/100% of the code that uses an SNMP library
169    * *is* part of an agent or client, and really *does* need that stuff,
170    * and *doesn't* need the interfaces we want?
171    */
172 #  undef SNMP_ERR_NOERROR
173 #  undef SNMP_ERR_TOOBIG
174 #  undef SNMP_ERR_NOSUCHNAME
175 #  undef SNMP_ERR_BADVALUE
176 #  undef SNMP_ERR_READONLY
177 #  undef SNMP_ERR_NOACCESS
178 #  undef SNMP_ERR_WRONGTYPE
179 #  undef SNMP_ERR_WRONGLENGTH
180 #  undef SNMP_ERR_WRONGENCODING
181 #  undef SNMP_ERR_WRONGVALUE
182 #  undef SNMP_ERR_NOCREATION
183 #  undef SNMP_ERR_INCONSISTENTVALUE
184 #  undef SNMP_ERR_RESOURCEUNAVAILABLE
185 #  undef SNMP_ERR_COMMITFAILED
186 #  undef SNMP_ERR_UNDOFAILED
187 #  undef SNMP_ERR_AUTHORIZATIONERROR
188 #  undef SNMP_ERR_NOTWRITABLE
189 #  undef SNMP_ERR_INCONSISTENTNAME
190 #  undef SNMP_TRAP_COLDSTART
191 #  undef SNMP_TRAP_WARMSTART
192 #  undef SNMP_TRAP_LINKDOWN
193 #  undef SNMP_TRAP_LINKUP
194 #  undef SNMP_TRAP_EGPNEIGHBORLOSS
195 #  undef SNMP_TRAP_ENTERPRISESPECIFIC
196 # endif
197 #endif
198
199 #include "asn1.h"
200
201 #include "packet-snmp.h"
202
203 /* Null string of type "guchar[]". */
204 static const guchar nullstring[] = "";
205
206 /* Take a pointer that may be null and return a pointer that's not null
207    by turning null pointers into pointers to the above null string. */
208 #define SAFE_STRING(s)  (((s) != NULL) ? (s) : nullstring)
209
210 static int proto_snmp = -1;
211 static int proto_smux = -1;
212
213 static gint ett_snmp = -1;
214 static gint ett_smux = -1;
215 static gint ett_parameters = -1;
216 static gint ett_parameters_qos = -1;
217 static gint ett_global = -1;
218 static gint ett_flags = -1;
219 static gint ett_secur = -1;
220
221 static int hf_snmpv3_flags = -1;
222 static int hf_snmpv3_flags_auth = -1;
223 static int hf_snmpv3_flags_crypt = -1;
224 static int hf_snmpv3_flags_report = -1;
225
226 #define TH_AUTH   0x01
227 #define TH_CRYPT  0x02
228 #define TH_REPORT 0x04
229
230 static const true_false_string flags_set_truth = {
231   "Set",
232   "Not set"
233 };
234
235 #define UDP_PORT_SNMP           161
236 #define UDP_PORT_SNMP_TRAP      162
237 #define TCP_PORT_SMUX           199
238
239 /* Protocol version numbers */
240 #define SNMP_VERSION_1  0
241 #define SNMP_VERSION_2c 1
242 #define SNMP_VERSION_2u 2
243 #define SNMP_VERSION_3  3
244
245 static const value_string versions[] = {
246         { SNMP_VERSION_1,       "1" },
247         { SNMP_VERSION_2c,      "2C" },
248         { SNMP_VERSION_2u,      "2U" },
249         { SNMP_VERSION_3,       "3" },
250         { 0,                    NULL },
251 };
252
253 /* PDU types */
254 #define SNMP_MSG_GET            0
255 #define SNMP_MSG_GETNEXT        1
256 #define SNMP_MSG_RESPONSE       2
257 #define SNMP_MSG_SET            3
258 #define SNMP_MSG_TRAP           4
259
260 #define SNMP_MSG_GETBULK        5
261 #define SNMP_MSG_INFORM         6
262 #define SNMP_MSG_TRAP2          7
263 #define SNMP_MSG_REPORT         8
264
265 static const value_string pdu_types[] = {
266         { SNMP_MSG_GET,         "GET" },
267         { SNMP_MSG_GETNEXT,     "GET-NEXT" },
268         { SNMP_MSG_SET,         "SET" },
269         { SNMP_MSG_RESPONSE,    "RESPONSE" },
270         { SNMP_MSG_TRAP,        "TRAP-V1" },
271         { SNMP_MSG_GETBULK,     "GETBULK" },
272         { SNMP_MSG_INFORM,      "INFORM" },
273         { SNMP_MSG_TRAP2,       "TRAP-V2" },
274         { SNMP_MSG_REPORT,      "REPORT" },
275         { 0,                    NULL }
276 };
277
278 /* SMUX PDU types */
279 #define SMUX_MSG_OPEN           0
280 #define SMUX_MSG_CLOSE          1
281 #define SMUX_MSG_RREQ           2
282 #define SMUX_MSG_RRSP           3
283 #define SMUX_MSG_SOUT           4
284
285 static const value_string smux_types[] = {
286         { SMUX_MSG_OPEN,        "Open" },
287         { SMUX_MSG_CLOSE,       "Close" },
288         { SMUX_MSG_RREQ,        "Registration Request" },
289         { SMUX_MSG_RRSP,        "Registration Response" },
290         { SMUX_MSG_SOUT,        "Commit Or Rollback" },
291         { 0,                    NULL }
292 };
293
294 /* SMUX Closing causes */
295 #define SMUX_CLOSE_DOWN                 0
296 #define SMUX_CLOSE_VERSION              1
297 #define SMUX_CLOSE_PACKET               2
298 #define SMUX_CLOSE_PROTOCOL             3
299 #define SMUX_CLOSE_INTERNAL             4
300 #define SMUX_CLOSE_NOAUTH               5
301
302 static const value_string smux_close[] = {
303         { SMUX_CLOSE_DOWN,      "Going down" },
304         { SMUX_CLOSE_VERSION,   "Unsupported Version" },
305         { SMUX_CLOSE_PACKET,    "Packet Format Error" },
306         { SMUX_CLOSE_PROTOCOL,  "Protocol Error" },
307         { SMUX_CLOSE_INTERNAL,  "Internal Error" },
308         { SMUX_CLOSE_NOAUTH,    "Unauthorized" },
309         { 0,                    NULL }
310 };
311
312 /* SMUX Request codes */
313 #define SMUX_RREQ_DELETE                0
314 #define SMUX_RREQ_READONLY              1
315 #define SMUX_RREQ_READWRITE             2
316
317 static const value_string smux_rreq[] = {
318         { SMUX_RREQ_DELETE,     "Delete" },
319         { SMUX_RREQ_READONLY,   "Read Only" },
320         { SMUX_RREQ_READWRITE,  "Read Write" },
321         { 0,                    NULL }
322 };
323
324 static const value_string smux_prio[] = {
325         { -1,                           "Failure" },
326         { 0,                            NULL }
327 };
328
329 /* SMUX SOut codes */
330 #define SMUX_SOUT_COMMIT                0
331 #define SMUX_SOUT_ROLLBACK              1
332
333 static const value_string smux_sout[] = {
334         { SMUX_SOUT_COMMIT,             "Commit" },
335         { SMUX_SOUT_ROLLBACK,           "Rollback" },
336         { 0,                            NULL }
337 };
338
339 /* Error status values */
340 #define SNMP_ERR_NOERROR                0
341 #define SNMP_ERR_TOOBIG                 1
342 #define SNMP_ERR_NOSUCHNAME             2
343 #define SNMP_ERR_BADVALUE               3
344 #define SNMP_ERR_READONLY               4
345 #define SNMP_ERR_GENERROR               5
346
347 #define SNMP_ERR_NOACCESS               6
348 #define SNMP_ERR_WRONGTYPE              7
349 #define SNMP_ERR_WRONGLENGTH            8
350 #define SNMP_ERR_WRONGENCODING          9
351 #define SNMP_ERR_WRONGVALUE             10
352 #define SNMP_ERR_NOCREATION             11
353 #define SNMP_ERR_INCONSISTENTVALUE      12
354 #define SNMP_ERR_RESOURCEUNAVAILABLE    13
355 #define SNMP_ERR_COMMITFAILED           14
356 #define SNMP_ERR_UNDOFAILED             15
357 #define SNMP_ERR_AUTHORIZATIONERROR     16
358 #define SNMP_ERR_NOTWRITABLE            17
359 #define SNMP_ERR_INCONSISTENTNAME       18
360
361 static const value_string error_statuses[] = {
362         { SNMP_ERR_NOERROR,             "NO ERROR" },
363         { SNMP_ERR_TOOBIG,              "TOOBIG" },
364         { SNMP_ERR_NOSUCHNAME,          "NO SUCH NAME" },
365         { SNMP_ERR_BADVALUE,            "BAD VALUE" },
366         { SNMP_ERR_READONLY,            "READ ONLY" },
367         { SNMP_ERR_GENERROR,            "GENERIC ERROR" },
368         { SNMP_ERR_NOACCESS,            "NO ACCESS" },
369         { SNMP_ERR_WRONGTYPE,           "WRONG TYPE" },
370         { SNMP_ERR_WRONGLENGTH,         "WRONG LENGTH" },
371         { SNMP_ERR_WRONGENCODING,       "WRONG ENCODING" },
372         { SNMP_ERR_WRONGVALUE,          "WRONG VALUE" },
373         { SNMP_ERR_NOCREATION,          "NO CREATION" },
374         { SNMP_ERR_INCONSISTENTVALUE,   "INCONSISTENT VALUE" },
375         { SNMP_ERR_RESOURCEUNAVAILABLE, "RESOURCE UNAVAILABLE" },
376         { SNMP_ERR_COMMITFAILED,        "COMMIT FAILED" },
377         { SNMP_ERR_UNDOFAILED,          "UNDO FAILED" },
378         { SNMP_ERR_AUTHORIZATIONERROR,  "AUTHORIZATION ERROR" },
379         { SNMP_ERR_NOTWRITABLE,         "NOT WRITABLE" },
380         { SNMP_ERR_INCONSISTENTNAME,    "INCONSISTENT NAME" },
381         { 0,                            NULL }
382 };
383
384 /* General SNMP V1 Traps */
385
386 #define SNMP_TRAP_COLDSTART             0
387 #define SNMP_TRAP_WARMSTART             1
388 #define SNMP_TRAP_LINKDOWN              2
389 #define SNMP_TRAP_LINKUP                3
390 #define SNMP_TRAP_AUTHFAIL              4
391 #define SNMP_TRAP_EGPNEIGHBORLOSS       5
392 #define SNMP_TRAP_ENTERPRISESPECIFIC    6
393
394 static const value_string trap_types[] = {
395         { SNMP_TRAP_COLDSTART,          "COLD START" },
396         { SNMP_TRAP_WARMSTART,          "WARM START" },
397         { SNMP_TRAP_LINKDOWN,           "LINK DOWN" },
398         { SNMP_TRAP_LINKUP,             "LINK UP" },
399         { SNMP_TRAP_AUTHFAIL,           "AUTHENTICATION FAILED" },
400         { SNMP_TRAP_EGPNEIGHBORLOSS,    "EGP NEIGHBORLOSS" },
401         { SNMP_TRAP_ENTERPRISESPECIFIC, "ENTERPRISE SPECIFIC" },
402         { 0,                            NULL }
403 };
404
405 /* Security Models */
406
407 #define SNMP_SEC_ANY                    0
408 #define SNMP_SEC_V1                     1
409 #define SNMP_SEC_V2C                    2
410 #define SNMP_SEC_USM                    3
411
412 static const value_string sec_models[] = {
413         { SNMP_SEC_ANY,                 "Any" },
414         { SNMP_SEC_V1,                  "V1" },
415         { SNMP_SEC_V2C,                 "V2C" },
416         { SNMP_SEC_USM,                 "USM" },
417         { 0,                            NULL }
418 };
419
420 /* SNMP Tags */
421
422 #define SNMP_IPA    0           /* IP Address */
423 #define SNMP_CNT    1           /* Counter (Counter32) */
424 #define SNMP_GGE    2           /* Gauge (Gauge32) */
425 #define SNMP_TIT    3           /* TimeTicks */
426 #define SNMP_OPQ    4           /* Opaque */
427 #define SNMP_NSP    5           /* NsapAddress */
428 #define SNMP_C64    6           /* Counter64 */
429 #define SNMP_U32    7           /* Uinteger32 */
430
431 #define SERR_NSO    0
432 #define SERR_NSI    1
433 #define SERR_EOM    2
434
435 /* SNMPv1 Types */
436
437 #define SNMP_NULL                0
438 #define SNMP_INTEGER             1    /* l  */
439 #define SNMP_OCTETSTR            2    /* c  */
440 #define SNMP_DISPLAYSTR          2    /* c  */
441 #define SNMP_OBJECTID            3    /* ul */
442 #define SNMP_IPADDR              4    /* uc */
443 #define SNMP_COUNTER             5    /* ul */
444 #define SNMP_GAUGE               6    /* ul */
445 #define SNMP_TIMETICKS           7    /* ul */
446 #define SNMP_OPAQUE              8    /* c  */
447
448 /* additional SNMPv2 Types */
449
450 #define SNMP_UINTEGER            5    /* ul */
451 #define SNMP_BITSTR              9    /* uc */
452 #define SNMP_NSAP               10    /* uc */
453 #define SNMP_COUNTER64          11    /* ul */
454 #define SNMP_NOSUCHOBJECT       12
455 #define SNMP_NOSUCHINSTANCE     13
456 #define SNMP_ENDOFMIBVIEW       14
457
458 typedef struct _SNMP_CNV SNMP_CNV;
459
460 struct _SNMP_CNV
461 {
462   guint class;
463   guint tag;
464   gint  syntax;
465   gchar *name;
466 };
467
468 static SNMP_CNV SnmpCnv [] =
469 {
470   {ASN1_UNI, ASN1_NUL, SNMP_NULL,      "NULL"},
471   {ASN1_UNI, ASN1_INT, SNMP_INTEGER,   "INTEGER"},
472   {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR,  "OCTET STRING"},
473   {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID,  "OBJECTID"},
474   {ASN1_APL, SNMP_IPA, SNMP_IPADDR,    "IPADDR"},
475   {ASN1_APL, SNMP_CNT, SNMP_COUNTER,   "COUNTER"},  /* Counter32 */
476   {ASN1_APL, SNMP_GGE, SNMP_GAUGE,     "GAUGE"},    /* Gauge32 == Unsigned32  */
477   {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS, "TIMETICKS"},
478   {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE,    "OPAQUE"},
479
480 /* SNMPv2 data types and errors */
481
482   {ASN1_UNI, ASN1_BTS, SNMP_BITSTR,         "BITSTR"},
483   {ASN1_APL, SNMP_C64, SNMP_COUNTER64,      "COUNTER64"},
484   {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT,   "NOSUCHOBJECT"},
485   {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE, "NOSUCHINSTANCE"},
486   {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW,   "ENDOFMIBVIEW"},
487   {0,       0,         -1,                  NULL}
488 };
489
490 /*
491  * NAME:        g_snmp_tag_cls2syntax
492  * SYNOPSIS:    gboolean g_snmp_tag_cls2syntax
493  *                  (
494  *                      guint    tag,
495  *                      guint    cls,
496  *                      gushort *syntax
497  *                  )
498  * DESCRIPTION: Converts ASN1 tag and class to Syntax tag and name.
499  *              See SnmpCnv for conversion.
500  * RETURNS:     name on success, NULL on failure
501  */
502
503 static gchar *
504 snmp_tag_cls2syntax ( guint tag, guint cls, gushort *syntax)
505 {
506     SNMP_CNV *cnv;
507
508     cnv = SnmpCnv;
509     while (cnv->syntax != -1)
510     {
511         if (cnv->tag == tag && cnv->class == cls)
512         {
513             *syntax = cnv->syntax;
514             return cnv->name;
515         }
516         cnv++;
517     }
518     return NULL;
519 }
520
521 static void
522 dissect_snmp_parse_error(const u_char *pd, int offset, frame_data *fd,
523                    proto_tree *tree, const char *field_name, int ret)
524 {
525         const gchar *errstr;
526
527         if (check_col(fd, COL_INFO)) {
528                 switch (ret) {
529
530                 case ASN1_ERR_EMPTY:
531                         errstr = "Ran out of data";
532                         break;
533
534                 case ASN1_ERR_EOC_MISMATCH:
535                         errstr = "EOC mismatch";
536                         break;
537
538                 case ASN1_ERR_WRONG_TYPE:
539                         errstr = "Wrong type for that item";
540                         break;
541
542                 case ASN1_ERR_LENGTH_NOT_DEFINITE:
543                         errstr = "Length was indefinite";
544                         break;
545
546                 case ASN1_ERR_LENGTH_MISMATCH:
547                         errstr = "Length mismatch";
548                         break;
549
550                 case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
551                         errstr = "Wrong length for that item's type";
552                         break;
553
554                 default:
555                         errstr = "Unknown error";
556                         break;
557                 }
558                 col_add_fstr(fd, COL_INFO,
559                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
560         }
561
562         old_dissect_data(pd, offset, fd, tree);
563 }
564
565 static void
566 dissect_snmp_error(const u_char *pd, int offset, frame_data *fd,
567                    proto_tree *tree, const char *message)
568 {
569         if (check_col(fd, COL_INFO))
570                 col_add_str(fd, COL_INFO, message);
571
572         old_dissect_data(pd, offset, fd, tree);
573 }
574
575 static gchar *
576 format_oid(subid_t *oid, guint oid_length)
577 {
578         char *result;
579         int result_len;
580         int len, i;
581         char *buf;
582
583         result_len = oid_length * 22;
584         result = g_malloc(result_len + 1);
585         buf = result;
586         len = sprintf(buf, "%lu", (unsigned long)oid[0]);
587         buf += len;
588         for (i = 1; i < oid_length;i++) {
589                 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
590                 buf += len;
591         }
592         return result;
593 }
594
595 #ifdef HAVE_SPRINT_VALUE
596 static gchar *
597 format_var(struct variable_list *variable, subid_t *variable_oid,
598     guint variable_oid_length, gushort vb_type, guint vb_length)
599 {
600         gchar *buf;
601
602         switch (vb_type) {
603
604         case SNMP_INTEGER:
605         case SNMP_COUNTER:
606         case SNMP_GAUGE:
607         case SNMP_TIMETICKS:
608                 /* We don't know how long this will be, but let's guess it
609                    fits within 128 characters; that should be enough for an
610                    integral value plus some sort of type indication. */
611                 buf = g_malloc(128);
612                 break;
613
614         case SNMP_OCTETSTR:
615         case SNMP_IPADDR:
616         case SNMP_OPAQUE:
617         case SNMP_NSAP:
618         case SNMP_BITSTR:
619         case SNMP_COUNTER64:
620                 /* We don't know how long this will be, but let's guess it
621                    fits within 128 characters plus 4 characters per octet. */
622                 buf = g_malloc(128 + 4*vb_length);
623                 break;
624
625         case SNMP_OBJECTID:
626                 /* We don't know how long this will be, but let's guess it
627                    fits within 128 characters plus 32 characters per subid
628                    (10 digits plus period, or a subid name). */
629                 buf = g_malloc(1024 + 32*vb_length);
630                 break;
631
632         default:
633                 /* Should not happen. */
634                 g_assert_not_reached();
635                 buf = NULL;
636                 break;
637         }
638
639         variable->next_variable = NULL;
640         variable->name = variable_oid;
641         variable->name_length = variable_oid_length;
642         switch (vb_type) {
643
644         case SNMP_INTEGER:
645                 variable->type = VALTYPE_INTEGER;
646                 break;
647
648         case SNMP_COUNTER:
649                 variable->type = VALTYPE_COUNTER;
650                 break;
651
652         case SNMP_GAUGE:
653                 variable->type = VALTYPE_GAUGE;
654                 break;
655
656         case SNMP_TIMETICKS:
657                 variable->type = VALTYPE_TIMETICKS;
658                 break;
659
660         case SNMP_OCTETSTR:
661                 variable->type = VALTYPE_STRING;
662                 break;
663
664         case SNMP_IPADDR:
665                 variable->type = VALTYPE_IPADDR;
666                 break;
667
668         case SNMP_OPAQUE:
669                 variable->type = VALTYPE_OPAQUE;
670                 break;
671
672         case SNMP_NSAP:
673                 variable->type = VALTYPE_NSAP;
674                 break;
675
676         case SNMP_OBJECTID:
677                 variable->type = VALTYPE_OBJECTID;
678                 vb_length *= sizeof (subid_t);  /* XXX - necessary? */
679                 break;
680
681         case SNMP_BITSTR:
682                 variable->type = VALTYPE_BITSTR;
683                 break;
684
685         case SNMP_COUNTER64:
686                 variable->type = VALTYPE_COUNTER64;
687                 break;
688         }
689         variable->val_len = vb_length;
690
691         sprint_value(buf, variable_oid, variable_oid_length, variable);
692         return buf;
693 }
694 #endif
695
696 static int
697 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
698     guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
699     gboolean unsafe)
700 {
701         const guchar *start;
702         guint length;
703         gboolean def;
704         guint vb_length;
705         gushort vb_type;
706         gchar *vb_type_name;
707         int ret;
708         guint cls, con, tag;
709
710         gint32 vb_integer_value;
711         guint32 vb_uinteger_value;
712
713         guint8 *vb_octet_string;
714
715         subid_t *vb_oid;
716         guint vb_oid_length;
717
718         gchar *vb_display_string;
719
720 #ifdef HAVE_SPRINT_VALUE
721         struct variable_list variable;
722 #if defined(HAVE_UCD_SNMP_SNMP_H)
723         long value;
724 #endif
725 #endif  /* HAVE_SPRINT_VALUE */
726         int i;
727         gchar *buf;
728         int len;
729
730         /* parse the type of the object */
731         start = asn1->pointer;
732         ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
733         if (ret != ASN1_ERR_NOERROR)
734                 return ret;
735         if (!def)
736                 return ASN1_ERR_LENGTH_NOT_DEFINITE;
737
738         /* Convert the class, constructed flag, and tag to a type. */
739         vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
740         if (vb_type_name == NULL) {
741                 /*
742                  * Unsupported type.
743                  * Dissect the value as an opaque string of octets.
744                  */
745                 vb_type_name = "unsupported type";
746                 vb_type = SNMP_OPAQUE;
747         }
748
749         /* parse the value */
750         switch (vb_type) {
751
752         case SNMP_INTEGER:
753                 ret = asn1_int32_value_decode(asn1, vb_length,
754                     &vb_integer_value);
755                 if (ret != ASN1_ERR_NOERROR)
756                         return ret;
757                 length = asn1->pointer - start;
758                 if (snmp_tree) {
759 #ifdef HAVE_SPRINT_VALUE
760                         if (!unsafe) {
761 #if defined(HAVE_UCD_SNMP_SNMP_H)
762                                 value = vb_integer_value;
763                                 variable.val.integer = &value;
764 #elif defined(HAVE_SNMP_SNMP_H)
765                                 variable.val.integer = &vb_integer_value;
766 #endif
767                                 vb_display_string = format_var(&variable,
768                                     variable_oid, variable_oid_length, vb_type,
769                                     vb_length);
770                                 proto_tree_add_text(snmp_tree, NullTVB, offset,
771                                     length,
772                                     "Value: %s", vb_display_string);
773                                 g_free(vb_display_string);
774                                 break;  /* we added formatted version to the tree */
775                         }
776 #endif /* HAVE_SPRINT_VALUE */
777                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
778                             "Value: %s: %d (%#x)", vb_type_name,
779                             vb_integer_value, vb_integer_value);
780                 }
781                 break;
782
783         case SNMP_COUNTER:
784         case SNMP_GAUGE:
785         case SNMP_TIMETICKS:
786                 ret = asn1_uint32_value_decode(asn1, vb_length,
787                     &vb_uinteger_value);
788                 if (ret != ASN1_ERR_NOERROR)
789                         return ret;
790                 length = asn1->pointer - start;
791                 if (snmp_tree) {
792 #ifdef HAVE_SPRINT_VALUE
793                         if (!unsafe) {
794 #if defined(HAVE_UCD_SNMP_SNMP_H)
795                                 value = vb_uinteger_value;
796                                 variable.val.integer = &value;
797 #elif defined(HAVE_SNMP_SNMP_H)
798                                 variable.val.integer = &vb_uinteger_value;
799 #endif
800                                 vb_display_string = format_var(&variable,
801                                     variable_oid, variable_oid_length, vb_type,
802                                     vb_length);
803                                 proto_tree_add_text(snmp_tree, NullTVB, offset,
804                                     length,
805                                     "Value: %s", vb_display_string);
806                                 g_free(vb_display_string);
807                                 break;  /* we added formatted version to the tree */
808                         }
809 #endif /* HAVE_SPRINT_VALUE */
810                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
811                             "Value: %s: %u (%#x)", vb_type_name,
812                             vb_uinteger_value, vb_uinteger_value);
813                 }
814                 break;
815
816         case SNMP_OCTETSTR:
817         case SNMP_IPADDR:
818         case SNMP_OPAQUE:
819         case SNMP_NSAP:
820         case SNMP_BITSTR:
821         case SNMP_COUNTER64:
822                 ret = asn1_string_value_decode (asn1, vb_length,
823                     &vb_octet_string);
824                 if (ret != ASN1_ERR_NOERROR)
825                         return ret;
826                 length = asn1->pointer - start;
827                 if (snmp_tree) {
828 #ifdef HAVE_SPRINT_VALUE
829                         if (!unsafe) {
830                                 variable.val.string = vb_octet_string;
831                                 vb_display_string = format_var(&variable,
832                                     variable_oid, variable_oid_length, vb_type,
833                                     vb_length);
834                                 proto_tree_add_text(snmp_tree, NullTVB, offset,
835                                     length,
836                                     "Value: %s", vb_display_string);
837                                 g_free(vb_display_string);
838                                 break;  /* we added formatted version to the tree */
839                         }
840 #endif /* HAVE_SPRINT_VALUE */
841                         /*
842                          * If some characters are not printable, display
843                          * the string as bytes.
844                          */
845                         for (i = 0; i < vb_length; i++) {
846                                 if (!(isprint(vb_octet_string[i])
847                                     || isspace(vb_octet_string[i])))
848                                         break;
849                         }
850                         if (i < vb_length) {
851                                 /*
852                                  * We stopped, due to a non-printable
853                                  * character, before we got to the end
854                                  * of the string.
855                                  */
856                                 vb_display_string = g_malloc(4*vb_length);
857                                 buf = &vb_display_string[0];
858                                 len = sprintf(buf, "%03u", vb_octet_string[0]);
859                                 buf += len;
860                                 for (i = 1; i < vb_length; i++) {
861                                         len = sprintf(buf, ".%03u",
862                                             vb_octet_string[i]);
863                                         buf += len;
864                                 }
865                                 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
866                                     "Value: %s: %s", vb_type_name,
867                                     vb_display_string);
868                                 g_free(vb_display_string);
869                         } else {
870                                 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
871                                     "Value: %s: %.*s", vb_type_name,
872                                     (int)vb_length, vb_octet_string);
873                         }
874                 }
875                 g_free(vb_octet_string);
876                 break;
877
878         case SNMP_NULL:
879                 ret = asn1_null_decode (asn1, vb_length);
880                 if (ret != ASN1_ERR_NOERROR)
881                         return ret;
882                 length = asn1->pointer - start;
883                 if (snmp_tree) {
884                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
885                             "Value: %s", vb_type_name);
886                 }
887                 break;
888
889         case SNMP_OBJECTID:
890                 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
891                     &vb_oid_length);
892                 if (ret != ASN1_ERR_NOERROR)
893                         return ret;
894                 length = asn1->pointer - start;
895                 if (snmp_tree) {
896 #ifdef HAVE_SPRINT_VALUE
897                         if (!unsafe) {
898                                 variable.val.objid = vb_oid;
899                                 vb_display_string = format_var(&variable,
900                                     variable_oid, variable_oid_length, vb_type,
901                                     vb_length);
902                                 proto_tree_add_text(snmp_tree, NullTVB, offset,
903                                     length,
904                                     "Value: %s", vb_display_string);
905                                 break;  /* we added formatted version to the tree */
906                         }
907 #endif /* HAVE_SPRINT_VALUE */
908                         vb_display_string = format_oid(vb_oid, vb_oid_length);
909                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
910                             "Value: %s: %s", vb_type_name, vb_display_string);
911                         g_free(vb_display_string);
912                 }
913                 g_free(vb_oid);
914                 break;
915
916         case SNMP_NOSUCHOBJECT:
917                 length = asn1->pointer - start;
918                 if (snmp_tree) {
919                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
920                             "Value: %s: no such object", vb_type_name);
921                 }
922                 break;
923
924         case SNMP_NOSUCHINSTANCE:
925                 length = asn1->pointer - start;
926                 if (snmp_tree) {
927                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
928                             "Value: %s: no such instance", vb_type_name);
929                 }
930                 break;
931
932         case SNMP_ENDOFMIBVIEW:
933                 length = asn1->pointer - start;
934                 if (snmp_tree) {
935                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
936                             "Value: %s: end of mib view", vb_type_name);
937                 }
938                 break;
939
940         default:
941                 g_assert_not_reached();
942                 return ASN1_ERR_WRONG_TYPE;
943         }
944         *lengthp = length;
945         return ASN1_ERR_NOERROR;
946 }
947
948 static void
949 dissect_common_pdu(const u_char *pd, int offset, frame_data *fd,
950     proto_tree *tree, ASN1_SCK asn1, guint pdu_type, const guchar *start)
951 {
952         gboolean def;
953         guint length;
954         guint sequence_length;
955
956         guint32 request_id;
957
958         guint32 error_status;
959
960         guint32 error_index;
961
962         char *pdu_type_string;
963
964         subid_t *enterprise;
965         guint enterprise_length;
966
967         guint8 *agent_address;
968         guint agent_address_length;
969
970         guint32 trap_type;
971
972         guint32 specific_type;
973
974         guint timestamp;
975         guint timestamp_length;
976
977         gchar *oid_string;
978
979         guint variable_bindings_length;
980
981         int vb_index;
982         guint variable_length;
983         subid_t *variable_oid;
984         guint variable_oid_length;
985 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
986         gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
987 #endif
988         gboolean unsafe;
989
990         int ret;
991         guint cls, con, tag;
992
993         pdu_type_string = val_to_str(pdu_type, pdu_types,
994             "Unknown PDU type %#x");
995         if (check_col(fd, COL_INFO))
996                 col_add_str(fd, COL_INFO, pdu_type_string);
997         length = asn1.pointer - start;
998         if (tree) {
999                 proto_tree_add_text(tree, NullTVB, offset, length,
1000                     "PDU type: %s", pdu_type_string);
1001         }
1002         offset += length;
1003
1004         /* get the fields in the PDU preceeding the variable-bindings sequence */
1005         switch (pdu_type) {
1006
1007         case SNMP_MSG_GET:
1008         case SNMP_MSG_GETNEXT:
1009         case SNMP_MSG_RESPONSE:
1010         case SNMP_MSG_SET:
1011         case SNMP_MSG_GETBULK:
1012         case SNMP_MSG_INFORM:
1013         case SNMP_MSG_TRAP2:
1014         case SNMP_MSG_REPORT:
1015                 /* request id */
1016                 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1017                 if (ret != ASN1_ERR_NOERROR) {
1018                         dissect_snmp_parse_error(pd, offset, fd, tree,
1019                             "request ID", ret);
1020                         return;
1021                 }
1022                 if (tree) {
1023                         proto_tree_add_text(tree, NullTVB, offset, length,
1024                             "Request Id: %#x", request_id);
1025                 }
1026                 offset += length;
1027                 
1028                 /* error status, or getbulk non-repeaters */
1029                 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1030                 if (ret != ASN1_ERR_NOERROR) {
1031                         dissect_snmp_parse_error(pd, offset, fd, tree,
1032                             (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1033                                                            : "error status",
1034                             ret);
1035                         return;
1036                 }
1037                 if (tree) {
1038                         if (pdu_type == SNMP_MSG_GETBULK) {
1039                                 proto_tree_add_text(tree, NullTVB, offset,
1040                                     length, "Non-repeaters: %u", error_status);
1041                         } else {
1042                                 proto_tree_add_text(tree, NullTVB, offset,
1043                                     length, "Error Status: %s",
1044                                     val_to_str(error_status, error_statuses,
1045                                       "Unknown (%d)"));
1046                         }
1047                 }
1048                 offset += length;
1049
1050                 /* error index, or getbulk max-repetitions */
1051                 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1052                 if (ret != ASN1_ERR_NOERROR) {
1053                         dissect_snmp_parse_error(pd, offset, fd, tree,
1054                             (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1055                                                            : "error index",
1056                             ret);
1057                         return;
1058                 }
1059                 if (tree) {
1060                         if (pdu_type == SNMP_MSG_GETBULK) {
1061                                 proto_tree_add_text(tree, NullTVB, offset,
1062                                     length, "Max repetitions: %u", error_index);
1063                         } else {
1064                                 proto_tree_add_text(tree, NullTVB, offset,
1065                                     length, "Error Index: %u", error_index);
1066                         }
1067                 }
1068                 offset += length;
1069                 break;
1070
1071         case SNMP_MSG_TRAP:
1072                 /* enterprise */
1073                 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1074                     &length);
1075                 if (ret != ASN1_ERR_NOERROR) {
1076                         dissect_snmp_parse_error(pd, offset, fd, tree,
1077                             "enterprise OID", ret);
1078                         return;
1079                 }
1080                 if (tree) {
1081                         oid_string = format_oid(enterprise, enterprise_length);
1082                         proto_tree_add_text(tree, NullTVB, offset, length,
1083                             "Enterprise: %s", oid_string);
1084                         g_free(oid_string);
1085                 }
1086                 g_free(enterprise);
1087                 offset += length;
1088
1089                 /* agent address */
1090                 start = asn1.pointer;
1091                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1092                     &def, &agent_address_length);
1093                 if (ret != ASN1_ERR_NOERROR) {
1094                         dissect_snmp_parse_error(pd, offset, fd, tree,
1095                             "agent address", ret);
1096                         return;
1097                 }
1098                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1099                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1100                         /* GXSNMP 0.0.15 says the latter is "needed for
1101                            Banyan" */
1102                         dissect_snmp_parse_error(pd, offset, fd, tree,
1103                             "agent_address", ASN1_ERR_WRONG_TYPE);
1104                         return;
1105                 }
1106                 if (agent_address_length != 4) {
1107                         dissect_snmp_parse_error(pd, offset, fd, tree,
1108                             "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1109                         return;
1110                 }
1111                 ret = asn1_string_value_decode (&asn1,
1112                     agent_address_length, &agent_address);
1113                 if (ret != ASN1_ERR_NOERROR) {
1114                         dissect_snmp_parse_error(pd, offset, fd, tree,
1115                             "agent address", ret);
1116                         return;
1117                 }
1118                 length = asn1.pointer - start;
1119                 if (tree) {
1120                         proto_tree_add_text(tree, NullTVB, offset, length,
1121                             "Agent address: %s", ip_to_str(agent_address));
1122                 }
1123                 g_free(agent_address);
1124                 offset += length;
1125                 
1126                 /* generic trap type */
1127                 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1128                 if (ret != ASN1_ERR_NOERROR) {
1129                         dissect_snmp_parse_error(pd, offset, fd, tree,
1130                             "generic trap type", ret);
1131                         return;
1132                 }
1133                 if (tree) {
1134                         proto_tree_add_text(tree, NullTVB, offset, length,
1135                             "Trap type: %s",
1136                             val_to_str(trap_type, trap_types, "Unknown (%u)"));
1137                 }               
1138                 offset += length;
1139                 
1140                 /* specific trap type */
1141                 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1142                 if (ret != ASN1_ERR_NOERROR) {
1143                         dissect_snmp_parse_error(pd, offset, fd, tree,
1144                             "specific trap type", ret);
1145                         return;
1146                 }
1147                 if (tree) {
1148                         proto_tree_add_text(tree, NullTVB, offset, length,
1149                             "Specific trap type: %u (%#x)",
1150                             specific_type, specific_type);
1151                 }               
1152                 offset += length;
1153                 
1154                 /* timestamp */
1155                 start = asn1.pointer;
1156                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1157                     &def, &timestamp_length);
1158                 if (ret != ASN1_ERR_NOERROR) {
1159                         dissect_snmp_parse_error(pd, offset, fd, tree,
1160                             "timestamp", ret);
1161                         return;
1162                 }
1163                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1164                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1165                         dissect_snmp_parse_error(pd, offset, fd, tree,
1166                             "timestamp", ASN1_ERR_WRONG_TYPE);
1167                         return;
1168                 }
1169                 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1170                     &timestamp);
1171                 if (ret != ASN1_ERR_NOERROR) {
1172                         dissect_snmp_parse_error(pd, offset, fd, tree,
1173                             "timestamp", ret);
1174                         return;
1175                 }
1176                 length = asn1.pointer - start;
1177                 if (tree) {
1178                         proto_tree_add_text(tree, NullTVB, offset, length,
1179                             "Timestamp: %u", timestamp);
1180                 }               
1181                 offset += length;
1182                 break;
1183         }
1184
1185         /* variable bindings */
1186         /* get header for variable-bindings sequence */
1187         ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1188         if (ret != ASN1_ERR_NOERROR) {
1189                 dissect_snmp_parse_error(pd, offset, fd, tree,
1190                         "variable bindings header", ret);
1191                 return;
1192         }
1193         offset += length;
1194
1195         /* loop on variable bindings */
1196         vb_index = 0;
1197         while (variable_bindings_length > 0) {
1198                 vb_index++;
1199                 sequence_length = 0;
1200
1201                 /* parse type */
1202                 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1203                 if (ret != ASN1_ERR_NOERROR) {
1204                         dissect_snmp_parse_error(pd, offset, fd, tree,
1205                                 "variable binding header", ret);
1206                         return;
1207                 }
1208                 sequence_length += length;
1209
1210                 /* parse object identifier */
1211                 ret = asn1_oid_decode (&asn1, &variable_oid,
1212                     &variable_oid_length, &length);
1213                 if (ret != ASN1_ERR_NOERROR) {
1214                         dissect_snmp_parse_error(pd, offset, fd, tree,
1215                             "variable binding OID", ret);
1216                         return;
1217                 }
1218                 sequence_length += length;
1219
1220                 unsafe = FALSE;
1221                 if (tree) {
1222                         oid_string = format_oid(variable_oid,
1223                             variable_oid_length);
1224                         
1225 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1226                         sprint_objid(vb_oid_string, variable_oid,
1227                             variable_oid_length);
1228                         proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1229                             "Object identifier %d: %s (%s)", vb_index,
1230                             oid_string, vb_oid_string);
1231 #ifdef HAVE_SNMP_SNMP_H
1232                         /*
1233                          * CMU SNMP has a bug wherein "sprint_value()"
1234                          * calls "get_symbol()", passing it the
1235                          * OID supplied, to get an information about the
1236                          * variable, and blithely assumes that it will
1237                          * never get a null pointer back and dereferences
1238                          * the resulting pointer.
1239                          *
1240                          * Not true.  If there's nothing in the MIB
1241                          * about *any* of the components of the OID,
1242                          * it'll return a null pointer.
1243                          *
1244                          * So we have to check for that, and pass
1245                          * down to "snmp_variable_decode" a flag
1246                          * saying "don't pass this to 'sprint_value()'.
1247                          *
1248                          * We check for that by looking for a decoded
1249                          * OID string beginning with "." followed by a
1250                          * digit, meaning it couldn't even find any
1251                          * symbolic representation for the very
1252                          * beginning of the OID string.
1253                          */
1254                         if (vb_oid_string[0] == '.' &&
1255                             isdigit((guchar)vb_oid_string[1]))
1256                                 unsafe = TRUE;
1257 #endif /* HAVE_SNMP_SNMP_H */
1258 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1259                         proto_tree_add_text(tree, NullTVB, offset, sequence_length,
1260                             "Object identifier %d: %s", vb_index,
1261                             oid_string);
1262 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1263                         g_free(oid_string);
1264                 }
1265                 offset += sequence_length;
1266                 variable_bindings_length -= sequence_length;
1267                                 
1268                 /* Parse the variable's value */
1269                 ret = snmp_variable_decode(tree, variable_oid,
1270                     variable_oid_length, &asn1, offset, &length,
1271                     unsafe);
1272                 if (ret != ASN1_ERR_NOERROR) {
1273                         dissect_snmp_parse_error(pd, offset, fd, tree,
1274                             "variable", ret);
1275                         return;
1276                 }
1277                 offset += length;
1278                 variable_bindings_length -= length;
1279         }
1280 }
1281
1282 static const value_string qos_vals[] = {
1283         { 0x0,  "No authentication or privacy" },
1284         { 0x1,  "Authentication, no privacy" },
1285         { 0x2,  "Authentication and privacy" },
1286         { 0x3,  "Authentication and privacy" },
1287         { 0,    NULL },
1288 };
1289
1290 static void
1291 dissect_snmp2u_parameters(proto_tree *tree, int offset, int length,
1292     guchar *parameters, int parameters_length)
1293 {
1294         proto_item *item;
1295         proto_tree *parameters_tree;
1296         proto_tree *qos_tree;
1297         guint8 model;
1298         guint8 qos;
1299         guint8 len;
1300
1301         item = proto_tree_add_text(tree, NullTVB, offset, length,
1302             "Parameters");
1303         parameters_tree = proto_item_add_subtree(item, ett_parameters);
1304         offset += length - parameters_length;
1305
1306         if (parameters_length < 1)
1307                 return;
1308         model = *parameters;
1309         proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1310             "model: %u", model);
1311         offset += 1;
1312         parameters += 1;
1313         parameters_length -= 1;
1314         if (model != 1) {
1315                 /* Unknown model. */
1316                 proto_tree_add_text(parameters_tree, NullTVB, offset,
1317                     parameters_length, "parameters: %s",
1318                     bytes_to_str(parameters, parameters_length));
1319                 return;
1320         }
1321
1322         if (parameters_length < 1)
1323                 return;
1324         qos = *parameters;
1325         item = proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1326             "qoS: 0x%x", qos);
1327         qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1328         proto_tree_add_text(qos_tree, NullTVB, offset, 1, "%s",
1329             decode_boolean_bitfield(qos, 0x04,
1330                 8, "Generation of report PDU allowed",
1331                    "Generation of report PDU not allowed"));
1332         proto_tree_add_text(qos_tree, NullTVB, offset, 1, "%s",
1333             decode_enumerated_bitfield(qos, 0x03,
1334                 8, qos_vals, "%s"));
1335         offset += 1;
1336         parameters += 1;
1337         parameters_length -= 1;
1338
1339         if (parameters_length < 12)
1340                 return;
1341         proto_tree_add_text(parameters_tree, NullTVB, offset, 12,
1342             "agentID: %s", bytes_to_str(parameters, 12));
1343         offset += 12;
1344         parameters += 12;
1345         parameters_length -= 12;
1346
1347         if (parameters_length < 4)
1348                 return;
1349         proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
1350             "agentBoots: %u", pntohl(parameters));
1351         offset += 4;
1352         parameters += 4;
1353         parameters_length -= 4;
1354
1355         if (parameters_length < 4)
1356                 return;
1357         proto_tree_add_text(parameters_tree, NullTVB, offset, 4,
1358             "agentTime: %u", pntohl(parameters));
1359         offset += 4;
1360         parameters += 4;
1361         parameters_length -= 4;
1362
1363         if (parameters_length < 2)
1364                 return;
1365         proto_tree_add_text(parameters_tree, NullTVB, offset, 2,
1366             "maxSize: %u", pntohs(parameters));
1367         offset += 2;
1368         parameters += 2;
1369         parameters_length -= 2;
1370
1371         if (parameters_length < 1)
1372                 return;
1373         len = *parameters;
1374         proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1375             "userLen: %u", len);
1376         offset += 1;
1377         parameters += 1;
1378         parameters_length -= 1;
1379
1380         if (parameters_length < len)
1381                 return;
1382         proto_tree_add_text(parameters_tree, NullTVB, offset, len,
1383             "userName: %.*s", len, parameters);
1384         offset += len;
1385         parameters += len;
1386         parameters_length -= len;
1387
1388         if (parameters_length < 1)
1389                 return;
1390         len = *parameters;
1391         proto_tree_add_text(parameters_tree, NullTVB, offset, 1,
1392             "authLen: %u", len);
1393         offset += 1;
1394         parameters += 1;
1395         parameters_length -= 1;
1396
1397         if (parameters_length < len)
1398                 return;
1399         proto_tree_add_text(parameters_tree, NullTVB, offset, len,
1400             "authDigest: %s", bytes_to_str(parameters, len));
1401         offset += len;
1402         parameters += len;
1403         parameters_length -= len;
1404
1405         if (parameters_length < 1)
1406                 return;
1407         proto_tree_add_text(parameters_tree, NullTVB, offset, parameters_length,
1408             "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1409 }
1410
1411 void
1412 dissect_snmp_pdu(const u_char *pd, int offset, frame_data *fd,
1413     proto_tree *tree, char *proto_name, int proto, gint ett)
1414 {
1415         ASN1_SCK asn1;
1416         const guchar *start;
1417         gboolean def;
1418         gboolean encrypted;
1419         guint length;
1420         guint message_length;
1421         guint global_length;
1422
1423         guint32 version;
1424         guint32 msgid;
1425         guint32 msgmax;
1426         guint32 msgsec;
1427         guint32 engineboots;
1428         guint32 enginetime;
1429
1430         guchar *msgflags;
1431         guchar *community;
1432         guchar *secparm;
1433         guchar *cengineid;
1434         guchar *cname;
1435         guchar *cryptpdu;
1436         guchar *aengineid;
1437         guchar *username;
1438         guchar *authpar;
1439         guchar *privpar;
1440         int msgflags_length;
1441         int community_length;
1442         int secparm_length;
1443         int cengineid_length;
1444         int cname_length;
1445         int cryptpdu_length;
1446         int aengineid_length;
1447         int username_length;
1448         int authpar_length;
1449         int privpar_length;
1450
1451         guint pdu_type;
1452         guint pdu_length;
1453
1454         proto_tree *snmp_tree = NULL;
1455         proto_tree *global_tree = NULL;
1456         proto_tree *flags_tree = NULL;
1457         proto_tree *secur_tree = NULL;
1458         proto_item *item = NULL;
1459         int ret;
1460         guint cls, con, tag;
1461
1462         if (check_col(fd, COL_PROTOCOL))
1463                 col_add_str(fd, COL_PROTOCOL, proto_name);
1464
1465         if (tree) {
1466                 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1467                     END_OF_FRAME, FALSE);
1468                 snmp_tree = proto_item_add_subtree(item, ett);
1469         }
1470
1471         /* NOTE: we have to parse the message piece by piece, since the
1472          * capture length may be less than the message length: a 'global'
1473          * parsing is likely to fail.
1474          */
1475         /* parse the SNMP header */
1476         asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1477         ret = asn1_sequence_decode(&asn1, &message_length, &length);
1478         if (ret != ASN1_ERR_NOERROR) {
1479                 dissect_snmp_parse_error(pd, offset, fd, tree,
1480                         "message header", ret);
1481                 return;
1482         }
1483         offset += length;
1484
1485         ret = asn1_uint32_decode (&asn1, &version, &length);
1486         if (ret != ASN1_ERR_NOERROR) {
1487                 dissect_snmp_parse_error(pd, offset, fd, tree, "version number",
1488                     ret);
1489                 return;
1490         }
1491         if (snmp_tree) {
1492                 proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1493                     "Version: %s",
1494                     val_to_str(version, versions, "Unknown version %#x"));
1495         }
1496         offset += length;
1497
1498
1499         switch (version) {
1500         case SNMP_VERSION_1:
1501         case SNMP_VERSION_2c:
1502                 ret = asn1_octet_string_decode (&asn1, &community, 
1503                     &community_length, &length);
1504                 if (ret != ASN1_ERR_NOERROR) {
1505                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1506                             "community", ret);
1507                         return;
1508                 }
1509                 if (tree) {
1510                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1511                             "Community: %.*s", community_length,
1512                             SAFE_STRING(community));
1513                 }
1514                 g_free(community);
1515                 offset += length;
1516                 break;
1517         case SNMP_VERSION_2u:
1518                 ret = asn1_octet_string_decode (&asn1, &community, 
1519                     &community_length, &length);
1520                 if (tree) {
1521                         dissect_snmp2u_parameters(snmp_tree, offset, length,
1522                             community, community_length);
1523                 }
1524                 g_free(community);
1525                 offset += length;
1526                 break;
1527         case SNMP_VERSION_3:
1528                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1529                 if (ret != ASN1_ERR_NOERROR) {
1530                         dissect_snmp_parse_error(pd, offset, fd, tree,
1531                                 "message global header", ret);
1532                         return;
1533                 }
1534                 if (snmp_tree) {
1535                         item = proto_tree_add_text(snmp_tree, NullTVB, offset,
1536                             global_length + length, "Message Global Header");
1537                         global_tree = proto_item_add_subtree(item, ett_global);
1538                         proto_tree_add_text(global_tree, NullTVB, offset,
1539                             length,
1540                             "Message Global Header Length: %d", global_length);
1541                 }
1542                 offset += length;
1543                 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1544                 if (ret != ASN1_ERR_NOERROR) {
1545                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1546                             "message id", ret);
1547                         return;
1548                 }
1549                 if (global_tree) {
1550                         proto_tree_add_text(global_tree, NullTVB, offset,
1551                             length, "Message ID: %d", msgid);
1552                 }
1553                 offset += length;
1554                 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1555                 if (ret != ASN1_ERR_NOERROR) {
1556                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1557                             "message max size", ret);
1558                         return;
1559                 }
1560                 if (global_tree) {
1561                         proto_tree_add_text(global_tree, NullTVB, offset,
1562                             length, "Message Max Size: %d", msgmax);
1563                 }
1564                 offset += length;
1565                 ret = asn1_octet_string_decode (&asn1, &msgflags, 
1566                     &msgflags_length, &length);
1567                 if (ret != ASN1_ERR_NOERROR) {
1568                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1569                             "message flags", ret);
1570                         return;
1571                 }
1572                 if (msgflags_length != 1) {
1573                         dissect_snmp_parse_error(pd, offset, fd, tree,
1574                             "message flags wrong length", ret);
1575                         g_free(msgflags);
1576                         return;
1577                 }
1578                 if (global_tree) {
1579                         item = proto_tree_add_uint_format(global_tree,
1580                             hf_snmpv3_flags, NullTVB, offset, length,
1581                             msgflags[0], "Flags: 0x%02x", msgflags[0]);
1582                         flags_tree = proto_item_add_subtree(item, ett_flags);
1583                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1584                             NullTVB, offset, length, msgflags[0]);
1585                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1586                             NullTVB, offset, length, msgflags[0]);
1587                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1588                             NullTVB, offset, length, msgflags[0]);
1589                 }
1590                 encrypted = msgflags[0] & TH_CRYPT;
1591                 g_free(msgflags);
1592                 offset += length;
1593                 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1594                 if (ret != ASN1_ERR_NOERROR) {
1595                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1596                             "message security model", ret);
1597                         return;
1598                 }
1599                 if (global_tree) {
1600                         proto_tree_add_text(global_tree, NullTVB, offset,
1601                             length, "Message Security Model: %s",
1602                             val_to_str(msgsec, sec_models,
1603                             "Unknown model %#x"));
1604                 }
1605                 offset += length;
1606                 switch(msgsec) {
1607                 case SNMP_SEC_USM:
1608                         start = asn1.pointer;
1609                         ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1610                             &def, &secparm_length);
1611                         length = asn1.pointer - start;
1612                         if (cls != ASN1_UNI && con != ASN1_PRI && 
1613                             tag != ASN1_OTS) {
1614                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1615                                     "Message Security Parameters",
1616                                     ASN1_ERR_WRONG_TYPE);
1617                                 return;
1618                         }
1619                         if (snmp_tree) {
1620                                 item = proto_tree_add_text(snmp_tree, NullTVB,
1621                                     offset, secparm_length + length,
1622                                     "Message Security Parameters");
1623                                 secur_tree = proto_item_add_subtree(item,
1624                                     ett_secur);
1625                                 proto_tree_add_text(secur_tree, NullTVB, offset,
1626                                     length, 
1627                                     "Message Security Parameters Length: %d",
1628                                     secparm_length);
1629                         }
1630                         offset += length;
1631                         ret = asn1_sequence_decode(&asn1, &secparm_length,
1632                             &length);
1633                         if (ret != ASN1_ERR_NOERROR) {
1634                                 dissect_snmp_parse_error(pd, offset, fd, tree,
1635                                     "USM sequence header", ret);
1636                                 return;
1637                         }
1638                         offset += length;
1639                         ret = asn1_octet_string_decode (&asn1, &aengineid, 
1640                             &aengineid_length, &length);
1641                         if (ret != ASN1_ERR_NOERROR) {
1642                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1643                                     "authoritative engine id", ret);
1644                                 return;
1645                         }
1646                         if (secur_tree) {
1647                                 proto_tree_add_text(secur_tree, NullTVB, offset,
1648                                     length, "Authoritative Engine ID: %s",
1649                                     bytes_to_str(aengineid, aengineid_length));
1650                         }
1651                         g_free(aengineid);
1652                         offset += length;
1653                         ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1654                         if (ret != ASN1_ERR_NOERROR) {
1655                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1656                                     "engine boots", ret);
1657                                 return;
1658                         }
1659                         if (secur_tree) {
1660                                 proto_tree_add_text(secur_tree, NullTVB,
1661                                     offset, length, "Engine Boots: %d", 
1662                                     engineboots);
1663                         }
1664                         offset += length;
1665                         ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1666                         if (ret != ASN1_ERR_NOERROR) {
1667                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1668                                     "engine time", ret);
1669                                 return;
1670                         }
1671                         if (secur_tree) {
1672                                 proto_tree_add_text(secur_tree, NullTVB,
1673                                     offset, length, "Engine Time: %d", 
1674                                     enginetime);
1675                         }
1676                         offset += length;
1677                         ret = asn1_octet_string_decode (&asn1, &username, 
1678                             &username_length, &length);
1679                         if (ret != ASN1_ERR_NOERROR) {
1680                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1681                                     "user name", ret);
1682                                 return;
1683                         }
1684                         if (secur_tree) {
1685                                 proto_tree_add_text(secur_tree, NullTVB, offset,
1686                                     length, "User Name: %.*s", 
1687                                     username_length,
1688                                     SAFE_STRING(username));
1689                         }
1690                         g_free(username);
1691                         offset += length;
1692                         ret = asn1_octet_string_decode (&asn1, &authpar, 
1693                             &authpar_length, &length);
1694                         if (ret != ASN1_ERR_NOERROR) {
1695                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1696                                     "authentication parameter", ret);
1697                                 return;
1698                         }
1699                         if (secur_tree) {
1700                                 proto_tree_add_text(secur_tree, NullTVB, offset,
1701                                     length, "Authentication Parameter: %s",
1702                                     bytes_to_str(authpar, authpar_length));
1703                         }
1704                         g_free(authpar);
1705                         offset += length;
1706                         ret = asn1_octet_string_decode (&asn1, &privpar, 
1707                             &privpar_length, &length);
1708                         if (ret != ASN1_ERR_NOERROR) {
1709                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1710                                     "privacy parameter", ret);
1711                                 return;
1712                         }
1713                         if (secur_tree) {
1714                                 proto_tree_add_text(secur_tree, NullTVB, offset,
1715                                     length, "Privacy Parameter: %s",
1716                                     bytes_to_str(privpar, privpar_length));
1717                         }
1718                         g_free(privpar);
1719                         offset += length;
1720                         break;
1721                 default:
1722                         ret = asn1_octet_string_decode (&asn1, 
1723                             &secparm, &secparm_length, &length);
1724                         if (ret != ASN1_ERR_NOERROR) {
1725                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1726                                     "Message Security Parameters", ret);
1727                                 return;
1728                         }
1729                         if (snmp_tree) {
1730                                 proto_tree_add_text(snmp_tree, NullTVB, offset,
1731                                     length,
1732                                     "Message Security Parameters Data"
1733                                     " (%d bytes)", secparm_length);
1734                         }
1735                         g_free(secparm);
1736                         offset += length;
1737                         break;
1738                 }
1739                 /* PDU starts here */
1740                 if (encrypted) {
1741                         ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1742                             &cryptpdu_length, &length);
1743                         if (ret != ASN1_ERR_NOERROR) {
1744                                 dissect_snmp_parse_error(pd, offset, fd, tree, 
1745                                     "encrypted PDU header", ret);
1746                                 return;
1747                         }
1748                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1749                             "Encrypted PDU (%d bytes)", length);
1750                         g_free(cryptpdu);
1751                         if (check_col(fd, COL_INFO))
1752                                 col_set_str(fd, COL_INFO, "Encrypted PDU");
1753                         return;
1754                 }
1755                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1756                 if (ret != ASN1_ERR_NOERROR) {
1757                         dissect_snmp_parse_error(pd, offset, fd, tree,
1758                                 "PDU header", ret);
1759                         return;
1760                 }
1761                 offset += length;
1762                 ret = asn1_octet_string_decode (&asn1, &cengineid, 
1763                     &cengineid_length, &length);
1764                 if (ret != ASN1_ERR_NOERROR) {
1765                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1766                             "context engine id", ret);
1767                         return;
1768                 }
1769                 if (snmp_tree) {
1770                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1771                             "Context Engine ID: %s",
1772                             bytes_to_str(cengineid, cengineid_length));
1773                 }
1774                 g_free(cengineid);
1775                 offset += length;
1776                 ret = asn1_octet_string_decode (&asn1, &cname, 
1777                     &cname_length, &length);
1778                 if (ret != ASN1_ERR_NOERROR) {
1779                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1780                             "context name", ret);
1781                         return;
1782                 }
1783                 if (snmp_tree) {
1784                         proto_tree_add_text(snmp_tree, NullTVB, offset, length,
1785                             "Context Name: %.*s", cname_length,
1786                             SAFE_STRING(cname));
1787                 }
1788                 g_free(cname);
1789                 offset += length;
1790                 break;
1791         default:
1792                 dissect_snmp_error(pd, offset, fd, tree,
1793                     "PDU for unknown version of SNMP");
1794                 return;
1795         }
1796
1797         start = asn1.pointer;
1798         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1799             &pdu_length);
1800         if (ret != ASN1_ERR_NOERROR) {
1801                 dissect_snmp_parse_error(pd, offset, fd, tree,
1802                     "PDU type", ret);
1803                 return;
1804         }
1805         if (cls != ASN1_CTX || con != ASN1_CON) {
1806                 dissect_snmp_parse_error(pd, offset, fd, tree,
1807                     "PDU type", ASN1_ERR_WRONG_TYPE);
1808                 return;
1809         }
1810         dissect_common_pdu(pd, offset, fd, snmp_tree, asn1, pdu_type, start);
1811 }
1812
1813 static void
1814 dissect_smux_pdu(const u_char *pd, int offset, frame_data *fd,
1815     proto_tree *tree, int proto, gint ett)
1816 {
1817         ASN1_SCK asn1;
1818         const guchar *start;
1819         gboolean def;
1820         guint length;
1821
1822         guint pdu_type;
1823         char *pdu_type_string;
1824         guint pdu_length;
1825
1826         guint32 version;
1827         guint32 cause;
1828         guint32 priority;
1829         guint32 operation;
1830         guint32 commit;
1831
1832         guchar *password;
1833         int password_length;
1834
1835         guchar *application;
1836         int application_length;
1837
1838         subid_t *regid;
1839         guint regid_length;
1840
1841         gchar *oid_string;
1842
1843         proto_tree *smux_tree = NULL;
1844         proto_item *item = NULL;
1845         int ret;
1846         guint cls, con;
1847
1848         if (check_col(fd, COL_PROTOCOL))
1849                 col_set_str(fd, COL_PROTOCOL, "SMUX");
1850
1851         if (tree) {
1852                 item = proto_tree_add_item(tree, proto, NullTVB, offset,
1853                     END_OF_FRAME, FALSE);
1854                 smux_tree = proto_item_add_subtree(item, ett);
1855         }
1856
1857         /* NOTE: we have to parse the message piece by piece, since the
1858          * capture length may be less than the message length: a 'global'
1859          * parsing is likely to fail.
1860          */
1861         /* parse the SNMP header */
1862         asn1_open(&asn1, &pd[offset], END_OF_FRAME);
1863         start = asn1.pointer;
1864         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1865             &pdu_length);
1866         if (ret != ASN1_ERR_NOERROR) {
1867                 dissect_snmp_parse_error(pd, offset, fd, tree,
1868                     "PDU type", ret);
1869                 return;
1870         }
1871
1872         /* Dissect SMUX here */
1873         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1874                 pdu_type_string = val_to_str(pdu_type, smux_types,
1875                     "Unknown PDU type %#x");
1876                 if (check_col(fd, COL_INFO))
1877                         col_add_str(fd, COL_INFO, pdu_type_string);
1878                 length = asn1.pointer - start;
1879                 if (tree) {
1880                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1881                             "PDU type: %s", pdu_type_string);
1882                 }
1883                 offset += length;
1884                 ret = asn1_uint32_decode (&asn1, &version, &length);
1885                 if (ret != ASN1_ERR_NOERROR) {
1886                         dissect_snmp_parse_error(pd, offset, fd, tree,
1887                             "version", ret);
1888                         return;
1889                 }
1890                 if (tree) {
1891                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1892                             "Version: %d", version);
1893                 }
1894                 offset += length;
1895
1896                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
1897                 if (ret != ASN1_ERR_NOERROR) {
1898                         dissect_snmp_parse_error(pd, offset, fd, tree,
1899                             "registration OID", ret);
1900                         return;
1901                 }
1902                 if (tree) {
1903                         oid_string = format_oid(regid, regid_length);
1904                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1905                             "Registration: %s", oid_string);
1906                         g_free(oid_string);
1907                 }
1908                 g_free(regid);
1909                 offset += length;
1910
1911                 ret = asn1_octet_string_decode (&asn1, &application, 
1912                     &application_length, &length);
1913                 if (ret != ASN1_ERR_NOERROR) {
1914                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1915                             "application", ret);
1916                         return;
1917                 }
1918                 if (tree) {
1919                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1920                             "Application: %.*s", application_length,
1921                              SAFE_STRING(application));
1922                 }
1923                 g_free(application);
1924                 offset += length;
1925
1926                 ret = asn1_octet_string_decode (&asn1, &password, 
1927                     &password_length, &length);
1928                 if (ret != ASN1_ERR_NOERROR) {
1929                         dissect_snmp_parse_error(pd, offset, fd, tree, 
1930                             "password", ret);
1931                         return;
1932                 }
1933                 if (tree) {
1934                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1935                             "Password: %.*s", password_length,
1936                             SAFE_STRING(password));
1937                 }
1938                 g_free(password);
1939                 offset += length;
1940                 return;
1941         }
1942         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1943                 pdu_type_string = val_to_str(pdu_type, smux_types,
1944                     "Unknown PDU type %#x");
1945                 if (check_col(fd, COL_INFO))
1946                         col_add_str(fd, COL_INFO, pdu_type_string);
1947                 length = asn1.pointer - start;
1948                 if (tree) {
1949                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1950                             "PDU type: %s", pdu_type_string);
1951                 }
1952                 offset += length;
1953                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1954                 if (ret != ASN1_ERR_NOERROR) {
1955                         dissect_snmp_parse_error(pd, offset, fd, tree,
1956                             "cause", ret);
1957                         return;
1958                 }
1959                 if (tree) {
1960                         proto_tree_add_text(smux_tree, NullTVB, offset,
1961                             pdu_length, "Cause: %s",
1962                             val_to_str(cause, smux_close, 
1963                                 "Unknown cause %#x"));
1964                 }
1965                 offset += pdu_length;
1966                 return;
1967         }
1968         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
1969                 pdu_type_string = val_to_str(pdu_type, smux_types,
1970                     "Unknown PDU type %#x");
1971                 if (check_col(fd, COL_INFO))
1972                         col_add_str(fd, COL_INFO, pdu_type_string);
1973                 length = asn1.pointer - start;
1974                 if (tree) {
1975                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1976                             "PDU type: %s", pdu_type_string);
1977                 }
1978                 offset += length;
1979                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
1980                 if (ret != ASN1_ERR_NOERROR) {
1981                         dissect_snmp_parse_error(pd, offset, fd, tree,
1982                             "registration subtree", ret);
1983                         return;
1984                 }
1985                 if (tree) {
1986                         oid_string = format_oid(regid, regid_length);
1987                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
1988                             "Registration: %s", oid_string);
1989                         g_free(oid_string);
1990                 }
1991                 g_free(regid);
1992                 offset += length;
1993
1994                 ret = asn1_uint32_decode (&asn1, &priority, &length);
1995                 if (ret != ASN1_ERR_NOERROR) {
1996                         dissect_snmp_parse_error(pd, offset, fd, tree,
1997                             "priority", ret);
1998                         return;
1999                 }
2000                 if (tree) {
2001                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
2002                             "Priority: %d", priority);
2003                 }
2004                 offset += length;
2005
2006                 ret = asn1_uint32_decode (&asn1, &operation, &length);
2007                 if (ret != ASN1_ERR_NOERROR) {
2008                         dissect_snmp_parse_error(pd, offset, fd, tree,
2009                             "operation", ret);
2010                         return;
2011                 }
2012                 if (tree) {
2013                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
2014                             "Operation: %s", 
2015                             val_to_str(operation, smux_rreq, 
2016                                 "Unknown operation %#x"));
2017                 }
2018                 offset += length;
2019                 return;
2020         }
2021         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2022                 pdu_type_string = val_to_str(pdu_type, smux_types,
2023                     "Unknown PDU type %#x");
2024                 if (check_col(fd, COL_INFO))
2025                         col_add_str(fd, COL_INFO, pdu_type_string);
2026                 length = asn1.pointer - start;
2027                 if (tree) {
2028                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
2029                             "PDU type: %s", pdu_type_string);
2030                 }
2031                 offset += length;
2032                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2033                 if (ret != ASN1_ERR_NOERROR) {
2034                         dissect_snmp_parse_error(pd, offset, fd, tree,
2035                             "priority", ret);
2036                         return;
2037                 }
2038                 if (tree) {
2039                         proto_tree_add_text(smux_tree, NullTVB, offset,
2040                             pdu_length, "%s",
2041                             val_to_str(priority, smux_prio, 
2042                                 "Priority: %#x"));
2043                 }
2044                 offset += pdu_length;
2045                 return;
2046         }
2047         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2048                 pdu_type_string = val_to_str(pdu_type, smux_types,
2049                     "Unknown PDU type %#x");
2050                 if (check_col(fd, COL_INFO))
2051                         col_add_str(fd, COL_INFO, pdu_type_string);
2052                 length = asn1.pointer - start;
2053                 if (tree) {
2054                         proto_tree_add_text(smux_tree, NullTVB, offset, length,
2055                             "PDU type: %s", pdu_type_string);
2056                 }
2057                 offset += length;
2058                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2059                 if (ret != ASN1_ERR_NOERROR) {
2060                         dissect_snmp_parse_error(pd, offset, fd, tree,
2061                             "commit", ret);
2062                         return;
2063                 }
2064                 if (tree) {
2065                         proto_tree_add_text(smux_tree, NullTVB, offset,
2066                             pdu_length, "%s",
2067                             val_to_str(commit, smux_sout, 
2068                                 "Unknown SOUT Value: %#x"));
2069                 }
2070                 offset += pdu_length;
2071                 return;
2072         }
2073         if (cls != ASN1_CTX || con != ASN1_CON) {
2074                 dissect_snmp_parse_error(pd, offset, fd, tree,
2075                     "PDU type", ASN1_ERR_WRONG_TYPE);
2076                 return;
2077         }
2078         dissect_common_pdu(pd, offset, fd, smux_tree, asn1, pdu_type, start);
2079 }
2080
2081 static void
2082 dissect_snmp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
2083 {
2084         conversation_t  *conversation;
2085
2086         OLD_CHECK_DISPLAY_AS_DATA(proto_snmp, pd, offset, fd, tree);
2087
2088         /*
2089          * The first SNMP packet goes to the SNMP port; the second one
2090          * may come from some *other* port, but goes back to the same
2091          * IP address and port as the ones from which the first packet
2092          * came; all subsequent packets presumably go between those two
2093          * IP addresses and ports.
2094          *
2095          * If this packet went to the SNMP port, we check to see if
2096          * there's already a conversation with the source IP address
2097          * and port of this packet, the destination IP address of this
2098          * packet, and any destination UDP port.  If not, we create
2099          * one, with a wildcard UDP port, and give it the SNMP dissector
2100          * as a dissector.
2101          */
2102         if (pi.destport == UDP_PORT_SNMP) {
2103           conversation = find_conversation(&pi.src, &pi.dst, PT_UDP,
2104                                            pi.srcport, 0, NO_DST_PORT);
2105           if (conversation == NULL) {
2106             conversation = conversation_new(&pi.src, &pi.dst, PT_UDP,
2107                                             pi.srcport, 0, NULL,
2108                                             NO_DST_PORT);
2109             old_conversation_set_dissector(conversation, dissect_snmp);
2110           }
2111         }
2112
2113         dissect_snmp_pdu(pd, offset, fd, tree, "SNMP", proto_snmp, ett_snmp);
2114 }
2115
2116 static void
2117 dissect_smux(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) 
2118 {
2119         OLD_CHECK_DISPLAY_AS_DATA(proto_smux, pd, offset, fd, tree);
2120         dissect_smux_pdu(pd, offset, fd, tree, proto_smux, ett_smux);
2121 }
2122
2123 void
2124 proto_register_snmp(void)
2125 {
2126 #ifdef linux
2127         void *libsnmp_handle;
2128         int (*snmp_set_suffix_only_p)(int);
2129         int (*ds_set_int_p)(int, int, int);
2130 #endif
2131
2132         static hf_register_info hf[] = {
2133                 { &hf_snmpv3_flags,
2134                 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2135                     0x0, "" }},
2136                 { &hf_snmpv3_flags_auth,
2137                 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2138                     TFS(&flags_set_truth), TH_AUTH, "" }},
2139                 { &hf_snmpv3_flags_crypt,
2140                 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2141                     TFS(&flags_set_truth), TH_CRYPT, "" }},
2142                 { &hf_snmpv3_flags_report,
2143                 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2144                     TFS(&flags_set_truth), TH_REPORT, "" }},
2145         };
2146         static gint *ett[] = {
2147                 &ett_snmp,
2148                 &ett_smux,
2149                 &ett_parameters,
2150                 &ett_parameters_qos,
2151                 &ett_global,
2152                 &ett_flags,
2153                 &ett_secur,
2154         };
2155
2156 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2157         /* UCD or CMU SNMP */
2158         init_mib();
2159 #ifdef HAVE_UCD_SNMP_SNMP_H
2160 #ifdef linux
2161         /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2162            changed "snmp_set_suffix_only()" from a function to a macro,
2163            removing "snmp_set_suffix_only()" from the library; this means
2164            that binaries that call "snmp_set_suffix_only()" and
2165            that are linked against shared libraries from earlier versions
2166            of the UCD SNMP library won't run with shared libraries from
2167            4.1.1.
2168
2169            This is a problem on Red Hat Linux, as pre-6.2 releases
2170            came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2171            Versions of Ethereal built on pre-6.2 releases don't run
2172            on 6.2, and the current Ethereal RPMs are built on pre-6.2
2173            releases, causing problems when users running 6.2 download
2174            them and try to use them.
2175
2176            Building the releases on 6.2 isn't necessarily the answer,
2177            as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2178            with a second argument not supported by at least some pre-4.1.1
2179            versions of the library - it appears that the 4.0.1 library,
2180            at least, checks for invalid arguments and returns an error
2181            rather than stomping random memory, but that means that you
2182            won't get get OIDs displayed as module-name::sub-OID.
2183
2184            So we use a trick similar to one I've seen mentioned as
2185            used in Windows applications to let you build binaries
2186            that run on many different versions of Windows 9x and
2187            Windows NT, that use features present on later versions
2188            if run on those later versions, but that avoid calling,
2189            when run on older versions, routines not present on those
2190            older versions.
2191
2192            I.e., we load "libsnmp.so.0" with "dlopen()", and call
2193            "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2194            don't find it, we make the appropriate call to
2195            "ds_set_int()" instead.  (We load "libsnmp.so.0" rather
2196            than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2197            exists only if you've loaded the libsnmp development package,
2198            which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2199            don't want to force users to install it or to make said
2200            symlink by hand.)
2201
2202            We do this only on Linux, for now, as we've only seen the
2203            problem on Red Hat; it may show up on other OSes that bundle
2204            UCD SNMP, or on OSes where it's not bundled but for which
2205            binary packages are built that link against a shared version
2206            of the UCD SNMP library.  If we run into one of those, we
2207            can do this under those OSes as well, *if* "dlopen()" makes
2208            the run-time linker use the same search rules as it uses when
2209            loading libraries with which the application is linked.
2210
2211            (Perhaps we could use the GLib wrappers for run-time linking,
2212            *if* they're thin enough; however, as this code is currently
2213            used only on Linux, we don't worry about that for now.) */
2214
2215         libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2216         if (libsnmp_handle == NULL) {
2217                 /* We didn't find "libsnmp.so.0".
2218
2219                    This could mean that there is no SNMP shared library
2220                    on this system, in which case we were linked statically,
2221                    in which case whatever call the following line of code
2222                    makes will presumably work, as we have the routine it
2223                    calls wired into our binary.  (If we were linked
2224                    dynamically with "-lsnmp", we would have failed to
2225                    start.)
2226
2227                    It could also mean that there is an SNMP shared library
2228                    on this system, but it's called something other than
2229                    "libsnmp.so.0"; so far, we've seen the problem we're
2230                    working around only on systems where the SNMP shared
2231                    library is called "libsnmp.so.0", so we assume for now
2232                    that systems with shared SNMP libraries named something
2233                    other than "libsnmp.so.0" have an SNMP library that's
2234                    not 4.1.1. */
2235                 snmp_set_suffix_only(2);
2236         } else {
2237                 /* OK, we have it loaded.  Do we have
2238                    "snmp_set_suffix_only()"? */
2239                 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2240                     "snmp_set_suffix_only");
2241                 if (snmp_set_suffix_only_p != NULL) {
2242                         /* Yes - call it. */
2243                         (*snmp_set_suffix_only_p)(2);
2244                 } else {
2245                         /* No; do we have "ds_set_int()"? */
2246                         ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2247                         if (ds_set_int_p != NULL) {
2248                                 /* Yes - cal it with DS_LIBRARY_ID,
2249                                    DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2250                                    arguments.
2251
2252                                    We do *not* use DS_LIBRARY_ID or
2253                                    DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2254                                    we don't require that Ethereal be built
2255                                    with versions of UCD SNMP that include
2256                                    that value; instead, we use their values
2257                                    in UCD SNMP 4.1.1, which are 0 and 4,
2258                                    respectively. */
2259                                 (*ds_set_int_p)(0, 4, 2);
2260                         }
2261                 }
2262                 dlclose(libsnmp_handle);
2263         }
2264 #else /* linux */
2265         snmp_set_suffix_only(2);
2266 #endif /* linux */
2267 #endif /* HAVE_UCD_SNMP_SNMP_H */
2268 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2269         proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2270             "SNMP", "snmp");
2271         proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2272             "SMUX", "smux");
2273         proto_register_field_array(proto_snmp, hf, array_length(hf));
2274         proto_register_subtree_array(ett, array_length(ett));
2275 }
2276
2277 void
2278 proto_reg_handoff_snmp(void)
2279 {
2280         old_dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp,
2281             proto_snmp);
2282         old_dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp,
2283             proto_snmp);
2284         old_dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux,
2285             proto_smux);
2286         old_dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp,
2287             proto_snmp);
2288         old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp,
2289             proto_snmp);
2290         old_dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp,
2291             proto_snmp);
2292 }