FreeRDP
Loading...
Searching...
No Matches
TestNdrBasic.c
1#include <stddef.h>
2#include <winpr/ndr.h>
3
4static int TestNdrBasic_1(void)
5{
6 int retCode = -2;
7 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new(FALSE, 1);
8 if (!decoder)
9 return -1;
10
11 BYTE payload[] = {
12 // == conformant array ==
13 0x02, 0x00, 0x00, 0x00, // (nitems)
14 0x30, 0x00, // content
15 0x00, 0x00 // (padding)
16 };
17 wStream staticS;
18 wStream* s = Stream_StaticInit(&staticS, payload, sizeof(payload));
19
20 BYTE* target = nullptr;
21 WinPrNdrArrayHints hints = { 2 };
22 WinPrNdrDeferredEntry e = { 0x020028, "arrayContent", &hints,
23 (void*)&target, TRUE, winpr_ndr_uint8Array_descr() };
24
25 if (!winpr_ndr_decoder_push_deferreds(decoder, &e, 1))
26 goto out;
27
28 if (!winpr_ndr_decoder_treat_deferreds(decoder, s))
29 goto out;
30
31 /* the decoded pointers are released, the type destroys the referent with the last reference */
33 retCode = 0;
34out:
36 return retCode;
37}
38
39#define NDR_TYPEDEF(V) \
40 static BOOL ndr_descr_read_##V(WinPrNdrDecoder* context, wStream* s, const void* hints, \
41 void* obj) \
42 { \
43 WINPR_UNUSED(hints); \
44 return winpr_ndr_decoder_read_fromDescr(context, s, &V##_struct, obj); \
45 } \
46 static BOOL ndr_descr_write_##V(WinPrNdrEncoder* context, wStream* s, const void* hints, \
47 const void* obj) \
48 { \
49 WINPR_UNUSED(hints); \
50 return winpr_ndr_encoder_write_fromDescr(context, s, &V##_struct, obj); \
51 } \
52 static void ndr_descr_destroy_##V(const void* hints, void* obj) \
53 { \
54 WINPR_UNUSED(hints); \
55 winpr_ndr_struct_destroy(&V##_struct, obj); \
56 } \
57 static void ndr_descr_dump_##V(wLog* logger, UINT32 lvl, size_t indentLevel, const void* obj) \
58 { \
59 winpr_ndr_struct_dump_fromDescr(logger, lvl, indentLevel, &V##_struct, obj); \
60 } \
61 \
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, \
65 }; \
66 \
67 WinPrNdrMessageType ndr_##V##_descr(void) \
68 { \
69 return &ndr_##V##_descr_s; \
70 }
71
72typedef struct
73{
74 /* [range] */ DWORD cbContext;
75 /* [size_is][unique] */ BYTE pbContext[16];
77
78static const WinPrNdrFieldStruct REDIR_SCARDCONTEXT_fields[] = {
79 { "cbContext", offsetof(REDIR_SCARDCONTEXT, cbContext), WINPR_NDR_NOT_POINTER, -1,
80 &winpr_ndr_uint32_descr_s },
81 { "pbContext", offsetof(REDIR_SCARDCONTEXT, pbContext), WINPR_NDR_FIXED_ARRAY, 0,
82 &winpr_ndr_uint8Array_descr_s, sizeof(((REDIR_SCARDCONTEXT*)nullptr)->pbContext) },
83};
84
85static const WinPrNdrStructDescr REDIR_SCARDCONTEXT_struct = { "REDIR_SCARDCONTEXT",
86 ARRAYSIZE(REDIR_SCARDCONTEXT_fields),
87 REDIR_SCARDCONTEXT_fields };
88
89NDR_TYPEDEF(REDIR_SCARDCONTEXT)
90
91/* ========================================================================== */
92typedef struct
93{
94 REDIR_SCARDCONTEXT hContext;
95 LONG ReturnCode;
97
98static const WinPrNdrFieldStruct EstablishContext_Return_fields[] = {
99 { "ReturnCode", offsetof(EstablishContext_Return, ReturnCode), WINPR_NDR_NOT_POINTER, -1,
100 &winpr_ndr_uint32_descr_s },
101 { "hContext", offsetof(EstablishContext_Return, hContext), WINPR_NDR_NOT_POINTER, -1,
102 &ndr_REDIR_SCARDCONTEXT_descr_s },
103};
104
105static const WinPrNdrStructDescr EstablishContext_Return_struct = {
106 "EstablishContext_Return", ARRAYSIZE(EstablishContext_Return_fields),
107 EstablishContext_Return_fields
108};
109
110NDR_TYPEDEF(EstablishContext_Return)
111
112/* ========================================================================== */
113
114static int TestNdrStaticArrayRead(void)
115{
116 int retCode = -2;
117
118 unsigned char payload[] = { 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc,
119 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120
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 };
124 wStream staticS;
125 wStream* s = Stream_StaticConstInit(&staticS, payload, sizeof(payload));
126
127 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new_fromStream(s);
128 if (!decoder)
129 return -1;
130
131 EstablishContext_Return context = WINPR_C_ARRAY_INIT;
132 wStream cpayload;
133 if (!winpr_ndr_decoder_read_object(decoder, s, &cpayload) ||
134 !ndr_EstablishContext_Return_descr_s.readFn(decoder, &cpayload, nullptr, &context) ||
135 !winpr_ndr_decoder_treat_deferreds(decoder, &cpayload))
136 goto out;
137 retCode = -3;
138
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)
141 goto out;
142
143 retCode = 0;
144out:
146 return retCode;
147}
148
149static int TestNdrStaticArrayWrite(void)
150{
151 int retCode = -2;
152 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(FALSE, 1);
153 if (!encoder)
154 return -1;
155
156 BYTE buffer[1000];
157 wStream staticS;
158 wStream* s = Stream_StaticInit(&staticS, buffer, sizeof(buffer));
159
160 REDIR_SCARDCONTEXT context = WINPR_C_ARRAY_INIT;
161 context.cbContext = 10;
162 for (int i = 0; i < 10; i++)
163 context.pbContext[i] = i + 1;
164 if (!winpr_ndr_encoder_write_fromDescr(encoder, s, &REDIR_SCARDCONTEXT_struct, &context))
165 goto out;
166
167 retCode = winpr_ndr_encoder_treat_deferreds(encoder, s) ? 0 : -3;
168 Stream_SealLength(s);
169
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,
173 };
174
175 if (Stream_Length(s) != sizeof(expected))
176 goto out;
177
178 retCode = memcmp(Stream_Buffer(s), expected, sizeof(expected));
179out:
181 return retCode;
182}
183
184static int TestNdrStaticArrayOverflow(void)
185{
186 /* cbContext announces 32 bytes, more than the 16 bytes of pbContext */
187 unsigned char payload[] = { 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x30, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189
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 };
195 wStream staticS;
196 wStream* s = Stream_StaticConstInit(&staticS, payload, sizeof(payload));
197
198 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new_fromStream(s);
199 if (!decoder)
200 return -1;
201
202 int retCode = -4;
203 EstablishContext_Return context = WINPR_C_ARRAY_INIT;
204 wStream cpayload;
205 if (winpr_ndr_decoder_read_object(decoder, s, &cpayload) &&
206 ndr_EstablishContext_Return_descr_s.readFn(decoder, &cpayload, nullptr, &context) &&
207 winpr_ndr_decoder_treat_deferreds(decoder, &cpayload))
208 goto out;
209
210 retCode = 0;
211out:
213 return retCode;
214}
215
216/* ========================================================================== */
217typedef struct
218{
219 UINT32 count;
220 BYTE* data;
221} TEST_BLOB;
222
223static const WinPrNdrFieldStruct TEST_BLOB_fields[] = {
224 { "count", offsetof(TEST_BLOB, count), WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s },
225 { "data", offsetof(TEST_BLOB, data), WINPR_NDR_POINTER_NON_NULL, 0,
226 &winpr_ndr_uint8Array_descr_s },
227};
228
229static const WinPrNdrStructDescr TEST_BLOB_struct = { "TEST_BLOB", ARRAYSIZE(TEST_BLOB_fields),
230 TEST_BLOB_fields };
231
232NDR_TYPEDEF(TEST_BLOB)
233
234static BOOL ndr_read_TEST_BLOB_array(WinPrNdrDecoder* context, wStream* s, const void* hints,
235 void* v)
236{
237 return winpr_ndr_decoder_read_uconformant_array(context, s, hints, &ndr_TEST_BLOB_descr_s, v);
238}
239
240static BOOL ndr_write_TEST_BLOB_array(WinPrNdrEncoder* context, wStream* s, const void* hints,
241 const void* v)
242{
243 const WinPrNdrArrayHints* ahints = hints;
244 return winpr_ndr_encoder_write_uconformant_array(context, s, ahints->count,
245 &ndr_TEST_BLOB_descr_s, v);
246}
247
248static void ndr_destroy_TEST_BLOB_array(const void* hints, void* obj)
249{
250 const WinPrNdrArrayHints* ahints = hints;
251 TEST_BLOB* blobs = obj;
252 for (UINT32 i = 0; i < ahints->count; i++)
253 winpr_ndr_struct_destroy(&TEST_BLOB_struct, &blobs[i]);
254}
255
256static const WinPrNdrMessageDescr ndr_TEST_BLOB_array_descr_s = {
257 WINPR_NDR_ARITY_ARRAYOF, sizeof(TEST_BLOB), ndr_read_TEST_BLOB_array,
258 ndr_write_TEST_BLOB_array, ndr_destroy_TEST_BLOB_array, nullptr
259};
260
261typedef struct
262{
263 WinPrNdrArrayHints hints;
264 TEST_BLOB* blobs;
265} TEST_BLOBS;
266
267static const WinPrNdrFieldStruct TEST_BLOBS_fields[] = {
268 { "count", offsetof(TEST_BLOBS, hints.count), WINPR_NDR_NOT_POINTER, -1,
269 &winpr_ndr_uint32_descr_s },
270 { "blobs", offsetof(TEST_BLOBS, blobs), WINPR_NDR_POINTER, 0, &ndr_TEST_BLOB_array_descr_s },
271};
272
273static const WinPrNdrStructDescr TEST_BLOBS_struct = { "TEST_BLOBS", ARRAYSIZE(TEST_BLOBS_fields),
274 TEST_BLOBS_fields };
275
276/* the referents of the pointers embedded in array items come after the array, in item order */
277static const BYTE blobsPayload[] = {
278 0x02, 0x00, 0x00, 0x00, /* count */
279 0x00, 0x00, 0x02, 0x00, /* blobs */
280 0x02, 0x00, 0x00, 0x00, /* blobs: conformance */
281 0x01, 0x00, 0x00, 0x00, /* blobs[0].count */
282 0x04, 0x00, 0x02, 0x00, /* blobs[0].data */
283 0x02, 0x00, 0x00, 0x00, /* blobs[1].count */
284 0x08, 0x00, 0x02, 0x00, /* blobs[1].data */
285 0x01, 0x00, 0x00, 0x00, /* blobs[0].data: conformance */
286 'A', 0x00, 0x00, 0x00, /* blobs[0].data, padding */
287 0x02, 0x00, 0x00, 0x00, /* blobs[1].data: conformance */
288 'B', 'C' /* blobs[1].data */
289};
290
291static int TestNdrDeferredOrderWrite(void)
292{
293 int retCode = -2;
294 BYTE data0[] = { 'A' };
295 BYTE data1[] = { 'B', 'C' };
296 TEST_BLOB items[] = { { 1, data0 }, { 2, data1 } };
297 TEST_BLOBS blobs = { { 2 }, items };
298
299 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(FALSE, 1);
300 wStream* s = Stream_New(nullptr, 100);
301 if (!encoder || !s)
302 goto out;
303
304 retCode = -3;
305 if (!winpr_ndr_encoder_write_fromDescr(encoder, s, &TEST_BLOBS_struct, &blobs) ||
307 goto out;
308
309 retCode = -4;
310 if ((Stream_GetPosition(s) != sizeof(blobsPayload)) ||
311 (memcmp(Stream_Buffer(s), blobsPayload, sizeof(blobsPayload)) != 0))
312 goto out;
313
314 retCode = 0;
315out:
316 Stream_Free(s, TRUE);
318 return retCode;
319}
320
321static int TestNdrDeferredOrderRead(void)
322{
323 int retCode = -2;
324 TEST_BLOBS blobs = WINPR_C_ARRAY_INIT;
325 wStream staticS;
326 wStream* s = Stream_StaticConstInit(&staticS, blobsPayload, sizeof(blobsPayload));
327
328 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new(FALSE, 1);
329 if (!decoder)
330 return -1;
331
332 if (!winpr_ndr_decoder_read_fromDescr(decoder, s, &TEST_BLOBS_struct, &blobs) ||
334 goto out;
335
336 retCode = -3;
337 if ((Stream_GetRemainingLength(s) != 0) || (blobs.hints.count != 2) || !blobs.blobs)
338 goto out;
339
340 retCode = -4;
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))
343 goto out;
344
345 retCode = 0;
346out:
347 winpr_ndr_struct_destroy(&TEST_BLOBS_struct, &blobs);
349 return retCode;
350}
351
352static int TestNdrObject(void)
353{
354 int retCode = -2;
355 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(FALSE, 1);
356 wStream* s = Stream_New(nullptr, 100);
357 if (!encoder || !s)
358 goto out;
359
360 retCode = -3;
361 if (!winpr_ndr_encoder_write_header(encoder, s) ||
362 !winpr_ndr_encoder_start_object(encoder, s) ||
364 !winpr_ndr_encoder_write_uint16(encoder, s, 0x1234) ||
365 !winpr_ndr_encoder_end_object(encoder, s))
366 goto out;
367
368 /* the object data is padded to a multiple of 8 */
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 };
372 retCode = -4;
373 if ((Stream_GetPosition(s) != sizeof(expected)) ||
374 (memcmp(Stream_Buffer(s), expected, sizeof(expected)) != 0))
375 goto out;
376
377 retCode = -5;
378 Stream_SealLength(s);
379 Stream_SetPosition(s, 0);
380
381 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new_fromStream(s);
382 wStream object = WINPR_C_ARRAY_INIT;
383 winpr_ndr_refid refId = 0;
384 UINT16 v = 0;
385 const BOOL ok = decoder && winpr_ndr_decoder_read_object(decoder, s, &object) &&
386 (Stream_GetRemainingLength(s) == 0) &&
387 winpr_ndr_decoder_read_refpointer(decoder, &object, &refId) &&
388 (refId == 0x20000) && winpr_ndr_decoder_read_uint16(decoder, &object, &v) &&
389 (v == 0x1234);
391 if (ok)
392 retCode = 0;
393out:
394 Stream_Free(s, TRUE);
396 return retCode;
397}
398
399/* the signed types in both byte orders: aligned on their size, sign kept */
400static int TestNdrSignedTypes(void)
401{
402 for (int bigEndian = 0; bigEndian < 2; bigEndian++)
403 {
404 int retCode = -2;
405 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(bigEndian != 0, 1);
406 WinPrNdrDecoder* decoder = nullptr;
407 wStream* s = Stream_New(nullptr, 64);
408 if (!encoder || !s)
409 goto out;
410
411 retCode = -3;
412 const INT8 i8 = -2;
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))
419 goto out;
420
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;
426 retCode = -4;
427 if ((Stream_GetPosition(s) != sizeof(expectedLE)) ||
428 (memcmp(Stream_Buffer(s), expected, sizeof(expectedLE)) != 0))
429 goto out;
430
431 retCode = -5;
432 Stream_SealLength(s);
433 Stream_SetPosition(s, 0);
434 decoder = winpr_ndr_decoder_new(bigEndian != 0, 1);
435 INT8 r8 = 0;
436 INT8 r8bis = 0;
437 INT16 r16 = 0;
438 INT64 r64 = 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))
443 goto out;
444
445 retCode = -6;
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))
449 goto out;
450
451 retCode = 0;
452 out:
455 Stream_Free(s, TRUE);
456 if (retCode)
457 return retCode - (bigEndian * 10);
458 }
459 return 0;
460}
461
462/* ================================== full pointers ======================================== */
463
464static BOOL decode_payload(const WinPrNdrStructDescr* descr, const BYTE* payload, size_t len,
465 void* obj)
466{
467 wStream staticS;
468 wStream* s = Stream_StaticConstInit(&staticS, payload, len);
469
470 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new(FALSE, 1);
471 const BOOL ok = decoder && winpr_ndr_decoder_read_fromDescr(decoder, s, descr, obj) &&
473 (Stream_GetRemainingLength(s) == 0);
475 return ok;
476}
477
478typedef struct
479{
480 UINT32* a;
481 UINT32* b;
482} FULL_PAIR;
483
484static const WinPrNdrFieldStruct FULL_PAIR_fields[] = {
485 { "a", offsetof(FULL_PAIR, a), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
486 { "b", offsetof(FULL_PAIR, b), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
487};
488
489static const WinPrNdrStructDescr FULL_PAIR_struct = { "FULL_PAIR", ARRAYSIZE(FULL_PAIR_fields),
490 FULL_PAIR_fields };
491
492/* two full pointers on the same referent: the referent is sent once */
493static int TestNdrFullPointerAlias(void)
494{
495 const BYTE payload[] = {
496 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x78, 0x56, 0x34, 0x12
497 };
498 FULL_PAIR pair = WINPR_C_ARRAY_INIT;
499 int retCode = -2;
500
501 if (!decode_payload(&FULL_PAIR_struct, payload, sizeof(payload), &pair))
502 goto out;
503
504 retCode = -3;
505 if (!pair.a || (pair.a != pair.b) || (*pair.a != 0x12345678))
506 goto out;
507
508 /* a reference keeps the referent after the structure is destroyed */
509 UINT32* kept = winpr_ndr_pointer_ref(pair.a);
510 winpr_ndr_struct_destroy(&FULL_PAIR_struct, &pair);
511
512 retCode = -4;
513 if (pair.a || pair.b || (*kept != 0x12345678))
514 {
516 goto out;
517 }
519
520 /* distinct referents */
521 const BYTE payload2[] = { 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00,
522 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 };
523 retCode = -5;
524 if (!decode_payload(&FULL_PAIR_struct, payload2, sizeof(payload2), &pair) ||
525 (pair.a == pair.b) || (*pair.a != 1) || (*pair.b != 2))
526 goto out;
527
528 retCode = 0;
529out:
530 winpr_ndr_struct_destroy(&FULL_PAIR_struct, &pair);
531 return retCode;
532}
533
534typedef struct
535{
536 UINT32* a;
537 UINT16* b;
538} FULL_MIXED;
539
540static const WinPrNdrFieldStruct FULL_MIXED_fields[] = {
541 { "a", offsetof(FULL_MIXED, a), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
542 { "b", offsetof(FULL_MIXED, b), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint16_descr_s },
543};
544
545static const WinPrNdrStructDescr FULL_MIXED_struct = { "FULL_MIXED", ARRAYSIZE(FULL_MIXED_fields),
546 FULL_MIXED_fields };
547
548typedef struct
549{
550 UINT32* u;
551 UINT32* f;
552} UNIQUE_FULL;
553
554static const WinPrNdrFieldStruct UNIQUE_FULL_fields[] = {
555 { "u", offsetof(UNIQUE_FULL, u), WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s },
556 { "f", offsetof(UNIQUE_FULL, f), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
557};
558
559static const WinPrNdrStructDescr UNIQUE_FULL_struct = { "UNIQUE_FULL",
560 ARRAYSIZE(UNIQUE_FULL_fields),
561 UNIQUE_FULL_fields };
562
563typedef struct
564{
566 BYTE* a;
568 BYTE* b;
569} FULL_ARRAYS;
570
571static const WinPrNdrFieldStruct FULL_ARRAYS_fields[] = {
572 { "n1", offsetof(FULL_ARRAYS, n1), WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s },
573 { "a", offsetof(FULL_ARRAYS, a), WINPR_NDR_POINTER_FULL, 0, &winpr_ndr_uint8Array_descr_s },
574 { "n2", offsetof(FULL_ARRAYS, n2), WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s },
575 { "b", offsetof(FULL_ARRAYS, b), WINPR_NDR_POINTER_FULL, 2, &winpr_ndr_uint8Array_descr_s },
576};
577
578static const WinPrNdrStructDescr FULL_ARRAYS_struct = { "FULL_ARRAYS",
579 ARRAYSIZE(FULL_ARRAYS_fields),
580 FULL_ARRAYS_fields };
581
582/* an aliased referent must keep its type and size */
583static int TestNdrFullPointerConfusion(void)
584{
585 int retCode = -2;
586
587 /* a UINT32 referent read as a UINT16 */
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);
591 winpr_ndr_struct_destroy(&FULL_MIXED_struct, &fmixed);
592 if (mixedOk)
593 return retCode;
594
595 /* the referent of a unique pointer can't be aliased */
596 retCode = -3;
597 UNIQUE_FULL ufull = WINPR_C_ARRAY_INIT;
598 const BOOL ufullOk = decode_payload(&UNIQUE_FULL_struct, mixed, sizeof(mixed), &ufull);
599 winpr_ndr_struct_destroy(&UNIQUE_FULL_struct, &ufull);
600 if (ufullOk)
601 return retCode;
602
603 /* arrays of the same type and size can be aliased */
604 retCode = -4;
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);
611 winpr_ndr_struct_destroy(&FULL_ARRAYS_struct, &farrays);
612 if (!arraysOk)
613 return retCode;
614
615 /* but not arrays of another size: the second one would be read past the referent */
616 retCode = -5;
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);
620 winpr_ndr_struct_destroy(&FULL_ARRAYS_struct, &farrays);
621 if (sizesOk)
622 return retCode;
623
624 return 0;
625}
626
627/* ================================== unions ======================================== */
628
629/* struct { short CallId; [switch_type(short), switch_is(CallId)] union {
630 * [case(0x10)] long Value; [case(0x20)] long* Pointer; [default]; } u; } */
631typedef union
632{
633 UINT32 Value;
634 UINT32* Pointer;
635} SHORT_UNION;
636
637static const WinPrNdrUnionArm SHORT_UNION_arms[] = {
638 { 0x10, { "Value", 0, WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s, 0, 0 } },
639 { 0x20, { "Pointer", 0, WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s, 0, 0 } },
640};
641static const WinPrNdrUnionArm SHORT_UNION_default = {
642 0, { "default", 0, WINPR_NDR_NOT_POINTER, -1, nullptr, 0, 0 }
643};
644static const WinPrNdrUnionDescr SHORT_UNION_union = { "SHORT_UNION", ARRAYSIZE(SHORT_UNION_arms),
645 SHORT_UNION_arms, 2, &SHORT_UNION_default };
646
647WINPR_NDR_UNION_MESSAGE_DEFINE(SHORT_UNION, SHORT_UNION);
648
649typedef struct
650{
651 UINT16 CallId;
652 SHORT_UNION u;
653} SHORT_SWITCH;
654
655static const WinPrNdrFieldStruct SHORT_SWITCH_fields[] = {
656 { "CallId", offsetof(SHORT_SWITCH, CallId), WINPR_NDR_NOT_POINTER, -1,
657 &winpr_ndr_uint16_descr_s, 0, 0 },
658 { "u", offsetof(SHORT_SWITCH, u), WINPR_NDR_NOT_POINTER, 0, &SHORT_UNION_descr_s, 0, 0 },
659};
660
661static const WinPrNdrStructDescr SHORT_SWITCH_struct = { "SHORT_SWITCH",
662 ARRAYSIZE(SHORT_SWITCH_fields),
663 SHORT_SWITCH_fields, 4 };
664
665static const BYTE shortSwitchPointer[] = {
666 0x20, 0x00, 0x20, 0x00, /* CallId, discriminant */
667 0x00, 0x00, 0x02, 0x00, /* Pointer */
668 0x44, 0x33, 0x22, 0x11, /* *Pointer */
669};
670
671static const BYTE shortSwitchValue[] = {
672 0x10, 0x00, 0x10, 0x00, /* CallId, discriminant */
673 0x88, 0x77, 0x66, 0x55, /* Value */
674};
675
676/* CallId, discriminant */
677static const BYTE shortSwitchDefault[] = { 0x99, 0x00, 0x99, 0x00 };
678
679static const BYTE shortSwitchMismatch[] = {
680 0x10, 0x00, 0x20, 0x00, /* CallId, discriminant */
681 0x88, 0x77, 0x66, 0x55,
682};
683
684static int TestNdrUnionWrite(void)
685{
686 int retCode = -2;
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) };
694
695 wStream* s = Stream_New(nullptr, 100);
696 if (!s)
697 return -1;
698
699 for (size_t i = 0; i < ARRAYSIZE(msgs); i++)
700 {
701 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(FALSE, 1);
702 Stream_SetPosition(s, 0);
703
704 const BOOL ok =
705 encoder &&
706 winpr_ndr_encoder_write_fromDescr(encoder, s, &SHORT_SWITCH_struct, &msgs[i]) &&
708 (Stream_GetPosition(s) == expectedLen[i]) &&
709 (memcmp(Stream_Buffer(s), expected[i], expectedLen[i]) == 0);
711 if (!ok)
712 goto out;
713 }
714
715 retCode = 0;
716out:
717 Stream_Free(s, TRUE);
718 return retCode;
719}
720
721static int TestNdrUnionRead(void)
722{
723 SHORT_SWITCH msg = WINPR_C_ARRAY_INIT;
724 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchPointer, sizeof(shortSwitchPointer),
725 &msg) ||
726 (msg.CallId != 0x20) || !msg.u.Pointer || (*msg.u.Pointer != 0x11223344))
727 return -2;
728 winpr_ndr_struct_destroy(&SHORT_SWITCH_struct, &msg);
729
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))
733 return -3;
734
735 SHORT_SWITCH def = WINPR_C_ARRAY_INIT;
736 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchDefault, sizeof(shortSwitchDefault),
737 &def) ||
738 (def.CallId != 0x99))
739 return -4;
740
741 SHORT_SWITCH mismatch = WINPR_C_ARRAY_INIT;
742 if (decode_payload(&SHORT_SWITCH_struct, shortSwitchMismatch, sizeof(shortSwitchMismatch),
743 &mismatch))
744 return -5;
745 winpr_ndr_struct_destroy(&SHORT_SWITCH_struct, &mismatch);
746
747 return 0;
748}
749
750int TestNdrBasic(int argc, char* argv[])
751{
752 WINPR_UNUSED(argc);
753 WINPR_UNUSED(argv);
754
755 int (*const tests[])(void) = { TestNdrBasic_1,
756 TestNdrStaticArrayRead,
757 TestNdrStaticArrayWrite,
758 TestNdrStaticArrayOverflow,
759 TestNdrDeferredOrderWrite,
760 TestNdrDeferredOrderRead,
761 TestNdrObject,
762 TestNdrSignedTypes,
763 TestNdrFullPointerAlias,
764 TestNdrFullPointerConfusion,
765 TestNdrUnionWrite,
766 TestNdrUnionRead };
767
768 for (size_t i = 0; i < ARRAYSIZE(tests); i++)
769 {
770 const int ret = tests[i]();
771 if (ret)
772 {
773 (void)fprintf(stderr, "test %" PRIuz " failed with %d\n", i, ret);
774 return ret;
775 }
776 }
777
778 return 0;
779}
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()
Definition ndr.c:282
UINT32 winpr_ndr_refid
a referent id, the wire value of a pointer (WINPR_NDR_PTR_NULL for a null pointer)
Definition ndr.h:230
@ WINPR_NDR_NOT_POINTER
Definition ndr.h:313
@ WINPR_NDR_POINTER_FULL
Definition ndr.h:320
@ WINPR_NDR_FIXED_ARRAY
Definition ndr.h:317
@ WINPR_NDR_POINTER
Definition ndr.h:316
@ WINPR_NDR_POINTER_NON_NULL
Definition ndr.h:315
WINPR_API void * winpr_ndr_pointer_ref(void *ptr)
takes a reference on a referent
Definition ndr.c:1433
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
Definition ndr.c:224
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
Definition ndr.c:1321
static INLINE void winpr_ndr_decoder_destroy(WinPrNdrDecoder **pcontext)
frees a decoder and resets the pointer
Definition ndr.h:657
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
Definition ndr.c:1655
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_treat_deferreds(WinPrNdrEncoder *context, wStream *s)
writes the pending deferred referents
Definition ndr.c:1030
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new(BOOL bigEndianDrep, BYTE version)
creates a decoder
Definition ndr.c:1061
WINPR_API WinPrNdrEncoder * winpr_ndr_encoder_new(BOOL bigEndianDrep, BYTE version)
creates an encoder
Definition ndr.c:194
static INLINE void winpr_ndr_encoder_destroy(WinPrNdrEncoder **pcontext)
frees an encoder and resets the pointer
Definition ndr.h:405
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
Definition ndr.c:317
@ WINPR_NDR_ARITY_ARRAYOF
Definition ndr.h:281
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_read_refpointer(WinPrNdrDecoder *context, wStream *s, UINT32 *refId)
reads a referent id
Definition ndr.c:1149
WINPR_API void winpr_ndr_pointer_release(void *ptr)
releases a referent
Definition ndr.c:1443
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)
Definition ndr.c:1154
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
Definition ndr.c:1079
#define WINPR_NDR_UNION_MESSAGE_DEFINE(PREFIX, CTYPE)
defines a static message type for a non-encapsulated union
Definition ndr.h:186
WINPR_API void winpr_ndr_struct_destroy(const WinPrNdrStructDescr *descr, void *pptr)
releases the content of a structure from its descriptor
Definition ndr.c:1965
UINT32 count
Definition ndr.h:554
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
Definition ndr.c:987
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()
Definition ndr.c:1763
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
Definition ndr.c:890
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)
Definition ndr.c:259
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_decoder_treat_deferreds(WinPrNdrDecoder *context, wStream *s)
reads the pending deferred referents
Definition ndr.c:1674
hints for a conformant array
Definition ndr.h:553
a deferred pointer, a referent to read after the current construct
Definition ndr.h:382
descriptor of a field in a structure
Definition ndr.h:328
message descriptor
Definition ndr.h:294
structure descriptor
Definition ndr.h:343
an arm of a non-encapsulated union
Definition ndr.h:354
a non-encapsulated union ([switch_type()])
Definition ndr.h:368