s3: modules: vfs_glusterfs: Fix leak of char **lines onto mem_ctx on return.
[Samba.git] / librpc / ndr / ndr.c
blobafe22a286022b69302293ed035e719b454bb739f
1 /*
2 Unix SMB/CIFS implementation.
4 libndr interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2005-2008
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.
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.
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/>.
24 this provides the core routines for NDR parsing functions
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27 of NDR encoding rules
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_RPC_PARSE
37 #define NDR_BASE_MARSHALL_SIZE 1024
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.
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.
48 #define NDR_TOKEN_MAX_LIST_SIZE 65535
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} },
56 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
57 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
61 const struct ndr_syntax_id ndr_syntax_id_null = {
62 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
67 work out the number of bytes needed to align on a n byte boundary
69 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
71 if ((offset & (n-1)) == 0) return 0;
72 return n - (offset & (n-1));
76 initialise a ndr parse structure from a data blob
78 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
80 struct ndr_pull *ndr;
82 ndr = talloc_zero(mem_ctx, struct ndr_pull);
83 if (!ndr) return NULL;
84 ndr->current_mem_ctx = mem_ctx;
86 ndr->data = blob->data;
87 ndr->data_size = blob->length;
89 return ndr;
92 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
94 enum ndr_err_code ndr_err;
95 DATA_BLOB b;
96 uint32_t append = 0;
97 bool ok;
99 if (blob->length == 0) {
100 return NDR_ERR_SUCCESS;
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;
108 NDR_CHECK(ndr_err);
110 if (ndr->data_size == 0) {
111 ndr->data = NULL;
112 append = UINT32_MAX;
115 if (append == UINT32_MAX) {
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
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__);
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__);
136 ndr->data = b.data;
137 ndr->data_size = b.length;
139 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
142 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
144 uint32_t skip = 0;
145 uint32_t append = 0;
147 if (ndr->relative_base_offset != 0) {
148 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
149 "%s", __location__);
151 if (ndr->relative_highest_offset != 0) {
152 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
153 "%s", __location__);
155 if (ndr->relative_list.count != 0) {
156 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
157 "%s", __location__);
159 if (ndr->relative_base_list.count != 0) {
160 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
161 "%s", __location__);
165 * we need to keep up to 7 bytes
166 * in order to get the aligment right.
168 skip = ndr->offset & 0xFFFFFFF8;
170 if (skip == 0) {
171 return NDR_ERR_SUCCESS;
174 ndr->offset -= skip;
175 ndr->data_size -= skip;
177 append = ndr_token_peek(&ndr->array_size_list, ndr);
178 if (append != UINT32_MAX) {
180 * here we assume, that ndr->data is not a
181 * talloc child of ndr.
183 ndr->data += skip;
184 return NDR_ERR_SUCCESS;
187 memmove(ndr->data, ndr->data + skip, ndr->data_size);
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__);
194 return NDR_ERR_SUCCESS;
198 advance by 'size' bytes
200 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
202 NDR_PULL_NEED_BYTES(ndr, size);
203 ndr->offset += size;
204 return NDR_ERR_SUCCESS;
208 set the parse offset to 'ofs'
210 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
212 ndr->offset = ofs;
213 if (ndr->offset > ndr->data_size) {
214 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
215 "ndr_pull_set_offset %u failed",
216 ofs);
218 return NDR_ERR_SUCCESS;
221 /* create a ndr_push structure, ready for some marshalling */
222 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
224 struct ndr_push *ndr;
226 ndr = talloc_zero(mem_ctx, struct ndr_push);
227 if (!ndr) {
228 return NULL;
231 ndr->flags = 0;
232 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
233 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
234 if (!ndr->data) {
235 talloc_free(ndr);
236 return NULL;
239 return ndr;
242 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
243 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
245 DATA_BLOB blob;
246 blob = data_blob_const(ndr->data, ndr->offset);
247 if (ndr->alloc_size > ndr->offset) {
248 ndr->data[ndr->offset] = 0;
250 return blob;
255 expand the available space in the buffer to ndr->offset + extra_size
257 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
259 uint32_t size = extra_size + ndr->offset;
261 if (size < ndr->offset) {
262 /* extra_size overflowed the offset */
263 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
264 size);
267 if (ndr->fixed_buf_size) {
268 if (ndr->alloc_size >= size) {
269 return NDR_ERR_SUCCESS;
271 return ndr_push_error(ndr,
272 NDR_ERR_BUFSIZE,
273 "Overflow of fixed buffer in "
274 "push_expand to %u",
275 size);
278 if (ndr->alloc_size > size) {
279 return NDR_ERR_SUCCESS;
282 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
283 if (size+1 > ndr->alloc_size) {
284 ndr->alloc_size = size+1;
286 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
287 if (!ndr->data) {
288 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
289 ndr->alloc_size);
292 return NDR_ERR_SUCCESS;
295 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
297 va_list ap;
298 char *s = NULL;
299 uint32_t i;
300 int ret;
301 int dbgc_class;
303 va_start(ap, format);
304 ret = vasprintf(&s, format, ap);
305 va_end(ap);
307 if (ret == -1) {
308 return;
311 dbgc_class = *(int *)ndr->private_data;
313 if (ndr->no_newline) {
314 DEBUGADDC(dbgc_class, 1,("%s", s));
315 free(s);
316 return;
319 for (i=0;i<ndr->depth;i++) {
320 DEBUGADDC(dbgc_class, 1,(" "));
323 DEBUGADDC(dbgc_class, 1,("%s\n", s));
324 free(s);
327 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
329 va_list ap;
330 char *s = NULL;
331 uint32_t i;
332 int ret;
334 va_start(ap, format);
335 ret = vasprintf(&s, format, ap);
336 va_end(ap);
338 if (ret == -1) {
339 return;
342 if (ndr->no_newline) {
343 DEBUGADD(1,("%s", s));
344 free(s);
345 return;
348 for (i=0;i<ndr->depth;i++) {
349 DEBUGADD(1,(" "));
352 DEBUGADD(1,("%s\n", s));
353 free(s);
356 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
358 va_list ap;
359 uint32_t i;
361 if (!ndr->no_newline) {
362 for (i=0;i<ndr->depth;i++) {
363 printf(" ");
367 va_start(ap, format);
368 vprintf(format, ap);
369 va_end(ap);
370 if (!ndr->no_newline) {
371 printf("\n");
375 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
377 va_list ap;
378 uint32_t i;
380 if (!ndr->no_newline) {
381 for (i=0;i<ndr->depth;i++) {
382 ndr->private_data = talloc_asprintf_append_buffer(
383 (char *)ndr->private_data, " ");
387 va_start(ap, format);
388 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
389 format, ap);
390 va_end(ap);
391 if (!ndr->no_newline) {
392 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
393 "\n");
398 a useful helper function for printing idl structures via DEBUGC()
400 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
402 struct ndr_print *ndr;
404 DEBUGC(dbgc_class, 1,(" "));
406 ndr = talloc_zero(NULL, struct ndr_print);
407 if (!ndr) return;
408 ndr->private_data = &dbgc_class;
409 ndr->print = ndr_print_debugc_helper;
410 ndr->depth = 1;
411 ndr->flags = 0;
412 #ifdef DEBUG_PASSWORD
413 if (CHECK_DEBUGLVL(100)) {
414 ndr->print_secrets = true;
416 #endif
418 fn(ndr, name, ptr);
419 talloc_free(ndr);
423 a useful helper function for printing idl structures via DEBUG()
425 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
427 struct ndr_print *ndr;
429 DEBUG(1,(" "));
431 ndr = talloc_zero(NULL, struct ndr_print);
432 if (!ndr) return;
433 ndr->print = ndr_print_debug_helper;
434 ndr->depth = 1;
435 ndr->flags = 0;
436 #ifdef DEBUG_PASSWORD
437 if (CHECK_DEBUGLVL(100)) {
438 ndr->print_secrets = true;
440 #endif
442 fn(ndr, name, ptr);
443 talloc_free(ndr);
447 a useful helper function for printing idl unions via DEBUG()
449 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
451 struct ndr_print *ndr;
453 DEBUG(1,(" "));
455 ndr = talloc_zero(NULL, struct ndr_print);
456 if (!ndr) return;
457 ndr->print = ndr_print_debug_helper;
458 ndr->depth = 1;
459 ndr->flags = 0;
460 #ifdef DEBUG_PASSWORD
461 if (CHECK_DEBUGLVL(100)) {
462 ndr->print_secrets = true;
464 #endif
466 ndr_print_set_switch_value(ndr, ptr, level);
467 fn(ndr, name, ptr);
468 talloc_free(ndr);
472 a useful helper function for printing idl function calls via DEBUG()
474 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
476 struct ndr_print *ndr;
478 DEBUG(1,(" "));
480 ndr = talloc_zero(NULL, struct ndr_print);
481 if (!ndr) return;
482 ndr->print = ndr_print_debug_helper;
483 ndr->depth = 1;
484 ndr->flags = 0;
485 #ifdef DEBUG_PASSWORD
486 if (CHECK_DEBUGLVL(100)) {
487 ndr->print_secrets = true;
489 #endif
491 fn(ndr, name, flags, ptr);
492 talloc_free(ndr);
496 a useful helper function for printing idl structures to a string
498 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
500 struct ndr_print *ndr;
501 char *ret = NULL;
503 ndr = talloc_zero(mem_ctx, struct ndr_print);
504 if (!ndr) return NULL;
505 ndr->private_data = talloc_strdup(ndr, "");
506 if (!ndr->private_data) {
507 goto failed;
509 ndr->print = ndr_print_string_helper;
510 ndr->depth = 1;
511 ndr->flags = 0;
513 fn(ndr, name, ptr);
514 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
515 failed:
516 talloc_free(ndr);
517 return ret;
521 a useful helper function for printing idl unions to a string
523 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
525 struct ndr_print *ndr;
526 char *ret = NULL;
528 ndr = talloc_zero(mem_ctx, struct ndr_print);
529 if (!ndr) return NULL;
530 ndr->private_data = talloc_strdup(ndr, "");
531 if (!ndr->private_data) {
532 goto failed;
534 ndr->print = ndr_print_string_helper;
535 ndr->depth = 1;
536 ndr->flags = 0;
537 ndr_print_set_switch_value(ndr, ptr, level);
538 fn(ndr, name, ptr);
539 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
540 failed:
541 talloc_free(ndr);
542 return ret;
546 a useful helper function for printing idl function calls to a string
548 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
549 ndr_print_function_t fn, const char *name,
550 int flags, void *ptr)
552 struct ndr_print *ndr;
553 char *ret = NULL;
555 ndr = talloc_zero(mem_ctx, struct ndr_print);
556 if (!ndr) return NULL;
557 ndr->private_data = talloc_strdup(ndr, "");
558 if (!ndr->private_data) {
559 goto failed;
561 ndr->print = ndr_print_string_helper;
562 ndr->depth = 1;
563 ndr->flags = 0;
564 fn(ndr, name, flags, ptr);
565 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
566 failed:
567 talloc_free(ndr);
568 return ret;
571 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
573 /* the big/little endian flags are inter-dependent */
574 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
575 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
576 (*pflags) &= ~LIBNDR_FLAG_NDR64;
578 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
579 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
580 (*pflags) &= ~LIBNDR_FLAG_NDR64;
582 if (new_flags & LIBNDR_ALIGN_FLAGS) {
583 /* Ensure we only have the passed-in
584 align flag set in the new_flags,
585 remove any old align flag. */
586 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
588 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
589 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
591 (*pflags) |= new_flags;
595 return and possibly log an NDR error
597 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
598 enum ndr_err_code ndr_err,
599 const char *function,
600 const char *location,
601 const char *format, ...)
603 char *s=NULL;
604 va_list ap;
605 int ret;
607 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
608 switch (ndr_err) {
609 case NDR_ERR_BUFSIZE:
610 return NDR_ERR_INCOMPLETE_BUFFER;
611 default:
612 break;
616 va_start(ap, format);
617 ret = vasprintf(&s, format, ap);
618 va_end(ap);
620 if (ret == -1) {
621 return NDR_ERR_ALLOC;
624 D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
625 function,
626 ndr_map_error2string(ndr_err),
628 location);
630 free(s);
632 return ndr_err;
636 return and possibly log an NDR error
638 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
639 enum ndr_err_code ndr_err,
640 const char *function,
641 const char *location,
642 const char *format, ...)
644 char *s=NULL;
645 va_list ap;
646 int ret;
648 va_start(ap, format);
649 ret = vasprintf(&s, format, ap);
650 va_end(ap);
652 if (ret == -1) {
653 return NDR_ERR_ALLOC;
656 D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
657 function,
658 ndr_map_error2string(ndr_err),
660 location);
662 free(s);
664 return ndr_err;
668 handle subcontext buffers, which in midl land are user-marshalled, but
669 we use magic in pidl to make them easier to cope with
671 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
672 struct ndr_pull **_subndr,
673 size_t header_size,
674 ssize_t size_is)
676 struct ndr_pull *subndr;
677 uint32_t r_content_size;
678 bool force_le = false;
679 bool force_be = false;
681 switch (header_size) {
682 case 0: {
683 uint32_t content_size = ndr->data_size - ndr->offset;
684 if (size_is >= 0) {
685 content_size = size_is;
687 r_content_size = content_size;
688 break;
691 case 2: {
692 uint16_t content_size;
693 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
694 if (size_is >= 0 && size_is != content_size) {
695 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
696 (int)size_is, (int)size_is,
697 (int)content_size,
698 (int)content_size);
700 r_content_size = content_size;
701 break;
704 case 4: {
705 uint32_t content_size;
706 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
707 if (size_is >= 0 && size_is != content_size) {
708 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
709 (int)size_is, (int)size_is,
710 (int)content_size,
711 (int)content_size);
713 r_content_size = content_size;
714 break;
716 case 0xFFFFFC01: {
718 * Common Type Header for the Serialization Stream
719 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
721 uint8_t version;
722 uint8_t drep;
723 uint16_t hdrlen;
724 uint32_t filler;
725 uint32_t content_size;
726 uint32_t reserved;
728 /* version */
729 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
731 if (version != 1) {
732 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
733 "Bad subcontext (PULL) Common Type Header version %d != 1",
734 (int)version);
738 * 0x10 little endian
739 * 0x00 big endian
741 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
742 if (drep == 0x10) {
743 force_le = true;
744 } else if (drep == 0x00) {
745 force_be = true;
746 } else {
747 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
748 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
749 (unsigned int)drep);
752 /* length of the "Private Header for Constructed Type" */
753 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
754 if (hdrlen != 8) {
755 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
756 "Bad subcontext (PULL) Common Type Header length %d != 8",
757 (int)hdrlen);
760 /* filler should be ignored */
761 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
764 * Private Header for Constructed Type
766 /* length - will be updated latter */
767 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
768 if (size_is >= 0 && size_is != content_size) {
769 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
770 (int)size_is, (int)content_size);
772 /* the content size must be a multiple of 8 */
773 if ((content_size % 8) != 0) {
774 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
775 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
776 (int)size_is, (int)content_size);
778 r_content_size = content_size;
780 /* reserved */
781 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
782 break;
784 case 0xFFFFFFFF:
786 * a shallow copy like subcontext
787 * useful for DCERPC pipe chunks.
789 subndr = talloc_zero(ndr, struct ndr_pull);
790 NDR_ERR_HAVE_NO_MEMORY(subndr);
792 subndr->flags = ndr->flags;
793 subndr->current_mem_ctx = ndr->current_mem_ctx;
794 subndr->data = ndr->data;
795 subndr->offset = ndr->offset;
796 subndr->data_size = ndr->data_size;
798 *_subndr = subndr;
799 return NDR_ERR_SUCCESS;
801 default:
802 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
803 (int)header_size);
806 NDR_PULL_NEED_BYTES(ndr, r_content_size);
808 subndr = talloc_zero(ndr, struct ndr_pull);
809 NDR_ERR_HAVE_NO_MEMORY(subndr);
810 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
811 subndr->current_mem_ctx = ndr->current_mem_ctx;
813 subndr->data = ndr->data + ndr->offset;
814 subndr->offset = 0;
815 subndr->data_size = r_content_size;
817 if (force_le) {
818 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
819 } else if (force_be) {
820 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
823 *_subndr = subndr;
824 return NDR_ERR_SUCCESS;
827 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
828 struct ndr_pull *subndr,
829 size_t header_size,
830 ssize_t size_is)
832 uint32_t advance;
833 uint32_t highest_ofs;
835 if (header_size == 0xFFFFFFFF) {
836 advance = subndr->offset - ndr->offset;
837 } else if (size_is >= 0) {
838 advance = size_is;
839 } else if (header_size > 0) {
840 advance = subndr->data_size;
841 } else {
842 advance = subndr->offset;
845 if (subndr->offset > ndr->relative_highest_offset) {
846 highest_ofs = subndr->offset;
847 } else {
848 highest_ofs = subndr->relative_highest_offset;
850 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
852 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
854 highest_ofs = advance;
856 if (highest_ofs < advance) {
857 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
858 "not all bytes consumed ofs[%u] advance[%u]",
859 highest_ofs, advance);
862 NDR_CHECK(ndr_pull_advance(ndr, advance));
863 return NDR_ERR_SUCCESS;
866 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
867 struct ndr_push **_subndr,
868 size_t header_size,
869 ssize_t size_is)
871 struct ndr_push *subndr;
873 subndr = ndr_push_init_ctx(ndr);
874 NDR_ERR_HAVE_NO_MEMORY(subndr);
875 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
877 if (size_is > 0) {
878 NDR_CHECK(ndr_push_zero(subndr, size_is));
879 subndr->offset = 0;
880 subndr->relative_end_offset = size_is;
883 *_subndr = subndr;
884 return NDR_ERR_SUCCESS;
888 push a subcontext header
890 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
891 struct ndr_push *subndr,
892 size_t header_size,
893 ssize_t size_is)
895 ssize_t padding_len;
897 if (size_is >= 0) {
898 padding_len = size_is - subndr->offset;
899 if (padding_len < 0) {
900 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
901 (int)subndr->offset, (int)size_is);
903 subndr->offset = size_is;
906 switch (header_size) {
907 case 0:
908 break;
910 case 2:
911 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
912 break;
914 case 4:
915 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
916 break;
918 case 0xFFFFFC01:
920 * Common Type Header for the Serialization Stream
921 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
923 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
924 if (padding_len > 0) {
925 NDR_CHECK(ndr_push_zero(subndr, padding_len));
928 /* version */
929 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
932 * 0x10 little endian
933 * 0x00 big endian
935 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
937 /* length of the "Private Header for Constructed Type" */
938 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
940 /* filler */
941 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
944 * Private Header for Constructed Type
946 /* length - will be updated latter */
947 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
949 /* reserved */
950 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
951 break;
953 default:
954 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
955 (int)header_size);
958 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
959 return NDR_ERR_SUCCESS;
963 struct ndr_token {
964 const void *key;
965 uint32_t value;
969 store a token in the ndr context, for later retrieval
971 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
972 struct ndr_token_list *list,
973 const void *key,
974 uint32_t value)
976 if (list->tokens == NULL) {
977 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
978 if (list->tokens == NULL) {
979 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
981 } else {
982 struct ndr_token *new_tokens = NULL;
983 uint32_t alloc_count = talloc_array_length(list->tokens);
986 * Check every time we have not allocated too many
987 * tokens. This ensures developer sanity when
988 * debugging the boundary condition
990 if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
991 return NDR_ERR_RANGE;
993 if (list->count == alloc_count) {
994 unsigned new_alloc;
996 * Double the list, until we start in chunks
997 * of 1000
999 unsigned increment = MIN(list->count, 1000);
1000 new_alloc = alloc_count + increment;
1001 if (new_alloc < alloc_count) {
1002 return NDR_ERR_RANGE;
1004 new_tokens = talloc_realloc(mem_ctx, list->tokens,
1005 struct ndr_token, new_alloc);
1006 NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1007 list->tokens = new_tokens;
1010 list->tokens[list->count].key = key;
1011 list->tokens[list->count].value = value;
1012 list->count++;
1013 return NDR_ERR_SUCCESS;
1017 retrieve a token from a ndr context, using cmp_fn to match the tokens
1019 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
1020 const void *key, uint32_t *v,
1021 comparison_fn_t _cmp_fn,
1022 bool erase)
1024 struct ndr_token *tokens = list->tokens;
1025 unsigned i;
1026 if (_cmp_fn) {
1027 for (i = list->count - 1; i < list->count; i--) {
1028 if (_cmp_fn(tokens[i].key, key) == 0) {
1029 goto found;
1032 } else {
1033 for (i = list->count - 1; i < list->count; i--) {
1034 if (tokens[i].key == key) {
1035 goto found;
1039 return NDR_ERR_TOKEN;
1040 found:
1041 *v = tokens[i].value;
1042 if (erase) {
1043 if (i != list->count - 1) {
1044 tokens[i] = tokens[list->count - 1];
1046 list->count--;
1048 return NDR_ERR_SUCCESS;
1052 retrieve a token from a ndr context
1054 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1055 const void *key, uint32_t *v)
1057 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1061 peek at but don't removed a token from a ndr context
1063 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list *list, const void *key)
1065 unsigned i;
1066 struct ndr_token *tokens = list->tokens;
1068 for (i = list->count - 1; i < list->count; i--) {
1069 if (tokens[i].key == key) {
1070 return tokens[i].value;
1074 return 0;
1078 pull an array size field and add it to the array_size_list token list
1080 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1082 enum ndr_err_code ret;
1083 uint32_t size;
1084 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1085 ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1086 if (ret == NDR_ERR_RANGE) {
1087 return ndr_pull_error(ndr, ret,
1088 "More than %d NDR tokens stored for array_size",
1089 NDR_TOKEN_MAX_LIST_SIZE);
1091 return ret;
1095 get the stored array size field
1097 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
1099 return ndr_token_peek(&ndr->array_size_list, p);
1103 check the stored array size field
1105 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
1107 uint32_t stored;
1108 stored = ndr_token_peek(&ndr->array_size_list, p);
1109 if (stored != size) {
1110 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1111 "Bad array size - got %u expected %u\n",
1112 stored, size);
1114 return NDR_ERR_SUCCESS;
1118 pull an array length field and add it to the array_length_list token list
1120 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1122 enum ndr_err_code ret;
1123 uint32_t length, offset;
1124 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1125 if (offset != 0) {
1126 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1127 "non-zero array offset %u\n", offset);
1129 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1130 ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1131 if (ret == NDR_ERR_RANGE) {
1132 return ndr_pull_error(ndr, ret,
1133 "More than %d NDR tokens stored for array_length_list",
1134 NDR_TOKEN_MAX_LIST_SIZE);
1136 return ret;
1140 get the stored array length field
1142 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1144 return ndr_token_peek(&ndr->array_length_list, p);
1148 check the stored array length field
1150 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1152 uint32_t stored;
1153 stored = ndr_token_peek(&ndr->array_length_list, p);
1154 if (stored != length) {
1155 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1156 "Bad array length - got %u expected %u\n",
1157 stored, length);
1159 return NDR_ERR_SUCCESS;
1162 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1164 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1165 int64_t tmp = 0 - (int64_t)count;
1166 uint64_t ncount = tmp;
1168 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1171 return NDR_ERR_SUCCESS;
1174 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1176 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1177 int64_t tmp = 0 - (int64_t)count;
1178 uint64_t ncount1 = tmp;
1179 uint64_t ncount2;
1181 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1182 if (ncount1 == ncount2) {
1183 return NDR_ERR_SUCCESS;
1186 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1187 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1188 (unsigned long long)ncount2,
1189 (unsigned long long)ncount1,
1190 (unsigned long)count);
1193 return NDR_ERR_SUCCESS;
1197 store a switch value
1199 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1201 enum ndr_err_code ret =
1202 ndr_token_store(ndr, &ndr->switch_list, p, val);
1203 if (ret == NDR_ERR_RANGE) {
1204 return ndr_push_error(ndr, ret,
1205 "More than %d NDR tokens stored for switch_list",
1206 NDR_TOKEN_MAX_LIST_SIZE);
1208 return ret;
1211 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1214 enum ndr_err_code ret =
1215 ndr_token_store(ndr, &ndr->switch_list, p, val);
1216 if (ret == NDR_ERR_RANGE) {
1217 return ndr_pull_error(ndr, ret,
1218 "More than %d NDR tokens stored for switch_list",
1219 NDR_TOKEN_MAX_LIST_SIZE);
1221 return ret;
1224 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1226 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1229 /* retrieve a switch value (for push) and remove it from the list */
1230 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1231 const void *p,
1232 uint32_t *v)
1234 return ndr_token_retrieve(&ndr->switch_list, p, v);
1237 /* retrieve a switch value and remove it from the list */
1238 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1240 enum ndr_err_code status;
1241 uint32_t v;
1243 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1244 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1245 return 0;
1248 return v;
1251 /* retrieve a switch value and remove it from the list */
1252 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1253 const void *p,
1254 uint32_t *v)
1256 return ndr_token_retrieve(&ndr->switch_list, p, v);
1260 pull a struct from a blob using NDR
1262 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1263 ndr_pull_flags_fn_t fn)
1265 struct ndr_pull *ndr;
1266 ndr = ndr_pull_init_blob(blob, mem_ctx);
1267 NDR_ERR_HAVE_NO_MEMORY(ndr);
1268 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1269 talloc_free(ndr);
1270 return NDR_ERR_SUCCESS;
1274 pull a struct from a blob using NDR - failing if all bytes are not consumed
1276 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1277 void *p, ndr_pull_flags_fn_t fn)
1279 struct ndr_pull *ndr;
1280 uint32_t highest_ofs;
1281 ndr = ndr_pull_init_blob(blob, mem_ctx);
1282 NDR_ERR_HAVE_NO_MEMORY(ndr);
1283 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1284 if (ndr->offset > ndr->relative_highest_offset) {
1285 highest_ofs = ndr->offset;
1286 } else {
1287 highest_ofs = ndr->relative_highest_offset;
1289 if (highest_ofs < ndr->data_size) {
1290 enum ndr_err_code ret;
1291 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1292 "not all bytes consumed ofs[%u] size[%u]",
1293 highest_ofs, ndr->data_size);
1294 talloc_free(ndr);
1295 return ret;
1297 talloc_free(ndr);
1298 return NDR_ERR_SUCCESS;
1302 pull a struct from a blob using NDR - failing if all bytes are not consumed
1304 This only works for structures with NO allocated memory, like
1305 objectSID and GUID. This helps because we parse these a lot.
1307 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1308 void *p, ndr_pull_flags_fn_t fn)
1311 * We init this structure on the stack here, to avoid a
1312 * talloc() as otherwise this call to the fn() is assured not
1313 * to be doing any allocation, eg SIDs and GUIDs.
1315 * This allows us to keep the safety of the PIDL-generated
1316 * code without the talloc() overhead.
1318 struct ndr_pull ndr = {
1319 .data = blob->data,
1320 .data_size = blob->length,
1321 .current_mem_ctx = (void *)-1
1323 uint32_t highest_ofs;
1324 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1325 highest_ofs = MAX(ndr.offset, ndr.relative_highest_offset);
1326 if (highest_ofs < ndr.data_size) {
1327 enum ndr_err_code ret;
1328 ret = ndr_pull_error(
1329 &ndr,
1330 NDR_ERR_UNREAD_BYTES,
1331 "not all bytes consumed ofs[%"PRIu32"] "
1332 "size[%"PRIu32"]",
1333 highest_ofs,
1334 ndr.data_size);
1335 return ret;
1337 return NDR_ERR_SUCCESS;
1341 pull a union from a blob using NDR, given the union discriminator
1343 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1344 void *p,
1345 uint32_t level, ndr_pull_flags_fn_t fn)
1347 struct ndr_pull *ndr;
1348 ndr = ndr_pull_init_blob(blob, mem_ctx);
1349 NDR_ERR_HAVE_NO_MEMORY(ndr);
1350 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1351 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1352 talloc_free(ndr);
1353 return NDR_ERR_SUCCESS;
1357 pull a union from a blob using NDR, given the union discriminator,
1358 failing if all bytes are not consumed
1360 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1361 void *p,
1362 uint32_t level, ndr_pull_flags_fn_t fn)
1364 struct ndr_pull *ndr;
1365 uint32_t highest_ofs;
1366 ndr = ndr_pull_init_blob(blob, mem_ctx);
1367 NDR_ERR_HAVE_NO_MEMORY(ndr);
1368 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1369 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1370 if (ndr->offset > ndr->relative_highest_offset) {
1371 highest_ofs = ndr->offset;
1372 } else {
1373 highest_ofs = ndr->relative_highest_offset;
1375 if (highest_ofs < ndr->data_size) {
1376 enum ndr_err_code ret;
1377 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1378 "not all bytes consumed ofs[%u] size[%u]",
1379 highest_ofs, ndr->data_size);
1380 talloc_free(ndr);
1381 return ret;
1383 talloc_free(ndr);
1384 return NDR_ERR_SUCCESS;
1388 push a struct to a blob using NDR
1390 _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)
1392 struct ndr_push *ndr;
1393 ndr = ndr_push_init_ctx(mem_ctx);
1394 NDR_ERR_HAVE_NO_MEMORY(ndr);
1396 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1398 *blob = ndr_push_blob(ndr);
1399 talloc_steal(mem_ctx, blob->data);
1400 talloc_free(ndr);
1402 return NDR_ERR_SUCCESS;
1406 push a struct into a provided blob using NDR.
1408 We error because we want to have the performance issue (extra
1409 talloc() calls) show up as an error, not just slower code. This is
1410 used for things like GUIDs, which we expect to be a fixed size, and
1411 SIDs that we can pre-calculate the size for.
1413 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1414 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1416 struct ndr_push ndr = {
1417 .data = blob->data,
1418 .alloc_size = blob->length,
1419 .fixed_buf_size = true
1422 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1424 if (ndr.offset != blob->length) {
1425 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1426 "buffer was either to large or small "
1427 "ofs[%u] size[%zu]",
1428 ndr.offset, blob->length);
1431 return NDR_ERR_SUCCESS;
1435 push a union to a blob using NDR
1437 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1438 uint32_t level, ndr_push_flags_fn_t fn)
1440 struct ndr_push *ndr;
1441 ndr = ndr_push_init_ctx(mem_ctx);
1442 NDR_ERR_HAVE_NO_MEMORY(ndr);
1444 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1445 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1447 *blob = ndr_push_blob(ndr);
1448 talloc_steal(mem_ctx, blob->data);
1449 talloc_free(ndr);
1451 return NDR_ERR_SUCCESS;
1455 generic ndr_size_*() handler for structures
1457 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1459 struct ndr_push *ndr;
1460 enum ndr_err_code status;
1461 size_t ret;
1463 /* avoid recursion */
1464 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1466 /* Avoid following a NULL pointer */
1467 if (p == NULL) {
1468 return 0;
1471 ndr = ndr_push_init_ctx(NULL);
1472 if (!ndr) return 0;
1473 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1474 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1475 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1476 talloc_free(ndr);
1477 return 0;
1479 ret = ndr->offset;
1480 talloc_free(ndr);
1481 return ret;
1485 generic ndr_size_*() handler for unions
1487 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1489 struct ndr_push *ndr;
1490 enum ndr_err_code status;
1491 size_t ret;
1493 /* avoid recursion */
1494 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1496 /* Avoid following a NULL pointer */
1497 if (p == NULL) {
1498 return 0;
1501 ndr = ndr_push_init_ctx(NULL);
1502 if (!ndr) return 0;
1503 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1505 status = ndr_push_set_switch_value(ndr, p, level);
1506 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1507 talloc_free(ndr);
1508 return 0;
1510 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1511 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1512 talloc_free(ndr);
1513 return 0;
1515 ret = ndr->offset;
1516 talloc_free(ndr);
1517 return ret;
1521 get the current base for relative pointers for the push
1523 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1525 return ndr->relative_base_offset;
1529 restore the old base for relative pointers for the push
1531 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1533 ndr->relative_base_offset = offset;
1537 setup the current base for relative pointers for the push
1538 called in the NDR_SCALAR stage
1540 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1542 enum ndr_err_code ret;
1543 ndr->relative_base_offset = offset;
1544 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1545 if (ret == NDR_ERR_RANGE) {
1546 return ndr_push_error(ndr, ret,
1547 "More than %d NDR tokens stored for relative_base_list",
1548 NDR_TOKEN_MAX_LIST_SIZE);
1550 return ret;
1554 setup the current base for relative pointers for the push
1555 called in the NDR_BUFFERS stage
1557 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1559 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1563 push a relative object - stage1
1564 this is called during SCALARS processing
1566 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1568 enum ndr_err_code ret;
1569 if (p == NULL) {
1570 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1571 return NDR_ERR_SUCCESS;
1573 NDR_CHECK(ndr_push_align(ndr, 4));
1574 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1575 if (ret == NDR_ERR_RANGE) {
1576 return ndr_push_error(ndr, ret,
1577 "More than %d NDR tokens stored for relative_list",
1578 NDR_TOKEN_MAX_LIST_SIZE);
1580 NDR_CHECK(ret);
1581 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1585 push a short relative object - stage1
1586 this is called during SCALARS processing
1588 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1590 enum ndr_err_code ret;
1591 if (p == NULL) {
1592 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1593 return NDR_ERR_SUCCESS;
1595 NDR_CHECK(ndr_push_align(ndr, 2));
1596 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1597 if (ret == NDR_ERR_RANGE) {
1598 return ndr_push_error(ndr, ret,
1599 "More than %d NDR tokens stored for relative_list",
1600 NDR_TOKEN_MAX_LIST_SIZE);
1602 NDR_CHECK(ret);
1603 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1606 push a relative object - stage2
1607 this is called during buffers processing
1609 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1611 uint32_t save_offset;
1612 uint32_t ptr_offset = 0xFFFFFFFF;
1613 if (p == NULL) {
1614 return NDR_ERR_SUCCESS;
1616 save_offset = ndr->offset;
1617 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1618 if (ptr_offset > ndr->offset) {
1619 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1620 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1621 ptr_offset, ndr->offset);
1623 ndr->offset = ptr_offset;
1624 if (save_offset < ndr->relative_base_offset) {
1625 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1626 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1627 save_offset, ndr->relative_base_offset);
1629 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1630 ndr->offset = save_offset;
1631 return NDR_ERR_SUCCESS;
1634 push a short relative object - stage2
1635 this is called during buffers processing
1637 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1639 uint32_t save_offset;
1640 uint32_t ptr_offset = 0xFFFF;
1641 uint32_t relative_offset;
1642 size_t pad;
1643 size_t align = 1;
1645 if (p == NULL) {
1646 return NDR_ERR_SUCCESS;
1649 if (ndr->offset < ndr->relative_base_offset) {
1650 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1651 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1652 ndr->offset, ndr->relative_base_offset);
1655 relative_offset = ndr->offset - ndr->relative_base_offset;
1657 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1658 align = 1;
1659 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1660 align = 2;
1661 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1662 align = 4;
1663 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1664 align = 8;
1667 pad = ndr_align_size(relative_offset, align);
1668 if (pad != 0) {
1669 NDR_CHECK(ndr_push_zero(ndr, pad));
1672 relative_offset = ndr->offset - ndr->relative_base_offset;
1673 if (relative_offset > UINT16_MAX) {
1674 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1675 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1676 relative_offset);
1679 save_offset = ndr->offset;
1680 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1681 if (ptr_offset > ndr->offset) {
1682 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1683 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1684 ptr_offset, ndr->offset);
1686 ndr->offset = ptr_offset;
1687 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1688 ndr->offset = save_offset;
1689 return NDR_ERR_SUCCESS;
1693 push a relative object - stage2 start
1694 this is called during buffers processing
1696 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1698 enum ndr_err_code ret;
1699 if (p == NULL) {
1700 return NDR_ERR_SUCCESS;
1702 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1703 uint32_t relative_offset;
1704 size_t pad;
1705 size_t align = 1;
1707 if (ndr->offset < ndr->relative_base_offset) {
1708 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1709 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1710 ndr->offset, ndr->relative_base_offset);
1713 relative_offset = ndr->offset - ndr->relative_base_offset;
1715 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1716 align = 1;
1717 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1718 align = 2;
1719 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1720 align = 4;
1721 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1722 align = 8;
1725 pad = ndr_align_size(relative_offset, align);
1726 if (pad) {
1727 NDR_CHECK(ndr_push_zero(ndr, pad));
1730 return ndr_push_relative_ptr2(ndr, p);
1732 if (ndr->relative_end_offset == -1) {
1733 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1734 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1735 ndr->relative_end_offset);
1737 ret = ndr_token_store(ndr,
1738 &ndr->relative_begin_list,
1740 ndr->offset);
1741 if (ret == NDR_ERR_RANGE) {
1742 return ndr_push_error(ndr, ret,
1743 "More than %d NDR tokens stored for array_size",
1744 NDR_TOKEN_MAX_LIST_SIZE);
1746 return ret;
1750 push a relative object - stage2 end
1751 this is called during buffers processing
1753 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1755 uint32_t begin_offset = 0xFFFFFFFF;
1756 ssize_t len;
1757 uint32_t correct_offset = 0;
1758 uint32_t align = 1;
1759 uint32_t pad = 0;
1761 if (p == NULL) {
1762 return NDR_ERR_SUCCESS;
1765 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1766 return NDR_ERR_SUCCESS;
1769 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1770 /* better say more than calculation a too small buffer */
1771 NDR_PUSH_ALIGN(ndr, 8);
1772 return NDR_ERR_SUCCESS;
1775 if (ndr->relative_end_offset < ndr->offset) {
1776 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1777 "ndr_push_relative_ptr2_end:"
1778 "relative_end_offset %u < offset %u",
1779 ndr->relative_end_offset, ndr->offset);
1782 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1784 /* we have marshalled a buffer, see how long it was */
1785 len = ndr->offset - begin_offset;
1787 if (len < 0) {
1788 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1789 "ndr_push_relative_ptr2_end:"
1790 "offset %u - begin_offset %u < 0",
1791 ndr->offset, begin_offset);
1794 if (ndr->relative_end_offset < len) {
1795 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1796 "ndr_push_relative_ptr2_end:"
1797 "relative_end_offset %u < len %lld",
1798 ndr->offset, (long long)len);
1801 /* the reversed offset is at the end of the main buffer */
1802 correct_offset = ndr->relative_end_offset - len;
1804 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1805 align = 1;
1806 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1807 align = 2;
1808 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1809 align = 4;
1810 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1811 align = 8;
1814 pad = ndr_align_size(correct_offset, align);
1815 if (pad) {
1816 correct_offset += pad;
1817 correct_offset -= align;
1820 if (correct_offset < begin_offset) {
1821 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1822 "ndr_push_relative_ptr2_end: "
1823 "correct_offset %u < begin_offset %u",
1824 correct_offset, begin_offset);
1827 if (len > 0) {
1828 uint32_t clear_size = correct_offset - begin_offset;
1830 clear_size = MIN(clear_size, len);
1832 /* now move the marshalled buffer to the end of the main buffer */
1833 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1835 if (clear_size) {
1836 /* and wipe out old buffer within the main buffer */
1837 memset(ndr->data + begin_offset, '\0', clear_size);
1841 /* and set the end offset for the next buffer */
1842 ndr->relative_end_offset = correct_offset;
1844 /* finally write the offset to the main buffer */
1845 ndr->offset = correct_offset;
1846 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1848 /* restore to where we were in the main buffer */
1849 ndr->offset = begin_offset;
1851 return NDR_ERR_SUCCESS;
1855 get the current base for relative pointers for the pull
1857 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1859 return ndr->relative_base_offset;
1863 restore the old base for relative pointers for the pull
1865 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1867 ndr->relative_base_offset = offset;
1871 setup the current base for relative pointers for the pull
1872 called in the NDR_SCALAR stage
1874 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1876 enum ndr_err_code ret;
1877 ndr->relative_base_offset = offset;
1878 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1879 if (ret == NDR_ERR_RANGE) {
1880 return ndr_pull_error(ndr, ret,
1881 "More than %d NDR tokens stored for relative_base_list",
1882 NDR_TOKEN_MAX_LIST_SIZE);
1884 return ret;
1888 setup the current base for relative pointers for the pull
1889 called in the NDR_BUFFERS stage
1891 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1893 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1897 pull a relative object - stage1
1898 called during SCALARS processing
1900 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1902 enum ndr_err_code ret;
1903 rel_offset += ndr->relative_base_offset;
1904 if (rel_offset > ndr->data_size) {
1905 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1906 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1907 rel_offset, ndr->data_size);
1909 ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1910 if (ret == NDR_ERR_RANGE) {
1911 return ndr_pull_error(ndr, ret,
1912 "More than %d NDR tokens stored for relative_list",
1913 NDR_TOKEN_MAX_LIST_SIZE);
1915 return ret;
1919 pull a relative object - stage2
1920 called during BUFFERS processing
1922 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1924 uint32_t rel_offset;
1925 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1926 return ndr_pull_set_offset(ndr, rel_offset);
1929 static const struct {
1930 enum ndr_err_code err;
1931 const char *string;
1932 } ndr_err_code_strings[] = {
1933 { NDR_ERR_SUCCESS, "Success" },
1934 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1935 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1936 { NDR_ERR_OFFSET, "Offset Error" },
1937 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1938 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1939 { NDR_ERR_LENGTH, "Length Error" },
1940 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1941 { NDR_ERR_COMPRESSION, "Compression Error" },
1942 { NDR_ERR_STRING, "String Error" },
1943 { NDR_ERR_VALIDATE, "Validate Error" },
1944 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1945 { NDR_ERR_ALLOC, "Allocation Error" },
1946 { NDR_ERR_RANGE, "Range Error" },
1947 { NDR_ERR_TOKEN, "Token Error" },
1948 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1949 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1950 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1951 { NDR_ERR_NDR64, "NDR64 assertion error" },
1952 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1953 { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" },
1954 { NDR_ERR_UNDERFLOW, "Underflow" },
1955 { 0, NULL }
1958 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1960 int i;
1961 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1962 if (ndr_err_code_strings[i].err == ndr_err)
1963 return ndr_err_code_strings[i].string;
1965 return "Unknown error";