Update Free Software Foundation address.
[metze/wireshark/wip.git] / epan / dissectors / packet-dcom-remunkn.c
1 /* packet-dcom-remunkn.c
2  * Routines for the IRemUnknown interface
3  * Copyright 2004, Jelmer Vernooij <jelmer@samba.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 /* see packet-dcom.c for details about DCOM */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include <epan/emem.h>
35 #include "packet-dcerpc.h"
36 #include "packet-dcom.h"
37 #include "guid-utils.h"
38
39
40 static int hf_remunk_opnum = -1;
41
42
43 static int hf_remunk_refs = -1;
44 static int hf_remunk_iids = -1;
45
46 static int hf_remunk_flags = -1;
47 static int hf_remunk_qiresult = -1;
48
49 static gint ett_remunk_reminterfaceref = -1;
50 static int hf_remunk_reminterfaceref = -1;
51 static int hf_remunk_interface_refs = -1;
52 static int hf_remunk_public_refs = -1;
53 static int hf_remunk_private_refs = -1;
54
55
56 static gint ett_remunk_rqi_result = -1;
57
58
59 static gint ett_remunk = -1;
60 static e_uuid_t uuid_remunk = { 0x00000131, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
61 static guint16  ver_remunk = 0;
62 static int proto_remunk = -1;
63
64 static e_uuid_t ipid_remunk = { 0x00000131, 0x1234, 0x5678, { 0xCA, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
65
66 /* There is a little bit confusion about the IRemUnknown2 interface UUIDs */
67 /* DCOM documentation tells us: 0x00000142 (7 methods) */
68 /* win2000 registry tells us: 0x00000142 IRemoteQI (4 methods) */
69 /* win2000 registry tells us: 0x00000143 IRemUnknown2 (7 methods) */
70 /* There is some evidence, that the DCOM documentation is wrong, so using 143 for IRemUnknown2 now. */
71
72 static gint ett_remunk2 = -1;
73 static e_uuid_t uuid_remunk2 = { 0x00000143, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
74 static guint16  ver_remunk2 = 0;
75 static int proto_remunk2 = -1;
76
77
78 typedef struct remunk_remqueryinterface_call_s {
79     guint        iid_count;
80     e_uuid_t    *iids;
81 } remunk_remqueryinterface_call_t;
82
83
84 static int
85 dissect_remunk_remqueryinterface_rqst(tvbuff_t *tvb, int offset,
86                                       packet_info *pinfo, proto_tree *tree, guint8 *drep)
87 {
88     e_uuid_t     ipid;
89     guint32      u32Refs;
90     guint16      u16IIDs;
91     guint32      u32ArraySize;
92     guint32      u32ItemIdx;
93     e_uuid_t     iid;
94     dcerpc_info *info = (dcerpc_info *) pinfo->private_data;
95     remunk_remqueryinterface_call_t *call;
96
97
98     offset = dissect_dcom_this(tvb, offset, pinfo, tree, drep);
99
100     offset = dissect_dcom_UUID(tvb, offset, pinfo, tree, drep,
101                                hf_dcom_ipid, &ipid);
102
103     offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, drep,
104                                 hf_remunk_refs, &u32Refs);
105
106     offset = dissect_dcom_WORD(tvb, offset, pinfo, tree, drep,
107                                hf_remunk_iids, &u16IIDs);
108
109     offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, drep,
110                                             &u32ArraySize);
111
112     /* limit the allocation to a reasonable size */
113     if(u32ArraySize < 100) {
114         call = se_alloc(sizeof(remunk_remqueryinterface_call_t) + u32ArraySize * sizeof(e_uuid_t));
115         call->iid_count = u32ArraySize;
116         call->iids = (e_uuid_t *) (call+1);
117         info->call_data->private_data = call;
118     } else {
119         call = NULL;
120     }
121
122     for (u32ItemIdx = 0; u32ArraySize--; u32ItemIdx++) {
123         offset = dissect_dcom_append_UUID(tvb, offset,  pinfo, tree, drep,
124                                           hf_dcom_iid, u32ItemIdx+1, &iid);
125         if(call != NULL) {
126             call->iids[u32ItemIdx] = iid;
127         }
128     }
129
130     return offset;
131 }
132
133
134 static int
135 dissect_remunk_remqueryinterface_resp(tvbuff_t *tvb, int offset,
136                                       packet_info *pinfo, proto_tree *tree, guint8 *drep)
137 {
138     guint32      u32Pointer;
139     guint32      u32ArraySize;
140     guint32      u32ItemIdx;
141     proto_item  *sub_item;
142     proto_tree  *sub_tree;
143     guint32      u32HResult;
144     guint32      u32SubStart;
145     e_uuid_t     iid;
146     e_uuid_t     iid_null = DCERPC_UUID_NULL;
147     dcerpc_info *info = (dcerpc_info *) pinfo->private_data;
148     remunk_remqueryinterface_call_t *call = info->call_data->private_data;
149     guint64      oxid;
150     guint64      oid;
151     e_uuid_t     ipid;
152
153
154     offset = dissect_dcom_that(tvb, offset, pinfo, tree, drep);
155
156     offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, drep,
157                                          &u32Pointer);
158     offset = dissect_dcom_dcerpc_array_size(tvb, offset, pinfo, tree, drep,
159                                             &u32ArraySize);
160
161     u32ItemIdx = 1;
162     while (u32ArraySize--) {
163         /* add subtree */
164         sub_item = proto_tree_add_item(tree, hf_remunk_qiresult, tvb, offset, 0, ENC_NA);
165         sub_tree = proto_item_add_subtree(sub_item, ett_remunk_rqi_result);
166
167         /* REMQIRESULT */
168         offset = dissect_dcom_HRESULT(tvb, offset, pinfo, sub_tree, drep,
169                                       &u32HResult);
170         u32SubStart = offset - 4;
171         offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, sub_tree, drep,
172                                              &u32Pointer);
173
174         /* try to read the iid from the request */
175         if(call != NULL && u32ItemIdx <= call->iid_count) {
176             iid = call->iids[u32ItemIdx-1];
177         } else {
178             iid = iid_null;
179         }
180
181         /* XXX - this doesn't seem to be dependent on the pointer above?!? */
182         /*if (u32Pointer) {*/
183         offset = dissect_dcom_STDOBJREF(tvb, offset, pinfo, sub_tree, drep, 0 /* hfindex */,
184                                         &oxid, &oid, &ipid);
185         /*}*/
186
187         /* add interface instance to database (we currently only handle IPv4) */
188         if(pinfo->net_src.type == AT_IPv4) {
189             dcom_interface_new(pinfo,
190                                pinfo->net_src.data,
191                                &iid, oxid, oid, &ipid);
192         }
193
194         /* update subtree */
195         proto_item_append_text(sub_item, "[%u]: %s",
196                                u32ItemIdx,
197                                val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)") );
198         proto_item_set_len(sub_item, offset - u32SubStart);
199
200         /* update column info now */
201         col_append_fstr(pinfo->cinfo, COL_INFO, " %s[%u]",
202                         val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)"),
203                         u32ItemIdx);
204         u32ItemIdx++;
205     }
206
207     /* HRESULT of call */
208     offset = dissect_dcom_HRESULT(tvb, offset, pinfo, tree, drep,
209                                   &u32HResult);
210
211     /* update column info now */
212     col_append_fstr(pinfo->cinfo, COL_INFO, " -> %s",
213                     val_to_str(u32HResult, dcom_hresult_vals, "Unknown (0x%08x)"));
214
215     return offset;
216 }
217
218
219 static int
220 dissect_remunk_remrelease_rqst(tvbuff_t *tvb, int offset,
221                                packet_info *pinfo, proto_tree *tree, guint8 *drep)
222 {
223     guint32      u32Pointer;
224     guint32      u32IntRefs;
225     guint32      u32ItemIdx;
226     e_uuid_t     ipid;
227     guint32      u32PublicRefs;
228     guint32      u32PrivateRefs;
229     const gchar *pszFormat;
230     proto_item  *sub_item;
231     proto_tree  *sub_tree;
232     guint32      u32SubStart;
233
234
235     offset = dissect_dcom_this(tvb, offset, pinfo, tree, drep);
236
237     offset = dissect_dcom_dcerpc_pointer(tvb, offset, pinfo, tree, drep,
238                                          &u32Pointer);
239
240     offset = dissect_dcom_DWORD(tvb, offset, pinfo, tree, drep,
241                                 hf_remunk_interface_refs, &u32IntRefs);
242
243     /* update column info now */
244     if (u32IntRefs) {
245         col_append_fstr(pinfo->cinfo, COL_INFO, " Cnt=%u Refs=", u32IntRefs);
246     } else {
247         col_append_str(pinfo->cinfo, COL_INFO, " Cnt=0");
248     }
249
250
251     u32ItemIdx = 1;
252     while (u32IntRefs--) {
253         /* add subtree */
254         sub_item = proto_tree_add_item(tree, hf_remunk_reminterfaceref, tvb, offset, 0, ENC_NA);
255         sub_tree = proto_item_add_subtree(sub_item, ett_remunk_reminterfaceref);
256         u32SubStart = offset;
257
258         offset = dissect_dcom_UUID(tvb, offset, pinfo, sub_tree, drep,
259                                    hf_dcom_ipid, &ipid);
260
261         offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, drep,
262                                     hf_remunk_public_refs, &u32PublicRefs);
263
264         offset = dissect_dcom_DWORD(tvb, offset, pinfo, sub_tree, drep,
265                                     hf_remunk_private_refs, &u32PrivateRefs);
266
267         /* update subtree */
268         proto_item_append_text(sub_item, "[%u]: IPID=%s, PublicRefs=%u, PrivateRefs=%u",
269                                u32ItemIdx,
270                                guids_resolve_uuid_to_str(&ipid),
271                                u32PublicRefs, u32PrivateRefs);
272         proto_item_set_len(sub_item, offset - u32SubStart);
273
274         /* update column info now */
275         pszFormat = "";
276         if (u32ItemIdx == 1) {
277             pszFormat = "%u-%u";
278         } else if (u32ItemIdx < 10) {
279             pszFormat = ",%u-%u";
280         } else if (u32ItemIdx == 10) {
281             pszFormat = ",...";
282         }
283         col_append_fstr(pinfo->cinfo, COL_INFO, pszFormat, u32PublicRefs, u32PrivateRefs);
284  
285         u32ItemIdx++;
286     }
287
288     return offset;
289 }
290
291
292 /* sub dissector table of IRemUnknown interface */
293 static dcerpc_sub_dissector remunk_dissectors[] = {
294     { 0, "QueryInterface", NULL, NULL },
295     { 1, "AddRef", NULL, NULL },
296     { 2, "Release", NULL, NULL },
297
298     { 3, "RemQueryInterface", dissect_remunk_remqueryinterface_rqst, dissect_remunk_remqueryinterface_resp },
299     { 4, "RemAddRef", NULL, NULL },
300     { 5, "RemRelease", dissect_remunk_remrelease_rqst, dissect_dcom_simple_resp },
301     { 0, NULL, NULL, NULL }
302 };
303
304 /* sub dissector table of IRemUnknown2 interface */
305 static dcerpc_sub_dissector remunk2_dissectors[] = {
306     { 0, "QueryInterface", NULL, NULL },
307     { 1, "AddRef", NULL, NULL },
308     { 2, "Release", NULL, NULL },
309
310     { 3, "RemQueryInterface", dissect_remunk_remqueryinterface_rqst, dissect_remunk_remqueryinterface_resp },
311     { 4, "RemAddRef", NULL, NULL },
312     { 5, "RemRelease", dissect_remunk_remrelease_rqst, dissect_dcom_simple_resp },
313
314     { 6, "RemQueryInterface2", NULL, NULL },
315     { 0, NULL, NULL, NULL }
316 };
317
318
319
320 void
321 proto_register_remunk (void)
322 {
323     static hf_register_info hf_remunk_rqi_array[] = {
324         { &hf_remunk_opnum,
325           { "Operation", "remunk.opnum", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
326
327         { &hf_remunk_refs,
328           { "Refs", "remunk.refs", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
329         { &hf_remunk_iids,
330           { "IIDs", "remunk.iids", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
331         { &hf_remunk_qiresult,
332           { "QIResult", "remunk.qiresult", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
333         { &hf_remunk_flags,
334           { "Flags", "remunk.flags",  FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
335         { &hf_remunk_public_refs,
336           { "PublicRefs", "remunk.public_refs",  FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
337         { &hf_remunk_reminterfaceref,
338           { "RemInterfaceRef", "remunk.reminterfaceref",  FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
339         { &hf_remunk_interface_refs,
340           { "InterfaceRefs", "remunk.int_refs",  FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
341         { &hf_remunk_private_refs,
342           { "PrivateRefs", "remunk.private_refs",  FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }}
343     };
344
345     static gint *ett_remunk_array[] = {
346         &ett_remunk,
347         &ett_remunk_rqi_result,
348         &ett_remunk2,
349         &ett_remunk_reminterfaceref
350     };
351
352     proto_remunk = proto_register_protocol ("IRemUnknown", "IRemUnknown", "remunk");
353     proto_register_field_array (proto_remunk, hf_remunk_rqi_array, array_length (hf_remunk_rqi_array));
354
355     proto_remunk2 = proto_register_protocol ("IRemUnknown2", "IRemUnknown2", "remunk2");
356
357     proto_register_subtree_array (ett_remunk_array, array_length (ett_remunk_array));
358 }
359
360 void
361 proto_reg_handoff_remunk (void)
362 {
363
364     /* Register the IPID */
365     guids_add_uuid(&ipid_remunk, "IPID-IRemUnknown");
366
367     /* Register the interfaces */
368     dcerpc_init_uuid(proto_remunk, ett_remunk,
369                      &uuid_remunk, ver_remunk,
370                      remunk_dissectors, hf_remunk_opnum);
371
372     dcerpc_init_uuid(proto_remunk2, ett_remunk2,
373                      &uuid_remunk2, ver_remunk2,
374                      remunk2_dissectors, hf_remunk_opnum);
375 }