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 UINT32 maxCount = 0;
522 UINT32 offset = 0;
523 UINT32 length = 0;
524
525 if (!ndr_read_uint32(context, s, &maxCount) || !ndr_read_uint32(context, s, &offset) ||
526 !ndr_read_uint32(context, s, &length))
527 return FALSE;
528
529 if ((length * itemType->itemSize) < hints->length)
530 return FALSE;
531
532 if ((maxCount * itemType->itemSize) < hints->maxLength)
533 return FALSE;
534
535 BYTE* target = (BYTE*)ptarget;
536 for (UINT32 i = 0; i < length; i++, target += itemType->itemSize)
537 {
538 if (!itemType->readFn(context, s, NULL, target))
539 return FALSE;
540 }
541
542 return ndr_read_align(context, s, 4);
543}
544
545BOOL ndr_write_uconformant_varying_array(NdrContext* context, wStream* s,
546 const NdrVaryingArrayHints* hints, NdrMessageType itemType,
547 const void* psrc)
548{
549 WINPR_ASSERT(context);
550 WINPR_ASSERT(s);
551 WINPR_ASSERT(hints);
552 WINPR_ASSERT(itemType);
553 WINPR_ASSERT(psrc);
554
555 if (!ndr_write_uint32(context, s, hints->maxLength) || !ndr_write_uint32(context, s, 0) ||
556 !ndr_write_uint32(context, s, hints->length))
557 return FALSE;
558
559 const BYTE* src = (const BYTE*)psrc;
560 for (UINT32 i = 0; i < hints->length; i++, src += itemType->itemSize)
561 {
562 if (!itemType->writeFn(context, s, NULL, src))
563 return FALSE;
564 }
565
566 return TRUE;
567}
568
569BOOL ndr_read_uconformant_array(NdrContext* context, wStream* s, const NdrArrayHints* hints,
570 NdrMessageType itemType, void* vtarget)
571{
572 WINPR_ASSERT(context);
573 WINPR_ASSERT(s);
574 WINPR_ASSERT(itemType);
575 WINPR_ASSERT(vtarget);
576
577 UINT32 count = 0;
578
579 if (!ndr_read_uint32(context, s, &count))
580 return FALSE;
581
582 if ((count * itemType->itemSize < hints->count))
583 return FALSE;
584
585 BYTE* target = (BYTE*)vtarget;
586 for (UINT32 i = 0; i < count; i++, target += itemType->itemSize)
587 {
588 if (!itemType->readFn(context, s, NULL, target))
589 return FALSE;
590 }
591
592 return ndr_read_align(context, s, /*context->alignBytes*/ 4);
593}
594
595BOOL ndr_write_uconformant_array(NdrContext* context, wStream* s, UINT32 len,
596 NdrMessageType itemType, const BYTE* ptr)
597{
598 WINPR_ASSERT(context);
599 WINPR_ASSERT(s);
600 WINPR_ASSERT(itemType);
601 WINPR_ASSERT(ptr);
602
603 size_t toWrite = len * itemType->itemSize;
604 size_t padding = (4 - (toWrite % 4)) % 4;
605 if (!ndr_write_uint32(context, s, len) || !Stream_EnsureRemainingCapacity(s, toWrite + padding))
606 return FALSE;
607
608 for (UINT32 i = 0; i < len; i++, ptr += itemType->itemSize)
609 {
610 if (!itemType->writeFn(context, s, NULL, ptr))
611 return FALSE;
612 }
613
614 if (padding)
615 {
616 Stream_Zero(s, padding);
617 ndr_context_bytes_written(context, padding);
618 }
619 return TRUE;
620}
621
622BOOL ndr_struct_read_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
623 void* target)
624{
625 WINPR_ASSERT(context);
626 WINPR_ASSERT(s);
627 WINPR_ASSERT(descr);
628 WINPR_ASSERT(target);
629
630#define NDR_MAX_STRUCT_DEFERRED 16
631 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = { 0 };
632 size_t ndeferred = 0;
633
634 for (size_t i = 0; i < descr->nfields; i++)
635 {
636 const NdrFieldStruct* field = &descr->fields[i];
637 BYTE* ptr = target;
638 ptr += field->structOffset;
639 void* hints = NULL;
640
641 if (field->hintsField >= 0)
642 {
643 /* computes the address of the hints field if any */
644 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
645 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
646
647 hints = (BYTE*)target + hintsField->structOffset;
648 }
649
650 switch (field->pointerType)
651 {
652 case NDR_NOT_POINTER:
653 if (!field->typeDescr->readFn(context, s, hints, ptr))
654 {
655 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
656 return FALSE;
657 }
658 break;
659 case NDR_POINTER:
660 case NDR_POINTER_NON_NULL:
661 {
662 NdrDeferredEntry* deferred = &deferreds[ndeferred];
663 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
664 {
665 WLog_ERR(TAG, "too many deferred when calling ndr_read_struct_fromDescr for %s",
666 descr->name);
667 return FALSE;
668 }
669
670 deferred->name = field->name;
671 deferred->hints = hints;
672 deferred->target = ptr;
673 deferred->msg = field->typeDescr;
674 if (!ndr_read_refpointer(context, s, &deferred->ptrId))
675 {
676 WLog_ERR(TAG, "error when reading %s.%s", descr->name, field->name);
677 return FALSE;
678 }
679
680 if (!deferred->ptrId && field->pointerType == NDR_POINTER_NON_NULL)
681 {
682 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
683 return FALSE;
684 }
685 ndeferred++;
686 break;
687 }
688 default:
689 WLog_ERR(TAG, "%s.%s unknown pointer type 0x%x", descr->name, field->name,
690 field->pointerType);
691 return FALSE;
692 }
693 }
694
695 return ndr_push_deferreds(context, deferreds, ndeferred);
696}
697
698BOOL ndr_struct_write_fromDescr(NdrContext* context, wStream* s, const NdrStructDescr* descr,
699 const void* src)
700{
701 WINPR_ASSERT(context);
702 WINPR_ASSERT(s);
703 WINPR_ASSERT(descr);
704 WINPR_ASSERT(src);
705
706 NdrDeferredEntry deferreds[NDR_MAX_STRUCT_DEFERRED] = { 0 };
707 size_t ndeferred = 0;
708
709 for (size_t i = 0; i < descr->nfields; i++)
710 {
711 const NdrFieldStruct* field = &descr->fields[i];
712 const BYTE* ptr = (const BYTE*)src + field->structOffset;
713
714 const void* hints = NULL;
715
716 if (field->hintsField >= 0)
717 {
718 /* computes the address of the hints field if any */
719 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
720 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
721
722 hints = (const BYTE*)src + hintsField->structOffset;
723 }
724
725 switch (field->pointerType)
726 {
727 case NDR_POINTER:
728 case NDR_POINTER_NON_NULL:
729 {
730 ndr_refid ptrId = NDR_PTR_NULL;
731 BOOL isNew = 0;
732 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
733
734 if (!ptr && field->pointerType == NDR_POINTER_NON_NULL)
735 {
736 WLog_ERR(TAG, "%s.%s can't be null", descr->name, field->name);
737 return FALSE;
738 }
739
740 if (!ndr_context_allocatePtr(context, ptr, &ptrId, &isNew))
741 return FALSE;
742
743 if (isNew)
744 {
745 NdrDeferredEntry* deferred = &deferreds[ndeferred];
746 if (ndeferred >= NDR_MAX_STRUCT_DEFERRED)
747 {
748 WLog_ERR(TAG,
749 "too many deferred when calling ndr_read_struct_fromDescr for %s",
750 descr->name);
751 return FALSE;
752 }
753
754 deferred->name = field->name;
755 deferred->hints = WINPR_CAST_CONST_PTR_AWAY(hints, void*);
756 deferred->target = WINPR_CAST_CONST_PTR_AWAY(ptr, void*);
757 deferred->msg = field->typeDescr;
758 ndeferred++;
759 }
760
761 if (!ndr_write_uint32(context, s, ptrId))
762 return FALSE;
763 break;
764 }
765 case NDR_NOT_POINTER:
766 if (!field->typeDescr->writeFn(context, s, hints, ptr))
767 {
768 WLog_ERR(TAG, "error when writing %s.%s", descr->name, field->name);
769 return FALSE;
770 }
771 break;
772 default:
773 break;
774 }
775 }
776
777 return ndr_push_deferreds(context, deferreds, ndeferred);
778}
779
780void ndr_struct_dump_fromDescr(wLog* logger, UINT32 lvl, size_t identLevel,
781 const NdrStructDescr* descr, const void* obj)
782{
783 char tabArray[30 + 1];
784 size_t ntabs = (identLevel <= 30) ? identLevel : 30;
785
786 memset(tabArray, '\t', ntabs);
787 tabArray[ntabs] = 0;
788
789 WLog_Print(logger, lvl, "%s%s", tabArray, descr->name);
790 for (size_t i = 0; i < descr->nfields; i++)
791 {
792 const NdrFieldStruct* field = &descr->fields[i];
793 const BYTE* ptr = (const BYTE*)obj + field->structOffset;
794
795 switch (field->pointerType)
796 {
797 case NDR_POINTER:
798 case NDR_POINTER_NON_NULL:
799 ptr = *(WINPR_CAST_CONST_PTR_AWAY(ptr, const void**));
800 break;
801 case NDR_NOT_POINTER:
802 break;
803 default:
804 WLog_ERR(TAG, "invalid field->pointerType");
805 break;
806 }
807
808 WLog_Print(logger, lvl, "%s*%s:", tabArray, field->name);
809 if (field->typeDescr->dumpFn)
810 field->typeDescr->dumpFn(logger, lvl, identLevel + 1, ptr);
811 else
812 WLog_Print(logger, lvl, "%s\t<no dump function>", tabArray);
813 }
814}
815
816void ndr_struct_destroy(NdrContext* context, const NdrStructDescr* descr, void* pptr)
817{
818 WINPR_ASSERT(context);
819 WINPR_ASSERT(descr);
820 WINPR_ASSERT(pptr);
821
822 for (size_t i = 0; i < descr->nfields; i++)
823 {
824 const NdrFieldStruct* field = &descr->fields[i];
825 void* ptr = (BYTE*)pptr + field->structOffset;
826 void* hints = NULL;
827
828 if (field->hintsField >= 0)
829 {
830 /* computes the address of the hints field if any */
831 WINPR_ASSERT((size_t)field->hintsField < descr->nfields);
832 const NdrFieldStruct* hintsField = &descr->fields[field->hintsField];
833
834 hints = (BYTE*)pptr + hintsField->structOffset;
835 }
836
837 if (field->pointerType != NDR_NOT_POINTER)
838 ptr = *(void**)ptr;
839
840 if (ptr && field->typeDescr->destroyFn)
841 field->typeDescr->destroyFn(context, hints, ptr);
842
843 if (field->pointerType != NDR_NOT_POINTER)
844 free(ptr);
845 }
846}
847
848ndr_refid ndr_pointer_refid(const void* ptr)
849{
850 return (ndr_refid)((ULONG_PTR)ptr);
851}
852
853BOOL ndr_read_refpointer(NdrContext* context, wStream* s, ndr_refid* refId)
854{
855 return ndr_read_uint32(context, s, refId);
856}
857
858typedef struct
859{
860 const void* needle;
861 ndr_refid* presult;
862} FindValueArgs;
863
864static BOOL findValueRefFn(const void* key, void* value, void* parg)
865{
866 WINPR_ASSERT(parg);
867
868 FindValueArgs* args = (FindValueArgs*)parg;
869 if (args->needle == value)
870 {
871 *args->presult = (ndr_refid)(UINT_PTR)key;
872 return FALSE;
873 }
874 return TRUE;
875}
876
877BOOL ndr_context_allocatePtr(NdrContext* context, const void* ptr, ndr_refid* prefId, BOOL* pnewPtr)
878{
879 WINPR_ASSERT(context);
880
881 FindValueArgs findArgs = { ptr, prefId };
882 if (!HashTable_Foreach(context->refPointers, findValueRefFn, &findArgs))
883 {
884 *pnewPtr = FALSE;
885 return TRUE;
886 }
887
888 *pnewPtr = TRUE;
889 *prefId = context->refIdCounter + 4;
890 if (!HashTable_Insert(context->refPointers, (void*)(UINT_PTR)(*prefId), ptr))
891 return FALSE;
892
893 context->refIdCounter += 4;
894 return TRUE;
895}
896
897BOOL ndr_read_pointedMessageEx(NdrContext* context, wStream* s, ndr_refid ptrId,
898 NdrMessageType descr, void* hints, void** target)
899{
900 WINPR_ASSERT(context);
901 WINPR_ASSERT(s);
902 WINPR_ASSERT(descr);
903 WINPR_ASSERT(target);
904
905 *target = NULL;
906 if (!ptrId)
907 return TRUE;
908
909 void* ret = HashTable_GetItemValue(context->refPointers, (void*)(UINT_PTR)ptrId);
910 if (!ret)
911 {
912 size_t itemCount = ndr_hintsCount(descr, hints);
913 ret = calloc(itemCount, descr->itemSize);
914 if (!ret)
915 return FALSE;
916
917 if (!descr->readFn(context, s, hints, ret) ||
918 !HashTable_Insert(context->refPointers, (void*)(UINT_PTR)ptrId, ret))
919 {
920 if (descr->destroyFn)
921 descr->destroyFn(context, hints, ret);
922 free(ret);
923 return FALSE;
924 }
925 }
926
927 *target = ret;
928 return TRUE;
929}
930
931BOOL ndr_push_deferreds(NdrContext* context, NdrDeferredEntry* deferreds, size_t ndeferred)
932{
933 WINPR_ASSERT(context);
934 WINPR_ASSERT(deferreds);
935
936 if (!ndeferred)
937 return TRUE;
938
939 if (context->ndeferred + ndeferred > NDR_MAX_DEFERRED)
940 {
941 WLog_ERR(TAG, "too many deferred");
942 return FALSE;
943 }
944
945 for (size_t i = ndeferred; i > 0; i--, context->ndeferred++)
946 {
947 context->deferred[context->ndeferred] = deferreds[i - 1];
948 }
949 return TRUE;
950}
951
952BOOL ndr_treat_deferred_read(NdrContext* context, wStream* s)
953{
954 WINPR_ASSERT(context);
955 WINPR_ASSERT(s);
956
957 while (context->ndeferred)
958 {
959 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
960 context->ndeferred--;
961
962 WLog_VRB(TAG, "treating read deferred 0x%x for %s", current.ptrId, current.name);
963 if (!ndr_read_pointedMessageEx(context, s, current.ptrId, current.msg, current.hints,
964 (void**)current.target))
965 {
966 WLog_ERR(TAG, "error parsing deferred %s", current.name);
967 return FALSE;
968 }
969 }
970
971 return TRUE;
972}
973
974BOOL ndr_treat_deferred_write(NdrContext* context, wStream* s)
975{
976 WINPR_ASSERT(context);
977 WINPR_ASSERT(s);
978
979 while (context->ndeferred)
980 {
981 NdrDeferredEntry current = context->deferred[context->ndeferred - 1];
982 context->ndeferred--;
983
984 WLog_VRB(TAG, "treating write deferred for %s", current.name);
985 if (!current.msg->writeFn(context, s, current.hints, current.target))
986 {
987 WLog_ERR(TAG, "error writing deferred %s", current.name);
988 return FALSE;
989 }
990 }
991
992 return TRUE;
993}
994
995BOOL ndr_write_data(NdrContext* context, wStream* s, const void* data, size_t sz)
996{
997 if (!Stream_EnsureRemainingCapacity(s, sz))
998 return FALSE;
999
1000 Stream_Write(s, data, sz);
1001 ndr_context_bytes_written(context, sz);
1002 return TRUE;
1003}
hints for a conformant array
Definition ndr.h:185
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:171