FreeRDP
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 
32 struct 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 
51 NdrContext* 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 
71 void 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 
85 NdrContext* 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 
106 void ndr_context_free(NdrContext* context)
107 {
108  if (context)
109  {
110  HashTable_Free(context->refPointers);
111  free(context);
112  }
113 }
114 
115 static void ndr_context_bytes_read(NdrContext* context, size_t len)
116 {
117  WINPR_ASSERT(context);
118  context->indentLevels[context->currentLevel] += len;
119 }
120 
121 static void ndr_context_bytes_written(NdrContext* context, size_t len)
122 {
123  ndr_context_bytes_read(context, len);
124 }
125 
126 NdrContext* 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 
144 BOOL 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 
160 BOOL 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 
172 BOOL 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 
190 BOOL 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 
209 BOOL 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 
222 BOOL 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 
234 BOOL 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 
257 BOOL ndr_start_constructed(NdrContext* context, wStream* s)
258 {
259  WINPR_ASSERT(context);
260 
261  if (!Stream_EnsureCapacity(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 
274 BOOL 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 
295 static 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 
315 BOOL 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 
328 BOOL 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 
334 BOOL 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 
344 BOOL 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 
354 const static NdrMessageDescr uint8_descr = { NDR_ARITY_SIMPLE, 1, ndr_read_uint8_,
355  ndr_write_uint8_, NULL, NULL };
356 
357 NdrMessageType 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 
426 SIMPLE_TYPE_IMPL(UINT32, uint32)
427 SIMPLE_TYPE_IMPL(UINT16, uint16)
428 SIMPLE_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 
504 ARRAY_OF_TYPE_IMPL(uint8, BYTE)
505 ARRAY_OF_TYPE_IMPL(uint16, UINT16)
506 
507 BOOL ndr_read_wchar(NdrContext* context, wStream* s, WCHAR* ptr)
508 {
509  return ndr_read_uint16(context, s, (UINT16*)ptr);
510 }
511 
512 BOOL 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 
546 BOOL 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 
570 BOOL 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 
596 BOOL 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 
623 BOOL 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 
699 BOOL 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 
781 void 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 
817 void 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 
849 ndr_refid ndr_pointer_refid(const void* ptr)
850 {
851  return (ndr_refid)((ULONG_PTR)ptr);
852 }
853 
854 BOOL ndr_read_refpointer(NdrContext* context, wStream* s, ndr_refid* refId)
855 {
856  return ndr_read_uint32(context, s, refId);
857 }
858 
859 typedef struct
860 {
861  const void* needle;
862  ndr_refid* presult;
863 } FindValueArgs;
864 
865 static 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 
878 BOOL 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 
898 BOOL 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 
932 BOOL 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 
953 BOOL 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 
975 BOOL 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 }
hints for a conformant array
Definition: ndr.h:184
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:170