1 /*
2 Unix SMB/CIFS implementation.
3
4 libndr interface
5
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2005-2008
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24 this provides the core routines for NDR parsing functions
25
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27 of NDR encoding rules
28 */
29
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_RPC_PARSE
36
37 #define NDR_BASE_MARSHALL_SIZE 1024
38
39 /*
40 * This value is arbitary, but designed to reduce the memory a client
41 * can allocate and the work the client can force in processing a
42 * malicious packet.
43 *
44 * In an ideal world this would be controlled by range() restrictions
45 * on array sizes and careful IDL construction to avoid arbitary
46 * linked lists, but this is a backstop for now.
47 */
48 #define NDR_TOKEN_MAX_LIST_SIZE 65535
49
50 /* this guid indicates NDR encoding in a protocol tower */
51 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
52 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
53 2
54 };
55
56 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
57 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
58 1
59 };
60
61 const struct ndr_syntax_id ndr_syntax_id_null = {
62 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
63 0
64 };
65
66 /*
67 work out the number of bytes needed to align on a n byte boundary
68 */
ndr_align_size(uint32_t offset,size_t n)69 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
70 {
71 if ((offset & (n-1)) == 0) return 0;
72 return n - (offset & (n-1));
73 }
74
75 /*
76 initialise a ndr parse structure from a data blob
77 */
ndr_pull_init_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx)78 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
79 {
80 struct ndr_pull *ndr;
81
82 ndr = talloc_zero(mem_ctx, struct ndr_pull);
83 if (!ndr) return NULL;
84 ndr->current_mem_ctx = mem_ctx;
85
86 ndr->data = blob->data;
87 ndr->data_size = blob->length;
88
89 return ndr;
90 }
91
ndr_pull_append(struct ndr_pull * ndr,DATA_BLOB * blob)92 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
93 {
94 enum ndr_err_code ndr_err;
95 DATA_BLOB b;
96 uint32_t append = 0;
97 bool ok;
98
99 if (blob->length == 0) {
100 return NDR_ERR_SUCCESS;
101 }
102
103 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
104 if (ndr_err == NDR_ERR_TOKEN) {
105 append = 0;
106 ndr_err = NDR_ERR_SUCCESS;
107 }
108 NDR_CHECK(ndr_err);
109
110 if (ndr->data_size == 0) {
111 ndr->data = NULL;
112 append = UINT32_MAX;
113 }
114
115 if (append == UINT32_MAX) {
116 /*
117 * append == UINT32_MAX means that
118 * ndr->data is either NULL or a valid
119 * talloc child of ndr, which means
120 * we can use data_blob_append() without
121 * data_blob_talloc() of the existing callers data
122 */
123 b = data_blob_const(ndr->data, ndr->data_size);
124 } else {
125 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
126 if (b.data == NULL) {
127 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
128 }
129 }
130
131 ok = data_blob_append(ndr, &b, blob->data, blob->length);
132 if (!ok) {
133 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
134 }
135
136 ndr->data = b.data;
137 ndr->data_size = b.length;
138
139 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
140 }
141
ndr_pull_pop(struct ndr_pull * ndr)142 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
143 {
144 uint32_t skip = 0;
145 uint32_t append = 0;
146
147 if (ndr->relative_base_offset != 0) {
148 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
149 "%s", __location__);
150 }
151 if (ndr->relative_highest_offset != 0) {
152 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
153 "%s", __location__);
154 }
155 if (ndr->relative_list.count != 0) {
156 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
157 "%s", __location__);
158 }
159 if (ndr->relative_base_list.count != 0) {
160 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
161 "%s", __location__);
162 }
163
164 /*
165 * we need to keep up to 7 bytes
166 * in order to get the aligment right.
167 */
168 skip = ndr->offset & 0xFFFFFFF8;
169
170 if (skip == 0) {
171 return NDR_ERR_SUCCESS;
172 }
173
174 ndr->offset -= skip;
175 ndr->data_size -= skip;
176
177 append = ndr_token_peek(&ndr->array_size_list, ndr);
178 if (append != UINT32_MAX) {
179 /*
180 * here we assume, that ndr->data is not a
181 * talloc child of ndr.
182 */
183 ndr->data += skip;
184 return NDR_ERR_SUCCESS;
185 }
186
187 memmove(ndr->data, ndr->data + skip, ndr->data_size);
188
189 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
190 if (ndr->data_size != 0 && ndr->data == NULL) {
191 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
192 }
193
194 return NDR_ERR_SUCCESS;
195 }
196
197 /*
198 advance by 'size' bytes
199 */
ndr_pull_advance(struct ndr_pull * ndr,uint32_t size)200 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
201 {
202 ndr->offset += size;
203 if (ndr->offset > ndr->data_size) {
204 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
205 "ndr_pull_advance by %u failed",
206 size);
207 }
208 return NDR_ERR_SUCCESS;
209 }
210
211 /*
212 set the parse offset to 'ofs'
213 */
ndr_pull_set_offset(struct ndr_pull * ndr,uint32_t ofs)214 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
215 {
216 ndr->offset = ofs;
217 if (ndr->offset > ndr->data_size) {
218 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
219 "ndr_pull_set_offset %u failed",
220 ofs);
221 }
222 return NDR_ERR_SUCCESS;
223 }
224
225 /* create a ndr_push structure, ready for some marshalling */
ndr_push_init_ctx(TALLOC_CTX * mem_ctx)226 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
227 {
228 struct ndr_push *ndr;
229
230 ndr = talloc_zero(mem_ctx, struct ndr_push);
231 if (!ndr) {
232 return NULL;
233 }
234
235 ndr->flags = 0;
236 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
237 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
238 if (!ndr->data) {
239 talloc_free(ndr);
240 return NULL;
241 }
242
243 return ndr;
244 }
245
246 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
ndr_push_blob(struct ndr_push * ndr)247 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
248 {
249 DATA_BLOB blob;
250 blob = data_blob_const(ndr->data, ndr->offset);
251 if (ndr->alloc_size > ndr->offset) {
252 ndr->data[ndr->offset] = 0;
253 }
254 return blob;
255 }
256
257
258 /*
259 expand the available space in the buffer to ndr->offset + extra_size
260 */
ndr_push_expand(struct ndr_push * ndr,uint32_t extra_size)261 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
262 {
263 uint32_t size = extra_size + ndr->offset;
264
265 if (size < ndr->offset) {
266 /* extra_size overflowed the offset */
267 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
268 size);
269 }
270
271 if (ndr->fixed_buf_size) {
272 if (ndr->alloc_size >= size) {
273 return NDR_ERR_SUCCESS;
274 }
275 return ndr_push_error(ndr,
276 NDR_ERR_BUFSIZE,
277 "Overflow of fixed buffer in "
278 "push_expand to %u",
279 size);
280 }
281
282 if (ndr->alloc_size > size) {
283 return NDR_ERR_SUCCESS;
284 }
285
286 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
287 if (size+1 > ndr->alloc_size) {
288 ndr->alloc_size = size+1;
289 }
290 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
291 if (!ndr->data) {
292 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
293 ndr->alloc_size);
294 }
295
296 return NDR_ERR_SUCCESS;
297 }
298
ndr_print_debugc_helper(struct ndr_print * ndr,const char * format,...)299 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
300 {
301 va_list ap;
302 char *s = NULL;
303 uint32_t i;
304 int ret;
305 int dbgc_class;
306
307 va_start(ap, format);
308 ret = vasprintf(&s, format, ap);
309 va_end(ap);
310
311 if (ret == -1) {
312 return;
313 }
314
315 dbgc_class = *(int *)ndr->private_data;
316
317 if (ndr->no_newline) {
318 DEBUGADDC(dbgc_class, 1,("%s", s));
319 free(s);
320 return;
321 }
322
323 for (i=0;i<ndr->depth;i++) {
324 DEBUGADDC(dbgc_class, 1,(" "));
325 }
326
327 DEBUGADDC(dbgc_class, 1,("%s\n", s));
328 free(s);
329 }
330
ndr_print_debug_helper(struct ndr_print * ndr,const char * format,...)331 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
332 {
333 va_list ap;
334 char *s = NULL;
335 uint32_t i;
336 int ret;
337
338 va_start(ap, format);
339 ret = vasprintf(&s, format, ap);
340 va_end(ap);
341
342 if (ret == -1) {
343 return;
344 }
345
346 if (ndr->no_newline) {
347 DEBUGADD(1,("%s", s));
348 free(s);
349 return;
350 }
351
352 for (i=0;i<ndr->depth;i++) {
353 DEBUGADD(1,(" "));
354 }
355
356 DEBUGADD(1,("%s\n", s));
357 free(s);
358 }
359
ndr_print_printf_helper(struct ndr_print * ndr,const char * format,...)360 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
361 {
362 va_list ap;
363 uint32_t i;
364
365 if (!ndr->no_newline) {
366 for (i=0;i<ndr->depth;i++) {
367 printf(" ");
368 }
369 }
370
371 va_start(ap, format);
372 vprintf(format, ap);
373 va_end(ap);
374 if (!ndr->no_newline) {
375 printf("\n");
376 }
377 }
378
ndr_print_string_helper(struct ndr_print * ndr,const char * format,...)379 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
380 {
381 va_list ap;
382 uint32_t i;
383
384 if (!ndr->no_newline) {
385 for (i=0;i<ndr->depth;i++) {
386 ndr->private_data = talloc_asprintf_append_buffer(
387 (char *)ndr->private_data, " ");
388 }
389 }
390
391 va_start(ap, format);
392 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
393 format, ap);
394 va_end(ap);
395 if (!ndr->no_newline) {
396 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
397 "\n");
398 }
399 }
400
401 /*
402 a useful helper function for printing idl structures via DEBUGC()
403 */
ndr_print_debugc(int dbgc_class,ndr_print_fn_t fn,const char * name,void * ptr)404 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
405 {
406 struct ndr_print *ndr;
407
408 DEBUGC(dbgc_class, 1,(" "));
409
410 ndr = talloc_zero(NULL, struct ndr_print);
411 if (!ndr) return;
412 ndr->private_data = &dbgc_class;
413 ndr->print = ndr_print_debugc_helper;
414 ndr->depth = 1;
415 ndr->flags = 0;
416 #ifdef DEBUG_PASSWORD
417 if (CHECK_DEBUGLVL(100)) {
418 ndr->print_secrets = true;
419 }
420 #endif
421
422 fn(ndr, name, ptr);
423 talloc_free(ndr);
424 }
425
426 /*
427 a useful helper function for printing idl structures via DEBUG()
428 */
ndr_print_debug(ndr_print_fn_t fn,const char * name,void * ptr)429 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
430 {
431 struct ndr_print *ndr;
432
433 DEBUG(1,(" "));
434
435 ndr = talloc_zero(NULL, struct ndr_print);
436 if (!ndr) return;
437 ndr->print = ndr_print_debug_helper;
438 ndr->depth = 1;
439 ndr->flags = 0;
440 #ifdef DEBUG_PASSWORD
441 if (CHECK_DEBUGLVL(100)) {
442 ndr->print_secrets = true;
443 }
444 #endif
445
446 fn(ndr, name, ptr);
447 talloc_free(ndr);
448 }
449
450 /*
451 a useful helper function for printing idl unions via DEBUG()
452 */
ndr_print_union_debug(ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)453 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
454 {
455 struct ndr_print *ndr;
456
457 DEBUG(1,(" "));
458
459 ndr = talloc_zero(NULL, struct ndr_print);
460 if (!ndr) return;
461 ndr->print = ndr_print_debug_helper;
462 ndr->depth = 1;
463 ndr->flags = 0;
464 #ifdef DEBUG_PASSWORD
465 if (CHECK_DEBUGLVL(100)) {
466 ndr->print_secrets = true;
467 }
468 #endif
469
470 ndr_print_set_switch_value(ndr, ptr, level);
471 fn(ndr, name, ptr);
472 talloc_free(ndr);
473 }
474
475 /*
476 a useful helper function for printing idl function calls via DEBUG()
477 */
ndr_print_function_debug(ndr_print_function_t fn,const char * name,int flags,void * ptr)478 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
479 {
480 struct ndr_print *ndr;
481
482 DEBUG(1,(" "));
483
484 ndr = talloc_zero(NULL, struct ndr_print);
485 if (!ndr) return;
486 ndr->print = ndr_print_debug_helper;
487 ndr->depth = 1;
488 ndr->flags = 0;
489 #ifdef DEBUG_PASSWORD
490 if (CHECK_DEBUGLVL(100)) {
491 ndr->print_secrets = true;
492 }
493 #endif
494
495 fn(ndr, name, flags, ptr);
496 talloc_free(ndr);
497 }
498
499 /*
500 a useful helper function for printing idl structures to a string
501 */
ndr_print_struct_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,void * ptr)502 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
503 {
504 struct ndr_print *ndr;
505 char *ret = NULL;
506
507 ndr = talloc_zero(mem_ctx, struct ndr_print);
508 if (!ndr) return NULL;
509 ndr->private_data = talloc_strdup(ndr, "");
510 if (!ndr->private_data) {
511 goto failed;
512 }
513 ndr->print = ndr_print_string_helper;
514 ndr->depth = 1;
515 ndr->flags = 0;
516
517 fn(ndr, name, ptr);
518 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
519 failed:
520 talloc_free(ndr);
521 return ret;
522 }
523
524 /*
525 a useful helper function for printing idl unions to a string
526 */
ndr_print_union_string(TALLOC_CTX * mem_ctx,ndr_print_fn_t fn,const char * name,uint32_t level,void * ptr)527 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
528 {
529 struct ndr_print *ndr;
530 char *ret = NULL;
531
532 ndr = talloc_zero(mem_ctx, struct ndr_print);
533 if (!ndr) return NULL;
534 ndr->private_data = talloc_strdup(ndr, "");
535 if (!ndr->private_data) {
536 goto failed;
537 }
538 ndr->print = ndr_print_string_helper;
539 ndr->depth = 1;
540 ndr->flags = 0;
541 ndr_print_set_switch_value(ndr, ptr, level);
542 fn(ndr, name, ptr);
543 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
544 failed:
545 talloc_free(ndr);
546 return ret;
547 }
548
549 /*
550 a useful helper function for printing idl function calls to a string
551 */
ndr_print_function_string(TALLOC_CTX * mem_ctx,ndr_print_function_t fn,const char * name,int flags,void * ptr)552 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
553 ndr_print_function_t fn, const char *name,
554 int flags, void *ptr)
555 {
556 struct ndr_print *ndr;
557 char *ret = NULL;
558
559 ndr = talloc_zero(mem_ctx, struct ndr_print);
560 if (!ndr) return NULL;
561 ndr->private_data = talloc_strdup(ndr, "");
562 if (!ndr->private_data) {
563 goto failed;
564 }
565 ndr->print = ndr_print_string_helper;
566 ndr->depth = 1;
567 ndr->flags = 0;
568 fn(ndr, name, flags, ptr);
569 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
570 failed:
571 talloc_free(ndr);
572 return ret;
573 }
574
ndr_set_flags(uint32_t * pflags,uint32_t new_flags)575 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
576 {
577 /* the big/little endian flags are inter-dependent */
578 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
579 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
580 (*pflags) &= ~LIBNDR_FLAG_NDR64;
581 }
582 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
583 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
584 (*pflags) &= ~LIBNDR_FLAG_NDR64;
585 }
586 if (new_flags & LIBNDR_ALIGN_FLAGS) {
587 /* Ensure we only have the passed-in
588 align flag set in the new_flags,
589 remove any old align flag. */
590 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
591 }
592 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
593 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
594 }
595 (*pflags) |= new_flags;
596 }
597
598 /*
599 return and possibly log an NDR error
600 */
_ndr_pull_error(struct ndr_pull * ndr,enum ndr_err_code ndr_err,const char * function,const char * location,const char * format,...)601 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
602 enum ndr_err_code ndr_err,
603 const char *function,
604 const char *location,
605 const char *format, ...)
606 {
607 char *s=NULL;
608 va_list ap;
609 int ret;
610
611 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
612 switch (ndr_err) {
613 case NDR_ERR_BUFSIZE:
614 return NDR_ERR_INCOMPLETE_BUFFER;
615 default:
616 break;
617 }
618 }
619
620 va_start(ap, format);
621 ret = vasprintf(&s, format, ap);
622 va_end(ap);
623
624 if (ret == -1) {
625 return NDR_ERR_ALLOC;
626 }
627
628 D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
629 function,
630 ndr_map_error2string(ndr_err),
631 s,
632 location);
633
634 free(s);
635
636 return ndr_err;
637 }
638
639 /*
640 return and possibly log an NDR error
641 */
_ndr_push_error(struct ndr_push * ndr,enum ndr_err_code ndr_err,const char * function,const char * location,const char * format,...)642 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
643 enum ndr_err_code ndr_err,
644 const char *function,
645 const char *location,
646 const char *format, ...)
647 {
648 char *s=NULL;
649 va_list ap;
650 int ret;
651
652 va_start(ap, format);
653 ret = vasprintf(&s, format, ap);
654 va_end(ap);
655
656 if (ret == -1) {
657 return NDR_ERR_ALLOC;
658 }
659
660 D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
661 function,
662 ndr_map_error2string(ndr_err),
663 s,
664 location);
665
666 free(s);
667
668 return ndr_err;
669 }
670
671 /*
672 handle subcontext buffers, which in midl land are user-marshalled, but
673 we use magic in pidl to make them easier to cope with
674 */
ndr_pull_subcontext_start(struct ndr_pull * ndr,struct ndr_pull ** _subndr,size_t header_size,ssize_t size_is)675 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
676 struct ndr_pull **_subndr,
677 size_t header_size,
678 ssize_t size_is)
679 {
680 struct ndr_pull *subndr;
681 uint32_t r_content_size;
682 bool force_le = false;
683 bool force_be = false;
684
685 switch (header_size) {
686 case 0: {
687 uint32_t content_size = ndr->data_size - ndr->offset;
688 if (size_is >= 0) {
689 content_size = size_is;
690 }
691 r_content_size = content_size;
692 break;
693 }
694
695 case 2: {
696 uint16_t content_size;
697 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
698 if (size_is >= 0 && size_is != content_size) {
699 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
700 (int)size_is, (int)size_is,
701 (int)content_size,
702 (int)content_size);
703 }
704 r_content_size = content_size;
705 break;
706 }
707
708 case 4: {
709 uint32_t content_size;
710 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
711 if (size_is >= 0 && size_is != content_size) {
712 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
713 (int)size_is, (int)size_is,
714 (int)content_size,
715 (int)content_size);
716 }
717 r_content_size = content_size;
718 break;
719 }
720 case 0xFFFFFC01: {
721 /*
722 * Common Type Header for the Serialization Stream
723 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
724 */
725 uint8_t version;
726 uint8_t drep;
727 uint16_t hdrlen;
728 uint32_t filler;
729 uint32_t content_size;
730 uint32_t reserved;
731
732 /* version */
733 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
734
735 if (version != 1) {
736 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
737 "Bad subcontext (PULL) Common Type Header version %d != 1",
738 (int)version);
739 }
740
741 /*
742 * 0x10 little endian
743 * 0x00 big endian
744 */
745 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
746 if (drep == 0x10) {
747 force_le = true;
748 } else if (drep == 0x00) {
749 force_be = true;
750 } else {
751 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
752 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
753 (unsigned int)drep);
754 }
755
756 /* length of the "Private Header for Constructed Type" */
757 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
758 if (hdrlen != 8) {
759 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
760 "Bad subcontext (PULL) Common Type Header length %d != 8",
761 (int)hdrlen);
762 }
763
764 /* filler should be ignored */
765 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
766
767 /*
768 * Private Header for Constructed Type
769 */
770 /* length - will be updated latter */
771 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
772 if (size_is >= 0 && size_is != content_size) {
773 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
774 (int)size_is, (int)content_size);
775 }
776 /* the content size must be a multiple of 8 */
777 if ((content_size % 8) != 0) {
778 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
779 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
780 (int)size_is, (int)content_size);
781 }
782 r_content_size = content_size;
783
784 /* reserved */
785 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
786 break;
787 }
788 case 0xFFFFFFFF:
789 /*
790 * a shallow copy like subcontext
791 * useful for DCERPC pipe chunks.
792 */
793 subndr = talloc_zero(ndr, struct ndr_pull);
794 NDR_ERR_HAVE_NO_MEMORY(subndr);
795
796 subndr->flags = ndr->flags;
797 subndr->current_mem_ctx = ndr->current_mem_ctx;
798 subndr->data = ndr->data;
799 subndr->offset = ndr->offset;
800 subndr->data_size = ndr->data_size;
801
802 *_subndr = subndr;
803 return NDR_ERR_SUCCESS;
804
805 default:
806 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
807 (int)header_size);
808 }
809
810 NDR_PULL_NEED_BYTES(ndr, r_content_size);
811
812 subndr = talloc_zero(ndr, struct ndr_pull);
813 NDR_ERR_HAVE_NO_MEMORY(subndr);
814 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
815 subndr->current_mem_ctx = ndr->current_mem_ctx;
816
817 subndr->data = ndr->data + ndr->offset;
818 subndr->offset = 0;
819 subndr->data_size = r_content_size;
820
821 if (force_le) {
822 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
823 } else if (force_be) {
824 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
825 }
826
827 *_subndr = subndr;
828 return NDR_ERR_SUCCESS;
829 }
830
ndr_pull_subcontext_end(struct ndr_pull * ndr,struct ndr_pull * subndr,size_t header_size,ssize_t size_is)831 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
832 struct ndr_pull *subndr,
833 size_t header_size,
834 ssize_t size_is)
835 {
836 uint32_t advance;
837 uint32_t highest_ofs;
838
839 if (header_size == 0xFFFFFFFF) {
840 advance = subndr->offset - ndr->offset;
841 } else if (size_is >= 0) {
842 advance = size_is;
843 } else if (header_size > 0) {
844 advance = subndr->data_size;
845 } else {
846 advance = subndr->offset;
847 }
848
849 if (subndr->offset > ndr->relative_highest_offset) {
850 highest_ofs = subndr->offset;
851 } else {
852 highest_ofs = subndr->relative_highest_offset;
853 }
854 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
855 /*
856 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
857 */
858 highest_ofs = advance;
859 }
860 if (highest_ofs < advance) {
861 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
862 "not all bytes consumed ofs[%u] advance[%u]",
863 highest_ofs, advance);
864 }
865
866 NDR_CHECK(ndr_pull_advance(ndr, advance));
867 return NDR_ERR_SUCCESS;
868 }
869
ndr_push_subcontext_start(struct ndr_push * ndr,struct ndr_push ** _subndr,size_t header_size,ssize_t size_is)870 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
871 struct ndr_push **_subndr,
872 size_t header_size,
873 ssize_t size_is)
874 {
875 struct ndr_push *subndr;
876
877 subndr = ndr_push_init_ctx(ndr);
878 NDR_ERR_HAVE_NO_MEMORY(subndr);
879 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
880
881 if (size_is > 0) {
882 NDR_CHECK(ndr_push_zero(subndr, size_is));
883 subndr->offset = 0;
884 subndr->relative_end_offset = size_is;
885 }
886
887 *_subndr = subndr;
888 return NDR_ERR_SUCCESS;
889 }
890
891 /*
892 push a subcontext header
893 */
ndr_push_subcontext_end(struct ndr_push * ndr,struct ndr_push * subndr,size_t header_size,ssize_t size_is)894 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
895 struct ndr_push *subndr,
896 size_t header_size,
897 ssize_t size_is)
898 {
899 ssize_t padding_len;
900
901 if (size_is >= 0) {
902 padding_len = size_is - subndr->offset;
903 if (padding_len < 0) {
904 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
905 (int)subndr->offset, (int)size_is);
906 }
907 subndr->offset = size_is;
908 }
909
910 switch (header_size) {
911 case 0:
912 break;
913
914 case 2:
915 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
916 break;
917
918 case 4:
919 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
920 break;
921
922 case 0xFFFFFC01:
923 /*
924 * Common Type Header for the Serialization Stream
925 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
926 */
927 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
928 if (padding_len > 0) {
929 NDR_CHECK(ndr_push_zero(subndr, padding_len));
930 }
931
932 /* version */
933 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
934
935 /*
936 * 0x10 little endian
937 * 0x00 big endian
938 */
939 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
940
941 /* length of the "Private Header for Constructed Type" */
942 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
943
944 /* filler */
945 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
946
947 /*
948 * Private Header for Constructed Type
949 */
950 /* length - will be updated latter */
951 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
952
953 /* reserved */
954 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
955 break;
956
957 default:
958 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
959 (int)header_size);
960 }
961
962 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
963 return NDR_ERR_SUCCESS;
964 }
965
966
967 struct ndr_token {
968 const void *key;
969 uint32_t value;
970 };
971
972 /*
973 store a token in the ndr context, for later retrieval
974 */
ndr_token_store(TALLOC_CTX * mem_ctx,struct ndr_token_list * list,const void * key,uint32_t value)975 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
976 struct ndr_token_list *list,
977 const void *key,
978 uint32_t value)
979 {
980 if (list->tokens == NULL) {
981 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
982 if (list->tokens == NULL) {
983 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
984 }
985 } else {
986 struct ndr_token *new_tokens = NULL;
987 uint32_t alloc_count = talloc_array_length(list->tokens);
988
989 /*
990 * Check every time we have not allocated too many
991 * tokens. This ensures developer sanity when
992 * debugging the boundary condition
993 */
994 if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
995 return NDR_ERR_RANGE;
996 }
997 if (list->count == alloc_count) {
998 unsigned new_alloc;
999 /*
1000 * Double the list, until we start in chunks
1001 * of 1000
1002 */
1003 unsigned increment = MIN(list->count, 1000);
1004 new_alloc = alloc_count + increment;
1005 if (new_alloc < alloc_count) {
1006 return NDR_ERR_RANGE;
1007 }
1008 new_tokens = talloc_realloc(mem_ctx, list->tokens,
1009 struct ndr_token, new_alloc);
1010 NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1011 list->tokens = new_tokens;
1012 }
1013 }
1014 list->tokens[list->count].key = key;
1015 list->tokens[list->count].value = value;
1016 list->count++;
1017 return NDR_ERR_SUCCESS;
1018 }
1019
1020 /*
1021 retrieve a token from a ndr context, using cmp_fn to match the tokens
1022 */
ndr_token_retrieve_cmp_fn(struct ndr_token_list * list,const void * key,uint32_t * v,comparison_fn_t _cmp_fn,bool erase)1023 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
1024 const void *key, uint32_t *v,
1025 comparison_fn_t _cmp_fn,
1026 bool erase)
1027 {
1028 struct ndr_token *tokens = list->tokens;
1029 unsigned i;
1030 if (_cmp_fn) {
1031 for (i = list->count - 1; i < list->count; i--) {
1032 if (_cmp_fn(tokens[i].key, key) == 0) {
1033 goto found;
1034 }
1035 }
1036 } else {
1037 for (i = list->count - 1; i < list->count; i--) {
1038 if (tokens[i].key == key) {
1039 goto found;
1040 }
1041 }
1042 }
1043 return NDR_ERR_TOKEN;
1044 found:
1045 *v = tokens[i].value;
1046 if (erase) {
1047 if (i != list->count - 1) {
1048 tokens[i] = tokens[list->count - 1];
1049 }
1050 list->count--;
1051 }
1052 return NDR_ERR_SUCCESS;
1053 }
1054
1055 /*
1056 retrieve a token from a ndr context
1057 */
ndr_token_retrieve(struct ndr_token_list * list,const void * key,uint32_t * v)1058 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1059 const void *key, uint32_t *v)
1060 {
1061 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1062 }
1063
1064 /*
1065 peek at but don't removed a token from a ndr context
1066 */
ndr_token_peek(struct ndr_token_list * list,const void * key)1067 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list *list, const void *key)
1068 {
1069 unsigned i;
1070 struct ndr_token *tokens = list->tokens;
1071
1072 for (i = list->count - 1; i < list->count; i--) {
1073 if (tokens[i].key == key) {
1074 return tokens[i].value;
1075 }
1076 }
1077
1078 return 0;
1079 }
1080
1081 /*
1082 pull an array size field and add it to the array_size_list token list
1083 */
ndr_pull_array_size(struct ndr_pull * ndr,const void * p)1084 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1085 {
1086 enum ndr_err_code ret;
1087 uint32_t size;
1088 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1089 ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1090 if (ret == NDR_ERR_RANGE) {
1091 return ndr_pull_error(ndr, ret,
1092 "More than %d NDR tokens stored for array_size",
1093 NDR_TOKEN_MAX_LIST_SIZE);
1094 }
1095 return ret;
1096 }
1097
1098 /*
1099 get the stored array size field
1100 */
ndr_get_array_size(struct ndr_pull * ndr,const void * p)1101 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
1102 {
1103 return ndr_token_peek(&ndr->array_size_list, p);
1104 }
1105
1106 /*
1107 check the stored array size field
1108 */
ndr_check_array_size(struct ndr_pull * ndr,void * p,uint32_t size)1109 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
1110 {
1111 uint32_t stored;
1112 stored = ndr_token_peek(&ndr->array_size_list, p);
1113 if (stored != size) {
1114 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1115 "Bad array size - got %u expected %u\n",
1116 stored, size);
1117 }
1118 return NDR_ERR_SUCCESS;
1119 }
1120
1121 /*
1122 pull an array length field and add it to the array_length_list token list
1123 */
ndr_pull_array_length(struct ndr_pull * ndr,const void * p)1124 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1125 {
1126 enum ndr_err_code ret;
1127 uint32_t length, offset;
1128 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1129 if (offset != 0) {
1130 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1131 "non-zero array offset %u\n", offset);
1132 }
1133 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1134 ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1135 if (ret == NDR_ERR_RANGE) {
1136 return ndr_pull_error(ndr, ret,
1137 "More than %d NDR tokens stored for array_length_list",
1138 NDR_TOKEN_MAX_LIST_SIZE);
1139 }
1140 return ret;
1141 }
1142
1143 /*
1144 get the stored array length field
1145 */
ndr_get_array_length(struct ndr_pull * ndr,const void * p)1146 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1147 {
1148 return ndr_token_peek(&ndr->array_length_list, p);
1149 }
1150
1151 /*
1152 check the stored array length field
1153 */
ndr_check_array_length(struct ndr_pull * ndr,void * p,uint32_t length)1154 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1155 {
1156 uint32_t stored;
1157 stored = ndr_token_peek(&ndr->array_length_list, p);
1158 if (stored != length) {
1159 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1160 "Bad array length - got %u expected %u\n",
1161 stored, length);
1162 }
1163 return NDR_ERR_SUCCESS;
1164 }
1165
ndr_push_pipe_chunk_trailer(struct ndr_push * ndr,int ndr_flags,uint32_t count)1166 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1167 {
1168 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1169 int64_t tmp = 0 - (int64_t)count;
1170 uint64_t ncount = tmp;
1171
1172 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1173 }
1174
1175 return NDR_ERR_SUCCESS;
1176 }
1177
ndr_check_pipe_chunk_trailer(struct ndr_pull * ndr,int ndr_flags,uint32_t count)1178 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1179 {
1180 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1181 int64_t tmp = 0 - (int64_t)count;
1182 uint64_t ncount1 = tmp;
1183 uint64_t ncount2;
1184
1185 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1186 if (ncount1 == ncount2) {
1187 return NDR_ERR_SUCCESS;
1188 }
1189
1190 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1191 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1192 (unsigned long long)ncount2,
1193 (unsigned long long)ncount1,
1194 (unsigned long)count);
1195 }
1196
1197 return NDR_ERR_SUCCESS;
1198 }
1199
1200 /*
1201 store a switch value
1202 */
ndr_push_set_switch_value(struct ndr_push * ndr,const void * p,uint32_t val)1203 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1204 {
1205 enum ndr_err_code ret =
1206 ndr_token_store(ndr, &ndr->switch_list, p, val);
1207 if (ret == NDR_ERR_RANGE) {
1208 return ndr_push_error(ndr, ret,
1209 "More than %d NDR tokens stored for switch_list",
1210 NDR_TOKEN_MAX_LIST_SIZE);
1211 }
1212 return ret;
1213 }
1214
ndr_pull_set_switch_value(struct ndr_pull * ndr,const void * p,uint32_t val)1215 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1216 {
1217
1218 enum ndr_err_code ret =
1219 ndr_token_store(ndr, &ndr->switch_list, p, val);
1220 if (ret == NDR_ERR_RANGE) {
1221 return ndr_pull_error(ndr, ret,
1222 "More than %d NDR tokens stored for switch_list",
1223 NDR_TOKEN_MAX_LIST_SIZE);
1224 }
1225 return ret;
1226 }
1227
ndr_print_set_switch_value(struct ndr_print * ndr,const void * p,uint32_t val)1228 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1229 {
1230 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1231 }
1232
1233 /* retrieve a switch value (for push) and remove it from the list */
ndr_push_steal_switch_value(struct ndr_push * ndr,const void * p,uint32_t * v)1234 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1235 const void *p,
1236 uint32_t *v)
1237 {
1238 return ndr_token_retrieve(&ndr->switch_list, p, v);
1239 }
1240
1241 /* retrieve a switch value and remove it from the list */
ndr_print_steal_switch_value(struct ndr_print * ndr,const void * p)1242 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1243 {
1244 enum ndr_err_code status;
1245 uint32_t v;
1246
1247 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1248 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1249 return 0;
1250 }
1251
1252 return v;
1253 }
1254
1255 /* retrieve a switch value and remove it from the list */
ndr_pull_steal_switch_value(struct ndr_pull * ndr,const void * p,uint32_t * v)1256 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1257 const void *p,
1258 uint32_t *v)
1259 {
1260 return ndr_token_retrieve(&ndr->switch_list, p, v);
1261 }
1262
1263 /*
1264 pull a struct from a blob using NDR
1265 */
ndr_pull_struct_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)1266 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1267 ndr_pull_flags_fn_t fn)
1268 {
1269 struct ndr_pull *ndr;
1270 ndr = ndr_pull_init_blob(blob, mem_ctx);
1271 NDR_ERR_HAVE_NO_MEMORY(ndr);
1272 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1273 talloc_free(ndr);
1274 return NDR_ERR_SUCCESS;
1275 }
1276
1277 /*
1278 pull a struct from a blob using NDR - failing if all bytes are not consumed
1279 */
ndr_pull_struct_blob_all(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,ndr_pull_flags_fn_t fn)1280 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1281 void *p, ndr_pull_flags_fn_t fn)
1282 {
1283 struct ndr_pull *ndr;
1284 uint32_t highest_ofs;
1285 ndr = ndr_pull_init_blob(blob, mem_ctx);
1286 NDR_ERR_HAVE_NO_MEMORY(ndr);
1287 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1288 if (ndr->offset > ndr->relative_highest_offset) {
1289 highest_ofs = ndr->offset;
1290 } else {
1291 highest_ofs = ndr->relative_highest_offset;
1292 }
1293 if (highest_ofs < ndr->data_size) {
1294 enum ndr_err_code ret;
1295 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1296 "not all bytes consumed ofs[%u] size[%u]",
1297 highest_ofs, ndr->data_size);
1298 talloc_free(ndr);
1299 return ret;
1300 }
1301 talloc_free(ndr);
1302 return NDR_ERR_SUCCESS;
1303 }
1304
1305 /*
1306 pull a struct from a blob using NDR - failing if all bytes are not consumed
1307
1308 This only works for structures with NO allocated memory, like
1309 objectSID and GUID. This helps because we parse these a lot.
1310 */
ndr_pull_struct_blob_all_noalloc(const DATA_BLOB * blob,void * p,ndr_pull_flags_fn_t fn)1311 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1312 void *p, ndr_pull_flags_fn_t fn)
1313 {
1314 /*
1315 * We init this structure on the stack here, to avoid a
1316 * talloc() as otherwise this call to the fn() is assured not
1317 * to be doing any allocation, eg SIDs and GUIDs.
1318 *
1319 * This allows us to keep the safety of the PIDL-generated
1320 * code without the talloc() overhead.
1321 */
1322 struct ndr_pull ndr = {
1323 .data = blob->data,
1324 .data_size = blob->length,
1325 .current_mem_ctx = (void *)-1
1326 };
1327 uint32_t highest_ofs;
1328 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1329 if (ndr.offset > ndr.relative_highest_offset) {
1330 highest_ofs = ndr.offset;
1331 } else {
1332 highest_ofs = ndr.relative_highest_offset;
1333 }
1334 if (highest_ofs < ndr.data_size) {
1335 enum ndr_err_code ret;
1336 ret = ndr_pull_error(&ndr, NDR_ERR_UNREAD_BYTES,
1337 "not all bytes consumed ofs[%u] size[%u]",
1338 highest_ofs, ndr.data_size);
1339 return ret;
1340 }
1341 return NDR_ERR_SUCCESS;
1342 }
1343
1344 /*
1345 pull a union from a blob using NDR, given the union discriminator
1346 */
ndr_pull_union_blob(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_pull_flags_fn_t fn)1347 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1348 void *p,
1349 uint32_t level, ndr_pull_flags_fn_t fn)
1350 {
1351 struct ndr_pull *ndr;
1352 ndr = ndr_pull_init_blob(blob, mem_ctx);
1353 NDR_ERR_HAVE_NO_MEMORY(ndr);
1354 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1355 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1356 talloc_free(ndr);
1357 return NDR_ERR_SUCCESS;
1358 }
1359
1360 /*
1361 pull a union from a blob using NDR, given the union discriminator,
1362 failing if all bytes are not consumed
1363 */
ndr_pull_union_blob_all(const DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_pull_flags_fn_t fn)1364 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1365 void *p,
1366 uint32_t level, ndr_pull_flags_fn_t fn)
1367 {
1368 struct ndr_pull *ndr;
1369 uint32_t highest_ofs;
1370 ndr = ndr_pull_init_blob(blob, mem_ctx);
1371 NDR_ERR_HAVE_NO_MEMORY(ndr);
1372 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1373 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1374 if (ndr->offset > ndr->relative_highest_offset) {
1375 highest_ofs = ndr->offset;
1376 } else {
1377 highest_ofs = ndr->relative_highest_offset;
1378 }
1379 if (highest_ofs < ndr->data_size) {
1380 enum ndr_err_code ret;
1381 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1382 "not all bytes consumed ofs[%u] size[%u]",
1383 highest_ofs, ndr->data_size);
1384 talloc_free(ndr);
1385 return ret;
1386 }
1387 talloc_free(ndr);
1388 return NDR_ERR_SUCCESS;
1389 }
1390
1391 /*
1392 push a struct to a blob using NDR
1393 */
ndr_push_struct_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,const void * p,ndr_push_flags_fn_t fn)1394 _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn)
1395 {
1396 struct ndr_push *ndr;
1397 ndr = ndr_push_init_ctx(mem_ctx);
1398 NDR_ERR_HAVE_NO_MEMORY(ndr);
1399
1400 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1401
1402 *blob = ndr_push_blob(ndr);
1403 talloc_steal(mem_ctx, blob->data);
1404 talloc_free(ndr);
1405
1406 return NDR_ERR_SUCCESS;
1407 }
1408
1409 /*
1410 push a struct into a provided blob using NDR.
1411
1412 We error because we want to have the performance issue (extra
1413 talloc() calls) show up as an error, not just slower code. This is
1414 used for things like GUIDs, which we expect to be a fixed size, and
1415 SIDs that we can pre-calculate the size for.
1416 */
ndr_push_struct_into_fixed_blob(DATA_BLOB * blob,const void * p,ndr_push_flags_fn_t fn)1417 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1418 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1419 {
1420 struct ndr_push ndr = {
1421 .data = blob->data,
1422 .alloc_size = blob->length,
1423 .fixed_buf_size = true
1424 };
1425
1426 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1427
1428 if (ndr.offset != blob->length) {
1429 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1430 "buffer was either to large or small "
1431 "ofs[%u] size[%zu]",
1432 ndr.offset, blob->length);
1433 }
1434
1435 return NDR_ERR_SUCCESS;
1436 }
1437
1438 /*
1439 push a union to a blob using NDR
1440 */
ndr_push_union_blob(DATA_BLOB * blob,TALLOC_CTX * mem_ctx,void * p,uint32_t level,ndr_push_flags_fn_t fn)1441 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1442 uint32_t level, ndr_push_flags_fn_t fn)
1443 {
1444 struct ndr_push *ndr;
1445 ndr = ndr_push_init_ctx(mem_ctx);
1446 NDR_ERR_HAVE_NO_MEMORY(ndr);
1447
1448 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1449 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1450
1451 *blob = ndr_push_blob(ndr);
1452 talloc_steal(mem_ctx, blob->data);
1453 talloc_free(ndr);
1454
1455 return NDR_ERR_SUCCESS;
1456 }
1457
1458 /*
1459 generic ndr_size_*() handler for structures
1460 */
ndr_size_struct(const void * p,int flags,ndr_push_flags_fn_t push)1461 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1462 {
1463 struct ndr_push *ndr;
1464 enum ndr_err_code status;
1465 size_t ret;
1466
1467 /* avoid recursion */
1468 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1469
1470 /* Avoid following a NULL pointer */
1471 if (p == NULL) {
1472 return 0;
1473 }
1474
1475 ndr = ndr_push_init_ctx(NULL);
1476 if (!ndr) return 0;
1477 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1478 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1479 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1480 talloc_free(ndr);
1481 return 0;
1482 }
1483 ret = ndr->offset;
1484 talloc_free(ndr);
1485 return ret;
1486 }
1487
1488 /*
1489 generic ndr_size_*() handler for unions
1490 */
ndr_size_union(const void * p,int flags,uint32_t level,ndr_push_flags_fn_t push)1491 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1492 {
1493 struct ndr_push *ndr;
1494 enum ndr_err_code status;
1495 size_t ret;
1496
1497 /* avoid recursion */
1498 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1499
1500 /* Avoid following a NULL pointer */
1501 if (p == NULL) {
1502 return 0;
1503 }
1504
1505 ndr = ndr_push_init_ctx(NULL);
1506 if (!ndr) return 0;
1507 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1508
1509 status = ndr_push_set_switch_value(ndr, p, level);
1510 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1511 talloc_free(ndr);
1512 return 0;
1513 }
1514 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1515 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1516 talloc_free(ndr);
1517 return 0;
1518 }
1519 ret = ndr->offset;
1520 talloc_free(ndr);
1521 return ret;
1522 }
1523
1524 /*
1525 get the current base for relative pointers for the push
1526 */
ndr_push_get_relative_base_offset(struct ndr_push * ndr)1527 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1528 {
1529 return ndr->relative_base_offset;
1530 }
1531
1532 /*
1533 restore the old base for relative pointers for the push
1534 */
ndr_push_restore_relative_base_offset(struct ndr_push * ndr,uint32_t offset)1535 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1536 {
1537 ndr->relative_base_offset = offset;
1538 }
1539
1540 /*
1541 setup the current base for relative pointers for the push
1542 called in the NDR_SCALAR stage
1543 */
ndr_push_setup_relative_base_offset1(struct ndr_push * ndr,const void * p,uint32_t offset)1544 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1545 {
1546 enum ndr_err_code ret;
1547 ndr->relative_base_offset = offset;
1548 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1549 if (ret == NDR_ERR_RANGE) {
1550 return ndr_push_error(ndr, ret,
1551 "More than %d NDR tokens stored for relative_base_list",
1552 NDR_TOKEN_MAX_LIST_SIZE);
1553 }
1554 return ret;
1555 }
1556
1557 /*
1558 setup the current base for relative pointers for the push
1559 called in the NDR_BUFFERS stage
1560 */
ndr_push_setup_relative_base_offset2(struct ndr_push * ndr,const void * p)1561 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1562 {
1563 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1564 }
1565
1566 /*
1567 push a relative object - stage1
1568 this is called during SCALARS processing
1569 */
ndr_push_relative_ptr1(struct ndr_push * ndr,const void * p)1570 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1571 {
1572 enum ndr_err_code ret;
1573 if (p == NULL) {
1574 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1575 return NDR_ERR_SUCCESS;
1576 }
1577 NDR_CHECK(ndr_push_align(ndr, 4));
1578 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1579 if (ret == NDR_ERR_RANGE) {
1580 return ndr_push_error(ndr, ret,
1581 "More than %d NDR tokens stored for relative_list",
1582 NDR_TOKEN_MAX_LIST_SIZE);
1583 }
1584 NDR_CHECK(ret);
1585 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1586 }
1587
1588 /*
1589 push a short relative object - stage1
1590 this is called during SCALARS processing
1591 */
ndr_push_short_relative_ptr1(struct ndr_push * ndr,const void * p)1592 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1593 {
1594 enum ndr_err_code ret;
1595 if (p == NULL) {
1596 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1597 return NDR_ERR_SUCCESS;
1598 }
1599 NDR_CHECK(ndr_push_align(ndr, 2));
1600 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1601 if (ret == NDR_ERR_RANGE) {
1602 return ndr_push_error(ndr, ret,
1603 "More than %d NDR tokens stored for relative_list",
1604 NDR_TOKEN_MAX_LIST_SIZE);
1605 }
1606 NDR_CHECK(ret);
1607 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1608 }
1609 /*
1610 push a relative object - stage2
1611 this is called during buffers processing
1612 */
ndr_push_relative_ptr2(struct ndr_push * ndr,const void * p)1613 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1614 {
1615 uint32_t save_offset;
1616 uint32_t ptr_offset = 0xFFFFFFFF;
1617 if (p == NULL) {
1618 return NDR_ERR_SUCCESS;
1619 }
1620 save_offset = ndr->offset;
1621 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1622 if (ptr_offset > ndr->offset) {
1623 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1624 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1625 ptr_offset, ndr->offset);
1626 }
1627 ndr->offset = ptr_offset;
1628 if (save_offset < ndr->relative_base_offset) {
1629 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1630 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1631 save_offset, ndr->relative_base_offset);
1632 }
1633 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1634 ndr->offset = save_offset;
1635 return NDR_ERR_SUCCESS;
1636 }
1637 /*
1638 push a short relative object - stage2
1639 this is called during buffers processing
1640 */
ndr_push_short_relative_ptr2(struct ndr_push * ndr,const void * p)1641 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1642 {
1643 uint32_t save_offset;
1644 uint32_t ptr_offset = 0xFFFF;
1645 uint32_t relative_offset;
1646 size_t pad;
1647 size_t align = 1;
1648
1649 if (p == NULL) {
1650 return NDR_ERR_SUCCESS;
1651 }
1652
1653 if (ndr->offset < ndr->relative_base_offset) {
1654 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1655 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1656 ndr->offset, ndr->relative_base_offset);
1657 }
1658
1659 relative_offset = ndr->offset - ndr->relative_base_offset;
1660
1661 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1662 align = 1;
1663 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1664 align = 2;
1665 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1666 align = 4;
1667 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1668 align = 8;
1669 }
1670
1671 pad = ndr_align_size(relative_offset, align);
1672 if (pad != 0) {
1673 NDR_CHECK(ndr_push_zero(ndr, pad));
1674 }
1675
1676 relative_offset = ndr->offset - ndr->relative_base_offset;
1677 if (relative_offset > UINT16_MAX) {
1678 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1679 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1680 relative_offset);
1681 }
1682
1683 save_offset = ndr->offset;
1684 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1685 if (ptr_offset > ndr->offset) {
1686 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1687 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1688 ptr_offset, ndr->offset);
1689 }
1690 ndr->offset = ptr_offset;
1691 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1692 ndr->offset = save_offset;
1693 return NDR_ERR_SUCCESS;
1694 }
1695
1696 /*
1697 push a relative object - stage2 start
1698 this is called during buffers processing
1699 */
ndr_push_relative_ptr2_start(struct ndr_push * ndr,const void * p)1700 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1701 {
1702 enum ndr_err_code ret;
1703 if (p == NULL) {
1704 return NDR_ERR_SUCCESS;
1705 }
1706 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1707 uint32_t relative_offset;
1708 size_t pad;
1709 size_t align = 1;
1710
1711 if (ndr->offset < ndr->relative_base_offset) {
1712 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1713 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1714 ndr->offset, ndr->relative_base_offset);
1715 }
1716
1717 relative_offset = ndr->offset - ndr->relative_base_offset;
1718
1719 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1720 align = 1;
1721 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1722 align = 2;
1723 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1724 align = 4;
1725 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1726 align = 8;
1727 }
1728
1729 pad = ndr_align_size(relative_offset, align);
1730 if (pad) {
1731 NDR_CHECK(ndr_push_zero(ndr, pad));
1732 }
1733
1734 return ndr_push_relative_ptr2(ndr, p);
1735 }
1736 if (ndr->relative_end_offset == -1) {
1737 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1738 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1739 ndr->relative_end_offset);
1740 }
1741 ret = ndr_token_store(ndr,
1742 &ndr->relative_begin_list,
1743 p,
1744 ndr->offset);
1745 if (ret == NDR_ERR_RANGE) {
1746 return ndr_push_error(ndr, ret,
1747 "More than %d NDR tokens stored for array_size",
1748 NDR_TOKEN_MAX_LIST_SIZE);
1749 }
1750 return ret;
1751 }
1752
1753 /*
1754 push a relative object - stage2 end
1755 this is called during buffers processing
1756 */
ndr_push_relative_ptr2_end(struct ndr_push * ndr,const void * p)1757 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1758 {
1759 uint32_t begin_offset = 0xFFFFFFFF;
1760 ssize_t len;
1761 uint32_t correct_offset = 0;
1762 uint32_t align = 1;
1763 uint32_t pad = 0;
1764
1765 if (p == NULL) {
1766 return NDR_ERR_SUCCESS;
1767 }
1768
1769 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1770 return NDR_ERR_SUCCESS;
1771 }
1772
1773 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1774 /* better say more than calculation a too small buffer */
1775 NDR_PUSH_ALIGN(ndr, 8);
1776 return NDR_ERR_SUCCESS;
1777 }
1778
1779 if (ndr->relative_end_offset < ndr->offset) {
1780 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1781 "ndr_push_relative_ptr2_end:"
1782 "relative_end_offset %u < offset %u",
1783 ndr->relative_end_offset, ndr->offset);
1784 }
1785
1786 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1787
1788 /* we have marshalled a buffer, see how long it was */
1789 len = ndr->offset - begin_offset;
1790
1791 if (len < 0) {
1792 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1793 "ndr_push_relative_ptr2_end:"
1794 "offset %u - begin_offset %u < 0",
1795 ndr->offset, begin_offset);
1796 }
1797
1798 if (ndr->relative_end_offset < len) {
1799 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1800 "ndr_push_relative_ptr2_end:"
1801 "relative_end_offset %u < len %lld",
1802 ndr->offset, (long long)len);
1803 }
1804
1805 /* the reversed offset is at the end of the main buffer */
1806 correct_offset = ndr->relative_end_offset - len;
1807
1808 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1809 align = 1;
1810 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1811 align = 2;
1812 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1813 align = 4;
1814 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1815 align = 8;
1816 }
1817
1818 pad = ndr_align_size(correct_offset, align);
1819 if (pad) {
1820 correct_offset += pad;
1821 correct_offset -= align;
1822 }
1823
1824 if (correct_offset < begin_offset) {
1825 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1826 "ndr_push_relative_ptr2_end: "
1827 "correct_offset %u < begin_offset %u",
1828 correct_offset, begin_offset);
1829 }
1830
1831 if (len > 0) {
1832 uint32_t clear_size = correct_offset - begin_offset;
1833
1834 clear_size = MIN(clear_size, len);
1835
1836 /* now move the marshalled buffer to the end of the main buffer */
1837 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1838
1839 if (clear_size) {
1840 /* and wipe out old buffer within the main buffer */
1841 memset(ndr->data + begin_offset, '\0', clear_size);
1842 }
1843 }
1844
1845 /* and set the end offset for the next buffer */
1846 ndr->relative_end_offset = correct_offset;
1847
1848 /* finally write the offset to the main buffer */
1849 ndr->offset = correct_offset;
1850 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1851
1852 /* restore to where we were in the main buffer */
1853 ndr->offset = begin_offset;
1854
1855 return NDR_ERR_SUCCESS;
1856 }
1857
1858 /*
1859 get the current base for relative pointers for the pull
1860 */
ndr_pull_get_relative_base_offset(struct ndr_pull * ndr)1861 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1862 {
1863 return ndr->relative_base_offset;
1864 }
1865
1866 /*
1867 restore the old base for relative pointers for the pull
1868 */
ndr_pull_restore_relative_base_offset(struct ndr_pull * ndr,uint32_t offset)1869 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1870 {
1871 ndr->relative_base_offset = offset;
1872 }
1873
1874 /*
1875 setup the current base for relative pointers for the pull
1876 called in the NDR_SCALAR stage
1877 */
ndr_pull_setup_relative_base_offset1(struct ndr_pull * ndr,const void * p,uint32_t offset)1878 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1879 {
1880 enum ndr_err_code ret;
1881 ndr->relative_base_offset = offset;
1882 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1883 if (ret == NDR_ERR_RANGE) {
1884 return ndr_pull_error(ndr, ret,
1885 "More than %d NDR tokens stored for relative_base_list",
1886 NDR_TOKEN_MAX_LIST_SIZE);
1887 }
1888 return ret;
1889 }
1890
1891 /*
1892 setup the current base for relative pointers for the pull
1893 called in the NDR_BUFFERS stage
1894 */
ndr_pull_setup_relative_base_offset2(struct ndr_pull * ndr,const void * p)1895 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1896 {
1897 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1898 }
1899
1900 /*
1901 pull a relative object - stage1
1902 called during SCALARS processing
1903 */
ndr_pull_relative_ptr1(struct ndr_pull * ndr,const void * p,uint32_t rel_offset)1904 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1905 {
1906 enum ndr_err_code ret;
1907 rel_offset += ndr->relative_base_offset;
1908 if (rel_offset > ndr->data_size) {
1909 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1910 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1911 rel_offset, ndr->data_size);
1912 }
1913 ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1914 if (ret == NDR_ERR_RANGE) {
1915 return ndr_pull_error(ndr, ret,
1916 "More than %d NDR tokens stored for relative_list",
1917 NDR_TOKEN_MAX_LIST_SIZE);
1918 }
1919 return ret;
1920 }
1921
1922 /*
1923 pull a relative object - stage2
1924 called during BUFFERS processing
1925 */
ndr_pull_relative_ptr2(struct ndr_pull * ndr,const void * p)1926 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1927 {
1928 uint32_t rel_offset;
1929 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1930 return ndr_pull_set_offset(ndr, rel_offset);
1931 }
1932
1933 const static struct {
1934 enum ndr_err_code err;
1935 const char *string;
1936 } ndr_err_code_strings[] = {
1937 { NDR_ERR_SUCCESS, "Success" },
1938 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1939 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1940 { NDR_ERR_OFFSET, "Offset Error" },
1941 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1942 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1943 { NDR_ERR_LENGTH, "Length Error" },
1944 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1945 { NDR_ERR_COMPRESSION, "Compression Error" },
1946 { NDR_ERR_STRING, "String Error" },
1947 { NDR_ERR_VALIDATE, "Validate Error" },
1948 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1949 { NDR_ERR_ALLOC, "Allocation Error" },
1950 { NDR_ERR_RANGE, "Range Error" },
1951 { NDR_ERR_TOKEN, "Token Error" },
1952 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1953 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1954 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1955 { NDR_ERR_NDR64, "NDR64 assertion error" },
1956 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1957 { 0, NULL }
1958 };
1959
ndr_map_error2string(enum ndr_err_code ndr_err)1960 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1961 {
1962 int i;
1963 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1964 if (ndr_err_code_strings[i].err == ndr_err)
1965 return ndr_err_code_strings[i].string;
1966 }
1967 return "Unknown error";
1968 }
1969