s3: libsmb: In cli_list_old_send(), push state->mask into the packet, not just mask.
[Samba.git] / librpc / ndr / ndr.c
blob25765880d8be52c92e948dc59032de7d507ef00b
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 arbitary
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 aligment 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+1 > ndr->alloc_size) {
290 ndr->alloc_size = size+1;
292 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
293 if (!ndr->data) {
294 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
295 ndr->alloc_size);
298 return NDR_ERR_SUCCESS;
301 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
303 va_list ap;
304 char *s = NULL;
305 uint32_t i;
306 int ret;
307 int dbgc_class;
309 va_start(ap, format);
310 ret = vasprintf(&s, format, ap);
311 va_end(ap);
313 if (ret == -1) {
314 return;
317 dbgc_class = *(int *)ndr->private_data;
319 if (ndr->no_newline) {
320 DEBUGADDC(dbgc_class, 1,("%s", s));
321 free(s);
322 return;
325 for (i=0;i<ndr->depth;i++) {
326 DEBUGADDC(dbgc_class, 1,(" "));
329 DEBUGADDC(dbgc_class, 1,("%s\n", s));
330 free(s);
333 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
335 va_list ap;
336 char *s = NULL;
337 uint32_t i;
338 int ret;
340 va_start(ap, format);
341 ret = vasprintf(&s, format, ap);
342 va_end(ap);
344 if (ret == -1) {
345 return;
348 if (ndr->no_newline) {
349 DEBUGADD(1,("%s", s));
350 free(s);
351 return;
354 for (i=0;i<ndr->depth;i++) {
355 DEBUGADD(1,(" "));
358 DEBUGADD(1,("%s\n", s));
359 free(s);
362 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
364 va_list ap;
365 uint32_t i;
367 if (!ndr->no_newline) {
368 for (i=0;i<ndr->depth;i++) {
369 printf(" ");
373 va_start(ap, format);
374 vprintf(format, ap);
375 va_end(ap);
376 if (!ndr->no_newline) {
377 printf("\n");
381 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
383 va_list ap;
384 uint32_t i;
386 if (!ndr->no_newline) {
387 for (i=0;i<ndr->depth;i++) {
388 ndr->private_data = talloc_asprintf_append_buffer(
389 (char *)ndr->private_data, " ");
393 va_start(ap, format);
394 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
395 format, ap);
396 va_end(ap);
397 if (!ndr->no_newline) {
398 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
399 "\n");
404 a useful helper function for printing idl structures via DEBUGC()
406 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
408 struct ndr_print *ndr;
410 DEBUGC(dbgc_class, 1,(" "));
412 ndr = talloc_zero(NULL, struct ndr_print);
413 if (!ndr) return;
414 ndr->private_data = &dbgc_class;
415 ndr->print = ndr_print_debugc_helper;
416 ndr->depth = 1;
417 ndr->flags = 0;
418 #ifdef DEBUG_PASSWORD
419 if (CHECK_DEBUGLVL(100)) {
420 ndr->print_secrets = true;
422 #endif
424 fn(ndr, name, ptr);
425 talloc_free(ndr);
429 a useful helper function for printing idl structures via DEBUG()
431 _PUBLIC_ bool ndr_print_debug(int level,
432 ndr_print_fn_t fn,
433 const char *name,
434 void *ptr,
435 const char *location,
436 const char *function)
438 struct ndr_print *ndr;
440 DEBUGLF(level, (" "), location, function);
442 ndr = talloc_zero(NULL, struct ndr_print);
443 if (!ndr) return false;
444 ndr->print = ndr_print_debug_helper;
445 ndr->depth = 1;
446 ndr->flags = 0;
447 #ifdef DEBUG_PASSWORD
448 if (CHECK_DEBUGLVL(100)) {
449 ndr->print_secrets = true;
451 #endif
453 fn(ndr, name, ptr);
454 talloc_free(ndr);
455 return true;
459 a useful helper function for printing idl unions via DEBUG()
461 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
463 struct ndr_print *ndr;
465 DEBUG(1,(" "));
467 ndr = talloc_zero(NULL, struct ndr_print);
468 if (!ndr) return;
469 ndr->print = ndr_print_debug_helper;
470 ndr->depth = 1;
471 ndr->flags = 0;
472 #ifdef DEBUG_PASSWORD
473 if (CHECK_DEBUGLVL(100)) {
474 ndr->print_secrets = true;
476 #endif
478 ndr_print_set_switch_value(ndr, ptr, level);
479 fn(ndr, name, ptr);
480 talloc_free(ndr);
484 a useful helper function for printing idl function calls via DEBUG()
486 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
488 struct ndr_print *ndr;
490 DEBUG(1,(" "));
492 ndr = talloc_zero(NULL, struct ndr_print);
493 if (!ndr) return;
494 ndr->print = ndr_print_debug_helper;
495 ndr->depth = 1;
496 ndr->flags = 0;
497 #ifdef DEBUG_PASSWORD
498 if (CHECK_DEBUGLVL(100)) {
499 ndr->print_secrets = true;
501 #endif
503 fn(ndr, name, flags, ptr);
504 talloc_free(ndr);
508 a useful helper function for printing idl structures to a string
510 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
512 struct ndr_print *ndr;
513 char *ret = NULL;
515 ndr = talloc_zero(mem_ctx, struct ndr_print);
516 if (!ndr) return NULL;
517 ndr->private_data = talloc_strdup(ndr, "");
518 if (!ndr->private_data) {
519 goto failed;
521 ndr->print = ndr_print_string_helper;
522 ndr->depth = 1;
523 ndr->flags = 0;
525 fn(ndr, name, ptr);
526 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
527 failed:
528 talloc_free(ndr);
529 return ret;
533 a useful helper function for printing idl unions to a string
535 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
537 struct ndr_print *ndr;
538 char *ret = NULL;
540 ndr = talloc_zero(mem_ctx, struct ndr_print);
541 if (!ndr) return NULL;
542 ndr->private_data = talloc_strdup(ndr, "");
543 if (!ndr->private_data) {
544 goto failed;
546 ndr->print = ndr_print_string_helper;
547 ndr->depth = 1;
548 ndr->flags = 0;
549 ndr_print_set_switch_value(ndr, ptr, level);
550 fn(ndr, name, ptr);
551 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
552 failed:
553 talloc_free(ndr);
554 return ret;
558 a useful helper function for printing idl function calls to a string
560 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
561 ndr_print_function_t fn, const char *name,
562 int flags, void *ptr)
564 struct ndr_print *ndr;
565 char *ret = NULL;
567 ndr = talloc_zero(mem_ctx, struct ndr_print);
568 if (!ndr) return NULL;
569 ndr->private_data = talloc_strdup(ndr, "");
570 if (!ndr->private_data) {
571 goto failed;
573 ndr->print = ndr_print_string_helper;
574 ndr->depth = 1;
575 ndr->flags = 0;
576 fn(ndr, name, flags, ptr);
577 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
578 failed:
579 talloc_free(ndr);
580 return ret;
583 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
585 /* the big/little endian flags are inter-dependent */
586 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
587 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
588 (*pflags) &= ~LIBNDR_FLAG_NDR64;
590 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
591 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
592 (*pflags) &= ~LIBNDR_FLAG_NDR64;
594 if (new_flags & LIBNDR_ALIGN_FLAGS) {
595 /* Ensure we only have the passed-in
596 align flag set in the new_flags,
597 remove any old align flag. */
598 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
600 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
601 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
603 (*pflags) |= new_flags;
607 return and possibly log an NDR error
609 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
610 enum ndr_err_code ndr_err,
611 const char *function,
612 const char *location,
613 const char *format, ...)
615 char *s=NULL;
616 va_list ap;
617 int ret;
619 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
620 switch (ndr_err) {
621 case NDR_ERR_BUFSIZE:
622 return NDR_ERR_INCOMPLETE_BUFFER;
623 default:
624 break;
628 va_start(ap, format);
629 ret = vasprintf(&s, format, ap);
630 va_end(ap);
632 if (ret == -1) {
633 return NDR_ERR_ALLOC;
636 D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
637 function,
638 ndr_map_error2string(ndr_err),
640 location);
642 free(s);
644 return ndr_err;
648 return and possibly log an NDR error
650 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
651 enum ndr_err_code ndr_err,
652 const char *function,
653 const char *location,
654 const char *format, ...)
656 char *s=NULL;
657 va_list ap;
658 int ret;
660 va_start(ap, format);
661 ret = vasprintf(&s, format, ap);
662 va_end(ap);
664 if (ret == -1) {
665 return NDR_ERR_ALLOC;
668 D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
669 function,
670 ndr_map_error2string(ndr_err),
672 location);
674 free(s);
676 return ndr_err;
680 handle subcontext buffers, which in midl land are user-marshalled, but
681 we use magic in pidl to make them easier to cope with
683 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
684 struct ndr_pull **_subndr,
685 size_t header_size,
686 ssize_t size_is)
688 struct ndr_pull *subndr;
689 uint32_t r_content_size;
690 bool force_le = false;
691 bool force_be = false;
693 switch (header_size) {
694 case 0: {
695 uint32_t content_size = ndr->data_size - ndr->offset;
696 if (size_is >= 0) {
697 content_size = size_is;
699 r_content_size = content_size;
700 break;
703 case 2: {
704 uint16_t content_size;
705 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
706 if (size_is >= 0 && size_is != content_size) {
707 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
708 (int)size_is, (int)size_is,
709 (int)content_size,
710 (int)content_size);
712 r_content_size = content_size;
713 break;
716 case 4: {
717 uint32_t content_size;
718 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
719 if (size_is >= 0 && size_is != content_size) {
720 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
721 (int)size_is, (int)size_is,
722 (int)content_size,
723 (int)content_size);
725 r_content_size = content_size;
726 break;
728 case 0xFFFFFC01: {
730 * Common Type Header for the Serialization Stream
731 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
733 uint8_t version;
734 uint8_t drep;
735 uint16_t hdrlen;
736 uint32_t filler;
737 uint32_t content_size;
738 uint32_t reserved;
740 /* version */
741 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
743 if (version != 1) {
744 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
745 "Bad subcontext (PULL) Common Type Header version %d != 1",
746 (int)version);
750 * 0x10 little endian
751 * 0x00 big endian
753 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
754 if (drep == 0x10) {
755 force_le = true;
756 } else if (drep == 0x00) {
757 force_be = true;
758 } else {
759 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
760 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
761 (unsigned int)drep);
764 /* length of the "Private Header for Constructed Type" */
765 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
766 if (hdrlen != 8) {
767 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
768 "Bad subcontext (PULL) Common Type Header length %d != 8",
769 (int)hdrlen);
772 /* filler should be ignored */
773 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
776 * Private Header for Constructed Type
778 /* length - will be updated latter */
779 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
780 if (size_is >= 0 && size_is != content_size) {
781 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
782 (int)size_is, (int)content_size);
784 /* the content size must be a multiple of 8 */
785 if ((content_size % 8) != 0) {
786 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
787 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
788 (int)size_is, (int)content_size);
790 r_content_size = content_size;
792 /* reserved */
793 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
794 break;
796 case 0xFFFFFFFF:
798 * a shallow copy like subcontext
799 * useful for DCERPC pipe chunks.
801 subndr = talloc_zero(ndr, struct ndr_pull);
802 NDR_ERR_HAVE_NO_MEMORY(subndr);
804 subndr->flags = ndr->flags;
805 subndr->current_mem_ctx = ndr->current_mem_ctx;
806 subndr->data = ndr->data;
807 subndr->offset = ndr->offset;
808 subndr->data_size = ndr->data_size;
810 *_subndr = subndr;
811 return NDR_ERR_SUCCESS;
813 default:
814 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
815 (int)header_size);
818 NDR_PULL_NEED_BYTES(ndr, r_content_size);
820 subndr = talloc_zero(ndr, struct ndr_pull);
821 NDR_ERR_HAVE_NO_MEMORY(subndr);
822 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
823 subndr->current_mem_ctx = ndr->current_mem_ctx;
825 subndr->data = ndr->data + ndr->offset;
826 subndr->offset = 0;
827 subndr->data_size = r_content_size;
829 if (force_le) {
830 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
831 } else if (force_be) {
832 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
835 *_subndr = subndr;
836 return NDR_ERR_SUCCESS;
839 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
840 struct ndr_pull *subndr,
841 size_t header_size,
842 ssize_t size_is)
844 uint32_t advance;
845 uint32_t highest_ofs;
847 if (header_size == 0xFFFFFFFF) {
848 advance = subndr->offset - ndr->offset;
849 } else if (size_is >= 0) {
850 advance = size_is;
851 } else if (header_size > 0) {
852 advance = subndr->data_size;
853 } else {
854 advance = subndr->offset;
857 if (subndr->offset > ndr->relative_highest_offset) {
858 highest_ofs = subndr->offset;
859 } else {
860 highest_ofs = subndr->relative_highest_offset;
862 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
864 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
866 highest_ofs = advance;
868 if (highest_ofs < advance) {
869 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
870 "not all bytes consumed ofs[%u] advance[%u]",
871 highest_ofs, advance);
874 NDR_CHECK(ndr_pull_advance(ndr, advance));
875 return NDR_ERR_SUCCESS;
878 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
879 struct ndr_push **_subndr,
880 size_t header_size,
881 ssize_t size_is)
883 struct ndr_push *subndr;
885 subndr = ndr_push_init_ctx(ndr);
886 NDR_ERR_HAVE_NO_MEMORY(subndr);
887 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
889 if (size_is > 0) {
890 NDR_CHECK(ndr_push_zero(subndr, size_is));
891 subndr->offset = 0;
892 subndr->relative_end_offset = size_is;
895 *_subndr = subndr;
896 return NDR_ERR_SUCCESS;
900 push a subcontext header
902 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
903 struct ndr_push *subndr,
904 size_t header_size,
905 ssize_t size_is)
907 ssize_t padding_len;
909 if (size_is >= 0) {
910 padding_len = size_is - subndr->offset;
911 if (padding_len < 0) {
912 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
913 (int)subndr->offset, (int)size_is);
915 subndr->offset = size_is;
918 switch (header_size) {
919 case 0:
920 break;
922 case 2:
923 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
924 break;
926 case 4:
927 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
928 break;
930 case 0xFFFFFC01:
932 * Common Type Header for the Serialization Stream
933 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
935 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
936 if (padding_len > 0) {
937 NDR_CHECK(ndr_push_zero(subndr, padding_len));
940 /* version */
941 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
944 * 0x10 little endian
945 * 0x00 big endian
947 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
949 /* length of the "Private Header for Constructed Type" */
950 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
952 /* filler */
953 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
956 * Private Header for Constructed Type
958 /* length - will be updated latter */
959 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
961 /* reserved */
962 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
963 break;
965 default:
966 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
967 (int)header_size);
970 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
971 return NDR_ERR_SUCCESS;
975 struct ndr_token {
976 const void *key;
977 uint32_t value;
981 store a token in the ndr context, for later retrieval
983 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
984 struct ndr_token_list *list,
985 const void *key,
986 uint32_t value)
988 if (list->tokens == NULL) {
989 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
990 if (list->tokens == NULL) {
991 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
993 } else {
994 struct ndr_token *new_tokens = NULL;
995 uint32_t alloc_count = talloc_array_length(list->tokens);
998 * Check every time we have not allocated too many
999 * tokens. This ensures developer sanity when
1000 * debugging the boundary condition
1002 if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
1003 return NDR_ERR_RANGE;
1005 if (list->count == alloc_count) {
1006 unsigned new_alloc;
1008 * Double the list, until we start in chunks
1009 * of 1000
1011 unsigned increment = MIN(list->count, 1000);
1012 new_alloc = alloc_count + increment;
1013 if (new_alloc < alloc_count) {
1014 return NDR_ERR_RANGE;
1016 new_tokens = talloc_realloc(mem_ctx, list->tokens,
1017 struct ndr_token, new_alloc);
1018 NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1019 list->tokens = new_tokens;
1022 list->tokens[list->count].key = key;
1023 list->tokens[list->count].value = value;
1024 list->count++;
1025 return NDR_ERR_SUCCESS;
1029 retrieve a token from a ndr context, using cmp_fn to match the tokens
1031 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
1032 const void *key, uint32_t *v,
1033 comparison_fn_t _cmp_fn,
1034 bool erase)
1036 struct ndr_token *tokens = list->tokens;
1037 unsigned i;
1038 if (_cmp_fn) {
1039 for (i = list->count - 1; i < list->count; i--) {
1040 if (_cmp_fn(tokens[i].key, key) == 0) {
1041 goto found;
1044 } else {
1045 for (i = list->count - 1; i < list->count; i--) {
1046 if (tokens[i].key == key) {
1047 goto found;
1051 return NDR_ERR_TOKEN;
1052 found:
1053 *v = tokens[i].value;
1054 if (erase) {
1055 if (i != list->count - 1) {
1056 tokens[i] = tokens[list->count - 1];
1058 list->count--;
1060 return NDR_ERR_SUCCESS;
1064 retrieve a token from a ndr context
1066 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1067 const void *key, uint32_t *v)
1069 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1073 peek at but don't removed a token from a ndr context
1075 _PUBLIC_ enum ndr_err_code ndr_token_peek(struct ndr_token_list *list,
1076 const void *key, uint32_t *v)
1078 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, false);
1082 pull an array size field and add it to the array_size_list token list
1084 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1086 enum ndr_err_code ret;
1087 uint32_t size;
1088 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1089 ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1090 if (ret == NDR_ERR_RANGE) {
1091 return ndr_pull_error(ndr, ret,
1092 "More than %d NDR tokens stored for array_size",
1093 NDR_TOKEN_MAX_LIST_SIZE);
1095 return ret;
1099 get the stored array size field
1101 _PUBLIC_ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1103 return ndr_token_peek(&ndr->array_size_list, p, size);
1107 get and remove from the stored list the stored array size field
1109 _PUBLIC_ enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1111 return ndr_token_retrieve(&ndr->array_size_list, p, size);
1115 * check the stored array size field and remove from the stored list
1116 * (the array_size NDR token list). We try to remove when possible to
1117 * avoid the list growing towards the bounds check
1119 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1121 uint32_t stored;
1122 NDR_CHECK(ndr_steal_array_size(ndr, p, &stored));
1123 if (stored != size) {
1124 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1125 "Bad array size - got %u expected %u\n",
1126 stored, size);
1128 return NDR_ERR_SUCCESS;
1132 * check the stored array size field (leaving it on the array_size
1133 * token list)
1135 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1137 uint32_t stored;
1138 NDR_CHECK(ndr_get_array_size(ndr, p, &stored));
1139 if (stored != size) {
1140 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1141 "Bad array size - got %u expected %u\n",
1142 stored, size);
1144 return NDR_ERR_SUCCESS;
1148 pull an array length field and add it to the array_length_list token list
1150 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1152 enum ndr_err_code ret;
1153 uint32_t length, offset;
1154 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1155 if (offset != 0) {
1156 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1157 "non-zero array offset %u\n", offset);
1159 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1160 ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1161 if (ret == NDR_ERR_RANGE) {
1162 return ndr_pull_error(ndr, ret,
1163 "More than %d NDR tokens stored for array_length_list",
1164 NDR_TOKEN_MAX_LIST_SIZE);
1166 return ret;
1170 get the stored array length field
1172 _PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1174 return ndr_token_peek(&ndr->array_length_list, p, length);
1178 * check the stored array length field and remove from the stored list
1179 * (the array_size NDR token list). We try to remove when possible to
1180 * avoid the list growing towards the bounds check
1182 _PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1184 return ndr_token_retrieve(&ndr->array_length_list, p, length);
1187 check the stored array length field, removing it from the list
1189 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
1191 uint32_t stored;
1192 NDR_CHECK(ndr_steal_array_length(ndr, p, &stored));
1193 if (stored != length) {
1194 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1195 "Bad array length - got %u expected %u\n",
1196 stored, length);
1198 return NDR_ERR_SUCCESS;
1201 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1203 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1204 int64_t tmp = 0 - (int64_t)count;
1205 uint64_t ncount = tmp;
1207 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1210 return NDR_ERR_SUCCESS;
1213 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1215 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1216 int64_t tmp = 0 - (int64_t)count;
1217 uint64_t ncount1 = tmp;
1218 uint64_t ncount2;
1220 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1221 if (ncount1 == ncount2) {
1222 return NDR_ERR_SUCCESS;
1225 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1226 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1227 (unsigned long long)ncount2,
1228 (unsigned long long)ncount1,
1229 (unsigned long)count);
1232 return NDR_ERR_SUCCESS;
1236 store a switch value
1238 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1240 enum ndr_err_code ret =
1241 ndr_token_store(ndr, &ndr->switch_list, p, val);
1242 if (ret == NDR_ERR_RANGE) {
1243 return ndr_push_error(ndr, ret,
1244 "More than %d NDR tokens stored for switch_list",
1245 NDR_TOKEN_MAX_LIST_SIZE);
1247 return ret;
1250 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1253 enum ndr_err_code ret =
1254 ndr_token_store(ndr, &ndr->switch_list, p, val);
1255 if (ret == NDR_ERR_RANGE) {
1256 return ndr_pull_error(ndr, ret,
1257 "More than %d NDR tokens stored for switch_list",
1258 NDR_TOKEN_MAX_LIST_SIZE);
1260 return ret;
1263 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1265 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1268 /* retrieve a switch value (for push) and remove it from the list */
1269 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1270 const void *p,
1271 uint32_t *v)
1273 return ndr_token_retrieve(&ndr->switch_list, p, v);
1276 /* retrieve a switch value and remove it from the list */
1277 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1279 enum ndr_err_code status;
1280 uint32_t v;
1282 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1283 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1284 return 0;
1287 return v;
1290 /* retrieve a switch value and remove it from the list */
1291 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1292 const void *p,
1293 uint32_t *v)
1295 return ndr_token_retrieve(&ndr->switch_list, p, v);
1299 pull a struct from a blob using NDR
1301 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1302 ndr_pull_flags_fn_t fn)
1304 struct ndr_pull *ndr;
1305 ndr = ndr_pull_init_blob(blob, mem_ctx);
1306 NDR_ERR_HAVE_NO_MEMORY(ndr);
1307 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1308 talloc_free(ndr);
1309 return NDR_ERR_SUCCESS;
1313 pull a struct from a blob using NDR - failing if all bytes are not consumed
1315 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1316 void *p, ndr_pull_flags_fn_t fn)
1318 struct ndr_pull *ndr;
1319 uint32_t highest_ofs;
1320 ndr = ndr_pull_init_blob(blob, mem_ctx);
1321 NDR_ERR_HAVE_NO_MEMORY(ndr);
1322 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1323 if (ndr->offset > ndr->relative_highest_offset) {
1324 highest_ofs = ndr->offset;
1325 } else {
1326 highest_ofs = ndr->relative_highest_offset;
1328 if (highest_ofs < ndr->data_size) {
1329 enum ndr_err_code ret;
1330 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1331 "not all bytes consumed ofs[%u] size[%u]",
1332 highest_ofs, ndr->data_size);
1333 talloc_free(ndr);
1334 return ret;
1336 talloc_free(ndr);
1337 return NDR_ERR_SUCCESS;
1341 pull a struct from a blob using NDR - failing if all bytes are not consumed
1343 This only works for structures with NO allocated memory, like
1344 objectSID and GUID. This helps because we parse these a lot.
1346 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1347 void *p, ndr_pull_flags_fn_t fn)
1350 * We init this structure on the stack here, to avoid a
1351 * talloc() as otherwise this call to the fn() is assured not
1352 * to be doing any allocation, eg SIDs and GUIDs.
1354 * This allows us to keep the safety of the PIDL-generated
1355 * code without the talloc() overhead.
1357 struct ndr_pull ndr = {
1358 .data = blob->data,
1359 .data_size = blob->length,
1360 .current_mem_ctx = (void *)-1
1362 uint32_t highest_ofs;
1363 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1364 highest_ofs = MAX(ndr.offset, ndr.relative_highest_offset);
1365 if (highest_ofs < ndr.data_size) {
1366 enum ndr_err_code ret;
1367 ret = ndr_pull_error(
1368 &ndr,
1369 NDR_ERR_UNREAD_BYTES,
1370 "not all bytes consumed ofs[%"PRIu32"] "
1371 "size[%"PRIu32"]",
1372 highest_ofs,
1373 ndr.data_size);
1374 return ret;
1376 return NDR_ERR_SUCCESS;
1380 pull a union from a blob using NDR, given the union discriminator
1382 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1383 void *p,
1384 uint32_t level, ndr_pull_flags_fn_t fn)
1386 struct ndr_pull *ndr;
1387 ndr = ndr_pull_init_blob(blob, mem_ctx);
1388 NDR_ERR_HAVE_NO_MEMORY(ndr);
1389 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1390 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1391 talloc_free(ndr);
1392 return NDR_ERR_SUCCESS;
1396 pull a union from a blob using NDR, given the union discriminator,
1397 failing if all bytes are not consumed
1399 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1400 void *p,
1401 uint32_t level, ndr_pull_flags_fn_t fn)
1403 struct ndr_pull *ndr;
1404 uint32_t highest_ofs;
1405 ndr = ndr_pull_init_blob(blob, mem_ctx);
1406 NDR_ERR_HAVE_NO_MEMORY(ndr);
1407 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1408 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1409 if (ndr->offset > ndr->relative_highest_offset) {
1410 highest_ofs = ndr->offset;
1411 } else {
1412 highest_ofs = ndr->relative_highest_offset;
1414 if (highest_ofs < ndr->data_size) {
1415 enum ndr_err_code ret;
1416 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1417 "not all bytes consumed ofs[%u] size[%u]",
1418 highest_ofs, ndr->data_size);
1419 talloc_free(ndr);
1420 return ret;
1422 talloc_free(ndr);
1423 return NDR_ERR_SUCCESS;
1427 push a struct to a blob using NDR
1429 _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)
1431 struct ndr_push *ndr;
1432 ndr = ndr_push_init_ctx(mem_ctx);
1433 NDR_ERR_HAVE_NO_MEMORY(ndr);
1435 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1437 *blob = ndr_push_blob(ndr);
1438 talloc_steal(mem_ctx, blob->data);
1439 talloc_free(ndr);
1441 return NDR_ERR_SUCCESS;
1445 push a struct into a provided blob using NDR.
1447 We error because we want to have the performance issue (extra
1448 talloc() calls) show up as an error, not just slower code. This is
1449 used for things like GUIDs, which we expect to be a fixed size, and
1450 SIDs that we can pre-calculate the size for.
1452 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1453 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1455 struct ndr_push ndr = {
1456 .data = blob->data,
1457 .alloc_size = blob->length,
1458 .fixed_buf_size = true
1461 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1463 if (ndr.offset != blob->length) {
1464 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1465 "buffer was either to large or small "
1466 "ofs[%u] size[%zu]",
1467 ndr.offset, blob->length);
1470 return NDR_ERR_SUCCESS;
1474 push a union to a blob using NDR
1476 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1477 uint32_t level, ndr_push_flags_fn_t fn)
1479 struct ndr_push *ndr;
1480 ndr = ndr_push_init_ctx(mem_ctx);
1481 NDR_ERR_HAVE_NO_MEMORY(ndr);
1483 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1484 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1486 *blob = ndr_push_blob(ndr);
1487 talloc_steal(mem_ctx, blob->data);
1488 talloc_free(ndr);
1490 return NDR_ERR_SUCCESS;
1494 generic ndr_size_*() handler for structures
1496 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1498 struct ndr_push *ndr;
1499 enum ndr_err_code status;
1500 size_t ret;
1502 /* avoid recursion */
1503 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1505 /* Avoid following a NULL pointer */
1506 if (p == NULL) {
1507 return 0;
1510 ndr = ndr_push_init_ctx(NULL);
1511 if (!ndr) return 0;
1512 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1513 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1514 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1515 talloc_free(ndr);
1516 return 0;
1518 ret = ndr->offset;
1519 talloc_free(ndr);
1520 return ret;
1524 generic ndr_size_*() handler for unions
1526 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1528 struct ndr_push *ndr;
1529 enum ndr_err_code status;
1530 size_t ret;
1532 /* avoid recursion */
1533 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1535 /* Avoid following a NULL pointer */
1536 if (p == NULL) {
1537 return 0;
1540 ndr = ndr_push_init_ctx(NULL);
1541 if (!ndr) return 0;
1542 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1544 status = ndr_push_set_switch_value(ndr, p, level);
1545 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1546 talloc_free(ndr);
1547 return 0;
1549 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1550 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1551 talloc_free(ndr);
1552 return 0;
1554 ret = ndr->offset;
1555 talloc_free(ndr);
1556 return ret;
1560 get the current base for relative pointers for the push
1562 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1564 return ndr->relative_base_offset;
1568 restore the old base for relative pointers for the push
1570 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1572 ndr->relative_base_offset = offset;
1576 setup the current base for relative pointers for the push
1577 called in the NDR_SCALAR stage
1579 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1581 enum ndr_err_code ret;
1582 ndr->relative_base_offset = offset;
1583 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1584 if (ret == NDR_ERR_RANGE) {
1585 return ndr_push_error(ndr, ret,
1586 "More than %d NDR tokens stored for relative_base_list",
1587 NDR_TOKEN_MAX_LIST_SIZE);
1589 return ret;
1593 setup the current base for relative pointers for the push
1594 called in the NDR_BUFFERS stage
1596 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1598 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1602 push a relative object - stage1
1603 this is called during SCALARS processing
1605 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1607 enum ndr_err_code ret;
1608 if (p == NULL) {
1609 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1610 return NDR_ERR_SUCCESS;
1612 NDR_CHECK(ndr_push_align(ndr, 4));
1613 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1614 if (ret == NDR_ERR_RANGE) {
1615 return ndr_push_error(ndr, ret,
1616 "More than %d NDR tokens stored for relative_list",
1617 NDR_TOKEN_MAX_LIST_SIZE);
1619 NDR_CHECK(ret);
1620 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1624 push a short relative object - stage1
1625 this is called during SCALARS processing
1627 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1629 enum ndr_err_code ret;
1630 if (p == NULL) {
1631 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1632 return NDR_ERR_SUCCESS;
1634 NDR_CHECK(ndr_push_align(ndr, 2));
1635 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1636 if (ret == NDR_ERR_RANGE) {
1637 return ndr_push_error(ndr, ret,
1638 "More than %d NDR tokens stored for relative_list",
1639 NDR_TOKEN_MAX_LIST_SIZE);
1641 NDR_CHECK(ret);
1642 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1645 push a relative object - stage2
1646 this is called during buffers processing
1648 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1650 uint32_t save_offset;
1651 uint32_t ptr_offset = 0xFFFFFFFF;
1652 if (p == NULL) {
1653 return NDR_ERR_SUCCESS;
1655 save_offset = ndr->offset;
1656 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1657 if (ptr_offset > ndr->offset) {
1658 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1659 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1660 ptr_offset, ndr->offset);
1662 ndr->offset = ptr_offset;
1663 if (save_offset < ndr->relative_base_offset) {
1664 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1665 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1666 save_offset, ndr->relative_base_offset);
1668 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1669 ndr->offset = save_offset;
1670 return NDR_ERR_SUCCESS;
1673 push a short relative object - stage2
1674 this is called during buffers processing
1676 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1678 uint32_t save_offset;
1679 uint32_t ptr_offset = 0xFFFF;
1680 uint32_t relative_offset;
1681 size_t pad;
1682 size_t align = 1;
1684 if (p == NULL) {
1685 return NDR_ERR_SUCCESS;
1688 if (ndr->offset < ndr->relative_base_offset) {
1689 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1690 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1691 ndr->offset, ndr->relative_base_offset);
1694 relative_offset = ndr->offset - ndr->relative_base_offset;
1696 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1697 align = 1;
1698 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1699 align = 2;
1700 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1701 align = 4;
1702 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1703 align = 8;
1706 pad = ndr_align_size(relative_offset, align);
1707 if (pad != 0) {
1708 NDR_CHECK(ndr_push_zero(ndr, pad));
1711 relative_offset = ndr->offset - ndr->relative_base_offset;
1712 if (relative_offset > UINT16_MAX) {
1713 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1714 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1715 relative_offset);
1718 save_offset = ndr->offset;
1719 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1720 if (ptr_offset > ndr->offset) {
1721 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1722 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1723 ptr_offset, ndr->offset);
1725 ndr->offset = ptr_offset;
1726 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1727 ndr->offset = save_offset;
1728 return NDR_ERR_SUCCESS;
1732 push a relative object - stage2 start
1733 this is called during buffers processing
1735 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1737 enum ndr_err_code ret;
1738 if (p == NULL) {
1739 return NDR_ERR_SUCCESS;
1741 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1742 uint32_t relative_offset;
1743 size_t pad;
1744 size_t align = 1;
1746 if (ndr->offset < ndr->relative_base_offset) {
1747 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1748 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1749 ndr->offset, ndr->relative_base_offset);
1752 relative_offset = ndr->offset - ndr->relative_base_offset;
1754 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1755 align = 1;
1756 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1757 align = 2;
1758 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1759 align = 4;
1760 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1761 align = 8;
1764 pad = ndr_align_size(relative_offset, align);
1765 if (pad) {
1766 NDR_CHECK(ndr_push_zero(ndr, pad));
1769 return ndr_push_relative_ptr2(ndr, p);
1771 if (ndr->relative_end_offset == -1) {
1772 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1773 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1774 ndr->relative_end_offset);
1776 ret = ndr_token_store(ndr,
1777 &ndr->relative_begin_list,
1779 ndr->offset);
1780 if (ret == NDR_ERR_RANGE) {
1781 return ndr_push_error(ndr, ret,
1782 "More than %d NDR tokens stored for array_size",
1783 NDR_TOKEN_MAX_LIST_SIZE);
1785 return ret;
1789 push a relative object - stage2 end
1790 this is called during buffers processing
1792 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1794 uint32_t begin_offset = 0xFFFFFFFF;
1795 ssize_t len;
1796 uint32_t correct_offset = 0;
1797 uint32_t align = 1;
1798 uint32_t pad = 0;
1800 if (p == NULL) {
1801 return NDR_ERR_SUCCESS;
1804 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1805 return NDR_ERR_SUCCESS;
1808 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1809 /* better say more than calculation a too small buffer */
1810 NDR_PUSH_ALIGN(ndr, 8);
1811 return NDR_ERR_SUCCESS;
1814 if (ndr->relative_end_offset < ndr->offset) {
1815 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1816 "ndr_push_relative_ptr2_end:"
1817 "relative_end_offset %u < offset %u",
1818 ndr->relative_end_offset, ndr->offset);
1821 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1823 /* we have marshalled a buffer, see how long it was */
1824 len = ndr->offset - begin_offset;
1826 if (len < 0) {
1827 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1828 "ndr_push_relative_ptr2_end:"
1829 "offset %u - begin_offset %u < 0",
1830 ndr->offset, begin_offset);
1833 if (ndr->relative_end_offset < len) {
1834 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1835 "ndr_push_relative_ptr2_end:"
1836 "relative_end_offset %u < len %lld",
1837 ndr->offset, (long long)len);
1840 /* the reversed offset is at the end of the main buffer */
1841 correct_offset = ndr->relative_end_offset - len;
1843 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1844 align = 1;
1845 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1846 align = 2;
1847 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1848 align = 4;
1849 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1850 align = 8;
1853 pad = ndr_align_size(correct_offset, align);
1854 if (pad) {
1855 correct_offset += pad;
1856 correct_offset -= align;
1859 if (correct_offset < begin_offset) {
1860 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1861 "ndr_push_relative_ptr2_end: "
1862 "correct_offset %u < begin_offset %u",
1863 correct_offset, begin_offset);
1866 if (len > 0) {
1867 uint32_t clear_size = correct_offset - begin_offset;
1869 clear_size = MIN(clear_size, len);
1871 /* now move the marshalled buffer to the end of the main buffer */
1872 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1874 if (clear_size) {
1875 /* and wipe out old buffer within the main buffer */
1876 memset(ndr->data + begin_offset, '\0', clear_size);
1880 /* and set the end offset for the next buffer */
1881 ndr->relative_end_offset = correct_offset;
1883 /* finally write the offset to the main buffer */
1884 ndr->offset = correct_offset;
1885 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1887 /* restore to where we were in the main buffer */
1888 ndr->offset = begin_offset;
1890 return NDR_ERR_SUCCESS;
1894 get the current base for relative pointers for the pull
1896 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1898 return ndr->relative_base_offset;
1902 restore the old base for relative pointers for the pull
1904 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1906 ndr->relative_base_offset = offset;
1910 setup the current base for relative pointers for the pull
1911 called in the NDR_SCALAR stage
1913 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1915 enum ndr_err_code ret;
1916 ndr->relative_base_offset = offset;
1917 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1918 if (ret == NDR_ERR_RANGE) {
1919 return ndr_pull_error(ndr, ret,
1920 "More than %d NDR tokens stored for relative_base_list",
1921 NDR_TOKEN_MAX_LIST_SIZE);
1923 return ret;
1927 setup the current base for relative pointers for the pull
1928 called in the NDR_BUFFERS stage
1930 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1932 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1936 pull a relative object - stage1
1937 called during SCALARS processing
1939 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1941 enum ndr_err_code ret;
1942 rel_offset += ndr->relative_base_offset;
1943 if (rel_offset > ndr->data_size) {
1944 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1945 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1946 rel_offset, ndr->data_size);
1948 ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1949 if (ret == NDR_ERR_RANGE) {
1950 return ndr_pull_error(ndr, ret,
1951 "More than %d NDR tokens stored for relative_list",
1952 NDR_TOKEN_MAX_LIST_SIZE);
1954 return ret;
1958 pull a relative object - stage2
1959 called during BUFFERS processing
1961 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1963 uint32_t rel_offset;
1964 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1965 return ndr_pull_set_offset(ndr, rel_offset);
1968 static const struct {
1969 enum ndr_err_code err;
1970 const char *string;
1971 } ndr_err_code_strings[] = {
1972 { NDR_ERR_SUCCESS, "Success" },
1973 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1974 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1975 { NDR_ERR_OFFSET, "Offset Error" },
1976 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1977 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1978 { NDR_ERR_LENGTH, "Length Error" },
1979 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1980 { NDR_ERR_COMPRESSION, "Compression Error" },
1981 { NDR_ERR_STRING, "String Error" },
1982 { NDR_ERR_VALIDATE, "Validate Error" },
1983 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1984 { NDR_ERR_ALLOC, "Allocation Error" },
1985 { NDR_ERR_RANGE, "Range Error" },
1986 { NDR_ERR_TOKEN, "Token Error" },
1987 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1988 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1989 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1990 { NDR_ERR_NDR64, "NDR64 assertion error" },
1991 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1992 { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" },
1993 { NDR_ERR_UNDERFLOW, "Underflow" },
1994 { 0, NULL }
1997 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1999 int i;
2000 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
2001 if (ndr_err_code_strings[i].err == ndr_err)
2002 return ndr_err_code_strings[i].string;
2004 return "Unknown error";