gpo: Test certificate policy without NDES
[Samba.git] / librpc / ndr / ndr.c
blobd187a0d01101ed7bdb5093e5d63f9df3e347bd51
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 "librpc/ndr/ndr_private.h"
33 #include "../lib/util/dlinklist.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_RPC_PARSE
38 #define NDR_BASE_MARSHALL_SIZE 1024
41 * This value is arbitrary, but designed to reduce the memory a client
42 * can allocate and the work the client can force in processing a
43 * malicious packet.
45 * In an ideal world this would be controlled by range() restrictions
46 * on array sizes and careful IDL construction to avoid arbitrary
47 * linked lists, but this is a backstop for now.
49 #define NDR_TOKEN_MAX_LIST_SIZE 65535
51 size_t ndr_token_max_list_size(void) {
52 return NDR_TOKEN_MAX_LIST_SIZE;
55 /* this guid indicates NDR encoding in a protocol tower */
56 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
57 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
61 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
62 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
66 const struct ndr_syntax_id ndr_syntax_id_null = {
67 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
72 work out the number of bytes needed to align on a n byte boundary
74 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
76 if ((offset & (n-1)) == 0) return 0;
77 return n - (offset & (n-1));
81 initialise a ndr parse structure from a data blob
83 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
85 struct ndr_pull *ndr;
87 ndr = talloc_zero(mem_ctx, struct ndr_pull);
88 if (!ndr) return NULL;
89 ndr->current_mem_ctx = mem_ctx;
91 ndr->data = blob->data;
92 ndr->data_size = blob->length;
94 return ndr;
97 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
99 enum ndr_err_code ndr_err;
100 DATA_BLOB b;
101 uint32_t append = 0;
102 bool ok;
104 if (blob->length == 0) {
105 return NDR_ERR_SUCCESS;
108 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
109 if (ndr_err == NDR_ERR_TOKEN) {
110 append = 0;
111 ndr_err = NDR_ERR_SUCCESS;
113 NDR_CHECK(ndr_err);
115 if (ndr->data_size == 0) {
116 ndr->data = NULL;
117 append = UINT32_MAX;
120 if (append == UINT32_MAX) {
122 * append == UINT32_MAX means that
123 * ndr->data is either NULL or a valid
124 * talloc child of ndr, which means
125 * we can use data_blob_append() without
126 * data_blob_talloc() of the existing callers data
128 b = data_blob_const(ndr->data, ndr->data_size);
129 } else {
130 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
131 if (b.data == NULL) {
132 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
136 ok = data_blob_append(ndr, &b, blob->data, blob->length);
137 if (!ok) {
138 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
141 ndr->data = b.data;
142 ndr->data_size = b.length;
144 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
147 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
149 uint32_t skip = 0;
150 uint32_t append = 0;
151 enum ndr_err_code ndr_err;
153 if (ndr->relative_base_offset != 0) {
154 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
155 "%s", __location__);
157 if (ndr->relative_highest_offset != 0) {
158 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
159 "%s", __location__);
161 if (ndr->relative_list.count != 0) {
162 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
163 "%s", __location__);
165 if (ndr->relative_base_list.count != 0) {
166 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
167 "%s", __location__);
171 * we need to keep up to 7 bytes
172 * in order to get the alignment right.
174 skip = ndr->offset & 0xFFFFFFF8;
176 if (skip == 0) {
177 return NDR_ERR_SUCCESS;
180 ndr->offset -= skip;
181 ndr->data_size -= skip;
183 ndr_err = ndr_token_peek(&ndr->array_size_list, ndr, &append);
184 if (ndr_err == NDR_ERR_TOKEN) {
186 * here we assume, that ndr->data is not a
187 * talloc child of ndr.
189 ndr->data += skip;
190 return NDR_ERR_SUCCESS;
193 memmove(ndr->data, ndr->data + skip, ndr->data_size);
195 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
196 if (ndr->data_size != 0 && ndr->data == NULL) {
197 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
200 return NDR_ERR_SUCCESS;
204 advance by 'size' bytes
206 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
208 NDR_PULL_NEED_BYTES(ndr, size);
209 ndr->offset += size;
210 return NDR_ERR_SUCCESS;
214 set the parse offset to 'ofs'
216 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
218 ndr->offset = ofs;
219 if (ndr->offset > ndr->data_size) {
220 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
221 "ndr_pull_set_offset %u failed",
222 ofs);
224 return NDR_ERR_SUCCESS;
227 /* create a ndr_push structure, ready for some marshalling */
228 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
230 struct ndr_push *ndr;
232 ndr = talloc_zero(mem_ctx, struct ndr_push);
233 if (!ndr) {
234 return NULL;
237 ndr->flags = 0;
238 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
239 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
240 if (!ndr->data) {
241 talloc_free(ndr);
242 return NULL;
245 return ndr;
248 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
249 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
251 DATA_BLOB blob;
252 blob = data_blob_const(ndr->data, ndr->offset);
253 if (ndr->alloc_size > ndr->offset) {
254 ndr->data[ndr->offset] = 0;
256 return blob;
261 expand the available space in the buffer to ndr->offset + extra_size
263 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
265 uint32_t size = extra_size + ndr->offset;
267 if (size < ndr->offset) {
268 /* extra_size overflowed the offset */
269 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
270 size);
273 if (ndr->fixed_buf_size) {
274 if (ndr->alloc_size >= size) {
275 return NDR_ERR_SUCCESS;
277 return ndr_push_error(ndr,
278 NDR_ERR_BUFSIZE,
279 "Overflow of fixed buffer in "
280 "push_expand to %u",
281 size);
284 if (ndr->alloc_size > size) {
285 return NDR_ERR_SUCCESS;
288 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
289 if (size == UINT32_MAX) {
290 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand");
292 if (size+1 > ndr->alloc_size) {
293 ndr->alloc_size = size+1;
295 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
296 if (!ndr->data) {
297 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
298 ndr->alloc_size);
301 return NDR_ERR_SUCCESS;
304 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
306 va_list ap;
307 char *s = NULL;
308 uint32_t i;
309 int ret;
310 int dbgc_class;
312 va_start(ap, format);
313 ret = vasprintf(&s, format, ap);
314 va_end(ap);
316 if (ret == -1) {
317 return;
320 dbgc_class = *(int *)ndr->private_data;
322 if (ndr->no_newline) {
323 DEBUGADDC(dbgc_class, 1,("%s", s));
324 free(s);
325 return;
328 for (i=0;i<ndr->depth;i++) {
329 DEBUGADDC(dbgc_class, 1,(" "));
332 DEBUGADDC(dbgc_class, 1,("%s\n", s));
333 free(s);
336 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
338 va_list ap;
339 char *s = NULL;
340 uint32_t i;
341 int ret;
343 va_start(ap, format);
344 ret = vasprintf(&s, format, ap);
345 va_end(ap);
347 if (ret == -1) {
348 return;
351 if (ndr->no_newline) {
352 DEBUGADD(1,("%s", s));
353 free(s);
354 return;
357 for (i=0;i<ndr->depth;i++) {
358 DEBUGADD(1,(" "));
361 DEBUGADD(1,("%s\n", s));
362 free(s);
365 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
367 va_list ap;
368 uint32_t i;
370 if (!ndr->no_newline) {
371 for (i=0;i<ndr->depth;i++) {
372 printf(" ");
376 va_start(ap, format);
377 vprintf(format, ap);
378 va_end(ap);
379 if (!ndr->no_newline) {
380 printf("\n");
384 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
386 va_list ap;
387 uint32_t i;
389 if (!ndr->no_newline) {
390 for (i=0;i<ndr->depth;i++) {
391 ndr->private_data = talloc_asprintf_append_buffer(
392 (char *)ndr->private_data, " ");
396 va_start(ap, format);
397 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
398 format, ap);
399 va_end(ap);
400 if (!ndr->no_newline) {
401 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
402 "\n");
407 a useful helper function for printing idl structures via DEBUGC()
409 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
411 struct ndr_print *ndr;
413 DEBUGC(dbgc_class, 1,(" "));
415 ndr = talloc_zero(NULL, struct ndr_print);
416 if (!ndr) return;
417 ndr->private_data = &dbgc_class;
418 ndr->print = ndr_print_debugc_helper;
419 ndr->depth = 1;
420 ndr->flags = 0;
421 #ifdef DEBUG_PASSWORD
422 if (CHECK_DEBUGLVL(100)) {
423 ndr->print_secrets = true;
425 #endif
427 fn(ndr, name, ptr);
428 talloc_free(ndr);
432 a useful helper function for printing idl structures via DEBUG()
434 _PUBLIC_ bool ndr_print_debug(int level,
435 ndr_print_fn_t fn,
436 const char *name,
437 void *ptr,
438 const char *location,
439 const char *function)
441 struct ndr_print *ndr;
443 DEBUGLF(level, (" "), location, function);
445 ndr = talloc_zero(NULL, struct ndr_print);
446 if (!ndr) return false;
447 ndr->print = ndr_print_debug_helper;
448 ndr->depth = 1;
449 ndr->flags = 0;
450 #ifdef DEBUG_PASSWORD
451 if (CHECK_DEBUGLVL(100)) {
452 ndr->print_secrets = true;
454 #endif
456 fn(ndr, name, ptr);
457 talloc_free(ndr);
458 return true;
462 a useful helper function for printing idl unions via DEBUG()
464 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
466 struct ndr_print *ndr;
468 DEBUG(1,(" "));
470 ndr = talloc_zero(NULL, struct ndr_print);
471 if (!ndr) return;
472 ndr->print = ndr_print_debug_helper;
473 ndr->depth = 1;
474 ndr->flags = 0;
475 #ifdef DEBUG_PASSWORD
476 if (CHECK_DEBUGLVL(100)) {
477 ndr->print_secrets = true;
479 #endif
481 ndr_print_set_switch_value(ndr, ptr, level);
482 fn(ndr, name, ptr);
483 talloc_free(ndr);
487 a useful helper function for printing idl function calls via DEBUG()
489 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
491 struct ndr_print *ndr;
493 DEBUG(1,(" "));
495 ndr = talloc_zero(NULL, struct ndr_print);
496 if (!ndr) return;
497 ndr->print = ndr_print_debug_helper;
498 ndr->depth = 1;
499 ndr->flags = 0;
500 #ifdef DEBUG_PASSWORD
501 if (CHECK_DEBUGLVL(100)) {
502 ndr->print_secrets = true;
504 #endif
506 fn(ndr, name, flags, ptr);
507 talloc_free(ndr);
511 a useful helper function for printing idl structures to a string
513 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
515 struct ndr_print *ndr;
516 char *ret = NULL;
518 ndr = talloc_zero(mem_ctx, struct ndr_print);
519 if (!ndr) return NULL;
520 ndr->private_data = talloc_strdup(ndr, "");
521 if (!ndr->private_data) {
522 goto failed;
524 ndr->print = ndr_print_string_helper;
525 ndr->depth = 1;
526 ndr->flags = 0;
528 fn(ndr, name, ptr);
529 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
530 failed:
531 talloc_free(ndr);
532 return ret;
536 a useful helper function for printing idl unions to a string
538 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
540 struct ndr_print *ndr;
541 char *ret = NULL;
543 ndr = talloc_zero(mem_ctx, struct ndr_print);
544 if (!ndr) return NULL;
545 ndr->private_data = talloc_strdup(ndr, "");
546 if (!ndr->private_data) {
547 goto failed;
549 ndr->print = ndr_print_string_helper;
550 ndr->depth = 1;
551 ndr->flags = 0;
552 ndr_print_set_switch_value(ndr, ptr, level);
553 fn(ndr, name, ptr);
554 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
555 failed:
556 talloc_free(ndr);
557 return ret;
561 a useful helper function for printing idl function calls to a string
563 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
564 ndr_print_function_t fn, const char *name,
565 int flags, void *ptr)
567 struct ndr_print *ndr;
568 char *ret = NULL;
570 ndr = talloc_zero(mem_ctx, struct ndr_print);
571 if (!ndr) return NULL;
572 ndr->private_data = talloc_strdup(ndr, "");
573 if (!ndr->private_data) {
574 goto failed;
576 ndr->print = ndr_print_string_helper;
577 ndr->depth = 1;
578 ndr->flags = 0;
579 fn(ndr, name, flags, ptr);
580 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
581 failed:
582 talloc_free(ndr);
583 return ret;
586 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
588 /* the big/little endian flags are inter-dependent */
589 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
590 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
591 (*pflags) &= ~LIBNDR_FLAG_NDR64;
593 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
594 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
595 (*pflags) &= ~LIBNDR_FLAG_NDR64;
597 if (new_flags & LIBNDR_ALIGN_FLAGS) {
598 /* Ensure we only have the passed-in
599 align flag set in the new_flags,
600 remove any old align flag. */
601 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
603 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
604 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
606 (*pflags) |= new_flags;
610 return and possibly log an NDR error
612 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
613 enum ndr_err_code ndr_err,
614 const char *function,
615 const char *location,
616 const char *format, ...)
618 char *s=NULL;
619 va_list ap;
620 int ret;
622 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
623 switch (ndr_err) {
624 case NDR_ERR_BUFSIZE:
625 return NDR_ERR_INCOMPLETE_BUFFER;
626 default:
627 break;
631 va_start(ap, format);
632 ret = vasprintf(&s, format, ap);
633 va_end(ap);
635 if (ret == -1) {
636 return NDR_ERR_ALLOC;
639 D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
640 function,
641 ndr_map_error2string(ndr_err),
643 location);
645 free(s);
647 return ndr_err;
651 return and possibly log an NDR error
653 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
654 enum ndr_err_code ndr_err,
655 const char *function,
656 const char *location,
657 const char *format, ...)
659 char *s=NULL;
660 va_list ap;
661 int ret;
663 va_start(ap, format);
664 ret = vasprintf(&s, format, ap);
665 va_end(ap);
667 if (ret == -1) {
668 return NDR_ERR_ALLOC;
671 D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
672 function,
673 ndr_map_error2string(ndr_err),
675 location);
677 free(s);
679 return ndr_err;
683 handle subcontext buffers, which in midl land are user-marshalled, but
684 we use magic in pidl to make them easier to cope with
686 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
687 struct ndr_pull **_subndr,
688 size_t header_size,
689 ssize_t size_is)
691 struct ndr_pull *subndr;
692 uint32_t r_content_size;
693 bool force_le = false;
694 bool force_be = false;
696 switch (header_size) {
697 case 0: {
698 uint32_t content_size = ndr->data_size - ndr->offset;
699 if (size_is >= 0) {
700 content_size = size_is;
702 r_content_size = content_size;
703 break;
706 case 2: {
707 uint16_t content_size;
708 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
709 if (size_is >= 0 && size_is != content_size) {
710 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
711 (int)size_is, (int)size_is,
712 (int)content_size,
713 (int)content_size);
715 r_content_size = content_size;
716 break;
719 case 4: {
720 uint32_t content_size;
721 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
722 if (size_is >= 0 && size_is != content_size) {
723 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
724 (int)size_is, (int)size_is,
725 (int)content_size,
726 (int)content_size);
728 r_content_size = content_size;
729 break;
731 case 0xFFFFFC01: {
733 * Common Type Header for the Serialization Stream
734 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
736 uint8_t version;
737 uint8_t drep;
738 uint16_t hdrlen;
739 uint32_t filler;
740 uint32_t content_size;
741 uint32_t reserved;
743 /* version */
744 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
746 if (version != 1) {
747 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
748 "Bad subcontext (PULL) Common Type Header version %d != 1",
749 (int)version);
753 * 0x10 little endian
754 * 0x00 big endian
756 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
757 if (drep == 0x10) {
758 force_le = true;
759 } else if (drep == 0x00) {
760 force_be = true;
761 } else {
762 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
763 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
764 (unsigned int)drep);
767 /* length of the "Private Header for Constructed Type" */
768 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
769 if (hdrlen != 8) {
770 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
771 "Bad subcontext (PULL) Common Type Header length %d != 8",
772 (int)hdrlen);
775 /* filler should be ignored */
776 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
779 * Private Header for Constructed Type
781 /* length - will be updated latter */
782 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
783 if (size_is >= 0 && size_is != content_size) {
784 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
785 (int)size_is, (int)content_size);
787 /* the content size must be a multiple of 8 */
788 if ((content_size % 8) != 0) {
789 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
790 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
791 (int)size_is, (int)content_size);
793 r_content_size = content_size;
795 /* reserved */
796 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
797 break;
799 case 0xFFFFFFFF:
801 * a shallow copy like subcontext
802 * useful for DCERPC pipe chunks.
804 subndr = talloc_zero(ndr, struct ndr_pull);
805 NDR_ERR_HAVE_NO_MEMORY(subndr);
807 subndr->flags = ndr->flags;
808 subndr->current_mem_ctx = ndr->current_mem_ctx;
809 subndr->data = ndr->data;
810 subndr->offset = ndr->offset;
811 subndr->data_size = ndr->data_size;
813 *_subndr = subndr;
814 return NDR_ERR_SUCCESS;
816 default:
817 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
818 (int)header_size);
821 NDR_PULL_NEED_BYTES(ndr, r_content_size);
823 subndr = talloc_zero(ndr, struct ndr_pull);
824 NDR_ERR_HAVE_NO_MEMORY(subndr);
825 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
826 subndr->current_mem_ctx = ndr->current_mem_ctx;
828 subndr->data = ndr->data + ndr->offset;
829 subndr->offset = 0;
830 subndr->data_size = r_content_size;
832 if (force_le) {
833 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
834 } else if (force_be) {
835 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
838 *_subndr = subndr;
839 return NDR_ERR_SUCCESS;
842 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
843 struct ndr_pull *subndr,
844 size_t header_size,
845 ssize_t size_is)
847 uint32_t advance;
848 uint32_t highest_ofs;
850 if (header_size == 0xFFFFFFFF) {
851 advance = subndr->offset - ndr->offset;
852 } else if (size_is >= 0) {
853 advance = size_is;
854 } else if (header_size > 0) {
855 advance = subndr->data_size;
856 } else {
857 advance = subndr->offset;
860 if (subndr->offset > ndr->relative_highest_offset) {
861 highest_ofs = subndr->offset;
862 } else {
863 highest_ofs = subndr->relative_highest_offset;
865 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
867 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
869 highest_ofs = advance;
871 if (highest_ofs < advance) {
872 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
873 "not all bytes consumed ofs[%u] advance[%u]",
874 highest_ofs, advance);
877 NDR_CHECK(ndr_pull_advance(ndr, advance));
878 return NDR_ERR_SUCCESS;
881 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
882 struct ndr_push **_subndr,
883 size_t header_size,
884 ssize_t size_is)
886 struct ndr_push *subndr;
888 subndr = ndr_push_init_ctx(ndr);
889 NDR_ERR_HAVE_NO_MEMORY(subndr);
890 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
892 if (size_is > 0) {
893 NDR_CHECK(ndr_push_zero(subndr, size_is));
894 subndr->offset = 0;
895 subndr->relative_end_offset = size_is;
898 *_subndr = subndr;
899 return NDR_ERR_SUCCESS;
903 push a subcontext header
905 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
906 struct ndr_push *subndr,
907 size_t header_size,
908 ssize_t size_is)
910 ssize_t padding_len;
912 if (size_is >= 0) {
913 padding_len = size_is - subndr->offset;
914 if (padding_len < 0) {
915 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
916 (int)subndr->offset, (int)size_is);
918 subndr->offset = size_is;
921 switch (header_size) {
922 case 0:
923 break;
925 case 2:
926 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
927 break;
929 case 4:
930 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
931 break;
933 case 0xFFFFFC01:
935 * Common Type Header for the Serialization Stream
936 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
938 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
939 if (padding_len > 0) {
940 NDR_CHECK(ndr_push_zero(subndr, padding_len));
943 /* version */
944 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
947 * 0x10 little endian
948 * 0x00 big endian
950 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
952 /* length of the "Private Header for Constructed Type" */
953 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
955 /* filler */
956 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
959 * Private Header for Constructed Type
961 /* length - will be updated latter */
962 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
964 /* reserved */
965 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
966 break;
968 default:
969 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
970 (int)header_size);
973 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
974 return NDR_ERR_SUCCESS;
978 struct ndr_token {
979 const void *key;
980 uint32_t value;
984 store a token in the ndr context, for later retrieval
986 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
987 struct ndr_token_list *list,
988 const void *key,
989 uint32_t value)
991 if (list->tokens == NULL) {
992 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
993 if (list->tokens == NULL) {
994 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
996 } else {
997 struct ndr_token *new_tokens = NULL;
998 uint32_t alloc_count = talloc_array_length(list->tokens);
1001 * Check every time we have not allocated too many
1002 * tokens. This ensures developer sanity when
1003 * debugging the boundary condition
1005 if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
1006 return NDR_ERR_RANGE;
1008 if (list->count == alloc_count) {
1009 unsigned new_alloc;
1011 * Double the list, until we start in chunks
1012 * of 1000
1014 unsigned increment = MIN(list->count, 1000);
1015 new_alloc = alloc_count + increment;
1016 if (new_alloc < alloc_count) {
1017 return NDR_ERR_RANGE;
1019 new_tokens = talloc_realloc(mem_ctx, list->tokens,
1020 struct ndr_token, new_alloc);
1021 NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1022 list->tokens = new_tokens;
1025 list->tokens[list->count].key = key;
1026 list->tokens[list->count].value = value;
1027 list->count++;
1028 return NDR_ERR_SUCCESS;
1032 retrieve a token from a ndr context, using cmp_fn to match the tokens
1034 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
1035 const void *key, uint32_t *v,
1036 comparison_fn_t _cmp_fn,
1037 bool erase)
1039 struct ndr_token *tokens = list->tokens;
1040 unsigned i;
1041 if (_cmp_fn) {
1042 for (i = list->count - 1; i < list->count; i--) {
1043 if (_cmp_fn(tokens[i].key, key) == 0) {
1044 goto found;
1047 } else {
1048 for (i = list->count - 1; i < list->count; i--) {
1049 if (tokens[i].key == key) {
1050 goto found;
1054 return NDR_ERR_TOKEN;
1055 found:
1056 *v = tokens[i].value;
1057 if (erase) {
1058 if (i != list->count - 1) {
1059 tokens[i] = tokens[list->count - 1];
1061 list->count--;
1063 return NDR_ERR_SUCCESS;
1067 retrieve a token from a ndr context
1069 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1070 const void *key, uint32_t *v)
1072 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1076 peek at but don't removed a token from a ndr context
1078 _PUBLIC_ enum ndr_err_code ndr_token_peek(struct ndr_token_list *list,
1079 const void *key, uint32_t *v)
1081 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, false);
1085 pull an array size field and add it to the array_size_list token list
1087 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1089 enum ndr_err_code ret;
1090 uint32_t size;
1091 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1092 ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1093 if (ret == NDR_ERR_RANGE) {
1094 return ndr_pull_error(ndr, ret,
1095 "More than %d NDR tokens stored for array_size",
1096 NDR_TOKEN_MAX_LIST_SIZE);
1098 return ret;
1102 get the stored array size field
1104 _PUBLIC_ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1106 return ndr_token_peek(&ndr->array_size_list, p, size);
1110 get and remove from the stored list the stored array size field
1112 _PUBLIC_ enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1114 return ndr_token_retrieve(&ndr->array_size_list, p, size);
1118 * check the stored array size field and remove from the stored list
1119 * (the array_size NDR token list). We try to remove when possible to
1120 * avoid the list growing towards the bounds check
1122 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1124 uint32_t stored;
1125 NDR_CHECK(ndr_steal_array_size(ndr, p, &stored));
1126 if (stored != size) {
1127 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1128 "Bad array size - got %u expected %u\n",
1129 stored, size);
1131 return NDR_ERR_SUCCESS;
1135 * check the stored array size field (leaving it on the array_size
1136 * token list)
1138 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1140 uint32_t stored;
1141 NDR_CHECK(ndr_get_array_size(ndr, p, &stored));
1142 if (stored != size) {
1143 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1144 "Bad array size - got %u expected %u\n",
1145 stored, size);
1147 return NDR_ERR_SUCCESS;
1151 pull an array length field and add it to the array_length_list token list
1153 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1155 enum ndr_err_code ret;
1156 uint32_t length, offset;
1157 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1158 if (offset != 0) {
1159 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1160 "non-zero array offset %u\n", offset);
1162 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1163 ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1164 if (ret == NDR_ERR_RANGE) {
1165 return ndr_pull_error(ndr, ret,
1166 "More than %d NDR tokens stored for array_length_list",
1167 NDR_TOKEN_MAX_LIST_SIZE);
1169 return ret;
1173 get the stored array length field
1175 _PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1177 return ndr_token_peek(&ndr->array_length_list, p, length);
1181 * check the stored array length field and remove from the stored list
1182 * (the array_size NDR token list). We try to remove when possible to
1183 * avoid the list growing towards the bounds check
1185 _PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1187 return ndr_token_retrieve(&ndr->array_length_list, p, length);
1190 check the stored array length field, removing it from the list
1192 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
1194 uint32_t stored;
1195 NDR_CHECK(ndr_steal_array_length(ndr, p, &stored));
1196 if (stored != length) {
1197 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1198 "Bad array length - got %u expected %u\n",
1199 stored, length);
1201 return NDR_ERR_SUCCESS;
1204 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1206 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1207 int64_t tmp = 0 - (int64_t)count;
1208 uint64_t ncount = tmp;
1210 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1213 return NDR_ERR_SUCCESS;
1216 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1218 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1219 int64_t tmp = 0 - (int64_t)count;
1220 uint64_t ncount1 = tmp;
1221 uint64_t ncount2;
1223 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1224 if (ncount1 == ncount2) {
1225 return NDR_ERR_SUCCESS;
1228 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1229 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1230 (unsigned long long)ncount2,
1231 (unsigned long long)ncount1,
1232 (unsigned long)count);
1235 return NDR_ERR_SUCCESS;
1239 store a switch value
1241 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1243 enum ndr_err_code ret =
1244 ndr_token_store(ndr, &ndr->switch_list, p, val);
1245 if (ret == NDR_ERR_RANGE) {
1246 return ndr_push_error(ndr, ret,
1247 "More than %d NDR tokens stored for switch_list",
1248 NDR_TOKEN_MAX_LIST_SIZE);
1250 return ret;
1253 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1256 enum ndr_err_code ret =
1257 ndr_token_store(ndr, &ndr->switch_list, p, val);
1258 if (ret == NDR_ERR_RANGE) {
1259 return ndr_pull_error(ndr, ret,
1260 "More than %d NDR tokens stored for switch_list",
1261 NDR_TOKEN_MAX_LIST_SIZE);
1263 return ret;
1266 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1268 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1271 /* retrieve a switch value (for push) and remove it from the list */
1272 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1273 const void *p,
1274 uint32_t *v)
1276 return ndr_token_retrieve(&ndr->switch_list, p, v);
1279 /* retrieve a switch value and remove it from the list */
1280 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1282 enum ndr_err_code status;
1283 uint32_t v;
1285 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1286 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1287 return 0;
1290 return v;
1293 /* retrieve a switch value and remove it from the list */
1294 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1295 const void *p,
1296 uint32_t *v)
1298 return ndr_token_retrieve(&ndr->switch_list, p, v);
1302 pull a struct from a blob using NDR
1304 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1305 ndr_pull_flags_fn_t fn)
1307 struct ndr_pull *ndr;
1308 ndr = ndr_pull_init_blob(blob, mem_ctx);
1309 NDR_ERR_HAVE_NO_MEMORY(ndr);
1310 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1311 talloc_free(ndr);
1312 return NDR_ERR_SUCCESS;
1316 pull a struct from a blob using NDR - failing if all bytes are not consumed
1318 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1319 void *p, ndr_pull_flags_fn_t fn)
1321 struct ndr_pull *ndr;
1322 uint32_t highest_ofs;
1323 ndr = ndr_pull_init_blob(blob, mem_ctx);
1324 NDR_ERR_HAVE_NO_MEMORY(ndr);
1325 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1326 if (ndr->offset > ndr->relative_highest_offset) {
1327 highest_ofs = ndr->offset;
1328 } else {
1329 highest_ofs = ndr->relative_highest_offset;
1331 if (highest_ofs < ndr->data_size) {
1332 enum ndr_err_code ret;
1333 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1334 "not all bytes consumed ofs[%u] size[%u]",
1335 highest_ofs, ndr->data_size);
1336 talloc_free(ndr);
1337 return ret;
1339 talloc_free(ndr);
1340 return NDR_ERR_SUCCESS;
1344 pull a struct from a blob using NDR - failing if all bytes are not consumed
1346 This only works for structures with NO allocated memory, like
1347 objectSID and GUID. This helps because we parse these a lot.
1349 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1350 void *p, ndr_pull_flags_fn_t fn)
1353 * We init this structure on the stack here, to avoid a
1354 * talloc() as otherwise this call to the fn() is assured not
1355 * to be doing any allocation, eg SIDs and GUIDs.
1357 * This allows us to keep the safety of the PIDL-generated
1358 * code without the talloc() overhead.
1360 struct ndr_pull ndr = {
1361 .data = blob->data,
1362 .data_size = blob->length,
1363 .current_mem_ctx = (void *)-1
1365 uint32_t highest_ofs;
1366 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1367 highest_ofs = MAX(ndr.offset, ndr.relative_highest_offset);
1368 if (highest_ofs < ndr.data_size) {
1369 enum ndr_err_code ret;
1370 ret = ndr_pull_error(
1371 &ndr,
1372 NDR_ERR_UNREAD_BYTES,
1373 "not all bytes consumed ofs[%"PRIu32"] "
1374 "size[%"PRIu32"]",
1375 highest_ofs,
1376 ndr.data_size);
1377 return ret;
1379 return NDR_ERR_SUCCESS;
1383 pull a union from a blob using NDR, given the union discriminator
1385 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1386 void *p,
1387 uint32_t level, ndr_pull_flags_fn_t fn)
1389 struct ndr_pull *ndr;
1390 ndr = ndr_pull_init_blob(blob, mem_ctx);
1391 NDR_ERR_HAVE_NO_MEMORY(ndr);
1392 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1393 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1394 talloc_free(ndr);
1395 return NDR_ERR_SUCCESS;
1399 pull a union from a blob using NDR, given the union discriminator,
1400 failing if all bytes are not consumed
1402 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1403 void *p,
1404 uint32_t level, ndr_pull_flags_fn_t fn)
1406 struct ndr_pull *ndr;
1407 uint32_t highest_ofs;
1408 ndr = ndr_pull_init_blob(blob, mem_ctx);
1409 NDR_ERR_HAVE_NO_MEMORY(ndr);
1410 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1411 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1412 if (ndr->offset > ndr->relative_highest_offset) {
1413 highest_ofs = ndr->offset;
1414 } else {
1415 highest_ofs = ndr->relative_highest_offset;
1417 if (highest_ofs < ndr->data_size) {
1418 enum ndr_err_code ret;
1419 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1420 "not all bytes consumed ofs[%u] size[%u]",
1421 highest_ofs, ndr->data_size);
1422 talloc_free(ndr);
1423 return ret;
1425 talloc_free(ndr);
1426 return NDR_ERR_SUCCESS;
1430 push a struct to a blob using NDR
1432 _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)
1434 struct ndr_push *ndr;
1435 ndr = ndr_push_init_ctx(mem_ctx);
1436 NDR_ERR_HAVE_NO_MEMORY(ndr);
1438 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1440 *blob = ndr_push_blob(ndr);
1441 talloc_steal(mem_ctx, blob->data);
1442 talloc_free(ndr);
1444 return NDR_ERR_SUCCESS;
1448 push a struct into a provided blob using NDR.
1450 We error because we want to have the performance issue (extra
1451 talloc() calls) show up as an error, not just slower code. This is
1452 used for things like GUIDs, which we expect to be a fixed size, and
1453 SIDs that we can pre-calculate the size for.
1455 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1456 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1458 struct ndr_push ndr = {
1459 .data = blob->data,
1460 .alloc_size = blob->length,
1461 .fixed_buf_size = true
1464 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1466 if (ndr.offset != blob->length) {
1467 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1468 "buffer was either to large or small "
1469 "ofs[%u] size[%zu]",
1470 ndr.offset, blob->length);
1473 return NDR_ERR_SUCCESS;
1477 push a union to a blob using NDR
1479 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1480 uint32_t level, ndr_push_flags_fn_t fn)
1482 struct ndr_push *ndr;
1483 ndr = ndr_push_init_ctx(mem_ctx);
1484 NDR_ERR_HAVE_NO_MEMORY(ndr);
1486 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1487 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1489 *blob = ndr_push_blob(ndr);
1490 talloc_steal(mem_ctx, blob->data);
1491 talloc_free(ndr);
1493 return NDR_ERR_SUCCESS;
1497 generic ndr_size_*() handler for structures
1499 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1501 struct ndr_push *ndr;
1502 enum ndr_err_code status;
1503 size_t ret;
1505 /* avoid recursion */
1506 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1508 /* Avoid following a NULL pointer */
1509 if (p == NULL) {
1510 return 0;
1513 ndr = ndr_push_init_ctx(NULL);
1514 if (!ndr) return 0;
1515 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1516 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1517 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1518 talloc_free(ndr);
1519 return 0;
1521 ret = ndr->offset;
1522 talloc_free(ndr);
1523 return ret;
1527 generic ndr_size_*() handler for unions
1529 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1531 struct ndr_push *ndr;
1532 enum ndr_err_code status;
1533 size_t ret;
1535 /* avoid recursion */
1536 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1538 /* Avoid following a NULL pointer */
1539 if (p == NULL) {
1540 return 0;
1543 ndr = ndr_push_init_ctx(NULL);
1544 if (!ndr) return 0;
1545 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1547 status = ndr_push_set_switch_value(ndr, p, level);
1548 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1549 talloc_free(ndr);
1550 return 0;
1552 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1553 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1554 talloc_free(ndr);
1555 return 0;
1557 ret = ndr->offset;
1558 talloc_free(ndr);
1559 return ret;
1563 get the current base for relative pointers for the push
1565 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1567 return ndr->relative_base_offset;
1571 restore the old base for relative pointers for the push
1573 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1575 ndr->relative_base_offset = offset;
1579 setup the current base for relative pointers for the push
1580 called in the NDR_SCALAR stage
1582 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1584 enum ndr_err_code ret;
1585 ndr->relative_base_offset = offset;
1586 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1587 if (ret == NDR_ERR_RANGE) {
1588 return ndr_push_error(ndr, ret,
1589 "More than %d NDR tokens stored for relative_base_list",
1590 NDR_TOKEN_MAX_LIST_SIZE);
1592 return ret;
1596 setup the current base for relative pointers for the push
1597 called in the NDR_BUFFERS stage
1599 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1601 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1605 push a relative object - stage1
1606 this is called during SCALARS processing
1608 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1610 enum ndr_err_code ret;
1611 if (p == NULL) {
1612 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1613 return NDR_ERR_SUCCESS;
1615 NDR_CHECK(ndr_push_align(ndr, 4));
1616 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1617 if (ret == NDR_ERR_RANGE) {
1618 return ndr_push_error(ndr, ret,
1619 "More than %d NDR tokens stored for relative_list",
1620 NDR_TOKEN_MAX_LIST_SIZE);
1622 NDR_CHECK(ret);
1623 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1627 push a short relative object - stage1
1628 this is called during SCALARS processing
1630 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1632 enum ndr_err_code ret;
1633 if (p == NULL) {
1634 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1635 return NDR_ERR_SUCCESS;
1637 NDR_CHECK(ndr_push_align(ndr, 2));
1638 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1639 if (ret == NDR_ERR_RANGE) {
1640 return ndr_push_error(ndr, ret,
1641 "More than %d NDR tokens stored for relative_list",
1642 NDR_TOKEN_MAX_LIST_SIZE);
1644 NDR_CHECK(ret);
1645 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1648 push a relative object - stage2
1649 this is called during buffers processing
1651 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1653 uint32_t save_offset;
1654 uint32_t ptr_offset = 0xFFFFFFFF;
1655 if (p == NULL) {
1656 return NDR_ERR_SUCCESS;
1658 save_offset = ndr->offset;
1659 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1660 if (ptr_offset > ndr->offset) {
1661 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1662 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1663 ptr_offset, ndr->offset);
1665 ndr->offset = ptr_offset;
1666 if (save_offset < ndr->relative_base_offset) {
1667 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1668 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1669 save_offset, ndr->relative_base_offset);
1671 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1672 ndr->offset = save_offset;
1673 return NDR_ERR_SUCCESS;
1676 push a short relative object - stage2
1677 this is called during buffers processing
1679 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1681 uint32_t save_offset;
1682 uint32_t ptr_offset = 0xFFFF;
1683 uint32_t relative_offset;
1684 size_t pad;
1685 size_t align = 1;
1687 if (p == NULL) {
1688 return NDR_ERR_SUCCESS;
1691 if (ndr->offset < ndr->relative_base_offset) {
1692 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1693 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1694 ndr->offset, ndr->relative_base_offset);
1697 relative_offset = ndr->offset - ndr->relative_base_offset;
1699 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1700 align = 1;
1701 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1702 align = 2;
1703 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1704 align = 4;
1705 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1706 align = 8;
1709 pad = ndr_align_size(relative_offset, align);
1710 if (pad != 0) {
1711 NDR_CHECK(ndr_push_zero(ndr, pad));
1714 relative_offset = ndr->offset - ndr->relative_base_offset;
1715 if (relative_offset > UINT16_MAX) {
1716 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1717 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1718 relative_offset);
1721 save_offset = ndr->offset;
1722 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1723 if (ptr_offset > ndr->offset) {
1724 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1725 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1726 ptr_offset, ndr->offset);
1728 ndr->offset = ptr_offset;
1729 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1730 ndr->offset = save_offset;
1731 return NDR_ERR_SUCCESS;
1735 push a relative object - stage2 start
1736 this is called during buffers processing
1738 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1740 enum ndr_err_code ret;
1741 if (p == NULL) {
1742 return NDR_ERR_SUCCESS;
1744 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1745 uint32_t relative_offset;
1746 size_t pad;
1747 size_t align = 1;
1749 if (ndr->offset < ndr->relative_base_offset) {
1750 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1751 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1752 ndr->offset, ndr->relative_base_offset);
1755 relative_offset = ndr->offset - ndr->relative_base_offset;
1757 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1758 align = 1;
1759 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1760 align = 2;
1761 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1762 align = 4;
1763 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1764 align = 8;
1767 pad = ndr_align_size(relative_offset, align);
1768 if (pad) {
1769 NDR_CHECK(ndr_push_zero(ndr, pad));
1772 return ndr_push_relative_ptr2(ndr, p);
1774 if (ndr->relative_end_offset == -1) {
1775 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1776 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1777 ndr->relative_end_offset);
1779 ret = ndr_token_store(ndr,
1780 &ndr->relative_begin_list,
1782 ndr->offset);
1783 if (ret == NDR_ERR_RANGE) {
1784 return ndr_push_error(ndr, ret,
1785 "More than %d NDR tokens stored for array_size",
1786 NDR_TOKEN_MAX_LIST_SIZE);
1788 return ret;
1792 push a relative object - stage2 end
1793 this is called during buffers processing
1795 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1797 uint32_t begin_offset = 0xFFFFFFFF;
1798 ssize_t len;
1799 uint32_t correct_offset = 0;
1800 uint32_t align = 1;
1801 uint32_t pad = 0;
1803 if (p == NULL) {
1804 return NDR_ERR_SUCCESS;
1807 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1808 return NDR_ERR_SUCCESS;
1811 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1812 /* better say more than calculation a too small buffer */
1813 NDR_PUSH_ALIGN(ndr, 8);
1814 return NDR_ERR_SUCCESS;
1817 if (ndr->relative_end_offset < ndr->offset) {
1818 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1819 "ndr_push_relative_ptr2_end:"
1820 "relative_end_offset %u < offset %u",
1821 ndr->relative_end_offset, ndr->offset);
1824 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1826 /* we have marshalled a buffer, see how long it was */
1827 len = ndr->offset - begin_offset;
1829 if (len < 0) {
1830 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1831 "ndr_push_relative_ptr2_end:"
1832 "offset %u - begin_offset %u < 0",
1833 ndr->offset, begin_offset);
1836 if (ndr->relative_end_offset < len) {
1837 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1838 "ndr_push_relative_ptr2_end:"
1839 "relative_end_offset %u < len %lld",
1840 ndr->offset, (long long)len);
1843 /* the reversed offset is at the end of the main buffer */
1844 correct_offset = ndr->relative_end_offset - len;
1846 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1847 align = 1;
1848 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1849 align = 2;
1850 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1851 align = 4;
1852 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1853 align = 8;
1856 pad = ndr_align_size(correct_offset, align);
1857 if (pad) {
1858 correct_offset += pad;
1859 correct_offset -= align;
1862 if (correct_offset < begin_offset) {
1863 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1864 "ndr_push_relative_ptr2_end: "
1865 "correct_offset %u < begin_offset %u",
1866 correct_offset, begin_offset);
1869 if (len > 0) {
1870 uint32_t clear_size = correct_offset - begin_offset;
1872 clear_size = MIN(clear_size, len);
1874 /* now move the marshalled buffer to the end of the main buffer */
1875 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1877 if (clear_size) {
1878 /* and wipe out old buffer within the main buffer */
1879 memset(ndr->data + begin_offset, '\0', clear_size);
1883 /* and set the end offset for the next buffer */
1884 ndr->relative_end_offset = correct_offset;
1886 /* finally write the offset to the main buffer */
1887 ndr->offset = correct_offset;
1888 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1890 /* restore to where we were in the main buffer */
1891 ndr->offset = begin_offset;
1893 return NDR_ERR_SUCCESS;
1897 get the current base for relative pointers for the pull
1899 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1901 return ndr->relative_base_offset;
1905 restore the old base for relative pointers for the pull
1907 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1909 ndr->relative_base_offset = offset;
1913 setup the current base for relative pointers for the pull
1914 called in the NDR_SCALAR stage
1916 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1918 enum ndr_err_code ret;
1919 ndr->relative_base_offset = offset;
1920 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1921 if (ret == NDR_ERR_RANGE) {
1922 return ndr_pull_error(ndr, ret,
1923 "More than %d NDR tokens stored for relative_base_list",
1924 NDR_TOKEN_MAX_LIST_SIZE);
1926 return ret;
1930 setup the current base for relative pointers for the pull
1931 called in the NDR_BUFFERS stage
1933 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1935 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1939 pull a relative object - stage1
1940 called during SCALARS processing
1942 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1944 enum ndr_err_code ret;
1945 rel_offset += ndr->relative_base_offset;
1946 if (rel_offset > ndr->data_size) {
1947 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1948 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1949 rel_offset, ndr->data_size);
1951 ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1952 if (ret == NDR_ERR_RANGE) {
1953 return ndr_pull_error(ndr, ret,
1954 "More than %d NDR tokens stored for relative_list",
1955 NDR_TOKEN_MAX_LIST_SIZE);
1957 return ret;
1961 pull a relative object - stage2
1962 called during BUFFERS processing
1964 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1966 uint32_t rel_offset;
1967 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1968 return ndr_pull_set_offset(ndr, rel_offset);
1971 static const struct {
1972 enum ndr_err_code err;
1973 const char *string;
1974 } ndr_err_code_strings[] = {
1975 { NDR_ERR_SUCCESS, "Success" },
1976 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1977 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1978 { NDR_ERR_OFFSET, "Offset Error" },
1979 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1980 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1981 { NDR_ERR_LENGTH, "Length Error" },
1982 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1983 { NDR_ERR_COMPRESSION, "Compression Error" },
1984 { NDR_ERR_STRING, "String Error" },
1985 { NDR_ERR_VALIDATE, "Validate Error" },
1986 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1987 { NDR_ERR_ALLOC, "Allocation Error" },
1988 { NDR_ERR_RANGE, "Range Error" },
1989 { NDR_ERR_TOKEN, "Token Error" },
1990 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1991 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1992 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1993 { NDR_ERR_NDR64, "NDR64 assertion error" },
1994 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1995 { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" },
1996 { NDR_ERR_UNDERFLOW, "Underflow" },
1997 { 0, NULL }
2000 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
2002 int i;
2003 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
2004 if (ndr_err_code_strings[i].err == ndr_err)
2005 return ndr_err_code_strings[i].string;
2007 return "Unknown error";