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