From Tim Potter: dissect some of the LSA RPCs stub data.
[obnox/wireshark/wip.git] / packet-dcerpc-nt.c
1 /* packet-dcerpc-nt.c
2  * Routines for DCERPC over SMB packet disassembly
3  * Copyright 2001, Tim Potter <tpot@samba.org>
4  *
5  * $Id: packet-dcerpc-nt.c,v 1.1 2001/12/16 20:17:10 guy Exp $
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 #include <glib.h>
31 #include "packet.h"
32 #include "packet-dcerpc.h"
33 #include "packet-dcerpc-nt.h"
34 #include "smb.h"
35
36 /*
37  * This file contains helper routines that are used by the DCERPC over SMB
38  * dissectors for ethereal.
39  */
40
41 /* Align offset to a n-byte boundary */
42
43 int prs_align(int offset, int n)
44 {
45         if (offset % n)
46                 offset += n - (offset % n);
47         
48         return offset;
49 }
50
51 /* Parse a 8-bit integer */
52
53 int prs_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
54               proto_tree *tree, guint8 *data, char *name)
55 {
56         guint8 i;
57         
58         /* No alignment required */
59
60         i = tvb_get_guint8(tvb, offset);
61         offset++;
62
63         if (name && tree)
64                 proto_tree_add_text(tree, tvb, offset - 1, 1, 
65                                     "%s: %d", name, i);
66
67         if (data)
68                 *data = i;
69
70         return offset;
71 }
72
73 int prs_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo,
74                proto_tree *tree, int count, guint8 **data, char *name)
75 {
76         const guint8 *ptr;
77         
78         /* No alignment required */
79
80         ptr = tvb_get_ptr(tvb, offset, count);
81
82         if (name && tree)
83                 proto_tree_add_text(tree, tvb, offset, count, "%s", name);
84
85         if (data)
86                 *data = (guint8 *)ptr;
87
88         offset += count;
89
90         return offset;
91 }
92
93 /* Parse a 16-bit integer */
94
95 int prs_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
96                proto_tree *tree, guint16 *data, char *name)
97 {
98         guint16 i;
99         
100         offset = prs_align(offset, 2);
101         
102         i = tvb_get_letohs(tvb, offset);
103         offset += 2;
104
105         if (name && tree)
106                 proto_tree_add_text(tree, tvb, offset - 2, 2, 
107                                     "%s: %d", name, i);
108         if (data)
109                 *data = i;
110
111         return offset;
112 }
113
114 /* Parse a number of uint16's */
115
116 int prs_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo,
117                 proto_tree *tree, int count, guint16 **data, char *name)
118 {
119         const guint8 *ptr;
120         
121         offset = prs_align(offset, 2);
122         
123         ptr = tvb_get_ptr(tvb, offset, count * 2);
124
125         if (name && tree)
126                 proto_tree_add_text(tree, tvb, offset, count * 2, 
127                                     "%s", name);
128         if (data)
129                 *data = (guint16 *)ptr;
130
131         offset += count * 2;
132
133         return offset;
134 }
135
136 /* Parse a 32-bit integer */
137
138 int prs_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
139                proto_tree *tree, guint32 *data, char *name)
140 {
141         guint32 i;
142         
143         offset = prs_align(offset, 4);
144         
145         i = tvb_get_letohl(tvb, offset);
146         offset += 4;
147
148         if (name && tree)
149                 proto_tree_add_text(tree, tvb, offset - 4, 4, 
150                                     "%s: %d", name, i);
151
152         if (data)
153                 *data = i;
154
155         return offset;
156 }
157
158 /* Parse a number of 32-bit integers */
159
160 int prs_uint32s(tvbuff_t *tvb, int offset, packet_info *pinfo,
161                 proto_tree *tree, int count, guint32 **data, char *name)
162 {
163         const guint8 *ptr;
164         
165         offset = prs_align(offset, 4);
166         
167         ptr = tvb_get_ptr(tvb, offset, count * 4);
168
169         if (name && tree)
170                 proto_tree_add_text(tree, tvb, offset - 4, 4, 
171                                     "%s", name);
172         if (data)
173                 *data = (guint32 *)ptr;
174
175         offset += count * 4;
176
177         return offset;
178 }
179
180 /* Parse a NT status code */
181
182 int prs_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo,
183                  proto_tree *tree)
184 {
185         guint32 status;
186
187         offset = prs_uint32(tvb, offset, pinfo, tree, &status, NULL);
188
189         if (tree)
190                 proto_tree_add_text(tree, tvb, offset - 4, 4, "Status: %s",
191                                     val_to_str(status, NT_errors, "???"));
192
193         return offset;
194 }
195
196 /*
197  * We need to keep track of deferred referrents as they appear in the
198  * packet after all the non-pointer objects.
199  * to keep track of pointers as they are parsed as scalars and need to be
200  * remembered for the next call to the prs function.
201  *
202  * Pointers are stored in a linked list and pushed in the PARSE_SCALARS
203  * section of the prs function and popped in the PARSE_BUFFERS section.  If
204  * we try to pop off a referrent that has a different name then we are
205  * expecting then something has gone wrong.
206  */
207
208 #undef DEBUG_PTRS
209
210 struct ptr {
211         char *name;
212         guint32 value;
213 };
214
215 /* Create a new pointer */
216
217 static struct ptr *new_ptr(char *name, guint32 value)
218 {
219         struct ptr *p;
220
221         p = g_malloc(sizeof(struct ptr));
222
223         p->name = g_strdup(name);
224         p->value = value;
225
226         return p;
227 }
228
229 /* Free a pointer */
230
231 static void free_ptr(struct ptr *p)
232 {
233         if (p) {
234                 g_free(p->name);
235                 g_free(p);
236         }
237 }
238
239 /* Parse a pointer and store it's value in a linked list */
240
241 int prs_push_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo,
242                  proto_tree *tree, GList **ptr_list, char *name)
243 {
244         struct ptr *p;
245         guint32 value;
246
247         offset = prs_uint32(tvb, offset, pinfo, tree, &value, NULL);
248
249         if (name && tree)
250                 proto_tree_add_text(tree, tvb, offset - 4, 4, 
251                                     "%s pointer: 0x%08x", name, value);
252
253         p = new_ptr(name, value);
254
255         *ptr_list = g_list_append(*ptr_list, p);
256
257 #ifdef DEBUG_PTRS
258         fprintf(stderr, "DEBUG_PTRS: pushing %s ptr = 0x%08x, %d ptrs in "
259                 "list\n", name, value, g_list_length(*ptr_list));
260 #endif
261
262         return offset;
263 }
264
265 /* Pop a pointer of a given name.  Return it's value. */
266
267 guint32 prs_pop_ptr(GList **ptr_list, char *name)
268 {
269         GList *elt;
270         struct ptr *p;
271         guint32 result;
272
273         g_assert(g_list_length(*ptr_list) != 0);        /* List too short */
274
275         /* Get pointer at head of list */
276
277         elt = g_list_first(*ptr_list);
278         p = (struct ptr *)elt->data;
279         result = p->value;
280
281 #ifdef DEBUG_PTRS
282         if (strcmp(p->name, name) != 0) {
283                 fprintf(stderr, "DEBUG_PTRS: wrong pointer (%s != %s)\n",
284                         p->name, name);
285         }
286 #endif
287
288         /* Free pointer record */
289
290         *ptr_list = g_list_remove_link(*ptr_list, elt);
291
292 #ifdef DEBUG_PTRS
293         fprintf(stderr, "DEBUG_PTRS: popping %s ptr = 0x%08x, %d ptrs in "
294                 "list\n", p->name, p->value, g_list_length(*ptr_list));
295 #endif
296
297         free_ptr(p);
298
299         return result;
300 }
301
302 /*
303  * Parse a UNISTR2 structure 
304  *
305  * typedef struct {
306  *   short length;
307  *   short size;
308  *   [size_is(size/2)] [length_is(length/2)] [unique] wchar_t *string;
309  * } UNICODE_STRING;
310  *
311  */
312
313 /* Convert a string from little-endian unicode to ascii.  At the moment we
314    fake it by taking every odd byte.  )-:  The caller must free the
315    result returned. */
316
317 static char *fake_unicode(guint16 *data, int len)
318 {
319         char *buffer;
320         int i;
321
322         buffer = malloc(len + 1);
323
324         for (i = 0; i < len; i++)
325                 buffer[i] = data[i] & 0xff;
326
327         buffer[len] = 0;
328
329         return buffer;
330 }
331
332 /* Parse a UNISTR2 structure */
333
334 int prs_UNISTR2(tvbuff_t *tvb, int offset, packet_info *pinfo,
335                 proto_tree *tree, int flags, char **data, char *name)
336 {
337         guint32 len = 0, unknown = 0, max_len = 0;
338
339         if (flags & PARSE_SCALARS) {
340                 offset = prs_uint32(tvb, offset, pinfo, tree, &len, "Length");
341                 offset = prs_uint32(tvb, offset, pinfo, tree, &unknown, 
342                                     "Offset");
343                 offset = prs_uint32(tvb, offset, pinfo, tree, &max_len, 
344                                     "Max length");
345         }
346
347         if (flags & PARSE_BUFFERS) {
348                 guint16 *data16;
349
350                 offset = prs_uint16s(tvb, offset, pinfo, tree, max_len,
351                                      &data16, "Buffer");
352
353                 if (data)
354                         *data = fake_unicode(data16, max_len);
355         }
356
357         return offset;
358 }
359
360 /* Parse a policy handle. */
361
362 int prs_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, 
363                    proto_tree *tree)
364 {
365         offset = prs_align(offset, 4);
366
367         proto_tree_add_text(tree, tvb, offset, 20, "Policy Handle");
368
369         return offset + 20;
370 }