Replace ip_to_str((tvb_get_ptr(...)) with tvb_ip_to_str().
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcerpc-epm.c
1 /* packet-dcerpc-epm.c
2  * Routines for dcerpc endpoint mapper dissection
3  * Copyright 2001, Todd Sabin <tas@webspan.net>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/expert.h>
33 #include "packet-dcerpc.h"
34 #include "packet-dcerpc-nt.h"
35
36
37 static int proto_epm3 = -1;
38 static int proto_epm4 = -1;
39
40 static int hf_epm_opnum = -1;
41 static int hf_epm_inquiry_type = -1;
42 static int hf_epm_object = -1;
43 static int hf_epm_if_id = -1;
44 static int hf_epm_ver_maj = -1;
45 static int hf_epm_ver_min = -1;
46 static int hf_epm_ver_opt = -1;
47 static int hf_epm_hnd = -1;
48 static int hf_epm_max_ents = -1;
49 static int hf_epm_num_ents = -1;
50 static int hf_epm_uuid = -1;
51 static int hf_epm_tower_length = -1;
52 static int hf_epm_tower_data = -1;
53 static int hf_epm_max_towers = -1;
54 static int hf_epm_num_towers = -1;
55 static int hf_epm_rc = -1;
56 static int hf_epm_replace = -1;
57 static int hf_epm_tower_num_floors = -1;
58 static int hf_epm_tower_rhs_len = -1;
59 static int hf_epm_tower_lhs_len = -1;
60 static int hf_epm_tower_proto_id = -1;
61 static int hf_epm_annotation = -1;
62 static int hf_epm_ann_offset = -1;
63 static int hf_epm_ann_len = -1;
64 static int hf_epm_proto_named_pipes = -1;
65 static int hf_epm_proto_netbios_name = -1;
66 static int hf_epm_proto_ip = -1;
67 static int hf_epm_proto_udp_port = -1;
68 static int hf_epm_proto_tcp_port = -1;
69 static int hf_epm_proto_http_port = -1;
70
71 static gint ett_epm = -1;
72 static gint ett_epm_tower_floor = -1;
73 static gint ett_epm_entry = -1;
74
75 /* the UUID is identical for interface versions 3 and 4 */
76 static e_uuid_t uuid_epm = { 0xe1af8308, 0x5d1f, 0x11c9, { 0x91, 0xa4, 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } };
77 static guint16  ver_epm3 = 3;
78 static guint16  ver_epm4 = 4;
79
80
81
82 static const value_string ep_service[] = {
83     { 0, "rpc_c_ep_all_elts" },
84     { 1, "rpc_c_ep_match_by_if" },
85     { 2, "rpc_c_ep_match_by_obj" },
86     { 3, "rpc_c_ep_match_by_both" },
87     { 0, NULL },
88 };
89
90 /* typedef struct {
91       unsigned int tower_len,
92       [size_is(tower_len)] char tower[];
93    } twr_t, *twr_p_t;
94 */
95 static int epm_dissect_tower (tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep);
96
97
98 static int
99 epm_dissect_pointer_IF_ID(tvbuff_t *tvb, int offset,
100                           packet_info *pinfo, proto_tree *tree,
101                           guint8 *drep)
102 {
103     dcerpc_info *di;
104
105     di=pinfo->private_data;
106     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
107                                  di->hf_index, NULL);
108     offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
109                                  hf_epm_ver_maj, NULL);
110     offset = dissect_ndr_uint16 (tvb, offset, pinfo, tree, drep,
111                                  hf_epm_ver_min, NULL);
112     return offset;
113 }
114
115 static int
116 epm_dissect_pointer_UUID(tvbuff_t *tvb, int offset,
117                              packet_info *pinfo, proto_tree *tree,
118                              guint8 *drep)
119 {
120     dcerpc_info *di;
121
122     di=pinfo->private_data;
123     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
124                                  di->hf_index, NULL);
125     return offset;
126 }
127
128 static int
129 epm_dissect_ept_lookup_rqst (tvbuff_t *tvb, int offset,
130                              packet_info *pinfo, proto_tree *tree,
131                              guint8 *drep)
132 {
133     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
134                                  hf_epm_inquiry_type, NULL);
135
136     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
137                              epm_dissect_pointer_UUID, NDR_POINTER_PTR,
138                              "Object:", hf_epm_object);
139
140     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
141                              epm_dissect_pointer_IF_ID, NDR_POINTER_PTR,
142                              "Interface:", hf_epm_if_id);
143
144     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
145                                  hf_epm_ver_opt, NULL);
146
147     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
148                                   hf_epm_hnd, NULL);
149
150     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
151                                  hf_epm_max_ents, NULL);
152     return offset;
153 }
154
155
156 static int
157 epm_dissect_ept_entry_t(tvbuff_t *tvb, int offset,
158                              packet_info *pinfo, proto_tree *parent_tree,
159                              guint8 *drep)
160 {
161     proto_item *item=NULL;
162     proto_tree *tree=NULL;
163     int old_offset=offset;
164     guint32 len;
165     dcerpc_info *di;
166     const char *str;
167
168     di=pinfo->private_data;
169     if(di->conformant_run){
170         return offset;
171     }
172
173     if(parent_tree){
174         item = proto_tree_add_text(parent_tree, tvb, offset, -1, "Entry:");
175         tree = proto_item_add_subtree(item, ett_epm_entry);
176     }
177
178     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
179                                  hf_epm_object, NULL);
180
181     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
182                              epm_dissect_tower, NDR_POINTER_PTR,
183                              "Tower pointer:", -1);
184
185     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
186                                  hf_epm_ann_offset, NULL);
187     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
188                                  hf_epm_ann_len, &len);
189     str=tvb_get_ephemeral_string(tvb, offset, len);
190     proto_tree_add_item(tree, hf_epm_annotation, tvb, offset, len, TRUE);
191     offset += len;
192
193     if(str&&str[0]){
194         if(parent_tree) {
195             proto_item_append_text(item, " Service:%s ", str);
196             proto_item_append_text(tree->parent, " Service:%s ", str);
197         }
198         if (check_col(pinfo->cinfo, COL_INFO)) {
199             col_append_fstr(pinfo->cinfo, COL_INFO, ", Service:%s", str);
200         }
201     }
202
203     proto_item_set_len(item, offset-old_offset);
204     return offset;
205 }
206
207 static int
208 epm_dissect_ept_entry_t_array(tvbuff_t *tvb, int offset,
209                              packet_info *pinfo, proto_tree *tree,
210                              guint8 *drep)
211 {
212     offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, drep,
213                              epm_dissect_ept_entry_t);
214
215     return offset;
216 }
217
218 static int
219 epm_dissect_ept_lookup_resp (tvbuff_t *tvb, int offset,
220                              packet_info *pinfo, proto_tree *tree,
221                              guint8 *drep)
222 {
223     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
224                                   hf_epm_hnd, NULL);
225
226     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
227                                  hf_epm_num_ents, NULL);
228
229     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
230                              epm_dissect_ept_entry_t_array, NDR_POINTER_REF,
231                              "Entries:", -1);
232
233     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
234                                  hf_epm_rc, NULL);
235
236     return offset;
237 }
238
239 static int
240 epm_dissect_uuid (tvbuff_t *tvb, int offset,
241                              packet_info *pinfo, proto_tree *tree,
242                              guint8 *drep)
243 {
244     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
245                                   hf_epm_uuid, NULL);
246     return offset;
247 }
248
249 #define PROTO_ID_OSI_OID        0x00
250 #define PROTO_ID_DNA_SESSCTL    0x02
251 #define PROTO_ID_DNA_SESSCTL_V3 0x03
252 #define PROTO_ID_DNA_NSP        0x04
253 #define PROTO_ID_OSI_TP4        0x05
254 #define PROTO_ID_OSI_CLNS       0x06
255 #define PROTO_ID_TCP            0x07
256 #define PROTO_ID_UDP            0x08
257 #define PROTO_ID_IP             0x09
258 #define PROTO_ID_RPC_CL         0x0a
259 #define PROTO_ID_RPC_CO         0x0b
260 #define PROTO_ID_SPX            0x0c    /* from DCOM spec (is this correct?) */
261 #define PROTO_ID_UUID           0x0d
262 #define PROTO_ID_IPX            0x0e    /* from DCOM spec (is this correct?) */
263 #define PROTO_ID_NAMED_PIPES    0x0f
264 #define PROTO_ID_NAMED_PIPES_2  0x10
265 #define PROTO_ID_NETBIOS        0x11
266 #define PROTO_ID_NETBEUI        0x12
267 #define PROTO_ID_NETWARE_SPX    0x13
268 #define PROTO_ID_NETWARE_IPX    0x14
269 #define PROTO_ID_ATALK_STREAM   0x16
270 #define PROTO_ID_ATALK_DATAGRAM 0x17
271 #define PROTO_ID_ATALK          0x18
272 #define PROTO_ID_NETBIOS_2      0x19
273 #define PROTO_ID_VINES_SPP      0x1a
274 #define PROTO_ID_VINES_IPC      0x1b
275 #define PROTO_ID_STREETTALK     0x1c
276 #define PROTO_ID_HTTP           0x1f
277 #define PROTO_ID_UNIX_DOMAIN    0x20
278 #define PROTO_ID_NULL           0x21
279 #define PROTO_ID_NETBIOS_3      0x22
280
281 static const value_string proto_id_vals[] = {
282     { PROTO_ID_OSI_OID,         "OSI OID"},
283     { PROTO_ID_DNA_SESSCTL,     "DNA Session Control"},
284     { PROTO_ID_DNA_SESSCTL_V3,  "DNA Session Control V3"},
285     { PROTO_ID_DNA_NSP,         "DNA NSP Transport"},
286     { PROTO_ID_OSI_TP4,         "OSI TP4"},
287     { PROTO_ID_OSI_CLNS,        "OSI CLNS or DNA Routing"},
288     { PROTO_ID_TCP,             "DOD TCP"},
289     { PROTO_ID_UDP,             "DOD UDP"},
290     { PROTO_ID_IP,              "DOD IP"},
291     { PROTO_ID_RPC_CL,          "RPC connectionless protocol"},
292     { PROTO_ID_RPC_CO,          "RPC connection-oriented protocol"},
293     { PROTO_ID_SPX,             "SPX?"},
294     { PROTO_ID_UUID,            "UUID"},
295     { PROTO_ID_IPX,             "IPX?"},
296     { PROTO_ID_NAMED_PIPES,     "Named Pipes"},
297     { PROTO_ID_NAMED_PIPES_2,   "Named Pipes"},
298     { PROTO_ID_NETBIOS,         "NetBIOS"},
299     { PROTO_ID_NETBEUI,         "NetBEUI"},
300     { PROTO_ID_NETWARE_SPX,     "Netware SPX"},
301     { PROTO_ID_NETWARE_IPX,     "Netware IPX"},
302     { PROTO_ID_ATALK_STREAM,    "Appletalk Stream"},
303     { PROTO_ID_ATALK_DATAGRAM,  "Appletalk Datagram"},
304     { PROTO_ID_ATALK,           "Appletalk"},
305     { PROTO_ID_NETBIOS_2,       "NetBIOS"},
306     { PROTO_ID_VINES_SPP,       "Vines SPP"},
307     { PROTO_ID_VINES_IPC,       "Vines IPC"},
308     { PROTO_ID_STREETTALK,      "StreetTalk"},
309     { PROTO_ID_HTTP,            "RPC over HTTP"},
310     { PROTO_ID_UNIX_DOMAIN,     "Unix Domain Socket"},
311     { PROTO_ID_NULL,            "null"},
312     { PROTO_ID_NETBIOS_3,       "NetBIOS"},
313     { 0, NULL},
314 };
315
316
317 /* XXX this function assumes LE encoding. can not use the NDR routines
318    since they assume padding.
319 */
320 static int
321 epm_dissect_tower_data (tvbuff_t *tvb, int offset,
322                              packet_info *pinfo, proto_tree *tree,
323                              guint8 *drep)
324 {
325     guint16 num_floors, i;
326     dcerpc_info *di;
327     const char *uuid_name;
328
329     di=pinfo->private_data;
330     if(di->conformant_run){
331         return offset;
332     }
333
334     num_floors = tvb_get_letohs(tvb, offset);
335     proto_tree_add_uint(tree, hf_epm_tower_num_floors, tvb, offset, 2, num_floors);
336     offset += 2;
337
338     for(i=1;i<=num_floors;i++){
339         proto_item *it = NULL;
340         proto_tree *tr = NULL;
341         int old_offset = offset;
342         guint16 len;
343         guint8 proto_id;
344         e_uuid_t uuid;
345         proto_item *pi;
346
347         it = proto_tree_add_text(tree, tvb, offset, 0, "Floor %d  ", i);
348         tr = proto_item_add_subtree(it, ett_epm_tower_floor);
349
350         len = tvb_get_letohs(tvb, offset);
351         proto_tree_add_uint(tr, hf_epm_tower_lhs_len, tvb, offset, 2, len);
352         offset += 2;
353
354         proto_id = tvb_get_guint8(tvb, offset);
355         proto_tree_add_uint(tr, hf_epm_tower_proto_id, tvb, offset, 1, proto_id);
356
357         switch(proto_id){
358         case PROTO_ID_UUID:
359             dcerpc_tvb_get_uuid (tvb, offset+1, drep, &uuid);
360
361             uuid_name = guids_get_uuid_name(&uuid);
362
363             if(uuid_name != NULL) {
364                 proto_tree_add_guid_format (tr, hf_epm_uuid, tvb, offset+1, 16, (e_guid_t *) &uuid,
365                               "UUID: %s (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
366                               uuid_name,
367                               uuid.Data1, uuid.Data2, uuid.Data3,
368                               uuid.Data4[0], uuid.Data4[1],
369                               uuid.Data4[2], uuid.Data4[3],
370                               uuid.Data4[4], uuid.Data4[5],
371                               uuid.Data4[6], uuid.Data4[7]);
372             } else {
373                 proto_tree_add_guid_format (tr, hf_epm_uuid, tvb, offset+1, 16, (e_guid_t *) &uuid,
374                               "UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
375                               uuid.Data1, uuid.Data2, uuid.Data3,
376                               uuid.Data4[0], uuid.Data4[1],
377                               uuid.Data4[2], uuid.Data4[3],
378                               uuid.Data4[4], uuid.Data4[5],
379                               uuid.Data4[6], uuid.Data4[7]);
380             }
381             proto_tree_add_text(tr, tvb, offset+17, 2, "Version %d.%d", tvb_get_guint8(tvb, offset+17), tvb_get_guint8(tvb, offset+18));
382
383             {
384                 guint16 version = tvb_get_ntohs(tvb, offset+17);
385                 const char *service = dcerpc_get_proto_name(&uuid, version);
386                 if (service || uuid_name)
387                     proto_item_append_text(tr, "UUID: %s", service ? service : uuid_name);
388                 else
389                     proto_item_append_text(tr, "UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Version %d.%d", uuid.Data1, uuid.Data2, uuid.Data3,
390                                            uuid.Data4[0], uuid.Data4[1],
391                                            uuid.Data4[2], uuid.Data4[3],
392                                            uuid.Data4[4], uuid.Data4[5],
393                                            uuid.Data4[6], uuid.Data4[7],
394                                            tvb_get_guint8(tvb, offset+17),
395                                            tvb_get_guint8(tvb, offset+18));
396             }
397             break;
398         }
399         offset += len;
400
401         len = tvb_get_letohs(tvb, offset);
402         pi = proto_tree_add_uint(tr, hf_epm_tower_rhs_len, tvb, offset, 2, len);
403         offset += 2;
404
405         switch(proto_id){
406
407         case PROTO_ID_UUID:
408             /* XXX - is this big or little endian? */
409             proto_tree_add_item(tr, hf_epm_ver_min, tvb, offset, 2, FALSE);
410             break;
411         case PROTO_ID_TCP: /* this one is always big endian */
412             proto_tree_add_item(tr, hf_epm_proto_tcp_port, tvb, offset, 2, FALSE);
413             proto_item_append_text(tr, "TCP Port:%d", tvb_get_ntohs(tvb, offset));
414             break;
415
416         case PROTO_ID_UDP: /* this one is always big endian */
417             proto_tree_add_item(tr, hf_epm_proto_udp_port, tvb, offset, 2, FALSE);
418             proto_item_append_text(tr, "UDP Port:%d", tvb_get_ntohs(tvb, offset));
419             break;
420
421         case PROTO_ID_IP: /* this one is always big endian */
422             proto_tree_add_item(tr, hf_epm_proto_ip, tvb, offset, 4, FALSE);
423             proto_item_append_text(tr, "IP:%s", tvb_ip_to_str(tvb, offset));
424             break;
425
426         case PROTO_ID_RPC_CO:
427             proto_item_append_text(tr, "RPC connection-oriented protocol");
428             break;
429
430         case PROTO_ID_RPC_CL:
431             proto_item_append_text(tr, "RPC connectionless protocol");
432             /* XXX - is this big or little endian? */
433             proto_tree_add_item(tr, hf_epm_ver_min, tvb, offset, 2, FALSE);
434             break;
435
436         case PROTO_ID_NAMED_PIPES: /* \\PIPE\xxx   named pipe */
437             proto_tree_add_item(tr, hf_epm_proto_named_pipes, tvb, offset, len, TRUE);
438             proto_item_append_text(tr, "NamedPipe:%s", tvb_get_ephemeral_string(tvb, offset, len));
439             break;
440
441         case PROTO_ID_NAMED_PIPES_2: /* PIPENAME  named pipe */
442             proto_tree_add_item(tr, hf_epm_proto_named_pipes, tvb, offset, len, TRUE);
443             proto_item_append_text(tr, "PIPE:%s", tvb_get_ephemeral_string(tvb, offset, len));
444             break;
445
446         case PROTO_ID_NETBIOS: /* \\NETBIOS   netbios name */
447             proto_tree_add_item(tr, hf_epm_proto_netbios_name, tvb, offset, len, TRUE);
448             proto_item_append_text(tr, "NetBIOS:%s", tvb_get_ephemeral_string(tvb, offset, len));
449             break;
450         case PROTO_ID_HTTP: /* RPC over HTTP */
451             proto_tree_add_item(tr, hf_epm_proto_http_port, tvb, offset, 2, FALSE);
452             proto_item_append_text(tr, "RPC over HTTP Port:%d", tvb_get_ntohs(tvb, offset));
453             break;
454
455         default:
456             if(len){
457                 expert_add_info_format(pinfo, pi, PI_UNDECODED, PI_WARN, "RightHandSide not decoded yet for proto_id 0x%x",
458                     proto_id);
459                 tvb_ensure_bytes_exist(tvb, offset, len);
460                 proto_tree_add_text(tr, tvb, offset, len, "RightHandSide not decoded yet for proto_id 0x%x", proto_id);
461             }
462         }
463         offset += len;
464
465         proto_item_set_len(it, offset-old_offset);
466     }
467     return offset;
468 }
469
470 /* typedef struct {
471       unsigned int tower_len,
472       [size_is(tower_len)] char tower[];
473    } twr_t, *twr_p_t;
474 */
475 static int
476 epm_dissect_tower (tvbuff_t *tvb, int offset,
477                              packet_info *pinfo, proto_tree *tree,
478                              guint8 *drep)
479 {
480     guint32 len;
481     dcerpc_info *di;
482
483     di=pinfo->private_data;
484     if(di->conformant_run){
485         return offset;
486     }
487
488     /* first one is the header of the conformant array, second one is the
489        length field */
490     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
491                                  hf_epm_tower_length, &len);
492     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
493                                  hf_epm_tower_length, NULL);
494     offset = epm_dissect_tower_data(tvb, offset, pinfo, tree, drep);
495
496     return offset;
497 }
498 static int
499 epm_dissect_tower_pointer (tvbuff_t *tvb, int offset,
500                              packet_info *pinfo, proto_tree *tree,
501                              guint8 *drep)
502 {
503     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
504                              epm_dissect_tower, NDR_POINTER_PTR,
505                              "Tower pointer:", -1);
506     return offset;
507 }
508 static int
509 epm_dissect_tower_array (tvbuff_t *tvb, int offset,
510                              packet_info *pinfo, proto_tree *tree,
511                              guint8 *drep)
512 {
513     offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, drep,
514                              epm_dissect_tower_pointer);
515
516     return offset;
517 }
518
519 static int
520 epm_dissect_ept_map_rqst (tvbuff_t *tvb, int offset,
521                              packet_info *pinfo, proto_tree *tree,
522                              guint8 *drep)
523 {
524     /* [in, ptr] uuid_p_t object */
525     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
526                              epm_dissect_uuid, NDR_POINTER_PTR,
527                              "UUID pointer:", -1);
528
529     /* [in, ptr] twr_p_t map_tower */
530     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
531                              epm_dissect_tower, NDR_POINTER_PTR,
532                              "Tower pointer:", -1);
533
534     /* [in, out] ept_lookup_handle_t *entry_handle */
535     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
536                                   hf_epm_hnd, NULL);
537
538     /* [in] unsigned32 max_towers */
539     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
540                                  hf_epm_max_towers, NULL);
541
542     return offset;
543 }
544
545 static int
546 epm_dissect_ept_map_resp (tvbuff_t *tvb, int offset,
547                              packet_info *pinfo, proto_tree *tree,
548                              guint8 *drep)
549 {
550     /* [in, out] ept_lookup_handle_t *entry_handle */
551     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
552                                   hf_epm_hnd, NULL);
553
554     /* [out, ptr] unsigned32 *num_towers */
555     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
556                                  hf_epm_num_towers, NULL);
557
558     /* [out, length_is(*num_towers), size_is(max_towers), ptr] twr_p_t towers[] */
559     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
560                              epm_dissect_tower_array, NDR_POINTER_REF,
561                              "Tower array:", -1);
562
563     /* [out] error_status_t *status */
564     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
565                                  hf_epm_rc, NULL);
566
567     return offset;
568 }
569
570 static int
571 epm_dissect_ept_entry_t_ucarray(tvbuff_t *tvb, int offset,
572                              packet_info *pinfo, proto_tree *tree,
573                              guint8 *drep)
574 {
575     offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, drep,
576                              epm_dissect_ept_entry_t);
577
578     return offset;
579 }
580
581 static int
582 epm_dissect_ept_insert_rqst (tvbuff_t *tvb, int offset,
583                              packet_info *pinfo, proto_tree *tree,
584                              guint8 *drep)
585 {
586     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
587                                  hf_epm_num_ents, NULL);
588
589     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
590                              epm_dissect_ept_entry_t_ucarray, NDR_POINTER_REF,
591                              "Entries:", -1);
592
593     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
594                                  hf_epm_replace, NULL);
595
596     return offset;
597 }
598
599
600
601 static int
602 epm_dissect_ept_insert_resp (tvbuff_t *tvb, int offset,
603                              packet_info *pinfo, proto_tree *tree,
604                              guint8 *drep)
605 {
606     /* [out] error_status_t *status */
607     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
608                                  hf_epm_rc, NULL);
609
610     return offset;
611 }
612
613
614 static int
615 epm_dissect_ept_delete_rqst (tvbuff_t *tvb, int offset,
616                              packet_info *pinfo, proto_tree *tree,
617                              guint8 *drep)
618 {
619     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
620                                  hf_epm_num_ents, NULL);
621
622     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
623                              epm_dissect_ept_entry_t_ucarray, NDR_POINTER_REF,
624                              "Entries:", -1);
625
626     return offset;
627 }
628
629
630
631 static int
632 epm_dissect_ept_delete_resp (tvbuff_t *tvb, int offset,
633                              packet_info *pinfo, proto_tree *tree,
634                              guint8 *drep)
635 {
636     /* [out] error_status_t *status */
637     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
638                                  hf_epm_rc, NULL);
639
640     return offset;
641 }
642
643
644
645 static int
646 epm_dissect_ept_lookup_handle_free_rqst (tvbuff_t *tvb, int offset,
647                              packet_info *pinfo, proto_tree *tree,
648                              guint8 *drep)
649 {
650     /* [in, out] ept_lookup_handle_t *entry_handle */
651     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
652                                   hf_epm_hnd, NULL);
653
654     return offset;
655 }
656
657 static int
658 epm_dissect_ept_lookup_handle_free_resp (tvbuff_t *tvb, int offset,
659                              packet_info *pinfo, proto_tree *tree,
660                              guint8 *drep)
661 {
662     /* [in, out] ept_lookup_handle_t *entry_handle */
663     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
664                                   hf_epm_hnd, NULL);
665
666     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
667                                  hf_epm_rc, NULL);
668
669     return offset;
670 }
671
672
673 static dcerpc_sub_dissector epm_dissectors[] = {
674     { 0, "Insert",
675         epm_dissect_ept_insert_rqst,
676         epm_dissect_ept_insert_resp },
677     { 1, "Delete",
678         epm_dissect_ept_delete_rqst,
679         epm_dissect_ept_delete_resp },
680     { 2, "Lookup",
681         epm_dissect_ept_lookup_rqst,
682         epm_dissect_ept_lookup_resp },
683     { 3, "Map",
684         epm_dissect_ept_map_rqst,
685         epm_dissect_ept_map_resp },
686     { 4, "LookupHandleFree",
687         epm_dissect_ept_lookup_handle_free_rqst,
688         epm_dissect_ept_lookup_handle_free_resp },
689     { 5, "InqObject", NULL, NULL },
690     { 6, "MgmtDelete", NULL, NULL },
691     { 0, NULL, NULL, NULL }
692 };
693
694 void
695 proto_register_epm (void)
696 {
697     static hf_register_info hf[] = {
698         { &hf_epm_opnum,
699           { "Operation", "epm.opnum", FT_UINT16, BASE_DEC,
700             NULL, 0x0, NULL, HFILL }},
701         { &hf_epm_inquiry_type,
702           { "Inquiry type", "epm.inq_type", FT_UINT32, BASE_DEC, VALS(ep_service), 0x0, NULL, HFILL }},
703         { &hf_epm_object,
704           { "Object", "epm.object", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
705         { &hf_epm_if_id,
706           { "Interface", "epm.if_id", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
707         { &hf_epm_ver_maj,
708           { "Version Major", "epm.ver_maj", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
709         { &hf_epm_ver_min,
710           { "Version Minor", "epm.ver_min", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
711         { &hf_epm_ver_opt,
712           { "Version Option", "epm.ver_opt", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
713         { &hf_epm_hnd,
714           { "Handle", "epm.hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "Context handle", HFILL }},
715         { &hf_epm_max_ents,
716           { "Max entries", "epm.max_ents", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
717         { &hf_epm_num_ents,
718           { "Num entries", "epm.num_ents", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
719         { &hf_epm_uuid,
720           { "UUID", "epm.uuid", FT_GUID, BASE_NONE, NULL, 0x0, NULL, HFILL }},
721         { &hf_epm_annotation,
722           { "Annotation", "epm.annotation", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
723         { &hf_epm_proto_named_pipes,
724           { "Named Pipe", "epm.proto.named_pipe", FT_STRING, BASE_NONE, NULL, 0x0, "Name of the named pipe for this service", HFILL }},
725         { &hf_epm_proto_netbios_name,
726           { "NetBIOS Name", "epm.proto.netbios_name", FT_STRING, BASE_NONE, NULL, 0x0, "NetBIOS name where this service can be found", HFILL }},
727         { &hf_epm_tower_length,
728           { "Length", "epm.tower.len", FT_UINT32, BASE_DEC, NULL, 0x0, "Length of tower data", HFILL }},
729         { &hf_epm_tower_data,
730           { "Tower", "epm.tower", FT_BYTES, BASE_NONE, NULL, 0x0, "Tower data", HFILL }},
731         { &hf_epm_max_towers,
732           { "Max Towers", "epm.max_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum number of towers to return", HFILL }},
733         { &hf_epm_num_towers,
734           { "Num Towers", "epm.num_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Number number of towers to return", HFILL }},
735         { &hf_epm_ann_offset,
736           { "Annotation offset", "epm.ann_offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
737         { &hf_epm_ann_len,
738           { "Annotation length", "epm.ann_len", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
739         { &hf_epm_rc,
740           { "Return code", "epm.rc", FT_UINT32, BASE_HEX, NULL, 0x0, "EPM return value", HFILL }},
741         { &hf_epm_replace,
742           { "Replace", "epm.replace", FT_UINT8, BASE_DEC, NULL, 0x0, "Replace existing objects?", HFILL }},
743         { &hf_epm_tower_num_floors,
744           { "Number of floors", "epm.tower.num_floors", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of floors in tower", HFILL }},
745         { &hf_epm_proto_udp_port,
746           { "UDP Port", "epm.proto.udp_port", FT_UINT16, BASE_DEC, NULL, 0x0, "UDP Port where this service can be found", HFILL }},
747         { &hf_epm_proto_tcp_port,
748           { "TCP Port", "epm.proto.tcp_port", FT_UINT16, BASE_DEC, NULL, 0x0, "TCP Port where this service can be found", HFILL }},
749         { &hf_epm_proto_http_port,
750           { "TCP Port", "epm.proto.http_port", FT_UINT16, BASE_DEC, NULL, 0x0, "TCP Port where this service can be found", HFILL }},
751         { &hf_epm_tower_rhs_len,
752           { "RHS Length", "epm.tower.rhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of RHS data", HFILL }},
753         { &hf_epm_tower_lhs_len,
754           { "LHS Length", "epm.tower.lhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of LHS data", HFILL }},
755         { &hf_epm_proto_ip,
756           { "IP", "epm.proto.ip", FT_IPv4, BASE_NONE, NULL, 0x0, "IP address where service is located", HFILL }},
757         { &hf_epm_tower_proto_id,
758           { "Protocol", "epm.tower.proto_id", FT_UINT8, BASE_HEX, VALS(proto_id_vals), 0x0, "Protocol identifier", HFILL }}
759     };
760     static gint *ett[] = {
761         &ett_epm,
762         &ett_epm_tower_floor,
763         &ett_epm_entry
764     };
765
766     /* interface version 3 */
767     proto_epm3 = proto_register_protocol ("DCE/RPC Endpoint Mapper", "EPM", "epm");
768     proto_register_field_array (proto_epm3, hf, array_length (hf));
769     proto_register_subtree_array (ett, array_length (ett));
770
771     /* interface version 4 */
772     proto_epm4 = proto_register_protocol ("DCE/RPC Endpoint Mapper v4", "EPMv4", "epm4");
773 }
774
775 void
776 proto_reg_handoff_epm (void)
777 {
778     /* Register the protocol as dcerpc */
779     dcerpc_init_uuid (proto_epm3, ett_epm, &uuid_epm, ver_epm3, epm_dissectors, hf_epm_opnum);
780     dcerpc_init_uuid (proto_epm4, ett_epm, &uuid_epm, ver_epm4, epm_dissectors, hf_epm_opnum);
781 }