c0b97d78568fbd27c824416bed9b639e72d1aef2
[metze/wireshark/wip.git] / asn1 / snmp / packet-snmp-template.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * Copyright (C) 1998 Didier Jorand
4  *
5  * See RFC 1157 for SNMPv1.
6  *
7  * See RFCs 1901, 1905, and 1906 for SNMPv2c.
8  *
9  * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
10  *
11  * See RFCs 2570-2576 for SNMPv3
12  * Updated to use the asn2wrs compiler made by Tomas Kukosa
13  * Copyright (C) 2005 - 2006 Anders Broman [AT] ericsson.com
14  *
15  * See RFC 3414 for User-based Security Model for SNMPv3
16  * See RFC 3826 for  (AES) Cipher Algorithm in the SNMP USM
17  * See RFC 2578 for Structure of Management Information Version 2 (SMIv2)
18  * Copyright (C) 2007 Luis E. Garcia Ontanon <luis@ontanon.org>
19  *
20  * Wireshark - Network traffic analyzer
21  * By Gerald Combs <gerald@wireshark.org>
22  * Copyright 1998 Gerald Combs
23  *
24  * Some stuff from:
25  *
26  * GXSNMP -- An snmp mangament application
27  * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
28  * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
29  *
30  * This program is free software; you can redistribute it and/or
31  * modify it under the terms of the GNU General Public License
32  * as published by the Free Software Foundation; either version 2
33  * of the License, or (at your option) any later version.
34  *
35  * This program is distributed in the hope that it will be useful,
36  * but WITHOUT ANY WARRANTY; without even the implied warranty of
37  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  * GNU General Public License for more details.
39  *
40  * You should have received a copy of the GNU General Public License
41  * along with this program; if not, write to the Free Software
42  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  */
44
45 #if 0
46 #include <stdio.h>
47 #define D(args) do {printf args; fflush(stdout); } while(0)
48 #endif
49
50 #include "config.h"
51
52 #include <epan/packet.h>
53 #include <epan/strutil.h>
54 #include <epan/conversation.h>
55 #include <epan/etypes.h>
56 #include <epan/prefs.h>
57 #include <epan/sminmpec.h>
58 #include <epan/next_tvb.h>
59 #include <epan/uat.h>
60 #include <epan/asn1.h>
61 #include <epan/expert.h>
62 #include <epan/oids.h>
63 #include <wsutil/sha1.h>
64 #include <wsutil/md5.h>
65 #include "packet-ipx.h"
66 #include "packet-hpext.h"
67 #include "packet-ber.h"
68 #include "packet-snmp.h"
69
70 #ifdef HAVE_LIBGCRYPT
71 #include <wsutil/wsgcrypt.h>
72 #endif
73
74 /* Take a pointer that may be null and return a pointer that's not null
75    by turning null pointers into pointers to the above null string,
76    and, if the argument pointer wasn't null, make sure we handle
77    non-printable characters in the string by escaping them. */
78 #define SAFE_STRING(s, l)       (((s) != NULL) ? format_text((s), (l)) : "")
79
80 #define PNAME  "Simple Network Management Protocol"
81 #define PSNAME "SNMP"
82 #define PFNAME "snmp"
83
84 #define UDP_PORT_SNMP           161
85 #define UDP_PORT_SNMP_TRAP      162
86 #define TCP_PORT_SNMP           161
87 #define TCP_PORT_SNMP_TRAP      162
88 #define TCP_PORT_SMUX           199
89 #define UDP_PORT_SNMP_PATROL 8161
90
91 /* Initialize the protocol and registered fields */
92 static int proto_snmp = -1;
93 static int proto_smux = -1;
94
95 static gboolean display_oid = TRUE;
96 static gboolean snmp_var_in_tree = TRUE;
97
98 void proto_register_snmp(void);
99 void proto_reg_handoff_snmp(void);
100 void proto_register_smux(void);
101 void proto_reg_handoff_smux(void);
102
103 static gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, guint8**, guint*, gchar const**);
104 static gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p, guint8**, guint*, gchar const**);
105
106 static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, gchar const**);
107 static tvbuff_t* snmp_usm_priv_aes128(snmp_usm_params_t*, tvbuff_t*, gchar const**);
108 static tvbuff_t* snmp_usm_priv_aes192(snmp_usm_params_t*, tvbuff_t*, gchar const**);
109 static tvbuff_t* snmp_usm_priv_aes256(snmp_usm_params_t*, tvbuff_t*, gchar const**);
110
111
112 static void snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key);
113 static void snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key);
114
115
116 static snmp_usm_auth_model_t model_md5 = {snmp_usm_password_to_key_md5, snmp_usm_auth_md5, 16};
117 static snmp_usm_auth_model_t model_sha1 = {snmp_usm_password_to_key_sha1, snmp_usm_auth_sha1, SHA1_DIGEST_LEN};
118
119 static const value_string auth_types[] = {
120         {0,"MD5"},
121         {1,"SHA1"},
122         {0,NULL}
123 };
124 static snmp_usm_auth_model_t* auth_models[] = {&model_md5,&model_sha1};
125
126 #define PRIV_DES        0
127 #define PRIV_AES128     1
128 #define PRIV_AES192     2
129 #define PRIV_AES256     3
130
131 static const value_string priv_types[] = {
132         { PRIV_DES,    "DES" },
133         { PRIV_AES128, "AES" },
134         { PRIV_AES192, "AES192" },
135         { PRIV_AES256, "AES256" },
136         { 0, NULL}
137 };
138 static snmp_usm_decoder_t priv_protos[] = {
139         snmp_usm_priv_des,
140         snmp_usm_priv_aes128,
141         snmp_usm_priv_aes192,
142         snmp_usm_priv_aes256
143 };
144
145 static snmp_ue_assoc_t* ueas = NULL;
146 static guint num_ueas = 0;
147 static snmp_ue_assoc_t* localized_ues = NULL;
148 static snmp_ue_assoc_t* unlocalized_ues = NULL;
149 /****/
150
151 /* Variabled used for handling enterprise spesific trap types */
152 typedef struct _snmp_st_assoc_t {
153         char *enterprise;
154         guint trap;
155         char *desc;
156 } snmp_st_assoc_t;
157 static guint num_specific_traps = 0;
158 static snmp_st_assoc_t *specific_traps = NULL;
159 static const char *enterprise_oid = NULL;
160 static guint generic_trap = 0;
161 static guint32 snmp_version = 0;
162
163 static snmp_usm_params_t usm_p = {FALSE,FALSE,0,0,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,FALSE};
164
165 #define TH_AUTH   0x01
166 #define TH_CRYPT  0x02
167 #define TH_REPORT 0x04
168
169 /* desegmentation of SNMP-over-TCP */
170 static gboolean snmp_desegment = TRUE;
171
172 /* Global variables */
173
174 guint32 MsgSecurityModel;
175 tvbuff_t *oid_tvb=NULL;
176 tvbuff_t *value_tvb=NULL;
177
178 static dissector_handle_t snmp_handle;
179 static dissector_handle_t data_handle;
180
181 static next_tvb_list_t var_list;
182
183 static int hf_snmp_v3_flags_auth = -1;
184 static int hf_snmp_v3_flags_crypt = -1;
185 static int hf_snmp_v3_flags_report = -1;
186
187 static int hf_snmp_engineid_conform = -1;
188 static int hf_snmp_engineid_enterprise = -1;
189 static int hf_snmp_engineid_format = -1;
190 static int hf_snmp_engineid_ipv4 = -1;
191 static int hf_snmp_engineid_ipv6 = -1;
192 static int hf_snmp_engineid_cisco_type = -1;
193 static int hf_snmp_engineid_mac = -1;
194 static int hf_snmp_engineid_text = -1;
195 static int hf_snmp_engineid_time = -1;
196 static int hf_snmp_engineid_data = -1;
197 static int hf_snmp_decryptedPDU = -1;
198 static int hf_snmp_msgAuthentication = -1;
199
200 static int hf_snmp_noSuchObject = -1;
201 static int hf_snmp_noSuchInstance = -1;
202 static int hf_snmp_endOfMibView = -1;
203 static int hf_snmp_unSpecified = -1;
204
205 static int hf_snmp_integer32_value = -1;
206 static int hf_snmp_octetstring_value = -1;
207 static int hf_snmp_oid_value = -1;
208 static int hf_snmp_null_value = -1;
209 static int hf_snmp_ipv4_value = -1;
210 static int hf_snmp_ipv6_value = -1;
211 static int hf_snmp_anyaddress_value = -1;
212 static int hf_snmp_unsigned32_value = -1;
213 static int hf_snmp_unknown_value = -1;
214 static int hf_snmp_opaque_value = -1;
215 static int hf_snmp_nsap_value = -1;
216 static int hf_snmp_counter_value = -1;
217 static int hf_snmp_timeticks_value = -1;
218 static int hf_snmp_big_counter_value = -1;
219 static int hf_snmp_gauge32_value = -1;
220
221 static int hf_snmp_objectname = -1;
222 static int hf_snmp_scalar_instance_index = -1;
223
224 static int hf_snmp_var_bind_str = -1;
225 static int hf_snmp_agentid_trailer = -1;
226
227 #include "packet-snmp-hf.c"
228
229 /* Initialize the subtree pointers */
230 static gint ett_smux = -1;
231 static gint ett_snmp = -1;
232 static gint ett_engineid = -1;
233 static gint ett_msgFlags = -1;
234 static gint ett_encryptedPDU = -1;
235 static gint ett_decrypted = -1;
236 static gint ett_authParameters = -1;
237 static gint ett_internet = -1;
238 static gint ett_varbind = -1;
239 static gint ett_name = -1;
240 static gint ett_value = -1;
241 static gint ett_decoding_error = -1;
242
243 #include "packet-snmp-ett.c"
244
245 static expert_field ei_snmp_failed_decrypted_data_pdu = EI_INIT;
246 static expert_field ei_snmp_decrypted_data_bad_formatted = EI_INIT;
247 static expert_field ei_snmp_verify_authentication_error = EI_INIT;
248 static expert_field ei_snmp_authentication_ok = EI_INIT;
249 static expert_field ei_snmp_authentication_error = EI_INIT;
250 static expert_field ei_snmp_varbind_not_uni_class_seq = EI_INIT;
251 static expert_field ei_snmp_varbind_has_indicator = EI_INIT;
252 static expert_field ei_snmp_objectname_not_oid = EI_INIT;
253 static expert_field ei_snmp_objectname_has_indicator = EI_INIT;
254 static expert_field ei_snmp_value_not_primitive_encoding = EI_INIT;
255 static expert_field ei_snmp_invalid_oid = EI_INIT;
256 static expert_field ei_snmp_varbind_wrong_tag = EI_INIT;
257 static expert_field ei_snmp_varbind_response = EI_INIT;
258 static expert_field ei_snmp_no_instance_subid = EI_INIT;
259 static expert_field ei_snmp_wrong_num_of_subids = EI_INIT;
260 static expert_field ei_snmp_index_suboid_too_short = EI_INIT;
261 static expert_field ei_snmp_unimplemented_instance_index = EI_INIT;
262 static expert_field ei_snmp_index_suboid_len0 = EI_INIT;
263 static expert_field ei_snmp_index_suboid_too_long = EI_INIT;
264 static expert_field ei_snmp_index_string_too_long = EI_INIT;
265 static expert_field ei_snmp_column_parent_not_row = EI_INIT;
266 static expert_field ei_snmp_uint_too_large = EI_INIT;
267 static expert_field ei_snmp_int_too_large = EI_INIT;
268 static expert_field ei_snmp_integral_value0 = EI_INIT;
269 static expert_field ei_snmp_missing_mib = EI_INIT;
270 static expert_field ei_snmp_varbind_wrong_length_value = EI_INIT;
271 static expert_field ei_snmp_varbind_wrong_class_tag = EI_INIT;
272 static expert_field ei_snmp_rfc1910_non_conformant = EI_INIT;
273 static expert_field ei_snmp_rfc3411_non_conformant = EI_INIT;
274 static expert_field ei_snmp_version_unknown = EI_INIT;
275 static expert_field ei_snmp_trap_pdu_obsolete = EI_INIT;
276
277 static const true_false_string auth_flags = {
278         "OK",
279         "Failed"
280 };
281
282 /* Security Models */
283
284 #define SNMP_SEC_ANY                    0
285 #define SNMP_SEC_V1                     1
286 #define SNMP_SEC_V2C                    2
287 #define SNMP_SEC_USM                    3
288
289 static const value_string sec_models[] = {
290         { SNMP_SEC_ANY,                 "Any" },
291         { SNMP_SEC_V1,                  "V1" },
292         { SNMP_SEC_V2C,                 "V2C" },
293         { SNMP_SEC_USM,                 "USM" },
294         { 0,                            NULL }
295 };
296
297 #if 0
298 /* SMUX PDU types */
299 #define SMUX_MSG_OPEN           0
300 #define SMUX_MSG_CLOSE          1
301 #define SMUX_MSG_RREQ           2
302 #define SMUX_MSG_RRSP           3
303 #define SMUX_MSG_SOUT           4
304
305 static const value_string smux_types[] = {
306         { SMUX_MSG_OPEN,        "Open" },
307         { SMUX_MSG_CLOSE,       "Close" },
308         { SMUX_MSG_RREQ,        "Registration Request" },
309         { SMUX_MSG_RRSP,        "Registration Response" },
310         { SMUX_MSG_SOUT,        "Commit Or Rollback" },
311         { 0,                    NULL }
312 };
313 #endif
314
315
316 #define SNMP_IPA    0           /* IP Address */
317 #define SNMP_CNT    1           /* Counter (Counter32) */
318 #define SNMP_GGE    2           /* Gauge (Gauge32) */
319 #define SNMP_TIT    3           /* TimeTicks */
320 #define SNMP_OPQ    4           /* Opaque */
321 #define SNMP_NSP    5           /* NsapAddress */
322 #define SNMP_C64    6           /* Counter64 */
323 #define SNMP_U32    7           /* Uinteger32 */
324
325 #define SERR_NSO    0
326 #define SERR_NSI    1
327 #define SERR_EOM    2
328
329
330 dissector_table_t value_sub_dissectors_table;
331
332
333 static const gchar *
334 snmp_lookup_specific_trap (guint specific_trap)
335 {
336         guint i;
337
338         for (i = 0; i < num_specific_traps; i++) {
339                 snmp_st_assoc_t *u = &(specific_traps[i]);
340
341                 if ((u->trap == specific_trap) &&
342                     (strcmp (u->enterprise, enterprise_oid) == 0))
343                 {
344                         return u->desc;
345                 }
346         }
347
348         return NULL;
349 }
350
351 static int
352 dissect_snmp_variable_string(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
353 {
354
355         proto_tree_add_item(tree, hf_snmp_var_bind_str, tvb, 0, -1, ENC_ASCII|ENC_NA);
356
357         return tvb_captured_length(tvb);
358 }
359
360 /*
361 DateAndTime ::= TEXTUAL-CONVENTION
362     DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
363     STATUS       current
364     DESCRIPTION
365             "A date-time specification.
366
367             field  octets  contents                  range
368             -----  ------  --------                  -----
369               1      1-2   year*                     0..65536
370               2       3    month                     1..12
371               3       4    day                       1..31
372               4       5    hour                      0..23
373               5       6    minutes                   0..59
374               6       7    seconds                   0..60
375                            (use 60 for leap-second)
376               7       8    deci-seconds              0..9
377               8       9    direction from UTC        '+' / '-'
378               9      10    hours from UTC*           0..13
379              10      11    minutes from UTC          0..59
380
381             * Notes:
382             - the value of year is in network-byte order
383             - daylight saving time in New Zealand is +13
384
385             For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
386             displayed as:
387
388                              1992-5-26,13:30:15.0,-4:0
389
390             Note that if only local time is known, then timezone
391             information (fields 8-10) is not present."
392     SYNTAX       OCTET STRING (SIZE (8 | 11))
393 */
394 static proto_item *
395 dissect_snmp_variable_date_and_time(proto_tree *tree,int hfid, tvbuff_t *tvb, int offset, int length)
396 {
397         guint16 year;
398         guint8 month;
399         guint8 day;
400         guint8 hour;
401         guint8 minutes;
402         guint8 seconds;
403         guint8 deci_seconds;
404         guint8 hour_from_utc;
405         guint8 min_from_utc;
406         gchar *str;
407
408         year                    = tvb_get_ntohs(tvb,offset);
409         month                   = tvb_get_guint8(tvb,offset+2);
410         day                     = tvb_get_guint8(tvb,offset+3);
411         hour                    = tvb_get_guint8(tvb,offset+4);
412         minutes                 = tvb_get_guint8(tvb,offset+5);
413         seconds                 = tvb_get_guint8(tvb,offset+6);
414         deci_seconds            = tvb_get_guint8(tvb,offset+7);
415         if(length > 8){
416                 hour_from_utc   = tvb_get_guint8(tvb,offset+9);
417                 min_from_utc    = tvb_get_guint8(tvb,offset+10);
418
419                 str = wmem_strdup_printf(wmem_packet_scope(),
420                          "%u-%u-%u, %u:%u:%u.%u UTC %s%u:%u",
421                          year,
422                          month,
423                          day,
424                          hour,
425                          minutes,
426                          seconds,
427                          deci_seconds,
428                          tvb_get_string_enc(wmem_packet_scope(),tvb,offset+8,1,ENC_ASCII|ENC_NA),
429                          hour_from_utc,
430                          min_from_utc);
431         }else{
432                  str = wmem_strdup_printf(wmem_packet_scope(),
433                          "%u-%u-%u, %u:%u:%u.%u",
434                          year,
435                          month,
436                          day,
437                          hour,
438                          minutes,
439                          seconds,
440                          deci_seconds);
441         }
442
443         return proto_tree_add_string(tree, hfid, tvb, offset, length, str);
444
445 }
446
447 /*
448  *  dissect_snmp_VarBind
449  *  this routine dissects variable bindings, looking for the oid information in our oid reporsitory
450  *  to format and add the value adequatelly.
451  *
452  * The choice to handwrite this code instead of using the asn compiler is to avoid having tons
453  * of uses of global variables distributed in very different parts of the code.
454  * Other than that there's a cosmetic thing: the tree from ASN generated code would be so
455  * convoluted due to the nesting of CHOICEs in the definition of VarBind/value.
456  *
457  * XXX: the length of this function (~400 lines) is an aberration!
458  *  oid_key_t:key_type could become a series of callbacks instead of an enum
459  *  the (! oid_info_is_ok) switch could be made into an array (would be slower)
460  *
461
462         NetworkAddress ::=  CHOICE { internet IpAddress }
463         IpAddress ::= [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4))
464         TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
465         Integer32 ::= INTEGER (-2147483648..2147483647)
466         ObjectName ::= OBJECT IDENTIFIER
467         Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
468         Gauge32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
469         Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
470         Integer-value ::=  INTEGER (-2147483648..2147483647)
471         Integer32 ::= INTEGER (-2147483648..2147483647)
472         ObjectID-value ::= OBJECT IDENTIFIER
473         Empty ::= NULL
474         TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
475         Opaque ::= [APPLICATION 4] IMPLICIT OCTET STRING
476         Counter64 ::= [APPLICATION 6] IMPLICIT INTEGER (0..18446744073709551615)
477
478         ObjectSyntax ::= CHOICE {
479                  simple SimpleSyntax,
480                  application-wide ApplicationSyntax
481         }
482
483         SimpleSyntax ::= CHOICE {
484            integer-value Integer-value,
485            string-value String-value,
486            objectID-value ObjectID-value,
487            empty  Empty
488         }
489
490         ApplicationSyntax ::= CHOICE {
491            ipAddress-value IpAddress,
492            counter-value Counter32,
493            timeticks-value TimeTicks,
494            arbitrary-value Opaque,
495            big-counter-value Counter64,
496            unsigned-integer-value Unsigned32
497         }
498
499         ValueType ::=  CHOICE {
500            value ObjectSyntax,
501            unSpecified NULL,
502            noSuchObject[0] IMPLICIT NULL,
503            noSuchInstance[1] IMPLICIT NULL,
504            endOfMibView[2] IMPLICIT NULL
505         }
506
507         VarBind ::= SEQUENCE {
508            name ObjectName,
509            valueType ValueType
510         }
511
512  */
513
514 static int
515 dissect_snmp_VarBind(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset,
516                      asn1_ctx_t *actx, proto_tree *tree, int hf_index _U_)
517 {
518         int seq_offset, name_offset, value_offset, value_start;
519         guint32 seq_len, name_len, value_len;
520         gint8 ber_class;
521         gboolean pc;
522         gint32 tag;
523         gboolean ind;
524         guint32* subids;
525         guint8* oid_bytes;
526         oid_info_t* oid_info = NULL;
527         guint oid_matched, oid_left;
528         proto_item *pi_name, *pi_varbind, *pi_value = NULL;
529         proto_tree *pt, *pt_varbind, *pt_name, *pt_value;
530         char label[ITEM_LABEL_LENGTH];
531         const char* repr = NULL;
532         const char* info_oid = NULL;
533         char* valstr;
534         int hfid = -1;
535         int min_len = 0, max_len = 0;
536         gboolean oid_info_is_ok;
537         const char* oid_string = NULL;
538         enum {BER_NO_ERROR, BER_WRONG_LENGTH, BER_WRONG_TAG} format_error = BER_NO_ERROR;
539
540         seq_offset = offset;
541
542         /* first have the VarBind's sequence header */
543         offset = dissect_ber_identifier(actx->pinfo, tree, tvb, offset, &ber_class, &pc, &tag);
544         offset = dissect_ber_length(actx->pinfo, tree, tvb, offset, &seq_len, &ind);
545
546         if (!pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_SEQUENCE) {
547                 proto_item* pi;
548                 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
549                                 ett_decoding_error, &pi, "VarBind must be an universal class sequence");
550                 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_not_uni_class_seq);
551                 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
552         }
553
554         if (ind) {
555                 proto_item* pi;
556                 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len + (offset - seq_offset),
557                                         ett_decoding_error, &pi, "Indicator must be clear in VarBind");
558                 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_has_indicator);
559                 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
560         }
561
562         /* we add the varbind tree root with a dummy label we'll fill later on */
563         pt_varbind = proto_tree_add_subtree(tree,tvb,offset,seq_len,ett_varbind,&pi_varbind,"VarBind");
564         *label = '\0';
565
566         seq_len += offset - seq_offset;
567
568         /* then we have the ObjectName's header */
569
570         offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
571         name_offset = offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &name_len, &ind);
572
573         if (! ( !pc && ber_class==BER_CLASS_UNI && tag==BER_UNI_TAG_OID) ) {
574                 proto_item* pi;
575                 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
576                                 ett_decoding_error, &pi, "ObjectName must be an OID in primitive encoding");
577                 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_not_oid);
578                 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
579         }
580
581         if (ind) {
582                 proto_item* pi;
583                 pt = proto_tree_add_subtree(tree, tvb, seq_offset, seq_len,
584                                 ett_decoding_error, &pi, "Indicator must be clear in ObjectName");
585                 expert_add_info(actx->pinfo, pi, &ei_snmp_objectname_has_indicator);
586                 return dissect_unknown_ber(actx->pinfo, tvb, seq_offset, pt);
587         }
588
589         pi_name = proto_tree_add_item(pt_varbind,hf_snmp_objectname,tvb,name_offset,name_len,ENC_NA);
590         pt_name = proto_item_add_subtree(pi_name,ett_name);
591
592         offset += name_len;
593         value_start = offset;
594         /* then we have the value's header */
595         offset = dissect_ber_identifier(actx->pinfo, pt_varbind, tvb, offset, &ber_class, &pc, &tag);
596         value_offset = dissect_ber_length(actx->pinfo, pt_varbind, tvb, offset, &value_len, &ind);
597
598         if (! (!pc) ) {
599                 proto_item* pi;
600                 pt = proto_tree_add_subtree(pt_varbind, tvb, value_start, value_len,
601                                 ett_decoding_error, &pi, "the value must be in primitive encoding");
602                 expert_add_info(actx->pinfo, pi, &ei_snmp_value_not_primitive_encoding);
603                 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
604         }
605
606         /* Now, we know where everithing is */
607
608         /* fetch ObjectName and its relative oid_info */
609         oid_bytes = (guint8*)tvb_memdup(wmem_packet_scope(), tvb, name_offset, name_len);
610         oid_info = oid_get_from_encoded(wmem_packet_scope(), oid_bytes, name_len, &subids, &oid_matched, &oid_left);
611
612         add_oid_debug_subtree(oid_info,pt_name);
613
614         if (!subids) {
615                 proto_item* pi;
616
617                 repr = oid_encoded2string(wmem_packet_scope(), oid_bytes, name_len);
618                 pt = proto_tree_add_subtree_format(pt_name,tvb, 0, 0, ett_decoding_error, &pi, "invalid oid: %s", repr);
619                 expert_add_info_format(actx->pinfo, pi, &ei_snmp_invalid_oid, "invalid oid: %s", repr);
620                 return dissect_unknown_ber(actx->pinfo, tvb, name_offset, pt);
621         }
622
623         if (oid_matched+oid_left) {
624                 oid_string = oid_subid2string(wmem_packet_scope(), subids,oid_matched+oid_left);
625         }
626
627         if (ber_class == BER_CLASS_CON) {
628                 /* if we have an error value just add it and get out the way ASAP */
629                 proto_item* pi;
630                 const char* note;
631
632                 if (value_len != 0) {
633                         min_len = max_len = 0;
634                         format_error = BER_WRONG_LENGTH;
635                 }
636
637                 switch (tag) {
638                         case SERR_NSO:
639                                 hfid = hf_snmp_noSuchObject;
640                                 note = "noSuchObject";
641                                 break;
642                         case SERR_NSI:
643                                 hfid = hf_snmp_noSuchInstance;
644                                 note = "noSuchInstance";
645                                 break;
646                         case SERR_EOM:
647                                 hfid = hf_snmp_endOfMibView;
648                                 note = "endOfMibView";
649                                 break;
650                         default: {
651                                 pt = proto_tree_add_subtree_format(pt_varbind,tvb,0,0,ett_decoding_error,&pi,
652                                                                 "Wrong tag for Error Value: expected 0, 1, or 2 but got: %d",tag);
653                                 expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_tag);
654                                 return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
655                         }
656                 }
657
658                 pi = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
659                 expert_add_info_format(actx->pinfo, pi, &ei_snmp_varbind_response, "%s",note);
660                 g_strlcpy (label, note, ITEM_LABEL_LENGTH);
661                 goto set_label;
662         }
663
664         /* now we'll try to figure out which are the indexing sub-oids and whether the oid we know about is the one oid we have to use */
665         switch (oid_info->kind) {
666                 case OID_KIND_SCALAR:
667                         if (oid_left == 1) {
668                                 /* OK: we got the instance sub-id */
669                                 proto_tree_add_uint64(pt_name,hf_snmp_scalar_instance_index,tvb,name_offset,name_len,subids[oid_matched]);
670                                 oid_info_is_ok = TRUE;
671                                 goto indexing_done;
672                         } else if (oid_left == 0) {
673                                 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
674                                         /* unSpecified  does not require an instance sub-id add the new value and get off the way! */
675                                         pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
676                                         goto set_label;
677                                 } else {
678                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_no_instance_subid,tvb,0,0);
679                                         oid_info_is_ok = FALSE;
680                                         goto indexing_done;
681                                 }
682                         } else {
683                                 proto_tree_add_expert_format(pt_name,actx->pinfo,&ei_snmp_wrong_num_of_subids,tvb,0,0,"A scalar should have only one instance sub-id this has: %d",oid_left);
684                                 oid_info_is_ok = FALSE;
685                                 goto indexing_done;
686                         }
687                 break;
688                 case OID_KIND_COLUMN:
689                         if ( oid_info->parent->kind == OID_KIND_ROW) {
690                                 oid_key_t* k = oid_info->parent->key;
691                                 guint key_start = oid_matched;
692                                 guint key_len = oid_left;
693                                 oid_info_is_ok = TRUE;
694
695                                 if ( key_len == 0 && ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
696                                         /* unSpecified  does not require an instance sub-id add the new value and get off the way! */
697                                         pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
698                                         goto set_label;
699                                 }
700
701                                 if (k) {
702                                         for (;k;k = k->next) {
703                                                 guint suboid_len;
704
705                                                 if (key_start >= oid_matched+oid_left) {
706                                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_short,tvb,0,0);
707                                                         oid_info_is_ok = FALSE;
708                                                         goto indexing_done;
709                                                 }
710
711                                                 switch(k->key_type) {
712                                                         case OID_KEY_TYPE_WRONG: {
713                                                                 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
714                                                                 oid_info_is_ok = FALSE;
715                                                                 goto indexing_done;
716                                                         }
717                                                         case OID_KEY_TYPE_INTEGER: {
718                                                                 if (IS_FT_INT(k->ft_type)) {
719                                                                         proto_tree_add_int(pt_name,k->hfid,tvb,name_offset,name_len,(guint)subids[key_start]);
720                                                                 } else { /* if it's not an unsigned int let proto_tree_add_uint throw a warning */
721                                                                         proto_tree_add_uint64(pt_name,k->hfid,tvb,name_offset,name_len,(guint)subids[key_start]);
722                                                                 }
723                                                                 key_start++;
724                                                                 key_len--;
725                                                                 continue; /* k->next */
726                                                         }
727                                                         case OID_KEY_TYPE_IMPLIED_OID:
728                                                                 suboid_len = key_len;
729
730                                                                 goto show_oid_index;
731
732                                                         case OID_KEY_TYPE_OID: {
733                                                                 guint8* suboid_buf;
734                                                                 guint suboid_buf_len;
735                                                                 guint32* suboid;
736
737                                                                 suboid_len = subids[key_start++];
738                                                                 key_len--;
739
740 show_oid_index:
741                                                                 suboid = &(subids[key_start]);
742
743                                                                 if( suboid_len == 0 ) {
744                                                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_len0,tvb,0,0);
745                                                                         oid_info_is_ok = FALSE;
746                                                                         goto indexing_done;
747                                                                 }
748
749                                                                 if( key_len < suboid_len ) {
750                                                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_suboid_too_long,tvb,0,0);
751                                                                         oid_info_is_ok = FALSE;
752                                                                         goto indexing_done;
753                                                                 }
754
755                                                                 suboid_buf_len = oid_subid2encoded(wmem_packet_scope(), suboid_len, suboid, &suboid_buf);
756
757                                                                 DISSECTOR_ASSERT(suboid_buf_len);
758
759                                                                 proto_tree_add_oid(pt_name,k->hfid,tvb,name_offset, suboid_buf_len, suboid_buf);
760
761                                                                 key_start += suboid_len;
762                                                                 key_len -= suboid_len + 1;
763                                                                 continue; /* k->next */
764                                                         }
765                                                         default: {
766                                                                 guint8* buf;
767                                                                 guint buf_len;
768                                                                 guint32* suboid;
769                                                                 guint i;
770
771
772                                                                 switch (k->key_type) {
773                                                                         case OID_KEY_TYPE_IPADDR:
774                                                                                 suboid = &(subids[key_start]);
775                                                                                 buf_len = 4;
776                                                                                 break;
777                                                                         case OID_KEY_TYPE_IMPLIED_STRING:
778                                                                         case OID_KEY_TYPE_IMPLIED_BYTES:
779                                                                         case OID_KEY_TYPE_ETHER:
780                                                                                 suboid = &(subids[key_start]);
781                                                                                 buf_len = key_len;
782                                                                                 break;
783                                                                         default:
784                                                                                 buf_len = k->num_subids;
785                                                                                 suboid = &(subids[key_start]);
786
787                                                                                 if(!buf_len) {
788                                                                                         buf_len = *suboid++;
789                                                                                         key_len--;
790                                                                                         key_start++;
791                                                                                 }
792                                                                                 break;
793                                                                 }
794
795                                                                 if( key_len < buf_len ) {
796                                                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_index_string_too_long,tvb,0,0);
797                                                                         oid_info_is_ok = FALSE;
798                                                                         goto indexing_done;
799                                                                 }
800
801                                                                 buf = (guint8*)wmem_alloc(wmem_packet_scope(), buf_len+1);
802                                                                 for (i = 0; i < buf_len; i++)
803                                                                         buf[i] = (guint8)suboid[i];
804                                                                 buf[i] = '\0';
805
806                                                                 switch(k->key_type) {
807                                                                         case OID_KEY_TYPE_STRING:
808                                                                         case OID_KEY_TYPE_IMPLIED_STRING:
809                                                                                 proto_tree_add_string(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
810                                                                                 break;
811                                                                         case OID_KEY_TYPE_BYTES:
812                                                                         case OID_KEY_TYPE_NSAP:
813                                                                         case OID_KEY_TYPE_IMPLIED_BYTES:
814                                                                                 proto_tree_add_bytes(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
815                                                                                 break;
816                                                                         case OID_KEY_TYPE_ETHER:
817                                                                                 proto_tree_add_ether(pt_name,k->hfid,tvb,name_offset,buf_len, buf);
818                                                                                 break;
819                                                                         case OID_KEY_TYPE_IPADDR: {
820                                                                                 guint32* ipv4_p = (guint32*)buf;
821                                                                                 proto_tree_add_ipv4(pt_name,k->hfid,tvb,name_offset,buf_len, *ipv4_p);
822                                                                                 }
823                                                                                 break;
824                                                                         default:
825                                                                                 DISSECTOR_ASSERT_NOT_REACHED();
826                                                                                 break;
827                                                                 }
828
829                                                                 key_start += buf_len;
830                                                                 key_len -= buf_len;
831                                                                 continue; /* k->next*/
832                                                         }
833                                                 }
834                                         }
835                                         goto indexing_done;
836                                 } else {
837                                         proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_unimplemented_instance_index,tvb,0,0);
838                                         oid_info_is_ok = FALSE;
839                                         goto indexing_done;
840                                 }
841                         } else {
842                                 proto_tree_add_expert(pt_name,actx->pinfo,&ei_snmp_column_parent_not_row,tvb,0,0);
843                                 oid_info_is_ok = FALSE;
844                                 goto indexing_done;
845                         }
846                 default: {
847 /*                      proto_tree_add_expert (pt_name,actx->pinfo,PI_MALFORMED, PI_WARN,tvb,0,0,"This kind OID should have no value"); */
848                         oid_info_is_ok = FALSE;
849                         goto indexing_done;
850                 }
851         }
852 indexing_done:
853
854         if (oid_info_is_ok && oid_info->value_type) {
855                 if (ber_class == BER_CLASS_UNI && tag == BER_UNI_TAG_NULL) {
856                         pi_value = proto_tree_add_item(pt_varbind,hf_snmp_unSpecified,tvb,value_offset,value_len,ENC_NA);
857                 } else {
858                         /* Provide a tree_item to attach errors to, if needed. */
859                         pi_value = pi_name;
860
861                         if ((oid_info->value_type->ber_class != BER_CLASS_ANY) &&
862                                 (ber_class != oid_info->value_type->ber_class))
863                                 format_error = BER_WRONG_TAG;
864                         else if ((oid_info->value_type->ber_tag != BER_TAG_ANY) &&
865                                 (tag != oid_info->value_type->ber_tag))
866                                 format_error = BER_WRONG_TAG;
867                         else {
868                                 max_len = oid_info->value_type->max_len == -1 ? 0xffffff : oid_info->value_type->max_len;
869                                 min_len = oid_info->value_type->min_len;
870
871                                 if ((int)value_len < min_len || (int)value_len > max_len)
872                                         format_error = BER_WRONG_LENGTH;
873                         }
874
875                         if (format_error == BER_NO_ERROR)
876                                 pi_value = proto_tree_add_item(pt_varbind,oid_info->value_hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
877                 }
878         } else {
879                 switch(ber_class|(tag<<4)) {
880                         case BER_CLASS_UNI|(BER_UNI_TAG_INTEGER<<4):
881                         {
882                                 gint64 val=0;
883                                 unsigned int int_val_offset = value_offset;
884                                 unsigned int i;
885
886                                 max_len = 4; min_len = 1;
887                                 if (value_len > (guint)max_len || value_len < (guint)min_len) {
888                                         hfid = hf_snmp_integer32_value;
889                                         format_error = BER_WRONG_LENGTH;
890                                         break;
891                                 }
892
893                                 if(value_len > 0) {
894                                         /* extend sign bit */
895                                         if(tvb_get_guint8(tvb, int_val_offset)&0x80) {
896                                                 val=-1;
897                                         }
898                                         for(i=0;i<value_len;i++) {
899                                                 val=(val<<8)|tvb_get_guint8(tvb, int_val_offset);
900                                                 int_val_offset++;
901                                         }
902                                 }
903                                 proto_tree_add_int64(pt_varbind, hf_snmp_integer32_value, tvb,value_offset,value_len, val);
904
905                                 goto already_added;
906                         }
907                         case BER_CLASS_UNI|(BER_UNI_TAG_OCTETSTRING<<4):
908                                 if(oid_info->value_hfid> -1){
909                                         hfid = oid_info->value_hfid;
910                                 }else{
911                                         hfid = hf_snmp_octetstring_value;
912                                 }
913                                 break;
914                         case BER_CLASS_UNI|(BER_UNI_TAG_OID<<4):
915                                 max_len = -1; min_len = 1;
916                                 if (value_len < (guint)min_len) format_error = BER_WRONG_LENGTH;
917                                 hfid = hf_snmp_oid_value;
918                                 break;
919                         case BER_CLASS_UNI|(BER_UNI_TAG_NULL<<4):
920                                 max_len = 0; min_len = 0;
921                                 if (value_len != 0) format_error = BER_WRONG_LENGTH;
922                                 hfid = hf_snmp_null_value;
923                                 break;
924                         case BER_CLASS_APP: /* | (SNMP_IPA<<4)*/
925                                 switch(value_len) {
926                                         case 4: hfid = hf_snmp_ipv4_value; break;
927                                         case 16: hfid = hf_snmp_ipv6_value; break;
928                                         default: hfid = hf_snmp_anyaddress_value; break;
929                                 }
930                                 break;
931                         case BER_CLASS_APP|(SNMP_U32<<4):
932                                 hfid = hf_snmp_unsigned32_value;
933                                 break;
934                         case BER_CLASS_APP|(SNMP_GGE<<4):
935                                 hfid = hf_snmp_gauge32_value;
936                                 break;
937                         case BER_CLASS_APP|(SNMP_CNT<<4):
938                                 hfid = hf_snmp_counter_value;
939                                 break;
940                         case BER_CLASS_APP|(SNMP_TIT<<4):
941                                 hfid = hf_snmp_timeticks_value;
942                                 break;
943                         case BER_CLASS_APP|(SNMP_OPQ<<4):
944                                 hfid = hf_snmp_opaque_value;
945                                 break;
946                         case BER_CLASS_APP|(SNMP_NSP<<4):
947                                 hfid = hf_snmp_nsap_value;
948                                 break;
949                         case BER_CLASS_APP|(SNMP_C64<<4):
950                                 hfid = hf_snmp_big_counter_value;
951                                 break;
952                         default:
953                                 hfid = hf_snmp_unknown_value;
954                                 break;
955                 }
956                 if (value_len > 8) {
957                         /*
958                          * Too long for an FT_UINT64 or an FT_INT64.
959                          */
960                         header_field_info *hfinfo = proto_registrar_get_nth(hfid);
961                         if (hfinfo->type == FT_UINT64) {
962                                 /*
963                                  * Check if this is an unsigned int64 with
964                                  * a big value.
965                                  */
966                                 if (value_len > 9 || tvb_get_guint8(tvb, value_offset) != 0) {
967                                         /* It is.  Fail. */
968                                         proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_uint_too_large,tvb,value_offset,value_len,"Integral value too large");
969                                         goto already_added;
970                                 }
971                                 /* Cheat and skip the leading 0 byte */
972                                 value_len--;
973                                 value_offset++;
974                         } else if (hfinfo->type == FT_INT64) {
975                                 /*
976                                  * For now, just reject these.
977                                  */
978                                 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_int_too_large,tvb,value_offset,value_len,"Integral value too large or too small");
979                                 goto already_added;
980                         }
981                 } else if (value_len == 0) {
982                         /*
983                          * X.690 section 8.3.1 "Encoding of an integer value":
984                          * "The encoding of an integer value shall be
985                          * primitive. The contents octets shall consist of
986                          * one or more octets."
987                          *
988                          * Zero is not "one or more".
989                          */
990                         header_field_info *hfinfo = proto_registrar_get_nth(hfid);
991                         if (hfinfo->type == FT_UINT64 || hfinfo->type == FT_INT64) {
992                                 proto_tree_add_expert_format(pt_varbind,actx->pinfo,&ei_snmp_integral_value0,tvb,value_offset,value_len,"Integral value is zero-length");
993                                 goto already_added;
994                         }
995                 }
996                 /* Special case DATE AND TIME */
997                 if((oid_info->value_type)&&(oid_info->value_type->keytype == OID_KEY_TYPE_DATE_AND_TIME)&&(value_len > 7)){
998                         pi_value = dissect_snmp_variable_date_and_time(pt_varbind, hfid, tvb, value_offset, value_len);
999                 }else{
1000                         pi_value = proto_tree_add_item(pt_varbind,hfid,tvb,value_offset,value_len,ENC_BIG_ENDIAN);
1001                 }
1002                 if (format_error != BER_NO_ERROR) {
1003                         expert_add_info(actx->pinfo, pi_value, &ei_snmp_missing_mib);
1004                 }
1005
1006         }
1007 already_added:
1008         pt_value = proto_item_add_subtree(pi_value,ett_value);
1009
1010         if (value_len > 0 && oid_string) {
1011                 tvbuff_t* sub_tvb = tvb_new_subset_length(tvb, value_offset, value_len);
1012
1013                 next_tvb_add_string(&var_list, sub_tvb, (snmp_var_in_tree) ? pt_value : NULL, value_sub_dissectors_table, oid_string);
1014         }
1015
1016
1017 set_label:
1018         if (pi_value) proto_item_fill_label(PITEM_FINFO(pi_value), label);
1019
1020         if (oid_info && oid_info->name) {
1021                 if (oid_left >= 1) {
1022                         repr = wmem_strdup_printf(wmem_packet_scope(), "%s.%s (%s)", oid_info->name,
1023                                                 oid_subid2string(wmem_packet_scope(), &(subids[oid_matched]),oid_left),
1024                                                 oid_subid2string(wmem_packet_scope(), subids,oid_matched+oid_left));
1025                         info_oid = wmem_strdup_printf(wmem_packet_scope(), "%s.%s", oid_info->name,
1026                                                 oid_subid2string(wmem_packet_scope(), &(subids[oid_matched]),oid_left));
1027                 } else {
1028                         repr = wmem_strdup_printf(wmem_packet_scope(), "%s (%s)", oid_info->name,
1029                                                 oid_subid2string(wmem_packet_scope(), subids,oid_matched));
1030                         info_oid = oid_info->name;
1031                 }
1032         } else if (oid_string) {
1033                 repr = wmem_strdup(wmem_packet_scope(), oid_string);
1034                 info_oid = oid_string;
1035         } else {
1036                 repr = wmem_strdup(wmem_packet_scope(), "[Bad OID]");
1037         }
1038
1039         valstr = strstr(label,": ");
1040         valstr = valstr ? valstr+2 : label;
1041
1042         proto_item_set_text(pi_varbind,"%s: %s",repr,valstr);
1043
1044         if (display_oid && info_oid) {
1045                 col_append_fstr (actx->pinfo->cinfo, COL_INFO, " %s", info_oid);
1046         }
1047
1048         switch (format_error) {
1049                 case BER_WRONG_LENGTH: {
1050                         proto_item* pi;
1051                         proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1052                         pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1053                                                              "Wrong value length: %u  expecting: %u <= len <= %u",
1054                                                              value_len, min_len, max_len == -1 ? 0xFFFFFF : max_len);
1055                         expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_length_value);
1056                         return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1057                 }
1058                 case BER_WRONG_TAG: {
1059                         proto_item* pi;
1060                         proto_tree* p_tree = proto_item_add_subtree(pi_value,ett_decoding_error);
1061                         pt = proto_tree_add_subtree_format(p_tree,tvb,0,0,ett_decoding_error,&pi,
1062                                                              "Wrong class/tag for Value expected: %d,%d got: %d,%d",
1063                                                              oid_info->value_type->ber_class, oid_info->value_type->ber_tag,
1064                                                              ber_class, tag);
1065                         expert_add_info(actx->pinfo, pi, &ei_snmp_varbind_wrong_class_tag);
1066                         return dissect_unknown_ber(actx->pinfo, tvb, value_start, pt);
1067                 }
1068                 default:
1069                         break;
1070         }
1071
1072         return seq_offset + seq_len;
1073 }
1074
1075
1076 #define F_SNMP_ENGINEID_CONFORM 0x80
1077 #define SNMP_ENGINEID_RFC1910 0x00
1078 #define SNMP_ENGINEID_RFC3411 0x01
1079
1080 static const true_false_string tfs_snmp_engineid_conform = {
1081         "RFC3411 (SNMPv3)",
1082         "RFC1910 (Non-SNMPv3)"
1083 };
1084
1085 #define SNMP_ENGINEID_FORMAT_IPV4 0x01
1086 #define SNMP_ENGINEID_FORMAT_IPV6 0x02
1087 #define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
1088 #define SNMP_ENGINEID_FORMAT_TEXT 0x04
1089 #define SNMP_ENGINEID_FORMAT_OCTETS 0x05
1090
1091 static const value_string snmp_engineid_format_vals[] = {
1092         { SNMP_ENGINEID_FORMAT_IPV4,    "IPv4 address" },
1093         { SNMP_ENGINEID_FORMAT_IPV6,    "IPv6 address" },
1094         { SNMP_ENGINEID_FORMAT_MACADDRESS,      "MAC address" },
1095         { SNMP_ENGINEID_FORMAT_TEXT,    "Text, administratively assigned" },
1096         { SNMP_ENGINEID_FORMAT_OCTETS,  "Octets, administratively assigned" },
1097         { 0,    NULL }
1098 };
1099
1100 #define SNMP_ENGINEID_CISCO_AGENT 0x00
1101 #define SNMP_ENGINEID_CISCO_MANAGER 0x01
1102
1103 static const value_string snmp_engineid_cisco_type_vals[] = {
1104         { SNMP_ENGINEID_CISCO_AGENT,    "Agent" },
1105         { SNMP_ENGINEID_CISCO_MANAGER,  "Manager" },
1106         { 0,    NULL }
1107 };
1108
1109 /*
1110  * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
1111  * or historic RFC 1910 (AgentID)
1112  */
1113 int
1114 dissect_snmp_engineid(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int offset, int len)
1115 {
1116         proto_item *item = NULL;
1117         guint8 conformance, format;
1118         guint32 enterpriseid, seconds;
1119         nstime_t ts;
1120         int len_remain = len;
1121
1122         /* first bit: engine id conformance */
1123         if (len_remain<1) return offset;
1124         conformance = ((tvb_get_guint8(tvb, offset)>>7) & 0x01);
1125         proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, ENC_BIG_ENDIAN);
1126
1127         /* 4-byte enterprise number/name */
1128         if (len_remain<4) return offset;
1129         enterpriseid = tvb_get_ntohl(tvb, offset);
1130         if (conformance)
1131                 enterpriseid -= 0x80000000; /* ignore first bit */
1132         proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
1133         offset+=4;
1134         len_remain-=4;
1135
1136         switch(conformance) {
1137
1138         case SNMP_ENGINEID_RFC1910:
1139                 /* 12-byte AgentID w/ 8-byte trailer */
1140                 if (len_remain==8) {
1141                         proto_tree_add_item(tree, hf_snmp_agentid_trailer, tvb, offset, 8, ENC_NA);
1142                         offset+=8;
1143                         len_remain-=8;
1144                 } else {
1145                         proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc1910_non_conformant, tvb, offset, len_remain);
1146                         return offset;
1147                 }
1148                 break;
1149
1150         case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
1151
1152                 /* 1-byte format specifier */
1153                 if (len_remain<1) return offset;
1154                 format = tvb_get_guint8(tvb, offset);
1155                 item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
1156                                                   val_to_str(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"), format);
1157                 offset+=1;
1158                 len_remain-=1;
1159
1160                 switch(format) {
1161                 case SNMP_ENGINEID_FORMAT_IPV4:
1162                         /* 4-byte IPv4 address */
1163                         if (len_remain==4) {
1164                                 proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
1165                                 offset+=4;
1166                                 len_remain=0;
1167                         }
1168                         break;
1169                 case SNMP_ENGINEID_FORMAT_IPV6:
1170                         /* 16-byte IPv6 address */
1171                         if (len_remain==16) {
1172                                 proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, ENC_NA);
1173                                 offset+=16;
1174                                 len_remain=0;
1175                         }
1176                         break;
1177                 case SNMP_ENGINEID_FORMAT_MACADDRESS:
1178                         /* See: https://supportforums.cisco.com/message/3010617#3010617 for details. */
1179                         if ((enterpriseid==9)&&(len_remain==7)) {
1180                                 proto_tree_add_item(tree, hf_snmp_engineid_cisco_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1181                                 offset++;
1182                                 len_remain--;
1183                         }
1184                         /* 6-byte MAC address */
1185                         if (len_remain==6) {
1186                                 proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, ENC_NA);
1187                                 offset+=6;
1188                                 len_remain=0;
1189                         }
1190                         break;
1191                 case SNMP_ENGINEID_FORMAT_TEXT:
1192                         /* max. 27-byte string, administratively assigned */
1193                         if (len_remain<=27) {
1194                                 proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, ENC_ASCII|ENC_NA);
1195                                 offset+=len_remain;
1196                                 len_remain=0;
1197                         }
1198                         break;
1199                 case 128:
1200                         /* most common enterprise-specific format: (ucd|net)-snmp random */
1201                         if ((enterpriseid==2021)||(enterpriseid==8072)) {
1202                                 proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
1203                                 /* demystify: 4B random, 4B epoch seconds */
1204                                 if (len_remain==8) {
1205                                         proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, ENC_NA);
1206                                         seconds = tvb_get_letohl(tvb, offset+4);
1207                                         ts.secs = seconds;
1208                                         ts.nsecs = 0;
1209                                         proto_tree_add_time_format_value(tree, hf_snmp_engineid_time, tvb, offset+4, 4,
1210                                                                          &ts, "%s",
1211                                                                          abs_time_secs_to_str(wmem_packet_scope(), seconds, ABSOLUTE_TIME_LOCAL, TRUE));
1212                                         offset+=8;
1213                                         len_remain=0;
1214                                 }
1215                         break;
1216                         }
1217                 /* fall through */
1218                 case SNMP_ENGINEID_FORMAT_OCTETS:
1219                 default:
1220                         /* max. 27 bytes, administratively assigned or unknown format */
1221                         if (len_remain<=27) {
1222                                 proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, ENC_NA);
1223                                 offset+=len_remain;
1224                                 len_remain=0;
1225                         }
1226                 break;
1227                 }
1228         }
1229
1230         if (len_remain>0) {
1231                 proto_tree_add_expert(tree, pinfo, &ei_snmp_rfc3411_non_conformant, tvb, offset, len_remain);
1232                 offset+=len_remain;
1233         }
1234         return offset;
1235 }
1236
1237
1238 static void set_ue_keys(snmp_ue_assoc_t* n ) {
1239         guint key_size = n->user.authModel->key_size;
1240
1241         n->user.authKey.data = (guint8 *)g_malloc(key_size);
1242         n->user.authKey.len = key_size;
1243         n->user.authModel->pass2key(n->user.authPassword.data,
1244                                     n->user.authPassword.len,
1245                                     n->engine.data,
1246                                     n->engine.len,
1247                                     n->user.authKey.data);
1248
1249         if (n->priv_proto == PRIV_AES128 || n->priv_proto == PRIV_AES192 || n->priv_proto == PRIV_AES256) {
1250                 guint need_key_len =
1251                         (n->priv_proto == PRIV_AES128) ? 16 :
1252                         (n->priv_proto == PRIV_AES192) ? 24 :
1253                         (n->priv_proto == PRIV_AES256) ? 32 :
1254                         0;
1255
1256                 guint key_len = key_size;
1257
1258                 while (key_len < need_key_len)
1259                         key_len += key_size;
1260
1261                 n->user.privKey.data = (guint8 *)g_malloc(key_len);
1262                 n->user.privKey.len  = need_key_len;
1263
1264                 n->user.authModel->pass2key(n->user.privPassword.data,
1265                                             n->user.privPassword.len,
1266                                             n->engine.data,
1267                                             n->engine.len,
1268                                             n->user.privKey.data);
1269
1270                 key_len = key_size;
1271
1272                 /* extend key if needed */
1273                 while (key_len < need_key_len) {
1274                         n->user.authModel->pass2key(
1275                                 n->user.privKey.data,
1276                                 key_len,
1277                                 n->engine.data,
1278                                 n->engine.len,
1279                                 n->user.privKey.data + key_len);
1280
1281                         key_len += key_size;
1282                 }
1283
1284         } else {
1285                 n->user.privKey.data = (guint8 *)g_malloc(key_size);
1286                 n->user.privKey.len = key_size;
1287                 n->user.authModel->pass2key(n->user.privPassword.data,
1288                                             n->user.privPassword.len,
1289                                             n->engine.data,
1290                                             n->engine.len,
1291                                             n->user.privKey.data);
1292         }
1293 }
1294
1295 static snmp_ue_assoc_t*
1296 ue_dup(snmp_ue_assoc_t* o)
1297 {
1298         snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)g_memdup(o,sizeof(snmp_ue_assoc_t));
1299
1300         d->user.authModel = o->user.authModel;
1301
1302         d->user.privProtocol = o->user.privProtocol;
1303
1304         d->user.userName.data = (guint8 *)g_memdup(o->user.userName.data,o->user.userName.len);
1305         d->user.userName.len = o->user.userName.len;
1306
1307         d->user.authPassword.data = o->user.authPassword.data ? (guint8 *)g_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1308         d->user.authPassword.len = o->user.authPassword.len;
1309
1310         d->user.privPassword.data = o->user.privPassword.data ? (guint8 *)g_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1311         d->user.privPassword.len = o->user.privPassword.len;
1312
1313         d->engine.len = o->engine.len;
1314
1315         if (d->engine.len) {
1316                 d->engine.data = (guint8 *)g_memdup(o->engine.data,o->engine.len);
1317                 set_ue_keys(d);
1318         }
1319
1320         return d;
1321
1322 }
1323
1324 static void*
1325 snmp_users_copy_cb(void* dest, const void* orig, size_t len _U_)
1326 {
1327         const snmp_ue_assoc_t* o = (const snmp_ue_assoc_t*)orig;
1328         snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)dest;
1329
1330         d->auth_model = o->auth_model;
1331         d->user.authModel = auth_models[o->auth_model];
1332
1333         d->priv_proto = o->priv_proto;
1334         d->user.privProtocol = priv_protos[o->priv_proto];
1335
1336         d->user.userName.data = (guint8*)g_memdup(o->user.userName.data,o->user.userName.len);
1337         d->user.userName.len = o->user.userName.len;
1338
1339         d->user.authPassword.data = o->user.authPassword.data ? (guint8*)g_memdup(o->user.authPassword.data,o->user.authPassword.len) : NULL;
1340         d->user.authPassword.len = o->user.authPassword.len;
1341
1342         d->user.privPassword.data = o->user.privPassword.data ? (guint8*)g_memdup(o->user.privPassword.data,o->user.privPassword.len) : NULL;
1343         d->user.privPassword.len = o->user.privPassword.len;
1344
1345         d->engine.len = o->engine.len;
1346         if (o->engine.data) {
1347                 d->engine.data = (guint8*)g_memdup(o->engine.data,o->engine.len);
1348         }
1349
1350         d->user.authKey.data = o->user.authKey.data ? (guint8*)g_memdup(o->user.authKey.data,o->user.authKey.len) : NULL;
1351         d->user.authKey.len = o->user.authKey.len;
1352
1353         d->user.privKey.data = o->user.privKey.data ? (guint8*)g_memdup(o->user.privKey.data,o->user.privKey.len) : NULL;
1354         d->user.privKey.len = o->user.privKey.len;
1355
1356         return d;
1357 }
1358
1359 static void
1360 snmp_users_free_cb(void* p)
1361 {
1362         snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1363         g_free(ue->user.userName.data);
1364         g_free(ue->user.authPassword.data);
1365         g_free(ue->user.privPassword.data);
1366         g_free(ue->user.authKey.data);
1367         g_free(ue->user.privKey.data);
1368         g_free(ue->engine.data);
1369 }
1370
1371 static gboolean
1372 snmp_users_update_cb(void* p _U_, char** err)
1373 {
1374         snmp_ue_assoc_t* ue = (snmp_ue_assoc_t*)p;
1375         GString* es = g_string_new("");
1376         unsigned int i;
1377
1378         *err = NULL;
1379
1380         if (num_ueas == 0)
1381                 /* Nothing to update */
1382                 return FALSE;
1383
1384         if (! ue->user.userName.len)
1385                 g_string_append_printf(es,"no userName\n");
1386
1387         for (i=0; i<num_ueas-1; i++) {
1388                 snmp_ue_assoc_t* u = &(ueas[i]);
1389
1390                 /* RFC 3411 section 5 */
1391                 if ((u->engine.len > 0) && (u->engine.len < 5 || u->engine.len > 32)) {
1392                         g_string_append_printf(es, "Invalid engineId length (%u). Must be between 5 and 32 (10 and 64 hex digits)\n", u->engine.len);
1393                 }
1394
1395
1396                 if ( u->user.userName.len == ue->user.userName.len
1397                         && u->engine.len == ue->engine.len && (u != ue)) {
1398
1399                         if (u->engine.len > 0 && memcmp( u->engine.data, ue->engine.data, u->engine.len ) == 0) {
1400                                 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1401                                         /* XXX: make a string for the engineId */
1402                                         g_string_append_printf(es,"Duplicate key (userName='%s')\n",ue->user.userName.data);
1403                                 }
1404                         }
1405
1406                         if (u->engine.len == 0) {
1407                                 if ( memcmp( u->user.userName.data, ue->user.userName.data, ue->user.userName.len ) == 0 ) {
1408                                         g_string_append_printf(es,"Duplicate key (userName='%s' engineId=NONE)\n",ue->user.userName.data);
1409                                 }
1410                         }
1411                 }
1412         }
1413
1414         if (es->len) {
1415                 es = g_string_truncate(es,es->len-1);
1416                 *err = g_string_free(es, FALSE);
1417                 return FALSE;
1418         }
1419
1420         return TRUE;
1421 }
1422
1423 static void
1424 free_ue_cache(snmp_ue_assoc_t **cache)
1425 {
1426         static snmp_ue_assoc_t *a, *nxt;
1427
1428         for (a = *cache; a; a = nxt) {
1429                 nxt = a->next;
1430                 snmp_users_free_cb(a);
1431                 g_free(a);
1432         }
1433
1434         *cache = NULL;
1435 }
1436
1437 #define CACHE_INSERT(c,a) if (c) { snmp_ue_assoc_t* t = c; c = a; c->next = t; } else { c = a; a->next = NULL; }
1438
1439 static void
1440 init_ue_cache(void)
1441 {
1442         guint i;
1443
1444         for (i = 0; i < num_ueas; i++) {
1445                 snmp_ue_assoc_t* a = ue_dup(&(ueas[i]));
1446
1447                 if (a->engine.len) {
1448                         CACHE_INSERT(localized_ues,a);
1449
1450                 } else {
1451                         CACHE_INSERT(unlocalized_ues,a);
1452                 }
1453
1454         }
1455 }
1456
1457 static void
1458 cleanup_ue_cache(void)
1459 {
1460         free_ue_cache(&localized_ues);
1461         free_ue_cache(&unlocalized_ues);
1462 }
1463
1464 /* Called when the user applies changes to UAT preferences. */
1465 static void
1466 renew_ue_cache(void)
1467 {
1468         cleanup_ue_cache();
1469         init_ue_cache();
1470 }
1471
1472
1473 static snmp_ue_assoc_t*
1474 localize_ue( snmp_ue_assoc_t* o, const guint8* engine, guint engine_len )
1475 {
1476         snmp_ue_assoc_t* n = (snmp_ue_assoc_t*)g_memdup(o,sizeof(snmp_ue_assoc_t));
1477
1478         n->engine.data = (guint8*)g_memdup(engine,engine_len);
1479         n->engine.len = engine_len;
1480
1481         set_ue_keys(n);
1482
1483         return n;
1484 }
1485
1486
1487 #define localized_match(a,u,ul,e,el) \
1488         ( a->user.userName.len == ul \
1489         && a->engine.len == el \
1490         && memcmp( a->user.userName.data, u, ul ) == 0 \
1491         && memcmp( a->engine.data,   e,  el ) == 0 )
1492
1493 #define unlocalized_match(a,u,l) \
1494         ( a->user.userName.len == l && memcmp( a->user.userName.data, u, l) == 0 )
1495
1496 static snmp_ue_assoc_t*
1497 get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb)
1498 {
1499         static snmp_ue_assoc_t* a;
1500         guint given_username_len;
1501         guint8* given_username;
1502         guint given_engine_len;
1503         guint8* given_engine;
1504
1505         if ( ! (localized_ues || unlocalized_ues ) ) return NULL;
1506
1507         if (! ( user_tvb && engine_tvb ) ) return NULL;
1508
1509         given_username_len = tvb_captured_length(user_tvb);
1510         given_engine_len = tvb_captured_length(engine_tvb);
1511         if (! ( given_engine_len && given_username_len ) ) return NULL;
1512         given_username = (guint8*)tvb_memdup(wmem_packet_scope(),user_tvb,0,-1);
1513         given_engine = (guint8*)tvb_memdup(wmem_packet_scope(),engine_tvb,0,-1);
1514
1515         for (a = localized_ues; a; a = a->next) {
1516                 if ( localized_match(a, given_username, given_username_len, given_engine, given_engine_len) ) {
1517                         return a;
1518                 }
1519         }
1520
1521         for (a = unlocalized_ues; a; a = a->next) {
1522                 if ( unlocalized_match(a, given_username, given_username_len) ) {
1523                         snmp_ue_assoc_t* n = localize_ue( a, given_engine, given_engine_len );
1524                         CACHE_INSERT(localized_ues,n);
1525                         return n;
1526                 }
1527         }
1528
1529         return NULL;
1530 }
1531
1532 static gboolean
1533 snmp_usm_auth_md5(snmp_usm_params_t* p, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error)
1534 {
1535         gint msg_len;
1536         guint8* msg;
1537         guint auth_len;
1538         guint8* auth;
1539         guint8* key;
1540         guint key_len;
1541         guint8 *calc_auth;
1542         guint start;
1543         guint end;
1544         guint i;
1545
1546         if (!p->auth_tvb) {
1547                 *error = "No Authenticator";
1548                 return FALSE;
1549         }
1550
1551         key = p->user_assoc->user.authKey.data;
1552         key_len = p->user_assoc->user.authKey.len;
1553
1554         if (! key ) {
1555                 *error = "User has no authKey";
1556                 return FALSE;
1557         }
1558
1559
1560         auth_len = tvb_captured_length(p->auth_tvb);
1561
1562         if (auth_len != 12) {
1563                 *error = "Authenticator length wrong";
1564                 return FALSE;
1565         }
1566
1567         msg_len = tvb_captured_length(p->msg_tvb);
1568         if (msg_len <= 0) {
1569                 *error = "Not enough data remaining";
1570                 return FALSE;
1571         }
1572         msg = (guint8*)tvb_memdup(wmem_packet_scope(),p->msg_tvb,0,msg_len);
1573
1574
1575         auth = (guint8*)tvb_memdup(wmem_packet_scope(),p->auth_tvb,0,auth_len);
1576
1577         start = p->auth_offset - p->start_offset;
1578         end =   start + auth_len;
1579
1580         /* fill the authenticator with zeros */
1581         for ( i = start ; i < end ; i++ ) {
1582                 msg[i] = '\0';
1583         }
1584
1585         calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), 16);
1586
1587         md5_hmac(msg, msg_len, key, key_len, calc_auth);
1588
1589         if (calc_auth_p) *calc_auth_p = calc_auth;
1590         if (calc_auth_len_p) *calc_auth_len_p = 12;
1591
1592         return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE;
1593 }
1594
1595
1596 static gboolean
1597 snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error _U_)
1598 {
1599         gint msg_len;
1600         guint8* msg;
1601         guint auth_len;
1602         guint8* auth;
1603         guint8* key;
1604         guint key_len;
1605         guint8 *calc_auth;
1606         guint start;
1607         guint end;
1608         guint i;
1609
1610         if (!p->auth_tvb) {
1611                 *error = "No Authenticator";
1612                 return FALSE;
1613         }
1614
1615         key = p->user_assoc->user.authKey.data;
1616         key_len = p->user_assoc->user.authKey.len;
1617
1618         if (! key ) {
1619                 *error = "User has no authKey";
1620                 return FALSE;
1621         }
1622
1623
1624         auth_len = tvb_captured_length(p->auth_tvb);
1625
1626
1627         if (auth_len != 12) {
1628                 *error = "Authenticator length wrong";
1629                 return FALSE;
1630         }
1631
1632         msg_len = tvb_captured_length(p->msg_tvb);
1633         if (msg_len <= 0) {
1634                 *error = "Not enough data remaining";
1635                 return FALSE;
1636         }
1637         msg = (guint8*)tvb_memdup(wmem_packet_scope(),p->msg_tvb,0,msg_len);
1638
1639         auth = (guint8*)tvb_memdup(wmem_packet_scope(),p->auth_tvb,0,auth_len);
1640
1641         start = p->auth_offset - p->start_offset;
1642         end =   start + auth_len;
1643
1644         /* fill the authenticator with zeros */
1645         for ( i = start ; i < end ; i++ ) {
1646                 msg[i] = '\0';
1647         }
1648
1649         calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), SHA1_DIGEST_LEN);
1650
1651         sha1_hmac(key, key_len, msg, msg_len, calc_auth);
1652
1653         if (calc_auth_p) *calc_auth_p = calc_auth;
1654         if (calc_auth_len_p) *calc_auth_len_p = 12;
1655
1656         return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE;
1657 }
1658
1659 static tvbuff_t*
1660 snmp_usm_priv_des(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error _U_)
1661 {
1662 #ifdef HAVE_LIBGCRYPT
1663         gcry_error_t err;
1664         gcry_cipher_hd_t hd = NULL;
1665
1666         guint8* cleartext;
1667         guint8* des_key = p->user_assoc->user.privKey.data; /* first 8 bytes */
1668         guint8* pre_iv = &(p->user_assoc->user.privKey.data[8]); /* last 8 bytes */
1669         guint8* salt;
1670         gint salt_len;
1671         gint cryptgrm_len;
1672         guint8* cryptgrm;
1673         tvbuff_t* clear_tvb;
1674         guint8 iv[8];
1675         guint i;
1676
1677
1678         salt_len = tvb_captured_length(p->priv_tvb);
1679
1680         if (salt_len != 8) {
1681                 *error = "decryptionError: msgPrivacyParameters length != 8";
1682                 return NULL;
1683         }
1684
1685         salt = (guint8*)tvb_memdup(wmem_packet_scope(),p->priv_tvb,0,salt_len);
1686
1687         /*
1688          The resulting "salt" is XOR-ed with the pre-IV to obtain the IV.
1689          */
1690         for (i=0; i<8; i++) {
1691                 iv[i] = pre_iv[i] ^ salt[i];
1692         }
1693
1694         cryptgrm_len = tvb_captured_length(encryptedData);
1695
1696         if ((cryptgrm_len <= 0) || (cryptgrm_len % 8)) {
1697                 *error = "decryptionError: the length of the encrypted data is not a mutiple of 8 octets";
1698                 return NULL;
1699         }
1700
1701         cryptgrm = (guint8*)tvb_memdup(wmem_packet_scope(),encryptedData,0,-1);
1702
1703         cleartext = (guint8*)g_malloc(cryptgrm_len);
1704
1705         err = gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0);
1706         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1707
1708         err = gcry_cipher_setiv(hd, iv, 8);
1709         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1710
1711         err = gcry_cipher_setkey(hd,des_key,8);
1712         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1713
1714         err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1715         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1716
1717         gcry_cipher_close(hd);
1718
1719         clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
1720         tvb_set_free_cb(clear_tvb, g_free);
1721
1722         return clear_tvb;
1723
1724 on_gcry_error:
1725         g_free(cleartext);
1726         *error = (const gchar *)gpg_strerror(err);
1727         if (hd) gcry_cipher_close(hd);
1728         return NULL;
1729 #else
1730         *error = "libgcrypt not present, cannot decrypt";
1731         return NULL;
1732 #endif
1733 }
1734
1735 #ifdef HAVE_LIBGCRYPT
1736 static tvbuff_t*
1737 snmp_usm_priv_aes_common(snmp_usm_params_t* p, tvbuff_t* encryptedData, gchar const** error, int algo)
1738 {
1739         gcry_error_t err;
1740         gcry_cipher_hd_t hd = NULL;
1741
1742         guint8* cleartext;
1743         guint8* aes_key = p->user_assoc->user.privKey.data;
1744         int aes_key_len = p->user_assoc->user.privKey.len;
1745         guint8 iv[16];
1746         gint priv_len;
1747         gint cryptgrm_len;
1748         guint8* cryptgrm;
1749         tvbuff_t* clear_tvb;
1750
1751         priv_len = tvb_captured_length(p->priv_tvb);
1752
1753         if (priv_len != 8) {
1754                 *error = "decryptionError: msgPrivacyParameters length != 8";
1755                 return NULL;
1756         }
1757
1758         iv[0] = (p->boots & 0xff000000) >> 24;
1759         iv[1] = (p->boots & 0x00ff0000) >> 16;
1760         iv[2] = (p->boots & 0x0000ff00) >> 8;
1761         iv[3] = (p->boots & 0x000000ff);
1762         iv[4] = (p->snmp_time & 0xff000000) >> 24;
1763         iv[5] = (p->snmp_time & 0x00ff0000) >> 16;
1764         iv[6] = (p->snmp_time & 0x0000ff00) >> 8;
1765         iv[7] = (p->snmp_time & 0x000000ff);
1766         tvb_memcpy(p->priv_tvb,&(iv[8]),0,8);
1767
1768         cryptgrm_len = tvb_captured_length(encryptedData);
1769         if (cryptgrm_len <= 0) {
1770                 *error = "Not enough data remaining";
1771                 return NULL;
1772         }
1773         cryptgrm = (guint8*)tvb_memdup(wmem_packet_scope(),encryptedData,0,-1);
1774
1775         cleartext = (guint8*)g_malloc(cryptgrm_len);
1776
1777         err = gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CFB, 0);
1778         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1779
1780         err = gcry_cipher_setiv(hd, iv, 16);
1781         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1782
1783         err = gcry_cipher_setkey(hd,aes_key,aes_key_len);
1784         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1785
1786         err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len);
1787         if (err != GPG_ERR_NO_ERROR) goto on_gcry_error;
1788
1789         gcry_cipher_close(hd);
1790
1791         clear_tvb = tvb_new_child_real_data(encryptedData, cleartext, cryptgrm_len, cryptgrm_len);
1792         tvb_set_free_cb(clear_tvb, g_free);
1793
1794         return clear_tvb;
1795
1796 on_gcry_error:
1797         g_free(cleartext);
1798         *error = (const gchar *)gpg_strerror(err);
1799         if (hd) gcry_cipher_close(hd);
1800         return NULL;
1801 }
1802 #endif
1803
1804 static tvbuff_t*
1805 snmp_usm_priv_aes128(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error)
1806 {
1807 #ifdef HAVE_LIBGCRYPT
1808         return snmp_usm_priv_aes_common(p, encryptedData, error, GCRY_CIPHER_AES);
1809 #else
1810         *error = "libgcrypt not present, cannot decrypt";
1811         return NULL;
1812 #endif
1813 }
1814
1815 static tvbuff_t*
1816 snmp_usm_priv_aes192(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error)
1817 {
1818 #ifdef HAVE_LIBGCRYPT
1819         return snmp_usm_priv_aes_common(p, encryptedData, error, GCRY_CIPHER_AES192);
1820 #else
1821         *error = "libgcrypt not present, cannot decrypt";
1822         return NULL;
1823 #endif
1824 }
1825
1826 static tvbuff_t*
1827 snmp_usm_priv_aes256(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar const** error)
1828 {
1829 #ifdef HAVE_LIBGCRYPT
1830         return snmp_usm_priv_aes_common(p, encryptedData, error, GCRY_CIPHER_AES256);
1831 #else
1832         *error = "libgcrypt not present, cannot decrypt";
1833         return NULL;
1834 #endif
1835 }
1836
1837 static gboolean
1838 check_ScopedPdu(tvbuff_t* tvb)
1839 {
1840         int offset;
1841         gint8 ber_class;
1842         gboolean pc;
1843         gint32 tag;
1844         int hoffset, eoffset;
1845         guint32 len;
1846
1847         offset = get_ber_identifier(tvb, 0, &ber_class, &pc, &tag);
1848         offset = get_ber_length(tvb, offset, NULL, NULL);
1849
1850         if ( ! (((ber_class!=BER_CLASS_APP) && (ber_class!=BER_CLASS_PRI) )
1851                         && ( (!pc) || (ber_class!=BER_CLASS_UNI) || (tag!=BER_UNI_TAG_ENUMERATED) )
1852                         )) return FALSE;
1853
1854         if((tvb_get_guint8(tvb, offset)==0)&&(tvb_get_guint8(tvb, offset+1)==0))
1855                 return TRUE;
1856
1857         hoffset = offset;
1858
1859         offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
1860         offset = get_ber_length(tvb, offset, &len, NULL);
1861         eoffset = offset + len;
1862
1863         if (eoffset <= hoffset) return FALSE;
1864
1865         if ((ber_class!=BER_CLASS_APP)&&(ber_class!=BER_CLASS_PRI))
1866                 if( (ber_class!=BER_CLASS_UNI)
1867                         ||((tag<BER_UNI_TAG_NumericString)&&(tag!=BER_UNI_TAG_OCTETSTRING)&&(tag!=BER_UNI_TAG_UTF8String)) )
1868                         return FALSE;
1869
1870         return TRUE;
1871
1872 }
1873
1874 #include "packet-snmp-fn.c"
1875
1876
1877 guint
1878 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
1879                  proto_tree *tree, int proto, gint ett, gboolean is_tcp)
1880 {
1881
1882         guint length_remaining;
1883         gint8 ber_class;
1884         gboolean pc, ind = 0;
1885         gint32 tag;
1886         guint32 len;
1887         guint message_length;
1888         int start_offset = offset;
1889         guint32 version = 0;
1890         tvbuff_t        *next_tvb;
1891
1892         proto_tree *snmp_tree = NULL;
1893         proto_item *item = NULL;
1894         asn1_ctx_t asn1_ctx;
1895         asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo);
1896
1897
1898         usm_p.msg_tvb = tvb;
1899         usm_p.start_offset = tvb_offset_from_real_beginning(tvb);
1900         usm_p.engine_tvb = NULL;
1901         usm_p.user_tvb = NULL;
1902         usm_p.auth_item = NULL;
1903         usm_p.auth_tvb = NULL;
1904         usm_p.auth_offset = 0;
1905         usm_p.priv_tvb = NULL;
1906         usm_p.user_assoc = NULL;
1907         usm_p.authenticated = FALSE;
1908         usm_p.encrypted = FALSE;
1909         usm_p.boots = 0;
1910         usm_p.snmp_time = 0;
1911         usm_p.authOK = FALSE;
1912
1913         /*
1914          * This will throw an exception if we don't have any data left.
1915          * That's what we want.  (See "tcp_dissect_pdus()", which is
1916          * similar, but doesn't have to deal with ASN.1.
1917          * XXX - can we make "tcp_dissect_pdus()" provide enough
1918          * information to the "get_pdu_len" routine so that we could
1919          * have that routine deal with ASN.1, and just use
1920          * "tcp_dissect_pdus()"?)
1921          */
1922         length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
1923
1924         /* NOTE: we have to parse the message piece by piece, since the
1925          * capture length may be less than the message length: a 'global'
1926          * parsing is likely to fail.
1927          */
1928
1929         /*
1930          * If this is SNMP-over-TCP, we might have to do reassembly
1931          * in order to read the "Sequence Of" header.
1932          */
1933         if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1934                 /*
1935                  * This is TCP, and we should, and can, do reassembly.
1936                  *
1937                  * Is the "Sequence Of" header split across segment
1938                  * boundaries?  We require at least 6 bytes for the
1939                  * header, which allows for a 4-byte length (ASN.1
1940                  * BER).
1941                  */
1942                 if (length_remaining < 6) {
1943                         /*
1944                          * Yes.  Tell the TCP dissector where the data
1945                          * for this message starts in the data it handed
1946                          * us and that we need "some more data."  Don't tell
1947                          * it exactly how many bytes we need because if/when
1948                          * we ask for even more (after the header) that will
1949                          * break reassembly.
1950                          */
1951                         pinfo->desegment_offset = offset;
1952                         pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
1953
1954                         /*
1955                          * Return 0, which means "I didn't dissect anything
1956                          * because I don't have enough data - we need
1957                          * to desegment".
1958                          */
1959                         return 0;
1960                 }
1961         }
1962
1963         /*
1964          * OK, try to read the "Sequence Of" header; this gets the total
1965          * length of the SNMP message.
1966          */
1967         offset = get_ber_identifier(tvb, offset, &ber_class, &pc, &tag);
1968         /*Get the total octet length of the SNMP data*/
1969         offset = get_ber_length(tvb, offset, &len, &ind);
1970         message_length = len + offset;
1971
1972         /*Get the SNMP version data*/
1973         /*offset =*/ dissect_ber_integer(FALSE, &asn1_ctx, 0, tvb, offset, -1, &version);
1974
1975
1976         /*
1977          * If this is SNMP-over-TCP, we might have to do reassembly
1978          * to get all of this message.
1979          */
1980         if (is_tcp && snmp_desegment && pinfo->can_desegment) {
1981                 /*
1982                  * Yes - is the message split across segment boundaries?
1983                  */
1984                 if (length_remaining < message_length) {
1985                         /*
1986                          * Yes.  Tell the TCP dissector where the data
1987                          * for this message starts in the data it handed
1988                          * us, and how many more bytes we need, and
1989                          * return.
1990                          */
1991                         pinfo->desegment_offset = start_offset;
1992                         pinfo->desegment_len =
1993                         message_length - length_remaining;
1994
1995                         /*
1996                          * Return 0, which means "I didn't dissect anything
1997                          * because I don't have enough data - we need
1998                          * to desegment".
1999                          */
2000                         return 0;
2001                 }
2002         }
2003
2004         next_tvb_init(&var_list);
2005
2006         col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_get_protocol_short_name(find_protocol_by_id(proto)));
2007
2008         item = proto_tree_add_item(tree, proto, tvb, start_offset, message_length, ENC_BIG_ENDIAN);
2009         snmp_tree = proto_item_add_subtree(item, ett);
2010
2011         switch (version) {
2012         case 0: /* v1 */
2013         case 1: /* v2c */
2014                 offset = dissect_snmp_Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
2015                 break;
2016         case 2: /* v2u */
2017                 offset = dissect_snmp_Messagev2u(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
2018                 break;
2019                         /* v3 */
2020         case 3:
2021                 offset = dissect_snmp_SNMPv3Message(FALSE , tvb, start_offset, &asn1_ctx, snmp_tree, -1);
2022                 break;
2023         default:
2024                 /*
2025                  * Return the length remaining in the tvbuff, so
2026                  * if this is SNMP-over-TCP, our caller thinks there's
2027                  * nothing left to dissect.
2028                  */
2029                 expert_add_info(pinfo, item, &ei_snmp_version_unknown);
2030                 return length_remaining;
2031                 break;
2032         }
2033
2034         /* There may be appended data after the SNMP data, so treat as raw
2035          * data which needs to be dissected in case of UDP as UDP is PDU oriented.
2036          */
2037         if((!is_tcp) && (length_remaining > (guint)offset)) {
2038                 next_tvb = tvb_new_subset_remaining(tvb, offset);
2039                 call_dissector(data_handle, next_tvb, pinfo, tree);
2040         } else {
2041                 next_tvb_call(&var_list, pinfo, tree, NULL, data_handle);
2042         }
2043
2044         return offset;
2045 }
2046
2047 static gint
2048 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
2049 {
2050         conversation_t *conversation;
2051         int offset;
2052         gint8 tmp_class;
2053         gboolean tmp_pc;
2054         gint32 tmp_tag;
2055         guint32 tmp_length;
2056         gboolean tmp_ind;
2057
2058         /*
2059          * See if this looks like SNMP or not. if not, return 0 so
2060          * wireshark can try som other dissector instead.
2061          */
2062         /* All SNMP packets are BER encoded and consist of a SEQUENCE
2063          * that spans the entire PDU. The first item is an INTEGER that
2064          * has the values 0-2 (version 1-3).
2065          * if not it is not snmp.
2066          */
2067         /* SNMP starts with a SEQUENCE */
2068         offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
2069         if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)) {
2070                 return 0;
2071         }
2072         /* then comes a length which spans the rest of the tvb */
2073         offset = get_ber_length(tvb, offset, &tmp_length, &tmp_ind);
2074         /* if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)) {
2075          * Losen the heuristic a bit to handle the case where data has intentionally
2076          * been added after the snmp PDU ( UDP case)
2077          */
2078         if ( pinfo->ptype == PT_UDP ) {
2079                 if(tmp_length>(guint32)tvb_reported_length_remaining(tvb, offset)) {
2080                         return 0;
2081                 }
2082         }else{
2083                 if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)) {
2084                         return 0;
2085                 }
2086         }
2087         /* then comes an INTEGER (version)*/
2088         get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
2089         if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)) {
2090                 return 0;
2091         }
2092         /* do we need to test that version is 0 - 2 (version1-3) ? */
2093
2094
2095         /*
2096          * The first SNMP packet goes to the SNMP port; the second one
2097          * may come from some *other* port, but goes back to the same
2098          * IP address and port as the ones from which the first packet
2099          * came; all subsequent packets presumably go between those two
2100          * IP addresses and ports.
2101          *
2102          * If this packet went to the SNMP port, we check to see if
2103          * there's already a conversation with one address/port pair
2104          * matching the source IP address and port of this packet,
2105          * the other address matching the destination IP address of this
2106          * packet, and any destination port.
2107          *
2108          * If not, we create one, with its address 1/port 1 pair being
2109          * the source address/port of this packet, its address 2 being
2110          * the destination address of this packet, and its port 2 being
2111          * wildcarded, and give it the SNMP dissector as a dissector.
2112          */
2113         if (pinfo->destport == UDP_PORT_SNMP) {
2114                 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
2115                                            pinfo->srcport, 0, NO_PORT_B);
2116                 if( (conversation == NULL) || (conversation_get_dissector(conversation, pinfo->fd->num)!=snmp_handle) ) {
2117                         conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
2118                                             pinfo->srcport, 0, NO_PORT2);
2119                         conversation_set_dissector(conversation, snmp_handle);
2120                 }
2121         }
2122
2123         return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
2124 }
2125
2126 static void
2127 dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2128 {
2129         int offset = 0;
2130         guint message_len;
2131
2132         while (tvb_reported_length_remaining(tvb, offset) > 0) {
2133                 message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, TRUE);
2134                 if (message_len == 0) {
2135                         /*
2136                          * We don't have all the data for that message,
2137                          * so we need to do desegmentation;
2138                          * "dissect_snmp_pdu()" has set that up.
2139                          */
2140                         break;
2141                 }
2142                 offset += message_len;
2143         }
2144 }
2145
2146 static int
2147 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2148 {
2149         proto_tree *smux_tree = NULL;
2150         proto_item *item = NULL;
2151
2152         next_tvb_init(&var_list);
2153
2154         col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMUX");
2155
2156         item = proto_tree_add_item(tree, proto_smux, tvb, 0, -1, ENC_NA);
2157         smux_tree = proto_item_add_subtree(item, ett_smux);
2158
2159         return dissect_SMUX_PDUs_PDU(tvb, pinfo, smux_tree, data);
2160 }
2161
2162
2163 /*
2164   MD5 Password to Key Algorithm
2165   from RFC 3414 A.2.1
2166 */
2167 static void
2168 snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen,
2169                              const guint8 *engineID, guint engineLength,
2170                              guint8 *key)
2171 {
2172         md5_state_t     MD;
2173         guint8          *cp, password_buf[64];
2174         guint32         password_index = 0;
2175         guint32         count = 0, i;
2176         guint8          key1[16];
2177         md5_init(&MD);   /* initialize MD5 */
2178
2179         /**********************************************/
2180         /* Use while loop until we've done 1 Megabyte */
2181         /**********************************************/
2182         while (count < 1048576) {
2183                 cp = password_buf;
2184                 if (passwordlen != 0) {
2185                         for (i = 0; i < 64; i++) {
2186                                 /*************************************************/
2187                                 /* Take the next octet of the password, wrapping */
2188                                 /* to the beginning of the password as necessary.*/
2189                                 /*************************************************/
2190                                 *cp++ = password[password_index++ % passwordlen];
2191                         }
2192                 } else {
2193                         *cp = 0;
2194                 }
2195                 md5_append(&MD, password_buf, 64);
2196                 count += 64;
2197         }
2198         md5_finish(&MD, key1); /* tell MD5 we're done */
2199
2200         /*****************************************************/
2201         /* Now localize the key with the engineID and pass   */
2202         /* through MD5 to produce final key                  */
2203         /* We ignore invalid engineLengths here. More strict */
2204         /* checking is done in snmp_users_update_cb.         */
2205         /*****************************************************/
2206
2207         md5_init(&MD);
2208         md5_append(&MD, key1, 16);
2209         md5_append(&MD, engineID, engineLength);
2210         md5_append(&MD, key1, 16);
2211         md5_finish(&MD, key);
2212
2213         return;
2214 }
2215
2216
2217
2218
2219 /*
2220    SHA1 Password to Key Algorithm COPIED from RFC 3414 A.2.2
2221  */
2222
2223 static void
2224 snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen,
2225                               const guint8 *engineID, guint engineLength,
2226                               guint8 *key)
2227 {
2228         sha1_context    SH;
2229         guint8          *cp, password_buf[64];
2230         guint32         password_index = 0;
2231         guint32         count = 0, i;
2232
2233         sha1_starts(&SH); /* initialize SHA */
2234
2235         /**********************************************/
2236         /* Use while loop until we've done 1 Megabyte */
2237         /**********************************************/
2238         while (count < 1048576) {
2239                 cp = password_buf;
2240                 if (passwordlen != 0) {
2241                         for (i = 0; i < 64; i++) {
2242                                 /*************************************************/
2243                                 /* Take the next octet of the password, wrapping */
2244                                 /* to the beginning of the password as necessary.*/
2245                                 /*************************************************/
2246                                 *cp++ = password[password_index++ % passwordlen];
2247                         }
2248                 } else {
2249                         *cp = 0;
2250                 }
2251                 sha1_update (&SH, password_buf, 64);
2252                 count += 64;
2253         }
2254         sha1_finish(&SH, key);
2255
2256         /*****************************************************/
2257         /* Now localize the key with the engineID and pass   */
2258         /* through SHA to produce final key                  */
2259         /* We ignore invalid engineLengths here. More strict */
2260         /* checking is done in snmp_users_update_cb.         */
2261         /*****************************************************/
2262
2263         sha1_starts(&SH);
2264         sha1_update(&SH, key, SHA1_DIGEST_LEN);
2265         sha1_update(&SH, engineID, engineLength);
2266         sha1_update(&SH, key, SHA1_DIGEST_LEN);
2267         sha1_finish(&SH, key);
2268         return;
2269  }
2270
2271
2272 static void
2273 process_prefs(void)
2274 {
2275 }
2276
2277 UAT_LSTRING_CB_DEF(snmp_users,userName,snmp_ue_assoc_t,user.userName.data,user.userName.len)
2278 UAT_LSTRING_CB_DEF(snmp_users,authPassword,snmp_ue_assoc_t,user.authPassword.data,user.authPassword.len)
2279 UAT_LSTRING_CB_DEF(snmp_users,privPassword,snmp_ue_assoc_t,user.privPassword.data,user.privPassword.len)
2280 UAT_BUFFER_CB_DEF(snmp_users,engine_id,snmp_ue_assoc_t,engine.data,engine.len)
2281 UAT_VS_DEF(snmp_users,auth_model,snmp_ue_assoc_t,guint,0,"MD5")
2282 UAT_VS_DEF(snmp_users,priv_proto,snmp_ue_assoc_t,guint,0,"DES")
2283
2284 static void *
2285 snmp_specific_trap_copy_cb(void *dest, const void *orig, size_t len _U_)
2286 {
2287         snmp_st_assoc_t *u = (snmp_st_assoc_t *)dest;
2288         const snmp_st_assoc_t *o = (const snmp_st_assoc_t *)orig;
2289
2290         u->enterprise = g_strdup(o->enterprise);
2291         u->trap = o->trap;
2292         u->desc = g_strdup(o->desc);
2293
2294         return dest;
2295 }
2296
2297 static void
2298 snmp_specific_trap_free_cb(void *r)
2299 {
2300         snmp_st_assoc_t *u = (snmp_st_assoc_t *)r;
2301
2302         g_free(u->enterprise);
2303         g_free(u->desc);
2304 }
2305
2306 UAT_CSTRING_CB_DEF(specific_traps, enterprise, snmp_st_assoc_t)
2307 UAT_DEC_CB_DEF(specific_traps, trap, snmp_st_assoc_t)
2308 UAT_CSTRING_CB_DEF(specific_traps, desc, snmp_st_assoc_t)
2309
2310         /*--- proto_register_snmp -------------------------------------------*/
2311 void proto_register_snmp(void) {
2312         /* List of fields */
2313         static hf_register_info hf[] = {
2314                 { &hf_snmp_v3_flags_auth,
2315                 { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
2316                     TFS(&tfs_set_notset), TH_AUTH, NULL, HFILL }},
2317                 { &hf_snmp_v3_flags_crypt,
2318                 { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
2319                     TFS(&tfs_set_notset), TH_CRYPT, NULL, HFILL }},
2320                 { &hf_snmp_v3_flags_report,
2321                 { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
2322                     TFS(&tfs_set_notset), TH_REPORT, NULL, HFILL }},
2323                 { &hf_snmp_engineid_conform, {
2324                     "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
2325                     TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
2326                 { &hf_snmp_engineid_enterprise, {
2327                     "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_DEC|BASE_EXT_STRING,
2328                     &sminmpec_values_ext, 0, NULL, HFILL }},
2329                 { &hf_snmp_engineid_format, {
2330                     "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
2331                     VALS(snmp_engineid_format_vals), 0, NULL, HFILL }},
2332                 { &hf_snmp_engineid_ipv4, {
2333                     "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
2334                     NULL, 0, NULL, HFILL }},
2335                 { &hf_snmp_engineid_ipv6, {
2336                     "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
2337                     NULL, 0, NULL, HFILL }},
2338                 { &hf_snmp_engineid_cisco_type, {
2339                     "Engine ID Data: Cisco type", "snmp.engineid.cisco.type", FT_UINT8, BASE_HEX,
2340                     VALS(snmp_engineid_cisco_type_vals), 0, NULL, HFILL }},
2341                 { &hf_snmp_engineid_mac, {
2342                     "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
2343                     NULL, 0, NULL, HFILL }},
2344                 { &hf_snmp_engineid_text, {
2345                     "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
2346                     NULL, 0, NULL, HFILL }},
2347                 { &hf_snmp_engineid_time, {
2348                     "Engine ID Data: Creation Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
2349                     NULL, 0, NULL, HFILL }},
2350                 { &hf_snmp_engineid_data, {
2351                     "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_NONE,
2352                     NULL, 0, NULL, HFILL }},
2353                 { &hf_snmp_msgAuthentication, {
2354                     "Authentication", "snmp.v3.auth", FT_BOOLEAN, BASE_NONE,
2355                     TFS(&auth_flags), 0, NULL, HFILL }},
2356                 { &hf_snmp_decryptedPDU, {
2357                     "Decrypted ScopedPDU", "snmp.decrypted_pdu", FT_BYTES, BASE_NONE,
2358                     NULL, 0, "Decrypted PDU", HFILL }},
2359                 { &hf_snmp_noSuchObject, {
2360                     "noSuchObject", "snmp.noSuchObject", FT_NONE, BASE_NONE,
2361                     NULL, 0, NULL, HFILL }},
2362                 { &hf_snmp_noSuchInstance, {
2363                     "noSuchInstance", "snmp.noSuchInstance", FT_NONE, BASE_NONE,
2364                     NULL, 0, NULL, HFILL }},
2365                 { &hf_snmp_endOfMibView, {
2366                     "endOfMibView", "snmp.endOfMibView", FT_NONE, BASE_NONE,
2367                     NULL, 0, NULL, HFILL }},
2368                 { &hf_snmp_unSpecified, {
2369                     "unSpecified", "snmp.unSpecified", FT_NONE, BASE_NONE,
2370                     NULL, 0, NULL, HFILL }},
2371
2372                 { &hf_snmp_integer32_value, {
2373                     "Value (Integer32)", "snmp.value.int", FT_INT64, BASE_DEC,
2374                     NULL, 0, NULL, HFILL }},
2375                 { &hf_snmp_octetstring_value, {
2376                     "Value (OctetString)", "snmp.value.octets", FT_BYTES, BASE_NONE,
2377                     NULL, 0, NULL, HFILL }},
2378                 { &hf_snmp_oid_value, {
2379                     "Value (OID)", "snmp.value.oid", FT_OID, BASE_NONE,
2380                     NULL, 0, NULL, HFILL }},
2381                 { &hf_snmp_null_value, {
2382                     "Value (Null)", "snmp.value.null", FT_NONE, BASE_NONE,
2383                     NULL, 0, NULL, HFILL }},
2384                 { &hf_snmp_ipv4_value, {
2385                     "Value (IpAddress)", "snmp.value.ipv4", FT_IPv4, BASE_NONE,
2386                     NULL, 0, NULL, HFILL }},
2387                 { &hf_snmp_ipv6_value, {
2388                     "Value (IpAddress)", "snmp.value.ipv6", FT_IPv6, BASE_NONE,
2389                     NULL, 0, NULL, HFILL }},
2390                 { &hf_snmp_anyaddress_value, {
2391                     "Value (IpAddress)", "snmp.value.addr", FT_BYTES, BASE_NONE,
2392                     NULL, 0, NULL, HFILL }},
2393                 { &hf_snmp_unsigned32_value, {
2394                     "Value (Unsigned32)", "snmp.value.u32", FT_INT64, BASE_DEC,
2395                     NULL, 0, NULL, HFILL }},
2396                 { &hf_snmp_gauge32_value, {
2397                     "Value (Gauge32)", "snmp.value.g32", FT_INT64, BASE_DEC,
2398                     NULL, 0, NULL, HFILL }},
2399                 { &hf_snmp_unknown_value, {
2400                     "Value (Unknown)", "snmp.value.unk", FT_BYTES, BASE_NONE,
2401                     NULL, 0, NULL, HFILL }},
2402                 { &hf_snmp_counter_value, {
2403                     "Value (Counter32)", "snmp.value.counter", FT_UINT64, BASE_DEC,
2404                     NULL, 0, NULL, HFILL }},
2405                 { &hf_snmp_big_counter_value, {
2406                     "Value (Counter64)", "snmp.value.counter", FT_UINT64, BASE_DEC,
2407                     NULL, 0, NULL, HFILL }},
2408                 { &hf_snmp_nsap_value, {
2409                     "Value (NSAP)", "snmp.value.nsap", FT_UINT64, BASE_DEC,
2410                     NULL, 0, NULL, HFILL }},
2411                 { &hf_snmp_timeticks_value, {
2412                     "Value (Timeticks)", "snmp.value.timeticks", FT_UINT64, BASE_DEC,
2413                     NULL, 0, NULL, HFILL }},
2414                 { &hf_snmp_opaque_value, {
2415                     "Value (Opaque)", "snmp.value.opaque", FT_BYTES, BASE_NONE,
2416                     NULL, 0, NULL, HFILL }},
2417                 { &hf_snmp_objectname, {
2418                     "Object Name", "snmp.name", FT_OID, BASE_NONE,
2419                     NULL, 0, NULL, HFILL }},
2420                 { &hf_snmp_scalar_instance_index, {
2421                     "Scalar Instance Index", "snmp.name.index", FT_UINT64, BASE_DEC,
2422                     NULL, 0, NULL, HFILL }},
2423                 { &hf_snmp_var_bind_str, {
2424                     "Variable-binding-string", "snmp.var-bind_str", FT_STRING, BASE_NONE,
2425                     NULL, 0, NULL, HFILL }},
2426                 { &hf_snmp_agentid_trailer, {
2427                     "AgentID Trailer", "snmp.agentid_trailer", FT_BYTES, BASE_NONE,
2428                     NULL, 0, NULL, HFILL }},
2429
2430
2431 #include "packet-snmp-hfarr.c"
2432         };
2433
2434         /* List of subtrees */
2435         static gint *ett[] = {
2436                 &ett_snmp,
2437                 &ett_engineid,
2438                 &ett_msgFlags,
2439                 &ett_encryptedPDU,
2440                 &ett_decrypted,
2441                 &ett_authParameters,
2442                 &ett_internet,
2443                 &ett_varbind,
2444                 &ett_name,
2445                 &ett_value,
2446                 &ett_decoding_error,
2447 #include "packet-snmp-ettarr.c"
2448         };
2449         static ei_register_info ei[] = {
2450                 { &ei_snmp_failed_decrypted_data_pdu, { "snmp.failed_decrypted_data_pdu", PI_MALFORMED, PI_WARN, "Failed to decrypt encryptedPDU", EXPFILL }},
2451                 { &ei_snmp_decrypted_data_bad_formatted, { "snmp.decrypted_data_bad_formatted", PI_MALFORMED, PI_WARN, "Decrypted data not formatted as expected, wrong key?", EXPFILL }},
2452                 { &ei_snmp_verify_authentication_error, { "snmp.verify_authentication_error", PI_MALFORMED, PI_ERROR, "Error while verifying Message authenticity", EXPFILL }},
2453                 { &ei_snmp_authentication_ok, { "snmp.authentication_ok", PI_CHECKSUM, PI_CHAT, "SNMP Authentication OK", EXPFILL }},
2454                 { &ei_snmp_authentication_error, { "snmp.authentication_error", PI_CHECKSUM, PI_WARN, "SNMP Authentication Error", EXPFILL }},
2455                 { &ei_snmp_varbind_not_uni_class_seq, { "snmp.varbind.not_uni_class_seq", PI_MALFORMED, PI_WARN, "VarBind is not an universal class sequence", EXPFILL }},
2456                 { &ei_snmp_varbind_has_indicator, { "snmp.varbind.has_indicator", PI_MALFORMED, PI_WARN, "VarBind has indicator set", EXPFILL }},
2457                 { &ei_snmp_objectname_not_oid, { "snmp.objectname_not_oid", PI_MALFORMED, PI_WARN, "ObjectName not an OID", EXPFILL }},
2458                 { &ei_snmp_objectname_has_indicator, { "snmp.objectname_has_indicator", PI_MALFORMED, PI_WARN, "ObjectName has indicator set", EXPFILL }},
2459                 { &ei_snmp_value_not_primitive_encoding, { "snmp.value_not_primitive_encoding", PI_MALFORMED, PI_WARN, "value not in primitive encoding", EXPFILL }},
2460                 { &ei_snmp_invalid_oid, { "snmp.invalid_oid", PI_MALFORMED, PI_WARN, "invalid oid", EXPFILL }},
2461                 { &ei_snmp_varbind_wrong_tag, { "snmp.varbind.wrong_tag", PI_MALFORMED, PI_WARN, "Wrong tag for SNMP VarBind error value", EXPFILL }},
2462                 { &ei_snmp_varbind_response, { "snmp.varbind.response", PI_RESPONSE_CODE, PI_NOTE, "Response", EXPFILL }},
2463                 { &ei_snmp_no_instance_subid, { "snmp.no_instance_subid", PI_MALFORMED, PI_WARN, "No instance sub-id in scalar value", EXPFILL }},
2464                 { &ei_snmp_wrong_num_of_subids, { "snmp.wrong_num_of_subids", PI_MALFORMED, PI_WARN, "Wrong number of instance sub-ids in scalar value", EXPFILL }},
2465                 { &ei_snmp_index_suboid_too_short, { "snmp.index_suboid_too_short", PI_MALFORMED, PI_WARN, "index sub-oid shorter than expected", EXPFILL }},
2466                 { &ei_snmp_unimplemented_instance_index, { "snmp.unimplemented_instance_index", PI_UNDECODED, PI_WARN, "OID instaces not handled, if you want this implemented please contact the wireshark developers", EXPFILL }},
2467                 { &ei_snmp_index_suboid_len0, { "snmp.ndex_suboid_len0", PI_MALFORMED, PI_WARN, "an index sub-oid OID cannot be 0 bytes long!", EXPFILL }},
2468                 { &ei_snmp_index_suboid_too_long, { "snmp.index_suboid_too_long", PI_MALFORMED, PI_WARN, "index sub-oid should not be longer than remaining oid size", EXPFILL }},
2469                 { &ei_snmp_index_string_too_long, { "snmp.index_string_too_long", PI_MALFORMED, PI_WARN, "index string should not be longer than remaining oid size", EXPFILL }},
2470                 { &ei_snmp_column_parent_not_row, { "snmp.column_parent_not_row", PI_MALFORMED, PI_ERROR, "COLUMS's parent is not a ROW", EXPFILL }},
2471                 { &ei_snmp_uint_too_large, { "snmp.uint_too_large", PI_UNDECODED, PI_NOTE, "Unsigned integer value > 2^64 - 1", EXPFILL }},
2472                 { &ei_snmp_int_too_large, { "snmp.int_too_large", PI_UNDECODED, PI_NOTE, "Signed integer value > 2^63 - 1 or <= -2^63", EXPFILL }},
2473                 { &ei_snmp_integral_value0, { "snmp.integral_value0", PI_UNDECODED, PI_NOTE, "Integral value is zero-length", EXPFILL }},
2474                 { &ei_snmp_missing_mib, { "snmp.missing_mib", PI_UNDECODED, PI_NOTE, "Unresolved value, Missing MIB", EXPFILL }},
2475                 { &ei_snmp_varbind_wrong_length_value, { "snmp.varbind.wrong_length_value", PI_MALFORMED, PI_WARN, "Wrong length for SNMP VarBind/value", EXPFILL }},
2476                 { &ei_snmp_varbind_wrong_class_tag, { "snmp.varbind.wrong_class_tag", PI_MALFORMED, PI_WARN, "Wrong class/tag for SNMP VarBind/value", EXPFILL }},
2477                 { &ei_snmp_rfc1910_non_conformant, { "snmp.rfc1910_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC1910", EXPFILL }},
2478                 { &ei_snmp_rfc3411_non_conformant, { "snmp.rfc3411_non_conformant", PI_PROTOCOL, PI_WARN, "Data not conforming to RFC3411", EXPFILL }},
2479                 { &ei_snmp_version_unknown, { "snmp.version.unknown", PI_PROTOCOL, PI_WARN, "Unknown version", EXPFILL }},
2480                 { &ei_snmp_trap_pdu_obsolete, { "snmp.trap_pdu_obsolete", PI_PROTOCOL, PI_WARN, "Trap-PDU is obsolete in this SNMP version", EXPFILL }},
2481
2482         };
2483
2484         expert_module_t* expert_snmp;
2485         module_t *snmp_module;
2486
2487         static uat_field_t users_fields[] = {
2488                 UAT_FLD_BUFFER(snmp_users,engine_id,"Engine ID","Engine-id for this entry (empty = any)"),
2489                 UAT_FLD_LSTRING(snmp_users,userName,"Username","The username"),
2490                 UAT_FLD_VS(snmp_users,auth_model,"Authentication model",auth_types,"Algorithm to be used for authentication."),
2491                 UAT_FLD_LSTRING(snmp_users,authPassword,"Password","The password used for authenticating packets for this entry"),
2492                 UAT_FLD_VS(snmp_users,priv_proto,"Privacy protocol",priv_types,"Algorithm to be used for privacy."),
2493                 UAT_FLD_LSTRING(snmp_users,privPassword,"Privacy password","The password used for encrypting packets for this entry"),
2494                 UAT_END_FIELDS
2495         };
2496
2497         uat_t *assocs_uat = uat_new("SNMP Users",
2498                                     sizeof(snmp_ue_assoc_t),
2499                                     "snmp_users",
2500                                     TRUE,
2501                                     &ueas,
2502                                     &num_ueas,
2503                                     UAT_AFFECTS_DISSECTION,     /* affects dissection of packets, but not set of named fields */
2504                                     "ChSNMPUsersSection",
2505                                     snmp_users_copy_cb,
2506                                     snmp_users_update_cb,
2507                                     snmp_users_free_cb,
2508                                     renew_ue_cache,
2509                                     users_fields);
2510
2511         static uat_field_t specific_traps_flds[] = {
2512                 UAT_FLD_CSTRING(specific_traps,enterprise,"Enterprise OID","Enterprise Object Identifier"),
2513                 UAT_FLD_DEC(specific_traps,trap,"Trap Id","The specific-trap value"),
2514                 UAT_FLD_CSTRING(specific_traps,desc,"Description","Trap type description"),
2515                 UAT_END_FIELDS
2516         };
2517
2518         uat_t* specific_traps_uat = uat_new("SNMP Enterprise Specific Trap Types",
2519                                             sizeof(snmp_st_assoc_t),
2520                                             "snmp_specific_traps",
2521                                             TRUE,
2522                                             &specific_traps,
2523                                             &num_specific_traps,
2524                                             UAT_AFFECTS_DISSECTION, /* affects dissection of packets, but not set of named fields */
2525                                             "ChSNMPEnterpriseSpecificTrapTypes",
2526                                             snmp_specific_trap_copy_cb,
2527                                             NULL,
2528                                             snmp_specific_trap_free_cb,
2529                                             NULL,
2530                                             specific_traps_flds);
2531
2532         /* Register protocol */
2533         proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
2534         new_register_dissector("snmp", dissect_snmp, proto_snmp);
2535
2536         /* Register fields and subtrees */
2537         proto_register_field_array(proto_snmp, hf, array_length(hf));
2538         proto_register_subtree_array(ett, array_length(ett));
2539         expert_snmp = expert_register_protocol(proto_snmp);
2540         expert_register_field_array(expert_snmp, ei, array_length(ei));
2541
2542
2543         /* Register configuration preferences */
2544         snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
2545         prefs_register_bool_preference(snmp_module, "display_oid",
2546                         "Show SNMP OID in info column",
2547                         "Whether the SNMP OID should be shown in the info column",
2548                         &display_oid);
2549
2550         prefs_register_obsolete_preference(snmp_module, "mib_modules");
2551         prefs_register_obsolete_preference(snmp_module, "users_file");
2552
2553         prefs_register_bool_preference(snmp_module, "desegment",
2554                         "Reassemble SNMP-over-TCP messages\nspanning multiple TCP segments",
2555                         "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
2556                         " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
2557                         &snmp_desegment);
2558
2559         prefs_register_bool_preference(snmp_module, "var_in_tree",
2560                         "Display dissected variables inside SNMP tree",
2561                         "ON - display dissected variables inside SNMP tree, OFF - display dissected variables in root tree after SNMP",
2562                         &snmp_var_in_tree);
2563
2564         prefs_register_uat_preference(snmp_module, "users_table",
2565                                 "Users Table",
2566                                 "Table of engine-user associations used for authentication and decryption",
2567                                 assocs_uat);
2568
2569         prefs_register_uat_preference(snmp_module, "specific_traps_table",
2570                                 "Enterprise Specific Trap Types",
2571                                 "Table of enterprise specific-trap type descriptions",
2572                                 specific_traps_uat);
2573
2574 #ifdef HAVE_LIBSMI
2575         prefs_register_static_text_preference(snmp_module, "info_mibs",
2576                                 "MIB settings can be changed in the Name Resolution preferences",
2577                                 "MIB settings can be changed in the Name Resolution preferences");
2578 #endif
2579
2580         value_sub_dissectors_table = register_dissector_table("snmp.variable_oid","SNMP Variable OID", FT_STRING, BASE_NONE);
2581
2582         register_init_routine(init_ue_cache);
2583         register_cleanup_routine(cleanup_ue_cache);
2584
2585         register_ber_syntax_dissector("SNMP", proto_snmp, dissect_snmp_tcp);
2586 }
2587
2588
2589 /*--- proto_reg_handoff_snmp ---------------------------------------*/
2590 void proto_reg_handoff_snmp(void) {
2591         dissector_handle_t snmp_tcp_handle;
2592
2593         snmp_handle = find_dissector("snmp");
2594
2595         dissector_add_uint("udp.port", UDP_PORT_SNMP, snmp_handle);
2596         dissector_add_uint("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
2597         dissector_add_uint("udp.port", UDP_PORT_SNMP_PATROL, snmp_handle);
2598         dissector_add_uint("ethertype", ETHERTYPE_SNMP, snmp_handle);
2599         dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
2600         dissector_add_uint("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
2601         dissector_add_uint("hpext.dxsap", HPEXT_SNMP, snmp_handle);
2602
2603         snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
2604         dissector_add_uint("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
2605         dissector_add_uint("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
2606
2607         data_handle = find_dissector("data");
2608
2609         /* SNMPv2-MIB sysDescr "1.3.6.1.2.1.1.1.0" */
2610         dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.1.0",
2611                 new_create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
2612         /* SNMPv2-MIB::sysName.0 (1.3.6.1.2.1.1.5.0) */
2613         dissector_add_string("snmp.variable_oid", "1.3.6.1.2.1.1.5.0",
2614                 new_create_dissector_handle(dissect_snmp_variable_string, proto_snmp));
2615
2616         /*
2617          * Process preference settings.
2618          *
2619          * We can't do this in the register routine, as preferences aren't
2620          * read until all dissector register routines have been called (so
2621          * that all dissector preferences have been registered).
2622          */
2623         process_prefs();
2624
2625 }
2626
2627 void
2628 proto_register_smux(void)
2629 {
2630         static gint *ett[] = {
2631                 &ett_smux,
2632         };
2633
2634         proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
2635             "SMUX", "smux");
2636
2637         proto_register_subtree_array(ett, array_length(ett));
2638
2639 }
2640
2641 void
2642 proto_reg_handoff_smux(void)
2643 {
2644         dissector_handle_t smux_handle;
2645
2646         smux_handle = new_create_dissector_handle(dissect_smux, proto_smux);
2647         dissector_add_uint("tcp.port", TCP_PORT_SMUX, smux_handle);
2648 }
2649
2650 /*
2651  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
2652  *
2653  * Local variables:
2654  * c-basic-offset: 8
2655  * tab-width: 8
2656  * indent-tabs-mode: t
2657  * End:
2658  *
2659  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
2660  * :indentSize=8:tabSize=8:noTabs=false:
2661  */