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