FreeRDP
Loading...
Searching...
No Matches
ndr.c
1
19#include <stddef.h>
20
21#include <winpr/assert.h>
22#include <winpr/collections.h>
23#include <winpr/interlocked.h>
24#include <winpr/wlog.h>
25#include <winpr/string.h>
26#include <winpr/ndr.h>
27
28#include "../log.h"
29
30#define TAG WINPR_TAG("ndr")
31
32#define NDR_MAX_DEFERRED 128
33
45typedef struct
46{
47 size_t nstack;
48 WinPrNdrDeferredEntry stack[NDR_MAX_DEFERRED];
49
50 size_t depth;
51 size_t nblock;
52 WinPrNdrDeferredEntry block[NDR_MAX_DEFERRED];
53} NdrDeferreds;
54
55struct WinPrNdrEncoder_s
56{
57 BYTE version;
58 BOOL bigEndianDrep;
59
60 size_t offset;
61 BOOL inObject;
62 size_t objectStart;
64 UINT32 refIdCounter;
65 NdrDeferreds deferreds;
66};
67
68struct WinPrNdrDecoder_s
69{
70 BYTE version;
71 BOOL bigEndianDrep;
72
73 size_t offset;
75 wHashTable* referents;
76 NdrDeferreds deferreds;
77};
78
79#define NDR_REFERENT_MAGIC 0x46455244 /* "DREF" */
80
86typedef struct
87{
88 UINT32 magic;
89 winpr_ndr_refid refId;
90 BOOL full;
91 volatile LONG refCount;
92 WinPrNdrMessageType typeDescr;
93 size_t size;
94 BOOL hasHints;
95 union
96 {
99 } hints;
100 union
101 {
102 /* max_align_t is not available with all the compilers (MSVC C) */
103 UINT64 u64;
104 double d;
105 long double ld;
106 void* ptr;
107 BYTE data[1];
108 } payload;
109} NdrReferent;
110
111static NdrReferent* ndr_referent(void* ptr)
112{
113 WINPR_ASSERT(ptr);
114
115 /* computed on the address: the referent header precedes the payload */
116 NdrReferent* ref = (NdrReferent*)((uintptr_t)ptr - offsetof(NdrReferent, payload));
117 WINPR_ASSERT(ref->magic == NDR_REFERENT_MAGIC);
118 return ref;
119}
120
121static void ndr_deferreds_enter(NdrDeferreds* d)
122{
123 WINPR_ASSERT(d);
124 d->depth++;
125}
126
127static BOOL ndr_deferreds_add(NdrDeferreds* d, const WinPrNdrDeferredEntry* entry)
128{
129 WINPR_ASSERT(d);
130 WINPR_ASSERT(d->depth);
131 WINPR_ASSERT(entry);
132
133 if (d->nblock == NDR_MAX_DEFERRED)
134 {
135 WLog_ERR(TAG, "too many deferred pointers when adding %s", entry->name);
136 return FALSE;
137 }
138
139 d->block[d->nblock++] = *entry;
140 return TRUE;
141}
142
143static BOOL ndr_deferreds_leave(NdrDeferreds* d, BOOL success)
144{
145 WINPR_ASSERT(d);
146 WINPR_ASSERT(d->depth);
147
148 d->depth--;
149 if (d->depth)
150 return success;
151
152 const size_t nblock = d->nblock;
153 d->nblock = 0;
154 if (!success)
155 return FALSE;
156
157 if (d->nstack + nblock > NDR_MAX_DEFERRED)
158 {
159 WLog_ERR(TAG, "too many deferred pointers");
160 return FALSE;
161 }
162
163 for (size_t i = nblock; i > 0; i--)
164 d->stack[d->nstack++] = d->block[i - 1];
165 return TRUE;
166}
167
168static BOOL ndr_deferreds_pop(NdrDeferreds* d, WinPrNdrDeferredEntry* entry)
169{
170 WINPR_ASSERT(d);
171 WINPR_ASSERT(entry);
172
173 if (!d->nstack)
174 return FALSE;
175
176 d->nstack--;
177 *entry = d->stack[d->nstack];
178 return TRUE;
179}
180
182static void* ndr_field_hints(const WinPrNdrStructDescr* descr, const WinPrNdrFieldStruct* field,
183 const void* obj)
184{
185 if (field->hintsField < 0)
186 return nullptr;
187
188 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
189 const WinPrNdrFieldStruct* hintsField = &descr->fields[field->hintsField];
190 const BYTE* hints = (const BYTE*)obj + hintsField->structOffset;
191 return WINPR_CAST_CONST_PTR_AWAY(hints, void*);
192}
193
194WinPrNdrEncoder* winpr_ndr_encoder_new(BOOL bigEndianDrep, BYTE version)
195{
196 WinPrNdrEncoder* ret = calloc(1, sizeof(*ret));
197 if (!ret)
198 return nullptr;
199
200 ret->version = version;
201 ret->bigEndianDrep = bigEndianDrep;
202 ret->refIdCounter = 0x20000;
203 return ret;
204}
205
206WinPrNdrEncoder* winpr_ndr_encoder_from_decoder(const WinPrNdrDecoder* src)
207{
208 WINPR_ASSERT(src);
209
210 return winpr_ndr_encoder_new(src->bigEndianDrep, src->version);
211}
212
213void winpr_ndr_encoder_free(WinPrNdrEncoder* context)
214{
215 free(context);
216}
217
218void winpr_ndr_encoder_bytes_written(WinPrNdrEncoder* context, size_t len)
219{
220 WINPR_ASSERT(context);
221 context->offset += len;
222}
223
224BOOL winpr_ndr_encoder_write_header(WinPrNdrEncoder* context, wStream* s)
225{
226 WINPR_ASSERT(context);
227
228 if (!Stream_EnsureRemainingCapacity(s, 8))
229 return FALSE;
230
231 Stream_Write_UINT8(s, context->version);
232 Stream_Write_UINT8(s, context->bigEndianDrep ? 0x00 : 0x10);
233 Stream_Write_UINT16(s, 0x8); /* header len */
234
235 BYTE filler[] = { 0xcc, 0xcc, 0xcc, 0xcc };
236 Stream_Write(s, filler, sizeof(filler));
237 return TRUE;
238}
239
240BOOL winpr_ndr_encoder_write_align(WinPrNdrEncoder* context, wStream* s, size_t sz)
241{
242 WINPR_ASSERT(context);
243
244 size_t rest = context->offset % sz;
245 if (rest)
246 {
247 size_t padding = (sz - rest);
248
249 if (!Stream_EnsureRemainingCapacity(s, padding))
250 return FALSE;
251
252 Stream_Zero(s, padding);
253 context->offset += padding;
254 }
255
256 return TRUE;
257}
258
259BOOL winpr_ndr_encoder_start_object(WinPrNdrEncoder* context, wStream* s)
260{
261 WINPR_ASSERT(context);
262 WINPR_ASSERT(s);
263
264 if (context->inObject)
265 {
266 WLog_ERR(TAG, "an object is already being serialized");
267 return FALSE;
268 }
269
270 if (!Stream_EnsureRemainingCapacity(s, 8))
271 return FALSE;
272
273 /* ObjectBufferLength, filled by winpr_ndr_encoder_end_object, and Filler */
274 context->objectStart = Stream_GetPosition(s);
275 Stream_Zero(s, 8);
276
277 context->inObject = TRUE;
278 context->offset = 0;
279 return TRUE;
280}
281
282BOOL winpr_ndr_encoder_end_object(WinPrNdrEncoder* context, wStream* s)
283{
284 WINPR_ASSERT(context);
285 WINPR_ASSERT(s);
286
287 if (!context->inObject)
288 {
289 WLog_ERR(TAG, "no object being serialized");
290 return FALSE;
291 }
292
293 const size_t start = context->objectStart + 8;
294 WINPR_ASSERT(Stream_GetPosition(s) >= start);
295
296 /* the length of the object buffer must be a multiple of 8 */
297 const size_t padding = (8 - ((Stream_GetPosition(s) - start) % 8)) % 8;
298 if (!Stream_EnsureRemainingCapacity(s, padding))
299 return FALSE;
300 Stream_Zero(s, padding);
301 context->offset += padding;
302
303 const size_t len = Stream_GetPosition(s) - start;
304 if (len > UINT32_MAX)
305 return FALSE;
306
307 BYTE* header = Stream_Buffer(s) + context->objectStart;
308 if (context->bigEndianDrep)
309 winpr_Data_Write_UINT32_BE(header, (UINT32)len);
310 else
311 winpr_Data_Write_UINT32(header, (UINT32)len);
312
313 context->inObject = FALSE;
314 return TRUE;
315}
316
317BOOL winpr_ndr_encoder_write_toplevel_refid(WinPrNdrEncoder* context, wStream* s)
318{
319 WINPR_ASSERT(context);
320
321 const winpr_ndr_refid refId = context->refIdCounter;
322 context->refIdCounter += 4;
323 return winpr_ndr_encoder_write_uint32(context, s, refId);
324}
325
326static size_t ndr_hintsCount(WinPrNdrMessageType msgType, const void* hints)
327{
328 WINPR_ASSERT(msgType);
329
330 switch (msgType->arity)
331 {
333 return 1;
335 WINPR_ASSERT(hints);
336 return ((const WinPrNdrArrayHints*)hints)->count;
338 WINPR_ASSERT(hints);
339 return ((const WinPrNdrVaryingArrayHints*)hints)->maxLength;
341 return 1;
342 default:
343 WINPR_ASSERT(0 && "unknown arity");
344 return 0;
345 }
346}
347
349static BOOL ndr_check_fixed_array(const WinPrNdrStructDescr* descr,
350 const WinPrNdrFieldStruct* field, const void* hints)
351{
352 if (!hints || !field->fixedArraySize)
353 {
354 WLog_ERR(TAG, "%s.%s: fixed array without hints or size", descr->name, field->name);
355 return FALSE;
356 }
357
358 const UINT64 needed =
359 1ull * ndr_hintsCount(field->typeDescr, hints) * field->typeDescr->itemSize;
360 if (needed > field->fixedArraySize)
361 {
362 WLog_ERR(TAG, "%s.%s: %" PRIu64 " bytes don't fit in a fixed array of %" PRIuz " bytes",
363 descr->name, field->name, needed, field->fixedArraySize);
364 return FALSE;
365 }
366 return TRUE;
367}
368
370static BOOL ndr_check_range(const WinPrNdrStructDescr* descr, const WinPrNdrFieldStruct* field,
371 const void* ptr)
372{
373 if (!field->rangeMax)
374 return TRUE;
375
376 UINT64 v = 0;
377 switch (field->typeDescr->itemSize)
378 {
379 case 1:
380 v = *(const UINT8*)ptr;
381 break;
382 case 2:
383 {
384 UINT16 v16 = 0;
385 memcpy(&v16, ptr, sizeof(v16));
386 v = v16;
387 }
388 break;
389 case 4:
390 {
391 UINT32 v32 = 0;
392 memcpy(&v32, ptr, sizeof(v32));
393 v = v32;
394 }
395 break;
396 case 8:
397 memcpy(&v, ptr, sizeof(v));
398 break;
399 default:
400 WLog_ERR(TAG, "%s.%s: range on a field of %" PRIuz " bytes", descr->name, field->name,
401 field->typeDescr->itemSize);
402 return FALSE;
403 }
404
405 if (v > field->rangeMax)
406 {
407 WLog_ERR(TAG, "%s.%s: %" PRIu64 " is out of range(0, %" PRIu32 ")", descr->name,
408 field->name, v, field->rangeMax);
409 return FALSE;
410 }
411 return TRUE;
412}
413
415static size_t ndr_inline_count(const WinPrNdrFieldStruct* field)
416{
417 WINPR_ASSERT(field->typeDescr->itemSize);
418 return field->fixedArraySize / field->typeDescr->itemSize;
419}
420
421BOOL winpr_ndr_encoder_write_uint8(WinPrNdrEncoder* context, wStream* s, BYTE v)
422{
423 if (!Stream_EnsureRemainingCapacity(s, 1))
424 return FALSE;
425
426 Stream_Write_UINT8(s, v);
428 return TRUE;
429}
430
431BOOL winpr_ndr_encoder_write_uint8_(WinPrNdrEncoder* context, wStream* s, const void* hints,
432 const void* v)
433{
434 WINPR_ASSERT(context);
435 WINPR_ASSERT(s);
436 WINPR_ASSERT(v);
437 WINPR_UNUSED(hints);
438
439 return winpr_ndr_encoder_write_uint8(context, s, *(const BYTE*)v);
440}
441
442const WinPrNdrMessageDescr winpr_ndr_uint8_descr_s = {
443 WINPR_NDR_ARITY_SIMPLE, 1, winpr_ndr_decoder_read_uint8_,
444 winpr_ndr_encoder_write_uint8_, nullptr, nullptr
445};
446
447WinPrNdrMessageType winpr_ndr_uint8_descr(void)
448{
449 return &winpr_ndr_uint8_descr_s;
450}
451
452BOOL winpr_ndr_encoder_write_int8(WinPrNdrEncoder* context, wStream* s, INT8 v)
453{
454 return winpr_ndr_encoder_write_uint8(context, s, (BYTE)v);
455}
456
457BOOL winpr_ndr_encoder_write_int8_(WinPrNdrEncoder* context, wStream* s, const void* hints,
458 const void* v)
459{
460 WINPR_ASSERT(context);
461 WINPR_ASSERT(s);
462 WINPR_ASSERT(v);
463 WINPR_UNUSED(hints);
464
465 return winpr_ndr_encoder_write_int8(context, s, *(const INT8*)v);
466}
467
468const WinPrNdrMessageDescr winpr_ndr_int8_descr_s = {
469 WINPR_NDR_ARITY_SIMPLE, 1, winpr_ndr_decoder_read_int8_,
470 winpr_ndr_encoder_write_int8_, nullptr, nullptr
471};
472
473WinPrNdrMessageType winpr_ndr_int8_descr(void)
474{
475 return &winpr_ndr_int8_descr_s;
476}
477
478#define SIMPLE_TYPE_IMPL(PREFIX, UPPERTYPE, LOWERTYPE) \
479 BOOL PREFIX##_decoder_read_##LOWERTYPE(WinPrNdrDecoder* context, wStream* s, UPPERTYPE* v) \
480 { \
481 WINPR_ASSERT(context); \
482 \
483 if (!winpr_ndr_decoder_read_align(context, s, sizeof(UPPERTYPE))) \
484 return FALSE; \
485 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(UPPERTYPE))) \
486 return FALSE; \
487 \
488 if (context->bigEndianDrep) \
489 Stream_Read_##UPPERTYPE##_BE(s, *v); \
490 else \
491 Stream_Read_##UPPERTYPE(s, *v); \
492 \
493 winpr_ndr_decoder_bytes_read(context, sizeof(UPPERTYPE)); \
494 return TRUE; \
495 } \
496 \
497 BOOL PREFIX##_decoder_read_##LOWERTYPE##_(WinPrNdrDecoder* context, wStream* s, \
498 const void* hints, void* v) \
499 { \
500 WINPR_UNUSED(hints); \
501 return PREFIX##_decoder_read_##LOWERTYPE(context, s, (UPPERTYPE*)v); \
502 } \
503 \
504 BOOL PREFIX##_encoder_write_##LOWERTYPE(WinPrNdrEncoder* context, wStream* s, UPPERTYPE v) \
505 { \
506 if (!winpr_ndr_encoder_write_align(context, s, sizeof(UPPERTYPE)) || \
507 !Stream_EnsureRemainingCapacity(s, sizeof(UPPERTYPE))) \
508 return FALSE; \
509 \
510 if (context->bigEndianDrep) \
511 Stream_Write_##UPPERTYPE##_BE(s, v); \
512 else \
513 Stream_Write_##UPPERTYPE(s, v); \
514 \
515 winpr_ndr_encoder_bytes_written(context, sizeof(UPPERTYPE)); \
516 return TRUE; \
517 } \
518 \
519 BOOL PREFIX##_encoder_write_##LOWERTYPE##_(WinPrNdrEncoder* context, wStream* s, \
520 const void* hints, const void* v) \
521 { \
522 WINPR_ASSERT(context); \
523 WINPR_ASSERT(s); \
524 WINPR_ASSERT(v); \
525 WINPR_UNUSED(hints); \
526 \
527 return PREFIX##_encoder_write_##LOWERTYPE(context, s, *(const UPPERTYPE*)v); \
528 } \
529 \
530 const WinPrNdrMessageDescr PREFIX##_##LOWERTYPE##_descr_s = { \
531 WINPR_NDR_ARITY_SIMPLE, \
532 sizeof(UPPERTYPE), \
533 PREFIX##_decoder_read_##LOWERTYPE##_, \
534 PREFIX##_encoder_write_##LOWERTYPE##_, \
535 nullptr, \
536 nullptr \
537 }; \
538 \
539 WinPrNdrMessageType PREFIX##_##LOWERTYPE##_descr(void) \
540 { \
541 return &PREFIX##_##LOWERTYPE##_descr_s; \
542 }
543
544SIMPLE_TYPE_IMPL(winpr_ndr, UINT32, uint32)
545SIMPLE_TYPE_IMPL(winpr_ndr, INT32, int32)
546SIMPLE_TYPE_IMPL(winpr_ndr, UINT16, uint16)
547SIMPLE_TYPE_IMPL(winpr_ndr, INT16, int16)
548SIMPLE_TYPE_IMPL(winpr_ndr, UINT64, uint64)
549SIMPLE_TYPE_IMPL(winpr_ndr, INT64, int64)
550
551#define ARRAY_OF_TYPE_IMPL(TYPE, UPPERTYPE) \
552 BOOL winpr_ndr_decoder_read_##TYPE##Array(WinPrNdrDecoder* context, wStream* s, \
553 const void* hints, void* v) \
554 { \
555 WINPR_ASSERT(context); \
556 WINPR_ASSERT(s); \
557 return winpr_ndr_decoder_read_uconformant_array(context, s, hints, \
558 winpr_ndr_##TYPE##_descr(), v); \
559 } \
560 \
561 BOOL winpr_ndr_encoder_write_##TYPE##Array(WinPrNdrEncoder* context, wStream* s, \
562 const void* hints, const void* v) \
563 { \
564 WINPR_ASSERT(context); \
565 WINPR_ASSERT(s); \
566 const WinPrNdrArrayHints* ahints = (const WinPrNdrArrayHints*)hints; \
567 return winpr_ndr_encoder_write_uconformant_array(context, s, ahints->count, \
568 winpr_ndr_##TYPE##_descr(), v); \
569 } \
570 void winpr_ndr_destroy_##TYPE##Array(const void* hints, void* obj) \
571 { \
572 WINPR_ASSERT(obj); \
573 WINPR_ASSERT(hints); \
574 const WinPrNdrArrayHints* ahints = (const WinPrNdrArrayHints*)hints; \
575 WinPrNdrMessageType descr = winpr_ndr_##TYPE##_descr(); \
576 if (descr->destroyFn) \
577 { \
578 UPPERTYPE* ptr = (UPPERTYPE*)obj; \
579 for (UINT32 i = 0; i < ahints->count; i++, ptr++) \
580 descr->destroyFn(nullptr, ptr); \
581 } \
582 } \
583 \
584 const WinPrNdrMessageDescr winpr_ndr_##TYPE##Array_descr_s = { \
585 WINPR_NDR_ARITY_ARRAYOF, \
586 sizeof(UPPERTYPE), \
587 winpr_ndr_decoder_read_##TYPE##Array, \
588 winpr_ndr_encoder_write_##TYPE##Array, \
589 winpr_ndr_destroy_##TYPE##Array, \
590 nullptr \
591 }; \
592 \
593 WinPrNdrMessageType winpr_ndr_##TYPE##Array_descr(void) \
594 { \
595 return &winpr_ndr_##TYPE##Array_descr_s; \
596 } \
597 \
598 BOOL winpr_ndr_decoder_read_##TYPE##VaryingArray(WinPrNdrDecoder* context, wStream* s, \
599 const void* hints, void* v) \
600 { \
601 WINPR_ASSERT(context); \
602 WINPR_ASSERT(s); \
603 return winpr_ndr_decoder_read_uconformant_varying_array( \
604 context, s, (const WinPrNdrVaryingArrayHints*)hints, winpr_ndr_##TYPE##_descr(), v); \
605 } \
606 BOOL winpr_ndr_encoder_write_##TYPE##VaryingArray(WinPrNdrEncoder* context, wStream* s, \
607 const void* hints, const void* v) \
608 { \
609 WINPR_ASSERT(context); \
610 WINPR_ASSERT(s); \
611 return winpr_ndr_encoder_write_uconformant_varying_array( \
612 context, s, (const WinPrNdrVaryingArrayHints*)hints, winpr_ndr_##TYPE##_descr(), v); \
613 } \
614 \
615 const WinPrNdrMessageDescr winpr_ndr_##TYPE##VaryingArray_descr_s = { \
616 WINPR_NDR_ARITY_VARYING_ARRAYOF, \
617 sizeof(UPPERTYPE), \
618 winpr_ndr_decoder_read_##TYPE##VaryingArray, \
619 winpr_ndr_encoder_write_##TYPE##VaryingArray, \
620 nullptr, \
621 nullptr \
622 }; \
623 \
624 WinPrNdrMessageType winpr_ndr_##TYPE##VaryingArray_descr(void) \
625 { \
626 return &winpr_ndr_##TYPE##VaryingArray_descr_s; \
627 }
628
629/* WinPR WCHAR strings are UTF-16LE whatever the byte order of the host, the characters are
630 * stored that way and not as host UINT16 */
631BOOL winpr_ndr_decoder_read_wchar(WinPrNdrDecoder* context, wStream* s, WCHAR* ptr)
632{
633 WINPR_ASSERT(ptr);
634
635 UINT16 v = 0;
636 if (!winpr_ndr_decoder_read_uint16(context, s, &v))
637 return FALSE;
638
639 winpr_Data_Write_UINT16(ptr, v);
640 return TRUE;
641}
642
643BOOL winpr_ndr_encoder_write_wchar(WinPrNdrEncoder* context, wStream* s, const WCHAR* ptr)
644{
645 WINPR_ASSERT(ptr);
646 return winpr_ndr_encoder_write_uint16(context, s, winpr_Data_Get_UINT16(ptr));
647}
648
649static BOOL ndr_decoder_read_wchar_(WinPrNdrDecoder* context, wStream* s, const void* hints,
650 void* v)
651{
652 WINPR_UNUSED(hints);
653 return winpr_ndr_decoder_read_wchar(context, s, (WCHAR*)v);
654}
655
656static BOOL ndr_encoder_write_wchar_(WinPrNdrEncoder* context, wStream* s, const void* hints,
657 const void* v)
658{
659 WINPR_UNUSED(hints);
660 return winpr_ndr_encoder_write_wchar(context, s, (const WCHAR*)v);
661}
662
664 WINPR_NDR_ARITY_SIMPLE, sizeof(WCHAR), ndr_decoder_read_wchar_,
665 ndr_encoder_write_wchar_, nullptr, nullptr
666};
667
672
673ARRAY_OF_TYPE_IMPL(uint8, BYTE)
674ARRAY_OF_TYPE_IMPL(uint16, UINT16)
675ARRAY_OF_TYPE_IMPL(wchar, WCHAR)
676
677static BOOL winpr_ndr_decoder_read_string_conformant(WinPrNdrDecoder* context, wStream* s,
678 const void* hints, void* v)
679{
680 WINPR_ASSERT(context);
681 WINPR_ASSERT(s);
682 WINPR_ASSERT(v);
683 WINPR_UNUSED(hints);
684
685 UINT32 sz = 0;
686 if (!winpr_ndr_decoder_read_uint32(context, s, &sz))
687 return FALSE;
688
689 if (!Stream_CheckAndLogRequiredLength(TAG, s, sz))
690 return FALSE;
691
692 char* ret = winpr_ndr_pointer_new(&winpr_ndr_string_conformant_descr_s, nullptr, 1ull * sz + 1);
693 if (!ret)
694 return FALSE;
695
696 Stream_Read(s, ret, sz);
697 ret[sz] = 0;
698
699 winpr_ndr_decoder_bytes_read(context, sz);
700 char** pstr = (char**)v;
701 *pstr = ret;
702 return TRUE;
703}
704
705static BOOL winpr_ndr_encoder_write_string_conformant(WinPrNdrEncoder* context, wStream* s,
706 const void* hints, const void* v)
707{
708 WINPR_ASSERT(context);
709 WINPR_ASSERT(s);
710 WINPR_ASSERT(v);
711 WINPR_UNUSED(hints);
712
713 const char* str = *(const char* const*)v;
714 const size_t l = str ? strlen(str) + 1 : 0;
715 if (l > UINT32_MAX)
716 return FALSE;
717
718 if (!winpr_ndr_encoder_write_uint32(context, s, (UINT32)l) ||
719 !Stream_EnsureRemainingCapacity(s, l))
720 return FALSE;
721 Stream_Write(s, str, l);
723 return TRUE;
724}
725
728 sizeof(char),
729 winpr_ndr_decoder_read_string_conformant,
730 winpr_ndr_encoder_write_string_conformant,
731 nullptr /* destroy */,
732 nullptr /* dump */
733};
734
739
741static BOOL ndr_read_string_varying_header(WinPrNdrDecoder* context, wStream* s, size_t charSize,
742 UINT32* plength)
743{
744 UINT32 maxCount = 0;
745 UINT32 offset = 0;
746 UINT32 length = 0;
747 if (!winpr_ndr_decoder_read_uint32(context, s, &maxCount) ||
748 !winpr_ndr_decoder_read_uint32(context, s, &offset) ||
749 !winpr_ndr_decoder_read_uint32(context, s, &length))
750 return FALSE;
751
752 if (offset != 0)
753 {
754 WLog_ERR(TAG, "offset != 0 not supported yet");
755 return FALSE;
756 }
757
758 if (length > maxCount)
759 {
760 WLog_ERR(TAG, "varying string length %" PRIu32 " > maximum count %" PRIu32, length,
761 maxCount);
762 return FALSE;
763 }
764
765 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, length, charSize))
766 return FALSE;
767
768 *plength = length;
769 return TRUE;
770}
771
772static BOOL winpr_ndr_decoder_read_string_varying(WinPrNdrDecoder* context, wStream* s,
773 const void* hints, void* v)
774{
775 WINPR_ASSERT(context);
776 WINPR_ASSERT(s);
777 WINPR_ASSERT(v);
778 WINPR_UNUSED(hints);
779
780 UINT32 length = 0;
781 if (!ndr_read_string_varying_header(context, s, sizeof(char), &length))
782 return FALSE;
783
784 char* ret =
785 winpr_ndr_pointer_new(&winpr_ndr_string_varying_descr_s, nullptr, 1ull * length + 1);
786 if (!ret)
787 return FALSE;
788
789 Stream_Read(s, ret, length);
790 ret[length] = 0;
791
792 winpr_ndr_decoder_bytes_read(context, length);
793 char** pstr = (char**)v;
794 *pstr = ret;
795 return TRUE;
796}
797
798static BOOL winpr_ndr_encoder_write_string_varying(WinPrNdrEncoder* context, wStream* s,
799 const void* hints, const void* v)
800{
801 WINPR_ASSERT(context);
802 WINPR_ASSERT(s);
803 WINPR_ASSERT(v);
804 WINPR_UNUSED(hints);
805
806 const char* str = *(const char* const*)v;
807 const size_t l = str ? strlen(str) + 1 : 0;
808 if (l > UINT32_MAX)
809 return FALSE;
810
811 if (!winpr_ndr_encoder_write_uint32(context, s, (UINT32)l) ||
812 !winpr_ndr_encoder_write_uint32(context, s, 0) ||
813 !winpr_ndr_encoder_write_uint32(context, s, (UINT32)l) ||
814 !Stream_EnsureRemainingCapacity(s, l))
815 return FALSE;
816
817 Stream_Write(s, str, l);
819 return TRUE;
820}
821
824 sizeof(char),
825 winpr_ndr_decoder_read_string_varying,
826 winpr_ndr_encoder_write_string_varying,
827 nullptr /* destroy */,
828 nullptr /* dump */
829};
830
835
836static BOOL ndr_decoder_read_wstring_varying(WinPrNdrDecoder* context, wStream* s,
837 const void* hints, void* v)
838{
839 WINPR_ASSERT(context);
840 WINPR_ASSERT(s);
841 WINPR_ASSERT(v);
842 WINPR_UNUSED(hints);
843
844 UINT32 length = 0;
845 if (!ndr_read_string_varying_header(context, s, sizeof(WCHAR), &length))
846 return FALSE;
847
848 WCHAR* ret = winpr_ndr_pointer_new(&winpr_ndr_wstring_varying_descr_s, nullptr,
849 (1ull * length + 1) * sizeof(WCHAR));
850 if (!ret)
851 return FALSE;
852
853 for (UINT32 i = 0; i < length; i++)
854 {
855 if (!winpr_ndr_decoder_read_wchar(context, s, &ret[i]))
856 {
858 return FALSE;
859 }
860 }
861
862 WCHAR** pstr = (WCHAR**)v;
863 *pstr = ret;
864 return TRUE;
865}
866
867static BOOL ndr_encoder_write_wstring_varying(WinPrNdrEncoder* context, wStream* s,
868 const void* hints, const void* v)
869{
870 WINPR_ASSERT(context);
871 WINPR_ASSERT(s);
872 WINPR_ASSERT(v);
873 WINPR_UNUSED(hints);
874
875 const WCHAR* str = *(const WCHAR* const*)v;
876 const size_t l = str ? _wcslen(str) + 1 : 0;
877 if (l > UINT32_MAX)
878 return FALSE;
879
880 if (!winpr_ndr_encoder_write_uint32(context, s, (UINT32)l) ||
881 !winpr_ndr_encoder_write_uint32(context, s, 0) ||
882 !winpr_ndr_encoder_write_uint32(context, s, (UINT32)l))
883 return FALSE;
884
885 for (size_t i = 0; i < l; i++)
886 {
887 if (!winpr_ndr_encoder_write_wchar(context, s, &str[i]))
888 return FALSE;
889 }
890 return TRUE;
891}
892
894 WINPR_NDR_ARITY_SELF_ALLOCATED, sizeof(WCHAR), ndr_decoder_read_wstring_varying,
895 ndr_encoder_write_wstring_varying, nullptr /* destroy */, nullptr /* dump */
896};
897
902
904static BOOL ndr_encoder_write_items(WinPrNdrEncoder* context, wStream* s, UINT32 count,
905 WinPrNdrMessageType itemType, const BYTE* src)
906{
907 BOOL ok = TRUE;
908
909 ndr_deferreds_enter(&context->deferreds);
910 for (UINT32 i = 0; ok && (i < count); i++, src += itemType->itemSize)
911 ok = itemType->writeFn(context, s, nullptr, src);
912
913 return ndr_deferreds_leave(&context->deferreds, ok);
914}
915
917 const WinPrNdrVaryingArrayHints* hints,
918 WinPrNdrMessageType itemType,
919 const void* psrc)
920{
921 WINPR_ASSERT(context);
922 WINPR_ASSERT(s);
923 WINPR_ASSERT(hints);
924 WINPR_ASSERT(itemType);
925 WINPR_ASSERT(psrc);
926
927 if (!winpr_ndr_encoder_write_uint32(context, s, hints->maxLength) ||
928 !winpr_ndr_encoder_write_uint32(context, s, 0) ||
929 !winpr_ndr_encoder_write_uint32(context, s, hints->length))
930 return FALSE;
931
932 return ndr_encoder_write_items(context, s, hints->length, itemType, psrc);
933}
934
935BOOL winpr_ndr_encoder_write_uconformant_array(WinPrNdrEncoder* context, wStream* s, UINT32 len,
936 WinPrNdrMessageType itemType, const BYTE* ptr)
937{
938 WINPR_ASSERT(context);
939 WINPR_ASSERT(s);
940 WINPR_ASSERT(itemType);
941 WINPR_ASSERT(ptr);
942
943 if (!winpr_ndr_encoder_write_uint32(context, s, len))
944 return FALSE;
945
946 return ndr_encoder_write_items(context, s, len, itemType, ptr);
947}
948
949static BOOL ndr_encoder_write_field(WinPrNdrEncoder* encoder, wStream* s,
950 const WinPrNdrStructDescr* descr,
951 const WinPrNdrFieldStruct* field, const void* src)
952{
953 const BYTE* ptr = (const BYTE*)src + field->structOffset;
954 void* hints = ndr_field_hints(descr, field, src);
955
956 switch (field->pointerType)
957 {
959 {
960 BOOL ok = FALSE;
961 if (field->fixedArraySize)
962 ok = ndr_encoder_write_items(encoder, s, (UINT32)ndr_inline_count(field),
963 field->typeDescr, ptr);
964 else
965 ok = ndr_check_range(descr, field, ptr) &&
966 field->typeDescr->writeFn(encoder, s, hints, ptr);
967
968 if (!ok)
969 {
970 WLog_ERR(TAG, "error when writing %s.%s", descr->name, field->name);
971 return FALSE;
972 }
973 return TRUE;
974 }
975
978 case WINPR_NDR_POINTER_FULL: /* each pointer has its own referent */
980 break;
981
982 default:
983 WLog_ERR(TAG, "%s.%s unknown pointer type 0x%x", descr->name, field->name,
984 field->pointerType);
985 return FALSE;
986 }
987
988 /* the target of the deferred: the referent, or the pointer itself for a self allocated type */
989 const void* target = ptr;
991 {
992 if (!ndr_check_fixed_array(descr, field, hints))
993 return FALSE;
994
995 /* an empty array is sent as a null pointer */
996 if (ndr_hintsCount(field->typeDescr, hints) == 0)
997 ptr = nullptr;
998 }
999 else
1000 {
1001 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
1002 if (field->typeDescr->arity != WINPR_NDR_ARITY_SELF_ALLOCATED)
1003 target = ptr;
1004
1005 if (!ptr && field->pointerType == WINPR_NDR_POINTER_NON_NULL)
1006 {
1007 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
1008 return FALSE;
1009 }
1010 }
1011
1013 BOOL isNew = FALSE;
1014 if (ptr && !winpr_ndr_encoder_allocatePtr(encoder, ptr, &ptrId, &isNew))
1015 {
1016 WLog_ERR(TAG, "error allocating pointer for %s.%s", descr->name, field->name);
1017 return FALSE;
1018 }
1019
1020 if (isNew)
1021 {
1022 const WinPrNdrDeferredEntry deferred = { ptrId, field->name,
1023 hints, WINPR_CAST_CONST_PTR_AWAY(target, void*),
1024 FALSE, field->typeDescr };
1025 if (!ndr_deferreds_add(&encoder->deferreds, &deferred))
1026 return FALSE;
1027 }
1028
1029 return winpr_ndr_encoder_write_uint32(encoder, s, ptrId);
1030}
1031
1032BOOL winpr_ndr_encoder_write_fromDescr(WinPrNdrEncoder* context, wStream* s,
1033 const WinPrNdrStructDescr* descr, const void* src)
1034{
1035 WINPR_ASSERT(context);
1036 WINPR_ASSERT(s);
1037 WINPR_ASSERT(descr);
1038 WINPR_ASSERT(src);
1039
1040 if ((descr->alignment > 1) && !winpr_ndr_encoder_write_align(context, s, descr->alignment))
1041 return FALSE;
1042
1043 BOOL ok = TRUE;
1044 ndr_deferreds_enter(&context->deferreds);
1045 for (size_t i = 0; ok && (i < descr->nfields); i++)
1046 ok = ndr_encoder_write_field(context, s, descr, &descr->fields[i], src);
1047
1048 return ndr_deferreds_leave(&context->deferreds, ok);
1049}
1050
1052{
1053 return (winpr_ndr_refid)((ULONG_PTR)ptr);
1054}
1055
1056BOOL winpr_ndr_encoder_allocatePtr(WinPrNdrEncoder* context, const void* ptr,
1057 winpr_ndr_refid* prefId, BOOL* pnewPtr)
1058{
1059 WINPR_ASSERT(context);
1060 WINPR_ASSERT(prefId);
1061 WINPR_ASSERT(pnewPtr);
1062 WINPR_UNUSED(ptr);
1063
1064 /* pointers are unique pointers: each non-null pointer has its own referent, the decoder
1065 * rejects aliased pointers */
1066 if (context->refIdCounter > UINT32_MAX - 4)
1067 return FALSE;
1068
1069 *pnewPtr = TRUE;
1070 *prefId = context->refIdCounter;
1071 context->refIdCounter += 4;
1072 return TRUE;
1073}
1074
1075BOOL winpr_ndr_encoder_treat_deferreds(WinPrNdrEncoder* context, wStream* s)
1076{
1077 WINPR_ASSERT(context);
1078 WINPR_ASSERT(s);
1079
1080 WinPrNdrDeferredEntry current = { 0 };
1081 while (ndr_deferreds_pop(&context->deferreds, &current))
1082 {
1083 WLog_VRB(TAG, "treating write deferred for %s", current.name);
1084 if (!current.msg->writeFn(context, s, current.hints, current.target))
1085 {
1086 WLog_ERR(TAG, "error writing deferred %s", current.name);
1087 return FALSE;
1088 }
1089 }
1090
1091 return TRUE;
1092}
1093
1094BOOL winpr_ndr_encoder_write_data(WinPrNdrEncoder* context, wStream* s, const void* data, size_t sz)
1095{
1096 if (!Stream_EnsureRemainingCapacity(s, sz))
1097 return FALSE;
1098
1099 Stream_Write(s, data, sz);
1101 return TRUE;
1102}
1103
1104/* ====================================================================================== */
1105
1106WinPrNdrDecoder* winpr_ndr_decoder_new(BOOL bigEndianDrep, BYTE version)
1107{
1108 WinPrNdrDecoder* ret = calloc(1, sizeof(*ret));
1109 if (!ret)
1110 return nullptr;
1111
1112 ret->version = version;
1113 ret->bigEndianDrep = bigEndianDrep;
1114 ret->referents = HashTable_New(FALSE);
1115 if (!ret->referents)
1116 {
1118 return nullptr;
1119 }
1120
1121 return ret;
1122}
1123
1125{
1126 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1127 return nullptr;
1128
1129 BYTE version = Stream_Get_UINT8(s);
1130 BYTE drep = Stream_Get_UINT8(s);
1131 UINT16 headerLen = Stream_Get_UINT16(s);
1132
1133 if (version != 1)
1134 {
1135 WLog_ERR(TAG, "unsupported type serialization version %" PRIu8, version);
1136 return nullptr;
1137 }
1138
1139 if (headerLen < 4 || !Stream_CheckAndLogRequiredLength(TAG, s, headerLen - 4))
1140 return nullptr;
1141
1142 /* skip filler */
1143 Stream_Seek(s, headerLen - 4);
1144
1145 return winpr_ndr_decoder_new((drep != 0x10), version);
1146}
1147
1148void winpr_ndr_decoder_free(WinPrNdrDecoder* context)
1149{
1150 if (context)
1151 {
1152 /* the referents belong to the pointers that reference them */
1153 HashTable_Free(context->referents);
1154 free(context);
1155 }
1156}
1157
1158void winpr_ndr_decoder_bytes_read(WinPrNdrDecoder* context, size_t len)
1159{
1160 WINPR_ASSERT(context);
1161 context->offset += len;
1162}
1163
1164BOOL winpr_ndr_decoder_skip_bytes(WinPrNdrDecoder* context, wStream* s, size_t nbytes)
1165{
1166 WINPR_ASSERT(context);
1167
1168 if (!Stream_CheckAndLogRequiredLength(TAG, s, nbytes))
1169 return FALSE;
1170
1171 context->offset += nbytes;
1172 Stream_Seek(s, nbytes);
1173 return TRUE;
1174}
1175
1176BOOL winpr_ndr_decoder_read_align(WinPrNdrDecoder* context, wStream* s, size_t sz)
1177{
1178 WINPR_ASSERT(context);
1179
1180 size_t rest = context->offset % sz;
1181 if (rest)
1182 {
1183 size_t padding = (sz - rest);
1184 if (!Stream_CheckAndLogRequiredLength(TAG, s, padding))
1185 return FALSE;
1186
1187 Stream_Seek(s, padding);
1188 context->offset += padding;
1189 }
1190
1191 return TRUE;
1192}
1193
1194BOOL winpr_ndr_decoder_read_refpointer(WinPrNdrDecoder* context, wStream* s, winpr_ndr_refid* refId)
1195{
1196 return winpr_ndr_decoder_read_uint32(context, s, refId);
1197}
1198
1199BOOL winpr_ndr_decoder_read_object(WinPrNdrDecoder* context, wStream* s, wStream* object)
1200{
1201 WINPR_ASSERT(context);
1202 WINPR_ASSERT(s);
1203 WINPR_ASSERT(object);
1204
1205 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1206 return FALSE;
1207
1208 UINT32 len = 0;
1209 if (context->bigEndianDrep)
1210 Stream_Read_UINT32_BE(s, len);
1211 else
1212 Stream_Read_UINT32(s, len);
1213 Stream_Seek(s, 4); /* Filler */
1214
1215 if (!Stream_CheckAndLogRequiredLength(TAG, s, len))
1216 return FALSE;
1217
1218 Stream_StaticInit(object, Stream_PointerAs(s, BYTE), len);
1219 Stream_Seek(s, len);
1220
1221 /* alignments are relative to the start of the object data */
1222 context->offset = 0;
1223 return TRUE;
1224}
1225
1226BOOL winpr_ndr_decoder_read_uint8(WinPrNdrDecoder* context, wStream* s, BYTE* v)
1227{
1228 WINPR_ASSERT(context);
1229
1230 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1231 return FALSE;
1232
1233 Stream_Read_UINT8(s, *v);
1234
1235 winpr_ndr_decoder_bytes_read(context, 1);
1236 return TRUE;
1237}
1238
1239BOOL winpr_ndr_decoder_read_uint8_(WinPrNdrDecoder* context, wStream* s, const void* hints, void* v)
1240{
1241 WINPR_UNUSED(hints);
1242 return winpr_ndr_decoder_read_uint8(context, s, (BYTE*)v);
1243}
1244
1245BOOL winpr_ndr_decoder_read_int8(WinPrNdrDecoder* context, wStream* s, INT8* v)
1246{
1247 WINPR_ASSERT(v);
1248
1249 BYTE b = 0;
1250 if (!winpr_ndr_decoder_read_uint8(context, s, &b))
1251 return FALSE;
1252 *v = (INT8)b;
1253 return TRUE;
1254}
1255
1256BOOL winpr_ndr_decoder_read_int8_(WinPrNdrDecoder* context, wStream* s, const void* hints, void* v)
1257{
1258 WINPR_UNUSED(hints);
1259 return winpr_ndr_decoder_read_int8(context, s, (INT8*)v);
1260}
1261
1263static BOOL ndr_decoder_read_items(WinPrNdrDecoder* context, wStream* s, UINT32 count,
1264 WinPrNdrMessageType itemType, BYTE* target)
1265{
1266 BOOL ok = TRUE;
1267
1268 ndr_deferreds_enter(&context->deferreds);
1269 for (UINT32 i = 0; ok && (i < count); i++, target += itemType->itemSize)
1270 ok = itemType->readFn(context, s, nullptr, target);
1271
1272 return ndr_deferreds_leave(&context->deferreds, ok);
1273}
1274
1280static BOOL ndr_check_array_bound(const char* what, UINT32 count, WinPrNdrMessageType itemType,
1281 UINT32 limit)
1282{
1283 if (itemType->arity == WINPR_NDR_ARITY_SIMPLE)
1284 {
1285 if (count != limit)
1286 {
1287 WLog_ERR(TAG, "%s: conformance %" PRIu32 " doesn't match the expected count %" PRIu32,
1288 what, count, limit);
1289 return FALSE;
1290 }
1291 return TRUE;
1292 }
1293
1294 if ((1ull * count * itemType->itemSize) > limit)
1295 {
1296 WLog_ERR(TAG, "%s: %" PRIu32 " items don't fit in %" PRIu32, what, count, limit);
1297 return FALSE;
1298 }
1299 return TRUE;
1300}
1301
1303static BOOL ndr_read_varying_array_header(WinPrNdrDecoder* context, wStream* s,
1304 const WinPrNdrVaryingArrayHints* hints,
1305 WinPrNdrMessageType itemType, UINT32* pmaxCount,
1306 UINT32* plength)
1307{
1308 if (itemType->itemSize == 0)
1309 return FALSE;
1310
1311 UINT32 maxCount = 0;
1312 UINT32 offset = 0;
1313 UINT32 length = 0;
1314
1315 if (!winpr_ndr_decoder_read_uint32(context, s, &maxCount) ||
1316 !winpr_ndr_decoder_read_uint32(context, s, &offset) ||
1317 !winpr_ndr_decoder_read_uint32(context, s, &length))
1318 return FALSE;
1319
1320 if (length > maxCount)
1321 {
1322 WLog_ERR(TAG, "varying array length %" PRIu32 " > maximum count %" PRIu32, length,
1323 maxCount);
1324 return FALSE;
1325 }
1326
1327 if (hints)
1328 {
1329 if ((1ull * length * itemType->itemSize) > hints->length)
1330 return FALSE;
1331
1332 if ((1ull * maxCount * itemType->itemSize) > hints->maxLength)
1333 return FALSE;
1334 }
1335
1336 *pmaxCount = maxCount;
1337 *plength = length;
1338 return TRUE;
1339}
1340
1342 const WinPrNdrVaryingArrayHints* hints,
1343 WinPrNdrMessageType itemType, void* target)
1344{
1345 WINPR_ASSERT(context);
1346 WINPR_ASSERT(s);
1347 WINPR_ASSERT(itemType);
1348 WINPR_ASSERT(target);
1349
1350 if (!hints)
1351 return FALSE;
1352
1353 UINT32 maxCount = 0;
1354 UINT32 length = 0;
1355 if (!ndr_read_varying_array_header(context, s, hints, itemType, &maxCount, &length))
1356 return FALSE;
1357
1358 return ndr_decoder_read_items(context, s, length, itemType, target);
1359}
1360
1361BOOL winpr_ndr_decoder_read_uconformant_array(WinPrNdrDecoder* context, wStream* s,
1362 const WinPrNdrArrayHints* hints,
1363 WinPrNdrMessageType itemType, void* vtarget)
1364{
1365 WINPR_ASSERT(context);
1366 WINPR_ASSERT(s);
1367 WINPR_ASSERT(itemType);
1368 WINPR_ASSERT(vtarget);
1369
1370 if (!hints)
1371 return FALSE;
1372
1373 if (itemType->itemSize == 0)
1374 return FALSE;
1375
1376 UINT32 count = 0;
1377 if (!winpr_ndr_decoder_read_uint32(context, s, &count))
1378 return FALSE;
1379
1380 if (!ndr_check_array_bound("conformant array", count, itemType, hints->count))
1381 return FALSE;
1382
1383 return ndr_decoder_read_items(context, s, count, itemType, vtarget);
1384}
1385
1387static BOOL ndr_referent_size(const char* name, WinPrNdrMessageType descr, const void* hints,
1388 size_t* psize)
1389{
1390 if (descr->arity == WINPR_NDR_ARITY_SELF_ALLOCATED)
1391 {
1392 WLog_ERR(TAG, "%s: the size of a self allocated type isn't known", name);
1393 return FALSE;
1394 }
1395
1396 if ((descr->arity != WINPR_NDR_ARITY_SIMPLE) && !hints)
1397 {
1398 WLog_ERR(TAG, "%s: no hints for an array", name);
1399 return FALSE;
1400 }
1401
1402 if (descr->itemSize == 0)
1403 return FALSE;
1404
1405 const size_t count = ndr_hintsCount(descr, hints);
1406 if (count > SIZE_MAX / descr->itemSize)
1407 return FALSE;
1408
1409 /* an empty array is still a valid referent */
1410 *psize = (count ? count : 1) * descr->itemSize;
1411 return TRUE;
1412}
1413
1414static void ndr_referent_copy_hints(NdrReferent* ref, const void* hints)
1415{
1416 ref->hasHints = FALSE;
1417 if (!ref->typeDescr || !hints)
1418 return;
1419
1420 switch (ref->typeDescr->arity)
1421 {
1423 ref->hints.array = *(const WinPrNdrArrayHints*)hints;
1424 ref->hasHints = TRUE;
1425 break;
1427 ref->hints.varying = *(const WinPrNdrVaryingArrayHints*)hints;
1428 ref->hasHints = TRUE;
1429 break;
1430 default:
1431 break;
1432 }
1433}
1434
1435static NdrReferent* ndr_referent_new(WinPrNdrMessageType descr, const void* hints, size_t size)
1436{
1437 const size_t headerSize = offsetof(NdrReferent, payload);
1438 const size_t payloadSize = sizeof(((NdrReferent*)nullptr)->payload);
1439 if (size > SIZE_MAX - headerSize - payloadSize)
1440 return nullptr;
1441
1442 NdrReferent* ref = calloc(1, headerSize + ((size > payloadSize) ? size : payloadSize));
1443 if (!ref)
1444 return nullptr;
1445
1446 ref->magic = NDR_REFERENT_MAGIC;
1447 ref->refCount = 1;
1448 ref->typeDescr = descr;
1449 ref->size = size;
1450 ndr_referent_copy_hints(ref, hints);
1451 return ref;
1452}
1453
1454void* winpr_ndr_pointer_new(WinPrNdrMessageType descr, const void* hints, size_t size)
1455{
1456 NdrReferent* ref = ndr_referent_new(descr, hints, size);
1457 WINPR_PRAGMA_DIAG_PUSH
1458 WINPR_DO_COVERITY_PRAGMA(
1459 coverity compliance block
1460 deviate 'RESOURCE_LEAK' 'returning a constant offset pointer, winpr_ndr_pointer_release does the inverse')
1461 return ref ? ref->payload.data : nullptr;
1462 WINPR_PRAGMA_DIAG_POP
1463}
1464
1465size_t winpr_ndr_pointer_size(const void* ptr)
1466{
1467 if (!ptr)
1468 return 0;
1469
1470 return ndr_referent(WINPR_CAST_CONST_PTR_AWAY(ptr, void*))->size;
1471}
1472
1474{
1475 if (!ptr)
1476 return nullptr;
1477
1478 NdrReferent* ref = ndr_referent(ptr);
1479 InterlockedIncrement(&ref->refCount);
1480 return ptr;
1481}
1482
1484{
1485 if (!ptr)
1486 return;
1487
1488 NdrReferent* ref = ndr_referent(ptr);
1489 if (InterlockedDecrement(&ref->refCount) > 0)
1490 return;
1491
1492 if (ref->typeDescr && ref->typeDescr->destroyFn)
1493 ref->typeDescr->destroyFn(ref->hasHints ? &ref->hints : nullptr, ref->payload.data);
1494 ref->magic = 0;
1495 free(ref);
1496}
1497
1499static BOOL ndr_decoder_register(WinPrNdrDecoder* decoder, NdrReferent* ref, winpr_ndr_refid refId,
1500 BOOL full)
1501{
1502 ref->refId = refId;
1503 ref->full = full;
1504 return HashTable_Insert(decoder->referents, (void*)(UINT_PTR)refId, ref);
1505}
1506
1508static BOOL ndr_referent_check(const char* name, const NdrReferent* ref, WinPrNdrMessageType descr,
1509 const void* hints, size_t size)
1510{
1511 if (!ref->full)
1512 {
1513 WLog_ERR(TAG, "%s: referent 0x%" PRIx32 " is the referent of a unique pointer", name,
1514 ref->refId);
1515 return FALSE;
1516 }
1517
1518 if ((ref->typeDescr != descr) || (ref->size != size))
1519 {
1520 WLog_ERR(TAG,
1521 "%s: referent 0x%" PRIx32 " is aliased with another type or size (%" PRIuz
1522 " vs %" PRIuz " bytes)",
1523 name, ref->refId, size, ref->size);
1524 return FALSE;
1525 }
1526
1527 BOOL same = TRUE;
1528 switch (descr->arity)
1529 {
1531 same = memcmp(&ref->hints.array, hints, sizeof(ref->hints.array)) == 0;
1532 break;
1534 same = memcmp(&ref->hints.varying, hints, sizeof(ref->hints.varying)) == 0;
1535 break;
1536 default:
1537 break;
1538 }
1539
1540 if (!same)
1541 WLog_ERR(TAG, "%s: referent 0x%" PRIx32 " is aliased with other hints", name, ref->refId);
1542 return same;
1543}
1544
1546static BOOL ndr_decoder_read_full_pointer(WinPrNdrDecoder* decoder, wStream* s, const char* name,
1547 WinPrNdrMessageType descr, void* hints, void** target)
1548{
1549 WINPR_ASSERT(decoder);
1550 WINPR_ASSERT(descr);
1551 WINPR_ASSERT(target);
1552
1553 *target = nullptr;
1554
1555 winpr_ndr_refid refId = 0;
1556 if (!winpr_ndr_decoder_read_refpointer(decoder, s, &refId))
1557 return FALSE;
1558 if (!refId)
1559 return TRUE;
1560
1561 size_t size = 0;
1562 if (!ndr_referent_size(name, descr, hints, &size))
1563 return FALSE;
1564
1565 NdrReferent* ref = HashTable_GetItemValue(decoder->referents, (void*)(UINT_PTR)refId);
1566 if (ref)
1567 {
1568 if (!ndr_referent_check(name, ref, descr, hints, size))
1569 return FALSE;
1570
1571 *target = winpr_ndr_pointer_ref(ref->payload.data);
1572 return TRUE;
1573 }
1574
1575 /* each item of an array takes at least one byte on the wire */
1576 if ((descr->arity == WINPR_NDR_ARITY_ARRAYOF) &&
1577 !Stream_CheckAndLogRequiredLength(TAG, s, ndr_hintsCount(descr, hints)))
1578 return FALSE;
1579
1580 ref = ndr_referent_new(descr, hints, size);
1581 if (!ref)
1582 return FALSE;
1583
1584 if (!ndr_decoder_register(decoder, ref, refId, TRUE))
1585 {
1586 free(ref);
1587 return FALSE;
1588 }
1589
1590 /* the referent is read with the deferred pointers */
1591 *target = ref->payload.data;
1592 const WinPrNdrDeferredEntry deferred = { refId, name, hints, ref->payload.data, FALSE, descr };
1593 return ndr_deferreds_add(&decoder->deferreds, &deferred);
1594}
1595
1596BOOL winpr_ndr_decoder_read_pointer_ex(WinPrNdrDecoder* context, wStream* s, const char* name,
1597 WinPrNdrMessageType descr, void* hints, void** target)
1598{
1599 WINPR_ASSERT(context);
1600
1601 ndr_deferreds_enter(&context->deferreds);
1602 const BOOL ok = ndr_decoder_read_full_pointer(context, s, name, descr, hints, target);
1603 return ndr_deferreds_leave(&context->deferreds, ok);
1604}
1605
1606static BOOL ndr_decoder_read_field(WinPrNdrDecoder* decoder, wStream* s,
1607 const WinPrNdrStructDescr* descr,
1608 const WinPrNdrFieldStruct* field, void* target)
1609{
1610 BYTE* ptr = (BYTE*)target + field->structOffset;
1611 void* hints = ndr_field_hints(descr, field, target);
1612
1613 switch (field->pointerType)
1614 {
1616 {
1617 BOOL ok = FALSE;
1618 if (field->fixedArraySize)
1619 ok = ndr_decoder_read_items(decoder, s, (UINT32)ndr_inline_count(field),
1620 field->typeDescr, ptr);
1621 else
1622 ok = field->typeDescr->readFn(decoder, s, hints, ptr) &&
1623 ndr_check_range(descr, field, ptr);
1624
1625 if (!ok)
1626 {
1627 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
1628 return FALSE;
1629 }
1630 return TRUE;
1631 }
1632
1634 {
1635 /* the field is a pointer, possibly not aligned in the byte view of the struct */
1636 void* referent = nullptr;
1637 const BOOL ok = ndr_decoder_read_full_pointer(decoder, s, field->name, field->typeDescr,
1638 hints, &referent);
1639
1640 /* stored even on failure, the referent is released with the structure */
1641 memcpy(ptr, (const void*)&referent, sizeof(referent));
1642 if (!ok)
1643 {
1644 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
1645 return FALSE;
1646 }
1647 return TRUE;
1648 }
1649
1650 case WINPR_NDR_POINTER:
1653 break;
1654
1655 default:
1656 WLog_ERR(TAG, "%s.%s unknown pointer type 0x%x", descr->name, field->name,
1657 field->pointerType);
1658 return FALSE;
1659 }
1660
1661 WinPrNdrDeferredEntry deferred = {
1662 WINPR_NDR_PTR_NULL, field->name, hints, ptr, field->pointerType != WINPR_NDR_FIXED_ARRAY,
1663 field->typeDescr
1664 };
1665 if (!winpr_ndr_decoder_read_refpointer(decoder, s, &deferred.ptrId))
1666 {
1667 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
1668 return FALSE;
1669 }
1670
1671 if (!deferred.ptrId)
1672 {
1674 {
1675 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
1676 return FALSE;
1677 }
1678
1679 /* the inline storage of a fixed array can't hold a null pointer to a non empty array */
1680 if ((field->pointerType == WINPR_NDR_FIXED_ARRAY) &&
1681 (!hints || (ndr_hintsCount(field->typeDescr, hints) != 0)))
1682 {
1683 WLog_ERR(TAG, "%s.%s is null but the array is not empty", descr->name, field->name);
1684 return FALSE;
1685 }
1686 return TRUE;
1687 }
1688
1689 if (!deferred.allocate && !ndr_check_fixed_array(descr, field, hints))
1690 return FALSE;
1691
1692 return ndr_deferreds_add(&decoder->deferreds, &deferred);
1693}
1694
1695BOOL winpr_ndr_decoder_read_fromDescr(WinPrNdrDecoder* context, wStream* s,
1696 const WinPrNdrStructDescr* descr, void* target)
1697{
1698 WINPR_ASSERT(context);
1699 WINPR_ASSERT(s);
1700 WINPR_ASSERT(descr);
1701 WINPR_ASSERT(target);
1702
1703 if ((descr->alignment > 1) && !winpr_ndr_decoder_read_align(context, s, descr->alignment))
1704 return FALSE;
1705
1706 BOOL ok = TRUE;
1707 ndr_deferreds_enter(&context->deferreds);
1708 for (size_t i = 0; ok && (i < descr->nfields); i++)
1709 ok = ndr_decoder_read_field(context, s, descr, &descr->fields[i], target);
1710
1711 return ndr_deferreds_leave(&context->deferreds, ok);
1712}
1713
1714BOOL winpr_ndr_decoder_treat_deferreds(WinPrNdrDecoder* context, wStream* s)
1715{
1716 WINPR_ASSERT(context);
1717 WINPR_ASSERT(s);
1718
1719 WinPrNdrDeferredEntry current = { 0 };
1720 while (ndr_deferreds_pop(&context->deferreds, &current))
1721 {
1722 WLog_VRB(TAG, "treating read deferred 0x%x for %s", current.ptrId, current.name);
1723
1724 BOOL ok = FALSE;
1725 if (current.allocate)
1726 ok = winpr_ndr_decoder_read_pointedMessageEx(context, s, current.ptrId, current.msg,
1727 current.hints, (void**)current.target);
1728 else
1729 ok = current.msg->readFn(context, s, current.hints, current.target);
1730
1731 if (!ok)
1732 {
1733 WLog_ERR(TAG, "error parsing deferred %s", current.name);
1734 return FALSE;
1735 }
1736 }
1737
1738 return TRUE;
1739}
1740
1741BOOL winpr_ndr_decoder_read_pointedMessageEx(WinPrNdrDecoder* context, wStream* s,
1743 void* hints, void** target)
1744{
1745 WINPR_ASSERT(context);
1746 WINPR_ASSERT(s);
1747 WINPR_ASSERT(descr);
1748 WINPR_ASSERT(target);
1749
1750 *target = nullptr;
1751 if (!ptrId)
1752 return TRUE;
1753
1754 /* a unique pointer can't share its referent */
1755 if (HashTable_Contains(context->referents, (void*)(UINT_PTR)ptrId))
1756 {
1757 WLog_ERR(TAG, "unique pointer 0x%" PRIx32 " is aliased", ptrId);
1758 return FALSE;
1759 }
1760
1761 void* ret = nullptr;
1762 if (descr->arity == WINPR_NDR_ARITY_SELF_ALLOCATED)
1763 {
1764 /* the reader allocates the referent with winpr_ndr_pointer_new() */
1765 if (!descr->readFn(context, s, hints, (void*)&ret))
1766 return FALSE;
1767 if (!ret)
1768 return FALSE;
1769 }
1770 else
1771 {
1772 size_t size = 0;
1773 if (!ndr_referent_size("unique pointer", descr, hints, &size))
1774 return FALSE;
1775
1776 /* each item takes at least one byte on the wire, don't allocate for data that isn't
1777 * there */
1778 if ((descr->arity == WINPR_NDR_ARITY_ARRAYOF) &&
1779 !Stream_CheckAndLogRequiredLength(TAG, s, ndr_hintsCount(descr, hints)))
1780 return FALSE;
1781
1782 ret = winpr_ndr_pointer_new(descr, hints, size);
1783 if (!ret)
1784 return FALSE;
1785
1786 if (!descr->readFn(context, s, hints, ret))
1787 {
1789 return FALSE;
1790 }
1791 }
1792
1793 if (!ndr_decoder_register(context, ndr_referent(ret), ptrId, FALSE))
1794 {
1796 return FALSE;
1797 }
1798
1799 *target = ret;
1800 return TRUE;
1801}
1802
1803BOOL winpr_ndr_decoder_push_deferreds(WinPrNdrDecoder* context, WinPrNdrDeferredEntry* deferreds,
1804 size_t ndeferred)
1805{
1806 WINPR_ASSERT(context);
1807 WINPR_ASSERT(deferreds);
1808
1809 BOOL ok = TRUE;
1810 ndr_deferreds_enter(&context->deferreds);
1811 for (size_t i = 0; ok && (i < ndeferred); i++)
1812 ok = ndr_deferreds_add(&context->deferreds, &deferreds[i]);
1813
1814 return ndr_deferreds_leave(&context->deferreds, ok);
1815}
1816
1817/* ========================================================================================================
1818 */
1819
1820/* ====================================== unions ========================================== */
1821
1823static size_t ndr_union_switch_size(const WinPrNdrUnionDescr* descr)
1824{
1825 WINPR_ASSERT(descr);
1826 WINPR_ASSERT((descr->switchSize == 0) || (descr->switchSize == 2) || (descr->switchSize == 4));
1827 return descr->switchSize ? descr->switchSize : 4;
1828}
1829
1830UINT32 winpr_ndr_union_switch_value(const WinPrNdrUnionDescr* descr, const void* switchField)
1831{
1832 WINPR_ASSERT(switchField);
1833
1834 if (ndr_union_switch_size(descr) == 2)
1835 return *(const UINT16*)switchField;
1836 return *(const UINT32*)switchField;
1837}
1838
1840static const WinPrNdrUnionArm* ndr_union_find_arm(const WinPrNdrUnionDescr* descr,
1841 UINT32 switchValue)
1842{
1843 WINPR_ASSERT(descr);
1844
1845 for (size_t i = 0; i < descr->narms; i++)
1846 {
1847 const WinPrNdrUnionArm* arm = &descr->arms[i];
1848 if (arm->discriminant == switchValue)
1849 return arm;
1850 }
1851 return descr->defaultArm;
1852}
1853
1855static const WinPrNdrUnionArm* ndr_union_arm(const WinPrNdrUnionDescr* descr, UINT32 switchValue,
1856 WinPrNdrStructDescr* armStruct)
1857{
1858 WINPR_ASSERT(armStruct);
1859
1860 const WinPrNdrUnionArm* arm = ndr_union_find_arm(descr, switchValue);
1861 if (!arm)
1862 {
1863 WLog_ERR(TAG, "%s: no arm for the discriminant 0x%08" PRIx32, descr->name, switchValue);
1864 return nullptr;
1865 }
1866
1867 WINPR_ASSERT(arm->field.hintsField < 0);
1868 armStruct->name = descr->name;
1869 armStruct->nfields = 1;
1870 armStruct->fields = &arm->field;
1871 armStruct->alignment = 0;
1872 return arm;
1873}
1874
1875static BOOL ndr_encoder_write_discriminant(WinPrNdrEncoder* context, wStream* s,
1876 const WinPrNdrUnionDescr* descr, UINT32 switchValue)
1877{
1878 if (ndr_union_switch_size(descr) == 4)
1879 return winpr_ndr_encoder_write_uint32(context, s, switchValue);
1880
1881 if (switchValue > UINT16_MAX)
1882 {
1883 WLog_ERR(TAG, "%s: discriminant 0x%08" PRIx32 " doesn't fit in 16 bits", descr->name,
1884 switchValue);
1885 return FALSE;
1886 }
1887 return winpr_ndr_encoder_write_uint16(context, s, (UINT16)switchValue);
1888}
1889
1890static BOOL ndr_decoder_read_discriminant(WinPrNdrDecoder* context, wStream* s,
1891 const WinPrNdrUnionDescr* descr, UINT32* discriminant)
1892{
1893 if (ndr_union_switch_size(descr) == 4)
1894 return winpr_ndr_decoder_read_uint32(context, s, discriminant);
1895
1896 UINT16 v = 0;
1897 if (!winpr_ndr_decoder_read_uint16(context, s, &v))
1898 return FALSE;
1899 *discriminant = v;
1900 return TRUE;
1901}
1902
1903BOOL winpr_ndr_encoder_write_union(WinPrNdrEncoder* context, wStream* s,
1904 const WinPrNdrUnionDescr* descr, UINT32 switchValue,
1905 const void* src)
1906{
1907 WINPR_ASSERT(context);
1908 WINPR_ASSERT(src);
1909
1910 WinPrNdrStructDescr armStruct = WINPR_C_ARRAY_INIT;
1911 const WinPrNdrUnionArm* arm = ndr_union_arm(descr, switchValue, &armStruct);
1912 if (!arm || !ndr_encoder_write_discriminant(context, s, descr, switchValue))
1913 return FALSE;
1914
1915 BOOL ok = TRUE;
1916 ndr_deferreds_enter(&context->deferreds);
1917 if (arm->field.typeDescr)
1918 ok = ndr_encoder_write_field(context, s, &armStruct, &arm->field, src);
1919 return ndr_deferreds_leave(&context->deferreds, ok);
1920}
1921
1922BOOL winpr_ndr_decoder_read_union(WinPrNdrDecoder* context, wStream* s,
1923 const WinPrNdrUnionDescr* descr, UINT32 switchValue, void* target)
1924{
1925 WINPR_ASSERT(context);
1926 WINPR_ASSERT(target);
1927
1928 UINT32 discriminant = 0;
1929 if (!ndr_decoder_read_discriminant(context, s, descr, &discriminant))
1930 return FALSE;
1931
1932 if (discriminant != switchValue)
1933 {
1934 WLog_ERR(TAG,
1935 "%s: discriminant 0x%08" PRIx32 " doesn't match the switch value 0x%08" PRIx32,
1936 descr->name, discriminant, switchValue);
1937 return FALSE;
1938 }
1939
1940 WinPrNdrStructDescr armStruct = WINPR_C_ARRAY_INIT;
1941 const WinPrNdrUnionArm* arm = ndr_union_arm(descr, switchValue, &armStruct);
1942 if (!arm)
1943 return FALSE;
1944
1945 BOOL ok = TRUE;
1946 ndr_deferreds_enter(&context->deferreds);
1947 if (arm->field.typeDescr)
1948 ok = ndr_decoder_read_field(context, s, &armStruct, &arm->field, target);
1949 return ndr_deferreds_leave(&context->deferreds, ok);
1950}
1951
1952void winpr_ndr_union_destroy(const WinPrNdrUnionDescr* descr, UINT32 switchValue, void* obj)
1953{
1954 WINPR_ASSERT(descr);
1955 WINPR_ASSERT(obj);
1956
1957 const WinPrNdrUnionArm* arm = ndr_union_find_arm(descr, switchValue);
1958 if (!arm || !arm->field.typeDescr)
1959 return;
1960
1961 const WinPrNdrStructDescr armStruct = { descr->name, 1, &arm->field, 0 };
1962 winpr_ndr_struct_destroy(&armStruct, obj);
1963}
1964
1965/* ======================================================================================== */
1966
1967void winpr_ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
1968 const WinPrNdrStructDescr* descr, const void* obj)
1969{
1970 char tabArray[30 + 1];
1971 size_t ntabs = (identLevel <= 30) ? identLevel : 30;
1972
1973 memset(tabArray, '\t', ntabs);
1974 tabArray[ntabs] = 0;
1975
1976 WLog_Print(logger, lvl, "%s%s", tabArray, descr->name);
1977 for (size_t i = 0; i < descr->nfields; i++)
1978 {
1979 const WinPrNdrFieldStruct* field = &descr->fields[i];
1980 const BYTE* ptr = (const BYTE*)obj + field->structOffset;
1981
1982 switch (field->pointerType)
1983 {
1984 case WINPR_NDR_POINTER:
1987 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
1988 break;
1991 break;
1992 default:
1993 WLog_ERR(TAG, "invalid field->pointerType");
1994 break;
1995 }
1996
1997 WLog_Print(logger, lvl, "%s*%s:", tabArray, field->name);
1998 if (field->typeDescr->dumpFn)
1999 field->typeDescr->dumpFn(logger, lvl, identLevel + 1, ptr);
2000 else
2001 WLog_Print(logger, lvl, "%s\t<no dump function>", tabArray);
2002 }
2003}
2004
2005void winpr_ndr_struct_destroy(const WinPrNdrStructDescr* descr, void* pptr)
2006{
2007 WINPR_ASSERT(descr);
2008 WINPR_ASSERT(pptr);
2009
2010 for (size_t i = 0; i < descr->nfields; i++)
2011 {
2012 const WinPrNdrFieldStruct* field = &descr->fields[i];
2013 void* ptr = (BYTE*)pptr + field->structOffset;
2014 void* hints = nullptr;
2015
2016 if (field->hintsField >= 0)
2017 {
2018 /* computes the address of the hints field if any */
2019 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
2020 const WinPrNdrFieldStruct* hintsField = &descr->fields[field->hintsField];
2021
2022 hints = (BYTE*)pptr + hintsField->structOffset;
2023 }
2024
2025 switch (field->pointerType)
2026 {
2027 case WINPR_NDR_POINTER:
2030 {
2031 /* the referent is destroyed with its last reference */
2032 void** pptrField = (void**)ptr;
2033 winpr_ndr_pointer_release(*pptrField);
2034 *pptrField = nullptr;
2035 }
2036 break;
2037
2038 default:
2039 /* NOT_POINTER and FIXED_ARRAY fields are stored inline in the struct */
2040 if (field->typeDescr->destroyFn)
2041 field->typeDescr->destroyFn(hints, ptr);
2042 break;
2043 }
2044 }
2045}
NDR encoder and decoder ([C706] chapter 14, [MS-RPCE] 2.2.5 and 2.2.6)
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_allocatePtr(WinPrNdrEncoder *context, const void *ptr, winpr_ndr_refid *prefId, BOOL *pnewPtr)
allocates the referent id of an embedded pointer
Definition ndr.c:1056
WinPrNdrFieldStruct field
Definition ndr.h:356
WINPR_API void winpr_ndr_decoder_free(WinPrNdrDecoder *context)
frees a decoder
Definition ndr.c:1148
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_end_object(WinPrNdrEncoder *context, wStream *s)
ends the serialized object started with winpr_ndr_encoder_start_object()
Definition ndr.c:282
UINT32 winpr_ndr_refid
a referent id, the wire value of a pointer (WINPR_NDR_PTR_NULL for a null pointer)
Definition ndr.h:230
@ WINPR_NDR_NOT_POINTER
Definition ndr.h:313
@ WINPR_NDR_POINTER_FULL
Definition ndr.h:320
@ WINPR_NDR_FIXED_ARRAY
Definition ndr.h:317
@ WINPR_NDR_POINTER
Definition ndr.h:316
@ WINPR_NDR_POINTER_NON_NULL
Definition ndr.h:315
WinPrNdrPointerType pointerType
Definition ndr.h:331
const char * name
Definition ndr.h:344
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_wchar(WinPrNdrEncoder *context, wStream *s, const WCHAR *ptr)
writes a WCHAR stored in UTF-16LE, aligned on 2 bytes
Definition ndr.c:643
WINPR_API void * winpr_ndr_pointer_ref(void *ptr)
takes a reference on a referent
Definition ndr.c:1473
size_t narms
Definition ndr.h:370
WINPR_ATTR_NODISCARD WINPR_API WinPrNdrMessageType winpr_ndr_string_varying_descr(void)
the message type of winpr_ndr_string_varying_descr_s
Definition ndr.c:831
size_t structOffset
Definition ndr.h:330
WINPR_ATTR_NODISCARD WINPR_API winpr_ndr_refid winpr_ndr_pointer_refid(const void *ptr)
a referent id built from the value of a pointer
Definition ndr.c:1051
const char * name
Definition ndr.h:329
size_t alignment
Definition ndr.h:347
WINPR_API void winpr_ndr_struct_dump_fromDescr(wLog *logger, UINT32 lvl, size_t identLevel, const WinPrNdrStructDescr *descr, const void *obj)
dumps a structure in the logs from its descriptor
Definition ndr.c:1967
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_header(WinPrNdrEncoder *context, wStream *s)
writes the common type header ([MS-RPCE] 2.2.6.1): version, endianness, header length and filler
Definition ndr.c:224
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_uconformant_array(WinPrNdrDecoder *context, wStream *s, const WinPrNdrArrayHints *hints, WinPrNdrMessageType itemType, void *vtarget)
reads a conformant array: its count and the items
Definition ndr.c:1361
UINT32 discriminant
Definition ndr.h:355
WINPR_NDR_DUMP_FN dumpFn
Definition ndr.h:300
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_skip_bytes(WinPrNdrDecoder *context, wStream *s, size_t nbytes)
skips bytes
Definition ndr.c:1164
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_pointedMessageEx(WinPrNdrDecoder *context, wStream *s, winpr_ndr_refid ptrId, WinPrNdrMessageType descr, void *hints, void **target)
reads the referent of a unique pointer
Definition ndr.c:1741
winpr_ndr_refid ptrId
Definition ndr.h:383
const WinPrNdrFieldStruct * fields
Definition ndr.h:346
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_fromDescr(WinPrNdrDecoder *context, wStream *s, const WinPrNdrStructDescr *descr, void *target)
reads a structure from its descriptor
Definition ndr.c:1695
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_data(WinPrNdrEncoder *context, wStream *s, const void *data, size_t sz)
writes raw bytes, without alignment
Definition ndr.c:1094
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_uconformant_varying_array(WinPrNdrDecoder *context, wStream *s, const WinPrNdrVaryingArrayHints *hints, WinPrNdrMessageType itemType, void *ptarget)
reads a conformant varying array: its maximum count, offset, actual count and the items
Definition ndr.c:1341
WINPR_ATTR_NODISCARD WINPR_API WinPrNdrMessageType winpr_ndr_wstring_varying_descr(void)
the message type of winpr_ndr_wstring_varying_descr_s
Definition ndr.c:898
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_treat_deferreds(WinPrNdrEncoder *context, wStream *s)
writes the pending deferred referents
Definition ndr.c:1075
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new(BOOL bigEndianDrep, BYTE version)
creates a decoder
Definition ndr.c:1106
WINPR_API WinPrNdrEncoder * winpr_ndr_encoder_new(BOOL bigEndianDrep, BYTE version)
creates an encoder
Definition ndr.c:194
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_union(WinPrNdrDecoder *context, wStream *s, const WinPrNdrUnionDescr *descr, UINT32 switchValue, void *target)
reads a union, its discriminant must be switchValue
Definition ndr.c:1922
WINPR_ATTR_NODISCARD WINPR_API WinPrNdrMessageType winpr_ndr_string_conformant_descr(void)
the message type of winpr_ndr_string_conformant_descr_s
Definition ndr.c:735
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_toplevel_refid(WinPrNdrEncoder *context, wStream *s)
writes a new referent id for a non-null top-level pointer
Definition ndr.c:317
WinPrNdrMessageType msg
Definition ndr.h:390
UINT32 rangeMax
Definition ndr.h:336
WINPR_NDR_DESTROY_FN destroyFn
Definition ndr.h:299
WINPR_ATTR_NODISCARD WINPR_API size_t winpr_ndr_pointer_size(const void *ptr)
the size of a referent, as allocated by winpr_ndr_pointer_new()
Definition ndr.c:1465
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_wchar(WinPrNdrDecoder *context, wStream *s, WCHAR *ptr)
reads a WCHAR, aligned on 2 bytes
Definition ndr.c:631
@ WINPR_NDR_ARITY_SIMPLE
Definition ndr.h:280
@ WINPR_NDR_ARITY_VARYING_ARRAYOF
Definition ndr.h:283
@ WINPR_NDR_ARITY_ARRAYOF
Definition ndr.h:281
@ WINPR_NDR_ARITY_SELF_ALLOCATED
Definition ndr.h:285
WINPR_API const WinPrNdrMessageDescr winpr_ndr_string_varying_descr_s
[string] char*: a conformant varying string of char, read in a char* allocated with winpr_ndr_pointer...
Definition ndr.c:822
WINPR_API void winpr_ndr_encoder_free(WinPrNdrEncoder *context)
frees an encoder
Definition ndr.c:213
WINPR_API const WinPrNdrMessageDescr winpr_ndr_wstring_varying_descr_s
[string] wchar_t*: a conformant varying string of WCHAR, read in a WCHAR* allocated with winpr_ndr_po...
Definition ndr.c:893
size_t switchSize
Definition ndr.h:372
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_refpointer(WinPrNdrDecoder *context, wStream *s, UINT32 *refId)
reads a referent id
Definition ndr.c:1194
WINPR_API void winpr_ndr_decoder_bytes_read(WinPrNdrDecoder *context, size_t len)
accounts for bytes read directly from the stream, for the alignments
Definition ndr.c:1158
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_align(WinPrNdrDecoder *context, wStream *s, size_t sz)
skips the padding to align the current object offset
Definition ndr.c:1176
SSIZE_T hintsField
Definition ndr.h:332
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_uconformant_varying_array(WinPrNdrEncoder *context, wStream *s, const WinPrNdrVaryingArrayHints *hints, WinPrNdrMessageType itemType, const void *src)
writes a conformant varying array: its maximum count, offset 0, actual count and the items
Definition ndr.c:916
WINPR_API WinPrNdrEncoder * winpr_ndr_encoder_from_decoder(const WinPrNdrDecoder *src)
creates an encoder with the same endianness and version as a decoder, to answer the message it decode...
Definition ndr.c:206
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_union(WinPrNdrEncoder *context, wStream *s, const WinPrNdrUnionDescr *descr, UINT32 switchValue, const void *src)
writes the discriminant and the arm of a union
Definition ndr.c:1903
WINPR_API void * winpr_ndr_pointer_new(WinPrNdrMessageType descr, const void *hints, size_t size)
allocates a referent
Definition ndr.c:1454
WINPR_API void winpr_ndr_encoder_bytes_written(WinPrNdrEncoder *context, size_t len)
accounts for bytes written directly in the stream, for the alignments
Definition ndr.c:218
WINPR_API void winpr_ndr_pointer_release(void *ptr)
releases a referent
Definition ndr.c:1483
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_object(WinPrNdrDecoder *context, wStream *s, wStream *object)
reads the private header of a serialized object ([MS-RPCE] 2.2.6 type serialization version 1)
Definition ndr.c:1199
const WinPrNdrUnionArm * arms
Definition ndr.h:371
const WinPrNdrUnionArm * defaultArm
Definition ndr.h:374
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new_fromStream(wStream *s)
reads the common type header ([MS-RPCE] 2.2.6.1) and creates a decoder for its version and endianness
Definition ndr.c:1124
size_t nfields
Definition ndr.h:345
WINPR_ATTR_NODISCARD WINPR_API WinPrNdrMessageType winpr_ndr_wchar_descr(void)
the message type of winpr_ndr_wchar_descr_s
Definition ndr.c:668
const char * name
Definition ndr.h:384
WINPR_ATTR_NODISCARD WINPR_API UINT32 winpr_ndr_union_switch_value(const WinPrNdrUnionDescr *descr, const void *switchField)
the value of the [switch_is()] field of a union
Definition ndr.c:1830
WINPR_API const WinPrNdrMessageDescr winpr_ndr_wchar_descr_s
a WCHAR, stored in UTF-16LE in memory
Definition ndr.c:663
WINPR_NDR_WRITER_FN writeFn
Definition ndr.h:298
WINPR_API void winpr_ndr_struct_destroy(const WinPrNdrStructDescr *descr, void *pptr)
releases the content of a structure from its descriptor
Definition ndr.c:2005
UINT32 count
Definition ndr.h:554
WINPR_NDR_READER_FN readFn
Definition ndr.h:297
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_fromDescr(WinPrNdrEncoder *context, wStream *s, const WinPrNdrStructDescr *descr, const void *src)
writes a structure from its descriptor
Definition ndr.c:1032
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_push_deferreds(WinPrNdrDecoder *context, WinPrNdrDeferredEntry *deferreds, size_t ndeferred)
adds deferred pointers, read by the next winpr_ndr_decoder_treat_deferreds()
Definition ndr.c:1803
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_uconformant_array(WinPrNdrEncoder *context, wStream *s, UINT32 len, WinPrNdrMessageType itemType, const BYTE *ptr)
writes a conformant array: its count and the items
Definition ndr.c:935
const char * name
Definition ndr.h:369
size_t itemSize
Definition ndr.h:296
WINPR_API const WinPrNdrMessageDescr winpr_ndr_string_conformant_descr_s
conformant string of char, read in a char* allocated with winpr_ndr_pointer_new()
Definition ndr.c:726
WINPR_API void winpr_ndr_union_destroy(const WinPrNdrUnionDescr *descr, UINT32 switchValue, void *obj)
releases the content of the arm switchValue of a union
Definition ndr.c:1952
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_align(WinPrNdrEncoder *context, wStream *s, size_t sz)
writes zero padding to align the current object offset
Definition ndr.c:240
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_pointer_ex(WinPrNdrDecoder *context, wStream *s, const char *name, WinPrNdrMessageType descr, void *hints, void **target)
reads a full pointer ([ptr])
Definition ndr.c:1596
#define WINPR_NDR_PTR_NULL
the referent id of a null pointer
Definition ndr.h:48
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_start_object(WinPrNdrEncoder *context, wStream *s)
starts a serialized object ([MS-RPCE] 2.2.6 type serialization version 1)
Definition ndr.c:259
size_t fixedArraySize
Definition ndr.h:335
WinPrNdrMessageType typeDescr
Definition ndr.h:334
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_treat_deferreds(WinPrNdrDecoder *context, wStream *s)
reads the pending deferred referents
Definition ndr.c:1714
hints for a conformant array
Definition ndr.h:553
a deferred pointer, a referent to read after the current construct
Definition ndr.h:382
descriptor of a field in a structure
Definition ndr.h:328
message descriptor
Definition ndr.h:294
structure descriptor
Definition ndr.h:343
an arm of a non-encapsulated union
Definition ndr.h:354
a non-encapsulated union ([switch_type()])
Definition ndr.h:368
hints for a conformant varying array
Definition ndr.h:526