2 Unix SMB/CIFS implementation.
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
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
34 #define NDR_BASE_MARSHALL_SIZE 1024
36 /* this guid indicates NDR encoding in a protocol tower */
37 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
38 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
42 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
43 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
47 const struct ndr_syntax_id ndr_syntax_id_null = {
48 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
53 work out the number of bytes needed to align on a n byte boundary
55 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
57 if ((offset & (n-1)) == 0) return 0;
58 return n - (offset & (n-1));
62 initialise a ndr parse structure from a data blob
64 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
68 ndr = talloc_zero(mem_ctx, struct ndr_pull);
69 if (!ndr) return NULL;
70 ndr->current_mem_ctx = mem_ctx;
72 ndr->data = blob->data;
73 ndr->data_size = blob->length;
79 advance by 'size' bytes
81 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
84 if (ndr->offset > ndr->data_size) {
85 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
86 "ndr_pull_advance by %u failed",
89 return NDR_ERR_SUCCESS;
93 set the parse offset to 'ofs'
95 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
98 if (ndr->offset > ndr->data_size) {
99 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
100 "ndr_pull_set_offset %u failed",
103 return NDR_ERR_SUCCESS;
106 /* create a ndr_push structure, ready for some marshalling */
107 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
109 struct ndr_push *ndr;
111 ndr = talloc_zero(mem_ctx, struct ndr_push);
117 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
118 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
126 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
127 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
130 blob = data_blob_const(ndr->data, ndr->offset);
131 if (ndr->alloc_size > ndr->offset) {
132 ndr->data[ndr->offset] = 0;
139 expand the available space in the buffer to ndr->offset + extra_size
141 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
143 uint32_t size = extra_size + ndr->offset;
145 if (size < ndr->offset) {
146 /* extra_size overflowed the offset */
147 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
151 if (ndr->alloc_size > size) {
152 return NDR_ERR_SUCCESS;
155 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
156 if (size+1 > ndr->alloc_size) {
157 ndr->alloc_size = size+1;
159 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
161 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
165 return NDR_ERR_SUCCESS;
168 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
176 va_start(ap, format);
177 ret = vasprintf(&s, format, ap);
184 dbgc_class = *(int *)ndr->private_data;
186 if (ndr->no_newline) {
187 DEBUGADDC(dbgc_class, 1,("%s", s));
192 for (i=0;i<ndr->depth;i++) {
193 DEBUGADDC(dbgc_class, 1,(" "));
196 DEBUGADDC(dbgc_class, 1,("%s\n", s));
200 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
207 va_start(ap, format);
208 ret = vasprintf(&s, format, ap);
215 if (ndr->no_newline) {
216 DEBUGADD(1,("%s", s));
221 for (i=0;i<ndr->depth;i++) {
225 DEBUGADD(1,("%s\n", s));
229 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
234 if (!ndr->no_newline) {
235 for (i=0;i<ndr->depth;i++) {
240 va_start(ap, format);
243 if (!ndr->no_newline) {
248 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
253 if (!ndr->no_newline) {
254 for (i=0;i<ndr->depth;i++) {
255 ndr->private_data = talloc_asprintf_append_buffer(
256 (char *)ndr->private_data, " ");
260 va_start(ap, format);
261 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
264 if (!ndr->no_newline) {
265 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
271 a useful helper function for printing idl structures via DEBUGC()
273 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
275 struct ndr_print *ndr;
277 DEBUGC(dbgc_class, 1,(" "));
279 ndr = talloc_zero(NULL, struct ndr_print);
281 ndr->private_data = &dbgc_class;
282 ndr->print = ndr_print_debugc_helper;
290 a useful helper function for printing idl structures via DEBUG()
292 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
294 struct ndr_print *ndr;
298 ndr = talloc_zero(NULL, struct ndr_print);
300 ndr->print = ndr_print_debug_helper;
308 a useful helper function for printing idl unions via DEBUG()
310 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
312 struct ndr_print *ndr;
316 ndr = talloc_zero(NULL, struct ndr_print);
318 ndr->print = ndr_print_debug_helper;
321 ndr_print_set_switch_value(ndr, ptr, level);
327 a useful helper function for printing idl function calls via DEBUG()
329 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
331 struct ndr_print *ndr;
335 ndr = talloc_zero(NULL, struct ndr_print);
337 ndr->print = ndr_print_debug_helper;
341 fn(ndr, name, flags, ptr);
346 a useful helper function for printing idl structures to a string
348 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
350 struct ndr_print *ndr;
353 ndr = talloc_zero(mem_ctx, struct ndr_print);
354 if (!ndr) return NULL;
355 ndr->private_data = talloc_strdup(ndr, "");
356 if (!ndr->private_data) {
359 ndr->print = ndr_print_string_helper;
364 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
371 a useful helper function for printing idl unions to a string
373 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
375 struct ndr_print *ndr;
378 ndr = talloc_zero(mem_ctx, struct ndr_print);
379 if (!ndr) return NULL;
380 ndr->private_data = talloc_strdup(ndr, "");
381 if (!ndr->private_data) {
384 ndr->print = ndr_print_string_helper;
387 ndr_print_set_switch_value(ndr, ptr, level);
389 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
396 a useful helper function for printing idl function calls to a string
398 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
399 ndr_print_function_t fn, const char *name,
400 int flags, void *ptr)
402 struct ndr_print *ndr;
405 ndr = talloc_zero(mem_ctx, struct ndr_print);
406 if (!ndr) return NULL;
407 ndr->private_data = talloc_strdup(ndr, "");
408 if (!ndr->private_data) {
411 ndr->print = ndr_print_string_helper;
414 fn(ndr, name, flags, ptr);
415 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
421 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
423 /* the big/little endian flags are inter-dependent */
424 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
425 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
426 (*pflags) &= ~LIBNDR_FLAG_NDR64;
428 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
429 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
430 (*pflags) &= ~LIBNDR_FLAG_NDR64;
432 if (new_flags & LIBNDR_ALIGN_FLAGS) {
433 /* Ensure we only have the passed-in
434 align flag set in the new_flags,
435 remove any old align flag. */
436 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
438 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
439 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
441 (*pflags) |= new_flags;
445 return and possibly log an NDR error
447 _PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
448 enum ndr_err_code ndr_err,
449 const char *format, ...)
455 va_start(ap, format);
456 ret = vasprintf(&s, format, ap);
460 return NDR_ERR_ALLOC;
463 DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
471 return and possibly log an NDR error
473 _PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
474 enum ndr_err_code ndr_err,
475 const char *format, ...)
481 va_start(ap, format);
482 ret = vasprintf(&s, format, ap);
486 return NDR_ERR_ALLOC;
489 DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
497 handle subcontext buffers, which in midl land are user-marshalled, but
498 we use magic in pidl to make them easier to cope with
500 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
501 struct ndr_pull **_subndr,
505 struct ndr_pull *subndr;
506 uint32_t r_content_size;
507 bool force_le = false;
508 bool force_be = false;
510 switch (header_size) {
512 uint32_t content_size = ndr->data_size - ndr->offset;
514 content_size = size_is;
516 r_content_size = content_size;
521 uint16_t content_size;
522 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
523 if (size_is >= 0 && size_is != content_size) {
524 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
525 (int)size_is, (int)content_size);
527 r_content_size = content_size;
532 uint32_t content_size;
533 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
534 if (size_is >= 0 && size_is != content_size) {
535 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
536 (int)size_is, (int)content_size);
538 r_content_size = content_size;
543 * Common Type Header for the Serialization Stream
544 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
550 uint32_t content_size;
554 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
557 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
558 "Bad subcontext (PULL) Common Type Header version %d != 1",
566 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
569 } else if (drep == 0x00) {
572 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
573 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
577 /* length of the "Private Header for Constructed Type" */
578 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
580 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
581 "Bad subcontext (PULL) Common Type Header length %d != 8",
585 /* filler should be ignored */
586 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
589 * Private Header for Constructed Type
591 /* length - will be updated latter */
592 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
593 if (size_is >= 0 && size_is != content_size) {
594 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
595 (int)size_is, (int)content_size);
597 /* the content size must be a multiple of 8 */
598 if ((content_size % 8) != 0) {
599 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
600 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
601 (int)size_is, (int)content_size);
603 r_content_size = content_size;
606 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
610 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
614 NDR_PULL_NEED_BYTES(ndr, r_content_size);
616 subndr = talloc_zero(ndr, struct ndr_pull);
617 NDR_ERR_HAVE_NO_MEMORY(subndr);
618 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
619 subndr->current_mem_ctx = ndr->current_mem_ctx;
621 subndr->data = ndr->data + ndr->offset;
623 subndr->data_size = r_content_size;
626 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
627 } else if (force_be) {
628 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
632 return NDR_ERR_SUCCESS;
635 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
636 struct ndr_pull *subndr,
641 uint32_t highest_ofs;
645 } else if (header_size > 0) {
646 advance = subndr->data_size;
648 advance = subndr->offset;
651 if (subndr->offset > ndr->relative_highest_offset) {
652 highest_ofs = subndr->offset;
654 highest_ofs = subndr->relative_highest_offset;
656 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
658 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
660 highest_ofs = advance;
662 if (highest_ofs < advance) {
663 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
664 "not all bytes consumed ofs[%u] advance[%u]",
665 highest_ofs, advance);
668 NDR_CHECK(ndr_pull_advance(ndr, advance));
669 return NDR_ERR_SUCCESS;
672 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
673 struct ndr_push **_subndr,
677 struct ndr_push *subndr;
679 subndr = ndr_push_init_ctx(ndr);
680 NDR_ERR_HAVE_NO_MEMORY(subndr);
681 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
684 NDR_CHECK(ndr_push_zero(subndr, size_is));
686 subndr->relative_end_offset = size_is;
690 return NDR_ERR_SUCCESS;
694 push a subcontext header
696 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
697 struct ndr_push *subndr,
704 padding_len = size_is - subndr->offset;
705 if (padding_len < 0) {
706 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
707 (int)subndr->offset, (int)size_is);
709 subndr->offset = size_is;
712 switch (header_size) {
717 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
721 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
726 * Common Type Header for the Serialization Stream
727 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
729 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
730 if (padding_len > 0) {
731 NDR_CHECK(ndr_push_zero(subndr, padding_len));
735 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
741 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
743 /* length of the "Private Header for Constructed Type" */
744 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
747 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
750 * Private Header for Constructed Type
752 /* length - will be updated latter */
753 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
756 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
760 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
764 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
765 return NDR_ERR_SUCCESS;
769 store a token in the ndr context, for later retrieval
771 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
772 struct ndr_token_list **list,
776 struct ndr_token_list *tok;
777 tok = talloc(mem_ctx, struct ndr_token_list);
778 NDR_ERR_HAVE_NO_MEMORY(tok);
781 DLIST_ADD((*list), tok);
782 return NDR_ERR_SUCCESS;
786 retrieve a token from a ndr context, using cmp_fn to match the tokens
788 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
789 comparison_fn_t _cmp_fn, bool _remove_tok)
791 struct ndr_token_list *tok;
792 for (tok=*list;tok;tok=tok->next) {
793 if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
794 else if (!_cmp_fn && tok->key == key) goto found;
796 return NDR_ERR_TOKEN;
800 DLIST_REMOVE((*list), tok);
803 return NDR_ERR_SUCCESS;
807 retrieve a token from a ndr context
809 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
811 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
815 peek at but don't removed a token from a ndr context
817 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
819 enum ndr_err_code status;
822 status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
823 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
831 pull an array size field and add it to the array_size_list token list
833 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
836 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
837 return ndr_token_store(ndr, &ndr->array_size_list, p, size);
841 get the stored array size field
843 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
845 return ndr_token_peek(&ndr->array_size_list, p);
849 check the stored array size field
851 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
854 stored = ndr_token_peek(&ndr->array_size_list, p);
855 if (stored != size) {
856 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
857 "Bad array size - got %u expected %u\n",
860 return NDR_ERR_SUCCESS;
864 pull an array length field and add it to the array_length_list token list
866 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
868 uint32_t length, offset;
869 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
871 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
872 "non-zero array offset %u\n", offset);
874 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
875 return ndr_token_store(ndr, &ndr->array_length_list, p, length);
879 get the stored array length field
881 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
883 return ndr_token_peek(&ndr->array_length_list, p);
887 check the stored array length field
889 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
892 stored = ndr_token_peek(&ndr->array_length_list, p);
893 if (stored != length) {
894 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
895 "Bad array length - got %u expected %u\n",
898 return NDR_ERR_SUCCESS;
901 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
903 if (ndr->flags & LIBNDR_FLAG_NDR64) {
904 int64_t tmp = 0 - (int64_t)count;
905 uint64_t ncount = tmp;
907 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
910 return NDR_ERR_SUCCESS;
913 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
915 if (ndr->flags & LIBNDR_FLAG_NDR64) {
916 int64_t tmp = 0 - (int64_t)count;
917 uint64_t ncount1 = tmp;
920 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
921 if (ncount1 == ncount2) {
922 return NDR_ERR_SUCCESS;
925 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
926 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
927 (unsigned long long)ncount2,
928 (unsigned long long)ncount1,
929 (unsigned long)count);
932 return NDR_ERR_SUCCESS;
938 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
940 return ndr_token_store(ndr, &ndr->switch_list, p, val);
943 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
945 return ndr_token_store(ndr, &ndr->switch_list, p, val);
948 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
950 return ndr_token_store(ndr, &ndr->switch_list, p, val);
954 retrieve a switch value
956 _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
958 return ndr_token_peek(&ndr->switch_list, p);
961 _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
963 return ndr_token_peek(&ndr->switch_list, p);
966 _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
968 return ndr_token_peek(&ndr->switch_list, p);
972 pull a struct from a blob using NDR
974 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
975 ndr_pull_flags_fn_t fn)
977 struct ndr_pull *ndr;
978 ndr = ndr_pull_init_blob(blob, mem_ctx);
979 NDR_ERR_HAVE_NO_MEMORY(ndr);
980 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
982 return NDR_ERR_SUCCESS;
986 pull a struct from a blob using NDR - failing if all bytes are not consumed
988 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
989 void *p, ndr_pull_flags_fn_t fn)
991 struct ndr_pull *ndr;
992 uint32_t highest_ofs;
993 ndr = ndr_pull_init_blob(blob, mem_ctx);
994 NDR_ERR_HAVE_NO_MEMORY(ndr);
995 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
996 if (ndr->offset > ndr->relative_highest_offset) {
997 highest_ofs = ndr->offset;
999 highest_ofs = ndr->relative_highest_offset;
1001 if (highest_ofs < ndr->data_size) {
1002 enum ndr_err_code ret;
1003 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1004 "not all bytes consumed ofs[%u] size[%u]",
1005 highest_ofs, ndr->data_size);
1010 return NDR_ERR_SUCCESS;
1014 pull a union from a blob using NDR, given the union discriminator
1016 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1018 uint32_t level, ndr_pull_flags_fn_t fn)
1020 struct ndr_pull *ndr;
1021 ndr = ndr_pull_init_blob(blob, mem_ctx);
1022 NDR_ERR_HAVE_NO_MEMORY(ndr);
1023 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1024 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1026 return NDR_ERR_SUCCESS;
1030 pull a union from a blob using NDR, given the union discriminator,
1031 failing if all bytes are not consumed
1033 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1035 uint32_t level, ndr_pull_flags_fn_t fn)
1037 struct ndr_pull *ndr;
1038 uint32_t highest_ofs;
1039 ndr = ndr_pull_init_blob(blob, mem_ctx);
1040 NDR_ERR_HAVE_NO_MEMORY(ndr);
1041 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1042 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1043 if (ndr->offset > ndr->relative_highest_offset) {
1044 highest_ofs = ndr->offset;
1046 highest_ofs = ndr->relative_highest_offset;
1048 if (highest_ofs < ndr->data_size) {
1049 enum ndr_err_code ret;
1050 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1051 "not all bytes consumed ofs[%u] size[%u]",
1052 highest_ofs, ndr->data_size);
1057 return NDR_ERR_SUCCESS;
1061 push a struct to a blob using NDR
1063 _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)
1065 struct ndr_push *ndr;
1066 ndr = ndr_push_init_ctx(mem_ctx);
1067 NDR_ERR_HAVE_NO_MEMORY(ndr);
1069 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1071 *blob = ndr_push_blob(ndr);
1072 talloc_steal(mem_ctx, blob->data);
1075 return NDR_ERR_SUCCESS;
1079 push a union to a blob using NDR
1081 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1082 uint32_t level, ndr_push_flags_fn_t fn)
1084 struct ndr_push *ndr;
1085 ndr = ndr_push_init_ctx(mem_ctx);
1086 NDR_ERR_HAVE_NO_MEMORY(ndr);
1088 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1089 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1091 *blob = ndr_push_blob(ndr);
1092 talloc_steal(mem_ctx, blob->data);
1095 return NDR_ERR_SUCCESS;
1099 generic ndr_size_*() handler for structures
1101 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1103 struct ndr_push *ndr;
1104 enum ndr_err_code status;
1107 /* avoid recursion */
1108 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1110 ndr = ndr_push_init_ctx(NULL);
1112 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1113 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1114 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1124 generic ndr_size_*() handler for unions
1126 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1128 struct ndr_push *ndr;
1129 enum ndr_err_code status;
1132 /* avoid recursion */
1133 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1135 ndr = ndr_push_init_ctx(NULL);
1137 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1139 status = ndr_push_set_switch_value(ndr, p, level);
1140 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1144 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1145 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1155 get the current base for relative pointers for the push
1157 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1159 return ndr->relative_base_offset;
1163 restore the old base for relative pointers for the push
1165 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1167 ndr->relative_base_offset = offset;
1171 setup the current base for relative pointers for the push
1172 called in the NDR_SCALAR stage
1174 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1176 ndr->relative_base_offset = offset;
1177 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1181 setup the current base for relative pointers for the push
1182 called in the NDR_BUFFERS stage
1184 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1186 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1190 push a relative object - stage1
1191 this is called during SCALARS processing
1193 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1196 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1197 return NDR_ERR_SUCCESS;
1199 NDR_CHECK(ndr_push_align(ndr, 4));
1200 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1201 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1205 push a short relative object - stage1
1206 this is called during SCALARS processing
1208 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1211 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1212 return NDR_ERR_SUCCESS;
1214 NDR_CHECK(ndr_push_align(ndr, 2));
1215 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1216 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1219 push a relative object - stage2
1220 this is called during buffers processing
1222 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1224 uint32_t save_offset;
1225 uint32_t ptr_offset = 0xFFFFFFFF;
1227 return NDR_ERR_SUCCESS;
1229 save_offset = ndr->offset;
1230 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1231 if (ptr_offset > ndr->offset) {
1232 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1233 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1234 ptr_offset, ndr->offset);
1236 ndr->offset = ptr_offset;
1237 if (save_offset < ndr->relative_base_offset) {
1238 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1239 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1240 save_offset, ndr->relative_base_offset);
1242 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1243 ndr->offset = save_offset;
1244 return NDR_ERR_SUCCESS;
1247 push a short relative object - stage2
1248 this is called during buffers processing
1250 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1252 uint32_t save_offset;
1253 uint32_t ptr_offset = 0xFFFF;
1255 return NDR_ERR_SUCCESS;
1257 save_offset = ndr->offset;
1258 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1259 if (ptr_offset > ndr->offset) {
1260 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1261 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1262 ptr_offset, ndr->offset);
1264 ndr->offset = ptr_offset;
1265 if (save_offset < ndr->relative_base_offset) {
1266 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1267 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1268 save_offset, ndr->relative_base_offset);
1270 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1271 ndr->offset = save_offset;
1272 return NDR_ERR_SUCCESS;
1276 push a relative object - stage2 start
1277 this is called during buffers processing
1279 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1282 return NDR_ERR_SUCCESS;
1284 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1285 uint32_t relative_offset;
1289 if (ndr->offset < ndr->relative_base_offset) {
1290 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1291 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1292 ndr->offset, ndr->relative_base_offset);
1295 relative_offset = ndr->offset - ndr->relative_base_offset;
1297 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1299 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1301 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1303 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1307 pad = ndr_align_size(relative_offset, align);
1309 NDR_CHECK(ndr_push_zero(ndr, pad));
1312 return ndr_push_relative_ptr2(ndr, p);
1314 if (ndr->relative_end_offset == -1) {
1315 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1316 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1317 ndr->relative_end_offset);
1319 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
1320 return NDR_ERR_SUCCESS;
1324 push a relative object - stage2 end
1325 this is called during buffers processing
1327 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1329 uint32_t begin_offset = 0xFFFFFFFF;
1331 uint32_t correct_offset = 0;
1336 return NDR_ERR_SUCCESS;
1339 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1340 return NDR_ERR_SUCCESS;
1343 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1344 /* better say more than calculation a too small buffer */
1345 NDR_PUSH_ALIGN(ndr, 8);
1346 return NDR_ERR_SUCCESS;
1349 if (ndr->relative_end_offset < ndr->offset) {
1350 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1351 "ndr_push_relative_ptr2_end:"
1352 "relative_end_offset %u < offset %u",
1353 ndr->relative_end_offset, ndr->offset);
1356 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1358 /* we have marshalled a buffer, see how long it was */
1359 len = ndr->offset - begin_offset;
1362 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1363 "ndr_push_relative_ptr2_end:"
1364 "offset %u - begin_offset %u < 0",
1365 ndr->offset, begin_offset);
1368 if (ndr->relative_end_offset < len) {
1369 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1370 "ndr_push_relative_ptr2_end:"
1371 "relative_end_offset %u < len %lld",
1372 ndr->offset, (long long)len);
1375 /* the reversed offset is at the end of the main buffer */
1376 correct_offset = ndr->relative_end_offset - len;
1378 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1380 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1382 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1384 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1388 pad = ndr_align_size(correct_offset, align);
1390 correct_offset += pad;
1391 correct_offset -= align;
1394 if (correct_offset < begin_offset) {
1395 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1396 "ndr_push_relative_ptr2_end: "
1397 "correct_offset %u < begin_offset %u",
1398 correct_offset, begin_offset);
1402 uint32_t clear_size = correct_offset - begin_offset;
1404 clear_size = MIN(clear_size, len);
1406 /* now move the marshalled buffer to the end of the main buffer */
1407 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1410 /* and wipe out old buffer within the main buffer */
1411 memset(ndr->data + begin_offset, '\0', clear_size);
1415 /* and set the end offset for the next buffer */
1416 ndr->relative_end_offset = correct_offset;
1418 /* finally write the offset to the main buffer */
1419 ndr->offset = correct_offset;
1420 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1422 /* restore to where we were in the main buffer */
1423 ndr->offset = begin_offset;
1425 return NDR_ERR_SUCCESS;
1429 get the current base for relative pointers for the pull
1431 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1433 return ndr->relative_base_offset;
1437 restore the old base for relative pointers for the pull
1439 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1441 ndr->relative_base_offset = offset;
1445 setup the current base for relative pointers for the pull
1446 called in the NDR_SCALAR stage
1448 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1450 ndr->relative_base_offset = offset;
1451 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1455 setup the current base for relative pointers for the pull
1456 called in the NDR_BUFFERS stage
1458 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1460 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1464 pull a relative object - stage1
1465 called during SCALARS processing
1467 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1469 rel_offset += ndr->relative_base_offset;
1470 if (rel_offset > ndr->data_size) {
1471 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1472 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1473 rel_offset, ndr->data_size);
1475 return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1479 pull a relative object - stage2
1480 called during BUFFERS processing
1482 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1484 uint32_t rel_offset;
1485 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1486 return ndr_pull_set_offset(ndr, rel_offset);
1489 const static struct {
1490 enum ndr_err_code err;
1492 } ndr_err_code_strings[] = {
1493 { NDR_ERR_SUCCESS, "Success" },
1494 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1495 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1496 { NDR_ERR_OFFSET, "Offset Error" },
1497 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1498 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1499 { NDR_ERR_LENGTH, "Length Error" },
1500 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1501 { NDR_ERR_COMPRESSION, "Compression Error" },
1502 { NDR_ERR_STRING, "String Error" },
1503 { NDR_ERR_VALIDATE, "Validate Error" },
1504 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1505 { NDR_ERR_ALLOC, "Allocation Error" },
1506 { NDR_ERR_RANGE, "Range Error" },
1507 { NDR_ERR_TOKEN, "Token Error" },
1508 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1509 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1510 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1511 { NDR_ERR_NDR64, "NDR64 assertion error" },
1515 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1518 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1519 if (ndr_err_code_strings[i].err == ndr_err)
1520 return ndr_err_code_strings[i].string;
1522 return "Unknown error";