FreeRDP
Loading...
Searching...
No Matches
ndr.c
1
19#include <winpr/assert.h>
20#include <winpr/collections.h>
21#include <winpr/wlog.h>
22
23#include <freerdp/log.h>
24
25#include <rdpear-common/ndr.h>
26
27#define TAG FREERDP_TAG("ndr")
28
29#define NDR_MAX_CONSTRUCTS 16
30#define NDR_MAX_DEFERRED 50
31
32struct NdrContext_s
33{
34 BYTE version;
35 BOOL bigEndianDrep;
36 size_t alignBytes;
37
38 int currentLevel;
39 size_t indentLevels[16];
40
41 int constructLevel;
42 size_t constructs[NDR_MAX_CONSTRUCTS];
43
44 wHashTable* refPointers;
45 size_t ndeferred;
46 NdrDeferredEntry deferred[NDR_MAX_DEFERRED];
47
48 UINT32 refIdCounter;
49};
50
51NdrContext* ndr_context_new(BOOL bigEndianDrep, BYTE version)
52{
53 NdrContext* ret = calloc(1, sizeof(*ret));
54 if (!ret)
55 return nullptr;
56
57 ret->version = version;
58 ret->bigEndianDrep = bigEndianDrep;
59 ret->alignBytes = 4;
60 ret->refPointers = HashTable_New(FALSE);
61 if (!ret->refPointers)
62 {
63 free(ret);
64 return nullptr;
65 }
66
67 ndr_context_reset(ret);
68 return ret;
69}
70
71void ndr_context_reset(NdrContext* context)
72{
73 WINPR_ASSERT(context);
74
75 context->currentLevel = 0;
76 context->constructLevel = -1;
77 memset(context->indentLevels, 0, sizeof(context->indentLevels));
78
79 if (context->refPointers)
80 HashTable_Clear(context->refPointers);
81 context->ndeferred = 0;
82 context->refIdCounter = 0x20000;
83}
84
85NdrContext* ndr_context_copy(const NdrContext* src)
86{
87 WINPR_ASSERT(src);
88
89 NdrContext* ret = calloc(1, sizeof(*ret));
90 if (!ret)
91 return nullptr;
92
93 *ret = *src;
94
95 ret->refPointers = HashTable_New(FALSE);
96 if (!ret->refPointers)
97 {
98 free(ret);
99 return nullptr;
100 }
101
102 ndr_context_reset(ret);
103 return ret;
104}
105
106void ndr_context_free(NdrContext* context)
107{
108 if (context)
109 {
110 HashTable_Free(context->refPointers);
111 free(context);
112 }
113}
114
115static void ndr_context_bytes_read(NdrContext* context, size_t len)
116{
117 WINPR_ASSERT(context);
118 context->indentLevels[context->currentLevel] += len;
119}
120
121static void ndr_context_bytes_written(NdrContext* context, size_t len)
122{
123 ndr_context_bytes_read(context, len);
124}
125
126NdrContext* ndr_read_header(wStream* s)
127{
128 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
129 return nullptr;
130
131 BYTE version = Stream_Get_UINT8(s);
132 BYTE drep = Stream_Get_UINT8(s);
133 UINT16 headerLen = Stream_Get_UINT16(s);
134
135 if (headerLen < 4 || !Stream_CheckAndLogRequiredLength(TAG, s, headerLen - 4))
136 return nullptr;
137
138 /* skip filler */
139 Stream_Seek(s, headerLen - 4);
140
141 return ndr_context_new((drep != 0x10), version);
142}
143
144BOOL ndr_write_header(NdrContext* context, wStream* s)
145{
146 WINPR_ASSERT(context);
147
148 if (!Stream_EnsureRemainingCapacity(s, 8))
149 return FALSE;
150
151 Stream_Write_UINT8(s, context->version);
152 Stream_Write_UINT8(s, context->bigEndianDrep ? 0x00 : 0x10);
153 Stream_Write_UINT16(s, 0x8); /* header len */
154
155 BYTE filler[] = { 0xcc, 0xcc, 0xcc, 0xcc };
156 Stream_Write(s, filler, sizeof(filler));
157 return TRUE;
158}
159
160BOOL ndr_skip_bytes(NdrContext* context, wStream* s, size_t nbytes)
161{
162 WINPR_ASSERT(context);
163
164 if (!Stream_CheckAndLogRequiredLength(TAG, s, nbytes))
165 return FALSE;
166
167 context->indentLevels[context->currentLevel] += nbytes;
168 Stream_Seek(s, nbytes);
169 return TRUE;
170}
171
172BOOL ndr_read_align(NdrContext* context, wStream* s, size_t sz)
173{
174 WINPR_ASSERT(context);
175
176 size_t rest = context->indentLevels[context->currentLevel] % sz;
177 if (rest)
178 {
179 size_t padding = (sz - rest);
180 if (!Stream_CheckAndLogRequiredLength(TAG, s, padding))
181 return FALSE;
182
183 Stream_Seek(s, padding);
184 context->indentLevels[context->currentLevel] += padding;
185 }
186
187 return TRUE;
188}
189
190BOOL ndr_write_align(NdrContext* context, wStream* s, size_t sz)
191{
192 WINPR_ASSERT(context);
193
194 size_t rest = context->indentLevels[context->currentLevel] % sz;
195 if (rest)
196 {
197 size_t padding = (sz - rest);
198
199 if (!Stream_EnsureRemainingCapacity(s, padding))
200 return FALSE;
201
202 Stream_Zero(s, padding);
203 context->indentLevels[context->currentLevel] += padding;
204 }
205
206 return TRUE;
207}
208
209BOOL ndr_read_pickle(NdrContext* context, wStream* s)
210{
211 WINPR_ASSERT(context);
212
213 UINT32 v = 0;
214
215 /* NDR format label */
216 return !(!ndr_read_uint32(context, s, &v) || v != 0x20000);
217}
218
219BOOL ndr_write_pickle(NdrContext* context, wStream* s)
220{
221 WINPR_ASSERT(context);
222
223 /* NDR format label */
224 return ndr_write_uint32(context, s, 0x20000);
225}
226
227BOOL ndr_read_constructed(NdrContext* context, wStream* s, wStream* target)
228{
229 WINPR_ASSERT(context);
230
231 UINT32 len = 0;
232
233 /* len */
234 if (!ndr_read_uint32(context, s, &len))
235 return FALSE;
236
237 /* padding */
238 if (!ndr_skip_bytes(context, s, 4))
239 return FALSE;
240
241 /* payload */
242 if (!Stream_CheckAndLogRequiredLength(TAG, s, len))
243 return FALSE;
244
245 Stream_StaticInit(target, Stream_PointerAs(s, BYTE), len);
246 Stream_Seek(s, len);
247 return TRUE;
248}
249
250BOOL ndr_start_constructed(NdrContext* context, wStream* s)
251{
252 WINPR_ASSERT(context);
253
254 if (!Stream_EnsureRemainingCapacity(s, 8))
255 return FALSE;
256
257 if (context->constructLevel == NDR_MAX_CONSTRUCTS)
258 return FALSE;
259
260 context->constructLevel++;
261 context->constructs[context->constructLevel] = Stream_GetPosition(s);
262
263 Stream_Zero(s, 8);
264 return TRUE;
265}
266
267BOOL ndr_end_constructed(NdrContext* context, wStream* s)
268{
269 WINPR_ASSERT(context);
270 WINPR_ASSERT(context->constructs);
271 WINPR_ASSERT(context->constructLevel >= 0);
272
273 size_t offset = context->constructs[context->constructLevel];
274
275 wStream staticS = WINPR_C_ARRAY_INIT;
276 Stream_StaticInit(&staticS, Stream_Buffer(s) + offset, 4);
277
278 /* len */
279 const size_t len = Stream_GetPosition(s) - (offset + 8);
280 if (len > UINT32_MAX)
281 return FALSE;
282 if (!ndr_write_uint32(context, &staticS, (UINT32)len))
283 return FALSE;
284
285 return TRUE;
286}
287
288static size_t ndr_hintsCount(NdrMessageType msgType, const void* hints)
289{
290 WINPR_ASSERT(msgType);
291
292 switch (msgType->arity)
293 {
294 case NDR_ARITY_SIMPLE:
295 return 1;
296 case NDR_ARITY_ARRAYOF:
297 WINPR_ASSERT(hints);
298 return ((const NdrArrayHints*)hints)->count;
299 case NDR_ARITY_VARYING_ARRAYOF:
300 WINPR_ASSERT(hints);
301 return ((const NdrVaryingArrayHints*)hints)->maxLength;
302 default:
303 WINPR_ASSERT(0 && "unknown arity");
304 return 0;
305 }
306}
307
308BOOL ndr_read_uint8(NdrContext* context, wStream* s, BYTE* v)
309{
310 WINPR_ASSERT(context);
311
312 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
313 return FALSE;
314
315 Stream_Read_UINT8(s, *v);
316
317 ndr_context_bytes_read(context, 1);
318 return TRUE;
319}
320
321BOOL ndr_read_uint8_(NdrContext* context, wStream* s, const void* hints, void* v)
322{
323 WINPR_UNUSED(hints);
324 return ndr_read_uint8(context, s, (BYTE*)v);
325}
326
327BOOL ndr_write_uint8(NdrContext* context, wStream* s, BYTE v)
328{
329 if (!Stream_EnsureRemainingCapacity(s, 1))
330 return FALSE;
331
332 Stream_Write_UINT8(s, v);
333 ndr_context_bytes_written(context, 1);
334 return TRUE;
335}
336
337BOOL ndr_write_uint8_(NdrContext* context, wStream* s, const void* hints, const void* v)
338{
339 WINPR_ASSERT(context);
340 WINPR_ASSERT(s);
341 WINPR_ASSERT(v);
342 WINPR_UNUSED(hints);
343
344 return ndr_write_uint8(context, s, *(const BYTE*)v);
345}
346
347const static NdrMessageDescr uint8_descr = { NDR_ARITY_SIMPLE, 1, ndr_read_uint8_,
348 ndr_write_uint8_, nullptr, nullptr };
349
350NdrMessageType ndr_uint8_descr(void)
351{
352 return &uint8_descr;
353}
354
355#define SIMPLE_TYPE_IMPL(UPPERTYPE, LOWERTYPE) \
356 BOOL ndr_read_##LOWERTYPE(NdrContext* context, wStream* s, UPPERTYPE* v) \
357 { \
358 WINPR_ASSERT(context); \
359 if (!ndr_read_align(context, s, sizeof(UPPERTYPE))) \
360 return FALSE; \
361 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(UPPERTYPE))) \
362 return FALSE; \
363 \
364 if (context->bigEndianDrep) \
365 Stream_Read_##UPPERTYPE##_BE(s, *v); \
366 else \
367 Stream_Read_##UPPERTYPE(s, *v); \
368 \
369 ndr_context_bytes_read(context, sizeof(UPPERTYPE)); \
370 return TRUE; \
371 } \
372 \
373 BOOL ndr_read_##LOWERTYPE##_(NdrContext* context, wStream* s, const void* hints, void* v) \
374 { \
375 WINPR_UNUSED(hints); \
376 return ndr_read_##LOWERTYPE(context, s, (UPPERTYPE*)v); \
377 } \
378 \
379 BOOL ndr_write_##LOWERTYPE(NdrContext* context, wStream* s, UPPERTYPE v) \
380 { \
381 if (!ndr_write_align(context, s, sizeof(UPPERTYPE)) || \
382 !Stream_EnsureRemainingCapacity(s, sizeof(UPPERTYPE))) \
383 return FALSE; \
384 \
385 if (context->bigEndianDrep) \
386 Stream_Write_##UPPERTYPE##_BE(s, v); \
387 else \
388 Stream_Write_##UPPERTYPE(s, v); \
389 \
390 ndr_context_bytes_written(context, sizeof(UPPERTYPE)); \
391 return TRUE; \
392 } \
393 \
394 BOOL ndr_write_##LOWERTYPE##_(NdrContext* context, wStream* s, const void* hints, \
395 const void* v) \
396 { \
397 WINPR_ASSERT(context); \
398 WINPR_ASSERT(s); \
399 WINPR_ASSERT(v); \
400 WINPR_UNUSED(hints); \
401 \
402 return ndr_write_##LOWERTYPE(context, s, *(const UPPERTYPE*)v); \
403 } \
404 \
405 const NdrMessageDescr ndr_##LOWERTYPE##_descr_s = { \
406 NDR_ARITY_SIMPLE, sizeof(UPPERTYPE), ndr_read_##LOWERTYPE##_, \
407 ndr_write_##LOWERTYPE##_, nullptr, nullptr \
408 }; \
409 \
410 NdrMessageType ndr_##LOWERTYPE##_descr(void) \
411 { \
412 return &ndr_##LOWERTYPE##_descr_s; \
413 }
414
415SIMPLE_TYPE_IMPL(UINT32, uint32)
416SIMPLE_TYPE_IMPL(UINT16, uint16)
417SIMPLE_TYPE_IMPL(UINT64, uint64)
418
419#define ARRAY_OF_TYPE_IMPL(TYPE, UPPERTYPE) \
420 BOOL ndr_read_##TYPE##Array(NdrContext* context, wStream* s, const void* hints, void* v) \
421 { \
422 WINPR_ASSERT(context); \
423 WINPR_ASSERT(s); \
424 WINPR_ASSERT(hints); \
425 return ndr_read_uconformant_array(context, s, hints, ndr_##TYPE##_descr(), v); \
426 } \
427 \
428 BOOL ndr_write_##TYPE##Array(NdrContext* context, wStream* s, const void* hints, \
429 const void* v) \
430 { \
431 WINPR_ASSERT(context); \
432 WINPR_ASSERT(s); \
433 WINPR_ASSERT(hints); \
434 const NdrArrayHints* ahints = (const NdrArrayHints*)hints; \
435 return ndr_write_uconformant_array(context, s, ahints->count, ndr_##TYPE##_descr(), v); \
436 } \
437 void ndr_destroy_##TYPE##Array(NdrContext* context, const void* hints, void* obj) \
438 { \
439 WINPR_ASSERT(context); \
440 WINPR_ASSERT(obj); \
441 WINPR_ASSERT(hints); \
442 const NdrArrayHints* ahints = (const NdrArrayHints*)hints; \
443 NdrMessageType descr = ndr_##TYPE##_descr(); \
444 if (descr->destroyFn) \
445 { \
446 UPPERTYPE* ptr = (UPPERTYPE*)obj; \
447 for (UINT32 i = 0; i < ahints->count; i++, ptr++) \
448 descr->destroyFn(context, nullptr, ptr); \
449 } \
450 } \
451 \
452 const NdrMessageDescr ndr_##TYPE##Array_descr_s = { \
453 NDR_ARITY_ARRAYOF, sizeof(UPPERTYPE), ndr_read_##TYPE##Array, \
454 ndr_write_##TYPE##Array, ndr_destroy_##TYPE##Array, nullptr \
455 }; \
456 \
457 NdrMessageType ndr_##TYPE##Array_descr(void) \
458 { \
459 return &ndr_##TYPE##Array_descr_s; \
460 } \
461 \
462 BOOL ndr_read_##TYPE##VaryingArray(NdrContext* context, wStream* s, const void* hints, \
463 void* v) \
464 { \
465 WINPR_ASSERT(context); \
466 WINPR_ASSERT(s); \
467 WINPR_ASSERT(hints); \
468 return ndr_read_uconformant_varying_array(context, s, (const NdrVaryingArrayHints*)hints, \
469 ndr_##TYPE##_descr(), v); \
470 } \
471 BOOL ndr_write_##TYPE##VaryingArray(NdrContext* context, wStream* s, const void* hints, \
472 const void* v) \
473 { \
474 WINPR_ASSERT(context); \
475 WINPR_ASSERT(s); \
476 WINPR_ASSERT(hints); \
477 return ndr_write_uconformant_varying_array(context, s, (const NdrVaryingArrayHints*)hints, \
478 ndr_##TYPE##_descr(), v); \
479 } \
480 \
481 const NdrMessageDescr ndr_##TYPE##VaryingArray_descr_s = { \
482 NDR_ARITY_VARYING_ARRAYOF, sizeof(UPPERTYPE), ndr_read_##TYPE##VaryingArray, \
483 ndr_write_##TYPE##VaryingArray, nullptr, nullptr \
484 }; \
485 \
486 NdrMessageType ndr_##TYPE##VaryingArray_descr(void) \
487 { \
488 return &ndr_##TYPE##VaryingArray_descr_s; \
489 }
490
491ARRAY_OF_TYPE_IMPL(uint8, BYTE)
492ARRAY_OF_TYPE_IMPL(uint16, UINT16)
493
494BOOL ndr_read_wchar(NdrContext* context, wStream* s, WCHAR* ptr)
495{
496 return ndr_read_uint16(context, s, (UINT16*)ptr);
497}
498
499BOOL ndr_read_uconformant_varying_array(NdrContext* context, wStream* s,
500 const NdrVaryingArrayHints* hints, NdrMessageType itemType,
501 void* ptarget)
502{
503 WINPR_ASSERT(context);
504 WINPR_ASSERT(s);
505 WINPR_ASSERT(hints);
506 WINPR_ASSERT(itemType);
507 WINPR_ASSERT(ptarget);
508
509 if (itemType->itemSize == 0)
510 return FALSE;
511
512 UINT32 maxCount = 0;
513 UINT32 offset = 0;
514 UINT32 length = 0;
515
516 if (!ndr_read_uint32(context, s, &maxCount) || !ndr_read_uint32(context, s, &offset) ||
517 !ndr_read_uint32(context, s, &length))
518 return FALSE;
519
520 if ((1ull * length * itemType->itemSize) > hints->length)
521 return FALSE;
522
523 if ((1ull * maxCount * itemType->itemSize) > hints->maxLength)
524 return FALSE;
525
526 BYTE* target = (BYTE*)ptarget;
527 for (UINT32 i = 0; i < length; i++, target += itemType->itemSize)
528 {
529 if (!itemType->readFn(context, s, nullptr, target))
530 return FALSE;
531 }
532
533 return ndr_read_align(context, s, 4);
534}
535
536BOOL ndr_write_uconformant_varying_array(NdrContext* context, wStream* s,
537 const NdrVaryingArrayHints* hints, NdrMessageType itemType,
538 const void* psrc)
539{
540 WINPR_ASSERT(context);
541 WINPR_ASSERT(s);
542 WINPR_ASSERT(hints);
543 WINPR_ASSERT(itemType);
544 WINPR_ASSERT(psrc);
545
546 if (itemType->itemSize == 0)
547 return FALSE;
548
549 if (!ndr_write_uint32(context, s, hints->maxLength) || !ndr_write_uint32(context, s, 0) ||
550 !ndr_write_uint32(context, s, hints->length))
551 return FALSE;
552
553 const BYTE* src = (const BYTE*)psrc;
554 for (UINT32 i = 0; i < hints->length; i++, src += itemType->itemSize)
555 {
556 if (!itemType->writeFn(context, s, nullptr, src))
557 return FALSE;
558 }
559
560 return TRUE;
561}
562
563BOOL ndr_read_uconformant_array(NdrContext* context, wStream* s, const NdrArrayHints* hints,
564 NdrMessageType itemType, void* vtarget)
565{
566 WINPR_ASSERT(context);
567 WINPR_ASSERT(s);
568 WINPR_ASSERT(itemType);
569 WINPR_ASSERT(vtarget);
570
571 if (itemType->itemSize == 0)
572 return FALSE;
573
574 UINT32 count = 0;
575 if (!ndr_read_uint32(context, s, &count))
576 return FALSE;
577
578 if (itemType->arity == NDR_ARITY_SIMPLE)
579 {
580 if (count > hints->count)
581 return FALSE;
582 }
583 else
584 {
585 if ((1ull * count * itemType->itemSize) > hints->count)
586 return FALSE;
587 }
588
589 BYTE* target = (BYTE*)vtarget;
590 for (UINT32 i = 0; i < count; i++, target += itemType->itemSize)
591 {
592 if (!itemType->readFn(context, s, nullptr, target))
593 return FALSE;
594 }
595
596 return ndr_read_align(context, s, /*context->alignBytes*/ 4);
597}
598
599BOOL ndr_write_uconformant_array(NdrContext* context, wStream* s, UINT32 len,
600 NdrMessageType itemType, const BYTE* ptr)
601{
602 WINPR_ASSERT(context);
603 WINPR_ASSERT(s);
604 WINPR_ASSERT(itemType);
605 WINPR_ASSERT(ptr);
606
607 size_t toWrite = len * itemType->itemSize;
608 size_t padding = (4 - (toWrite % 4)) % 4;
609 if (!ndr_write_uint32(context, s, len) || !Stream_EnsureRemainingCapacity(s, toWrite + padding))
610 return FALSE;
611
612 for (UINT32 i = 0; i < len; i++, ptr += itemType->itemSize)
613 {
614 if (!itemType->writeFn(context, s, nullptr, ptr))
615 return FALSE;
616 }
617
618 if (padding)
619 {
620 Stream_Zero(s, padding);
621 ndr_context_bytes_written(context, padding);
622 }
623 return TRUE;
624}
625
626BOOL ndr_struct_read_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
627 void* target)
628{
629 WINPR_ASSERT(context);
630 WINPR_ASSERT(s);
631 WINPR_ASSERT(descr);
632 WINPR_ASSERT(target);
633
634#define NDR_MAX_STRUCT_DEFERRED 16
635 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = WINPR_C_ARRAY_INIT;
636 size_t ndeferred = 0;
637
638 for (size_t i = 0; i < descr->nfields; i++)
639 {
640 const NdrFieldStruct* field = &descr->fields[i];
641 BYTE* ptr = target;
642 ptr += field->structOffset;
643 void* hints = nullptr;
644
645 if (field->hintsField >= 0)
646 {
647 /* computes the address of the hints field if any */
648 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
649 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
650
651 hints = (BYTE*)target + hintsField->structOffset;
652 }
653
654 switch (field->pointerType)
655 {
656 case NDR_NOT_POINTER:
657 if (!field->typeDescr->readFn(context, s, hints, ptr))
658 {
659 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
660 return FALSE;
661 }
662 break;
663 case NDR_POINTER:
664 case NDR_POINTER_NON_NULL:
665 {
666 NdrDeferredEntry* deferred = &deferreds[ndeferred];
667 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
668 {
669 WLog_ERR(TAG, "too many deferred when calling ndr_read_struct_fromDescr for %s",
670 descr->name);
671 return FALSE;
672 }
673
674 deferred->name = field->name;
675 deferred->hints = hints;
676 deferred->target = ptr;
677 deferred->msg = field->typeDescr;
678 if (!ndr_read_refpointer(context, s, &deferred->ptrId))
679 {
680 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
681 return FALSE;
682 }
683
684 if (!deferred->ptrId && field->pointerType == NDR_POINTER_NON_NULL)
685 {
686 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
687 return FALSE;
688 }
689 ndeferred++;
690 break;
691 }
692 default:
693 WLog_ERR(TAG, "%s.%s unknown pointer type 0x%x", descr->name, field->name,
694 field->pointerType);
695 return FALSE;
696 }
697 }
698
699 return ndr_push_deferreds(context, deferreds, ndeferred);
700}
701
702BOOL ndr_struct_write_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
703 const void* src)
704{
705 WINPR_ASSERT(context);
706 WINPR_ASSERT(s);
707 WINPR_ASSERT(descr);
708 WINPR_ASSERT(src);
709
710 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = WINPR_C_ARRAY_INIT;
711 size_t ndeferred = 0;
712
713 for (size_t i = 0; i < descr->nfields; i++)
714 {
715 const NdrFieldStruct* field = &descr->fields[i];
716 const BYTE* ptr = (const BYTE*)src + field->structOffset;
717
718 const void* hints = nullptr;
719
720 if (field->hintsField >= 0)
721 {
722 /* computes the address of the hints field if any */
723 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
724 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
725
726 hints = (const BYTE*)src + hintsField->structOffset;
727 }
728
729 switch (field->pointerType)
730 {
731 case NDR_POINTER:
732 case NDR_POINTER_NON_NULL:
733 {
734 ndr_refid ptrId = NDR_PTR_NULL;
735 BOOL isNew = 0;
736 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
737
738 if (!ptr && field->pointerType == NDR_POINTER_NON_NULL)
739 {
740 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
741 return FALSE;
742 }
743
744 if (!ndr_context_allocatePtr(context, ptr, &ptrId, &isNew))
745 return FALSE;
746
747 if (isNew)
748 {
749 NdrDeferredEntry* deferred = &deferreds[ndeferred];
750 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
751 {
752 WLog_ERR(TAG,
753 "too many deferred when calling ndr_read_struct_fromDescr for %s",
754 descr->name);
755 return FALSE;
756 }
757
758 deferred->name = field->name;
759 deferred->hints = WINPR_CAST_CONST_PTR_AWAY(hints, void*);
760 deferred->target = WINPR_CAST_CONST_PTR_AWAY(ptr, void*);
761 deferred->msg = field->typeDescr;
762 ndeferred++;
763 }
764
765 if (!ndr_write_uint32(context, s, ptrId))
766 return FALSE;
767 break;
768 }
769 case NDR_NOT_POINTER:
770 if (!field->typeDescr->writeFn(context, s, hints, ptr))
771 {
772 WLog_ERR(TAG, "error when writing %s.%s", descr->name, field->name);
773 return FALSE;
774 }
775 break;
776 default:
777 break;
778 }
779 }
780
781 return ndr_push_deferreds(context, deferreds, ndeferred);
782}
783
784void ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
785 const NdrStructDescr* descr, const void* obj)
786{
787 char tabArray[30 + 1];
788 size_t ntabs = (identLevel <= 30) ? identLevel : 30;
789
790 memset(tabArray, '\t', ntabs);
791 tabArray[ntabs] = 0;
792
793 WLog_Print(logger, lvl, "%s%s", tabArray, descr->name);
794 for (size_t i = 0; i < descr->nfields; i++)
795 {
796 const NdrFieldStruct* field = &descr->fields[i];
797 const BYTE* ptr = (const BYTE*)obj + field->structOffset;
798
799 switch (field->pointerType)
800 {
801 case NDR_POINTER:
802 case NDR_POINTER_NON_NULL:
803 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
804 break;
805 case NDR_NOT_POINTER:
806 break;
807 default:
808 WLog_ERR(TAG, "invalid field->pointerType");
809 break;
810 }
811
812 WLog_Print(logger, lvl, "%s*%s:", tabArray, field->name);
813 if (field->typeDescr->dumpFn)
814 field->typeDescr->dumpFn(logger, lvl, identLevel + 1, ptr);
815 else
816 WLog_Print(logger, lvl, "%s\t<no dump function>", tabArray);
817 }
818}
819
820void ndr_struct_destroy(NdrContext* context, const NdrStructDescr* descr, void* pptr)
821{
822 WINPR_ASSERT(context);
823 WINPR_ASSERT(descr);
824 WINPR_ASSERT(pptr);
825
826 for (size_t i = 0; i < descr->nfields; i++)
827 {
828 const NdrFieldStruct* field = &descr->fields[i];
829 void* ptr = (BYTE*)pptr + field->structOffset;
830 void* hints = nullptr;
831
832 if (field->hintsField >= 0)
833 {
834 /* computes the address of the hints field if any */
835 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
836 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
837
838 hints = (BYTE*)pptr + hintsField->structOffset;
839 }
840
841 if (field->pointerType != NDR_NOT_POINTER)
842 ptr = *(void**)ptr;
843
844 if (ptr && field->typeDescr->destroyFn)
845 field->typeDescr->destroyFn(context, hints, ptr);
846
847 if (field->pointerType != NDR_NOT_POINTER)
848 free(ptr);
849 }
850}
851
852ndr_refid ndr_pointer_refid(const void* ptr)
853{
854 return (ndr_refid)((ULONG_PTR)ptr);
855}
856
857BOOL ndr_read_refpointer(NdrContext* context, wStream* s, ndr_refid* refId)
858{
859 return ndr_read_uint32(context, s, refId);
860}
861
862typedef struct
863{
864 const void* needle;
865 ndr_refid* presult;
866} FindValueArgs;
867
868static BOOL findValueRefFn(const void* key, void* value, void* parg)
869{
870 WINPR_ASSERT(parg);
871
872 FindValueArgs* args = (FindValueArgs*)parg;
873 if (args->needle == value)
874 {
875 *args->presult = (ndr_refid)(UINT_PTR)key;
876 return FALSE;
877 }
878 return TRUE;
879}
880
881BOOL ndr_context_allocatePtr(NdrContext* context, const void* ptr, ndr_refid* prefId, BOOL* pnewPtr)
882{
883 WINPR_ASSERT(context);
884
885 FindValueArgs findArgs = { ptr, prefId };
886 if (!HashTable_Foreach(context->refPointers, findValueRefFn, &findArgs))
887 {
888 *pnewPtr = FALSE;
889 return TRUE;
890 }
891
892 *pnewPtr = TRUE;
893 *prefId = context->refIdCounter + 4;
894 if (!HashTable_Insert(context->refPointers, (void*)(UINT_PTR)(*prefId), ptr))
895 return FALSE;
896
897 context->refIdCounter += 4;
898 return TRUE;
899}
900
901BOOL ndr_read_pointedMessageEx(NdrContext* context, wStream* s, ndr_refid ptrId,
902 NdrMessageType descr, void* hints, void** target)
903{
904 WINPR_ASSERT(context);
905 WINPR_ASSERT(s);
906 WINPR_ASSERT(descr);
907 WINPR_ASSERT(target);
908
909 *target = nullptr;
910 if (!ptrId)
911 return TRUE;
912
913 void* ret = HashTable_GetItemValue(context->refPointers, (void*)(UINT_PTR)ptrId);
914 if (!ret)
915 {
916 size_t itemCount = ndr_hintsCount(descr, hints);
917 if (itemCount == 0)
918 return FALSE;
919 ret = calloc(itemCount, descr->itemSize);
920 if (!ret)
921 return FALSE;
922
923 if (!descr->readFn(context, s, hints, ret) ||
924 !HashTable_Insert(context->refPointers, (void*)(UINT_PTR)ptrId, ret))
925 {
926 if (descr->destroyFn)
927 descr->destroyFn(context, hints, ret);
928 free(ret);
929 return FALSE;
930 }
931 }
932 else
933 {
934 WLog_ERR(TAG, "aliased pointer aren't supported for now");
935 return FALSE;
936 }
937
938 *target = ret;
939 return TRUE;
940}
941
942BOOL ndr_push_deferreds(NdrContext* context, NdrDeferredEntry* deferreds, size_t ndeferred)
943{
944 WINPR_ASSERT(context);
945 WINPR_ASSERT(deferreds);
946
947 if (!ndeferred)
948 return TRUE;
949
950 if (context->ndeferred + ndeferred > NDR_MAX_DEFERRED)
951 {
952 WLog_ERR(TAG, "too many deferred");
953 return FALSE;
954 }
955
956 for (size_t i = ndeferred; i > 0; i--, context->ndeferred++)
957 {
958 context->deferred[context->ndeferred] = deferreds[i - 1];
959 }
960 return TRUE;
961}
962
963BOOL ndr_treat_deferred_read(NdrContext* context, wStream* s)
964{
965 WINPR_ASSERT(context);
966 WINPR_ASSERT(s);
967
968 while (context->ndeferred)
969 {
970 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
971 context->ndeferred--;
972
973 WLog_VRB(TAG, "treating read deferred 0x%x for %s", current.ptrId, current.name);
974 if (!ndr_read_pointedMessageEx(context, s, current.ptrId, current.msg, current.hints,
975 (void**)current.target))
976 {
977 WLog_ERR(TAG, "error parsing deferred %s", current.name);
978 return FALSE;
979 }
980 }
981
982 return TRUE;
983}
984
985BOOL ndr_treat_deferred_write(NdrContext* context, wStream* s)
986{
987 WINPR_ASSERT(context);
988 WINPR_ASSERT(s);
989
990 while (context->ndeferred)
991 {
992 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
993 context->ndeferred--;
994
995 WLog_VRB(TAG, "treating write deferred for %s", current.name);
996 if (!current.msg->writeFn(context, s, current.hints, current.target))
997 {
998 WLog_ERR(TAG, "error writing deferred %s", current.name);
999 return FALSE;
1000 }
1001 }
1002
1003 return TRUE;
1004}
1005
1006BOOL ndr_write_data(NdrContext* context, wStream* s, const void* data, size_t sz)
1007{
1008 if (!Stream_EnsureRemainingCapacity(s, sz))
1009 return FALSE;
1010
1011 Stream_Write(s, data, sz);
1012 ndr_context_bytes_written(context, sz);
1013 return TRUE;
1014}
hints for a conformant array
Definition ndr.h:210
a deferred pointer
Definition ndr.h:123
descriptor of a field in a structure
Definition ndr.h:105
message descriptor
Definition ndr.h:84
structure descriptor
Definition ndr.h:115
hints for a varying conformant array
Definition ndr.h:195