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