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