Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
 */