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