Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-dcerpc-ndr.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-dcerpc-ndr.c
2
 * Routines for DCERPC NDR dissection
3
 * Copyright 2001, Todd Sabin <tas@webspan.net>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
#include "config.h"
13
14
#include <epan/packet.h>
15
16
#include <wsutil/ws_roundup.h>
17
#include <wsutil/ws_padding_to.h>
18
19
#include "packet-dcerpc.h"
20
21
/*
22
 * The NDR routines are for use by dcerpc subdissetors.  They're
23
 * primarily for making sure things are aligned properly according
24
 * to the rules of NDR.
25
 */
26
27
int
28
dissect_ndr_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
29
                  proto_tree *tree, dcerpc_info *di, uint8_t *drep,
30
                  int hfindex, uint8_t *pdata)
31
0
{
32
    /* Some callers expect us to initialize pdata, even in error conditions, so
33
     * do it right away in case we forget later */
34
0
    if (pdata)
35
0
        *pdata = 0;
36
37
0
    if (di->conformant_run) {
38
        /* just a run to handle conformant arrays, no scalars to dissect */
39
0
        return offset;
40
0
    }
41
42
    /* no alignment needed */
43
0
    return dissect_dcerpc_uint8(tvb, offset, pinfo,
44
0
                                tree, drep, hfindex, pdata);
45
0
}
46
47
int
48
PIDL_dissect_uint8_val(tvbuff_t *tvb, int offset, packet_info *pinfo,
49
                       proto_tree *tree, dcerpc_info *di, uint8_t *drep,
50
                       int hfindex, uint32_t param, uint8_t *pval)
51
0
{
52
0
    uint8_t      val;
53
54
0
    if (di->conformant_run) {
55
        /* just a run to handle conformant arrays, no scalars to dissect */
56
0
        return offset;
57
0
    }
58
59
    /* no alignment needed */
60
0
    offset = dissect_dcerpc_uint8(tvb, offset, pinfo,
61
0
                                  tree, drep, hfindex, &val);
62
63
0
    if (param&PIDL_SET_COL_INFO) {
64
0
        header_field_info *hf_info;
65
0
        char *valstr;
66
67
0
        hf_info = proto_registrar_get_nth(hfindex);
68
69
0
        valstr = (char *)wmem_alloc(pinfo->pool, 64);
70
0
        valstr[0]=0;
71
72
0
        switch (hf_info->display) {
73
0
        case BASE_DEC:
74
0
            if (hf_info->strings) {
75
0
                snprintf(valstr, 64, "%s(%d)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
76
0
            } else {
77
0
                snprintf(valstr, 64, "%d", val);
78
0
            }
79
0
            break;
80
0
        case BASE_HEX:
81
0
            if (hf_info->strings) {
82
0
                snprintf(valstr, 64, "%s(0x%02x)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
83
0
            } else {
84
0
                snprintf(valstr, 64, "0x%02x", val);
85
0
            }
86
0
            break;
87
0
        default:
88
0
            REPORT_DISSECTOR_BUG("Invalid hf->display value");
89
0
        }
90
91
0
        col_append_fstr(pinfo->cinfo, COL_INFO," %s:%s", hf_info->name, valstr);
92
0
    }
93
0
    if (pval) {
94
0
        *pval = val;
95
0
    }
96
97
0
    return offset;
98
0
}
99
100
int
101
PIDL_dissect_uint8(tvbuff_t *tvb, int offset, packet_info *pinfo,
102
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
103
                   int hfindex, uint32_t param)
104
0
{
105
0
    return PIDL_dissect_uint8_val(tvb, offset, pinfo, tree, di, drep, hfindex, param, NULL);
106
0
}
107
108
109
int
110
dissect_ndr_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
111
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
112
                   int hfindex, uint16_t *pdata)
113
0
{
114
    /* Some callers expect us to initialize pdata, even in error conditions, so
115
     * do it right away in case we forget later */
116
0
    if (pdata)
117
0
        *pdata = 0;
118
119
0
    if (di->conformant_run) {
120
        /* just a run to handle conformant arrays, no scalars to dissect */
121
0
        return offset;
122
0
    }
123
124
125
0
    if (!di->no_align) {
126
0
        offset = WS_ROUNDUP_2(offset);
127
0
    }
128
0
    return dissect_dcerpc_uint16(tvb, offset, pinfo,
129
0
                                 tree, drep, hfindex, pdata);
130
0
}
131
132
int
133
PIDL_dissect_uint16_val(tvbuff_t *tvb, int offset, packet_info *pinfo,
134
                        proto_tree *tree, dcerpc_info *di, uint8_t *drep,
135
                        int hfindex, uint32_t param, uint16_t *pval)
136
0
{
137
0
    uint16_t     val;
138
139
0
    if (di->conformant_run) {
140
        /* just a run to handle conformant arrays, no scalars to dissect */
141
0
        return offset;
142
0
    }
143
144
145
0
    if (!di->no_align) {
146
0
        offset = WS_ROUNDUP_2(offset);
147
0
    }
148
0
    offset = dissect_dcerpc_uint16(tvb, offset, pinfo,
149
0
                                   tree, drep, hfindex, &val);
150
151
0
    if (param&PIDL_SET_COL_INFO) {
152
0
        header_field_info *hf_info;
153
0
        char *valstr;
154
155
0
        hf_info = proto_registrar_get_nth(hfindex);
156
157
0
        valstr = (char *)wmem_alloc(pinfo->pool, 64);
158
0
        valstr[0]=0;
159
160
0
        switch (hf_info->display) {
161
0
        case BASE_DEC:
162
0
            if (hf_info->strings) {
163
0
                snprintf(valstr, 64, "%s(%d)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
164
0
            } else {
165
0
                snprintf(valstr, 64, "%d", val);
166
0
            }
167
0
            break;
168
0
        case BASE_HEX:
169
0
            if (hf_info->strings) {
170
0
                snprintf(valstr, 64, "%s(0x%04x)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
171
0
            } else {
172
0
                snprintf(valstr, 64, "0x%04x", val);
173
0
            }
174
0
            break;
175
0
        default:
176
0
            REPORT_DISSECTOR_BUG("Invalid hf->display value");
177
0
        }
178
179
0
        col_append_fstr(pinfo->cinfo, COL_INFO," %s:%s", hf_info->name, valstr);
180
0
    }
181
182
0
    if (pval) {
183
0
        *pval = val;
184
0
    }
185
0
    return offset;
186
0
}
187
188
int
189
PIDL_dissect_uint16(tvbuff_t *tvb, int offset, packet_info *pinfo,
190
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
191
                    int hfindex, uint32_t param)
192
0
{
193
0
    return PIDL_dissect_uint16_val(tvb, offset, pinfo, tree, di, drep, hfindex, param, NULL);
194
0
}
195
196
int
197
dissect_ndr_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
198
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
199
                   int hfindex, uint32_t *pdata)
200
0
{
201
    /* Some callers expect us to initialize pdata, even in error conditions, so
202
     * do it right away in case we forget later */
203
0
    if (pdata)
204
0
        *pdata = 0;
205
206
0
    if ((di != NULL) && (di->conformant_run)) {
207
        /* just a run to handle conformant arrays, no scalars to dissect */
208
0
        return offset;
209
0
    }
210
211
212
0
    if ((di != NULL) && (!di->no_align)) {
213
0
        offset = WS_ROUNDUP_4(offset);
214
0
    }
215
0
    return dissect_dcerpc_uint32(tvb, offset, pinfo,
216
0
                                 tree, drep, hfindex, pdata);
217
0
}
218
219
/* This is used to dissect the new datatypes, such as pointers and conformance
220
   data, which is 4 bytes in size in NDR but 8 bytes in NDR64.
221
*/
222
int
223
dissect_ndr_uint3264(tvbuff_t *tvb, int offset, packet_info *pinfo,
224
                     proto_tree *tree, dcerpc_info *di, uint8_t *drep,
225
                     int hfindex, uint3264_t *pdata)
226
0
{
227
0
    if (di->call_data->flags & DCERPC_IS_NDR64) {
228
0
        return dissect_ndr_uint64(tvb, offset, pinfo, tree, di, drep, hfindex, pdata);
229
0
    } else {
230
0
        uint32_t val = 0;
231
0
        offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hfindex, &val);
232
0
        if (pdata) {
233
0
            *pdata = val;
234
0
        }
235
0
        return offset;
236
0
    }
237
0
}
238
239
/* This is used to dissect the new datatypes, such as enums
240
   that are 2 bytes in size in NDR but 4 bytes in NDR64.
241
*/
242
int
243
dissect_ndr_uint1632(tvbuff_t *tvb, int offset, packet_info *pinfo,
244
                     proto_tree *tree, dcerpc_info *di, uint8_t *drep,
245
                     int hfindex, uint1632_t *pdata)
246
0
{
247
0
    if (di->call_data->flags & DCERPC_IS_NDR64) {
248
0
        return dissect_ndr_uint32(tvb, offset, pinfo, tree, di, drep, hfindex, pdata);
249
0
    } else {
250
0
        uint16_t val = 0;
251
0
        offset = dissect_ndr_uint16(tvb, offset, pinfo, tree, di, drep, hfindex, &val);
252
0
        if (pdata) {
253
0
            *pdata = val;
254
0
        }
255
0
        return offset;
256
0
    }
257
0
}
258
259
int
260
PIDL_dissect_uint32_val(tvbuff_t *tvb, int offset, packet_info *pinfo,
261
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
262
                    int hfindex, uint32_t param, uint32_t *rval)
263
0
{
264
0
    uint32_t     val;
265
266
0
    if (di->conformant_run) {
267
        /* just a run to handle conformant arrays, no scalars to dissect */
268
0
        return offset;
269
0
    }
270
271
272
0
    if (!di->no_align) {
273
0
        offset = WS_ROUNDUP_4(offset);
274
0
    }
275
0
    offset = dissect_dcerpc_uint32(tvb, offset, pinfo,
276
0
                                   tree, drep, hfindex, &val);
277
278
0
    if (param&PIDL_SET_COL_INFO) {
279
0
        header_field_info *hf_info;
280
0
        char *valstr;
281
282
0
        hf_info = proto_registrar_get_nth(hfindex);
283
284
0
        valstr = (char *)wmem_alloc(pinfo->pool, 64);
285
0
        valstr[0]=0;
286
287
0
        switch (hf_info->display) {
288
0
        case BASE_DEC:
289
0
            if (hf_info->strings) {
290
0
                snprintf(valstr, 64, "%s(%d)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
291
0
            } else {
292
0
                snprintf(valstr, 64, "%d", val);
293
0
            }
294
0
            break;
295
0
        case BASE_HEX:
296
0
            if (hf_info->strings) {
297
0
                snprintf(valstr, 64, "%s(0x%08x)",val_to_str(val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
298
0
            } else {
299
0
                snprintf(valstr, 64, "0x%08x", val);
300
0
            }
301
0
            break;
302
0
        default:
303
0
            REPORT_DISSECTOR_BUG("Invalid hf->display value");
304
0
        }
305
306
0
        col_append_fstr(pinfo->cinfo, COL_INFO," %s:%s", hf_info->name, valstr);
307
0
    }
308
0
    if (rval != NULL) {
309
0
        *rval = val;
310
0
    }
311
0
    return offset;
312
0
}
313
314
int
315
PIDL_dissect_uint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
316
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
317
                    int hfindex, uint32_t param)
318
0
{
319
0
    return PIDL_dissect_uint32_val(tvb, offset, pinfo, tree, di, drep, hfindex, param, NULL);
320
0
}
321
322
/* Double uint32
323
   This function dissects the 64bit datatype that is common for
324
   ms interfaces and which is 32bit aligned.
325
   It is really just 2 uint32's
326
*/
327
int
328
dissect_ndr_duint32(tvbuff_t *tvb, int offset, packet_info *pinfo,
329
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
330
                    int hfindex, uint64_t *pdata)
331
0
{
332
    /* Some callers expect us to initialize pdata, even in error conditions, so
333
     * do it right away in case we forget later */
334
0
    if (pdata)
335
0
        *pdata = 0;
336
337
0
    if (di->conformant_run) {
338
        /* just a run to handle conformant arrays, no scalars to dissect */
339
0
        return offset;
340
0
    }
341
342
0
    if (!di->no_align) {
343
0
        offset = WS_ROUNDUP_4(offset);
344
0
    }
345
0
    return dissect_dcerpc_uint64(tvb, offset, pinfo,
346
0
                                 tree, di, drep, hfindex, pdata);
347
0
}
348
349
/* uint64 : hyper
350
   a 64 bit integer  aligned to proper 8 byte boundaries
351
*/
352
int
353
dissect_ndr_uint64(tvbuff_t *tvb, int offset, packet_info *pinfo,
354
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
355
                   int hfindex, uint64_t *pdata)
356
0
{
357
    /* Some callers expect us to initialize pdata, even in error conditions, so
358
     * do it right away in case we forget later */
359
0
    if (pdata)
360
0
        *pdata = 0;
361
362
0
    if (di->conformant_run) {
363
        /* just a run to handle conformant arrays, no scalars to dissect */
364
0
        return offset;
365
0
    }
366
367
0
    if (!di->no_align) {
368
0
        unsigned padding = WS_PADDING_TO_8(offset);
369
0
        if (padding != 0) {
370
0
            proto_tree_add_item(tree, hf_dcerpc_ndr_padding, tvb, offset, padding, ENC_NA);
371
0
            offset += padding;
372
0
        }
373
0
    }
374
0
    return dissect_dcerpc_uint64(tvb, offset, pinfo,
375
0
                                 tree, di, drep, hfindex, pdata);
376
0
}
377
378
int
379
PIDL_dissect_uint64_val(tvbuff_t *tvb, int offset, packet_info *pinfo,
380
                        proto_tree *tree, dcerpc_info *di, uint8_t *drep,
381
                        int hfindex, uint32_t param, uint64_t *pval)
382
0
{
383
0
    uint64_t     val;
384
385
0
    if (di->conformant_run) {
386
        /* just a run to handle conformant arrays, no scalars to dissect */
387
0
        return offset;
388
0
    }
389
390
0
    if (!di->no_align) {
391
0
        offset = WS_ROUNDUP_8(offset);
392
0
    }
393
0
    offset = dissect_dcerpc_uint64(tvb, offset, pinfo,
394
0
                                   tree, di, drep, hfindex, &val);
395
396
0
    if (param&PIDL_SET_COL_INFO) {
397
0
        header_field_info *hf_info;
398
0
        char *valstr;
399
400
0
        hf_info = proto_registrar_get_nth(hfindex);
401
402
0
        valstr = (char *)wmem_alloc(pinfo->pool, 64);
403
0
        valstr[0]=0;
404
405
0
        switch (hf_info->display) {
406
0
        case BASE_DEC:
407
0
            if (hf_info->strings) {
408
0
                snprintf(valstr, 64, "%s(%" PRIu64 ")",val_to_str( (uint32_t) val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
409
0
            } else {
410
0
                snprintf(valstr, 64, "%" PRIu64, val);
411
0
            }
412
0
            break;
413
0
        case BASE_HEX:
414
0
            if (hf_info->strings) {
415
0
                snprintf(valstr, 64, "%s(0x%" PRIx64 ")",val_to_str( (uint32_t) val, (const value_string *)hf_info->strings, "Unknown:%u"), val);
416
0
            } else {
417
0
                snprintf(valstr, 64, "0x%" PRIx64, val);
418
0
            }
419
0
            break;
420
0
        default:
421
0
            REPORT_DISSECTOR_BUG("Invalid hf->display value");
422
0
        }
423
424
0
        col_append_fstr(pinfo->cinfo, COL_INFO," %s:%s", hf_info->name, valstr);
425
0
    }
426
427
0
    if (pval) {
428
0
        *pval = val;
429
0
    }
430
0
    return offset;
431
0
}
432
433
int
434
PIDL_dissect_uint64(tvbuff_t *tvb, int offset, packet_info *pinfo,
435
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
436
                    int hfindex, uint32_t param)
437
0
{
438
0
    return PIDL_dissect_uint64_val(tvb, offset, pinfo, tree, di, drep, hfindex, param, NULL);
439
0
}
440
441
int
442
dissect_ndr_float(tvbuff_t *tvb, int offset, packet_info *pinfo,
443
                  proto_tree *tree, dcerpc_info *di, uint8_t *drep,
444
                  int hfindex, float *pdata)
445
0
{
446
    /* Some callers expect us to initialize pdata, even in error conditions, so
447
     * do it right away in case we forget later */
448
0
    if (pdata)
449
0
        *pdata = 0;
450
451
452
0
    if (di->conformant_run) {
453
        /* just a run to handle conformant arrays, no scalars to dissect */
454
0
        return offset;
455
0
    }
456
457
0
    if (!di->no_align) {
458
0
        offset = WS_ROUNDUP_4(offset);
459
0
    }
460
0
    return dissect_dcerpc_float(tvb, offset, pinfo,
461
0
                                tree, drep, hfindex, pdata);
462
0
}
463
464
465
int
466
dissect_ndr_double(tvbuff_t *tvb, int offset, packet_info *pinfo,
467
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
468
                   int hfindex, double *pdata)
469
0
{
470
    /* Some callers expect us to initialize pdata, even in error conditions, so
471
     * do it right away in case we forget later */
472
0
    if (pdata)
473
0
        *pdata = 0;
474
475
0
    if (di->conformant_run) {
476
        /* just a run to handle conformant arrays, no scalars to dissect */
477
0
        return offset;
478
0
    }
479
480
0
    if (!di->no_align) {
481
0
        offset = WS_ROUNDUP_8(offset);
482
0
    }
483
0
    return dissect_dcerpc_double(tvb, offset, pinfo,
484
0
                                 tree, drep, hfindex, pdata);
485
0
}
486
487
/* handles unix 32 bit time_t */
488
int
489
dissect_ndr_time_t(tvbuff_t *tvb, int offset, packet_info *pinfo,
490
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
491
                   int hfindex, uint32_t *pdata)
492
0
{
493
    /* Some callers expect us to initialize pdata, even in error conditions, so
494
     * do it right away in case we forget later */
495
0
    if (pdata)
496
0
        *pdata = 0;
497
498
0
    if (di->conformant_run) {
499
        /* just a run to handle conformant arrays, no scalars to dissect */
500
0
        return offset;
501
0
    }
502
503
504
0
    if (!di->no_align) {
505
0
        offset = WS_ROUNDUP_4(offset);
506
0
    }
507
0
    return dissect_dcerpc_time_t(tvb, offset, pinfo,
508
0
                                 tree, drep, hfindex, pdata);
509
0
}
510
511
int
512
dissect_ndr_uuid_t(tvbuff_t *tvb, int offset, packet_info *pinfo,
513
                   proto_tree *tree, dcerpc_info *di, uint8_t *drep,
514
                   int hfindex, e_guid_t *pdata)
515
0
{
516
    /* Some callers expect us to initialize pdata, even in error conditions, so
517
     * do it right away in case we forget later */
518
0
    if (pdata)
519
0
        memset(pdata, 0, sizeof(*pdata));
520
521
0
    if (di->conformant_run) {
522
        /* just a run to handle conformant arrays, no scalars to dissect */
523
0
        return offset;
524
0
    }
525
526
    /* uuid's are aligned to 4 bytes, due to initial uint32 in struct */
527
0
    if (!di->no_align) {
528
0
        offset = WS_ROUNDUP_4(offset);
529
0
    }
530
0
    return dissect_dcerpc_uuid_t(tvb, offset, pinfo,
531
0
                                 tree, drep, hfindex, pdata);
532
0
}
533
534
/*
535
 * XXX - at least according to the DCE RPC 1.1 "nbase.idl", an
536
 * "ndr_context_handle" is an unsigned32 "context_handle_attributes"
537
 * and a uuid_t "context_handle_uuid".  The attributes do not appear to
538
 * be used, and always appear to be set to 0, in the DCE RPC 1.1 code.
539
 *
540
 * Should we display an "ndr_context_handle" with a tree holding the
541
 * attributes and the uuid_t?
542
 */
543
int
544
dissect_ndr_ctx_hnd(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
545
                    proto_tree *tree, dcerpc_info *di, uint8_t *drep,
546
                    int hfindex, e_ctx_hnd *pdata)
547
0
{
548
0
    static e_ctx_hnd ctx_hnd;
549
550
0
    if (di->conformant_run) {
551
        /* just a run to handle conformant arrays, no scalars to dissect */
552
0
        return offset;
553
0
    }
554
555
0
    if (!di->no_align) {
556
0
        offset = WS_ROUNDUP_4(offset);
557
0
    }
558
0
    ctx_hnd.attributes = dcerpc_tvb_get_ntohl(tvb, offset, drep);
559
0
    dcerpc_tvb_get_uuid(tvb, offset+4, drep, &ctx_hnd.uuid);
560
0
    if (tree) {
561
        /* Bytes is bytes - don't worry about the data representation */
562
0
        proto_tree_add_item(tree, hfindex, tvb, offset, 20, ENC_NA);
563
0
    }
564
0
    if (pdata) {
565
0
        *pdata = ctx_hnd;
566
0
    }
567
0
    return offset + 20;
568
0
}
569
570
/*
571
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
572
 *
573
 * Local variables:
574
 * c-basic-offset: 4
575
 * tab-width: 8
576
 * indent-tabs-mode: nil
577
 * End:
578
 *
579
 * vi: set shiftwidth=4 tabstop=8 expandtab:
580
 * :indentSize=4:tabSize=8:noTabs=true:
581
 */