Add a few tvb_ensure_bytes_exist() calls.
[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  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
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
31 #include <string.h>
32
33 #include <glib.h>
34 #include <epan/packet.h>
35 #include "packet-dcerpc.h"
36 #include "packet-dcerpc-nt.h"
37
38
39 static int proto_epm3 = -1;
40 static int proto_epm4 = -1;
41
42 static int hf_epm_opnum = -1;
43 static int hf_epm_inquiry_type = -1;
44 static int hf_epm_object = -1;
45 static int hf_epm_if_id = -1;
46 static int hf_epm_ver_maj = -1;
47 static int hf_epm_ver_min = -1;
48 static int hf_epm_ver_opt = -1;
49 static int hf_epm_hnd = -1;
50 static int hf_epm_max_ents = -1;
51 static int hf_epm_num_ents = -1;
52 static int hf_epm_uuid = -1;
53 static int hf_epm_tower_length = -1;
54 static int hf_epm_tower_data = -1;
55 static int hf_epm_max_towers = -1;
56 static int hf_epm_num_towers = -1;
57 static int hf_epm_rc = -1;
58 static int hf_epm_replace = -1;
59 static int hf_epm_tower_num_floors = -1;
60 static int hf_epm_tower_rhs_len = -1;
61 static int hf_epm_tower_lhs_len = -1;
62 static int hf_epm_tower_proto_id = -1;
63 static int hf_epm_annotation = -1;
64 static int hf_epm_ann_offset = -1;
65 static int hf_epm_ann_len = -1;
66 static int hf_epm_proto_named_pipes = -1;
67 static int hf_epm_proto_netbios_name = -1;
68 static int hf_epm_proto_ip = -1;
69 static int hf_epm_proto_udp_port = -1;
70 static int hf_epm_proto_tcp_port = -1;
71 static int hf_epm_proto_http_port = -1;
72
73 static gint ett_epm = -1;
74 static gint ett_epm_tower_floor = -1;
75 static gint ett_epm_entry = -1;
76
77 /* the UUID is identical for interface versions 3 and 4 */
78 static e_uuid_t uuid_epm = { 0xe1af8308, 0x5d1f, 0x11c9, { 0x91, 0xa4, 0x08, 0x00, 0x2b, 0x14, 0xa0, 0xfa } };
79 static guint16  ver_epm3 = 3;
80 static guint16  ver_epm4 = 4;
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     gint strlen;
166     dcerpc_info *di;
167     const char *str;
168     
169     di=pinfo->private_data;
170     if(di->conformant_run){
171         return offset;
172     }
173
174     if(parent_tree){
175         item = proto_tree_add_text(parent_tree, tvb, offset, -1, "Entry:");
176         tree = proto_item_add_subtree(item, ett_epm_entry);
177     }
178
179     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
180                                  hf_epm_object, NULL);
181
182     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
183                              epm_dissect_tower, NDR_POINTER_PTR,
184                              "Tower pointer:", -1);
185
186     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
187                                  hf_epm_ann_offset, NULL);
188     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
189                                  hf_epm_ann_len, &len);
190     str=(const char *)tvb_get_ptr(tvb, offset, -1);
191     strlen=len;
192     strlen=MIN(strlen,tvb_length_remaining(tvb, offset));
193     tvb_ensure_bytes_exist(tvb, offset, len);
194     proto_tree_add_item(tree, hf_epm_annotation, tvb, offset, len, TRUE);
195     offset += len;
196
197     if(str&&str[0]){
198         if(parent_tree) {
199             proto_item_append_text(item, " Service:%*s ", strlen, str);
200             proto_item_append_text(tree->parent, " Service:%*s ", strlen, str);
201         }
202         if (check_col(pinfo->cinfo, COL_INFO)) {
203             col_append_fstr(pinfo->cinfo, COL_INFO, ", Service:%*s", strlen, str);
204         }
205     }
206
207     proto_item_set_len(item, offset-old_offset);
208     return offset;
209 }
210
211 static int
212 epm_dissect_ept_entry_t_array(tvbuff_t *tvb, int offset,
213                              packet_info *pinfo, proto_tree *tree,
214                              guint8 *drep)
215 {
216     offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, drep,
217                              epm_dissect_ept_entry_t);
218
219     return offset;
220 }
221
222 static int
223 epm_dissect_ept_lookup_resp (tvbuff_t *tvb, int offset,
224                              packet_info *pinfo, proto_tree *tree,
225                              guint8 *drep)
226 {
227     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
228                                   hf_epm_hnd, NULL);
229
230     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
231                                  hf_epm_num_ents, NULL);
232
233     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
234                              epm_dissect_ept_entry_t_array, NDR_POINTER_REF,
235                              "Entries:", -1);
236
237     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
238                                  hf_epm_rc, NULL);
239
240     return offset;
241 }
242
243 static int
244 epm_dissect_uuid (tvbuff_t *tvb, int offset,
245                              packet_info *pinfo, proto_tree *tree,
246                              guint8 *drep)
247 {
248     offset = dissect_ndr_uuid_t (tvb, offset, pinfo, tree, drep,
249                                   hf_epm_uuid, NULL);
250     return offset;
251 }
252
253 #define PROTO_ID_OSI_OID        0x00
254 #define PROTO_ID_DNA_SESSCTL    0x02
255 #define PROTO_ID_DNA_SESSCTL_V3 0x03
256 #define PROTO_ID_DNA_NSP        0x04
257 #define PROTO_ID_OSI_TP4        0x05
258 #define PROTO_ID_OSI_CLNS       0x06
259 #define PROTO_ID_TCP            0x07
260 #define PROTO_ID_UDP            0x08
261 #define PROTO_ID_IP             0x09
262 #define PROTO_ID_RPC_CL         0x0a
263 #define PROTO_ID_RPC_CO         0x0b
264 #define PROTO_ID_UUID           0x0d
265 #define PROTO_ID_NAMED_PIPES    0x0f
266 #define PROTO_ID_NAMED_PIPES_2  0x10
267 #define PROTO_ID_NETBIOS        0x11
268 #define PROTO_ID_NETBEUI        0x12
269 #define PROTO_ID_NETWARE_SPX    0x13
270 #define PROTO_ID_NETWARE_IPX    0x14
271 #define PROTO_ID_ATALK_STREAM   0x16
272 #define PROTO_ID_ATALK_DATAGRAM 0x17
273 #define PROTO_ID_ATALK          0x18
274 #define PROTO_ID_NETBIOS_2      0x19
275 #define PROTO_ID_VINES_SPP      0x1a
276 #define PROTO_ID_VINES_IPC      0x1b
277 #define PROTO_ID_STREETTALK     0x1c
278 #define PROTO_ID_HTTP           0x1f
279 #define PROTO_ID_UNIX_DOMAIN    0x20
280 #define PROTO_ID_NULL           0x21
281 #define PROTO_ID_NETBIOS_3      0x22
282
283 static const value_string proto_id_vals[] = {
284         { PROTO_ID_OSI_OID,             "OSI OID"},
285         { PROTO_ID_DNA_SESSCTL,         "DNA Session Control"},
286         { PROTO_ID_DNA_SESSCTL_V3,      "DNA Session Control V3"},
287         { PROTO_ID_DNA_NSP,             "DNA NSP Transport"},
288         { PROTO_ID_OSI_TP4,             "OSI TP4"},
289         { PROTO_ID_OSI_CLNS,            "OSI CLNS or DNA Routing"},
290         { PROTO_ID_TCP,                 "DOD TCP"},
291         { PROTO_ID_UDP,                 "DOD UDP"},
292         { PROTO_ID_IP,                  "DOD IP"},
293         { PROTO_ID_RPC_CL,              "RPC connectionless protocol"},
294         { PROTO_ID_RPC_CO,              "RPC connection-oriented protocol"},
295         { PROTO_ID_UUID,                "UUID"},
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
328     di=pinfo->private_data;
329     if(di->conformant_run){
330         return offset;
331     }
332
333     num_floors = tvb_get_letohs(tvb, offset);
334     proto_tree_add_uint(tree, hf_epm_tower_num_floors, tvb, offset, 2, num_floors);
335     offset += 2;
336
337     for(i=1;i<=num_floors;i++){
338         proto_item *it = NULL;
339         proto_tree *tr = NULL;
340         int old_offset = offset;
341         guint16 len;
342         guint8 proto_id;
343         e_uuid_t uuid;
344
345         it = proto_tree_add_text(tree, tvb, offset, 0, "Floor %d  ", i);
346         tr = proto_item_add_subtree(it, ett_epm_tower_floor);
347
348         len = tvb_get_letohs(tvb, offset);
349         proto_tree_add_uint(tr, hf_epm_tower_lhs_len, tvb, offset, 2, len);
350         offset += 2;
351
352         proto_id = tvb_get_guint8(tvb, offset);
353         proto_tree_add_uint(tr, hf_epm_tower_proto_id, tvb, offset, 1, proto_id);
354
355         switch(proto_id){
356         case PROTO_ID_UUID:
357             dcerpc_tvb_get_uuid (tvb, offset+1, drep, &uuid);
358
359             proto_tree_add_string_format (tr, hf_epm_uuid, tvb, offset+1, 16, "",
360                           "UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
361                           uuid.Data1, uuid.Data2, uuid.Data3,
362                           uuid.Data4[0], uuid.Data4[1],
363                           uuid.Data4[2], uuid.Data4[3],
364                           uuid.Data4[4], uuid.Data4[5],
365                           uuid.Data4[6], uuid.Data4[7]);
366             proto_tree_add_text(tr, tvb, offset+17, 2, "Version %d.%d", tvb_get_guint8(tvb, offset+17), tvb_get_guint8(tvb, offset+18));
367
368             {
369                 guint16 version = tvb_get_ntohs(tvb, offset+17); 
370                 char *service = dcerpc_get_proto_name(&uuid, version);
371                 if (service)
372                     proto_item_append_text(tr, "UUID: %s", service);
373                 else
374                     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,
375                                            uuid.Data4[0], uuid.Data4[1],
376                                            uuid.Data4[2], uuid.Data4[3],
377                                            uuid.Data4[4], uuid.Data4[5],
378                                            uuid.Data4[6], uuid.Data4[7],
379                                            tvb_get_guint8(tvb, offset+17), 
380                                            tvb_get_guint8(tvb, offset+18));
381             }
382             break;
383         }
384         offset += len;
385
386         len = tvb_get_letohs(tvb, offset);
387         proto_tree_add_uint(tr, hf_epm_tower_rhs_len, tvb, offset, 2, len);
388         offset += 2;
389
390         switch(proto_id){
391
392         case PROTO_ID_TCP: /* this one is always big endian */
393             proto_tree_add_item(tr, hf_epm_proto_tcp_port, tvb, offset, 2, FALSE);
394             proto_item_append_text(tr, "TCP Port:%d", tvb_get_ntohs(tvb, offset));
395             break;
396
397         case PROTO_ID_UDP: /* this one is always big endian */
398             proto_tree_add_item(tr, hf_epm_proto_udp_port, tvb, offset, 2, FALSE);
399             proto_item_append_text(tr, "UDP Port:%d", tvb_get_ntohs(tvb, offset));
400             break;
401
402         case PROTO_ID_IP: /* this one is always big endian */
403             proto_tree_add_item(tr, hf_epm_proto_ip, tvb, offset, 4, FALSE);
404             proto_item_append_text(tr, "IP:%s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
405             break;
406
407         case PROTO_ID_RPC_CO:
408             proto_item_append_text(tr, "RPC connection-oriented protocol");
409             break;
410
411         case PROTO_ID_NAMED_PIPES: /* \\PIPE\xxx   named pipe */
412             tvb_ensure_bytes_exist(tvb, offset, len);
413             proto_tree_add_item(tr, hf_epm_proto_named_pipes, tvb, offset, len, TRUE);
414             proto_item_append_text(tr, "NamedPipe:%*s",MIN(len,tvb_length_remaining(tvb, offset)), tvb_get_ptr(tvb, offset, -1)); 
415             break;
416
417         case PROTO_ID_NAMED_PIPES_2: /* PIPENAME  named pipe */
418             tvb_ensure_bytes_exist(tvb, offset, len);
419             proto_tree_add_item(tr, hf_epm_proto_named_pipes, tvb, offset, len, TRUE);
420             proto_item_append_text(tr, "PIPE:%*s",MIN(len,tvb_length_remaining(tvb, offset)), tvb_get_ptr(tvb, offset, -1)); 
421             break;
422
423         case PROTO_ID_NETBIOS: /* \\NETBIOS   netbios name */
424             tvb_ensure_bytes_exist(tvb, offset, len);
425             proto_tree_add_item(tr, hf_epm_proto_netbios_name, tvb, offset, len, TRUE);
426             proto_item_append_text(tr, "NetBIOS:%*s",MIN(len,tvb_length_remaining(tvb, offset)), tvb_get_ptr(tvb, offset, -1)); 
427             break;
428         case PROTO_ID_HTTP: /* RPC over HTTP */
429             proto_tree_add_item(tr, hf_epm_proto_http_port, tvb, offset, 2, FALSE);
430             proto_item_append_text(tr, "RPC over HTTP Port:%d", tvb_get_ntohs(tvb, offset));
431             break;
432                         
433         default:
434             if(len){
435                 tvb_ensure_bytes_exist(tvb, offset, len);
436                 proto_tree_add_text(tr, tvb, offset, len, "not decoded yet");
437             }
438         }
439         offset += len;
440
441         proto_item_set_len(it, offset-old_offset);
442     }
443     return offset;
444 }
445
446 /* typedef struct {
447       unsigned int tower_len,
448       [size_is(tower_len)] char tower[];
449    } twr_t, *twr_p_t;
450 */
451 static int
452 epm_dissect_tower (tvbuff_t *tvb, int offset,
453                              packet_info *pinfo, proto_tree *tree,
454                              guint8 *drep)
455 {
456     guint32 len;
457     dcerpc_info *di;
458
459     di=pinfo->private_data;
460     if(di->conformant_run){
461         return offset;
462     }
463
464     /* first one is the header of the conformant array, second one is the
465        length field */
466     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
467                                  hf_epm_tower_length, &len);
468     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
469                                  hf_epm_tower_length, NULL);
470     offset = epm_dissect_tower_data(tvb, offset, pinfo, tree, drep);
471
472     return offset;
473 }
474 static int
475 epm_dissect_tower_pointer (tvbuff_t *tvb, int offset,
476                              packet_info *pinfo, proto_tree *tree,
477                              guint8 *drep)
478 {
479     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
480                              epm_dissect_tower, NDR_POINTER_PTR,
481                              "Tower pointer:", -1);
482     return offset;
483 }
484 static int
485 epm_dissect_tower_array (tvbuff_t *tvb, int offset,
486                              packet_info *pinfo, proto_tree *tree,
487                              guint8 *drep)
488 {
489     offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, drep,
490                              epm_dissect_tower_pointer);
491
492     return offset;
493 }
494
495 static int
496 epm_dissect_ept_map_rqst (tvbuff_t *tvb, int offset,
497                              packet_info *pinfo, proto_tree *tree,
498                              guint8 *drep)
499 {
500     /* [in, ptr] uuid_p_t object */
501     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
502                              epm_dissect_uuid, NDR_POINTER_PTR,
503                              "UUID pointer:", -1);
504
505     /* [in, ptr] twr_p_t map_tower */
506     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
507                              epm_dissect_tower, NDR_POINTER_PTR,
508                              "Tower pointer:", -1);
509
510     /* [in, out] ept_lookup_handle_t *entry_handle */
511     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
512                                   hf_epm_hnd, NULL);
513
514     /* [in] unsigned32 max_towers */
515     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
516                                  hf_epm_max_towers, NULL);
517
518     return offset;
519 }
520
521 static int
522 epm_dissect_ept_map_resp (tvbuff_t *tvb, int offset,
523                              packet_info *pinfo, proto_tree *tree,
524                              guint8 *drep)
525 {
526     /* [in, out] ept_lookup_handle_t *entry_handle */
527     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
528                                   hf_epm_hnd, NULL);
529
530     /* [out, ptr] unsigned32 *num_towers */
531     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
532                                  hf_epm_num_towers, NULL);
533
534     /* [out, length_is(*num_towers), size_is(max_towers), ptr] twr_p_t towers[] */
535     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
536                              epm_dissect_tower_array, NDR_POINTER_REF,
537                              "Tower array:", -1);
538
539     /* [out] error_status_t *status */
540     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
541                                  hf_epm_rc, NULL);
542
543     return offset;
544 }
545
546 static int
547 epm_dissect_ept_entry_t_ucarray(tvbuff_t *tvb, int offset,
548                              packet_info *pinfo, proto_tree *tree,
549                              guint8 *drep)
550 {
551     offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, drep,
552                              epm_dissect_ept_entry_t);
553
554     return offset;
555 }
556
557 static int
558 epm_dissect_ept_insert_rqst (tvbuff_t *tvb, int offset,
559                              packet_info *pinfo, proto_tree *tree,
560                              guint8 *drep)
561 {
562     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
563                                  hf_epm_num_ents, NULL);
564
565     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
566                              epm_dissect_ept_entry_t_ucarray, NDR_POINTER_REF,
567                              "Entries:", -1);
568
569     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
570                                  hf_epm_replace, NULL);
571
572     return offset;
573 }
574
575
576
577 static int
578 epm_dissect_ept_insert_resp (tvbuff_t *tvb, int offset,
579                              packet_info *pinfo, proto_tree *tree,
580                              guint8 *drep)
581 {
582     /* [out] error_status_t *status */
583     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
584                                  hf_epm_rc, NULL);
585
586     return offset;
587 }
588
589
590 static int
591 epm_dissect_ept_delete_rqst (tvbuff_t *tvb, int offset,
592                              packet_info *pinfo, proto_tree *tree,
593                              guint8 *drep)
594 {
595     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
596                                  hf_epm_num_ents, NULL);
597
598     offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, drep,
599                              epm_dissect_ept_entry_t_ucarray, NDR_POINTER_REF,
600                              "Entries:", -1);
601
602     return offset;
603 }
604
605
606
607 static int
608 epm_dissect_ept_delete_resp (tvbuff_t *tvb, int offset,
609                              packet_info *pinfo, proto_tree *tree,
610                              guint8 *drep)
611 {
612     /* [out] error_status_t *status */
613     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
614                                  hf_epm_rc, NULL);
615
616     return offset;
617 }
618
619
620
621 static int
622 epm_dissect_ept_lookup_handle_free_rqst (tvbuff_t *tvb, int offset,
623                              packet_info *pinfo, proto_tree *tree,
624                              guint8 *drep)
625 {
626     /* [in, out] ept_lookup_handle_t *entry_handle */
627     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
628                                   hf_epm_hnd, NULL);
629
630     return offset;
631 }
632
633 static int
634 epm_dissect_ept_lookup_handle_free_resp (tvbuff_t *tvb, int offset,
635                              packet_info *pinfo, proto_tree *tree,
636                              guint8 *drep)
637 {
638     /* [in, out] ept_lookup_handle_t *entry_handle */
639     offset = dissect_ndr_ctx_hnd (tvb, offset, pinfo, tree, drep,
640                                   hf_epm_hnd, NULL);
641
642     offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, drep,
643                                  hf_epm_rc, NULL);
644
645     return offset;
646 }
647
648
649 static dcerpc_sub_dissector epm_dissectors[] = {
650     { 0, "Insert", 
651         epm_dissect_ept_insert_rqst,
652         epm_dissect_ept_insert_resp },
653     { 1, "Delete",
654         epm_dissect_ept_delete_rqst,
655         epm_dissect_ept_delete_resp },
656     { 2, "Lookup",
657         epm_dissect_ept_lookup_rqst,
658         epm_dissect_ept_lookup_resp },
659     { 3, "Map",
660         epm_dissect_ept_map_rqst,
661         epm_dissect_ept_map_resp },
662     { 4, "LookupHandleFree",
663         epm_dissect_ept_lookup_handle_free_rqst,
664         epm_dissect_ept_lookup_handle_free_resp },
665     { 5, "InqObject", NULL, NULL },
666     { 6, "MgmtDelete", NULL, NULL },
667     { 0, NULL, NULL, NULL }
668 };
669
670 void
671 proto_register_epm (void)
672 {
673     static hf_register_info hf[] = {
674         { &hf_epm_opnum,
675           { "Operation", "epm.opnum", FT_UINT16, BASE_DEC,
676             NULL, 0x0, "Operation", HFILL }},
677         { &hf_epm_inquiry_type,
678           { "Inquiry type", "epm.inq_type", FT_UINT32, BASE_DEC, VALS(ep_service), 0x0, "", HFILL }},
679         { &hf_epm_object,
680           { "Object", "epm.object", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
681         { &hf_epm_if_id,
682           { "Interface", "epm.if_id", FT_STRING, BASE_NONE, NULL, 0x0, "", HFILL }},
683         { &hf_epm_ver_maj,
684           { "Version Major", "epm.ver_maj", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
685         { &hf_epm_ver_min,
686           { "Version Minor", "epm.ver_min", FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
687         { &hf_epm_ver_opt,
688           { "Version Option", "epm.ver_opt", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
689         { &hf_epm_hnd,
690           { "Handle", "epm.hnd", FT_BYTES, BASE_NONE, NULL, 0x0, "Context handle", HFILL }},
691         { &hf_epm_max_ents,
692           { "Max entries", "epm.max_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
693         { &hf_epm_num_ents,
694           { "Num entries", "epm.num_ents", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
695         { &hf_epm_uuid,
696           { "UUID", "epm.uuid", FT_STRING, BASE_NONE, NULL, 0x0, "UUID", HFILL }},
697         { &hf_epm_annotation,
698           { "Annotation", "epm.annotation", FT_STRING, BASE_NONE, NULL, 0x0, "Annotation", HFILL }},
699         { &hf_epm_proto_named_pipes,
700           { "Named Pipe", "epm.proto.named_pipe", FT_STRING, BASE_NONE, NULL, 0x0, "Name of the named pipe for this service", HFILL }},
701         { &hf_epm_proto_netbios_name,
702           { "NetBIOS Name", "epm.proto.netbios_name", FT_STRING, BASE_NONE, NULL, 0x0, "NetBIOS name where this service can be found", HFILL }},
703         { &hf_epm_tower_length,
704           { "Length", "epm.tower.len", FT_UINT32, BASE_DEC, NULL, 0x0, "Length of tower data", HFILL }},
705         { &hf_epm_tower_data,
706           { "Tower", "epm.tower", FT_BYTES, BASE_HEX, NULL, 0x0, "Tower data", HFILL }},
707         { &hf_epm_max_towers,
708           { "Max Towers", "epm.max_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Maximum number of towers to return", HFILL }},
709         { &hf_epm_num_towers,
710           { "Num Towers", "epm.num_towers", FT_UINT32, BASE_DEC, NULL, 0x0, "Number number of towers to return", HFILL }},
711         { &hf_epm_ann_offset,
712           { "Annotation offset", "epm.ann_offset", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
713         { &hf_epm_ann_len,
714           { "Annotation length", "epm.ann_len", FT_UINT32, BASE_DEC, NULL, 0x0, "", HFILL }},
715         { &hf_epm_rc,
716           { "Return code", "epm.rc", FT_UINT32, BASE_HEX, NULL, 0x0, "EPM return value", HFILL }},
717         { &hf_epm_replace,
718           { "Replace", "epm.replace", FT_UINT8, BASE_DEC, NULL, 0x0, "Replace existing objects?", HFILL }},
719         { &hf_epm_tower_num_floors,
720           { "Number of floors", "epm.tower.num_floors", FT_UINT16, BASE_DEC, NULL, 0x0, "Number of floors in tower", HFILL }},
721         { &hf_epm_proto_udp_port,
722           { "UDP Port", "epm.proto.udp_port", FT_UINT16, BASE_DEC, NULL, 0x0, "UDP Port where this service can be found", HFILL }},
723         { &hf_epm_proto_tcp_port,
724           { "TCP Port", "epm.proto.tcp_port", FT_UINT16, BASE_DEC, NULL, 0x0, "TCP Port where this service can be found", HFILL }},
725         { &hf_epm_proto_http_port,
726           { "TCP Port", "epm.proto.http_port", FT_UINT16, BASE_DEC, NULL, 0x0, "TCP Port where this service can be found", HFILL }},      
727         { &hf_epm_tower_rhs_len,
728           { "RHS Length", "epm.tower.rhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of RHS data", HFILL }},
729         { &hf_epm_tower_lhs_len,
730           { "LHS Length", "epm.tower.lhs.len", FT_UINT16, BASE_DEC, NULL, 0x0, "Length of LHS data", HFILL }},
731         { &hf_epm_proto_ip,
732           { "IP", "epm.proto.ip", FT_IPv4, BASE_NONE, NULL, 0x0, "IP address where service is located", HFILL }},
733         { &hf_epm_tower_proto_id,
734           { "Protocol", "epm.tower.proto_id", FT_UINT8, BASE_HEX, VALS(proto_id_vals), 0x0, "Protocol identifier", HFILL }}
735     };
736     static gint *ett[] = {
737         &ett_epm,
738         &ett_epm_tower_floor,
739         &ett_epm_entry
740     };
741     
742     /* interface version 3 */
743     proto_epm3 = proto_register_protocol ("DCE/RPC Endpoint Mapper", "EPM", "epm");
744     proto_register_field_array (proto_epm3, hf, array_length (hf));
745     proto_register_subtree_array (ett, array_length (ett));
746
747     /* interface version 4 */
748         proto_epm4 = proto_register_protocol ("DCE/RPC Endpoint Mapper v4", "EPMv4", "epm4");
749 }
750
751 void
752 proto_reg_handoff_epm (void)
753 {
754     /* Register the protocol as dcerpc */
755     dcerpc_init_uuid (proto_epm3, ett_epm, &uuid_epm, ver_epm3, epm_dissectors, hf_epm_opnum);
756     dcerpc_init_uuid (proto_epm4, ett_epm, &uuid_epm, ver_epm4, epm_dissectors, hf_epm_opnum);
757 }