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 \
360 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(UPPERTYPE))) \
361 return FALSE; \
362 \
363 if (!ndr_read_align(context, s, sizeof(UPPERTYPE))) \
364 return FALSE; \
365 \
366 if (context->bigEndianDrep) \
367 Stream_Read_##UPPERTYPE##_BE(s, *v); \
368 else \
369 Stream_Read_##UPPERTYPE(s, *v); \
370 \
371 ndr_context_bytes_read(context, sizeof(UPPERTYPE)); \
372 return TRUE; \
373 } \
374 \
375 BOOL ndr_read_##LOWERTYPE##_(NdrContext* context, wStream* s, const void* hints, void* v) \
376 { \
377 WINPR_UNUSED(hints); \
378 return ndr_read_##LOWERTYPE(context, s, (UPPERTYPE*)v); \
379 } \
380 \
381 BOOL ndr_write_##LOWERTYPE(NdrContext* context, wStream* s, UPPERTYPE v) \
382 { \
383 if (!ndr_write_align(context, s, sizeof(UPPERTYPE)) || \
384 !Stream_EnsureRemainingCapacity(s, sizeof(UPPERTYPE))) \
385 return FALSE; \
386 \
387 if (context->bigEndianDrep) \
388 Stream_Write_##UPPERTYPE##_BE(s, v); \
389 else \
390 Stream_Write_##UPPERTYPE(s, v); \
391 \
392 ndr_context_bytes_written(context, sizeof(UPPERTYPE)); \
393 return TRUE; \
394 } \
395 \
396 BOOL ndr_write_##LOWERTYPE##_(NdrContext* context, wStream* s, const void* hints, \
397 const void* v) \
398 { \
399 WINPR_ASSERT(context); \
400 WINPR_ASSERT(s); \
401 WINPR_ASSERT(v); \
402 WINPR_UNUSED(hints); \
403 \
404 return ndr_write_##LOWERTYPE(context, s, *(const UPPERTYPE*)v); \
405 } \
406 \
407 const NdrMessageDescr ndr_##LOWERTYPE##_descr_s = { \
408 NDR_ARITY_SIMPLE, sizeof(UPPERTYPE), ndr_read_##LOWERTYPE##_, \
409 ndr_write_##LOWERTYPE##_, nullptr, nullptr \
410 }; \
411 \
412 NdrMessageType ndr_##LOWERTYPE##_descr(void) \
413 { \
414 return &ndr_##LOWERTYPE##_descr_s; \
415 }
416
417SIMPLE_TYPE_IMPL(UINT32, uint32)
418SIMPLE_TYPE_IMPL(UINT16, uint16)
419SIMPLE_TYPE_IMPL(UINT64, uint64)
420
421#define ARRAY_OF_TYPE_IMPL(TYPE, UPPERTYPE) \
422 BOOL ndr_read_##TYPE##Array(NdrContext* context, wStream* s, const void* hints, void* v) \
423 { \
424 WINPR_ASSERT(context); \
425 WINPR_ASSERT(s); \
426 WINPR_ASSERT(hints); \
427 return ndr_read_uconformant_array(context, s, hints, ndr_##TYPE##_descr(), v); \
428 } \
429 \
430 BOOL ndr_write_##TYPE##Array(NdrContext* context, wStream* s, const void* hints, \
431 const void* v) \
432 { \
433 WINPR_ASSERT(context); \
434 WINPR_ASSERT(s); \
435 WINPR_ASSERT(hints); \
436 const NdrArrayHints* ahints = (const NdrArrayHints*)hints; \
437 return ndr_write_uconformant_array(context, s, ahints->count, ndr_##TYPE##_descr(), v); \
438 } \
439 void ndr_destroy_##TYPE##Array(NdrContext* context, const void* hints, void* obj) \
440 { \
441 WINPR_ASSERT(context); \
442 WINPR_ASSERT(obj); \
443 WINPR_ASSERT(hints); \
444 const NdrArrayHints* ahints = (const NdrArrayHints*)hints; \
445 NdrMessageType descr = ndr_##TYPE##_descr(); \
446 if (descr->destroyFn) \
447 { \
448 UPPERTYPE* ptr = (UPPERTYPE*)obj; \
449 for (UINT32 i = 0; i < ahints->count; i++, ptr++) \
450 descr->destroyFn(context, nullptr, ptr); \
451 } \
452 } \
453 \
454 const NdrMessageDescr ndr_##TYPE##Array_descr_s = { \
455 NDR_ARITY_ARRAYOF, sizeof(UPPERTYPE), ndr_read_##TYPE##Array, \
456 ndr_write_##TYPE##Array, ndr_destroy_##TYPE##Array, nullptr \
457 }; \
458 \
459 NdrMessageType ndr_##TYPE##Array_descr(void) \
460 { \
461 return &ndr_##TYPE##Array_descr_s; \
462 } \
463 \
464 BOOL ndr_read_##TYPE##VaryingArray(NdrContext* context, wStream* s, const void* hints, \
465 void* v) \
466 { \
467 WINPR_ASSERT(context); \
468 WINPR_ASSERT(s); \
469 WINPR_ASSERT(hints); \
470 return ndr_read_uconformant_varying_array(context, s, (const NdrVaryingArrayHints*)hints, \
471 ndr_##TYPE##_descr(), v); \
472 } \
473 BOOL ndr_write_##TYPE##VaryingArray(NdrContext* context, wStream* s, const void* hints, \
474 const void* v) \
475 { \
476 WINPR_ASSERT(context); \
477 WINPR_ASSERT(s); \
478 WINPR_ASSERT(hints); \
479 return ndr_write_uconformant_varying_array(context, s, (const NdrVaryingArrayHints*)hints, \
480 ndr_##TYPE##_descr(), v); \
481 } \
482 \
483 const NdrMessageDescr ndr_##TYPE##VaryingArray_descr_s = { \
484 NDR_ARITY_VARYING_ARRAYOF, sizeof(UPPERTYPE), ndr_read_##TYPE##VaryingArray, \
485 ndr_write_##TYPE##VaryingArray, nullptr, nullptr \
486 }; \
487 \
488 NdrMessageType ndr_##TYPE##VaryingArray_descr(void) \
489 { \
490 return &ndr_##TYPE##VaryingArray_descr_s; \
491 }
492
493ARRAY_OF_TYPE_IMPL(uint8, BYTE)
494ARRAY_OF_TYPE_IMPL(uint16, UINT16)
495
496BOOL ndr_read_wchar(NdrContext* context, wStream* s, WCHAR* ptr)
497{
498 return ndr_read_uint16(context, s, (UINT16*)ptr);
499}
500
501BOOL ndr_read_uconformant_varying_array(NdrContext* context, wStream* s,
502 const NdrVaryingArrayHints* hints, NdrMessageType itemType,
503 void* ptarget)
504{
505 WINPR_ASSERT(context);
506 WINPR_ASSERT(s);
507 WINPR_ASSERT(hints);
508 WINPR_ASSERT(itemType);
509 WINPR_ASSERT(ptarget);
510
511 if (itemType->itemSize == 0)
512 return FALSE;
513
514 UINT32 maxCount = 0;
515 UINT32 offset = 0;
516 UINT32 length = 0;
517
518 if (!ndr_read_uint32(context, s, &maxCount) || !ndr_read_uint32(context, s, &offset) ||
519 !ndr_read_uint32(context, s, &length))
520 return FALSE;
521
522 if ((1ull * length * itemType->itemSize) > hints->length)
523 return FALSE;
524
525 if ((1ull * maxCount * itemType->itemSize) > hints->maxLength)
526 return FALSE;
527
528 BYTE* target = (BYTE*)ptarget;
529 for (UINT32 i = 0; i < length; i++, target += itemType->itemSize)
530 {
531 if (!itemType->readFn(context, s, nullptr, target))
532 return FALSE;
533 }
534
535 return ndr_read_align(context, s, 4);
536}
537
538BOOL ndr_write_uconformant_varying_array(NdrContext* context, wStream* s,
539 const NdrVaryingArrayHints* hints, NdrMessageType itemType,
540 const void* psrc)
541{
542 WINPR_ASSERT(context);
543 WINPR_ASSERT(s);
544 WINPR_ASSERT(hints);
545 WINPR_ASSERT(itemType);
546 WINPR_ASSERT(psrc);
547
548 if (itemType->itemSize == 0)
549 return FALSE;
550
551 if (!ndr_write_uint32(context, s, hints->maxLength) || !ndr_write_uint32(context, s, 0) ||
552 !ndr_write_uint32(context, s, hints->length))
553 return FALSE;
554
555 const BYTE* src = (const BYTE*)psrc;
556 for (UINT32 i = 0; i < hints->length; i++, src += itemType->itemSize)
557 {
558 if (!itemType->writeFn(context, s, nullptr, src))
559 return FALSE;
560 }
561
562 return TRUE;
563}
564
565BOOL ndr_read_uconformant_array(NdrContext* context, wStream* s, const NdrArrayHints* hints,
566 NdrMessageType itemType, void* vtarget)
567{
568 WINPR_ASSERT(context);
569 WINPR_ASSERT(s);
570 WINPR_ASSERT(itemType);
571 WINPR_ASSERT(vtarget);
572
573 if (itemType->itemSize == 0)
574 return FALSE;
575
576 UINT32 count = 0;
577 if (!ndr_read_uint32(context, s, &count))
578 return FALSE;
579
580 if (itemType->arity == NDR_ARITY_SIMPLE)
581 {
582 if (count > hints->count)
583 return FALSE;
584 }
585 else
586 {
587 if ((1ull * count * itemType->itemSize) > hints->count)
588 return FALSE;
589 }
590
591 BYTE* target = (BYTE*)vtarget;
592 for (UINT32 i = 0; i < count; i++, target += itemType->itemSize)
593 {
594 if (!itemType->readFn(context, s, nullptr, target))
595 return FALSE;
596 }
597
598 return ndr_read_align(context, s, /*context->alignBytes*/ 4);
599}
600
601BOOL ndr_write_uconformant_array(NdrContext* context, wStream* s, UINT32 len,
602 NdrMessageType itemType, const BYTE* ptr)
603{
604 WINPR_ASSERT(context);
605 WINPR_ASSERT(s);
606 WINPR_ASSERT(itemType);
607 WINPR_ASSERT(ptr);
608
609 size_t toWrite = len * itemType->itemSize;
610 size_t padding = (4 - (toWrite % 4)) % 4;
611 if (!ndr_write_uint32(context, s, len) || !Stream_EnsureRemainingCapacity(s, toWrite + padding))
612 return FALSE;
613
614 for (UINT32 i = 0; i < len; i++, ptr += itemType->itemSize)
615 {
616 if (!itemType->writeFn(context, s, nullptr, ptr))
617 return FALSE;
618 }
619
620 if (padding)
621 {
622 Stream_Zero(s, padding);
623 ndr_context_bytes_written(context, padding);
624 }
625 return TRUE;
626}
627
628BOOL ndr_struct_read_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
629 void* target)
630{
631 WINPR_ASSERT(context);
632 WINPR_ASSERT(s);
633 WINPR_ASSERT(descr);
634 WINPR_ASSERT(target);
635
636#define NDR_MAX_STRUCT_DEFERRED 16
637 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = WINPR_C_ARRAY_INIT;
638 size_t ndeferred = 0;
639
640 for (size_t i = 0; i < descr->nfields; i++)
641 {
642 const NdrFieldStruct* field = &descr->fields[i];
643 BYTE* ptr = target;
644 ptr += field->structOffset;
645 void* hints = nullptr;
646
647 if (field->hintsField >= 0)
648 {
649 /* computes the address of the hints field if any */
650 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
651 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
652
653 hints = (BYTE*)target + hintsField->structOffset;
654 }
655
656 switch (field->pointerType)
657 {
658 case NDR_NOT_POINTER:
659 if (!field->typeDescr->readFn(context, s, hints, ptr))
660 {
661 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
662 return FALSE;
663 }
664 break;
665 case NDR_POINTER:
666 case NDR_POINTER_NON_NULL:
667 {
668 NdrDeferredEntry* deferred = &deferreds[ndeferred];
669 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
670 {
671 WLog_ERR(TAG, "too many deferred when calling ndr_read_struct_fromDescr for %s",
672 descr->name);
673 return FALSE;
674 }
675
676 deferred->name = field->name;
677 deferred->hints = hints;
678 deferred->target = ptr;
679 deferred->msg = field->typeDescr;
680 if (!ndr_read_refpointer(context, s, &deferred->ptrId))
681 {
682 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
683 return FALSE;
684 }
685
686 if (!deferred->ptrId && field->pointerType == NDR_POINTER_NON_NULL)
687 {
688 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
689 return FALSE;
690 }
691 ndeferred++;
692 break;
693 }
694 default:
695 WLog_ERR(TAG, "%s.%s unknown pointer type 0x%x", descr->name, field->name,
696 field->pointerType);
697 return FALSE;
698 }
699 }
700
701 return ndr_push_deferreds(context, deferreds, ndeferred);
702}
703
704BOOL ndr_struct_write_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
705 const void* src)
706{
707 WINPR_ASSERT(context);
708 WINPR_ASSERT(s);
709 WINPR_ASSERT(descr);
710 WINPR_ASSERT(src);
711
712 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = WINPR_C_ARRAY_INIT;
713 size_t ndeferred = 0;
714
715 for (size_t i = 0; i < descr->nfields; i++)
716 {
717 const NdrFieldStruct* field = &descr->fields[i];
718 const BYTE* ptr = (const BYTE*)src + field->structOffset;
719
720 const void* hints = nullptr;
721
722 if (field->hintsField >= 0)
723 {
724 /* computes the address of the hints field if any */
725 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
726 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
727
728 hints = (const BYTE*)src + hintsField->structOffset;
729 }
730
731 switch (field->pointerType)
732 {
733 case NDR_POINTER:
734 case NDR_POINTER_NON_NULL:
735 {
736 ndr_refid ptrId = NDR_PTR_NULL;
737 BOOL isNew = 0;
738 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
739
740 if (!ptr && field->pointerType == NDR_POINTER_NON_NULL)
741 {
742 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
743 return FALSE;
744 }
745
746 if (!ndr_context_allocatePtr(context, ptr, &ptrId, &isNew))
747 return FALSE;
748
749 if (isNew)
750 {
751 NdrDeferredEntry* deferred = &deferreds[ndeferred];
752 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
753 {
754 WLog_ERR(TAG,
755 "too many deferred when calling ndr_read_struct_fromDescr for %s",
756 descr->name);
757 return FALSE;
758 }
759
760 deferred->name = field->name;
761 deferred->hints = WINPR_CAST_CONST_PTR_AWAY(hints, void*);
762 deferred->target = WINPR_CAST_CONST_PTR_AWAY(ptr, void*);
763 deferred->msg = field->typeDescr;
764 ndeferred++;
765 }
766
767 if (!ndr_write_uint32(context, s, ptrId))
768 return FALSE;
769 break;
770 }
771 case NDR_NOT_POINTER:
772 if (!field->typeDescr->writeFn(context, s, hints, ptr))
773 {
774 WLog_ERR(TAG, "error when writing %s.%s", descr->name, field->name);
775 return FALSE;
776 }
777 break;
778 default:
779 break;
780 }
781 }
782
783 return ndr_push_deferreds(context, deferreds, ndeferred);
784}
785
786void ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
787 const NdrStructDescr* descr, const void* obj)
788{
789 char tabArray[30 + 1];
790 size_t ntabs = (identLevel <= 30) ? identLevel : 30;
791
792 memset(tabArray, '\t', ntabs);
793 tabArray[ntabs] = 0;
794
795 WLog_Print(logger, lvl, "%s%s", tabArray, descr->name);
796 for (size_t i = 0; i < descr->nfields; i++)
797 {
798 const NdrFieldStruct* field = &descr->fields[i];
799 const BYTE* ptr = (const BYTE*)obj + field->structOffset;
800
801 switch (field->pointerType)
802 {
803 case NDR_POINTER:
804 case NDR_POINTER_NON_NULL:
805 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
806 break;
807 case NDR_NOT_POINTER:
808 break;
809 default:
810 WLog_ERR(TAG, "invalid field->pointerType");
811 break;
812 }
813
814 WLog_Print(logger, lvl, "%s*%s:", tabArray, field->name);
815 if (field->typeDescr->dumpFn)
816 field->typeDescr->dumpFn(logger, lvl, identLevel + 1, ptr);
817 else
818 WLog_Print(logger, lvl, "%s\t<no dump function>", tabArray);
819 }
820}
821
822void ndr_struct_destroy(NdrContext* context, const NdrStructDescr* descr, void* pptr)
823{
824 WINPR_ASSERT(context);
825 WINPR_ASSERT(descr);
826 WINPR_ASSERT(pptr);
827
828 for (size_t i = 0; i < descr->nfields; i++)
829 {
830 const NdrFieldStruct* field = &descr->fields[i];
831 void* ptr = (BYTE*)pptr + field->structOffset;
832 void* hints = nullptr;
833
834 if (field->hintsField >= 0)
835 {
836 /* computes the address of the hints field if any */
837 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
838 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
839
840 hints = (BYTE*)pptr + hintsField->structOffset;
841 }
842
843 if (field->pointerType != NDR_NOT_POINTER)
844 ptr = *(void**)ptr;
845
846 if (ptr && field->typeDescr->destroyFn)
847 field->typeDescr->destroyFn(context, hints, ptr);
848
849 if (field->pointerType != NDR_NOT_POINTER)
850 free(ptr);
851 }
852}
853
854ndr_refid ndr_pointer_refid(const void* ptr)
855{
856 return (ndr_refid)((ULONG_PTR)ptr);
857}
858
859BOOL ndr_read_refpointer(NdrContext* context, wStream* s, ndr_refid* refId)
860{
861 return ndr_read_uint32(context, s, refId);
862}
863
864typedef struct
865{
866 const void* needle;
867 ndr_refid* presult;
868} FindValueArgs;
869
870static BOOL findValueRefFn(const void* key, void* value, void* parg)
871{
872 WINPR_ASSERT(parg);
873
874 FindValueArgs* args = (FindValueArgs*)parg;
875 if (args->needle == value)
876 {
877 *args->presult = (ndr_refid)(UINT_PTR)key;
878 return FALSE;
879 }
880 return TRUE;
881}
882
883BOOL ndr_context_allocatePtr(NdrContext* context, const void* ptr, ndr_refid* prefId, BOOL* pnewPtr)
884{
885 WINPR_ASSERT(context);
886
887 FindValueArgs findArgs = { ptr, prefId };
888 if (!HashTable_Foreach(context->refPointers, findValueRefFn, &findArgs))
889 {
890 *pnewPtr = FALSE;
891 return TRUE;
892 }
893
894 *pnewPtr = TRUE;
895 *prefId = context->refIdCounter + 4;
896 if (!HashTable_Insert(context->refPointers, (void*)(UINT_PTR)(*prefId), ptr))
897 return FALSE;
898
899 context->refIdCounter += 4;
900 return TRUE;
901}
902
903BOOL ndr_read_pointedMessageEx(NdrContext* context, wStream* s, ndr_refid ptrId,
904 NdrMessageType descr, void* hints, void** target)
905{
906 WINPR_ASSERT(context);
907 WINPR_ASSERT(s);
908 WINPR_ASSERT(descr);
909 WINPR_ASSERT(target);
910
911 *target = nullptr;
912 if (!ptrId)
913 return TRUE;
914
915 void* ret = HashTable_GetItemValue(context->refPointers, (void*)(UINT_PTR)ptrId);
916 if (!ret)
917 {
918 size_t itemCount = ndr_hintsCount(descr, hints);
919 if (itemCount == 0)
920 return FALSE;
921 ret = calloc(itemCount, descr->itemSize);
922 if (!ret)
923 return FALSE;
924
925 if (!descr->readFn(context, s, hints, ret) ||
926 !HashTable_Insert(context->refPointers, (void*)(UINT_PTR)ptrId, ret))
927 {
928 if (descr->destroyFn)
929 descr->destroyFn(context, hints, ret);
930 free(ret);
931 return FALSE;
932 }
933 }
934
935 *target = ret;
936 return TRUE;
937}
938
939BOOL ndr_push_deferreds(NdrContext* context, NdrDeferredEntry* deferreds, size_t ndeferred)
940{
941 WINPR_ASSERT(context);
942 WINPR_ASSERT(deferreds);
943
944 if (!ndeferred)
945 return TRUE;
946
947 if (context->ndeferred + ndeferred > NDR_MAX_DEFERRED)
948 {
949 WLog_ERR(TAG, "too many deferred");
950 return FALSE;
951 }
952
953 for (size_t i = ndeferred; i > 0; i--, context->ndeferred++)
954 {
955 context->deferred[context->ndeferred] = deferreds[i - 1];
956 }
957 return TRUE;
958}
959
960BOOL ndr_treat_deferred_read(NdrContext* context, wStream* s)
961{
962 WINPR_ASSERT(context);
963 WINPR_ASSERT(s);
964
965 while (context->ndeferred)
966 {
967 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
968 context->ndeferred--;
969
970 WLog_VRB(TAG, "treating read deferred 0x%x for %s", current.ptrId, current.name);
971 if (!ndr_read_pointedMessageEx(context, s, current.ptrId, current.msg, current.hints,
972 (void**)current.target))
973 {
974 WLog_ERR(TAG, "error parsing deferred %s", current.name);
975 return FALSE;
976 }
977 }
978
979 return TRUE;
980}
981
982BOOL ndr_treat_deferred_write(NdrContext* context, wStream* s)
983{
984 WINPR_ASSERT(context);
985 WINPR_ASSERT(s);
986
987 while (context->ndeferred)
988 {
989 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
990 context->ndeferred--;
991
992 WLog_VRB(TAG, "treating write deferred for %s", current.name);
993 if (!current.msg->writeFn(context, s, current.hints, current.target))
994 {
995 WLog_ERR(TAG, "error writing deferred %s", current.name);
996 return FALSE;
997 }
998 }
999
1000 return TRUE;
1001}
1002
1003BOOL ndr_write_data(NdrContext* context, wStream* s, const void* data, size_t sz)
1004{
1005 if (!Stream_EnsureRemainingCapacity(s, sz))
1006 return FALSE;
1007
1008 Stream_Write(s, data, sz);
1009 ndr_context_bytes_written(context, sz);
1010 return TRUE;
1011}
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