/src/wireshark/epan/dissectors/packet-dcerpc-nt.c
Line | Count | Source |
1 | | /* TODO: |
2 | | dissect_ndr_nt_SID_with_options see comment. |
3 | | */ |
4 | | /* packet-dcerpc-nt.c |
5 | | * Routines for DCERPC over SMB packet disassembly |
6 | | * Copyright 2001-2003, Tim Potter <tpot@samba.org> |
7 | | * Copyright 2011-2013, Matthieu Patou <mat@matws.net> |
8 | | * |
9 | | * Wireshark - Network traffic analyzer |
10 | | * By Gerald Combs <gerald@wireshark.org> |
11 | | * Copyright 1998 Gerald Combs |
12 | | * |
13 | | * SPDX-License-Identifier: GPL-2.0-or-later |
14 | | */ |
15 | | |
16 | | #include "config.h" |
17 | | |
18 | | |
19 | | #include <epan/packet.h> |
20 | | #include <epan/expert.h> |
21 | | #include <epan/tfs.h> |
22 | | |
23 | | #include <wsutil/array.h> |
24 | | #include <wsutil/ws_roundup.h> |
25 | | |
26 | | #include "packet-dcerpc.h" |
27 | | #include "packet-dcerpc-nt.h" |
28 | | #include "packet-windows-common.h" |
29 | | |
30 | | |
31 | | int hf_nt_cs_len; |
32 | | int hf_nt_error; |
33 | | int hf_nt_cs_size; |
34 | | static int hf_lsa_String_name_len; |
35 | | static int hf_lsa_String_name_size; |
36 | | static int hf_nt_data_blob_len; |
37 | | static int hf_nt_data_blob_data; |
38 | | static int hf_nt_midl_blob_len; |
39 | | static int hf_nt_midl_fill_bytes; |
40 | | static int hf_nt_midl_version; |
41 | | static int hf_nt_midl_hdr_len; |
42 | | |
43 | | static int ett_nt_MIDL_BLOB; |
44 | | static int ett_lsa_String; |
45 | | static int ett_nt_data_blob; |
46 | | static int ett_nt_counted_string; |
47 | | static expert_field ei_dcerpc_nt_badsid; |
48 | | |
49 | | |
50 | | |
51 | | /* This is used to safely walk the decode tree up, one item at a time safely. |
52 | | This is used by dcerpc dissectors that want to push the display of a string |
53 | | higher up in the tree for greater visibility. |
54 | | */ |
55 | | #define GET_ITEM_PARENT(x) \ |
56 | 0 | ((x->parent!=NULL)?x->parent:x) |
57 | | |
58 | | /* |
59 | | * This file contains helper routines that are used by the DCERPC over SMB |
60 | | * dissectors for wireshark. |
61 | | */ |
62 | | |
63 | | /* |
64 | | * Used by several dissectors. |
65 | | */ |
66 | | const value_string platform_id_vals[] = { |
67 | | { 300, "DOS" }, |
68 | | { 400, "OS/2" }, |
69 | | { 500, "Windows NT" }, |
70 | | { 600, "OSF" }, |
71 | | { 700, "VMS" }, |
72 | | { 0, NULL } |
73 | | }; |
74 | | |
75 | | int |
76 | | dissect_ndr_datablob(tvbuff_t *tvb, int offset, packet_info *pinfo, |
77 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hf_index, |
78 | | int use_remaining_space) |
79 | 0 | { |
80 | 0 | proto_item *item; |
81 | 0 | uint3264_t len; |
82 | 0 | proto_tree *subtree; |
83 | |
|
84 | 0 | subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_nt_data_blob, &item, |
85 | 0 | proto_registrar_get_name(hf_index)); |
86 | |
|
87 | 0 | if (use_remaining_space) { |
88 | 0 | len = tvb_captured_length_remaining (tvb, offset); |
89 | 0 | } else { |
90 | 0 | offset = dissect_ndr_uint3264(tvb, offset, pinfo, subtree, di, drep, |
91 | 0 | hf_nt_data_blob_len, &len); |
92 | 0 | } |
93 | 0 | proto_tree_add_item(subtree, hf_nt_data_blob_data, tvb, offset, (int)len, ENC_NA); |
94 | 0 | offset += (int)len; |
95 | 0 | return offset; |
96 | 0 | } |
97 | | |
98 | | int |
99 | | dissect_null_term_string(tvbuff_t *tvb, int offset, |
100 | | packet_info *pinfo _U_, proto_tree *tree, |
101 | | uint8_t *drep _U_, int hf_index, int levels _U_) |
102 | 0 | { |
103 | 0 | unsigned len; |
104 | |
|
105 | 0 | len = tvb_strsize(tvb, offset); |
106 | 0 | proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_ASCII|ENC_NA); |
107 | |
|
108 | 0 | return offset + len; |
109 | 0 | } |
110 | | |
111 | | int |
112 | | dissect_null_term_wstring(tvbuff_t *tvb, int offset, |
113 | | packet_info *pinfo _U_, proto_tree *tree, |
114 | | uint8_t *drep _U_, int hf_index, int levels _U_) |
115 | 0 | { |
116 | 0 | unsigned len; |
117 | |
|
118 | 0 | len = tvb_unicode_strsize(tvb, offset); |
119 | 0 | proto_tree_add_item(tree, hf_index, tvb, offset, len, ENC_UTF_16|ENC_LITTLE_ENDIAN); |
120 | |
|
121 | 0 | return offset + len; |
122 | 0 | } |
123 | | |
124 | | /* Parse some common RPC structures */ |
125 | | |
126 | | /* Dissect a counted string as a callback to dissect_ndr_pointer_cb() */ |
127 | | |
128 | | int |
129 | | dissect_ndr_counted_string_cb(tvbuff_t *tvb, int offset, |
130 | | packet_info *pinfo, proto_tree *tree, |
131 | | dcerpc_info *di, uint8_t *drep, int hf_index, |
132 | | dcerpc_callback_fnct_t *callback, |
133 | | void *callback_args) |
134 | 0 | { |
135 | 0 | uint16_t len, size; |
136 | | |
137 | | /* Structure starts with short, but is aligned for pointer */ |
138 | |
|
139 | 0 | ALIGN_TO_5_BYTES; |
140 | |
|
141 | 0 | if (di->conformant_run) |
142 | 0 | return offset; |
143 | | |
144 | | /* |
145 | | struct { |
146 | | short len; |
147 | | short size; |
148 | | [size_is(size/2), length_is(len/2), ptr] unsigned short *string; |
149 | | } UNICODE_STRING; |
150 | | |
151 | | */ |
152 | | |
153 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, |
154 | 0 | hf_nt_cs_len, &len); |
155 | |
|
156 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, |
157 | 0 | hf_nt_cs_size, &size); |
158 | |
|
159 | 0 | offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, di, drep, |
160 | 0 | dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE, |
161 | 0 | "Character Array", hf_index, callback, callback_args); |
162 | |
|
163 | 0 | if (di->call_data->flags & DCERPC_IS_NDR64) { |
164 | 0 | ALIGN_TO_5_BYTES; |
165 | 0 | } |
166 | |
|
167 | 0 | return offset; |
168 | 0 | } |
169 | | |
170 | | static int |
171 | | dissect_ndr_counted_string_helper(tvbuff_t *tvb, int offset, |
172 | | packet_info *pinfo, proto_tree *tree, |
173 | | dcerpc_info *di, uint8_t *drep, int hf_index, int levels, |
174 | | bool add_subtree) |
175 | 0 | { |
176 | 0 | proto_item *item; |
177 | 0 | proto_tree *subtree = tree; |
178 | |
|
179 | 0 | if (add_subtree) { |
180 | |
|
181 | 0 | subtree = proto_tree_add_subtree( |
182 | 0 | tree, tvb, offset, 0, ett_nt_counted_string, &item, |
183 | 0 | proto_registrar_get_name(hf_index)); |
184 | 0 | } |
185 | | |
186 | | /* |
187 | | * Add 2 levels, so that the string gets attached to the |
188 | | * "Character Array" top-level item and to the top-level item |
189 | | * added above. |
190 | | */ |
191 | 0 | return dissect_ndr_counted_string_cb( |
192 | 0 | tvb, offset, pinfo, subtree, di, drep, hf_index, |
193 | 0 | cb_wstr_postprocess, GINT_TO_POINTER(2 + levels)); |
194 | 0 | } |
195 | | |
196 | | /* Dissect a counted string in-line. */ |
197 | | |
198 | | int |
199 | | dissect_ndr_counted_string(tvbuff_t *tvb, int offset, |
200 | | packet_info *pinfo, proto_tree *tree, |
201 | | dcerpc_info *di, uint8_t *drep, int hf_index, int levels) |
202 | 0 | { |
203 | 0 | return dissect_ndr_counted_string_helper( |
204 | 0 | tvb, offset, pinfo, tree, di, drep, hf_index, levels, true); |
205 | 0 | } |
206 | | |
207 | | /* Dissect a counted string as a callback to dissect_ndr_pointer(). |
208 | | This doesn't add a adds a proto item and subtreee for the string as |
209 | | the pointer dissection already creates one. */ |
210 | | |
211 | | int |
212 | | dissect_ndr_counted_string_ptr(tvbuff_t *tvb, int offset, |
213 | | packet_info *pinfo, proto_tree *tree, |
214 | | dcerpc_info *di, uint8_t *drep) |
215 | 0 | { |
216 | 0 | return dissect_ndr_counted_string_helper( |
217 | 0 | tvb, offset, pinfo, tree, di, drep, di->hf_index, 0, false); |
218 | 0 | } |
219 | | |
220 | | /* Dissect a counted byte_array as a callback to dissect_ndr_pointer_cb() */ |
221 | | |
222 | | static int ett_nt_counted_byte_array; |
223 | | |
224 | | /* Dissect a counted byte array in-line. */ |
225 | | |
226 | | int |
227 | | dissect_ndr_counted_byte_array_cb(tvbuff_t *tvb, int offset, |
228 | | packet_info *pinfo, proto_tree *tree, |
229 | | dcerpc_info *di, uint8_t *drep, int hf_index, |
230 | | dcerpc_callback_fnct_t *callback, |
231 | | void *callback_args) |
232 | 0 | { |
233 | 0 | proto_item *item; |
234 | 0 | proto_tree *subtree; |
235 | 0 | uint16_t len, size; |
236 | | |
237 | | /* Structure starts with short, but is aligned for pointer */ |
238 | |
|
239 | 0 | ALIGN_TO_5_BYTES; |
240 | |
|
241 | 0 | if (di->conformant_run) |
242 | 0 | return offset; |
243 | | |
244 | 0 | subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_nt_counted_byte_array, &item, |
245 | 0 | proto_registrar_get_name(hf_index)); |
246 | | |
247 | | /* |
248 | | struct { |
249 | | short len; |
250 | | short size; |
251 | | [size_is(size), length_is(len), ptr] unsigned char *string; |
252 | | } WHATEVER_THIS_IS_CALLED; |
253 | | |
254 | | */ |
255 | |
|
256 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep, |
257 | 0 | hf_nt_cs_len, &len); |
258 | |
|
259 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep, |
260 | 0 | hf_nt_cs_size, &size); |
261 | |
|
262 | 0 | offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, subtree, di, drep, |
263 | 0 | dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE, |
264 | 0 | "Byte Array", hf_index, callback, callback_args); |
265 | |
|
266 | 0 | if (di->call_data->flags & DCERPC_IS_NDR64) { |
267 | 0 | ALIGN_TO_5_BYTES; |
268 | 0 | } |
269 | |
|
270 | 0 | return offset; |
271 | 0 | } |
272 | | |
273 | | static void cb_byte_array_postprocess(packet_info *pinfo, proto_tree *tree _U_, |
274 | | proto_item *item, dcerpc_info *di _U_, tvbuff_t *tvb, |
275 | | int start_offset, int end_offset, |
276 | | void *callback_args) |
277 | 0 | { |
278 | 0 | int options = GPOINTER_TO_INT(callback_args); |
279 | 0 | int levels = CB_STR_ITEM_LEVELS(options); |
280 | 0 | char *s; |
281 | | |
282 | | /* Align start_offset on 4-byte boundary. */ |
283 | |
|
284 | 0 | start_offset = WS_ROUNDUP_4(start_offset); |
285 | | |
286 | | /* Get byte array value */ |
287 | |
|
288 | 0 | if ((end_offset - start_offset) <= 12) |
289 | 0 | return; |
290 | | |
291 | 0 | s = tvb_bytes_to_str(pinfo->pool, tvb, start_offset + 12, (end_offset - start_offset - 12) ); |
292 | | |
293 | | /* Append string to COL_INFO */ |
294 | |
|
295 | 0 | if (options & CB_STR_COL_INFO) { |
296 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s); |
297 | 0 | } |
298 | | |
299 | | /* Append string to upper-level proto_items */ |
300 | |
|
301 | 0 | if (levels > 0 && item && s && s[0]) { |
302 | 0 | proto_item_append_text(item, ": %s", s); |
303 | 0 | item = GET_ITEM_PARENT(item); |
304 | 0 | levels--; |
305 | 0 | if (levels > 0) { |
306 | 0 | proto_item_append_text(item, ": %s", s); |
307 | 0 | item = GET_ITEM_PARENT(item); |
308 | 0 | levels--; |
309 | 0 | while (levels > 0) { |
310 | 0 | proto_item_append_text(item, " %s", s); |
311 | 0 | item = GET_ITEM_PARENT(item); |
312 | 0 | levels--; |
313 | 0 | } |
314 | 0 | } |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | | int |
319 | | dissect_ndr_counted_byte_array(tvbuff_t *tvb, int offset, |
320 | | packet_info *pinfo, proto_tree *tree, |
321 | | dcerpc_info *di, uint8_t *drep, int hf_index, int levels) |
322 | 0 | { |
323 | 0 | return dissect_ndr_counted_byte_array_cb( |
324 | 0 | tvb, offset, pinfo, tree, di, drep, hf_index, cb_byte_array_postprocess, GINT_TO_POINTER(2 + levels)); |
325 | 0 | } |
326 | | |
327 | | /* Dissect a counted ascii string in-line. */ |
328 | | static int ett_nt_counted_ascii_string; |
329 | | |
330 | | int |
331 | | dissect_ndr_counted_ascii_string_cb(tvbuff_t *tvb, int offset, |
332 | | packet_info *pinfo, proto_tree *tree, |
333 | | dcerpc_info *di, uint8_t *drep, int hf_index, |
334 | | dcerpc_callback_fnct_t *callback, |
335 | | void *callback_args) |
336 | 0 | { |
337 | 0 | proto_item *item; |
338 | 0 | proto_tree *subtree; |
339 | 0 | uint16_t len, size; |
340 | | |
341 | | /* Structure starts with short, but is aligned for pointer */ |
342 | |
|
343 | 0 | ALIGN_TO_5_BYTES; |
344 | |
|
345 | 0 | if (di->conformant_run) |
346 | 0 | return offset; |
347 | | |
348 | 0 | subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_nt_counted_ascii_string, &item, |
349 | 0 | proto_registrar_get_name(hf_index)); |
350 | | |
351 | | /* |
352 | | struct { |
353 | | short len; |
354 | | short size; |
355 | | [size_is(size), length_is(len), ptr] unsigned char *string; |
356 | | } WHATEVER_THIS_IS_CALLED; |
357 | | |
358 | | */ |
359 | |
|
360 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep, |
361 | 0 | hf_nt_cs_len, &len); |
362 | |
|
363 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, subtree, di, drep, |
364 | 0 | hf_nt_cs_size, &size); |
365 | |
|
366 | 0 | offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, subtree, di, drep, |
367 | 0 | dissect_ndr_char_cvstring, NDR_POINTER_UNIQUE, |
368 | 0 | "Ascii String", hf_index, callback, callback_args); |
369 | |
|
370 | 0 | if (di->call_data->flags & DCERPC_IS_NDR64) { |
371 | 0 | ALIGN_TO_5_BYTES; |
372 | 0 | } |
373 | |
|
374 | 0 | return offset; |
375 | 0 | } |
376 | | |
377 | | int |
378 | | dissect_ndr_counted_ascii_string(tvbuff_t *tvb, int offset, |
379 | | packet_info *pinfo, proto_tree *tree, |
380 | | dcerpc_info *di, uint8_t *drep, int hf_index, int levels) |
381 | 0 | { |
382 | 0 | return dissect_ndr_counted_ascii_string_cb( |
383 | 0 | tvb, offset, pinfo, tree, di, drep, hf_index, cb_str_postprocess, GINT_TO_POINTER(2 + levels)); |
384 | 0 | } |
385 | | |
386 | | static int hf_nt_guid; |
387 | | |
388 | | int |
389 | | dissect_nt_GUID(tvbuff_t *tvb, int offset, |
390 | | packet_info *pinfo, proto_tree *tree, |
391 | | dcerpc_info *di, uint8_t *drep) |
392 | 0 | { |
393 | 0 | offset=dissect_ndr_uuid_t(tvb, offset, pinfo, tree, di, drep, hf_nt_guid, NULL); |
394 | |
|
395 | 0 | return offset; |
396 | 0 | } |
397 | | |
398 | | /* This function is used to dissect a lsa_String |
399 | | typedef [public] struct { |
400 | | [value(strlen_m_term(name)*2)] uint16 name_len; |
401 | | [value(strlen_m_term(name)*2)] uint16 name_size; |
402 | | [string,charset(UTF16)] uint16 *name; |
403 | | } lsa_String; |
404 | | */ |
405 | | int |
406 | | dissect_ndr_lsa_String(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, dcerpc_info *di, uint8_t *drep, uint32_t param, int hfindex) |
407 | 0 | { |
408 | 0 | proto_item *item; |
409 | 0 | proto_tree *tree; |
410 | 0 | int old_offset; |
411 | 0 | header_field_info *hf_info; |
412 | |
|
413 | 0 | ALIGN_TO_5_BYTES; |
414 | |
|
415 | 0 | old_offset = offset; |
416 | 0 | hf_info=proto_registrar_get_nth(hfindex); |
417 | |
|
418 | 0 | tree = proto_tree_add_subtree_format(parent_tree, tvb, offset, 0, ett_lsa_String, &item, "%s: ", hf_info->name); |
419 | |
|
420 | 0 | offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_len, 0); |
421 | |
|
422 | 0 | offset = PIDL_dissect_uint16(tvb, offset, pinfo, tree, di, drep, hf_lsa_String_name_size, 0); |
423 | |
|
424 | 0 | offset = dissect_ndr_pointer_cb( |
425 | 0 | tvb, offset, pinfo, tree, di, drep, |
426 | 0 | dissect_ndr_wchar_cvstring, NDR_POINTER_UNIQUE, |
427 | 0 | hf_info->name, hfindex, cb_wstr_postprocess, |
428 | 0 | GINT_TO_POINTER(param)); |
429 | |
|
430 | 0 | proto_item_set_len(item, offset-old_offset); |
431 | |
|
432 | 0 | if (di->call_data->flags & DCERPC_IS_NDR64) { |
433 | 0 | ALIGN_TO_5_BYTES; |
434 | 0 | } |
435 | |
|
436 | 0 | return offset; |
437 | 0 | } |
438 | | |
439 | | /* This function is used to dissect a DCERPC encoded 64 bit time value. */ |
440 | | int |
441 | | dissect_ndr_nt_NTTIME (tvbuff_t *tvb, int offset, |
442 | | packet_info *pinfo _U_, proto_tree *tree, |
443 | | dcerpc_info *di, uint8_t *drep, int hf_index) |
444 | 0 | { |
445 | 0 | if(di->conformant_run){ |
446 | | /*just a run to handle conformant arrays, nothing to dissect */ |
447 | 0 | return offset; |
448 | 0 | } |
449 | | |
450 | 0 | ALIGN_TO_4_BYTES; |
451 | |
|
452 | 0 | dissect_nttime(tvb, tree, offset, hf_index, |
453 | 0 | (drep[0] & DREP_LITTLE_ENDIAN) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN); |
454 | 0 | offset += 8; |
455 | 0 | return offset; |
456 | 0 | } |
457 | | |
458 | | int |
459 | | dissect_ndr_nt_NTTIME_hyper (tvbuff_t *tvb, int offset, |
460 | | packet_info *pinfo _U_, proto_tree *tree, |
461 | | dcerpc_info *di, uint8_t *drep _U_, int hf_index) |
462 | 0 | { |
463 | 0 | if(di->conformant_run){ |
464 | | /*just a run to handle conformant arrays, nothing to dissect */ |
465 | 0 | return offset; |
466 | 0 | } |
467 | | |
468 | 0 | ALIGN_TO_8_BYTES; |
469 | |
|
470 | 0 | dissect_nttime_hyper(tvb, tree, offset, hf_index, |
471 | 0 | (drep[0] & DREP_LITTLE_ENDIAN) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN); |
472 | 0 | offset += 8; |
473 | 0 | return offset; |
474 | 0 | } |
475 | | |
476 | | int |
477 | | dissect_ndr_nt_NTTIME_1sec (tvbuff_t *tvb, int offset, |
478 | | packet_info *pinfo _U_, proto_tree *tree, |
479 | | dcerpc_info *di, uint8_t *drep, int hf_index) |
480 | 0 | { |
481 | 0 | if(di->conformant_run){ |
482 | | /*just a run to handle conformant arrays, nothing to dissect */ |
483 | 0 | return offset; |
484 | 0 | } |
485 | | |
486 | 0 | ALIGN_TO_8_BYTES; |
487 | |
|
488 | 0 | dissect_nttime_hyper_1sec(tvb, tree, offset, hf_index, |
489 | 0 | (drep[0] & DREP_LITTLE_ENDIAN) ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN); |
490 | 0 | offset += 8; |
491 | 0 | return offset; |
492 | 0 | } |
493 | | |
494 | | /* Define this symbol to display warnings about request/response and |
495 | | policy handle hash table collisions. This happens when a packet with |
496 | | the same conversation, smb fid and dcerpc call id occurs. I think this |
497 | | is due to a bug in the dcerpc/smb fragment reassembly code. */ |
498 | | |
499 | | #undef DEBUG_HASH_COLL |
500 | | |
501 | | /* |
502 | | * Policy handle hashing. |
503 | | * |
504 | | * We hash based on the policy handle value; the items in the hash table |
505 | | * are lists of policy handle information about one or more policy |
506 | | * handles with that value. We have multiple values in case a given |
507 | | * policy handle is opened in frame N, closed in frame M, and re-opened |
508 | | * in frame O, where N < M < O. |
509 | | * |
510 | | * XXX - we really should also use a DCE RPC conversation/session handle |
511 | | * of some sort, in case two separate sessions have the same handle |
512 | | * value. A transport-layer conversation might not be sufficient, as you |
513 | | * might, for example, have multiple pipes in a single SMB connection, |
514 | | * and you might have the same handle opened and closed separately on |
515 | | * those two pipes. |
516 | | * |
517 | | * The policy handle information has "first frame" and "last frame" |
518 | | * information; the entry should be used when dissecting a given frame |
519 | | * only if that frame is within the interval [first frame,last frame]. |
520 | | * The list is sorted by "first frame". |
521 | | * |
522 | | * This doesn't handle the case of a handle being opened in frame N and |
523 | | * re-opened in frame M, where N < M, with no intervening close, but I'm |
524 | | * not sure anything can handle that if it's within the same DCE RPC |
525 | | * session (if it's not, the conversation/session handle would fix that). |
526 | | */ |
527 | | |
528 | | typedef struct { |
529 | | uint8_t policy_hnd[20]; |
530 | | } pol_hash_key; |
531 | | |
532 | | typedef struct { |
533 | | pol_value *list; /* List of policy handle entries */ |
534 | | } pol_hash_value; |
535 | | |
536 | | static wmem_map_t *pol_hash; |
537 | | |
538 | | /* Hash function */ |
539 | | |
540 | | static unsigned pol_hash_fn(const void *k) |
541 | 0 | { |
542 | 0 | const pol_hash_key *key = (const pol_hash_key *)k; |
543 | | |
544 | | /* Bytes 4-7 of the policy handle are a timestamp so should make a |
545 | | reasonable hash value */ |
546 | |
|
547 | 0 | return key->policy_hnd[4] + (key->policy_hnd[5] << 8) + |
548 | 0 | (key->policy_hnd[6] << 16) + (key->policy_hnd[7] << 24); |
549 | 0 | } |
550 | | |
551 | | /* Return true if a policy handle is all zeros */ |
552 | | |
553 | | static bool is_null_pol(e_ctx_hnd *policy_hnd) |
554 | 0 | { |
555 | 0 | static uint8_t null_policy_hnd[20]; |
556 | |
|
557 | 0 | return memcmp(policy_hnd, null_policy_hnd, 20) == 0; |
558 | 0 | } |
559 | | |
560 | | /* Hash compare function */ |
561 | | |
562 | | static int pol_hash_compare(const void *k1, const void *k2) |
563 | 0 | { |
564 | 0 | const pol_hash_key *key1 = (const pol_hash_key *)k1; |
565 | 0 | const pol_hash_key *key2 = (const pol_hash_key *)k2; |
566 | |
|
567 | 0 | return memcmp(key1->policy_hnd, key2->policy_hnd, |
568 | 0 | sizeof(key1->policy_hnd)) == 0; |
569 | 0 | } |
570 | | |
571 | | /* |
572 | | * Look up the instance of a policy handle value in whose range of frames |
573 | | * the specified frame falls. |
574 | | */ |
575 | | static pol_value *find_pol_handle(e_ctx_hnd *policy_hnd, uint32_t frame, |
576 | | pol_hash_value **valuep) |
577 | 0 | { |
578 | 0 | pol_hash_key key; |
579 | 0 | pol_value *pol; |
580 | |
|
581 | 0 | memcpy(&key.policy_hnd, policy_hnd, sizeof(key.policy_hnd)); |
582 | 0 | if ((*valuep = (pol_hash_value *)wmem_map_lookup(pol_hash, &key))) { |
583 | | /* |
584 | | * Look for the first value such that both: |
585 | | * |
586 | | * 1) the first frame in which it was seen is |
587 | | * <= the specified frame; |
588 | | * |
589 | | * 2) the last frame in which it was seen is |
590 | | * either unknown (meaning we haven't yet |
591 | | * seen a close or another open of the |
592 | | * same handle, which is assumed to imply |
593 | | * an intervening close that wasn't captured) |
594 | | * or is >= the specified frame. |
595 | | * |
596 | | * If there's more than one such frame, that's the |
597 | | * case where a handle is opened in frame N and |
598 | | * reopened in frame M, with no intervening close; |
599 | | * there is no right answer for that, so the instance |
600 | | * opened in frame N is as right as anything else. |
601 | | */ |
602 | 0 | for (pol = (*valuep)->list; pol != NULL; pol = pol->next) { |
603 | 0 | if (pol->first_frame <= frame && |
604 | 0 | (pol->last_frame == 0 || |
605 | 0 | pol->last_frame >= frame)) |
606 | 0 | break; /* found one */ |
607 | 0 | } |
608 | 0 | return pol; |
609 | 0 | } else { |
610 | | /* |
611 | | * The handle isn't in the hash table. |
612 | | */ |
613 | 0 | return NULL; |
614 | 0 | } |
615 | 0 | } |
616 | | |
617 | | static void add_pol_handle(e_ctx_hnd *policy_hnd, uint32_t frame, |
618 | | pol_value *pol, pol_hash_value *value) |
619 | 0 | { |
620 | 0 | pol_hash_key *key; |
621 | 0 | pol_value *polprev, *polnext; |
622 | |
|
623 | 0 | if (value == NULL) { |
624 | | /* |
625 | | * There's no hash value; create one, put the new |
626 | | * value at the beginning of its policy handle list, |
627 | | * and put the hash value in the policy handle hash |
628 | | * table. |
629 | | */ |
630 | 0 | value = wmem_new(wmem_file_scope(), pol_hash_value); |
631 | 0 | value->list = pol; |
632 | 0 | pol->next = NULL; |
633 | 0 | key = wmem_new(wmem_file_scope(), pol_hash_key); |
634 | 0 | memcpy(&key->policy_hnd, policy_hnd, sizeof(key->policy_hnd)); |
635 | 0 | wmem_map_insert(pol_hash, key, value); |
636 | 0 | } else { |
637 | | /* |
638 | | * Put the new value in the hash value's policy handle |
639 | | * list so that it's sorted by the first frame in |
640 | | * which it appeared. |
641 | | * |
642 | | * Search for the first entry whose first frame number |
643 | | * is greater than the current frame number, if any. |
644 | | */ |
645 | 0 | for (polnext = value->list, polprev = NULL; |
646 | 0 | polnext != NULL && polnext->first_frame <= frame; |
647 | 0 | polprev = polnext, polnext = polnext->next) |
648 | 0 | ; |
649 | | |
650 | | /* |
651 | | * "polprev" points to the entry in the list after |
652 | | * which we should put the new entry; if it's null, |
653 | | * that means we should put it at the beginning of |
654 | | * the list. |
655 | | */ |
656 | 0 | if (polprev == NULL) |
657 | 0 | value->list = pol; |
658 | 0 | else |
659 | 0 | polprev->next = pol; |
660 | | |
661 | | /* |
662 | | * "polnext" points to the entry in the list before |
663 | | * which we should put the new entry; if it's null, |
664 | | * that means we should put it at the end of the list. |
665 | | */ |
666 | 0 | pol->next = polnext; |
667 | 0 | } |
668 | 0 | } |
669 | | |
670 | | /* Store the open and close frame numbers of a policy handle */ |
671 | | |
672 | | void dcerpc_smb_store_pol_pkts(e_ctx_hnd *policy_hnd, packet_info *pinfo, |
673 | | uint32_t param) |
674 | 0 | { |
675 | 0 | pol_hash_value *value; |
676 | 0 | pol_value *pol; |
677 | | |
678 | | /* |
679 | | * By the time the first pass is done, the policy handle database |
680 | | * has been completely constructed. If we've already seen this |
681 | | * frame, there's nothing to do. |
682 | | */ |
683 | 0 | if (pinfo->fd->visited) |
684 | 0 | return; |
685 | | |
686 | 0 | if (is_null_pol(policy_hnd)) |
687 | 0 | return; |
688 | | |
689 | | /* Look up existing value */ |
690 | 0 | pol = find_pol_handle(policy_hnd, pinfo->num, &value); |
691 | |
|
692 | 0 | if (pol != NULL) { |
693 | | /* |
694 | | * Update the existing value as appropriate. |
695 | | */ |
696 | 0 | if (param & PIDL_POLHND_OPEN) { |
697 | | /* |
698 | | * This is an open; we assume that we missed |
699 | | * a close of this handle, so we set its |
700 | | * "last frame" value and act as if we didn't |
701 | | * see it. |
702 | | * |
703 | | * XXX - note that we might be called twice for |
704 | | * the same operation (see "dissect_pipe_dcerpc()", |
705 | | * which calls the DCE RPC dissector twice), so we |
706 | | * must first check to see if this is a handle we |
707 | | * just filled in. |
708 | | * |
709 | | * We check whether this handle's "first frame" |
710 | | * frame number is this frame and its "last frame |
711 | | * is 0; if so, this is presumably a duplicate call, |
712 | | * and we don't do an implicit close. |
713 | | */ |
714 | 0 | if (pol->first_frame == pinfo->num && |
715 | 0 | pol->last_frame == 0) |
716 | 0 | return; |
717 | 0 | pol->last_frame = pinfo->num; |
718 | 0 | pol = NULL; |
719 | 0 | } else { |
720 | 0 | if (param & PIDL_POLHND_CLOSE) { |
721 | 0 | pol->close_frame = pinfo->num; |
722 | 0 | pol->last_frame = pinfo->num; |
723 | 0 | } |
724 | 0 | return; |
725 | 0 | } |
726 | 0 | } |
727 | | |
728 | | /* Create a new value */ |
729 | | |
730 | 0 | pol = wmem_new(wmem_file_scope(), pol_value); |
731 | |
|
732 | 0 | pol->open_frame = (param & PIDL_POLHND_OPEN) ? pinfo->num : 0; |
733 | 0 | pol->close_frame = (param & PIDL_POLHND_CLOSE) ? pinfo->num : 0; |
734 | 0 | pol->first_frame = pinfo->num; |
735 | 0 | pol->last_frame = pol->close_frame; /* if 0, unknown; if non-0, known */ |
736 | 0 | pol->type=0; |
737 | 0 | pol->name = NULL; |
738 | |
|
739 | 0 | add_pol_handle(policy_hnd, pinfo->num, pol, value); |
740 | 0 | } |
741 | | |
742 | | /* Store the type of a policy handle */ |
743 | | static void dcerpc_store_polhnd_type(e_ctx_hnd *policy_hnd, packet_info *pinfo, |
744 | | uint32_t type) |
745 | 0 | { |
746 | 0 | pol_hash_value *value; |
747 | 0 | pol_value *pol; |
748 | | |
749 | | /* |
750 | | * By the time the first pass is done, the policy handle database |
751 | | * has been completely constructed. If we've already seen this |
752 | | * frame, there's nothing to do. |
753 | | */ |
754 | 0 | if (pinfo->fd->visited) |
755 | 0 | return; |
756 | | |
757 | 0 | if (is_null_pol(policy_hnd)) |
758 | 0 | return; |
759 | | |
760 | | /* Look up existing value */ |
761 | 0 | pol = find_pol_handle(policy_hnd, pinfo->num, &value); |
762 | |
|
763 | 0 | if (pol != NULL) { |
764 | | /* |
765 | | * Update the existing value as appropriate. |
766 | | */ |
767 | 0 | pol->type=type; |
768 | 0 | } |
769 | 0 | } |
770 | | |
771 | | /* Store a text string with a policy handle */ |
772 | | void dcerpc_store_polhnd_name(e_ctx_hnd *policy_hnd, packet_info *pinfo, |
773 | | const char *name) |
774 | 0 | { |
775 | 0 | pol_hash_value *value; |
776 | 0 | pol_value *pol; |
777 | | |
778 | | /* |
779 | | * By the time the first pass is done, the policy handle database |
780 | | * has been completely constructed. If we've already seen this |
781 | | * frame, there's nothing to do. |
782 | | */ |
783 | 0 | if (pinfo->fd->visited) |
784 | 0 | return; |
785 | | |
786 | 0 | if (is_null_pol(policy_hnd)) |
787 | 0 | return; |
788 | | |
789 | | /* Look up existing value */ |
790 | 0 | pol = find_pol_handle(policy_hnd, pinfo->num, &value); |
791 | |
|
792 | 0 | if (pol != NULL) { |
793 | | /* |
794 | | * This is the first pass; update the existing |
795 | | * value as appropriate. |
796 | | */ |
797 | 0 | if (pol->name && name) { |
798 | | #ifdef DEBUG_HASH_COLL |
799 | | if (strcmp(pol->name, name) != 0) |
800 | | ws_warning("dcerpc_smb: pol_hash name collision %s/%s\n", value->name, name); |
801 | | #endif |
802 | | /* pol->name is wmem_file_scope() allocated, don't free it now */ |
803 | 0 | } |
804 | |
|
805 | 0 | pol->name = wmem_strdup(wmem_file_scope(), name); |
806 | |
|
807 | 0 | return; |
808 | 0 | } |
809 | | |
810 | | /* Create a new value */ |
811 | | |
812 | 0 | pol = wmem_new(wmem_file_scope(), pol_value); |
813 | |
|
814 | 0 | pol->open_frame = 0; |
815 | 0 | pol->close_frame = 0; |
816 | 0 | pol->first_frame = pinfo->num; |
817 | 0 | pol->last_frame = 0; |
818 | 0 | pol->type = 0; |
819 | 0 | if (name) |
820 | 0 | pol->name = wmem_strdup(wmem_file_scope(), name); |
821 | 0 | else |
822 | 0 | pol->name = wmem_strdup(wmem_file_scope(), "<UNKNOWN>"); |
823 | |
|
824 | 0 | add_pol_handle(policy_hnd, pinfo->num, pol, value); |
825 | 0 | } |
826 | | |
827 | | /* |
828 | | * Retrieve a policy handle. |
829 | | * |
830 | | * XXX - should this get a "param" argument, and match even closed |
831 | | * policy handles if the call closes the handle, so we can handle |
832 | | * retransmitted close operations? |
833 | | */ |
834 | | |
835 | | bool dcerpc_fetch_polhnd_data(e_ctx_hnd *policy_hnd, |
836 | | char **name, uint32_t *type, |
837 | | uint32_t *open_frame, uint32_t *close_frame, |
838 | | uint32_t cur_frame) |
839 | 0 | { |
840 | 0 | pol_hash_value *value; |
841 | 0 | pol_value *pol; |
842 | | |
843 | | /* Prevent uninitialised return vars */ |
844 | |
|
845 | 0 | if (name) |
846 | 0 | *name = NULL; |
847 | |
|
848 | 0 | if (type) |
849 | 0 | *type = 0; |
850 | |
|
851 | 0 | if (open_frame) |
852 | 0 | *open_frame = 0; |
853 | |
|
854 | 0 | if (close_frame) |
855 | 0 | *close_frame = 0; |
856 | | |
857 | | /* Look up existing value */ |
858 | 0 | pol = find_pol_handle(policy_hnd, cur_frame, &value); |
859 | |
|
860 | 0 | if (pol) { |
861 | 0 | if (name) |
862 | 0 | *name = pol->name; |
863 | |
|
864 | 0 | if (type) |
865 | 0 | *type = pol->type; |
866 | |
|
867 | 0 | if (open_frame) |
868 | 0 | *open_frame = pol->open_frame; |
869 | |
|
870 | 0 | if (close_frame) |
871 | 0 | *close_frame = pol->close_frame; |
872 | 0 | } |
873 | |
|
874 | 0 | return pol != NULL; |
875 | 0 | } |
876 | | |
877 | | /* Dissect a NT status code */ |
878 | | |
879 | | int |
880 | | dissect_ntstatus(tvbuff_t *tvb, int offset, packet_info *pinfo, |
881 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
882 | | int hfindex, uint32_t *pdata) |
883 | 0 | { |
884 | 0 | uint32_t status; |
885 | |
|
886 | 0 | offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, |
887 | 0 | hfindex, &status); |
888 | |
|
889 | 0 | if (status != 0) |
890 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", |
891 | 0 | val_to_str_ext(pinfo->pool, status, &NT_errors_ext, |
892 | 0 | "Unknown error 0x%08x")); |
893 | 0 | if (pdata) |
894 | 0 | *pdata = status; |
895 | |
|
896 | 0 | return offset; |
897 | 0 | } |
898 | | |
899 | | /* Dissect a DOS status code */ |
900 | | |
901 | | int |
902 | | dissect_doserror(tvbuff_t *tvb, int offset, packet_info *pinfo, |
903 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
904 | | int hfindex, uint32_t *pdata) |
905 | 0 | { |
906 | 0 | uint32_t status; |
907 | |
|
908 | 0 | offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, |
909 | 0 | hfindex, &status); |
910 | |
|
911 | 0 | if (status != 0) |
912 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", |
913 | 0 | val_to_str_ext(pinfo->pool, status, &DOS_errors_ext, |
914 | 0 | "Unknown error 0x%08x")); |
915 | 0 | if (pdata) |
916 | 0 | *pdata = status; |
917 | |
|
918 | 0 | return offset; |
919 | 0 | } |
920 | | |
921 | | int |
922 | | dissect_werror(tvbuff_t *tvb, int offset, packet_info *pinfo, |
923 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
924 | | int hfindex, uint32_t *pdata) |
925 | 0 | { |
926 | 0 | uint32_t status; |
927 | |
|
928 | 0 | offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, |
929 | 0 | hfindex, &status); |
930 | |
|
931 | 0 | if (status != 0) |
932 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", |
933 | 0 | val_to_str_ext(pinfo->pool, status, &WERR_errors_ext, |
934 | 0 | "Unknown error 0x%08x")); |
935 | 0 | if (pdata) |
936 | 0 | *pdata = status; |
937 | |
|
938 | 0 | return offset; |
939 | 0 | } |
940 | | |
941 | | /* Dissect a HRESULT status code */ |
942 | | |
943 | | int |
944 | | dissect_hresult(tvbuff_t *tvb, int offset, packet_info *pinfo, |
945 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
946 | | int hfindex, uint32_t *pdata) |
947 | 0 | { |
948 | 0 | uint32_t status; |
949 | |
|
950 | 0 | offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, |
951 | 0 | hfindex, &status); |
952 | |
|
953 | 0 | if (status != 0) |
954 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", |
955 | 0 | val_to_str_ext(pinfo->pool, status, &HRES_errors_ext, |
956 | 0 | "Unknown error 0x%08x")); |
957 | 0 | if (pdata) |
958 | 0 | *pdata = status; |
959 | |
|
960 | 0 | return offset; |
961 | 0 | } |
962 | | |
963 | | /* Dissect a NT policy handle */ |
964 | | |
965 | | static int hf_nt_policy_open_frame; |
966 | | static int hf_nt_policy_close_frame; |
967 | | |
968 | | static int ett_nt_policy_hnd; |
969 | | |
970 | | /* this function is used to dissect a "handle". |
971 | | * it will keep track of which frame a handle is opened from and in which |
972 | | * frame it is closed. |
973 | | * normally, this function would be used for tracking 20 byte policy handles |
974 | | * as used in dcerpc but it has shown VERY useful to also use it for tracking |
975 | | * GUIDs such as for the file ids in smb2. |
976 | | */ |
977 | | typedef enum { |
978 | | HND_TYPE_CTX_HANDLE, |
979 | | HND_TYPE_GUID |
980 | | } e_hnd_type; |
981 | | |
982 | | static int |
983 | | dissect_nt_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, |
984 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hfindex, |
985 | | e_ctx_hnd *pdata, proto_item **pitem, |
986 | | uint32_t param, e_hnd_type type) |
987 | 0 | { |
988 | 0 | proto_item *item=NULL; |
989 | 0 | proto_tree *subtree; |
990 | 0 | e_ctx_hnd hnd; |
991 | 0 | uint32_t open_frame = 0, close_frame = 0; |
992 | 0 | char *name; |
993 | 0 | int old_offset = offset; |
994 | 0 | if(di->conformant_run){ |
995 | | /* |
996 | | * just a run to handle conformant arrays, no scalars to |
997 | | * dissect - and "dissect_ndr_ctx_hnd()" won't return |
998 | | * a handle, so we can't do the hashing stuff in any |
999 | | * case |
1000 | | */ |
1001 | 0 | return offset; |
1002 | 0 | } |
1003 | | |
1004 | | /* Add to proto tree */ |
1005 | | |
1006 | 0 | switch(type){ |
1007 | 0 | case HND_TYPE_CTX_HANDLE: |
1008 | 0 | if (!di->no_align) { |
1009 | 0 | offset = WS_ROUNDUP_4(offset); |
1010 | 0 | } |
1011 | 0 | subtree = proto_tree_add_subtree(tree, tvb, offset, sizeof(e_ctx_hnd), |
1012 | 0 | ett_nt_policy_hnd, &item, "Policy Handle"); |
1013 | |
|
1014 | 0 | offset = dissect_ndr_ctx_hnd(tvb, offset, pinfo, subtree, di, drep, |
1015 | 0 | hfindex, &hnd); |
1016 | 0 | break; |
1017 | 0 | case HND_TYPE_GUID: |
1018 | 0 | subtree = proto_tree_add_subtree(tree, tvb, offset, 16, |
1019 | 0 | ett_nt_policy_hnd, &item, "GUID handle"); |
1020 | |
|
1021 | 0 | hnd.attributes=0; |
1022 | 0 | offset=dissect_ndr_uuid_t(tvb, offset, pinfo, subtree, di, drep, hfindex, &hnd.uuid); |
1023 | 0 | break; |
1024 | 0 | default: |
1025 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
1026 | 0 | return offset; |
1027 | 0 | } |
1028 | | |
1029 | | /* |
1030 | | * Create a new entry for this handle if it's not a null handle |
1031 | | * and no entry already exists, and, in any case, set the |
1032 | | * open, close, first, and last frame information as appropriate. |
1033 | | */ |
1034 | 0 | dcerpc_smb_store_pol_pkts(&hnd, pinfo, param); |
1035 | | |
1036 | | /* Insert open/close/name information if known */ |
1037 | 0 | if (dcerpc_fetch_polhnd_data(&hnd, &name, NULL, &open_frame, |
1038 | 0 | &close_frame, pinfo->num)) { |
1039 | |
|
1040 | 0 | if (open_frame) { |
1041 | 0 | proto_item *item_local; |
1042 | 0 | item_local=proto_tree_add_uint( |
1043 | 0 | subtree, hf_nt_policy_open_frame, tvb, |
1044 | 0 | old_offset, sizeof(e_ctx_hnd), open_frame); |
1045 | 0 | proto_item_set_generated(item_local); |
1046 | 0 | } |
1047 | 0 | if (close_frame) { |
1048 | 0 | proto_item *item_local; |
1049 | 0 | item_local=proto_tree_add_uint( |
1050 | 0 | subtree, hf_nt_policy_close_frame, tvb, |
1051 | 0 | old_offset, sizeof(e_ctx_hnd), close_frame); |
1052 | 0 | proto_item_set_generated(item_local); |
1053 | 0 | } |
1054 | | |
1055 | | /* |
1056 | | * Don't append the handle name if pitem is null; that's |
1057 | | * an indication that our caller will do so, as we're |
1058 | | * supplying a pointer to the item so that they can do |
1059 | | * so. |
1060 | | */ |
1061 | 0 | if (name != NULL && pitem == NULL) |
1062 | 0 | proto_item_append_text(item, ": %s", name); |
1063 | 0 | } |
1064 | |
|
1065 | 0 | if (pdata) |
1066 | 0 | *pdata = hnd; |
1067 | |
|
1068 | 0 | if (pitem) |
1069 | 0 | *pitem = item; |
1070 | |
|
1071 | 0 | return offset; |
1072 | 0 | } |
1073 | | |
1074 | | |
1075 | | int |
1076 | | dissect_nt_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1077 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hfindex, |
1078 | | e_ctx_hnd *pdata, proto_item **pitem, |
1079 | | uint32_t param) |
1080 | 0 | { |
1081 | 0 | offset=dissect_nt_hnd(tvb, offset, pinfo, |
1082 | 0 | tree, di, drep, hfindex, |
1083 | 0 | pdata, pitem, |
1084 | 0 | param, HND_TYPE_CTX_HANDLE); |
1085 | |
|
1086 | 0 | return offset; |
1087 | 0 | } |
1088 | | |
1089 | | /* This function is called from PIDL generated dissectors to dissect a |
1090 | | * NT style policy handle (connect handle). |
1091 | | * |
1092 | | * param can be used to specify where policy handles are opened and closed |
1093 | | * by setting PARAM_VALUE to |
1094 | | * PIDL_POLHND_OPEN where the policy handle is opened/created |
1095 | | * PIDL_POLHND_CLOSE where it is closed. |
1096 | | * This enables policy handle tracking so that when a policy handle is |
1097 | | * dissected it will be so as an expansion showing which frame it was |
1098 | | * opened/closed in. |
1099 | | * |
1100 | | * See conformance file for winreg (epan/dissectors/pidl/winreg.cnf) |
1101 | | * for examples. |
1102 | | */ |
1103 | | int |
1104 | | PIDL_dissect_policy_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1105 | | proto_tree *tree, dcerpc_info* di, uint8_t *drep, int hfindex, |
1106 | | uint32_t param) |
1107 | 0 | { |
1108 | 0 | e_ctx_hnd policy_hnd; |
1109 | |
|
1110 | 0 | offset=dissect_nt_hnd(tvb, offset, pinfo, |
1111 | 0 | tree, di, drep, hfindex, |
1112 | 0 | &policy_hnd, NULL, |
1113 | 0 | param, HND_TYPE_CTX_HANDLE); |
1114 | | |
1115 | | /* If this was an open/create and we don't yet have a policy name |
1116 | | * then create one. |
1117 | | * XXX We do not yet have the infrastructure to know the name of the |
1118 | | * actual object so just show it as <...> for the time being. |
1119 | | */ |
1120 | 0 | if((param&PIDL_POLHND_OPEN) |
1121 | 0 | && !pinfo->fd->visited |
1122 | 0 | && !di->conformant_run){ |
1123 | 0 | char *pol_string=NULL; |
1124 | 0 | const char *pol_name=NULL; |
1125 | 0 | dcerpc_call_value *dcv; |
1126 | |
|
1127 | 0 | dcv = (dcerpc_call_value *)di->call_data; |
1128 | 0 | pol_name = (const char *)dcv->private_data; |
1129 | 0 | if(!pol_name){ |
1130 | 0 | pol_name="<...>"; |
1131 | 0 | } |
1132 | 0 | pol_string=wmem_strdup_printf(pinfo->pool, "%s(%s)", di->dcerpc_procedure_name, pol_name); |
1133 | 0 | dcerpc_store_polhnd_name(&policy_hnd, pinfo, pol_string); |
1134 | 0 | dcerpc_store_polhnd_type(&policy_hnd, pinfo, param&PIDL_POLHND_TYPE_MASK); |
1135 | 0 | } |
1136 | | |
1137 | | /* Track this policy handle for the response */ |
1138 | 0 | if(!pinfo->fd->visited |
1139 | 0 | && !di->conformant_run){ |
1140 | 0 | dcerpc_call_value *dcv; |
1141 | |
|
1142 | 0 | dcv = (dcerpc_call_value *)di->call_data; |
1143 | 0 | if(!dcv->pol){ |
1144 | 0 | dcv->pol=(e_ctx_hnd *)wmem_memdup(wmem_file_scope(), &policy_hnd, sizeof(e_ctx_hnd)); |
1145 | 0 | } |
1146 | 0 | } |
1147 | |
|
1148 | 0 | return offset; |
1149 | 0 | } |
1150 | | |
1151 | | /* this function must be called with hfindex being HF_GUID */ |
1152 | | int |
1153 | | dissect_nt_guid_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1154 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, int hfindex, |
1155 | | e_ctx_hnd *pdata, proto_item **pitem, |
1156 | | uint32_t param) |
1157 | 0 | { |
1158 | 0 | offset=dissect_nt_hnd(tvb, offset, pinfo, |
1159 | 0 | tree, di, drep, hfindex, |
1160 | 0 | pdata, pitem, |
1161 | 0 | param, HND_TYPE_GUID); |
1162 | |
|
1163 | 0 | return offset; |
1164 | 0 | } |
1165 | | |
1166 | | /* Some helper routines to dissect a range of uint8 characters. I don't |
1167 | | think these are "official" NDR representations and are probably specific |
1168 | | to NT so for the moment they're put here instead of in packet-dcerpc.c |
1169 | | and packet-dcerpc-ndr.c. */ |
1170 | | |
1171 | | int |
1172 | | dissect_dcerpc_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, |
1173 | | proto_tree *tree, dcerpc_info *di _U_, uint8_t *drep _U_, int hfindex, |
1174 | | int length, const uint8_t **pdata) |
1175 | 0 | { |
1176 | 0 | const uint8_t *data; |
1177 | |
|
1178 | 0 | data = (const uint8_t *)tvb_get_ptr(tvb, offset, length); |
1179 | | |
1180 | | /* This should be an FT_BYTES, so the byte order should not matter */ |
1181 | 0 | proto_tree_add_item (tree, hfindex, tvb, offset, length, ENC_NA); |
1182 | |
|
1183 | 0 | if (pdata) |
1184 | 0 | *pdata = data; |
1185 | |
|
1186 | 0 | return offset + length; |
1187 | 0 | } |
1188 | | |
1189 | | int |
1190 | | dissect_ndr_uint8s(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1191 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
1192 | | int hfindex, int length, const uint8_t **pdata) |
1193 | 0 | { |
1194 | 0 | if(di->conformant_run){ |
1195 | | /* just a run to handle conformant arrays, no scalars to dissect */ |
1196 | 0 | return offset; |
1197 | 0 | } |
1198 | | |
1199 | | /* no alignment needed */ |
1200 | 0 | return dissect_dcerpc_uint8s(tvb, offset, pinfo, |
1201 | 0 | tree, di, drep, hfindex, length, pdata); |
1202 | 0 | } |
1203 | | |
1204 | | int |
1205 | | dissect_dcerpc_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, |
1206 | | proto_tree *tree, uint8_t *drep, int hfindex, |
1207 | | int length) |
1208 | 0 | { |
1209 | | /* These are FT_BYTES fields, so the byte order should not matter; |
1210 | | however, perhaps there should be an FT_HEXADECTETS type, |
1211 | | or something such as that, with each pair of octets |
1212 | | displayed as a single unit, in which case the byte order |
1213 | | would matter, so we'll calculate the byte order here. */ |
1214 | 0 | proto_tree_add_item (tree, hfindex, tvb, offset, length * 2, DREP_ENC_INTEGER(drep)); |
1215 | |
|
1216 | 0 | return offset + length * 2; |
1217 | 0 | } |
1218 | | |
1219 | | int |
1220 | | dissect_ndr_uint16s(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1221 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, |
1222 | | int hfindex, int length) |
1223 | 0 | { |
1224 | 0 | if(di->conformant_run){ |
1225 | | /* just a run to handle conformant arrays, no scalars to dissect */ |
1226 | 0 | return offset; |
1227 | 0 | } |
1228 | | |
1229 | 0 | if (offset % 2) |
1230 | 0 | offset++; |
1231 | |
|
1232 | 0 | return dissect_dcerpc_uint16s(tvb, offset, pinfo, |
1233 | 0 | tree, drep, hfindex, length); |
1234 | 0 | } |
1235 | | |
1236 | | static void cb_str_postprocess_options(packet_info *pinfo, |
1237 | | proto_item *item, |
1238 | | dcerpc_info *di, |
1239 | | int options, |
1240 | | const char *s) |
1241 | 0 | { |
1242 | 0 | int levels = CB_STR_ITEM_LEVELS(options); |
1243 | | |
1244 | | /* Append string to COL_INFO */ |
1245 | |
|
1246 | 0 | if ((options & CB_STR_COL_INFO) && (!di->conformant_run)) { |
1247 | | /* |
1248 | | * kludge, ugly, but this is called twice for all |
1249 | | * dcerpc interfaces due to how we chase pointers |
1250 | | * and putting the sid twice on the summary line |
1251 | | * looks even worse. |
1252 | | * Real solution would be to block updates to col_info |
1253 | | * while we just do a conformance run, this might |
1254 | | * have sideeffects so it needs some more thoughts first. |
1255 | | */ |
1256 | 0 | col_append_fstr(pinfo->cinfo, COL_INFO, ", %s", s); |
1257 | 0 | } |
1258 | | |
1259 | | /* Append string to upper-level proto_items */ |
1260 | 0 | if (levels > 0 && item && s && s[0]) { |
1261 | 0 | proto_item_append_text(item, ": %s", s); |
1262 | 0 | item = GET_ITEM_PARENT(item); |
1263 | 0 | levels--; |
1264 | 0 | if (item && levels > 0) { |
1265 | 0 | proto_item_append_text(item, ": %s", s); |
1266 | 0 | item = GET_ITEM_PARENT(item); |
1267 | 0 | levels--; |
1268 | 0 | while (item && levels > 0) { |
1269 | 0 | proto_item_append_text(item, " %s", s); |
1270 | 0 | item = GET_ITEM_PARENT(item); |
1271 | 0 | levels--; |
1272 | 0 | } |
1273 | 0 | } |
1274 | 0 | } |
1275 | | |
1276 | | /* Save string to dcv->private_data */ |
1277 | 0 | if (options & CB_STR_SAVE) { |
1278 | 0 | dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; |
1279 | 0 | dcv->private_data = wmem_strdup(wmem_file_scope(), s); |
1280 | 0 | } |
1281 | 0 | } |
1282 | | |
1283 | | /* |
1284 | | * Helper routines for dissecting NDR strings |
1285 | | */ |
1286 | | void cb_wstr_postprocess(packet_info *pinfo, proto_tree *tree _U_, |
1287 | | proto_item *item, dcerpc_info *di, tvbuff_t *tvb, |
1288 | | int start_offset, int end_offset, |
1289 | | void *callback_args) |
1290 | 0 | { |
1291 | 0 | int options = GPOINTER_TO_INT(callback_args); |
1292 | 0 | const char *s; |
1293 | | |
1294 | | /* Align start_offset on 4-byte boundary. */ |
1295 | |
|
1296 | 0 | start_offset = WS_ROUNDUP_4(start_offset); |
1297 | | |
1298 | | /* Get string value */ |
1299 | |
|
1300 | 0 | if ((end_offset - start_offset) <= 12) |
1301 | 0 | return; /* XXX: Use unistr2 dissector instead? */ |
1302 | | |
1303 | | /* |
1304 | | * XXX - need to handle non-printable characters here. |
1305 | | * |
1306 | | * XXX - this is typically called after the string has already |
1307 | | * been fetched and processed by some other routine; is there |
1308 | | * some way we can get that string, rather than duplicating the |
1309 | | * efforts of that routine? |
1310 | | */ |
1311 | 0 | s = (char*)tvb_get_string_enc(pinfo->pool, |
1312 | 0 | tvb, start_offset + 12, end_offset - start_offset - 12, |
1313 | 0 | ENC_UTF_16|ENC_LITTLE_ENDIAN); |
1314 | |
|
1315 | 0 | cb_str_postprocess_options(pinfo, item, di, options, s); |
1316 | 0 | } |
1317 | | |
1318 | | void cb_str_postprocess(packet_info *pinfo, proto_tree *tree _U_, |
1319 | | proto_item *item, dcerpc_info *di, tvbuff_t *tvb, |
1320 | | int start_offset, int end_offset, |
1321 | | void *callback_args) |
1322 | 0 | { |
1323 | 0 | int options = GPOINTER_TO_INT(callback_args); |
1324 | 0 | const char *s; |
1325 | | |
1326 | | /* Align start_offset on 4-byte boundary. */ |
1327 | |
|
1328 | 0 | start_offset = WS_ROUNDUP_4(start_offset); |
1329 | | |
1330 | | /* Get string value */ |
1331 | |
|
1332 | 0 | if ((end_offset - start_offset) <= 12) |
1333 | 0 | return; /* XXX: Use unistr2 dissector instead? */ |
1334 | | |
1335 | | /* |
1336 | | * XXX - need to handle non-printable characters here. |
1337 | | * |
1338 | | * XXX - this is typically called after the string has already |
1339 | | * been fetched and processed by some other routine; is there |
1340 | | * some way we can get that string, rather than duplicating the |
1341 | | * efforts of that routine? |
1342 | | */ |
1343 | 0 | s = (char*)tvb_get_string_enc(pinfo->pool, |
1344 | 0 | tvb, start_offset + 12, (end_offset - start_offset - 12), ENC_ASCII); |
1345 | |
|
1346 | 0 | cb_str_postprocess_options(pinfo, item, di, options, s); |
1347 | 0 | } |
1348 | | |
1349 | | /* Dissect a pointer to a NDR string and append the string value to the |
1350 | | proto_item. */ |
1351 | | |
1352 | | int dissect_ndr_str_pointer_item(tvbuff_t *tvb, int offset, |
1353 | | packet_info *pinfo, proto_tree *tree, |
1354 | | dcerpc_info *di, uint8_t *drep, int type, const char *text, |
1355 | | int hf_index, int levels) |
1356 | 0 | { |
1357 | 0 | return dissect_ndr_pointer_cb( |
1358 | 0 | tvb, offset, pinfo, tree, di, drep, |
1359 | 0 | dissect_ndr_wchar_cvstring, type, text, hf_index, |
1360 | 0 | cb_wstr_postprocess, GINT_TO_POINTER(levels + 1)); |
1361 | 0 | } |
1362 | | |
1363 | | /* SID dissection routines */ |
1364 | | |
1365 | | static int hf_nt_count; |
1366 | | static int hf_nt_domain_sid; |
1367 | | |
1368 | | /* That's a SID that is always 28 bytes long */ |
1369 | | int |
1370 | | dissect_ndr_nt_SID28(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1371 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep _U_, int hf_index) |
1372 | 0 | { |
1373 | 0 | proto_item *item; |
1374 | 0 | dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; |
1375 | 0 | char *sid_str=NULL; |
1376 | 0 | const char *name; |
1377 | 0 | int newoffset; |
1378 | |
|
1379 | 0 | if(hf_index > 0){ |
1380 | 0 | name=proto_registrar_get_name(hf_index); |
1381 | 0 | } else { |
1382 | 0 | name="Domain"; |
1383 | 0 | } |
1384 | 0 | if(di->conformant_run){ |
1385 | | /* just a run to handle conformant arrays, no scalars to dissect */ |
1386 | 0 | return offset; |
1387 | 0 | } |
1388 | | |
1389 | 0 | newoffset = dissect_nt_sid(tvb, pinfo, offset, tree, name, &sid_str, |
1390 | 0 | hf_nt_domain_sid); |
1391 | | /* The dissected stuff can't be more than 28 bytes */ |
1392 | 0 | if ((newoffset - offset) > 28) { |
1393 | 0 | item = proto_tree_get_parent(tree? tree->last_child : NULL); |
1394 | 0 | expert_add_info(pinfo, item, &ei_dcerpc_nt_badsid); |
1395 | | |
1396 | | /* The rest of the dissection will most probably wrong as we are not dissecting what we expect */ |
1397 | 0 | return newoffset; |
1398 | 0 | } |
1399 | | |
1400 | | /* No matter how much we used for the real dissection of the SID consume 28 bytes */ |
1401 | 0 | if (tree) { |
1402 | 0 | item = proto_tree_get_parent(tree->last_child); |
1403 | 0 | proto_item_set_len(item, 28); |
1404 | 0 | } |
1405 | 0 | offset += 28; |
1406 | | /* dcv can be null, for example when this ndr structure is embedded |
1407 | | * inside non-dcerpc pdus, i.e. kerberos PAC structure |
1408 | | */ |
1409 | 0 | if(dcv){ |
1410 | | /* |
1411 | | * sid_str has ephemeral storage duration; |
1412 | | * dcerpc_call_values have session duration, |
1413 | | * so we need to make its private data have |
1414 | | * session duration as well. |
1415 | | */ |
1416 | 0 | dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str); |
1417 | 0 | } |
1418 | |
|
1419 | 0 | return offset; |
1420 | 0 | } |
1421 | | |
1422 | | int |
1423 | | dissect_ndr_nt_SID(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1424 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep) |
1425 | 0 | { |
1426 | 0 | dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; |
1427 | 0 | char *sid_str=NULL; |
1428 | 0 | const char *name; |
1429 | |
|
1430 | 0 | if(di->hf_index > 0){ |
1431 | 0 | name=proto_registrar_get_name(di->hf_index); |
1432 | 0 | } else { |
1433 | 0 | name="Domain"; |
1434 | 0 | } |
1435 | 0 | if(di->conformant_run){ |
1436 | | /* just a run to handle conformant arrays, no scalars to dissect */ |
1437 | 0 | return offset; |
1438 | 0 | } |
1439 | | |
1440 | | /* the SID contains a conformant array, first we must eat |
1441 | | the 4-byte max_count before we can hand it off */ |
1442 | | |
1443 | 0 | offset = dissect_ndr_uint3264 (tvb, offset, pinfo, tree, di, drep, |
1444 | 0 | hf_nt_count, NULL); |
1445 | |
|
1446 | 0 | offset = dissect_nt_sid(tvb, pinfo, offset, tree, name, &sid_str, |
1447 | 0 | hf_nt_domain_sid); |
1448 | | |
1449 | | /* dcv can be null, for example when this ndr structure is embedded |
1450 | | * inside non-dcerpc pdus, i.e. kerberos PAC structure |
1451 | | */ |
1452 | 0 | if(dcv){ |
1453 | | /* |
1454 | | * sid_str has ephemeral storage duration; |
1455 | | * dcerpc_call_values have session duration, |
1456 | | * so we need to make its private data have |
1457 | | * session duration as well. |
1458 | | */ |
1459 | 0 | dcv->private_data = wmem_strdup(wmem_file_scope(), sid_str); |
1460 | 0 | } |
1461 | |
|
1462 | 0 | return offset; |
1463 | 0 | } |
1464 | | |
1465 | | /* same as dissect_ndr_nt_SID() but takes the same options as counted strings |
1466 | | do to prettify the dissect pane and the COL_INFO summary line |
1467 | | */ |
1468 | | /* Note this is in fact for dissecting the dom_sid2*/ |
1469 | | int |
1470 | | dissect_ndr_nt_SID_with_options(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1471 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep, uint32_t options, int hf_index) |
1472 | 0 | { |
1473 | 0 | dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; |
1474 | |
|
1475 | 0 | di->hf_index = hf_index; |
1476 | 0 | offset=dissect_ndr_nt_SID(tvb, offset, pinfo, tree, di, drep); |
1477 | |
|
1478 | 0 | if(dcv && dcv->private_data){ |
1479 | 0 | char *s=(char *)dcv->private_data; |
1480 | 0 | proto_item *item=(proto_item *)tree; |
1481 | | |
1482 | | /* |
1483 | | * The string is already saved by dissect_ndr_nt_SID() |
1484 | | */ |
1485 | 0 | options &= ~CB_STR_SAVE; |
1486 | |
|
1487 | 0 | cb_str_postprocess_options(pinfo, |
1488 | 0 | item, |
1489 | 0 | di, |
1490 | 0 | options, |
1491 | 0 | s); |
1492 | 0 | } |
1493 | |
|
1494 | 0 | return offset; |
1495 | 0 | } |
1496 | | |
1497 | | static int |
1498 | | dissect_ndr_nt_SID_hf_through_ptr(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1499 | | proto_tree *tree, dcerpc_info *di, uint8_t *drep) |
1500 | 0 | { |
1501 | 0 | offset = dissect_ndr_nt_SID_with_options(tvb, offset, pinfo, tree, |
1502 | 0 | di, drep, |
1503 | 0 | CB_STR_ITEM_LEVELS(2), |
1504 | 0 | di->hf_index); |
1505 | |
|
1506 | 0 | return offset; |
1507 | 0 | } |
1508 | | |
1509 | | static int ett_nt_sid_pointer; |
1510 | | |
1511 | | int |
1512 | | dissect_ndr_nt_PSID_cb(tvbuff_t *tvb, int offset, |
1513 | | packet_info *pinfo, proto_tree *parent_tree, |
1514 | | dcerpc_info *di, uint8_t *drep, |
1515 | | dcerpc_callback_fnct_t *callback, void *callback_args) |
1516 | 0 | { |
1517 | 0 | proto_item *item; |
1518 | 0 | proto_tree *tree; |
1519 | 0 | int old_offset=offset; |
1520 | |
|
1521 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, |
1522 | 0 | ett_nt_sid_pointer, &item, "SID pointer"); |
1523 | |
|
1524 | 0 | offset = dissect_ndr_pointer_cb(tvb, offset, pinfo, tree, di, drep, |
1525 | 0 | dissect_ndr_nt_SID_hf_through_ptr, NDR_POINTER_UNIQUE, |
1526 | 0 | "SID pointer", hf_nt_domain_sid, |
1527 | 0 | callback, callback_args); |
1528 | |
|
1529 | 0 | proto_item_set_len(item, offset-old_offset); |
1530 | 0 | return offset; |
1531 | 0 | } |
1532 | | |
1533 | | int |
1534 | | dissect_ndr_nt_PSID(tvbuff_t *tvb, int offset, |
1535 | | packet_info *pinfo, proto_tree *parent_tree, |
1536 | | dcerpc_info *di, uint8_t *drep) |
1537 | 0 | { |
1538 | 0 | return dissect_ndr_nt_PSID_cb(tvb, offset, pinfo, parent_tree, |
1539 | 0 | di, drep, NULL, NULL); |
1540 | 0 | } |
1541 | | |
1542 | | static const true_false_string tfs_nt_acb_disabled = { |
1543 | | "Account is DISABLED", |
1544 | | "Account is NOT disabled" |
1545 | | }; |
1546 | | static const true_false_string tfs_nt_acb_homedirreq = { |
1547 | | "Homedir is REQUIRED", |
1548 | | "Homedir is NOT required" |
1549 | | }; |
1550 | | static const true_false_string tfs_nt_acb_pwnotreq = { |
1551 | | "Password is NOT required", |
1552 | | "Password is REQUIRED" |
1553 | | }; |
1554 | | static const true_false_string tfs_nt_acb_tempdup = { |
1555 | | "This is a TEMPORARY DUPLICATE account", |
1556 | | "This is NOT a temporary duplicate account" |
1557 | | }; |
1558 | | static const true_false_string tfs_nt_acb_normal = { |
1559 | | "This is a NORMAL USER account", |
1560 | | "This is NOT a normal user account" |
1561 | | }; |
1562 | | static const true_false_string tfs_nt_acb_mns = { |
1563 | | "This is a MNS account", |
1564 | | "This is NOT a mns account" |
1565 | | }; |
1566 | | static const true_false_string tfs_nt_acb_domtrust = { |
1567 | | "This is a DOMAIN TRUST account", |
1568 | | "This is NOT a domain trust account" |
1569 | | }; |
1570 | | static const true_false_string tfs_nt_acb_wstrust = { |
1571 | | "This is a WORKSTATION TRUST account", |
1572 | | "This is NOT a workstation trust account" |
1573 | | }; |
1574 | | static const true_false_string tfs_nt_acb_svrtrust = { |
1575 | | "This is a SERVER TRUST account", |
1576 | | "This is NOT a server trust account" |
1577 | | }; |
1578 | | static const true_false_string tfs_nt_acb_pwnoexp = { |
1579 | | "Passwords does NOT expire", |
1580 | | "Password will EXPIRE" |
1581 | | }; |
1582 | | static const true_false_string tfs_nt_acb_autolock = { |
1583 | | "This account has been AUTO LOCKED", |
1584 | | "This account has NOT been auto locked" |
1585 | | }; |
1586 | | |
1587 | | static int ett_nt_acct_ctrl; |
1588 | | |
1589 | | static int hf_nt_acct_ctrl; |
1590 | | static int hf_nt_acb_disabled; |
1591 | | static int hf_nt_acb_homedirreq; |
1592 | | static int hf_nt_acb_pwnotreq; |
1593 | | static int hf_nt_acb_tempdup; |
1594 | | static int hf_nt_acb_normal; |
1595 | | static int hf_nt_acb_mns; |
1596 | | static int hf_nt_acb_domtrust; |
1597 | | static int hf_nt_acb_wstrust; |
1598 | | static int hf_nt_acb_svrtrust; |
1599 | | static int hf_nt_acb_pwnoexp; |
1600 | | static int hf_nt_acb_autolock; |
1601 | | |
1602 | | int |
1603 | | dissect_ndr_nt_acct_ctrl(tvbuff_t *tvb, int offset, packet_info *pinfo, |
1604 | | proto_tree *parent_tree, dcerpc_info *di, uint8_t *drep) |
1605 | 0 | { |
1606 | 0 | uint32_t mask; |
1607 | 0 | static int * const flags[] = { |
1608 | 0 | &hf_nt_acb_autolock, |
1609 | 0 | &hf_nt_acb_pwnoexp, |
1610 | 0 | &hf_nt_acb_svrtrust, |
1611 | 0 | &hf_nt_acb_wstrust, |
1612 | 0 | &hf_nt_acb_domtrust, |
1613 | 0 | &hf_nt_acb_mns, |
1614 | 0 | &hf_nt_acb_normal, |
1615 | 0 | &hf_nt_acb_tempdup, |
1616 | 0 | &hf_nt_acb_pwnotreq, |
1617 | 0 | &hf_nt_acb_homedirreq, |
1618 | 0 | &hf_nt_acb_disabled, |
1619 | 0 | NULL |
1620 | 0 | }; |
1621 | |
|
1622 | 0 | offset=dissect_ndr_uint32(tvb, offset, pinfo, NULL, di, drep, -1, &mask); |
1623 | |
|
1624 | 0 | proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset-4, hf_nt_acct_ctrl, |
1625 | 0 | ett_nt_acct_ctrl, flags, mask, BMT_NO_APPEND); |
1626 | |
|
1627 | 0 | return offset; |
1628 | 0 | } |
1629 | | |
1630 | | static int hf_logonhours_unknown_char; |
1631 | | |
1632 | | static int |
1633 | | dissect_LOGON_HOURS_entry(tvbuff_t *tvb, int offset, |
1634 | | packet_info *pinfo, proto_tree *tree, |
1635 | | dcerpc_info *di, uint8_t *drep) |
1636 | 0 | { |
1637 | 0 | offset = dissect_ndr_uint8(tvb, offset, pinfo, tree, di, drep, |
1638 | 0 | hf_logonhours_unknown_char, NULL); |
1639 | 0 | return offset; |
1640 | 0 | } |
1641 | | |
1642 | | static int ett_nt_logon_hours_hours; |
1643 | | |
1644 | | static int |
1645 | | dissect_LOGON_HOURS_hours(tvbuff_t *tvb, int offset, |
1646 | | packet_info *pinfo, proto_tree *parent_tree, |
1647 | | dcerpc_info *di, uint8_t *drep) |
1648 | 0 | { |
1649 | 0 | proto_item *item; |
1650 | 0 | proto_tree *tree; |
1651 | 0 | int old_offset=offset; |
1652 | |
|
1653 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, |
1654 | 0 | ett_nt_logon_hours_hours, &item, "LOGON_HOURS:"); |
1655 | |
|
1656 | 0 | offset = dissect_ndr_ucvarray(tvb, offset, pinfo, tree, di, drep, |
1657 | 0 | dissect_LOGON_HOURS_entry); |
1658 | |
|
1659 | 0 | proto_item_set_len(item, offset-old_offset); |
1660 | 0 | return offset; |
1661 | 0 | } |
1662 | | |
1663 | | static int ett_nt_logon_hours; |
1664 | | static int hf_logonhours_divisions; |
1665 | | |
1666 | | int |
1667 | | dissect_ndr_nt_LOGON_HOURS(tvbuff_t *tvb, int offset, |
1668 | | packet_info *pinfo, proto_tree *parent_tree, |
1669 | | dcerpc_info *di, uint8_t *drep) |
1670 | 0 | { |
1671 | 0 | proto_item *item; |
1672 | 0 | proto_tree *tree; |
1673 | 0 | int old_offset=offset; |
1674 | |
|
1675 | 0 | ALIGN_TO_4_BYTES; /* structure starts with short, but is aligned for longs */ |
1676 | |
|
1677 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, |
1678 | 0 | ett_nt_logon_hours, &item, "LOGON_HOURS:"); |
1679 | |
|
1680 | 0 | offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, |
1681 | 0 | hf_logonhours_divisions, NULL); |
1682 | | /* XXX - is this a bitmask like the "logon hours" field in the |
1683 | | Remote API call "NetUserGetInfo()" with an information level |
1684 | | of 11? */ |
1685 | 0 | offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep, |
1686 | 0 | dissect_LOGON_HOURS_hours, NDR_POINTER_UNIQUE, |
1687 | 0 | "LOGON_HOURS", -1); |
1688 | |
|
1689 | 0 | proto_item_set_len(item, offset-old_offset); |
1690 | 0 | return offset; |
1691 | 0 | } |
1692 | | |
1693 | | static int |
1694 | | dissect_ndr_nt_PSID_no_hf(tvbuff_t *tvb, int offset, |
1695 | | packet_info *pinfo, proto_tree *parent_tree, |
1696 | | dcerpc_info *di, uint8_t *drep) |
1697 | 0 | { |
1698 | 0 | offset=dissect_ndr_nt_PSID(tvb, offset, pinfo, parent_tree, di, drep); |
1699 | 0 | return offset; |
1700 | 0 | } |
1701 | | |
1702 | | static int |
1703 | | dissect_ndr_nt_PSID_ARRAY_sids (tvbuff_t *tvb, int offset, |
1704 | | packet_info *pinfo, proto_tree *tree, |
1705 | | dcerpc_info *di, uint8_t *drep) |
1706 | 0 | { |
1707 | 0 | offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep, |
1708 | 0 | dissect_ndr_nt_PSID_no_hf); |
1709 | |
|
1710 | 0 | return offset; |
1711 | 0 | } |
1712 | | |
1713 | | static int ett_nt_sid_array; |
1714 | | |
1715 | | int |
1716 | | dissect_ndr_nt_PSID_ARRAY(tvbuff_t *tvb, int offset, |
1717 | | packet_info *pinfo, proto_tree *parent_tree, |
1718 | | dcerpc_info *di, uint8_t *drep) |
1719 | 0 | { |
1720 | 0 | uint32_t count; |
1721 | 0 | proto_item *item; |
1722 | 0 | proto_tree *tree; |
1723 | 0 | int old_offset=offset; |
1724 | |
|
1725 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, -1, |
1726 | 0 | ett_nt_sid_array, &item, "SID array:"); |
1727 | |
|
1728 | 0 | ALIGN_TO_5_BYTES; |
1729 | |
|
1730 | 0 | offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep, |
1731 | 0 | hf_nt_count, &count); |
1732 | 0 | offset = dissect_ndr_pointer(tvb, offset, pinfo, tree, di, drep, |
1733 | 0 | dissect_ndr_nt_PSID_ARRAY_sids, NDR_POINTER_UNIQUE, |
1734 | 0 | "PSID_ARRAY", -1); |
1735 | |
|
1736 | 0 | proto_item_set_len(item, offset-old_offset); |
1737 | |
|
1738 | 0 | if (di->call_data->flags & DCERPC_IS_NDR64) { |
1739 | 0 | ALIGN_TO_5_BYTES; |
1740 | 0 | } |
1741 | |
|
1742 | 0 | return offset; |
1743 | 0 | } |
1744 | | |
1745 | | static int ett_nt_sid_and_attributes; |
1746 | | static int ett_nt_se_group_attrs; |
1747 | | static int hf_nt_se_group_attrs; |
1748 | | static int hf_nt_se_group_attrs_mandatory; |
1749 | | static int hf_nt_se_group_attrs_enabled_by_default; |
1750 | | static int hf_nt_se_group_attrs_enabled; |
1751 | | static int hf_nt_se_group_attrs_owner; |
1752 | | static int hf_nt_se_group_attrs_resource_group; |
1753 | | |
1754 | | static const true_false_string group_attrs_mandatory = { |
1755 | | "The MANDATORY bit is SET", |
1756 | | "The mandatory bit is NOT set", |
1757 | | }; |
1758 | | static const true_false_string group_attrs_enabled_by_default = { |
1759 | | "The ENABLED_BY_DEFAULT bit is SET", |
1760 | | "The enabled_by_default bit is NOT set", |
1761 | | }; |
1762 | | static const true_false_string group_attrs_enabled = { |
1763 | | "The ENABLED bit is SET", |
1764 | | "The enabled bit is NOT set", |
1765 | | }; |
1766 | | static const true_false_string group_attrs_owner = { |
1767 | | "The OWNER bit is SET", |
1768 | | "The owner bit is NOT set", |
1769 | | }; |
1770 | | static const true_false_string group_attrs_resource_group = { |
1771 | | "The RESOURCE GROUP bit is SET", |
1772 | | "The resource group bit is NOT set", |
1773 | | }; |
1774 | | |
1775 | | int |
1776 | | dissect_ndr_nt_SE_GROUP_ATTRIBUTES(tvbuff_t *tvb, int offset, |
1777 | | packet_info *pinfo, proto_tree *parent_tree, |
1778 | | dcerpc_info *di, uint8_t *drep) |
1779 | 0 | { |
1780 | 0 | uint32_t mask; |
1781 | 0 | static int * const attr[] = { |
1782 | 0 | &hf_nt_se_group_attrs_mandatory, |
1783 | 0 | &hf_nt_se_group_attrs_enabled_by_default, |
1784 | 0 | &hf_nt_se_group_attrs_enabled, |
1785 | 0 | &hf_nt_se_group_attrs_owner, |
1786 | 0 | &hf_nt_se_group_attrs_resource_group, |
1787 | 0 | NULL |
1788 | 0 | }; |
1789 | |
|
1790 | 0 | if(di->conformant_run){ |
1791 | | /*just a run to handle conformant arrays, nothing to dissect */ |
1792 | 0 | return offset; |
1793 | 0 | } |
1794 | | |
1795 | 0 | offset=dissect_ndr_uint32(tvb, offset, pinfo, NULL, di, drep, |
1796 | 0 | -1, &mask); |
1797 | |
|
1798 | 0 | proto_tree_add_bitmask_value_with_flags(parent_tree, tvb, offset-4, |
1799 | 0 | hf_nt_se_group_attrs, ett_nt_se_group_attrs, |
1800 | 0 | attr, mask, BMT_NO_APPEND); |
1801 | 0 | return offset; |
1802 | 0 | } |
1803 | | |
1804 | | static void dissect_propagate_SID_to_parent_callback(packet_info *pinfo, |
1805 | | proto_tree *tree _U_, |
1806 | | proto_item *item _U_, |
1807 | | dcerpc_info *di, |
1808 | | tvbuff_t *tvb _U_, |
1809 | | int start_offset _U_, |
1810 | | int end_offset _U_, |
1811 | | void *callback_args) |
1812 | 0 | { |
1813 | 0 | proto_item *parent_item = (proto_item *)callback_args; |
1814 | 0 | dcerpc_call_value *dcv = (dcerpc_call_value *)di->call_data; |
1815 | |
|
1816 | 0 | if (parent_item && dcv && dcv->private_data) { |
1817 | 0 | const char *s = (const char *)dcv->private_data; |
1818 | |
|
1819 | 0 | cb_str_postprocess_options(pinfo, |
1820 | 0 | parent_item, |
1821 | 0 | di, |
1822 | 0 | CB_STR_ITEM_LEVELS(1), |
1823 | 0 | s); |
1824 | 0 | } |
1825 | 0 | } |
1826 | | |
1827 | | int |
1828 | | dissect_ndr_nt_SID_AND_ATTRIBUTES(tvbuff_t *tvb, int offset, |
1829 | | packet_info *pinfo, proto_tree *parent_tree, |
1830 | | dcerpc_info *di, uint8_t *drep) |
1831 | 0 | { |
1832 | 0 | proto_item *item; |
1833 | 0 | proto_tree *tree; |
1834 | |
|
1835 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, 0, |
1836 | 0 | ett_nt_sid_and_attributes, &item, "SID_AND_ATTRIBUTES"); |
1837 | |
|
1838 | 0 | offset = dissect_ndr_nt_PSID_cb(tvb, offset, pinfo, tree, di, drep, |
1839 | 0 | dissect_propagate_SID_to_parent_callback, item); |
1840 | |
|
1841 | 0 | offset = dissect_ndr_nt_SE_GROUP_ATTRIBUTES(tvb, offset, pinfo, tree, di, drep); |
1842 | |
|
1843 | 0 | return offset; |
1844 | 0 | } |
1845 | | |
1846 | | static int ett_nt_sid_and_attributes_array; |
1847 | | |
1848 | | int |
1849 | | dissect_ndr_nt_SID_AND_ATTRIBUTES_ARRAY(tvbuff_t *tvb, int offset, |
1850 | | packet_info *pinfo, proto_tree *parent_tree, |
1851 | | dcerpc_info *di, uint8_t *drep) |
1852 | 0 | { |
1853 | 0 | proto_item *item; |
1854 | 0 | proto_tree *tree; |
1855 | 0 | int old_offset=offset; |
1856 | |
|
1857 | 0 | tree = proto_tree_add_subtree(parent_tree, tvb, offset, 0, |
1858 | 0 | ett_nt_sid_and_attributes_array, &item, "SID_AND_ATTRIBUTES array:"); |
1859 | | |
1860 | | /*offset = dissect_ndr_uint32 (tvb, offset, pinfo, tree, di, drep, |
1861 | | hf_samr_count, &count); */ |
1862 | 0 | offset = dissect_ndr_ucarray(tvb, offset, pinfo, tree, di, drep, |
1863 | 0 | dissect_ndr_nt_SID_AND_ATTRIBUTES); |
1864 | |
|
1865 | 0 | proto_item_set_len(item, offset-old_offset); |
1866 | 0 | return offset; |
1867 | 0 | } |
1868 | | |
1869 | | /* This might be some sort of header that MIDL generates when creating |
1870 | | * marshalling/unmarshalling code for blobs that are not to be transported |
1871 | | * on top of DCERPC and where the DREP fields specifying things such as |
1872 | | * endianness and similar are not available. |
1873 | | */ |
1874 | | int |
1875 | | nt_dissect_MIDL_NDRHEADERBLOB(proto_tree *parent_tree, tvbuff_t *tvb, int offset, uint8_t *drep) |
1876 | 0 | { |
1877 | 0 | proto_tree *tree; |
1878 | 0 | uint8_t val; |
1879 | |
|
1880 | 0 | tree=proto_tree_add_subtree(parent_tree, tvb, offset, 16, ett_nt_MIDL_BLOB, NULL, "MES header"); |
1881 | | |
1882 | | /* modified DREP field that is used for stuff that is transported on top |
1883 | | * of non dcerpc |
1884 | | */ |
1885 | 0 | proto_tree_add_item(tree, hf_nt_midl_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); |
1886 | 0 | offset++; |
1887 | |
|
1888 | 0 | val = tvb_get_uint8(tvb, offset); |
1889 | 0 | proto_tree_add_uint(tree, hf_dcerpc_drep_byteorder, tvb, offset, 1, val>>4); |
1890 | |
|
1891 | 0 | offset++; |
1892 | |
|
1893 | 0 | if (drep) { |
1894 | 0 | *drep = val; |
1895 | 0 | } |
1896 | |
|
1897 | 0 | proto_tree_add_item(tree, hf_nt_midl_hdr_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); |
1898 | 0 | offset+=2; |
1899 | |
|
1900 | 0 | proto_tree_add_item(tree, hf_nt_midl_fill_bytes, tvb, offset, 4, ENC_LITTLE_ENDIAN); |
1901 | 0 | offset += 4; |
1902 | | |
1903 | | /* length of blob that follows */ |
1904 | 0 | proto_tree_add_item(tree, hf_nt_midl_blob_len, tvb, offset, 8, ENC_LITTLE_ENDIAN); |
1905 | 0 | offset += 8; |
1906 | |
|
1907 | 0 | return offset; |
1908 | 0 | } |
1909 | | |
1910 | | /* |
1911 | | * Register ett/hf values and perform DCERPC over SMB specific |
1912 | | * initialisation. |
1913 | | */ |
1914 | | void dcerpc_smb_init(int proto_dcerpc) |
1915 | 14 | { |
1916 | 14 | expert_module_t* expert_dcerpc_nt; |
1917 | 14 | static hf_register_info hf[] = { |
1918 | | |
1919 | | /* String handling */ |
1920 | | |
1921 | 14 | { &hf_nt_cs_size, |
1922 | 14 | { "Size", "dcerpc.nt.str.size", FT_UINT16, BASE_DEC, |
1923 | 14 | NULL, 0x0, "Size of string in short integers", |
1924 | 14 | HFILL }}, |
1925 | | |
1926 | 14 | { &hf_nt_cs_len, |
1927 | 14 | { "Length", "dcerpc.nt.str.len", FT_UINT16, BASE_DEC, |
1928 | 14 | NULL, 0x0, "Length of string in short integers", |
1929 | 14 | HFILL }}, |
1930 | | |
1931 | | /* GUIDs */ |
1932 | 14 | { &hf_nt_guid, |
1933 | 14 | { "GUID", "dcerpc.nt.guid", FT_GUID, BASE_NONE, |
1934 | 14 | NULL, 0x0, "GUID (uuid for groups?)", HFILL }}, |
1935 | | |
1936 | | /* Policy handles */ |
1937 | | |
1938 | 14 | { &hf_nt_policy_open_frame, |
1939 | 14 | { "Frame handle opened", "dcerpc.nt.open_frame", |
1940 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
1941 | 14 | NULL, HFILL }}, |
1942 | | |
1943 | 14 | { &hf_nt_policy_close_frame, |
1944 | 14 | { "Frame handle closed", "dcerpc.nt.close_frame", |
1945 | 14 | FT_FRAMENUM, BASE_NONE, NULL, 0x0, |
1946 | 14 | NULL, HFILL }}, |
1947 | | |
1948 | | /* ACBs */ |
1949 | | |
1950 | 14 | { &hf_nt_acct_ctrl, |
1951 | 14 | { "Acct Ctrl", "dcerpc.nt.acct_ctrl", FT_UINT32, BASE_HEX, |
1952 | 14 | NULL, 0x0, NULL, HFILL }}, |
1953 | | |
1954 | 14 | { &hf_nt_acb_disabled, |
1955 | 14 | { "Account disabled", "dcerpc.nt.acb.disabled", FT_BOOLEAN, 32, |
1956 | 14 | TFS(&tfs_nt_acb_disabled), 0x00000001, |
1957 | 14 | "If this account is enabled or disabled", HFILL }}, |
1958 | | |
1959 | 14 | { &hf_nt_acb_homedirreq, |
1960 | 14 | { "Home dir required", "dcerpc.nt.acb.homedirreq", FT_BOOLEAN, 32, |
1961 | 14 | TFS(&tfs_nt_acb_homedirreq), 0x00000002, |
1962 | 14 | "Is homedirs required for this account?", HFILL }}, |
1963 | | |
1964 | 14 | { &hf_nt_acb_pwnotreq, |
1965 | 14 | { "Password required", "dcerpc.nt.acb.pwnotreq", FT_BOOLEAN, 32, |
1966 | 14 | TFS(&tfs_nt_acb_pwnotreq), 0x00000004, |
1967 | 14 | "If a password is required for this account?", HFILL }}, |
1968 | | |
1969 | 14 | { &hf_nt_acb_tempdup, |
1970 | 14 | { "Temporary duplicate account", "dcerpc.nt.acb.tempdup", FT_BOOLEAN, 32, |
1971 | 14 | TFS(&tfs_nt_acb_tempdup), 0x00000008, |
1972 | 14 | "If this is a temporary duplicate account", HFILL }}, |
1973 | | |
1974 | 14 | { &hf_nt_acb_normal, |
1975 | 14 | { "Normal user account", "dcerpc.nt.acb.normal", FT_BOOLEAN, 32, |
1976 | 14 | TFS(&tfs_nt_acb_normal), 0x00000010, |
1977 | 14 | "If this is a normal user account", HFILL }}, |
1978 | | |
1979 | 14 | { &hf_nt_acb_mns, |
1980 | 14 | { "MNS logon user account", "dcerpc.nt.acb.mns", FT_BOOLEAN, 32, |
1981 | 14 | TFS(&tfs_nt_acb_mns), 0x00000020, |
1982 | 14 | NULL, HFILL }}, |
1983 | | |
1984 | 14 | { &hf_nt_acb_domtrust, |
1985 | 14 | { "Interdomain trust account", "dcerpc.nt.acb.domtrust", FT_BOOLEAN, 32, |
1986 | 14 | TFS(&tfs_nt_acb_domtrust), 0x00000040, |
1987 | 14 | NULL, HFILL }}, |
1988 | | |
1989 | 14 | { &hf_nt_acb_wstrust, |
1990 | 14 | { "Workstation trust account", "dcerpc.nt.acb.wstrust", FT_BOOLEAN, 32, |
1991 | 14 | TFS(&tfs_nt_acb_wstrust), 0x00000080, |
1992 | 14 | NULL, HFILL }}, |
1993 | | |
1994 | 14 | { &hf_nt_acb_svrtrust, |
1995 | 14 | { "Server trust account", "dcerpc.nt.acb.svrtrust", FT_BOOLEAN, 32, |
1996 | 14 | TFS(&tfs_nt_acb_svrtrust), 0x00000100, |
1997 | 14 | NULL, HFILL }}, |
1998 | | |
1999 | 14 | { &hf_nt_acb_pwnoexp, |
2000 | 14 | { "Password expires", "dcerpc.nt.acb.pwnoexp", FT_BOOLEAN, 32, |
2001 | 14 | TFS(&tfs_nt_acb_pwnoexp), 0x00000200, |
2002 | 14 | "If this account expires or not", HFILL }}, |
2003 | | |
2004 | 14 | { &hf_nt_acb_autolock, |
2005 | 14 | { "Account is autolocked", "dcerpc.nt.acb.autolock", FT_BOOLEAN, 32, |
2006 | 14 | TFS(&tfs_nt_acb_autolock), 0x00000400, |
2007 | 14 | "If this account has been autolocked", HFILL }}, |
2008 | | |
2009 | 14 | { &hf_nt_error, |
2010 | 14 | { "Wrong string type", "dcerpc.nt.sting_error", |
2011 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
2012 | 14 | "Non terminated string", HFILL }}, |
2013 | | |
2014 | | /* SIDs */ |
2015 | | |
2016 | 14 | { &hf_nt_domain_sid, |
2017 | 14 | { "Domain SID", "dcerpc.nt.domain_sid", |
2018 | 14 | FT_STRING, BASE_NONE, NULL, 0x0, |
2019 | 14 | "The Domain SID", HFILL }}, |
2020 | | |
2021 | 14 | { &hf_nt_count, |
2022 | 14 | { "Count", "dcerpc.nt.count", |
2023 | 14 | FT_UINT32, BASE_DEC, NULL, 0x0, |
2024 | 14 | "Number of elements in following array", HFILL }}, |
2025 | | |
2026 | | /* Logon hours */ |
2027 | | |
2028 | 14 | { &hf_logonhours_divisions, |
2029 | 14 | { "Divisions", "dcerpc.nt.logonhours.divisions", |
2030 | 14 | FT_UINT16, BASE_DEC, NULL, 0, |
2031 | 14 | "Number of divisions for LOGON_HOURS", HFILL }}, |
2032 | | |
2033 | 14 | { &hf_logonhours_unknown_char, |
2034 | 14 | { "Unknown char", "dcerpc.nt.unknown.char", |
2035 | 14 | FT_UINT8, BASE_HEX, NULL, 0x0, |
2036 | 14 | "Unknown char. If you know what this is, contact wireshark developers.", HFILL }}, |
2037 | | |
2038 | | /* Misc */ |
2039 | | |
2040 | 14 | { &hf_lsa_String_name_len, |
2041 | 14 | { "Name Len", "dcerpc.lsa_String.name_len", |
2042 | 14 | FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, |
2043 | | |
2044 | 14 | { &hf_lsa_String_name_size, |
2045 | 14 | { "Name Size", "dcerpc.lsa_String.name_size", |
2046 | 14 | FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, |
2047 | | |
2048 | 14 | { &hf_nt_data_blob_len, |
2049 | 14 | { "Blob size", "dcerpc.nt.blob.size", |
2050 | 14 | FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }}, |
2051 | | |
2052 | 14 | { &hf_nt_data_blob_data, |
2053 | 14 | { "Blob data", "dcerpc.nt.blob.data", |
2054 | 14 | FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}, |
2055 | | |
2056 | 14 | { &hf_nt_midl_blob_len, { |
2057 | 14 | "Blob Length", "nt.midl_blob_len", FT_UINT64, BASE_DEC, |
2058 | 14 | NULL, 0, "Length of NDR encoded data that follows", HFILL }}, |
2059 | | |
2060 | 14 | { &hf_nt_midl_fill_bytes, { |
2061 | 14 | "Fill bytes", "nt.midl.fill_bytes", FT_UINT32, BASE_HEX, |
2062 | 14 | NULL, 0, "Just some fill bytes", HFILL }}, |
2063 | | |
2064 | 14 | { &hf_nt_midl_version, { |
2065 | 14 | "Version", "nt.midl.version", FT_UINT8, BASE_DEC, |
2066 | 14 | NULL, 0, "Version of pickling", HFILL }}, |
2067 | | |
2068 | 14 | { &hf_nt_midl_hdr_len, { |
2069 | 14 | "HDR Length", "nt.midl.hdr_len", FT_UINT16, BASE_DEC, |
2070 | 14 | NULL, 0, "Length of header", HFILL }}, |
2071 | | |
2072 | 14 | { &hf_nt_se_group_attrs, |
2073 | 14 | { "Group Attributes", "dcerpc.nt.groups.attrs", |
2074 | 14 | FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }}, |
2075 | | |
2076 | 14 | { &hf_nt_se_group_attrs_mandatory, |
2077 | 14 | { "Mandatory", "dcerpc.nt.groups.attrs.mandatory", |
2078 | 14 | FT_BOOLEAN, 32, TFS(&group_attrs_mandatory), 0x00000001, |
2079 | 14 | "The group attributes MANDATORY flag", HFILL }}, |
2080 | | |
2081 | 14 | { &hf_nt_se_group_attrs_enabled_by_default, { |
2082 | 14 | "Enabled By Default", "dcerpc.nt.groups.attrs.enabled_by_default", |
2083 | 14 | FT_BOOLEAN, 32, TFS(&group_attrs_enabled_by_default), 0x00000002, |
2084 | 14 | "The group attributes ENABLED_BY_DEFAULT flag", HFILL }}, |
2085 | | |
2086 | 14 | { &hf_nt_se_group_attrs_enabled, { |
2087 | 14 | "Enabled", "dcerpc.nt.groups.attrs.enabled", |
2088 | 14 | FT_BOOLEAN, 32, TFS(&group_attrs_enabled), 0x00000004, |
2089 | 14 | "The group attributes ENABLED flag", HFILL }}, |
2090 | | |
2091 | 14 | { &hf_nt_se_group_attrs_owner, { |
2092 | 14 | "Owner", "dcerpc.nt.groups.attrs.owner", |
2093 | 14 | FT_BOOLEAN, 32, TFS(&group_attrs_owner), 0x00000008, |
2094 | 14 | "The group attributes OWNER flag", HFILL }}, |
2095 | | |
2096 | 14 | { &hf_nt_se_group_attrs_resource_group, { |
2097 | 14 | "Resource Group", "dcerpc.nt.groups.attrs.resource_group", |
2098 | 14 | FT_BOOLEAN, 32, TFS(&group_attrs_resource_group), 0x20000000, |
2099 | 14 | "The group attributes RESOURCE GROUP flag", HFILL }}, |
2100 | | |
2101 | 14 | }; |
2102 | | |
2103 | 14 | static int *ett[] = { |
2104 | 14 | &ett_nt_data_blob, |
2105 | 14 | &ett_nt_counted_string, |
2106 | 14 | &ett_nt_counted_byte_array, |
2107 | 14 | &ett_nt_policy_hnd, |
2108 | 14 | &ett_nt_sid_pointer, |
2109 | 14 | &ett_nt_acct_ctrl, |
2110 | 14 | &ett_nt_logon_hours, |
2111 | 14 | &ett_nt_logon_hours_hours, |
2112 | 14 | &ett_nt_sid_array, |
2113 | 14 | &ett_nt_sid_and_attributes_array, |
2114 | 14 | &ett_nt_sid_and_attributes, |
2115 | 14 | &ett_nt_se_group_attrs, |
2116 | 14 | &ett_nt_counted_ascii_string, |
2117 | 14 | &ett_lsa_String, |
2118 | 14 | &ett_nt_MIDL_BLOB, |
2119 | 14 | }; |
2120 | 14 | static ei_register_info ei[] = { |
2121 | 14 | { &ei_dcerpc_nt_badsid, { "dcerpc.nt.badsid", PI_MALFORMED, PI_ERROR, "Association rejected", EXPFILL }}, |
2122 | 14 | }; |
2123 | | |
2124 | | /* Register ett's and hf's */ |
2125 | | |
2126 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
2127 | 14 | proto_register_field_array(proto_dcerpc, hf, array_length(hf)); |
2128 | | |
2129 | | /* Initialise policy handle hash */ |
2130 | 14 | expert_dcerpc_nt = expert_register_protocol(proto_dcerpc); |
2131 | 14 | expert_register_field_array(expert_dcerpc_nt, ei, array_length(ei)); |
2132 | | |
2133 | 14 | pol_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), pol_hash_fn, pol_hash_compare); |
2134 | 14 | } |
2135 | | |
2136 | | /* |
2137 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
2138 | | * |
2139 | | * Local variables: |
2140 | | * c-basic-offset: 8 |
2141 | | * tab-width: 8 |
2142 | | * indent-tabs-mode: t |
2143 | | * End: |
2144 | | * |
2145 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
2146 | | * :indentSize=8:tabSize=8:noTabs=false: |
2147 | | */ |