40f6ecd89443c3049079bc46ce901a7e3f777f30
[obnox/wireshark/wip.git] / packet-snmp.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * Copyright (C) 1998 Didier Jorand
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.70 2001/09/03 08:19:12 guy Exp $
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@ethereal.com>
15  * Copyright 1998 Gerald Combs
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(tvbuff_t *tvb, int offset, packet_info *pinfo,
523                    proto_tree *tree, const char *field_name, int ret)
524 {
525         const gchar *errstr;
526
527         switch (ret) {
528
529         case ASN1_ERR_EOC_MISMATCH:
530                 errstr = "EOC mismatch";
531                 break;
532
533         case ASN1_ERR_WRONG_TYPE:
534                 errstr = "Wrong type for that item";
535                 break;
536
537         case ASN1_ERR_LENGTH_NOT_DEFINITE:
538                 errstr = "Length was indefinite";
539                 break;
540
541         case ASN1_ERR_LENGTH_MISMATCH:
542                 errstr = "Length mismatch";
543                 break;
544
545         case ASN1_ERR_WRONG_LENGTH_FOR_TYPE:
546                 errstr = "Wrong length for that item's type";
547                 break;
548
549         default:
550                 errstr = "Unknown error";
551                 break;
552         }
553
554         if (check_col(pinfo->fd, COL_INFO)) {
555                 col_add_fstr(pinfo->fd, COL_INFO,
556                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
557         }
558         if (tree != NULL) {
559                 proto_tree_add_text(tree, tvb, offset, 0,
560                     "ERROR: Couldn't parse %s: %s", field_name, errstr);
561                 dissect_data(tvb, offset, pinfo, tree);
562         }
563 }
564
565 static void
566 dissect_snmp_error(tvbuff_t *tvb, int offset, packet_info *pinfo,
567                    proto_tree *tree, const char *message)
568 {
569         if (check_col(pinfo->fd, COL_INFO))
570                 col_add_str(pinfo->fd, COL_INFO, message);
571
572         if (tree != NULL) {
573                 proto_tree_add_text(tree, tvb, offset, 0, "%s", message);
574                 dissect_data(tvb, offset, pinfo, tree);
575         }
576 }
577
578 static gchar *
579 format_oid(subid_t *oid, guint oid_length)
580 {
581         char *result;
582         int result_len;
583         int len;
584         unsigned int i;
585         char *buf;
586
587         result_len = oid_length * 22;
588         result = g_malloc(result_len + 1);
589         buf = result;
590         len = sprintf(buf, "%lu", (unsigned long)oid[0]);
591         buf += len;
592         for (i = 1; i < oid_length;i++) {
593                 len = sprintf(buf, ".%lu", (unsigned long)oid[i]);
594                 buf += len;
595         }
596         return result;
597 }
598
599 #ifdef HAVE_SPRINT_VALUE
600 static gchar *
601 format_var(struct variable_list *variable, subid_t *variable_oid,
602     guint variable_oid_length, gushort vb_type, guint vb_length)
603 {
604         gchar *buf;
605
606         switch (vb_type) {
607
608         case SNMP_INTEGER:
609         case SNMP_COUNTER:
610         case SNMP_GAUGE:
611         case SNMP_TIMETICKS:
612                 /* We don't know how long this will be, but let's guess it
613                    fits within 128 characters; that should be enough for an
614                    integral value plus some sort of type indication. */
615                 buf = g_malloc(128);
616                 break;
617
618         case SNMP_OCTETSTR:
619         case SNMP_IPADDR:
620         case SNMP_OPAQUE:
621         case SNMP_NSAP:
622         case SNMP_BITSTR:
623         case SNMP_COUNTER64:
624                 /* We don't know how long this will be, but let's guess it
625                    fits within 128 characters plus 4 characters per octet. */
626                 buf = g_malloc(128 + 4*vb_length);
627                 break;
628
629         case SNMP_OBJECTID:
630                 /* We don't know how long this will be, but let's guess it
631                    fits within 128 characters plus 32 characters per subid
632                    (10 digits plus period, or a subid name). */
633                 buf = g_malloc(1024 + 32*vb_length);
634                 break;
635
636         default:
637                 /* Should not happen. */
638                 g_assert_not_reached();
639                 buf = NULL;
640                 break;
641         }
642
643         variable->next_variable = NULL;
644         variable->name = variable_oid;
645         variable->name_length = variable_oid_length;
646         switch (vb_type) {
647
648         case SNMP_INTEGER:
649                 variable->type = VALTYPE_INTEGER;
650                 break;
651
652         case SNMP_COUNTER:
653                 variable->type = VALTYPE_COUNTER;
654                 break;
655
656         case SNMP_GAUGE:
657                 variable->type = VALTYPE_GAUGE;
658                 break;
659
660         case SNMP_TIMETICKS:
661                 variable->type = VALTYPE_TIMETICKS;
662                 break;
663
664         case SNMP_OCTETSTR:
665                 variable->type = VALTYPE_STRING;
666                 break;
667
668         case SNMP_IPADDR:
669                 variable->type = VALTYPE_IPADDR;
670                 break;
671
672         case SNMP_OPAQUE:
673                 variable->type = VALTYPE_OPAQUE;
674                 break;
675
676         case SNMP_NSAP:
677                 variable->type = VALTYPE_NSAP;
678                 break;
679
680         case SNMP_OBJECTID:
681                 variable->type = VALTYPE_OBJECTID;
682                 vb_length *= sizeof (subid_t);  /* XXX - necessary? */
683                 break;
684
685         case SNMP_BITSTR:
686                 variable->type = VALTYPE_BITSTR;
687                 break;
688
689         case SNMP_COUNTER64:
690                 variable->type = VALTYPE_COUNTER64;
691                 break;
692         }
693         variable->val_len = vb_length;
694
695         sprint_value(buf, variable_oid, variable_oid_length, variable);
696         return buf;
697 }
698 #endif
699
700 static int
701 snmp_variable_decode(proto_tree *snmp_tree, subid_t *variable_oid,
702     guint variable_oid_length, ASN1_SCK *asn1, int offset, guint *lengthp,
703     gboolean unsafe)
704 {
705         int start;
706         guint length;
707         gboolean def;
708         guint vb_length;
709         gushort vb_type;
710         gchar *vb_type_name;
711         int ret;
712         guint cls, con, tag;
713
714         gint32 vb_integer_value;
715         guint32 vb_uinteger_value;
716
717         guint8 *vb_octet_string;
718
719         subid_t *vb_oid;
720         guint vb_oid_length;
721
722         gchar *vb_display_string;
723
724 #ifdef HAVE_SPRINT_VALUE
725         struct variable_list variable;
726 #if defined(HAVE_UCD_SNMP_SNMP_H)
727         long value;
728 #endif
729 #endif  /* HAVE_SPRINT_VALUE */
730         unsigned int i;
731         gchar *buf;
732         int len;
733
734         /* parse the type of the object */
735         start = asn1->offset;
736         ret = asn1_header_decode (asn1, &cls, &con, &tag, &def, &vb_length);
737         if (ret != ASN1_ERR_NOERROR)
738                 return ret;
739         if (!def)
740                 return ASN1_ERR_LENGTH_NOT_DEFINITE;
741
742         /* Convert the class, constructed flag, and tag to a type. */
743         vb_type_name = snmp_tag_cls2syntax(tag, cls, &vb_type);
744         if (vb_type_name == NULL) {
745                 /*
746                  * Unsupported type.
747                  * Dissect the value as an opaque string of octets.
748                  */
749                 vb_type_name = "unsupported type";
750                 vb_type = SNMP_OPAQUE;
751         }
752
753         /* parse the value */
754         switch (vb_type) {
755
756         case SNMP_INTEGER:
757                 ret = asn1_int32_value_decode(asn1, vb_length,
758                     &vb_integer_value);
759                 if (ret != ASN1_ERR_NOERROR)
760                         return ret;
761                 length = asn1->offset - start;
762                 if (snmp_tree) {
763 #ifdef HAVE_SPRINT_VALUE
764                         if (!unsafe) {
765 #if defined(HAVE_UCD_SNMP_SNMP_H)
766                                 value = vb_integer_value;
767                                 variable.val.integer = &value;
768 #elif defined(HAVE_SNMP_SNMP_H)
769                                 variable.val.integer = &vb_integer_value;
770 #endif
771                                 vb_display_string = format_var(&variable,
772                                     variable_oid, variable_oid_length, vb_type,
773                                     vb_length);
774                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
775                                     length,
776                                     "Value: %s", vb_display_string);
777                                 g_free(vb_display_string);
778                                 break;  /* we added formatted version to the tree */
779                         }
780 #endif /* HAVE_SPRINT_VALUE */
781                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
782                             "Value: %s: %d (%#x)", vb_type_name,
783                             vb_integer_value, vb_integer_value);
784                 }
785                 break;
786
787         case SNMP_COUNTER:
788         case SNMP_GAUGE:
789         case SNMP_TIMETICKS:
790                 ret = asn1_uint32_value_decode(asn1, vb_length,
791                     &vb_uinteger_value);
792                 if (ret != ASN1_ERR_NOERROR)
793                         return ret;
794                 length = asn1->offset - start;
795                 if (snmp_tree) {
796 #ifdef HAVE_SPRINT_VALUE
797                         if (!unsafe) {
798 #if defined(HAVE_UCD_SNMP_SNMP_H)
799                                 value = vb_uinteger_value;
800                                 variable.val.integer = &value;
801 #elif defined(HAVE_SNMP_SNMP_H)
802                                 variable.val.integer = &vb_uinteger_value;
803 #endif
804                                 vb_display_string = format_var(&variable,
805                                     variable_oid, variable_oid_length, vb_type,
806                                     vb_length);
807                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
808                                     length,
809                                     "Value: %s", vb_display_string);
810                                 g_free(vb_display_string);
811                                 break;  /* we added formatted version to the tree */
812                         }
813 #endif /* HAVE_SPRINT_VALUE */
814                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
815                             "Value: %s: %u (%#x)", vb_type_name,
816                             vb_uinteger_value, vb_uinteger_value);
817                 }
818                 break;
819
820         case SNMP_OCTETSTR:
821         case SNMP_IPADDR:
822         case SNMP_OPAQUE:
823         case SNMP_NSAP:
824         case SNMP_BITSTR:
825         case SNMP_COUNTER64:
826                 ret = asn1_string_value_decode (asn1, vb_length,
827                     &vb_octet_string);
828                 if (ret != ASN1_ERR_NOERROR)
829                         return ret;
830                 length = asn1->offset - start;
831                 if (snmp_tree) {
832 #ifdef HAVE_SPRINT_VALUE
833                         if (!unsafe) {
834                                 variable.val.string = vb_octet_string;
835                                 vb_display_string = format_var(&variable,
836                                     variable_oid, variable_oid_length, vb_type,
837                                     vb_length);
838                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
839                                     length,
840                                     "Value: %s", vb_display_string);
841                                 g_free(vb_display_string);
842                                 break;  /* we added formatted version to the tree */
843                         }
844 #endif /* HAVE_SPRINT_VALUE */
845                         /*
846                          * If some characters are not printable, display
847                          * the string as bytes.
848                          */
849                         for (i = 0; i < vb_length; i++) {
850                                 if (!(isprint(vb_octet_string[i])
851                                     || isspace(vb_octet_string[i])))
852                                         break;
853                         }
854                         if (i < vb_length) {
855                                 /*
856                                  * We stopped, due to a non-printable
857                                  * character, before we got to the end
858                                  * of the string.
859                                  */
860                                 vb_display_string = g_malloc(4*vb_length);
861                                 buf = &vb_display_string[0];
862                                 len = sprintf(buf, "%03u", vb_octet_string[0]);
863                                 buf += len;
864                                 for (i = 1; i < vb_length; i++) {
865                                         len = sprintf(buf, ".%03u",
866                                             vb_octet_string[i]);
867                                         buf += len;
868                                 }
869                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
870                                     "Value: %s: %s", vb_type_name,
871                                     vb_display_string);
872                                 g_free(vb_display_string);
873                         } else {
874                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
875                                     "Value: %s: %.*s", vb_type_name,
876                                     (int)vb_length,
877                                     SAFE_STRING(vb_octet_string));
878                         }
879                 }
880                 g_free(vb_octet_string);
881                 break;
882
883         case SNMP_NULL:
884                 ret = asn1_null_decode (asn1, vb_length);
885                 if (ret != ASN1_ERR_NOERROR)
886                         return ret;
887                 length = asn1->offset - start;
888                 if (snmp_tree) {
889                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
890                             "Value: %s", vb_type_name);
891                 }
892                 break;
893
894         case SNMP_OBJECTID:
895                 ret = asn1_oid_value_decode (asn1, vb_length, &vb_oid,
896                     &vb_oid_length);
897                 if (ret != ASN1_ERR_NOERROR)
898                         return ret;
899                 length = asn1->offset - start;
900                 if (snmp_tree) {
901 #ifdef HAVE_SPRINT_VALUE
902                         if (!unsafe) {
903                                 variable.val.objid = vb_oid;
904                                 vb_display_string = format_var(&variable,
905                                     variable_oid, variable_oid_length, vb_type,
906                                     vb_length);
907                                 proto_tree_add_text(snmp_tree, asn1->tvb, offset,
908                                     length,
909                                     "Value: %s", vb_display_string);
910                                 break;  /* we added formatted version to the tree */
911                         }
912 #endif /* HAVE_SPRINT_VALUE */
913                         vb_display_string = format_oid(vb_oid, vb_oid_length);
914                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
915                             "Value: %s: %s", vb_type_name, vb_display_string);
916                         g_free(vb_display_string);
917                 }
918                 g_free(vb_oid);
919                 break;
920
921         case SNMP_NOSUCHOBJECT:
922                 length = asn1->offset - start;
923                 if (snmp_tree) {
924                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
925                             "Value: %s: no such object", vb_type_name);
926                 }
927                 break;
928
929         case SNMP_NOSUCHINSTANCE:
930                 length = asn1->offset - start;
931                 if (snmp_tree) {
932                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
933                             "Value: %s: no such instance", vb_type_name);
934                 }
935                 break;
936
937         case SNMP_ENDOFMIBVIEW:
938                 length = asn1->offset - start;
939                 if (snmp_tree) {
940                         proto_tree_add_text(snmp_tree, asn1->tvb, offset, length,
941                             "Value: %s: end of mib view", vb_type_name);
942                 }
943                 break;
944
945         default:
946                 g_assert_not_reached();
947                 return ASN1_ERR_WRONG_TYPE;
948         }
949         *lengthp = length;
950         return ASN1_ERR_NOERROR;
951 }
952
953 static void
954 dissect_common_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
955     proto_tree *tree, ASN1_SCK asn1, guint pdu_type, int start)
956 {
957         gboolean def;
958         guint length;
959         guint sequence_length;
960
961         guint32 request_id;
962
963         guint32 error_status;
964
965         guint32 error_index;
966
967         char *pdu_type_string;
968
969         subid_t *enterprise;
970         guint enterprise_length;
971
972         guint8 *agent_address;
973         guint agent_address_length;
974
975         guint32 trap_type;
976
977         guint32 specific_type;
978
979         guint timestamp;
980         guint timestamp_length;
981
982         gchar *oid_string;
983
984         guint variable_bindings_length;
985
986         int vb_index;
987         guint variable_length;
988         subid_t *variable_oid;
989         guint variable_oid_length;
990 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
991         gchar vb_oid_string[MAX_STRING_LEN]; /* TBC */
992 #endif
993         gboolean unsafe;
994
995         int ret;
996         guint cls, con, tag;
997
998         pdu_type_string = val_to_str(pdu_type, pdu_types,
999             "Unknown PDU type %#x");
1000         if (check_col(pinfo->fd, COL_INFO))
1001                 col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
1002         length = asn1.offset - start;
1003         if (tree) {
1004                 proto_tree_add_text(tree, tvb, offset, length,
1005                     "PDU type: %s", pdu_type_string);
1006         }
1007         offset += length;
1008
1009         /* get the fields in the PDU preceeding the variable-bindings sequence */
1010         switch (pdu_type) {
1011
1012         case SNMP_MSG_GET:
1013         case SNMP_MSG_GETNEXT:
1014         case SNMP_MSG_RESPONSE:
1015         case SNMP_MSG_SET:
1016         case SNMP_MSG_GETBULK:
1017         case SNMP_MSG_INFORM:
1018         case SNMP_MSG_TRAP2:
1019         case SNMP_MSG_REPORT:
1020                 /* request id */
1021                 ret = asn1_uint32_decode (&asn1, &request_id, &length);
1022                 if (ret != ASN1_ERR_NOERROR) {
1023                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1024                             "request ID", ret);
1025                         return;
1026                 }
1027                 if (tree) {
1028                         proto_tree_add_text(tree, tvb, offset, length,
1029                             "Request Id: %#x", request_id);
1030                 }
1031                 offset += length;
1032                 
1033                 /* error status, or getbulk non-repeaters */
1034                 ret = asn1_uint32_decode (&asn1, &error_status, &length);
1035                 if (ret != ASN1_ERR_NOERROR) {
1036                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1037                             (pdu_type == SNMP_MSG_GETBULK) ? "non-repeaters"
1038                                                            : "error status",
1039                             ret);
1040                         return;
1041                 }
1042                 if (tree) {
1043                         if (pdu_type == SNMP_MSG_GETBULK) {
1044                                 proto_tree_add_text(tree, tvb, offset,
1045                                     length, "Non-repeaters: %u", error_status);
1046                         } else {
1047                                 proto_tree_add_text(tree, tvb, offset,
1048                                     length, "Error Status: %s",
1049                                     val_to_str(error_status, error_statuses,
1050                                       "Unknown (%d)"));
1051                         }
1052                 }
1053                 offset += length;
1054
1055                 /* error index, or getbulk max-repetitions */
1056                 ret = asn1_uint32_decode (&asn1, &error_index, &length);
1057                 if (ret != ASN1_ERR_NOERROR) {
1058                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1059                             (pdu_type == SNMP_MSG_GETBULK) ? "max repetitions"
1060                                                            : "error index",
1061                             ret);
1062                         return;
1063                 }
1064                 if (tree) {
1065                         if (pdu_type == SNMP_MSG_GETBULK) {
1066                                 proto_tree_add_text(tree, tvb, offset,
1067                                     length, "Max repetitions: %u", error_index);
1068                         } else {
1069                                 proto_tree_add_text(tree, tvb, offset,
1070                                     length, "Error Index: %u", error_index);
1071                         }
1072                 }
1073                 offset += length;
1074                 break;
1075
1076         case SNMP_MSG_TRAP:
1077                 /* enterprise */
1078                 ret = asn1_oid_decode (&asn1, &enterprise, &enterprise_length,
1079                     &length);
1080                 if (ret != ASN1_ERR_NOERROR) {
1081                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1082                             "enterprise OID", ret);
1083                         return;
1084                 }
1085                 if (tree) {
1086                         oid_string = format_oid(enterprise, enterprise_length);
1087                         proto_tree_add_text(tree, tvb, offset, length,
1088                             "Enterprise: %s", oid_string);
1089                         g_free(oid_string);
1090                 }
1091                 g_free(enterprise);
1092                 offset += length;
1093
1094                 /* agent address */
1095                 start = asn1.offset;
1096                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1097                     &def, &agent_address_length);
1098                 if (ret != ASN1_ERR_NOERROR) {
1099                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1100                             "agent address", ret);
1101                         return;
1102                 }
1103                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) ||
1104                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) {
1105                         /* GXSNMP 0.0.15 says the latter is "needed for
1106                            Banyan" */
1107                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1108                             "agent_address", ASN1_ERR_WRONG_TYPE);
1109                         return;
1110                 }
1111                 if (agent_address_length != 4) {
1112                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1113                             "agent_address", ASN1_ERR_WRONG_LENGTH_FOR_TYPE);
1114                         return;
1115                 }
1116                 ret = asn1_string_value_decode (&asn1,
1117                     agent_address_length, &agent_address);
1118                 if (ret != ASN1_ERR_NOERROR) {
1119                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1120                             "agent address", ret);
1121                         return;
1122                 }
1123                 length = asn1.offset - start;
1124                 if (tree) {
1125                         if (agent_address_length != 4) {
1126                                 proto_tree_add_text(tree, tvb, offset,
1127                                     length,
1128                                     "Agent address: <length is %u, not 4>",
1129                                     agent_address_length);
1130                         } else {
1131                                 proto_tree_add_text(tree, tvb, offset,
1132                                     length,
1133                                     "Agent address: %s",
1134                                     ip_to_str(agent_address));
1135                         }
1136                 }
1137                 g_free(agent_address);
1138                 offset += length;
1139                 
1140                 /* generic trap type */
1141                 ret = asn1_uint32_decode (&asn1, &trap_type, &length);
1142                 if (ret != ASN1_ERR_NOERROR) {
1143                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1144                             "generic trap type", ret);
1145                         return;
1146                 }
1147                 if (tree) {
1148                         proto_tree_add_text(tree, tvb, offset, length,
1149                             "Trap type: %s",
1150                             val_to_str(trap_type, trap_types, "Unknown (%u)"));
1151                 }               
1152                 offset += length;
1153                 
1154                 /* specific trap type */
1155                 ret = asn1_uint32_decode (&asn1, &specific_type, &length);
1156                 if (ret != ASN1_ERR_NOERROR) {
1157                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1158                             "specific trap type", ret);
1159                         return;
1160                 }
1161                 if (tree) {
1162                         proto_tree_add_text(tree, tvb, offset, length,
1163                             "Specific trap type: %u (%#x)",
1164                             specific_type, specific_type);
1165                 }               
1166                 offset += length;
1167                 
1168                 /* timestamp */
1169                 start = asn1.offset;
1170                 ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1171                     &def, &timestamp_length);
1172                 if (ret != ASN1_ERR_NOERROR) {
1173                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1174                             "timestamp", ret);
1175                         return;
1176                 }
1177                 if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) ||
1178                     (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) {
1179                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1180                             "timestamp", ASN1_ERR_WRONG_TYPE);
1181                         return;
1182                 }
1183                 ret = asn1_uint32_value_decode(&asn1, timestamp_length,
1184                     &timestamp);
1185                 if (ret != ASN1_ERR_NOERROR) {
1186                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1187                             "timestamp", ret);
1188                         return;
1189                 }
1190                 length = asn1.offset - start;
1191                 if (tree) {
1192                         proto_tree_add_text(tree, tvb, offset, length,
1193                             "Timestamp: %u", timestamp);
1194                 }               
1195                 offset += length;
1196                 break;
1197         }
1198
1199         /* variable bindings */
1200         /* get header for variable-bindings sequence */
1201         ret = asn1_sequence_decode(&asn1, &variable_bindings_length, &length);
1202         if (ret != ASN1_ERR_NOERROR) {
1203                 dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1204                         "variable bindings header", ret);
1205                 return;
1206         }
1207         offset += length;
1208
1209         /* loop on variable bindings */
1210         vb_index = 0;
1211         while (variable_bindings_length > 0) {
1212                 vb_index++;
1213                 sequence_length = 0;
1214
1215                 /* parse type */
1216                 ret = asn1_sequence_decode(&asn1, &variable_length, &length);
1217                 if (ret != ASN1_ERR_NOERROR) {
1218                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1219                                 "variable binding header", ret);
1220                         return;
1221                 }
1222                 sequence_length += length;
1223
1224                 /* parse object identifier */
1225                 ret = asn1_oid_decode (&asn1, &variable_oid,
1226                     &variable_oid_length, &length);
1227                 if (ret != ASN1_ERR_NOERROR) {
1228                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1229                             "variable binding OID", ret);
1230                         return;
1231                 }
1232                 sequence_length += length;
1233
1234                 unsafe = FALSE;
1235                 if (tree) {
1236                         oid_string = format_oid(variable_oid,
1237                             variable_oid_length);
1238                         
1239 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
1240                         sprint_objid(vb_oid_string, variable_oid,
1241                             variable_oid_length);
1242                         proto_tree_add_text(tree, tvb, offset, sequence_length,
1243                             "Object identifier %d: %s (%s)", vb_index,
1244                             oid_string, vb_oid_string);
1245 #ifdef HAVE_SNMP_SNMP_H
1246                         /*
1247                          * CMU SNMP has a bug wherein "sprint_value()"
1248                          * calls "get_symbol()", passing it the
1249                          * OID supplied, to get an information about the
1250                          * variable, and blithely assumes that it will
1251                          * never get a null pointer back and dereferences
1252                          * the resulting pointer.
1253                          *
1254                          * Not true.  If there's nothing in the MIB
1255                          * about *any* of the components of the OID,
1256                          * it'll return a null pointer.
1257                          *
1258                          * So we have to check for that, and pass
1259                          * down to "snmp_variable_decode" a flag
1260                          * saying "don't pass this to 'sprint_value()'.
1261                          *
1262                          * We check for that by looking for a decoded
1263                          * OID string beginning with "." followed by a
1264                          * digit, meaning it couldn't even find any
1265                          * symbolic representation for the very
1266                          * beginning of the OID string.
1267                          */
1268                         if (vb_oid_string[0] == '.' &&
1269                             isdigit((guchar)vb_oid_string[1]))
1270                                 unsafe = TRUE;
1271 #endif /* HAVE_SNMP_SNMP_H */
1272 #else /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1273                         proto_tree_add_text(tree, tvb, offset, sequence_length,
1274                             "Object identifier %d: %s", vb_index,
1275                             oid_string);
1276 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
1277                         g_free(oid_string);
1278                 }
1279                 offset += sequence_length;
1280                 variable_bindings_length -= sequence_length;
1281                                 
1282                 /* Parse the variable's value */
1283                 ret = snmp_variable_decode(tree, variable_oid,
1284                     variable_oid_length, &asn1, offset, &length,
1285                     unsafe);
1286                 if (ret != ASN1_ERR_NOERROR) {
1287                         dissect_snmp_parse_error(tvb, offset, pinfo, tree,
1288                             "variable", ret);
1289                         return;
1290                 }
1291                 offset += length;
1292                 variable_bindings_length -= length;
1293         }
1294 }
1295
1296 static const value_string qos_vals[] = {
1297         { 0x0,  "No authentication or privacy" },
1298         { 0x1,  "Authentication, no privacy" },
1299         { 0x2,  "Authentication and privacy" },
1300         { 0x3,  "Authentication and privacy" },
1301         { 0,    NULL },
1302 };
1303
1304 static void
1305 dissect_snmp2u_parameters(proto_tree *tree, tvbuff_t *tvb, int offset, int length,
1306     guchar *parameters, int parameters_length)
1307 {
1308         proto_item *item;
1309         proto_tree *parameters_tree;
1310         proto_tree *qos_tree;
1311         guint8 model;
1312         guint8 qos;
1313         guint8 len;
1314
1315         item = proto_tree_add_text(tree, tvb, offset, length,
1316             "Parameters");
1317         parameters_tree = proto_item_add_subtree(item, ett_parameters);
1318         offset += length - parameters_length;
1319
1320         if (parameters_length < 1)
1321                 return;
1322         model = *parameters;
1323         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1324             "model: %u", model);
1325         offset += 1;
1326         parameters += 1;
1327         parameters_length -= 1;
1328         if (model != 1) {
1329                 /* Unknown model. */
1330                 proto_tree_add_text(parameters_tree, tvb, offset,
1331                     parameters_length, "parameters: %s",
1332                     bytes_to_str(parameters, parameters_length));
1333                 return;
1334         }
1335
1336         if (parameters_length < 1)
1337                 return;
1338         qos = *parameters;
1339         item = proto_tree_add_text(parameters_tree, tvb, offset, 1,
1340             "qoS: 0x%x", qos);
1341         qos_tree = proto_item_add_subtree(item, ett_parameters_qos);
1342         proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1343             decode_boolean_bitfield(qos, 0x04,
1344                 8, "Generation of report PDU allowed",
1345                    "Generation of report PDU not allowed"));
1346         proto_tree_add_text(qos_tree, tvb, offset, 1, "%s",
1347             decode_enumerated_bitfield(qos, 0x03,
1348                 8, qos_vals, "%s"));
1349         offset += 1;
1350         parameters += 1;
1351         parameters_length -= 1;
1352
1353         if (parameters_length < 12)
1354                 return;
1355         proto_tree_add_text(parameters_tree, tvb, offset, 12,
1356             "agentID: %s", bytes_to_str(parameters, 12));
1357         offset += 12;
1358         parameters += 12;
1359         parameters_length -= 12;
1360
1361         if (parameters_length < 4)
1362                 return;
1363         proto_tree_add_text(parameters_tree, tvb, offset, 4,
1364             "agentBoots: %u", pntohl(parameters));
1365         offset += 4;
1366         parameters += 4;
1367         parameters_length -= 4;
1368
1369         if (parameters_length < 4)
1370                 return;
1371         proto_tree_add_text(parameters_tree, tvb, offset, 4,
1372             "agentTime: %u", pntohl(parameters));
1373         offset += 4;
1374         parameters += 4;
1375         parameters_length -= 4;
1376
1377         if (parameters_length < 2)
1378                 return;
1379         proto_tree_add_text(parameters_tree, tvb, offset, 2,
1380             "maxSize: %u", pntohs(parameters));
1381         offset += 2;
1382         parameters += 2;
1383         parameters_length -= 2;
1384
1385         if (parameters_length < 1)
1386                 return;
1387         len = *parameters;
1388         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1389             "userLen: %u", len);
1390         offset += 1;
1391         parameters += 1;
1392         parameters_length -= 1;
1393
1394         if (parameters_length < len)
1395                 return;
1396         proto_tree_add_text(parameters_tree, tvb, offset, len,
1397             "userName: %.*s", len, parameters);
1398         offset += len;
1399         parameters += len;
1400         parameters_length -= len;
1401
1402         if (parameters_length < 1)
1403                 return;
1404         len = *parameters;
1405         proto_tree_add_text(parameters_tree, tvb, offset, 1,
1406             "authLen: %u", len);
1407         offset += 1;
1408         parameters += 1;
1409         parameters_length -= 1;
1410
1411         if (parameters_length < len)
1412                 return;
1413         proto_tree_add_text(parameters_tree, tvb, offset, len,
1414             "authDigest: %s", bytes_to_str(parameters, len));
1415         offset += len;
1416         parameters += len;
1417         parameters_length -= len;
1418
1419         if (parameters_length < 1)
1420                 return;
1421         proto_tree_add_text(parameters_tree, tvb, offset, parameters_length,
1422             "contextSelector: %s", bytes_to_str(parameters, parameters_length));
1423 }
1424
1425 void
1426 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1427     proto_tree *tree, char *proto_name, int proto, gint ett)
1428 {
1429         ASN1_SCK asn1;
1430         int start;
1431         gboolean def;
1432         gboolean encrypted;
1433         guint length;
1434         guint message_length;
1435         guint global_length;
1436
1437         guint32 version;
1438         guint32 msgid;
1439         guint32 msgmax;
1440         guint32 msgsec;
1441         guint32 engineboots;
1442         guint32 enginetime;
1443
1444         guchar *msgflags;
1445         guchar *community;
1446         guchar *secparm;
1447         guchar *cengineid;
1448         guchar *cname;
1449         guchar *cryptpdu;
1450         guchar *aengineid;
1451         guchar *username;
1452         guchar *authpar;
1453         guchar *privpar;
1454         int msgflags_length;
1455         int community_length;
1456         int secparm_length;
1457         int cengineid_length;
1458         int cname_length;
1459         int cryptpdu_length;
1460         int aengineid_length;
1461         int username_length;
1462         int authpar_length;
1463         int privpar_length;
1464
1465         guint pdu_type;
1466         guint pdu_length;
1467
1468         proto_tree *snmp_tree = NULL;
1469         proto_tree *global_tree = NULL;
1470         proto_tree *flags_tree = NULL;
1471         proto_tree *secur_tree = NULL;
1472         proto_item *item = NULL;
1473         int ret;
1474         guint cls, con, tag;
1475
1476         if (check_col(pinfo->fd, COL_PROTOCOL))
1477                 col_add_str(pinfo->fd, COL_PROTOCOL, proto_name);
1478
1479         if (tree) {
1480                 item = proto_tree_add_item(tree, proto, tvb, offset,
1481                     tvb_length_remaining(tvb, offset), FALSE);
1482                 snmp_tree = proto_item_add_subtree(item, ett);
1483         }
1484
1485         /* NOTE: we have to parse the message piece by piece, since the
1486          * capture length may be less than the message length: a 'global'
1487          * parsing is likely to fail.
1488          */
1489         /* parse the SNMP header */
1490         asn1_open(&asn1, tvb, offset);
1491         ret = asn1_sequence_decode(&asn1, &message_length, &length);
1492         if (ret != ASN1_ERR_NOERROR) {
1493                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1494                         "message header", ret);
1495                 return;
1496         }
1497         offset += length;
1498
1499         ret = asn1_uint32_decode (&asn1, &version, &length);
1500         if (ret != ASN1_ERR_NOERROR) {
1501                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1502                     "version number", ret);
1503                 return;
1504         }
1505         if (snmp_tree) {
1506                 proto_tree_add_text(snmp_tree, tvb, offset, length,
1507                     "Version: %s",
1508                     val_to_str(version, versions, "Unknown version %#x"));
1509         }
1510         offset += length;
1511
1512
1513         switch (version) {
1514         case SNMP_VERSION_1:
1515         case SNMP_VERSION_2c:
1516                 ret = asn1_octet_string_decode (&asn1, &community, 
1517                     &community_length, &length);
1518                 if (ret != ASN1_ERR_NOERROR) {
1519                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1520                             "community", ret);
1521                         return;
1522                 }
1523                 if (tree) {
1524                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1525                             "Community: %.*s", community_length,
1526                             SAFE_STRING(community));
1527                 }
1528                 g_free(community);
1529                 offset += length;
1530                 break;
1531         case SNMP_VERSION_2u:
1532                 ret = asn1_octet_string_decode (&asn1, &community, 
1533                     &community_length, &length);
1534                 if (tree) {
1535                         dissect_snmp2u_parameters(snmp_tree, tvb, offset, length,
1536                             community, community_length);
1537                 }
1538                 g_free(community);
1539                 offset += length;
1540                 break;
1541         case SNMP_VERSION_3:
1542                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1543                 if (ret != ASN1_ERR_NOERROR) {
1544                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1545                                 "message global header", ret);
1546                         return;
1547                 }
1548                 if (snmp_tree) {
1549                         item = proto_tree_add_text(snmp_tree, tvb, offset,
1550                             global_length + length, "Message Global Header");
1551                         global_tree = proto_item_add_subtree(item, ett_global);
1552                         proto_tree_add_text(global_tree, tvb, offset,
1553                             length,
1554                             "Message Global Header Length: %d", global_length);
1555                 }
1556                 offset += length;
1557                 ret = asn1_uint32_decode (&asn1, &msgid, &length);
1558                 if (ret != ASN1_ERR_NOERROR) {
1559                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1560                             "message id", ret);
1561                         return;
1562                 }
1563                 if (global_tree) {
1564                         proto_tree_add_text(global_tree, tvb, offset,
1565                             length, "Message ID: %d", msgid);
1566                 }
1567                 offset += length;
1568                 ret = asn1_uint32_decode (&asn1, &msgmax, &length);
1569                 if (ret != ASN1_ERR_NOERROR) {
1570                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1571                             "message max size", ret);
1572                         return;
1573                 }
1574                 if (global_tree) {
1575                         proto_tree_add_text(global_tree, tvb, offset,
1576                             length, "Message Max Size: %d", msgmax);
1577                 }
1578                 offset += length;
1579                 ret = asn1_octet_string_decode (&asn1, &msgflags, 
1580                     &msgflags_length, &length);
1581                 if (ret != ASN1_ERR_NOERROR) {
1582                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1583                             "message flags", ret);
1584                         return;
1585                 }
1586                 if (msgflags_length != 1) {
1587                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1588                             "message flags wrong length", ret);
1589                         g_free(msgflags);
1590                         return;
1591                 }
1592                 if (global_tree) {
1593                         item = proto_tree_add_uint_format(global_tree,
1594                             hf_snmpv3_flags, tvb, offset, length,
1595                             msgflags[0], "Flags: 0x%02x", msgflags[0]);
1596                         flags_tree = proto_item_add_subtree(item, ett_flags);
1597                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_report,
1598                             tvb, offset, length, msgflags[0]);
1599                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_crypt,
1600                             tvb, offset, length, msgflags[0]);
1601                         proto_tree_add_boolean(flags_tree, hf_snmpv3_flags_auth,
1602                             tvb, offset, length, msgflags[0]);
1603                 }
1604                 encrypted = msgflags[0] & TH_CRYPT;
1605                 g_free(msgflags);
1606                 offset += length;
1607                 ret = asn1_uint32_decode (&asn1, &msgsec, &length);
1608                 if (ret != ASN1_ERR_NOERROR) {
1609                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1610                             "message security model", ret);
1611                         return;
1612                 }
1613                 if (global_tree) {
1614                         proto_tree_add_text(global_tree, tvb, offset,
1615                             length, "Message Security Model: %s",
1616                             val_to_str(msgsec, sec_models,
1617                             "Unknown model %#x"));
1618                 }
1619                 offset += length;
1620                 switch(msgsec) {
1621                 case SNMP_SEC_USM:
1622                         start = asn1.offset;
1623                         ret = asn1_header_decode (&asn1, &cls, &con, &tag,
1624                             &def, &secparm_length);
1625                         length = asn1.offset - start;
1626                         if (cls != ASN1_UNI && con != ASN1_PRI && 
1627                             tag != ASN1_OTS) {
1628                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1629                                     snmp_tree, "Message Security Parameters",
1630                                     ASN1_ERR_WRONG_TYPE);
1631                                 return;
1632                         }
1633                         if (snmp_tree) {
1634                                 item = proto_tree_add_text(snmp_tree, tvb,
1635                                     offset, secparm_length + length,
1636                                     "Message Security Parameters");
1637                                 secur_tree = proto_item_add_subtree(item,
1638                                     ett_secur);
1639                                 proto_tree_add_text(secur_tree, tvb, offset,
1640                                     length, 
1641                                     "Message Security Parameters Length: %d",
1642                                     secparm_length);
1643                         }
1644                         offset += length;
1645                         ret = asn1_sequence_decode(&asn1, &secparm_length,
1646                             &length);
1647                         if (ret != ASN1_ERR_NOERROR) {
1648                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1649                                     snmp_tree, "USM sequence header", ret);
1650                                 return;
1651                         }
1652                         offset += length;
1653                         ret = asn1_octet_string_decode (&asn1, &aengineid, 
1654                             &aengineid_length, &length);
1655                         if (ret != ASN1_ERR_NOERROR) {
1656                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1657                                     snmp_tree, "authoritative engine id", ret);
1658                                 return;
1659                         }
1660                         if (secur_tree) {
1661                                 proto_tree_add_text(secur_tree, tvb, offset,
1662                                     length, "Authoritative Engine ID: %s",
1663                                     bytes_to_str(aengineid, aengineid_length));
1664                         }
1665                         g_free(aengineid);
1666                         offset += length;
1667                         ret = asn1_uint32_decode (&asn1, &engineboots, &length);
1668                         if (ret != ASN1_ERR_NOERROR) {
1669                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1670                                     snmp_tree, "engine boots", ret);
1671                                 return;
1672                         }
1673                         if (secur_tree) {
1674                                 proto_tree_add_text(secur_tree, tvb,
1675                                     offset, length, "Engine Boots: %d", 
1676                                     engineboots);
1677                         }
1678                         offset += length;
1679                         ret = asn1_uint32_decode (&asn1, &enginetime, &length);
1680                         if (ret != ASN1_ERR_NOERROR) {
1681                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1682                                     snmp_tree,  "engine time", ret);
1683                                 return;
1684                         }
1685                         if (secur_tree) {
1686                                 proto_tree_add_text(secur_tree, tvb,
1687                                     offset, length, "Engine Time: %d", 
1688                                     enginetime);
1689                         }
1690                         offset += length;
1691                         ret = asn1_octet_string_decode (&asn1, &username, 
1692                             &username_length, &length);
1693                         if (ret != ASN1_ERR_NOERROR) {
1694                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1695                                     snmp_tree, "user name", ret);
1696                                 return;
1697                         }
1698                         if (secur_tree) {
1699                                 proto_tree_add_text(secur_tree, tvb, offset,
1700                                     length, "User Name: %.*s", 
1701                                     username_length,
1702                                     SAFE_STRING(username));
1703                         }
1704                         g_free(username);
1705                         offset += length;
1706                         ret = asn1_octet_string_decode (&asn1, &authpar, 
1707                             &authpar_length, &length);
1708                         if (ret != ASN1_ERR_NOERROR) {
1709                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1710                                     snmp_tree, "authentication parameter", ret);
1711                                 return;
1712                         }
1713                         if (secur_tree) {
1714                                 proto_tree_add_text(secur_tree, tvb, offset,
1715                                     length, "Authentication Parameter: %s",
1716                                     bytes_to_str(authpar, authpar_length));
1717                         }
1718                         g_free(authpar);
1719                         offset += length;
1720                         ret = asn1_octet_string_decode (&asn1, &privpar, 
1721                             &privpar_length, &length);
1722                         if (ret != ASN1_ERR_NOERROR) {
1723                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1724                                     snmp_tree, "privacy parameter", ret);
1725                                 return;
1726                         }
1727                         if (secur_tree) {
1728                                 proto_tree_add_text(secur_tree, tvb, offset,
1729                                     length, "Privacy Parameter: %s",
1730                                     bytes_to_str(privpar, privpar_length));
1731                         }
1732                         g_free(privpar);
1733                         offset += length;
1734                         break;
1735                 default:
1736                         ret = asn1_octet_string_decode (&asn1, 
1737                             &secparm, &secparm_length, &length);
1738                         if (ret != ASN1_ERR_NOERROR) {
1739                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1740                                     snmp_tree, "Message Security Parameters",
1741                                     ret);
1742                                 return;
1743                         }
1744                         if (snmp_tree) {
1745                                 proto_tree_add_text(snmp_tree, tvb, offset,
1746                                     length,
1747                                     "Message Security Parameters Data"
1748                                     " (%d bytes)", secparm_length);
1749                         }
1750                         g_free(secparm);
1751                         offset += length;
1752                         break;
1753                 }
1754                 /* PDU starts here */
1755                 if (encrypted) {
1756                         ret = asn1_octet_string_decode (&asn1, &cryptpdu,
1757                             &cryptpdu_length, &length);
1758                         if (ret != ASN1_ERR_NOERROR) {
1759                                 dissect_snmp_parse_error(tvb, offset, pinfo,
1760                                     snmp_tree, "encrypted PDU header", ret);
1761                                 return;
1762                         }
1763                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1764                             "Encrypted PDU (%d bytes)", length);
1765                         g_free(cryptpdu);
1766                         if (check_col(pinfo->fd, COL_INFO))
1767                                 col_set_str(pinfo->fd, COL_INFO, "Encrypted PDU");
1768                         return;
1769                 }
1770                 ret = asn1_sequence_decode(&asn1, &global_length, &length);
1771                 if (ret != ASN1_ERR_NOERROR) {
1772                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1773                                 "PDU header", ret);
1774                         return;
1775                 }
1776                 offset += length;
1777                 ret = asn1_octet_string_decode (&asn1, &cengineid, 
1778                     &cengineid_length, &length);
1779                 if (ret != ASN1_ERR_NOERROR) {
1780                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1781                             "context engine id", ret);
1782                         return;
1783                 }
1784                 if (snmp_tree) {
1785                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1786                             "Context Engine ID: %s",
1787                             bytes_to_str(cengineid, cengineid_length));
1788                 }
1789                 g_free(cengineid);
1790                 offset += length;
1791                 ret = asn1_octet_string_decode (&asn1, &cname, 
1792                     &cname_length, &length);
1793                 if (ret != ASN1_ERR_NOERROR) {
1794                         dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree, 
1795                             "context name", ret);
1796                         return;
1797                 }
1798                 if (snmp_tree) {
1799                         proto_tree_add_text(snmp_tree, tvb, offset, length,
1800                             "Context Name: %.*s", cname_length,
1801                             SAFE_STRING(cname));
1802                 }
1803                 g_free(cname);
1804                 offset += length;
1805                 break;
1806         default:
1807                 dissect_snmp_error(tvb, offset, pinfo, snmp_tree,
1808                     "PDU for unknown version of SNMP");
1809                 return;
1810         }
1811
1812         start = asn1.offset;
1813         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1814             &pdu_length);
1815         if (ret != ASN1_ERR_NOERROR) {
1816                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1817                     "PDU type", ret);
1818                 return;
1819         }
1820         if (cls != ASN1_CTX || con != ASN1_CON) {
1821                 dissect_snmp_parse_error(tvb, offset, pinfo, snmp_tree,
1822                     "PDU type", ASN1_ERR_WRONG_TYPE);
1823                 return;
1824         }
1825         dissect_common_pdu(tvb, offset, pinfo, snmp_tree, asn1, pdu_type, start);
1826 }
1827
1828 static void
1829 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1830     proto_tree *tree, int proto, gint ett)
1831 {
1832         ASN1_SCK asn1;
1833         int start;
1834         gboolean def;
1835         guint length;
1836
1837         guint pdu_type;
1838         char *pdu_type_string;
1839         guint pdu_length;
1840
1841         guint32 version;
1842         guint32 cause;
1843         guint32 priority;
1844         guint32 operation;
1845         guint32 commit;
1846
1847         guchar *password;
1848         int password_length;
1849
1850         guchar *application;
1851         int application_length;
1852
1853         subid_t *regid;
1854         guint regid_length;
1855
1856         gchar *oid_string;
1857
1858         proto_tree *smux_tree = NULL;
1859         proto_item *item = NULL;
1860         int ret;
1861         guint cls, con;
1862
1863         if (check_col(pinfo->fd, COL_PROTOCOL))
1864                 col_set_str(pinfo->fd, COL_PROTOCOL, "SMUX");
1865
1866         if (tree) {
1867                 item = proto_tree_add_item(tree, proto, tvb, offset,
1868                     tvb_length_remaining(tvb, offset), FALSE);
1869                 smux_tree = proto_item_add_subtree(item, ett);
1870         }
1871
1872         /* NOTE: we have to parse the message piece by piece, since the
1873          * capture length may be less than the message length: a 'global'
1874          * parsing is likely to fail.
1875          */
1876         /* parse the SNMP header */
1877         asn1_open(&asn1, tvb, offset);
1878         start = asn1.offset;
1879         ret = asn1_header_decode (&asn1, &cls, &con, &pdu_type, &def,
1880             &pdu_length);
1881         if (ret != ASN1_ERR_NOERROR) {
1882                 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1883                     "PDU type", ret);
1884                 return;
1885         }
1886
1887         /* Dissect SMUX here */
1888         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_OPEN) {
1889                 pdu_type_string = val_to_str(pdu_type, smux_types,
1890                     "Unknown PDU type %#x");
1891                 if (check_col(pinfo->fd, COL_INFO))
1892                         col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
1893                 length = asn1.offset - start;
1894                 if (tree) {
1895                         proto_tree_add_text(smux_tree, tvb, offset, length,
1896                             "PDU type: %s", pdu_type_string);
1897                 }
1898                 offset += length;
1899                 ret = asn1_uint32_decode (&asn1, &version, &length);
1900                 if (ret != ASN1_ERR_NOERROR) {
1901                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1902                             "version", ret);
1903                         return;
1904                 }
1905                 if (tree) {
1906                         proto_tree_add_text(smux_tree, tvb, offset, length,
1907                             "Version: %d", version);
1908                 }
1909                 offset += length;
1910
1911                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
1912                 if (ret != ASN1_ERR_NOERROR) {
1913                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1914                             "registration OID", ret);
1915                         return;
1916                 }
1917                 if (tree) {
1918                         oid_string = format_oid(regid, regid_length);
1919                         proto_tree_add_text(smux_tree, tvb, offset, length,
1920                             "Registration: %s", oid_string);
1921                         g_free(oid_string);
1922                 }
1923                 g_free(regid);
1924                 offset += length;
1925
1926                 ret = asn1_octet_string_decode (&asn1, &application, 
1927                     &application_length, &length);
1928                 if (ret != ASN1_ERR_NOERROR) {
1929                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
1930                             "application", ret);
1931                         return;
1932                 }
1933                 if (tree) {
1934                         proto_tree_add_text(smux_tree, tvb, offset, length,
1935                             "Application: %.*s", application_length,
1936                              SAFE_STRING(application));
1937                 }
1938                 g_free(application);
1939                 offset += length;
1940
1941                 ret = asn1_octet_string_decode (&asn1, &password, 
1942                     &password_length, &length);
1943                 if (ret != ASN1_ERR_NOERROR) {
1944                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree, 
1945                             "password", ret);
1946                         return;
1947                 }
1948                 if (tree) {
1949                         proto_tree_add_text(smux_tree, tvb, offset, length,
1950                             "Password: %.*s", password_length,
1951                             SAFE_STRING(password));
1952                 }
1953                 g_free(password);
1954                 offset += length;
1955                 return;
1956         }
1957         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_CLOSE) {
1958                 pdu_type_string = val_to_str(pdu_type, smux_types,
1959                     "Unknown PDU type %#x");
1960                 if (check_col(pinfo->fd, COL_INFO))
1961                         col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
1962                 length = asn1.offset - start;
1963                 if (tree) {
1964                         proto_tree_add_text(smux_tree, tvb, offset, length,
1965                             "PDU type: %s", pdu_type_string);
1966                 }
1967                 offset += length;
1968                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &cause);
1969                 if (ret != ASN1_ERR_NOERROR) {
1970                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1971                             "cause", ret);
1972                         return;
1973                 }
1974                 if (tree) {
1975                         proto_tree_add_text(smux_tree, tvb, offset,
1976                             pdu_length, "Cause: %s",
1977                             val_to_str(cause, smux_close, 
1978                                 "Unknown cause %#x"));
1979                 }
1980                 offset += pdu_length;
1981                 return;
1982         }
1983         if (cls == ASN1_APL && con == ASN1_CON && pdu_type == SMUX_MSG_RREQ) {
1984                 pdu_type_string = val_to_str(pdu_type, smux_types,
1985                     "Unknown PDU type %#x");
1986                 if (check_col(pinfo->fd, COL_INFO))
1987                         col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
1988                 length = asn1.offset - start;
1989                 if (tree) {
1990                         proto_tree_add_text(smux_tree, tvb, offset, length,
1991                             "PDU type: %s", pdu_type_string);
1992                 }
1993                 offset += length;
1994                 ret = asn1_oid_decode (&asn1, &regid, &regid_length, &length);
1995                 if (ret != ASN1_ERR_NOERROR) {
1996                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
1997                             "registration subtree", ret);
1998                         return;
1999                 }
2000                 if (tree) {
2001                         oid_string = format_oid(regid, regid_length);
2002                         proto_tree_add_text(smux_tree, tvb, offset, length,
2003                             "Registration: %s", oid_string);
2004                         g_free(oid_string);
2005                 }
2006                 g_free(regid);
2007                 offset += length;
2008
2009                 ret = asn1_uint32_decode (&asn1, &priority, &length);
2010                 if (ret != ASN1_ERR_NOERROR) {
2011                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2012                             "priority", ret);
2013                         return;
2014                 }
2015                 if (tree) {
2016                         proto_tree_add_text(smux_tree, tvb, offset, length,
2017                             "Priority: %d", priority);
2018                 }
2019                 offset += length;
2020
2021                 ret = asn1_uint32_decode (&asn1, &operation, &length);
2022                 if (ret != ASN1_ERR_NOERROR) {
2023                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2024                             "operation", ret);
2025                         return;
2026                 }
2027                 if (tree) {
2028                         proto_tree_add_text(smux_tree, tvb, offset, length,
2029                             "Operation: %s", 
2030                             val_to_str(operation, smux_rreq, 
2031                                 "Unknown operation %#x"));
2032                 }
2033                 offset += length;
2034                 return;
2035         }
2036         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_RRSP) {
2037                 pdu_type_string = val_to_str(pdu_type, smux_types,
2038                     "Unknown PDU type %#x");
2039                 if (check_col(pinfo->fd, COL_INFO))
2040                         col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
2041                 length = asn1.offset - start;
2042                 if (tree) {
2043                         proto_tree_add_text(smux_tree, tvb, offset, length,
2044                             "PDU type: %s", pdu_type_string);
2045                 }
2046                 offset += length;
2047                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &priority);
2048                 if (ret != ASN1_ERR_NOERROR) {
2049                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2050                             "priority", ret);
2051                         return;
2052                 }
2053                 if (tree) {
2054                         proto_tree_add_text(smux_tree, tvb, offset,
2055                             pdu_length, "%s",
2056                             val_to_str(priority, smux_prio, 
2057                                 "Priority: %#x"));
2058                 }
2059                 offset += pdu_length;
2060                 return;
2061         }
2062         if (cls == ASN1_APL && con == ASN1_PRI && pdu_type == SMUX_MSG_SOUT) {
2063                 pdu_type_string = val_to_str(pdu_type, smux_types,
2064                     "Unknown PDU type %#x");
2065                 if (check_col(pinfo->fd, COL_INFO))
2066                         col_add_str(pinfo->fd, COL_INFO, pdu_type_string);
2067                 length = asn1.offset - start;
2068                 if (tree) {
2069                         proto_tree_add_text(smux_tree, tvb, offset, length,
2070                             "PDU type: %s", pdu_type_string);
2071                 }
2072                 offset += length;
2073                 ret = asn1_uint32_value_decode (&asn1, pdu_length, &commit);
2074                 if (ret != ASN1_ERR_NOERROR) {
2075                         dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2076                             "commit", ret);
2077                         return;
2078                 }
2079                 if (tree) {
2080                         proto_tree_add_text(smux_tree, tvb, offset,
2081                             pdu_length, "%s",
2082                             val_to_str(commit, smux_sout, 
2083                                 "Unknown SOUT Value: %#x"));
2084                 }
2085                 offset += pdu_length;
2086                 return;
2087         }
2088         if (cls != ASN1_CTX || con != ASN1_CON) {
2089                 dissect_snmp_parse_error(tvb, offset, pinfo, smux_tree,
2090                     "PDU type", ASN1_ERR_WRONG_TYPE);
2091                 return;
2092         }
2093         dissect_common_pdu(tvb, offset, pinfo, smux_tree, asn1, pdu_type, start);
2094 }
2095
2096 static void
2097 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
2098 {
2099         conversation_t  *conversation;
2100
2101         /*
2102          * XXX - this is a conversation dissector, and the code to
2103          * call a conversation dissector doesn't check for disabled
2104          * protocols or set "pinfo->current_proto".
2105          */
2106         CHECK_DISPLAY_AS_DATA(proto_snmp, tvb, pinfo, tree);
2107
2108         pinfo->current_proto = "SNMP";
2109
2110         /*
2111          * The first SNMP packet goes to the SNMP port; the second one
2112          * may come from some *other* port, but goes back to the same
2113          * IP address and port as the ones from which the first packet
2114          * came; all subsequent packets presumably go between those two
2115          * IP addresses and ports.
2116          *
2117          * If this packet went to the SNMP port, we check to see if
2118          * there's already a conversation with one address/port pair
2119          * matching the source IP address and port of this packet,
2120          * the other address matching the destination IP address of this
2121          * packet, and any destination port.
2122          *
2123          * If not, we create one, with its address 1/port 1 pair being
2124          * the source address/port of this packet, its address 2 being
2125          * the destination address of this packet, and its port 2 being
2126          * wildcarded, and give it the SNMP dissector as a dissector.
2127          */
2128         if (pinfo->destport == UDP_PORT_SNMP) {
2129           conversation = find_conversation(&pinfo->src, &pinfo->dst, PT_UDP,
2130                                            pinfo->srcport, 0, NO_PORT_B);
2131           if (conversation == NULL) {
2132             conversation = conversation_new(&pinfo->src, &pinfo->dst, PT_UDP,
2133                                             pinfo->srcport, 0, NULL,
2134                                             NO_PORT2);
2135             conversation_set_dissector(conversation, dissect_snmp);
2136           }
2137         }
2138
2139         dissect_snmp_pdu(tvb, 0, pinfo, tree, "SNMP", proto_snmp, ett_snmp);
2140 }
2141
2142 static void
2143 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) 
2144 {
2145         dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
2146 }
2147
2148 void
2149 proto_register_snmp(void)
2150 {
2151 #if defined(HAVE_UCD_SNMP_SNMP_H) && defined(linux)
2152         void *libsnmp_handle;
2153         int (*snmp_set_suffix_only_p)(int);
2154         int (*ds_set_int_p)(int, int, int);
2155 #endif
2156
2157         static hf_register_info hf[] = {
2158                 { &hf_snmpv3_flags,
2159                 { "SNMPv3 Flags", "snmpv3.flags", FT_UINT8, BASE_HEX, NULL,
2160                     0x0, "", HFILL }},
2161                 { &hf_snmpv3_flags_auth,
2162                 { "Authenticated", "snmpv3.flags.auth", FT_BOOLEAN, 8,
2163                     TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
2164                 { &hf_snmpv3_flags_crypt,
2165                 { "Encrypted", "snmpv3.flags.crypt", FT_BOOLEAN, 8,
2166                     TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
2167                 { &hf_snmpv3_flags_report,
2168                 { "Reportable", "snmpv3.flags.report", FT_BOOLEAN, 8,
2169                     TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
2170         };
2171         static gint *ett[] = {
2172                 &ett_snmp,
2173                 &ett_smux,
2174                 &ett_parameters,
2175                 &ett_parameters_qos,
2176                 &ett_global,
2177                 &ett_flags,
2178                 &ett_secur,
2179         };
2180
2181 #if defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H)
2182         /* UCD or CMU SNMP */
2183         init_mib();
2184 #ifdef HAVE_UCD_SNMP_SNMP_H
2185 #ifdef linux
2186         /* As per the comment near the beginning of the file, UCD SNMP 4.1.1
2187            changed "snmp_set_suffix_only()" from a function to a macro,
2188            removing "snmp_set_suffix_only()" from the library; this means
2189            that binaries that call "snmp_set_suffix_only()" and
2190            that are linked against shared libraries from earlier versions
2191            of the UCD SNMP library won't run with shared libraries from
2192            4.1.1.
2193
2194            This is a problem on Red Hat Linux, as pre-6.2 releases
2195            came with pre-4.1.1 UCD SNMP, while 6.2 comes the 4.1.1.
2196            Versions of Ethereal built on pre-6.2 releases don't run
2197            on 6.2, and the current Ethereal RPMs are built on pre-6.2
2198            releases, causing problems when users running 6.2 download
2199            them and try to use them.
2200
2201            Building the releases on 6.2 isn't necessarily the answer,
2202            as "snmp_set_suffix_only()" expands to a call to "ds_set_int()"
2203            with a second argument not supported by at least some pre-4.1.1
2204            versions of the library - it appears that the 4.0.1 library,
2205            at least, checks for invalid arguments and returns an error
2206            rather than stomping random memory, but that means that you
2207            won't get get OIDs displayed as module-name::sub-OID.
2208
2209            So we use a trick similar to one I've seen mentioned as
2210            used in Windows applications to let you build binaries
2211            that run on many different versions of Windows 9x and
2212            Windows NT, that use features present on later versions
2213            if run on those later versions, but that avoid calling,
2214            when run on older versions, routines not present on those
2215            older versions.
2216
2217            I.e., we load "libsnmp.so.0" with "dlopen()", and call
2218            "dlsym()" to try to find "snmp_set_suffix_only()"; if we
2219            don't find it, we make the appropriate call to
2220            "ds_set_int()" instead.  (We load "libsnmp.so.0" rather
2221            than "libsnmp.so" because, at least on RH 6.2, "libsnmp.so"
2222            exists only if you've loaded the libsnmp development package,
2223            which makes "libsnmp.so" a symlink to "libsnmp.so.0"; we
2224            don't want to force users to install it or to make said
2225            symlink by hand.)
2226
2227            We do this only on Linux, for now, as we've only seen the
2228            problem on Red Hat; it may show up on other OSes that bundle
2229            UCD SNMP, or on OSes where it's not bundled but for which
2230            binary packages are built that link against a shared version
2231            of the UCD SNMP library.  If we run into one of those, we
2232            can do this under those OSes as well, *if* "dlopen()" makes
2233            the run-time linker use the same search rules as it uses when
2234            loading libraries with which the application is linked.
2235
2236            (Perhaps we could use the GLib wrappers for run-time linking,
2237            *if* they're thin enough; however, as this code is currently
2238            used only on Linux, we don't worry about that for now.) */
2239
2240         libsnmp_handle = dlopen("libsnmp.so.0", RTLD_LAZY|RTLD_GLOBAL);
2241         if (libsnmp_handle == NULL) {
2242                 /* We didn't find "libsnmp.so.0".
2243
2244                    This could mean that there is no SNMP shared library
2245                    on this system, in which case we were linked statically,
2246                    in which case whatever call the following line of code
2247                    makes will presumably work, as we have the routine it
2248                    calls wired into our binary.  (If we were linked
2249                    dynamically with "-lsnmp", we would have failed to
2250                    start.)
2251
2252                    It could also mean that there is an SNMP shared library
2253                    on this system, but it's called something other than
2254                    "libsnmp.so.0"; so far, we've seen the problem we're
2255                    working around only on systems where the SNMP shared
2256                    library is called "libsnmp.so.0", so we assume for now
2257                    that systems with shared SNMP libraries named something
2258                    other than "libsnmp.so.0" have an SNMP library that's
2259                    not 4.1.1. */
2260                 snmp_set_suffix_only(2);
2261         } else {
2262                 /* OK, we have it loaded.  Do we have
2263                    "snmp_set_suffix_only()"? */
2264                 snmp_set_suffix_only_p = dlsym(libsnmp_handle,
2265                     "snmp_set_suffix_only");
2266                 if (snmp_set_suffix_only_p != NULL) {
2267                         /* Yes - call it. */
2268                         (*snmp_set_suffix_only_p)(2);
2269                 } else {
2270                         /* No; do we have "ds_set_int()"? */
2271                         ds_set_int_p = dlsym(libsnmp_handle, "ds_set_int");
2272                         if (ds_set_int_p != NULL) {
2273                                 /* Yes - cal it with DS_LIBRARY_ID,
2274                                    DS_LIB_PRINT_SUFFIX_ONLY, and 2 as
2275                                    arguments.
2276
2277                                    We do *not* use DS_LIBRARY_ID or
2278                                    DS_LIB_PRINT_SUFFIX_ONLY by name, so that
2279                                    we don't require that Ethereal be built
2280                                    with versions of UCD SNMP that include
2281                                    that value; instead, we use their values
2282                                    in UCD SNMP 4.1.1, which are 0 and 4,
2283                                    respectively. */
2284                                 (*ds_set_int_p)(0, 4, 2);
2285                         }
2286                 }
2287                 dlclose(libsnmp_handle);
2288         }
2289 #else /* linux */
2290         snmp_set_suffix_only(2);
2291 #endif /* linux */
2292 #endif /* HAVE_UCD_SNMP_SNMP_H */
2293 #endif /* defined(HAVE_UCD_SNMP_SNMP_H) || defined(HAVE_SNMP_SNMP_H) */
2294         proto_snmp = proto_register_protocol("Simple Network Management Protocol",
2295             "SNMP", "snmp");
2296         proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2297             "SMUX", "smux");
2298         proto_register_field_array(proto_snmp, hf, array_length(hf));
2299         proto_register_subtree_array(ett, array_length(ett));
2300 }
2301
2302 void
2303 proto_reg_handoff_snmp(void)
2304 {
2305         dissector_add("udp.port", UDP_PORT_SNMP, dissect_snmp, proto_snmp);
2306         dissector_add("udp.port", UDP_PORT_SNMP_TRAP, dissect_snmp, proto_snmp);
2307         dissector_add("tcp.port", TCP_PORT_SMUX, dissect_smux, proto_smux);
2308         dissector_add("ethertype", ETHERTYPE_SNMP, dissect_snmp, proto_snmp);
2309         dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, dissect_snmp,
2310             proto_snmp);
2311         dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, dissect_snmp,
2312             proto_snmp);
2313 }