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/* ===================================== WCHAR ============================================= */
463
464/* WinPR WCHAR strings are UTF-16LE in memory whatever the host byte order, "a€" */
465static const BYTE wcharMemory[] = { 'a', 0x00, 0xac, 0x20 };
466
467static const BYTE wcharArrayLE[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468 0x02, 0x00, 0x00, 0x00, 'a', 0x00, 0xac, 0x20 };
469static const BYTE wcharArrayBE[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
470 0x00, 0x00, 0x00, 0x02, 0x00, 'a', 0x20, 0xac };
471
472static int TestNdrWchar(void)
473{
474 for (int bigEndian = 0; bigEndian < 2; bigEndian++)
475 {
476 const BYTE* expected = bigEndian ? wcharArrayBE : wcharArrayLE;
477 WCHAR str[ARRAYSIZE(wcharMemory) / sizeof(WCHAR) + 1] = WINPR_C_ARRAY_INIT;
478 WCHAR* decodedStr = nullptr;
479 WCHAR decoded[ARRAYSIZE(str)] = WINPR_C_ARRAY_INIT;
480 memcpy(str, wcharMemory, sizeof(wcharMemory));
481
482 int retCode = -2;
483 WinPrNdrDecoder* decoder = nullptr;
484 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(bigEndian != 0, 1);
485 wStream* s = Stream_New(nullptr, 64);
486 if (!encoder || !s)
487 goto out;
488
489 /* the encoder hints are item counts */
490 retCode = -3;
491 const WinPrNdrVaryingArrayHints countHints = { 2, 2 };
492 if (!winpr_ndr_wcharVaryingArray_descr()->writeFn(encoder, s, &countHints, str) ||
493 (Stream_GetPosition(s) != sizeof(wcharArrayLE)) ||
494 (memcmp(Stream_Buffer(s), expected, sizeof(wcharArrayLE)) != 0))
495 goto out;
496
497 /* the decoder hints are byte lengths, like the ones of a RPC_UNICODE_STRING */
498 retCode = -4;
499 Stream_SealLength(s);
500 Stream_SetPosition(s, 0);
501 decoder = winpr_ndr_decoder_new(bigEndian != 0, 1);
502 const WinPrNdrVaryingArrayHints byteHints = { sizeof(wcharMemory), sizeof(wcharMemory) };
503 if (!decoder ||
504 !winpr_ndr_wcharVaryingArray_descr()->readFn(decoder, s, &byteHints, decoded) ||
505 (Stream_GetRemainingLength(s) != 0) ||
506 (memcmp(decoded, wcharMemory, sizeof(wcharMemory)) != 0))
507 goto out;
508
509 /* [string] wchar_t*: the same characters and a terminating null */
510 retCode = -5;
511 const WCHAR* pstr = str;
512 Stream_SetPosition(s, 0);
513 if (!winpr_ndr_wstring_varying_descr()->writeFn(encoder, s, nullptr, (const void*)&pstr))
514 goto out;
515
516 retCode = -6;
517 Stream_SealLength(s);
518 Stream_SetPosition(s, 0);
520 decoder = winpr_ndr_decoder_new(bigEndian != 0, 1);
521 if (!decoder ||
522 !winpr_ndr_wstring_varying_descr()->readFn(decoder, s, nullptr, (void*)&decodedStr) ||
523 !decodedStr || (memcmp(decodedStr, wcharMemory, sizeof(wcharMemory)) != 0) ||
524 (decodedStr[ARRAYSIZE(str) - 1] != 0))
525 goto out;
526
527 retCode = 0;
528 out:
529 winpr_ndr_pointer_release(decodedStr);
532 Stream_Free(s, TRUE);
533 if (retCode)
534 return retCode - (bigEndian * 10);
535 }
536 return 0;
537}
538
539/* ================================== full pointers ======================================== */
540
541static BOOL decode_payload(const WinPrNdrStructDescr* descr, const BYTE* payload, size_t len,
542 void* obj)
543{
544 wStream staticS;
545 wStream* s = Stream_StaticConstInit(&staticS, payload, len);
546
547 WinPrNdrDecoder* decoder = winpr_ndr_decoder_new(FALSE, 1);
548 const BOOL ok = decoder && winpr_ndr_decoder_read_fromDescr(decoder, s, descr, obj) &&
550 (Stream_GetRemainingLength(s) == 0);
552 return ok;
553}
554
555typedef struct
556{
557 UINT32* a;
558 UINT32* b;
559} FULL_PAIR;
560
561static const WinPrNdrFieldStruct FULL_PAIR_fields[] = {
562 { "a", offsetof(FULL_PAIR, a), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
563 { "b", offsetof(FULL_PAIR, b), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
564};
565
566static const WinPrNdrStructDescr FULL_PAIR_struct = { "FULL_PAIR", ARRAYSIZE(FULL_PAIR_fields),
567 FULL_PAIR_fields };
568
569/* two full pointers on the same referent: the referent is sent once */
570static int TestNdrFullPointerAlias(void)
571{
572 const BYTE payload[] = {
573 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x78, 0x56, 0x34, 0x12
574 };
575 FULL_PAIR pair = WINPR_C_ARRAY_INIT;
576 int retCode = -2;
577
578 if (!decode_payload(&FULL_PAIR_struct, payload, sizeof(payload), &pair))
579 goto out;
580
581 retCode = -3;
582 if (!pair.a || (pair.a != pair.b) || (*pair.a != 0x12345678))
583 goto out;
584
585 /* a reference keeps the referent after the structure is destroyed */
586 UINT32* kept = winpr_ndr_pointer_ref(pair.a);
587 winpr_ndr_struct_destroy(&FULL_PAIR_struct, &pair);
588
589 retCode = -4;
590 if (pair.a || pair.b || (*kept != 0x12345678))
591 {
593 goto out;
594 }
596
597 /* distinct referents */
598 const BYTE payload2[] = { 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00,
599 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 };
600 retCode = -5;
601 if (!decode_payload(&FULL_PAIR_struct, payload2, sizeof(payload2), &pair) ||
602 (pair.a == pair.b) || (*pair.a != 1) || (*pair.b != 2))
603 goto out;
604
605 retCode = 0;
606out:
607 winpr_ndr_struct_destroy(&FULL_PAIR_struct, &pair);
608 return retCode;
609}
610
611typedef struct
612{
613 UINT32* a;
614 UINT16* b;
615} FULL_MIXED;
616
617static const WinPrNdrFieldStruct FULL_MIXED_fields[] = {
618 { "a", offsetof(FULL_MIXED, a), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
619 { "b", offsetof(FULL_MIXED, b), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint16_descr_s },
620};
621
622static const WinPrNdrStructDescr FULL_MIXED_struct = { "FULL_MIXED", ARRAYSIZE(FULL_MIXED_fields),
623 FULL_MIXED_fields };
624
625typedef struct
626{
627 UINT32* u;
628 UINT32* f;
629} UNIQUE_FULL;
630
631static const WinPrNdrFieldStruct UNIQUE_FULL_fields[] = {
632 { "u", offsetof(UNIQUE_FULL, u), WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s },
633 { "f", offsetof(UNIQUE_FULL, f), WINPR_NDR_POINTER_FULL, -1, &winpr_ndr_uint32_descr_s },
634};
635
636static const WinPrNdrStructDescr UNIQUE_FULL_struct = { "UNIQUE_FULL",
637 ARRAYSIZE(UNIQUE_FULL_fields),
638 UNIQUE_FULL_fields };
639
640typedef struct
641{
643 BYTE* a;
645 BYTE* b;
646} FULL_ARRAYS;
647
648static const WinPrNdrFieldStruct FULL_ARRAYS_fields[] = {
649 { "n1", offsetof(FULL_ARRAYS, n1), WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s },
650 { "a", offsetof(FULL_ARRAYS, a), WINPR_NDR_POINTER_FULL, 0, &winpr_ndr_uint8Array_descr_s },
651 { "n2", offsetof(FULL_ARRAYS, n2), WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s },
652 { "b", offsetof(FULL_ARRAYS, b), WINPR_NDR_POINTER_FULL, 2, &winpr_ndr_uint8Array_descr_s },
653};
654
655static const WinPrNdrStructDescr FULL_ARRAYS_struct = { "FULL_ARRAYS",
656 ARRAYSIZE(FULL_ARRAYS_fields),
657 FULL_ARRAYS_fields };
658
659/* an aliased referent must keep its type and size */
660static int TestNdrFullPointerConfusion(void)
661{
662 int retCode = -2;
663
664 /* a UINT32 referent read as a UINT16 */
665 const BYTE mixed[] = { 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x78, 0x56, 0x34, 0x12 };
666 FULL_MIXED fmixed = WINPR_C_ARRAY_INIT;
667 const BOOL mixedOk = decode_payload(&FULL_MIXED_struct, mixed, sizeof(mixed), &fmixed);
668 winpr_ndr_struct_destroy(&FULL_MIXED_struct, &fmixed);
669 if (mixedOk)
670 return retCode;
671
672 /* the referent of a unique pointer can't be aliased */
673 retCode = -3;
674 UNIQUE_FULL ufull = WINPR_C_ARRAY_INIT;
675 const BOOL ufullOk = decode_payload(&UNIQUE_FULL_struct, mixed, sizeof(mixed), &ufull);
676 winpr_ndr_struct_destroy(&UNIQUE_FULL_struct, &ufull);
677 if (ufullOk)
678 return retCode;
679
680 /* arrays of the same type and size can be aliased */
681 retCode = -4;
682 const BYTE arrays[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 'A', 'B' };
684 FULL_ARRAYS farrays = WINPR_C_ARRAY_INIT;
685 const BOOL arraysOk = decode_payload(&FULL_ARRAYS_struct, arrays, sizeof(arrays), &farrays) &&
686 farrays.a && (farrays.a == farrays.b) &&
687 (memcmp(farrays.a, "AB", 2) == 0);
688 winpr_ndr_struct_destroy(&FULL_ARRAYS_struct, &farrays);
689 if (!arraysOk)
690 return retCode;
691
692 /* but not arrays of another size: the second one would be read past the referent */
693 retCode = -5;
694 const BYTE sizes[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x00, 0x00,
695 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 'A', 'B' };
696 const BOOL sizesOk = decode_payload(&FULL_ARRAYS_struct, sizes, sizeof(sizes), &farrays);
697 winpr_ndr_struct_destroy(&FULL_ARRAYS_struct, &farrays);
698 if (sizesOk)
699 return retCode;
700
701 return 0;
702}
703
704/* ================================== unions ======================================== */
705
706/* struct { short CallId; [switch_type(short), switch_is(CallId)] union {
707 * [case(0x10)] long Value; [case(0x20)] long* Pointer; [default]; } u; } */
708typedef union
709{
710 UINT32 Value;
711 UINT32* Pointer;
712} SHORT_UNION;
713
714static const WinPrNdrUnionArm SHORT_UNION_arms[] = {
715 { 0x10, { "Value", 0, WINPR_NDR_NOT_POINTER, -1, &winpr_ndr_uint32_descr_s, 0, 0 } },
716 { 0x20, { "Pointer", 0, WINPR_NDR_POINTER, -1, &winpr_ndr_uint32_descr_s, 0, 0 } },
717};
718static const WinPrNdrUnionArm SHORT_UNION_default = {
719 0, { "default", 0, WINPR_NDR_NOT_POINTER, -1, nullptr, 0, 0 }
720};
721static const WinPrNdrUnionDescr SHORT_UNION_union = { "SHORT_UNION", ARRAYSIZE(SHORT_UNION_arms),
722 SHORT_UNION_arms, 2, &SHORT_UNION_default };
723
724WINPR_NDR_UNION_MESSAGE_DEFINE(SHORT_UNION, SHORT_UNION);
725
726typedef struct
727{
728 UINT16 CallId;
729 SHORT_UNION u;
730} SHORT_SWITCH;
731
732static const WinPrNdrFieldStruct SHORT_SWITCH_fields[] = {
733 { "CallId", offsetof(SHORT_SWITCH, CallId), WINPR_NDR_NOT_POINTER, -1,
734 &winpr_ndr_uint16_descr_s, 0, 0 },
735 { "u", offsetof(SHORT_SWITCH, u), WINPR_NDR_NOT_POINTER, 0, &SHORT_UNION_descr_s, 0, 0 },
736};
737
738static const WinPrNdrStructDescr SHORT_SWITCH_struct = { "SHORT_SWITCH",
739 ARRAYSIZE(SHORT_SWITCH_fields),
740 SHORT_SWITCH_fields, 4 };
741
742static const BYTE shortSwitchPointer[] = {
743 0x20, 0x00, 0x20, 0x00, /* CallId, discriminant */
744 0x00, 0x00, 0x02, 0x00, /* Pointer */
745 0x44, 0x33, 0x22, 0x11, /* *Pointer */
746};
747
748static const BYTE shortSwitchValue[] = {
749 0x10, 0x00, 0x10, 0x00, /* CallId, discriminant */
750 0x88, 0x77, 0x66, 0x55, /* Value */
751};
752
753/* CallId, discriminant */
754static const BYTE shortSwitchDefault[] = { 0x99, 0x00, 0x99, 0x00 };
755
756static const BYTE shortSwitchMismatch[] = {
757 0x10, 0x00, 0x20, 0x00, /* CallId, discriminant */
758 0x88, 0x77, 0x66, 0x55,
759};
760
761static int TestNdrUnionWrite(void)
762{
763 int retCode = -2;
764 UINT32 value = 0x11223344;
765 const SHORT_SWITCH msgs[] = { { 0x20, { .Pointer = &value } },
766 { 0x10, { .Value = 0x55667788 } },
767 { 0x99, { .Value = 0 } } };
768 const BYTE* expected[] = { shortSwitchPointer, shortSwitchValue, shortSwitchDefault };
769 const size_t expectedLen[] = { sizeof(shortSwitchPointer), sizeof(shortSwitchValue),
770 sizeof(shortSwitchDefault) };
771
772 wStream* s = Stream_New(nullptr, 100);
773 if (!s)
774 return -1;
775
776 for (size_t i = 0; i < ARRAYSIZE(msgs); i++)
777 {
778 WinPrNdrEncoder* encoder = winpr_ndr_encoder_new(FALSE, 1);
779 Stream_SetPosition(s, 0);
780
781 const BOOL ok =
782 encoder &&
783 winpr_ndr_encoder_write_fromDescr(encoder, s, &SHORT_SWITCH_struct, &msgs[i]) &&
785 (Stream_GetPosition(s) == expectedLen[i]) &&
786 (memcmp(Stream_Buffer(s), expected[i], expectedLen[i]) == 0);
788 if (!ok)
789 goto out;
790 }
791
792 retCode = 0;
793out:
794 Stream_Free(s, TRUE);
795 return retCode;
796}
797
798static int TestNdrUnionRead(void)
799{
800 SHORT_SWITCH msg = WINPR_C_ARRAY_INIT;
801 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchPointer, sizeof(shortSwitchPointer),
802 &msg) ||
803 (msg.CallId != 0x20) || !msg.u.Pointer || (*msg.u.Pointer != 0x11223344))
804 return -2;
805 winpr_ndr_struct_destroy(&SHORT_SWITCH_struct, &msg);
806
807 SHORT_SWITCH value = WINPR_C_ARRAY_INIT;
808 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchValue, sizeof(shortSwitchValue), &value) ||
809 (value.CallId != 0x10) || (value.u.Value != 0x55667788))
810 return -3;
811
812 SHORT_SWITCH def = WINPR_C_ARRAY_INIT;
813 if (!decode_payload(&SHORT_SWITCH_struct, shortSwitchDefault, sizeof(shortSwitchDefault),
814 &def) ||
815 (def.CallId != 0x99))
816 return -4;
817
818 SHORT_SWITCH mismatch = WINPR_C_ARRAY_INIT;
819 if (decode_payload(&SHORT_SWITCH_struct, shortSwitchMismatch, sizeof(shortSwitchMismatch),
820 &mismatch))
821 return -5;
822 winpr_ndr_struct_destroy(&SHORT_SWITCH_struct, &mismatch);
823
824 return 0;
825}
826
827int TestNdrBasic(int argc, char* argv[])
828{
829 WINPR_UNUSED(argc);
830 WINPR_UNUSED(argv);
831
832 int (*const tests[])(void) = { TestNdrBasic_1,
833 TestNdrStaticArrayRead,
834 TestNdrStaticArrayWrite,
835 TestNdrStaticArrayOverflow,
836 TestNdrDeferredOrderWrite,
837 TestNdrDeferredOrderRead,
838 TestNdrObject,
839 TestNdrSignedTypes,
840 TestNdrWchar,
841 TestNdrFullPointerAlias,
842 TestNdrFullPointerConfusion,
843 TestNdrUnionWrite,
844 TestNdrUnionRead };
845
846 for (size_t i = 0; i < ARRAYSIZE(tests); i++)
847 {
848 const int ret = tests[i]();
849 if (ret)
850 {
851 (void)fprintf(stderr, "test %" PRIuz " failed with %d\n", i, ret);
852 return ret;
853 }
854 }
855
856 return 0;
857}
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:1473
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:1361
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:1695
WINPR_ATTR_NODISCARD WINPR_API WinPrNdrMessageType winpr_ndr_wstring_varying_descr(void)
the message type of winpr_ndr_wstring_varying_descr_s
Definition ndr.c:898
WINPR_ATTR_NODISCARD WINPR_API BOOL winpr_ndr_encoder_treat_deferreds(WinPrNdrEncoder *context, wStream *s)
writes the pending deferred referents
Definition ndr.c:1075
WINPR_API WinPrNdrDecoder * winpr_ndr_decoder_new(BOOL bigEndianDrep, BYTE version)
creates a decoder
Definition ndr.c:1106
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:1194
WINPR_API void winpr_ndr_pointer_release(void *ptr)
releases a referent
Definition ndr.c:1483
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:1199
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:1124
#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:2005
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:1032
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:1803
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:935
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:1714
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
hints for a conformant varying array
Definition ndr.h:526