VERSION: Disable GIT_SNAPSHOTS for the 4.6.0 release.
[Samba.git] / librpc / ndr / ndr.c
blob22c4d763d09f719b9c8fedd440ad85e2b0f594c4
1 /*
2 Unix SMB/CIFS implementation.
4 libndr interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2005-2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 this provides the core routines for NDR parsing functions
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27 of NDR encoding rules
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
34 #define NDR_BASE_MARSHALL_SIZE 1024
36 /* this guid indicates NDR encoding in a protocol tower */
37 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
38 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
42 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
43 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
47 const struct ndr_syntax_id ndr_syntax_id_null = {
48 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
53 work out the number of bytes needed to align on a n byte boundary
55 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
57 if ((offset & (n-1)) == 0) return 0;
58 return n - (offset & (n-1));
62 initialise a ndr parse structure from a data blob
64 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
66 struct ndr_pull *ndr;
68 ndr = talloc_zero(mem_ctx, struct ndr_pull);
69 if (!ndr) return NULL;
70 ndr->current_mem_ctx = mem_ctx;
72 ndr->data = blob->data;
73 ndr->data_size = blob->length;
75 return ndr;
78 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
80 enum ndr_err_code ndr_err;
81 DATA_BLOB b;
82 uint32_t append = 0;
83 bool ok;
85 if (blob->length == 0) {
86 return NDR_ERR_SUCCESS;
89 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
90 if (ndr_err == NDR_ERR_TOKEN) {
91 append = 0;
92 ndr_err = NDR_ERR_SUCCESS;
94 NDR_CHECK(ndr_err);
96 if (ndr->data_size == 0) {
97 ndr->data = NULL;
98 append = UINT32_MAX;
101 if (append == UINT32_MAX) {
103 * append == UINT32_MAX means that
104 * ndr->data is either NULL or a valid
105 * talloc child of ndr, which means
106 * we can use data_blob_append() without
107 * data_blob_talloc() of the existing callers data
109 b = data_blob_const(ndr->data, ndr->data_size);
110 } else {
111 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
112 if (b.data == NULL) {
113 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
117 ok = data_blob_append(ndr, &b, blob->data, blob->length);
118 if (!ok) {
119 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
122 ndr->data = b.data;
123 ndr->data_size = b.length;
125 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
128 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
130 uint32_t skip = 0;
131 uint32_t append = 0;
133 if (ndr->relative_base_offset != 0) {
134 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
135 "%s", __location__);
137 if (ndr->relative_highest_offset != 0) {
138 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
139 "%s", __location__);
141 if (ndr->relative_list != NULL) {
142 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
143 "%s", __location__);
145 if (ndr->relative_base_list != NULL) {
146 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
147 "%s", __location__);
151 * we need to keep up to 7 bytes
152 * in order to get the aligment right.
154 skip = ndr->offset & 0xFFFFFFF8;
156 if (skip == 0) {
157 return NDR_ERR_SUCCESS;
160 ndr->offset -= skip;
161 ndr->data_size -= skip;
163 append = ndr_token_peek(&ndr->array_size_list, ndr);
164 if (append != UINT32_MAX) {
166 * here we assume, that ndr->data is not a
167 * talloc child of ndr.
169 ndr->data += skip;
170 return NDR_ERR_SUCCESS;
173 memmove(ndr->data, ndr->data + skip, ndr->data_size);
175 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
176 if (ndr->data_size != 0 && ndr->data == NULL) {
177 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
180 return NDR_ERR_SUCCESS;
184 advance by 'size' bytes
186 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
188 ndr->offset += size;
189 if (ndr->offset > ndr->data_size) {
190 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
191 "ndr_pull_advance by %u failed",
192 size);
194 return NDR_ERR_SUCCESS;
198 set the parse offset to 'ofs'
200 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
202 ndr->offset = ofs;
203 if (ndr->offset > ndr->data_size) {
204 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
205 "ndr_pull_set_offset %u failed",
206 ofs);
208 return NDR_ERR_SUCCESS;
211 /* create a ndr_push structure, ready for some marshalling */
212 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
214 struct ndr_push *ndr;
216 ndr = talloc_zero(mem_ctx, struct ndr_push);
217 if (!ndr) {
218 return NULL;
221 ndr->flags = 0;
222 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
223 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
224 if (!ndr->data) {
225 talloc_free(ndr);
226 return NULL;
229 return ndr;
232 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
233 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
235 DATA_BLOB blob;
236 blob = data_blob_const(ndr->data, ndr->offset);
237 if (ndr->alloc_size > ndr->offset) {
238 ndr->data[ndr->offset] = 0;
240 return blob;
245 expand the available space in the buffer to ndr->offset + extra_size
247 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
249 uint32_t size = extra_size + ndr->offset;
251 if (size < ndr->offset) {
252 /* extra_size overflowed the offset */
253 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
254 size);
257 if (ndr->fixed_buf_size) {
258 if (ndr->alloc_size >= size) {
259 return NDR_ERR_SUCCESS;
261 return ndr_push_error(ndr,
262 NDR_ERR_BUFSIZE,
263 "Overflow of fixed buffer in "
264 "push_expand to %u",
265 size);
268 if (ndr->alloc_size > size) {
269 return NDR_ERR_SUCCESS;
272 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
273 if (size+1 > ndr->alloc_size) {
274 ndr->alloc_size = size+1;
276 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
277 if (!ndr->data) {
278 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
279 ndr->alloc_size);
282 return NDR_ERR_SUCCESS;
285 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
287 va_list ap;
288 char *s = NULL;
289 uint32_t i;
290 int ret;
291 int dbgc_class;
293 va_start(ap, format);
294 ret = vasprintf(&s, format, ap);
295 va_end(ap);
297 if (ret == -1) {
298 return;
301 dbgc_class = *(int *)ndr->private_data;
303 if (ndr->no_newline) {
304 DEBUGADDC(dbgc_class, 1,("%s", s));
305 free(s);
306 return;
309 for (i=0;i<ndr->depth;i++) {
310 DEBUGADDC(dbgc_class, 1,(" "));
313 DEBUGADDC(dbgc_class, 1,("%s\n", s));
314 free(s);
317 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
319 va_list ap;
320 char *s = NULL;
321 uint32_t i;
322 int ret;
324 va_start(ap, format);
325 ret = vasprintf(&s, format, ap);
326 va_end(ap);
328 if (ret == -1) {
329 return;
332 if (ndr->no_newline) {
333 DEBUGADD(1,("%s", s));
334 free(s);
335 return;
338 for (i=0;i<ndr->depth;i++) {
339 DEBUGADD(1,(" "));
342 DEBUGADD(1,("%s\n", s));
343 free(s);
346 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
348 va_list ap;
349 uint32_t i;
351 if (!ndr->no_newline) {
352 for (i=0;i<ndr->depth;i++) {
353 printf(" ");
357 va_start(ap, format);
358 vprintf(format, ap);
359 va_end(ap);
360 if (!ndr->no_newline) {
361 printf("\n");
365 _PUBLIC_ void ndr_print_string_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 ndr->private_data = talloc_asprintf_append_buffer(
373 (char *)ndr->private_data, " ");
377 va_start(ap, format);
378 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
379 format, ap);
380 va_end(ap);
381 if (!ndr->no_newline) {
382 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
383 "\n");
388 a useful helper function for printing idl structures via DEBUGC()
390 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
392 struct ndr_print *ndr;
394 DEBUGC(dbgc_class, 1,(" "));
396 ndr = talloc_zero(NULL, struct ndr_print);
397 if (!ndr) return;
398 ndr->private_data = &dbgc_class;
399 ndr->print = ndr_print_debugc_helper;
400 ndr->depth = 1;
401 ndr->flags = 0;
402 fn(ndr, name, ptr);
403 talloc_free(ndr);
407 a useful helper function for printing idl structures via DEBUG()
409 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
411 struct ndr_print *ndr;
413 DEBUG(1,(" "));
415 ndr = talloc_zero(NULL, struct ndr_print);
416 if (!ndr) return;
417 ndr->print = ndr_print_debug_helper;
418 ndr->depth = 1;
419 ndr->flags = 0;
420 fn(ndr, name, ptr);
421 talloc_free(ndr);
425 a useful helper function for printing idl unions via DEBUG()
427 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
429 struct ndr_print *ndr;
431 DEBUG(1,(" "));
433 ndr = talloc_zero(NULL, struct ndr_print);
434 if (!ndr) return;
435 ndr->print = ndr_print_debug_helper;
436 ndr->depth = 1;
437 ndr->flags = 0;
438 ndr_print_set_switch_value(ndr, ptr, level);
439 fn(ndr, name, ptr);
440 talloc_free(ndr);
444 a useful helper function for printing idl function calls via DEBUG()
446 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
448 struct ndr_print *ndr;
450 DEBUG(1,(" "));
452 ndr = talloc_zero(NULL, struct ndr_print);
453 if (!ndr) return;
454 ndr->print = ndr_print_debug_helper;
455 ndr->depth = 1;
456 ndr->flags = 0;
458 fn(ndr, name, flags, ptr);
459 talloc_free(ndr);
463 a useful helper function for printing idl structures to a string
465 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
467 struct ndr_print *ndr;
468 char *ret = NULL;
470 ndr = talloc_zero(mem_ctx, struct ndr_print);
471 if (!ndr) return NULL;
472 ndr->private_data = talloc_strdup(ndr, "");
473 if (!ndr->private_data) {
474 goto failed;
476 ndr->print = ndr_print_string_helper;
477 ndr->depth = 1;
478 ndr->flags = 0;
480 fn(ndr, name, ptr);
481 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
482 failed:
483 talloc_free(ndr);
484 return ret;
488 a useful helper function for printing idl unions to a string
490 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
492 struct ndr_print *ndr;
493 char *ret = NULL;
495 ndr = talloc_zero(mem_ctx, struct ndr_print);
496 if (!ndr) return NULL;
497 ndr->private_data = talloc_strdup(ndr, "");
498 if (!ndr->private_data) {
499 goto failed;
501 ndr->print = ndr_print_string_helper;
502 ndr->depth = 1;
503 ndr->flags = 0;
504 ndr_print_set_switch_value(ndr, ptr, level);
505 fn(ndr, name, ptr);
506 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
507 failed:
508 talloc_free(ndr);
509 return ret;
513 a useful helper function for printing idl function calls to a string
515 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
516 ndr_print_function_t fn, const char *name,
517 int flags, void *ptr)
519 struct ndr_print *ndr;
520 char *ret = NULL;
522 ndr = talloc_zero(mem_ctx, struct ndr_print);
523 if (!ndr) return NULL;
524 ndr->private_data = talloc_strdup(ndr, "");
525 if (!ndr->private_data) {
526 goto failed;
528 ndr->print = ndr_print_string_helper;
529 ndr->depth = 1;
530 ndr->flags = 0;
531 fn(ndr, name, flags, ptr);
532 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
533 failed:
534 talloc_free(ndr);
535 return ret;
538 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
540 /* the big/little endian flags are inter-dependent */
541 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
542 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
543 (*pflags) &= ~LIBNDR_FLAG_NDR64;
545 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
546 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
547 (*pflags) &= ~LIBNDR_FLAG_NDR64;
549 if (new_flags & LIBNDR_ALIGN_FLAGS) {
550 /* Ensure we only have the passed-in
551 align flag set in the new_flags,
552 remove any old align flag. */
553 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
555 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
556 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
558 (*pflags) |= new_flags;
562 return and possibly log an NDR error
564 _PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
565 enum ndr_err_code ndr_err,
566 const char *format, ...)
568 char *s=NULL;
569 va_list ap;
570 int ret;
572 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
573 switch (ndr_err) {
574 case NDR_ERR_BUFSIZE:
575 return NDR_ERR_INCOMPLETE_BUFFER;
576 default:
577 break;
581 va_start(ap, format);
582 ret = vasprintf(&s, format, ap);
583 va_end(ap);
585 if (ret == -1) {
586 return NDR_ERR_ALLOC;
589 DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
591 free(s);
593 return ndr_err;
597 return and possibly log an NDR error
599 _PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
600 enum ndr_err_code ndr_err,
601 const char *format, ...)
603 char *s=NULL;
604 va_list ap;
605 int ret;
607 va_start(ap, format);
608 ret = vasprintf(&s, format, ap);
609 va_end(ap);
611 if (ret == -1) {
612 return NDR_ERR_ALLOC;
615 DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
617 free(s);
619 return ndr_err;
623 handle subcontext buffers, which in midl land are user-marshalled, but
624 we use magic in pidl to make them easier to cope with
626 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
627 struct ndr_pull **_subndr,
628 size_t header_size,
629 ssize_t size_is)
631 struct ndr_pull *subndr;
632 uint32_t r_content_size;
633 bool force_le = false;
634 bool force_be = false;
636 switch (header_size) {
637 case 0: {
638 uint32_t content_size = ndr->data_size - ndr->offset;
639 if (size_is >= 0) {
640 content_size = size_is;
642 r_content_size = content_size;
643 break;
646 case 2: {
647 uint16_t content_size;
648 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
649 if (size_is >= 0 && size_is != content_size) {
650 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
651 (int)size_is, (int)size_is,
652 (int)content_size,
653 (int)content_size);
655 r_content_size = content_size;
656 break;
659 case 4: {
660 uint32_t content_size;
661 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
662 if (size_is >= 0 && size_is != content_size) {
663 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
664 (int)size_is, (int)size_is,
665 (int)content_size,
666 (int)content_size);
668 r_content_size = content_size;
669 break;
671 case 0xFFFFFC01: {
673 * Common Type Header for the Serialization Stream
674 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
676 uint8_t version;
677 uint8_t drep;
678 uint16_t hdrlen;
679 uint32_t filler;
680 uint32_t content_size;
681 uint32_t reserved;
683 /* version */
684 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
686 if (version != 1) {
687 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
688 "Bad subcontext (PULL) Common Type Header version %d != 1",
689 (int)version);
693 * 0x10 little endian
694 * 0x00 big endian
696 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
697 if (drep == 0x10) {
698 force_le = true;
699 } else if (drep == 0x00) {
700 force_be = true;
701 } else {
702 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
703 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
704 (unsigned int)drep);
707 /* length of the "Private Header for Constructed Type" */
708 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
709 if (hdrlen != 8) {
710 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
711 "Bad subcontext (PULL) Common Type Header length %d != 8",
712 (int)hdrlen);
715 /* filler should be ignored */
716 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
719 * Private Header for Constructed Type
721 /* length - will be updated latter */
722 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
723 if (size_is >= 0 && size_is != content_size) {
724 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
725 (int)size_is, (int)content_size);
727 /* the content size must be a multiple of 8 */
728 if ((content_size % 8) != 0) {
729 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
730 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
731 (int)size_is, (int)content_size);
733 r_content_size = content_size;
735 /* reserved */
736 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
737 break;
739 case 0xFFFFFFFF:
741 * a shallow copy like subcontext
742 * useful for DCERPC pipe chunks.
744 subndr = talloc_zero(ndr, struct ndr_pull);
745 NDR_ERR_HAVE_NO_MEMORY(subndr);
747 subndr->flags = ndr->flags;
748 subndr->current_mem_ctx = ndr->current_mem_ctx;
749 subndr->data = ndr->data;
750 subndr->offset = ndr->offset;
751 subndr->data_size = ndr->data_size;
753 *_subndr = subndr;
754 return NDR_ERR_SUCCESS;
756 default:
757 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
758 (int)header_size);
761 NDR_PULL_NEED_BYTES(ndr, r_content_size);
763 subndr = talloc_zero(ndr, struct ndr_pull);
764 NDR_ERR_HAVE_NO_MEMORY(subndr);
765 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
766 subndr->current_mem_ctx = ndr->current_mem_ctx;
768 subndr->data = ndr->data + ndr->offset;
769 subndr->offset = 0;
770 subndr->data_size = r_content_size;
772 if (force_le) {
773 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
774 } else if (force_be) {
775 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
778 *_subndr = subndr;
779 return NDR_ERR_SUCCESS;
782 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
783 struct ndr_pull *subndr,
784 size_t header_size,
785 ssize_t size_is)
787 uint32_t advance;
788 uint32_t highest_ofs;
790 if (header_size == 0xFFFFFFFF) {
791 advance = subndr->offset - ndr->offset;
792 } else if (size_is >= 0) {
793 advance = size_is;
794 } else if (header_size > 0) {
795 advance = subndr->data_size;
796 } else {
797 advance = subndr->offset;
800 if (subndr->offset > ndr->relative_highest_offset) {
801 highest_ofs = subndr->offset;
802 } else {
803 highest_ofs = subndr->relative_highest_offset;
805 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
807 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
809 highest_ofs = advance;
811 if (highest_ofs < advance) {
812 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
813 "not all bytes consumed ofs[%u] advance[%u]",
814 highest_ofs, advance);
817 NDR_CHECK(ndr_pull_advance(ndr, advance));
818 return NDR_ERR_SUCCESS;
821 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
822 struct ndr_push **_subndr,
823 size_t header_size,
824 ssize_t size_is)
826 struct ndr_push *subndr;
828 subndr = ndr_push_init_ctx(ndr);
829 NDR_ERR_HAVE_NO_MEMORY(subndr);
830 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
832 if (size_is > 0) {
833 NDR_CHECK(ndr_push_zero(subndr, size_is));
834 subndr->offset = 0;
835 subndr->relative_end_offset = size_is;
838 *_subndr = subndr;
839 return NDR_ERR_SUCCESS;
843 push a subcontext header
845 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
846 struct ndr_push *subndr,
847 size_t header_size,
848 ssize_t size_is)
850 ssize_t padding_len;
852 if (size_is >= 0) {
853 padding_len = size_is - subndr->offset;
854 if (padding_len < 0) {
855 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
856 (int)subndr->offset, (int)size_is);
858 subndr->offset = size_is;
861 switch (header_size) {
862 case 0:
863 break;
865 case 2:
866 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
867 break;
869 case 4:
870 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
871 break;
873 case 0xFFFFFC01:
875 * Common Type Header for the Serialization Stream
876 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
878 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
879 if (padding_len > 0) {
880 NDR_CHECK(ndr_push_zero(subndr, padding_len));
883 /* version */
884 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
887 * 0x10 little endian
888 * 0x00 big endian
890 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
892 /* length of the "Private Header for Constructed Type" */
893 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
895 /* filler */
896 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
899 * Private Header for Constructed Type
901 /* length - will be updated latter */
902 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
904 /* reserved */
905 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
906 break;
908 default:
909 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
910 (int)header_size);
913 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
914 return NDR_ERR_SUCCESS;
918 store a token in the ndr context, for later retrieval
920 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
921 struct ndr_token_list **list,
922 const void *key,
923 uint32_t value)
925 struct ndr_token_list *tok;
926 tok = talloc(mem_ctx, struct ndr_token_list);
927 NDR_ERR_HAVE_NO_MEMORY(tok);
928 tok->key = key;
929 tok->value = value;
930 DLIST_ADD((*list), tok);
931 return NDR_ERR_SUCCESS;
935 retrieve a token from a ndr context, using cmp_fn to match the tokens
937 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
938 comparison_fn_t _cmp_fn, bool _remove_tok)
940 struct ndr_token_list *tok;
941 for (tok=*list;tok;tok=tok->next) {
942 if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
943 else if (!_cmp_fn && tok->key == key) goto found;
945 return NDR_ERR_TOKEN;
946 found:
947 *v = tok->value;
948 if (_remove_tok) {
949 DLIST_REMOVE((*list), tok);
950 talloc_free(tok);
952 return NDR_ERR_SUCCESS;
956 retrieve a token from a ndr context
958 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
960 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
964 peek at but don't removed a token from a ndr context
966 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
968 struct ndr_token_list *tok;
969 for (tok = *list; tok; tok = tok->next) {
970 if (tok->key == key) {
971 return tok->value;
974 return 0;
978 pull an array size field and add it to the array_size_list token list
980 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
982 uint32_t size;
983 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
984 return ndr_token_store(ndr, &ndr->array_size_list, p, size);
988 get the stored array size field
990 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
992 return ndr_token_peek(&ndr->array_size_list, p);
996 check the stored array size field
998 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
1000 uint32_t stored;
1001 stored = ndr_token_peek(&ndr->array_size_list, p);
1002 if (stored != size) {
1003 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1004 "Bad array size - got %u expected %u\n",
1005 stored, size);
1007 return NDR_ERR_SUCCESS;
1011 pull an array length field and add it to the array_length_list token list
1013 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1015 uint32_t length, offset;
1016 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1017 if (offset != 0) {
1018 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1019 "non-zero array offset %u\n", offset);
1021 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1022 return ndr_token_store(ndr, &ndr->array_length_list, p, length);
1026 get the stored array length field
1028 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1030 return ndr_token_peek(&ndr->array_length_list, p);
1034 check the stored array length field
1036 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1038 uint32_t stored;
1039 stored = ndr_token_peek(&ndr->array_length_list, p);
1040 if (stored != length) {
1041 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1042 "Bad array length - got %u expected %u\n",
1043 stored, length);
1045 return NDR_ERR_SUCCESS;
1048 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1050 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1051 int64_t tmp = 0 - (int64_t)count;
1052 uint64_t ncount = tmp;
1054 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1057 return NDR_ERR_SUCCESS;
1060 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1062 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1063 int64_t tmp = 0 - (int64_t)count;
1064 uint64_t ncount1 = tmp;
1065 uint64_t ncount2;
1067 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1068 if (ncount1 == ncount2) {
1069 return NDR_ERR_SUCCESS;
1072 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1073 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1074 (unsigned long long)ncount2,
1075 (unsigned long long)ncount1,
1076 (unsigned long)count);
1079 return NDR_ERR_SUCCESS;
1083 store a switch value
1085 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1087 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1090 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1092 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1095 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1097 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1101 retrieve a switch value
1103 _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
1105 return ndr_token_peek(&ndr->switch_list, p);
1108 _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
1110 return ndr_token_peek(&ndr->switch_list, p);
1113 _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
1115 return ndr_token_peek(&ndr->switch_list, p);
1118 /* retrieve a switch value and remove it from the list */
1119 _PUBLIC_ uint32_t ndr_pull_steal_switch_value(struct ndr_pull *ndr, const void *p)
1121 enum ndr_err_code status;
1122 uint32_t v;
1124 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1125 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1126 return 0;
1129 return v;
1133 pull a struct from a blob using NDR
1135 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1136 ndr_pull_flags_fn_t fn)
1138 struct ndr_pull *ndr;
1139 ndr = ndr_pull_init_blob(blob, mem_ctx);
1140 NDR_ERR_HAVE_NO_MEMORY(ndr);
1141 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1142 talloc_free(ndr);
1143 return NDR_ERR_SUCCESS;
1147 pull a struct from a blob using NDR - failing if all bytes are not consumed
1149 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1150 void *p, ndr_pull_flags_fn_t fn)
1152 struct ndr_pull *ndr;
1153 uint32_t highest_ofs;
1154 ndr = ndr_pull_init_blob(blob, mem_ctx);
1155 NDR_ERR_HAVE_NO_MEMORY(ndr);
1156 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1157 if (ndr->offset > ndr->relative_highest_offset) {
1158 highest_ofs = ndr->offset;
1159 } else {
1160 highest_ofs = ndr->relative_highest_offset;
1162 if (highest_ofs < ndr->data_size) {
1163 enum ndr_err_code ret;
1164 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1165 "not all bytes consumed ofs[%u] size[%u]",
1166 highest_ofs, ndr->data_size);
1167 talloc_free(ndr);
1168 return ret;
1170 talloc_free(ndr);
1171 return NDR_ERR_SUCCESS;
1175 pull a struct from a blob using NDR - failing if all bytes are not consumed
1177 This only works for structures with NO allocated memory, like
1178 objectSID and GUID. This helps because we parse these a lot.
1180 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1181 void *p, ndr_pull_flags_fn_t fn)
1184 * We init this structure on the stack here, to avoid a
1185 * talloc() as otherwise this call to the fn() is assured not
1186 * to be doing any allocation, eg SIDs and GUIDs.
1188 * This allows us to keep the safety of the PIDL-generated
1189 * code without the talloc() overhead.
1191 struct ndr_pull ndr = {
1192 .data = blob->data,
1193 .data_size = blob->length,
1194 .current_mem_ctx = (void *)-1
1196 uint32_t highest_ofs;
1197 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1198 if (ndr.offset > ndr.relative_highest_offset) {
1199 highest_ofs = ndr.offset;
1200 } else {
1201 highest_ofs = ndr.relative_highest_offset;
1203 if (highest_ofs < ndr.data_size) {
1204 enum ndr_err_code ret;
1205 ret = ndr_pull_error(&ndr, NDR_ERR_UNREAD_BYTES,
1206 "not all bytes consumed ofs[%u] size[%u]",
1207 highest_ofs, ndr.data_size);
1208 return ret;
1210 return NDR_ERR_SUCCESS;
1214 pull a union from a blob using NDR, given the union discriminator
1216 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1217 void *p,
1218 uint32_t level, ndr_pull_flags_fn_t fn)
1220 struct ndr_pull *ndr;
1221 ndr = ndr_pull_init_blob(blob, mem_ctx);
1222 NDR_ERR_HAVE_NO_MEMORY(ndr);
1223 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1224 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1225 talloc_free(ndr);
1226 return NDR_ERR_SUCCESS;
1230 pull a union from a blob using NDR, given the union discriminator,
1231 failing if all bytes are not consumed
1233 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1234 void *p,
1235 uint32_t level, ndr_pull_flags_fn_t fn)
1237 struct ndr_pull *ndr;
1238 uint32_t highest_ofs;
1239 ndr = ndr_pull_init_blob(blob, mem_ctx);
1240 NDR_ERR_HAVE_NO_MEMORY(ndr);
1241 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1242 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1243 if (ndr->offset > ndr->relative_highest_offset) {
1244 highest_ofs = ndr->offset;
1245 } else {
1246 highest_ofs = ndr->relative_highest_offset;
1248 if (highest_ofs < ndr->data_size) {
1249 enum ndr_err_code ret;
1250 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1251 "not all bytes consumed ofs[%u] size[%u]",
1252 highest_ofs, ndr->data_size);
1253 talloc_free(ndr);
1254 return ret;
1256 talloc_free(ndr);
1257 return NDR_ERR_SUCCESS;
1261 push a struct to a blob using NDR
1263 _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)
1265 struct ndr_push *ndr;
1266 ndr = ndr_push_init_ctx(mem_ctx);
1267 NDR_ERR_HAVE_NO_MEMORY(ndr);
1269 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1271 *blob = ndr_push_blob(ndr);
1272 talloc_steal(mem_ctx, blob->data);
1273 talloc_free(ndr);
1275 return NDR_ERR_SUCCESS;
1279 push a struct into a provided blob using NDR.
1281 We error because we want to have the performance issue (extra
1282 talloc() calls) show up as an error, not just slower code. This is
1283 used for things like GUIDs, which we expect to be a fixed size, and
1284 SIDs that we can pre-calculate the size for.
1286 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1287 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1289 struct ndr_push ndr = {
1290 .data = blob->data,
1291 .alloc_size = blob->length,
1292 .fixed_buf_size = true
1295 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1297 if (ndr.offset != blob->length) {
1298 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1299 "buffer was either to large or small "
1300 "ofs[%u] size[%zu]",
1301 ndr.offset, blob->length);
1304 return NDR_ERR_SUCCESS;
1308 push a union to a blob using NDR
1310 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1311 uint32_t level, ndr_push_flags_fn_t fn)
1313 struct ndr_push *ndr;
1314 ndr = ndr_push_init_ctx(mem_ctx);
1315 NDR_ERR_HAVE_NO_MEMORY(ndr);
1317 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1318 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1320 *blob = ndr_push_blob(ndr);
1321 talloc_steal(mem_ctx, blob->data);
1322 talloc_free(ndr);
1324 return NDR_ERR_SUCCESS;
1328 generic ndr_size_*() handler for structures
1330 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1332 struct ndr_push *ndr;
1333 enum ndr_err_code status;
1334 size_t ret;
1336 /* avoid recursion */
1337 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1339 ndr = ndr_push_init_ctx(NULL);
1340 if (!ndr) return 0;
1341 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1342 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1343 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1344 talloc_free(ndr);
1345 return 0;
1347 ret = ndr->offset;
1348 talloc_free(ndr);
1349 return ret;
1353 generic ndr_size_*() handler for unions
1355 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1357 struct ndr_push *ndr;
1358 enum ndr_err_code status;
1359 size_t ret;
1361 /* avoid recursion */
1362 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1364 ndr = ndr_push_init_ctx(NULL);
1365 if (!ndr) return 0;
1366 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1368 status = ndr_push_set_switch_value(ndr, p, level);
1369 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1370 talloc_free(ndr);
1371 return 0;
1373 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1374 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1375 talloc_free(ndr);
1376 return 0;
1378 ret = ndr->offset;
1379 talloc_free(ndr);
1380 return ret;
1384 get the current base for relative pointers for the push
1386 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1388 return ndr->relative_base_offset;
1392 restore the old base for relative pointers for the push
1394 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1396 ndr->relative_base_offset = offset;
1400 setup the current base for relative pointers for the push
1401 called in the NDR_SCALAR stage
1403 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1405 ndr->relative_base_offset = offset;
1406 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1410 setup the current base for relative pointers for the push
1411 called in the NDR_BUFFERS stage
1413 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1415 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1419 push a relative object - stage1
1420 this is called during SCALARS processing
1422 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1424 if (p == NULL) {
1425 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1426 return NDR_ERR_SUCCESS;
1428 NDR_CHECK(ndr_push_align(ndr, 4));
1429 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1430 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1434 push a short relative object - stage1
1435 this is called during SCALARS processing
1437 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1439 if (p == NULL) {
1440 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1441 return NDR_ERR_SUCCESS;
1443 NDR_CHECK(ndr_push_align(ndr, 2));
1444 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1445 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1448 push a relative object - stage2
1449 this is called during buffers processing
1451 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1453 uint32_t save_offset;
1454 uint32_t ptr_offset = 0xFFFFFFFF;
1455 if (p == NULL) {
1456 return NDR_ERR_SUCCESS;
1458 save_offset = ndr->offset;
1459 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1460 if (ptr_offset > ndr->offset) {
1461 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1462 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1463 ptr_offset, ndr->offset);
1465 ndr->offset = ptr_offset;
1466 if (save_offset < ndr->relative_base_offset) {
1467 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1468 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1469 save_offset, ndr->relative_base_offset);
1471 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1472 ndr->offset = save_offset;
1473 return NDR_ERR_SUCCESS;
1476 push a short relative object - stage2
1477 this is called during buffers processing
1479 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1481 uint32_t save_offset;
1482 uint32_t ptr_offset = 0xFFFF;
1483 uint32_t relative_offset;
1484 size_t pad;
1485 size_t align = 1;
1487 if (p == NULL) {
1488 return NDR_ERR_SUCCESS;
1491 if (ndr->offset < ndr->relative_base_offset) {
1492 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1493 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1494 ndr->offset, ndr->relative_base_offset);
1497 relative_offset = ndr->offset - ndr->relative_base_offset;
1499 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1500 align = 1;
1501 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1502 align = 2;
1503 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1504 align = 4;
1505 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1506 align = 8;
1509 pad = ndr_align_size(relative_offset, align);
1510 if (pad != 0) {
1511 NDR_CHECK(ndr_push_zero(ndr, pad));
1514 relative_offset = ndr->offset - ndr->relative_base_offset;
1515 if (relative_offset > UINT16_MAX) {
1516 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1517 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1518 relative_offset);
1521 save_offset = ndr->offset;
1522 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1523 if (ptr_offset > ndr->offset) {
1524 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1525 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1526 ptr_offset, ndr->offset);
1528 ndr->offset = ptr_offset;
1529 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1530 ndr->offset = save_offset;
1531 return NDR_ERR_SUCCESS;
1535 push a relative object - stage2 start
1536 this is called during buffers processing
1538 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1540 if (p == NULL) {
1541 return NDR_ERR_SUCCESS;
1543 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1544 uint32_t relative_offset;
1545 size_t pad;
1546 size_t align = 1;
1548 if (ndr->offset < ndr->relative_base_offset) {
1549 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1550 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1551 ndr->offset, ndr->relative_base_offset);
1554 relative_offset = ndr->offset - ndr->relative_base_offset;
1556 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1557 align = 1;
1558 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1559 align = 2;
1560 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1561 align = 4;
1562 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1563 align = 8;
1566 pad = ndr_align_size(relative_offset, align);
1567 if (pad) {
1568 NDR_CHECK(ndr_push_zero(ndr, pad));
1571 return ndr_push_relative_ptr2(ndr, p);
1573 if (ndr->relative_end_offset == -1) {
1574 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1575 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1576 ndr->relative_end_offset);
1578 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
1579 return NDR_ERR_SUCCESS;
1583 push a relative object - stage2 end
1584 this is called during buffers processing
1586 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1588 uint32_t begin_offset = 0xFFFFFFFF;
1589 ssize_t len;
1590 uint32_t correct_offset = 0;
1591 uint32_t align = 1;
1592 uint32_t pad = 0;
1594 if (p == NULL) {
1595 return NDR_ERR_SUCCESS;
1598 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1599 return NDR_ERR_SUCCESS;
1602 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1603 /* better say more than calculation a too small buffer */
1604 NDR_PUSH_ALIGN(ndr, 8);
1605 return NDR_ERR_SUCCESS;
1608 if (ndr->relative_end_offset < ndr->offset) {
1609 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1610 "ndr_push_relative_ptr2_end:"
1611 "relative_end_offset %u < offset %u",
1612 ndr->relative_end_offset, ndr->offset);
1615 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1617 /* we have marshalled a buffer, see how long it was */
1618 len = ndr->offset - begin_offset;
1620 if (len < 0) {
1621 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1622 "ndr_push_relative_ptr2_end:"
1623 "offset %u - begin_offset %u < 0",
1624 ndr->offset, begin_offset);
1627 if (ndr->relative_end_offset < len) {
1628 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1629 "ndr_push_relative_ptr2_end:"
1630 "relative_end_offset %u < len %lld",
1631 ndr->offset, (long long)len);
1634 /* the reversed offset is at the end of the main buffer */
1635 correct_offset = ndr->relative_end_offset - len;
1637 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1638 align = 1;
1639 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1640 align = 2;
1641 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1642 align = 4;
1643 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1644 align = 8;
1647 pad = ndr_align_size(correct_offset, align);
1648 if (pad) {
1649 correct_offset += pad;
1650 correct_offset -= align;
1653 if (correct_offset < begin_offset) {
1654 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1655 "ndr_push_relative_ptr2_end: "
1656 "correct_offset %u < begin_offset %u",
1657 correct_offset, begin_offset);
1660 if (len > 0) {
1661 uint32_t clear_size = correct_offset - begin_offset;
1663 clear_size = MIN(clear_size, len);
1665 /* now move the marshalled buffer to the end of the main buffer */
1666 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1668 if (clear_size) {
1669 /* and wipe out old buffer within the main buffer */
1670 memset(ndr->data + begin_offset, '\0', clear_size);
1674 /* and set the end offset for the next buffer */
1675 ndr->relative_end_offset = correct_offset;
1677 /* finally write the offset to the main buffer */
1678 ndr->offset = correct_offset;
1679 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1681 /* restore to where we were in the main buffer */
1682 ndr->offset = begin_offset;
1684 return NDR_ERR_SUCCESS;
1688 get the current base for relative pointers for the pull
1690 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1692 return ndr->relative_base_offset;
1696 restore the old base for relative pointers for the pull
1698 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1700 ndr->relative_base_offset = offset;
1704 setup the current base for relative pointers for the pull
1705 called in the NDR_SCALAR stage
1707 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1709 ndr->relative_base_offset = offset;
1710 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1714 setup the current base for relative pointers for the pull
1715 called in the NDR_BUFFERS stage
1717 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1719 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1723 pull a relative object - stage1
1724 called during SCALARS processing
1726 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1728 rel_offset += ndr->relative_base_offset;
1729 if (rel_offset > ndr->data_size) {
1730 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1731 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1732 rel_offset, ndr->data_size);
1734 return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1738 pull a relative object - stage2
1739 called during BUFFERS processing
1741 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1743 uint32_t rel_offset;
1744 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1745 return ndr_pull_set_offset(ndr, rel_offset);
1748 const static struct {
1749 enum ndr_err_code err;
1750 const char *string;
1751 } ndr_err_code_strings[] = {
1752 { NDR_ERR_SUCCESS, "Success" },
1753 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1754 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1755 { NDR_ERR_OFFSET, "Offset Error" },
1756 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1757 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1758 { NDR_ERR_LENGTH, "Length Error" },
1759 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1760 { NDR_ERR_COMPRESSION, "Compression Error" },
1761 { NDR_ERR_STRING, "String Error" },
1762 { NDR_ERR_VALIDATE, "Validate Error" },
1763 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1764 { NDR_ERR_ALLOC, "Allocation Error" },
1765 { NDR_ERR_RANGE, "Range Error" },
1766 { NDR_ERR_TOKEN, "Token Error" },
1767 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1768 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1769 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1770 { NDR_ERR_NDR64, "NDR64 assertion error" },
1771 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1772 { 0, NULL }
1775 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1777 int i;
1778 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1779 if (ndr_err_code_strings[i].err == ndr_err)
1780 return ndr_err_code_strings[i].string;
1782 return "Unknown error";