4static int TestNdrBasic_1(
void)
13 0x02, 0x00, 0x00, 0x00,
18 wStream* s = Stream_StaticInit(&staticS, payload,
sizeof(payload));
20 BYTE* target =
nullptr;
23 (
void*)&target, TRUE, winpr_ndr_uint8Array_descr() };
39#define NDR_TYPEDEF(V) \
40 static BOOL ndr_descr_read_##V(WinPrNdrDecoder* context, wStream* s, const void* hints, \
43 WINPR_UNUSED(hints); \
44 return winpr_ndr_decoder_read_fromDescr(context, s, &V##_struct, obj); \
46 static BOOL ndr_descr_write_##V(WinPrNdrEncoder* context, wStream* s, const void* hints, \
49 WINPR_UNUSED(hints); \
50 return winpr_ndr_encoder_write_fromDescr(context, s, &V##_struct, obj); \
52 static void ndr_descr_destroy_##V(const void* hints, void* obj) \
54 WINPR_UNUSED(hints); \
55 winpr_ndr_struct_destroy(&V##_struct, obj); \
57 static void ndr_descr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj) \
59 winpr_ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
62 static WinPrNdrMessageDescr ndr_##V##_descr_s = { \
63 WINPR_NDR_ARITY_SIMPLE, sizeof(V), ndr_descr_read_##V, ndr_descr_write_##V, \
64 ndr_descr_destroy_##V, ndr_descr_dump_##V, \
67 WinPrNdrMessageType ndr_##V##_descr(void) \
69 return &ndr_##V##_descr_s; \
80 &winpr_ndr_uint32_descr_s },
86 ARRAYSIZE(REDIR_SCARDCONTEXT_fields),
87 REDIR_SCARDCONTEXT_fields };
100 &winpr_ndr_uint32_descr_s },
102 &ndr_REDIR_SCARDCONTEXT_descr_s },
106 "EstablishContext_Return", ARRAYSIZE(EstablishContext_Return_fields),
107 EstablishContext_Return_fields
114static int TestNdrStaticArrayRead(
void)
118 unsigned char payload[] = { 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
119 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0,
122 0x0, 0x0, 0x2, 0x0, 0x8, 0x0, 0x0, 0x0,
123 0x49, 0x91, 0xe4, 0x7c, 0x0, 0x0, 0x0, 0x0 };
125 wStream* s = Stream_StaticConstInit(&staticS, payload,
sizeof(payload));
134 !ndr_EstablishContext_Return_descr_s.readFn(decoder, &cpayload,
nullptr, &context) ||
139 unsigned char expected[] = { 0x49, 0x91, 0xe4, 0x7c, 0x0, 0x0, 0x0, 0x0 };
140 if (context.hContext.cbContext != 8 || memcmp(context.hContext.pbContext, expected, 8) != 0)
149static int TestNdrStaticArrayWrite(
void)
158 wStream* s = Stream_StaticInit(&staticS, buffer,
sizeof(buffer));
161 context.cbContext = 10;
162 for (
int i = 0; i < 10; i++)
163 context.pbContext[i] = i + 1;
168 Stream_SealLength(s);
170 unsigned char expected[] = {
171 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0xa, 0x0, 0x0,
172 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
175 if (Stream_Length(s) !=
sizeof(expected))
178 retCode = memcmp(Stream_Buffer(s), expected,
sizeof(expected));
184static int TestNdrStaticArrayOverflow(
void)
187 unsigned char payload[] = { 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x30, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0,
191 0x2, 0x0, 0x20, 0x0, 0x0, 0x0, 0x41, 0x41, 0x41, 0x41,
192 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
193 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
194 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 };
196 wStream* s = Stream_StaticConstInit(&staticS, payload,
sizeof(payload));
206 ndr_EstablishContext_Return_descr_s.readFn(decoder, &cpayload,
nullptr, &context) &&
226 &winpr_ndr_uint8Array_descr_s },
229static const WinPrNdrStructDescr TEST_BLOB_struct = {
"TEST_BLOB", ARRAYSIZE(TEST_BLOB_fields),
232NDR_TYPEDEF(TEST_BLOB)
234static BOOL ndr_read_TEST_BLOB_array(WinPrNdrDecoder* context,
wStream* s,
const void* hints,
240static BOOL ndr_write_TEST_BLOB_array(WinPrNdrEncoder* context,
wStream* s,
const void* hints,
245 &ndr_TEST_BLOB_descr_s, v);
248static void ndr_destroy_TEST_BLOB_array(
const void* hints,
void* obj)
251 TEST_BLOB* blobs = obj;
252 for (UINT32 i = 0; i < ahints->
count; i++)
258 ndr_write_TEST_BLOB_array, ndr_destroy_TEST_BLOB_array,
nullptr
269 &winpr_ndr_uint32_descr_s },
270 {
"blobs", offsetof(TEST_BLOBS, blobs),
WINPR_NDR_POINTER, 0, &ndr_TEST_BLOB_array_descr_s },
273static const WinPrNdrStructDescr TEST_BLOBS_struct = {
"TEST_BLOBS", ARRAYSIZE(TEST_BLOBS_fields),
277static const BYTE blobsPayload[] = {
278 0x02, 0x00, 0x00, 0x00,
279 0x00, 0x00, 0x02, 0x00,
280 0x02, 0x00, 0x00, 0x00,
281 0x01, 0x00, 0x00, 0x00,
282 0x04, 0x00, 0x02, 0x00,
283 0x02, 0x00, 0x00, 0x00,
284 0x08, 0x00, 0x02, 0x00,
285 0x01, 0x00, 0x00, 0x00,
286 'A', 0x00, 0x00, 0x00,
287 0x02, 0x00, 0x00, 0x00,
291static int TestNdrDeferredOrderWrite(
void)
294 BYTE data0[] = {
'A' };
295 BYTE data1[] = {
'B',
'C' };
296 TEST_BLOB items[] = { { 1, data0 }, { 2, data1 } };
297 TEST_BLOBS blobs = { { 2 }, items };
300 wStream* s = Stream_New(
nullptr, 100);
310 if ((Stream_GetPosition(s) !=
sizeof(blobsPayload)) ||
311 (memcmp(Stream_Buffer(s), blobsPayload,
sizeof(blobsPayload)) != 0))
316 Stream_Free(s, TRUE);
321static int TestNdrDeferredOrderRead(
void)
324 TEST_BLOBS blobs = WINPR_C_ARRAY_INIT;
326 wStream* s = Stream_StaticConstInit(&staticS, blobsPayload,
sizeof(blobsPayload));
337 if ((Stream_GetRemainingLength(s) != 0) || (blobs.hints.count != 2) || !blobs.blobs)
341 if ((blobs.blobs[0].count != 1) || (blobs.blobs[0].data[0] !=
'A') ||
342 (blobs.blobs[1].count != 2) || (memcmp(blobs.blobs[1].data,
"BC", 2) != 0))
352static int TestNdrObject(
void)
356 wStream* s = Stream_New(
nullptr, 100);
364 !winpr_ndr_encoder_write_uint16(encoder, s, 0x1234) ||
369 const BYTE expected[] = { 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
370 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
371 0x00, 0x00, 0x02, 0x00, 0x34, 0x12, 0x00, 0x00 };
373 if ((Stream_GetPosition(s) !=
sizeof(expected)) ||
374 (memcmp(Stream_Buffer(s), expected,
sizeof(expected)) != 0))
378 Stream_SealLength(s);
379 Stream_SetPosition(s, 0);
382 wStream object = WINPR_C_ARRAY_INIT;
386 (Stream_GetRemainingLength(s) == 0) &&
388 (refId == 0x20000) && winpr_ndr_decoder_read_uint16(decoder, &
object, &v) &&
394 Stream_Free(s, TRUE);
400static int TestNdrSignedTypes(
void)
402 for (
int bigEndian = 0; bigEndian < 2; bigEndian++)
406 WinPrNdrDecoder* decoder =
nullptr;
407 wStream* s = Stream_New(
nullptr, 64);
413 const INT16 i16 = -0x1234;
414 const INT64 i64 = -0x123456789abcdefLL;
415 if (!winpr_ndr_encoder_write_int8(encoder, s, i8) ||
416 !winpr_ndr_encoder_write_int16(encoder, s, i16) ||
417 !winpr_ndr_encoder_write_int8_(encoder, s,
nullptr, &i8) ||
418 !winpr_ndr_encoder_write_int64(encoder, s, i64))
421 const BYTE expectedLE[] = { 0xfe, 0x00, 0xcc, 0xed, 0xfe, 0x00, 0x00, 0x00,
422 0x11, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe };
423 const BYTE expectedBE[] = { 0xfe, 0x00, 0xed, 0xcc, 0xfe, 0x00, 0x00, 0x00,
424 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x11 };
425 const BYTE* expected = bigEndian ? expectedBE : expectedLE;
427 if ((Stream_GetPosition(s) !=
sizeof(expectedLE)) ||
428 (memcmp(Stream_Buffer(s), expected,
sizeof(expectedLE)) != 0))
432 Stream_SealLength(s);
433 Stream_SetPosition(s, 0);
439 if (!decoder || !winpr_ndr_decoder_read_int8(decoder, s, &r8) ||
440 !winpr_ndr_int16_descr()->readFn(decoder, s,
nullptr, &r16) ||
441 !winpr_ndr_decoder_read_int8_(decoder, s,
nullptr, &r8bis) ||
442 !winpr_ndr_decoder_read_int64(decoder, s, &r64))
446 if ((r8 != i8) || (r16 != i16) || (r8bis != i8) || (r64 != i64) ||
447 (Stream_GetRemainingLength(s) != 0) || (winpr_ndr_int8_descr()->itemSize != 1) ||
448 (winpr_ndr_int16_descr()->itemSize != 2) || (winpr_ndr_int64_descr()->itemSize != 8))
455 Stream_Free(s, TRUE);
457 return retCode - (bigEndian * 10);
464static BOOL decode_payload(
const WinPrNdrStructDescr* descr,
const BYTE* payload,
size_t len,
468 wStream* s = Stream_StaticConstInit(&staticS, payload, len);
473 (Stream_GetRemainingLength(s) == 0);
489static const WinPrNdrStructDescr FULL_PAIR_struct = {
"FULL_PAIR", ARRAYSIZE(FULL_PAIR_fields),
493static int TestNdrFullPointerAlias(
void)
495 const BYTE payload[] = {
496 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x78, 0x56, 0x34, 0x12
498 FULL_PAIR pair = WINPR_C_ARRAY_INIT;
501 if (!decode_payload(&FULL_PAIR_struct, payload,
sizeof(payload), &pair))
505 if (!pair.a || (pair.a != pair.b) || (*pair.a != 0x12345678))
513 if (pair.a || pair.b || (*kept != 0x12345678))
521 const BYTE payload2[] = { 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00,
522 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 };
524 if (!decode_payload(&FULL_PAIR_struct, payload2,
sizeof(payload2), &pair) ||
525 (pair.a == pair.b) || (*pair.a != 1) || (*pair.b != 2))
545static const WinPrNdrStructDescr FULL_MIXED_struct = {
"FULL_MIXED", ARRAYSIZE(FULL_MIXED_fields),
555 {
"u", offsetof(UNIQUE_FULL, u),
WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s },
560 ARRAYSIZE(UNIQUE_FULL_fields),
561 UNIQUE_FULL_fields };
579 ARRAYSIZE(FULL_ARRAYS_fields),
580 FULL_ARRAYS_fields };
583static int TestNdrFullPointerConfusion(
void)
588 const BYTE mixed[] = { 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x78, 0x56, 0x34, 0x12 };
589 FULL_MIXED fmixed = WINPR_C_ARRAY_INIT;
590 const BOOL mixedOk = decode_payload(&FULL_MIXED_struct, mixed,
sizeof(mixed), &fmixed);
597 UNIQUE_FULL ufull = WINPR_C_ARRAY_INIT;
598 const BOOL ufullOk = decode_payload(&UNIQUE_FULL_struct, mixed,
sizeof(mixed), &ufull);
605 const BYTE arrays[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
606 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
'A',
'B' };
607 FULL_ARRAYS farrays = WINPR_C_ARRAY_INIT;
608 const BOOL arraysOk = decode_payload(&FULL_ARRAYS_struct, arrays,
sizeof(arrays), &farrays) &&
609 farrays.a && (farrays.a == farrays.b) &&
610 (memcmp(farrays.a,
"AB", 2) == 0);
617 const BYTE sizes[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x00, 0x00,
618 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
'A',
'B' };
619 const BOOL sizesOk = decode_payload(&FULL_ARRAYS_struct, sizes,
sizeof(sizes), &farrays);
639 { 0x20, {
"Pointer", 0,
WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s, 0, 0 } },
644static const WinPrNdrUnionDescr SHORT_UNION_union = {
"SHORT_UNION", ARRAYSIZE(SHORT_UNION_arms),
645 SHORT_UNION_arms, 2, &SHORT_UNION_default };
657 &winpr_ndr_uint16_descr_s, 0, 0 },
662 ARRAYSIZE(SHORT_SWITCH_fields),
663 SHORT_SWITCH_fields, 4 };
665static const BYTE shortSwitchPointer[] = {
666 0x20, 0x00, 0x20, 0x00,
667 0x00, 0x00, 0x02, 0x00,
668 0x44, 0x33, 0x22, 0x11,
671static const BYTE shortSwitchValue[] = {
672 0x10, 0x00, 0x10, 0x00,
673 0x88, 0x77, 0x66, 0x55,
677static const BYTE shortSwitchDefault[] = { 0x99, 0x00, 0x99, 0x00 };
679static const BYTE shortSwitchMismatch[] = {
680 0x10, 0x00, 0x20, 0x00,
681 0x88, 0x77, 0x66, 0x55,
684static int TestNdrUnionWrite(
void)
687 UINT32 value = 0x11223344;
688 const SHORT_SWITCH msgs[] = { { 0x20, { .Pointer = &value } },
689 { 0x10, { .Value = 0x55667788 } },
690 { 0x99, { .Value = 0 } } };
691 const BYTE* expected[] = { shortSwitchPointer, shortSwitchValue, shortSwitchDefault };
692 const size_t expectedLen[] = {
sizeof(shortSwitchPointer),
sizeof(shortSwitchValue),
693 sizeof(shortSwitchDefault) };
695 wStream* s = Stream_New(
nullptr, 100);
699 for (
size_t i = 0; i < ARRAYSIZE(msgs); i++)
702 Stream_SetPosition(s, 0);
708 (Stream_GetPosition(s) == expectedLen[i]) &&
709 (memcmp(Stream_Buffer(s), expected[i], expectedLen[i]) == 0);
717 Stream_Free(s, TRUE);
721static int TestNdrUnionRead(
void)
723 SHORT_SWITCH msg = WINPR_C_ARRAY_INIT;
724 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchPointer,
sizeof(shortSwitchPointer),
726 (msg.CallId != 0x20) || !msg.u.Pointer || (*msg.u.Pointer != 0x11223344))
730 SHORT_SWITCH value = WINPR_C_ARRAY_INIT;
731 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchValue,
sizeof(shortSwitchValue), &value) ||
732 (value.CallId != 0x10) || (value.u.Value != 0x55667788))
735 SHORT_SWITCH def = WINPR_C_ARRAY_INIT;
736 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchDefault,
sizeof(shortSwitchDefault),
738 (def.CallId != 0x99))
741 SHORT_SWITCH mismatch = WINPR_C_ARRAY_INIT;
742 if (decode_payload(&SHORT_SWITCH_struct, shortSwitchMismatch,
sizeof(shortSwitchMismatch),
750int TestNdrBasic(
int argc,
char* argv[])
755 int (*
const tests[])(void) = { TestNdrBasic_1,
756 TestNdrStaticArrayRead,
757 TestNdrStaticArrayWrite,
758 TestNdrStaticArrayOverflow,
759 TestNdrDeferredOrderWrite,
760 TestNdrDeferredOrderRead,
763 TestNdrFullPointerAlias,
764 TestNdrFullPointerConfusion,
768 for (
size_t i = 0; i < ARRAYSIZE(tests); i++)
770 const int ret = tests[i]();
773 (void)fprintf(stderr,
"test %" PRIuz
" failed with %d\n", i, ret);
NDR encoder and decoder ([C706] chapter 14, [MS-RPCE] 2.2.5 and 2.2.6)
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_end_object(WinPrNdrEncoder *context, wStream *s)
ends the serialized object started with winpr_ndr_encoder_start_object()
UINT32 winpr_ndr_refid
a referent id, the wire value of a pointer (WINPR_NDR_PTR_NULL for a null pointer)
@ WINPR_NDR_POINTER_NON_NULL
WINPR_API void * winpr_ndr_pointer_ref(void *ptr)
takes a reference on a referent
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_header(WinPrNdrEncoder *context, wStream *s)
writes the common type header ([MS-RPCE] 2.2.6.1): version, endianness, header length and filler
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_uconformant_array(WinPrNdrDecoder *context, wStream *s, const WinPrNdrArrayHints *hints, WinPrNdrMessageType itemType, void *vtarget)
reads a conformant array: its count and the items
static INLINE void winpr_ndr_decoder_destroy(WinPrNdrDecoder **pcontext)
frees a decoder and resets the pointer
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_fromDescr(WinPrNdrDecoder *context, wStream *s, const WinPrNdrStructDescr *descr, void *target)
reads a structure from its descriptor
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_treat_deferreds(WinPrNdrEncoder *context, wStream *s)
writes the pending deferred referents
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new(BOOL bigEndianDrep, BYTE version)
creates a decoder
WINPR_API WinPrNdrEncoder * winpr_ndr_encoder_new(BOOL bigEndianDrep, BYTE version)
creates an encoder
static INLINE void winpr_ndr_encoder_destroy(WinPrNdrEncoder **pcontext)
frees an encoder and resets the pointer
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_toplevel_refid(WinPrNdrEncoder *context, wStream *s)
writes a new referent id for a non-null top-level pointer
@ WINPR_NDR_ARITY_ARRAYOF
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_refpointer(WinPrNdrDecoder *context, wStream *s, UINT32 *refId)
reads a referent id
WINPR_API void winpr_ndr_pointer_release(void *ptr)
releases a referent
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_object(WinPrNdrDecoder *context, wStream *s, wStream *object)
reads the private header of a serialized object ([MS-RPCE] 2.2.6 type serialization version 1)
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new_fromStream(wStream *s)
reads the common type header ([MS-RPCE] 2.2.6.1) and creates a decoder for its version and endianness
#define WINPR_NDR_UNION_MESSAGE_DEFINE(PREFIX, CTYPE)
defines a static message type for a non-encapsulated union
WINPR_API void winpr_ndr_struct_destroy(const WinPrNdrStructDescr *descr, void *pptr)
releases the content of a structure from its descriptor
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_fromDescr(WinPrNdrEncoder *context, wStream *s, const WinPrNdrStructDescr *descr, const void *src)
writes a structure from its descriptor
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_push_deferreds(WinPrNdrDecoder *context, WinPrNdrDeferredEntry *deferreds, size_t ndeferred)
adds deferred pointers, read by the next winpr_ndr_decoder_treat_deferreds()
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_write_uconformant_array(WinPrNdrEncoder *context, wStream *s, UINT32 len, WinPrNdrMessageType itemType, const BYTE *ptr)
writes a conformant array: its count and the items
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_start_object(WinPrNdrEncoder *context, wStream *s)
starts a serialized object ([MS-RPCE] 2.2.6 type serialization version 1)
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_treat_deferreds(WinPrNdrDecoder *context, wStream *s)
reads the pending deferred referents
hints for a conformant array
a deferred pointer, a referent to read after the current construct
descriptor of a field in a structure
an arm of a non-encapsulated union
a non-encapsulated union ([switch_type()])