winbindd: complete WBFLAG_PAM_AUTH_PAC handling in winbindd_pam_auth_crap_send()
[Samba.git] / librpc / ndr / ndr.c
blobd478eb69c013d472ad2bff428dd826458f99af34
1 /*
2 Unix SMB/CIFS implementation.
4 libndr interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2005-2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 this provides the core routines for NDR parsing functions
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27 of NDR encoding rules
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "../lib/util/dlinklist.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_RPC_PARSE
37 #define NDR_BASE_MARSHALL_SIZE 1024
39 /* this guid indicates NDR encoding in a protocol tower */
40 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
41 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
45 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
46 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
50 const struct ndr_syntax_id ndr_syntax_id_null = {
51 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
56 work out the number of bytes needed to align on a n byte boundary
58 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
60 if ((offset & (n-1)) == 0) return 0;
61 return n - (offset & (n-1));
65 initialise a ndr parse structure from a data blob
67 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
69 struct ndr_pull *ndr;
71 ndr = talloc_zero(mem_ctx, struct ndr_pull);
72 if (!ndr) return NULL;
73 ndr->current_mem_ctx = mem_ctx;
75 ndr->data = blob->data;
76 ndr->data_size = blob->length;
78 return ndr;
81 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
83 enum ndr_err_code ndr_err;
84 DATA_BLOB b;
85 uint32_t append = 0;
86 bool ok;
88 if (blob->length == 0) {
89 return NDR_ERR_SUCCESS;
92 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
93 if (ndr_err == NDR_ERR_TOKEN) {
94 append = 0;
95 ndr_err = NDR_ERR_SUCCESS;
97 NDR_CHECK(ndr_err);
99 if (ndr->data_size == 0) {
100 ndr->data = NULL;
101 append = UINT32_MAX;
104 if (append == UINT32_MAX) {
106 * append == UINT32_MAX means that
107 * ndr->data is either NULL or a valid
108 * talloc child of ndr, which means
109 * we can use data_blob_append() without
110 * data_blob_talloc() of the existing callers data
112 b = data_blob_const(ndr->data, ndr->data_size);
113 } else {
114 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
115 if (b.data == NULL) {
116 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
120 ok = data_blob_append(ndr, &b, blob->data, blob->length);
121 if (!ok) {
122 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
125 ndr->data = b.data;
126 ndr->data_size = b.length;
128 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
131 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
133 uint32_t skip = 0;
134 uint32_t append = 0;
136 if (ndr->relative_base_offset != 0) {
137 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
138 "%s", __location__);
140 if (ndr->relative_highest_offset != 0) {
141 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
142 "%s", __location__);
144 if (ndr->relative_list.count != 0) {
145 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
146 "%s", __location__);
148 if (ndr->relative_base_list.count != 0) {
149 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
150 "%s", __location__);
154 * we need to keep up to 7 bytes
155 * in order to get the aligment right.
157 skip = ndr->offset & 0xFFFFFFF8;
159 if (skip == 0) {
160 return NDR_ERR_SUCCESS;
163 ndr->offset -= skip;
164 ndr->data_size -= skip;
166 append = ndr_token_peek(&ndr->array_size_list, ndr);
167 if (append != UINT32_MAX) {
169 * here we assume, that ndr->data is not a
170 * talloc child of ndr.
172 ndr->data += skip;
173 return NDR_ERR_SUCCESS;
176 memmove(ndr->data, ndr->data + skip, ndr->data_size);
178 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
179 if (ndr->data_size != 0 && ndr->data == NULL) {
180 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
183 return NDR_ERR_SUCCESS;
187 advance by 'size' bytes
189 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
191 ndr->offset += size;
192 if (ndr->offset > ndr->data_size) {
193 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
194 "ndr_pull_advance by %u failed",
195 size);
197 return NDR_ERR_SUCCESS;
201 set the parse offset to 'ofs'
203 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
205 ndr->offset = ofs;
206 if (ndr->offset > ndr->data_size) {
207 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
208 "ndr_pull_set_offset %u failed",
209 ofs);
211 return NDR_ERR_SUCCESS;
214 /* create a ndr_push structure, ready for some marshalling */
215 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
217 struct ndr_push *ndr;
219 ndr = talloc_zero(mem_ctx, struct ndr_push);
220 if (!ndr) {
221 return NULL;
224 ndr->flags = 0;
225 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
226 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
227 if (!ndr->data) {
228 talloc_free(ndr);
229 return NULL;
232 return ndr;
235 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
236 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
238 DATA_BLOB blob;
239 blob = data_blob_const(ndr->data, ndr->offset);
240 if (ndr->alloc_size > ndr->offset) {
241 ndr->data[ndr->offset] = 0;
243 return blob;
248 expand the available space in the buffer to ndr->offset + extra_size
250 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
252 uint32_t size = extra_size + ndr->offset;
254 if (size < ndr->offset) {
255 /* extra_size overflowed the offset */
256 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
257 size);
260 if (ndr->fixed_buf_size) {
261 if (ndr->alloc_size >= size) {
262 return NDR_ERR_SUCCESS;
264 return ndr_push_error(ndr,
265 NDR_ERR_BUFSIZE,
266 "Overflow of fixed buffer in "
267 "push_expand to %u",
268 size);
271 if (ndr->alloc_size > size) {
272 return NDR_ERR_SUCCESS;
275 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
276 if (size+1 > ndr->alloc_size) {
277 ndr->alloc_size = size+1;
279 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
280 if (!ndr->data) {
281 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
282 ndr->alloc_size);
285 return NDR_ERR_SUCCESS;
288 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
290 va_list ap;
291 char *s = NULL;
292 uint32_t i;
293 int ret;
294 int dbgc_class;
296 va_start(ap, format);
297 ret = vasprintf(&s, format, ap);
298 va_end(ap);
300 if (ret == -1) {
301 return;
304 dbgc_class = *(int *)ndr->private_data;
306 if (ndr->no_newline) {
307 DEBUGADDC(dbgc_class, 1,("%s", s));
308 free(s);
309 return;
312 for (i=0;i<ndr->depth;i++) {
313 DEBUGADDC(dbgc_class, 1,(" "));
316 DEBUGADDC(dbgc_class, 1,("%s\n", s));
317 free(s);
320 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
322 va_list ap;
323 char *s = NULL;
324 uint32_t i;
325 int ret;
327 va_start(ap, format);
328 ret = vasprintf(&s, format, ap);
329 va_end(ap);
331 if (ret == -1) {
332 return;
335 if (ndr->no_newline) {
336 DEBUGADD(1,("%s", s));
337 free(s);
338 return;
341 for (i=0;i<ndr->depth;i++) {
342 DEBUGADD(1,(" "));
345 DEBUGADD(1,("%s\n", s));
346 free(s);
349 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
351 va_list ap;
352 uint32_t i;
354 if (!ndr->no_newline) {
355 for (i=0;i<ndr->depth;i++) {
356 printf(" ");
360 va_start(ap, format);
361 vprintf(format, ap);
362 va_end(ap);
363 if (!ndr->no_newline) {
364 printf("\n");
368 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
370 va_list ap;
371 uint32_t i;
373 if (!ndr->no_newline) {
374 for (i=0;i<ndr->depth;i++) {
375 ndr->private_data = talloc_asprintf_append_buffer(
376 (char *)ndr->private_data, " ");
380 va_start(ap, format);
381 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
382 format, ap);
383 va_end(ap);
384 if (!ndr->no_newline) {
385 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
386 "\n");
391 a useful helper function for printing idl structures via DEBUGC()
393 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
395 struct ndr_print *ndr;
397 DEBUGC(dbgc_class, 1,(" "));
399 ndr = talloc_zero(NULL, struct ndr_print);
400 if (!ndr) return;
401 ndr->private_data = &dbgc_class;
402 ndr->print = ndr_print_debugc_helper;
403 ndr->depth = 1;
404 ndr->flags = 0;
405 #ifdef DEBUG_PASSWORD
406 if (CHECK_DEBUGLVL(100)) {
407 ndr->print_secrets = true;
409 #endif
411 fn(ndr, name, ptr);
412 talloc_free(ndr);
416 a useful helper function for printing idl structures via DEBUG()
418 _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
420 struct ndr_print *ndr;
422 DEBUG(1,(" "));
424 ndr = talloc_zero(NULL, struct ndr_print);
425 if (!ndr) return;
426 ndr->print = ndr_print_debug_helper;
427 ndr->depth = 1;
428 ndr->flags = 0;
429 #ifdef DEBUG_PASSWORD
430 if (CHECK_DEBUGLVL(100)) {
431 ndr->print_secrets = true;
433 #endif
435 fn(ndr, name, ptr);
436 talloc_free(ndr);
440 a useful helper function for printing idl unions via DEBUG()
442 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
444 struct ndr_print *ndr;
446 DEBUG(1,(" "));
448 ndr = talloc_zero(NULL, struct ndr_print);
449 if (!ndr) return;
450 ndr->print = ndr_print_debug_helper;
451 ndr->depth = 1;
452 ndr->flags = 0;
453 #ifdef DEBUG_PASSWORD
454 if (CHECK_DEBUGLVL(100)) {
455 ndr->print_secrets = true;
457 #endif
459 ndr_print_set_switch_value(ndr, ptr, level);
460 fn(ndr, name, ptr);
461 talloc_free(ndr);
465 a useful helper function for printing idl function calls via DEBUG()
467 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
469 struct ndr_print *ndr;
471 DEBUG(1,(" "));
473 ndr = talloc_zero(NULL, struct ndr_print);
474 if (!ndr) return;
475 ndr->print = ndr_print_debug_helper;
476 ndr->depth = 1;
477 ndr->flags = 0;
478 #ifdef DEBUG_PASSWORD
479 if (CHECK_DEBUGLVL(100)) {
480 ndr->print_secrets = true;
482 #endif
484 fn(ndr, name, flags, ptr);
485 talloc_free(ndr);
489 a useful helper function for printing idl structures to a string
491 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
493 struct ndr_print *ndr;
494 char *ret = NULL;
496 ndr = talloc_zero(mem_ctx, struct ndr_print);
497 if (!ndr) return NULL;
498 ndr->private_data = talloc_strdup(ndr, "");
499 if (!ndr->private_data) {
500 goto failed;
502 ndr->print = ndr_print_string_helper;
503 ndr->depth = 1;
504 ndr->flags = 0;
506 fn(ndr, name, ptr);
507 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
508 failed:
509 talloc_free(ndr);
510 return ret;
514 a useful helper function for printing idl unions to a string
516 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
518 struct ndr_print *ndr;
519 char *ret = NULL;
521 ndr = talloc_zero(mem_ctx, struct ndr_print);
522 if (!ndr) return NULL;
523 ndr->private_data = talloc_strdup(ndr, "");
524 if (!ndr->private_data) {
525 goto failed;
527 ndr->print = ndr_print_string_helper;
528 ndr->depth = 1;
529 ndr->flags = 0;
530 ndr_print_set_switch_value(ndr, ptr, level);
531 fn(ndr, name, ptr);
532 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
533 failed:
534 talloc_free(ndr);
535 return ret;
539 a useful helper function for printing idl function calls to a string
541 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
542 ndr_print_function_t fn, const char *name,
543 int flags, void *ptr)
545 struct ndr_print *ndr;
546 char *ret = NULL;
548 ndr = talloc_zero(mem_ctx, struct ndr_print);
549 if (!ndr) return NULL;
550 ndr->private_data = talloc_strdup(ndr, "");
551 if (!ndr->private_data) {
552 goto failed;
554 ndr->print = ndr_print_string_helper;
555 ndr->depth = 1;
556 ndr->flags = 0;
557 fn(ndr, name, flags, ptr);
558 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
559 failed:
560 talloc_free(ndr);
561 return ret;
564 _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
566 /* the big/little endian flags are inter-dependent */
567 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
568 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
569 (*pflags) &= ~LIBNDR_FLAG_NDR64;
571 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
572 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
573 (*pflags) &= ~LIBNDR_FLAG_NDR64;
575 if (new_flags & LIBNDR_ALIGN_FLAGS) {
576 /* Ensure we only have the passed-in
577 align flag set in the new_flags,
578 remove any old align flag. */
579 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
581 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
582 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
584 (*pflags) |= new_flags;
588 return and possibly log an NDR error
590 _PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
591 enum ndr_err_code ndr_err,
592 const char *format, ...)
594 char *s=NULL;
595 va_list ap;
596 int ret;
598 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
599 switch (ndr_err) {
600 case NDR_ERR_BUFSIZE:
601 return NDR_ERR_INCOMPLETE_BUFFER;
602 default:
603 break;
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_pull_error(%u): %s\n", ndr_err, s));
617 free(s);
619 return ndr_err;
623 return and possibly log an NDR error
625 _PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
626 enum ndr_err_code ndr_err,
627 const char *format, ...)
629 char *s=NULL;
630 va_list ap;
631 int ret;
633 va_start(ap, format);
634 ret = vasprintf(&s, format, ap);
635 va_end(ap);
637 if (ret == -1) {
638 return NDR_ERR_ALLOC;
641 DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
643 free(s);
645 return ndr_err;
649 handle subcontext buffers, which in midl land are user-marshalled, but
650 we use magic in pidl to make them easier to cope with
652 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
653 struct ndr_pull **_subndr,
654 size_t header_size,
655 ssize_t size_is)
657 struct ndr_pull *subndr;
658 uint32_t r_content_size;
659 bool force_le = false;
660 bool force_be = false;
662 switch (header_size) {
663 case 0: {
664 uint32_t content_size = ndr->data_size - ndr->offset;
665 if (size_is >= 0) {
666 content_size = size_is;
668 r_content_size = content_size;
669 break;
672 case 2: {
673 uint16_t content_size;
674 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
675 if (size_is >= 0 && size_is != content_size) {
676 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%04x) mismatch content_size %d (0x%04x)",
677 (int)size_is, (int)size_is,
678 (int)content_size,
679 (int)content_size);
681 r_content_size = content_size;
682 break;
685 case 4: {
686 uint32_t content_size;
687 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
688 if (size_is >= 0 && size_is != content_size) {
689 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) (0x%08x) mismatch content_size %d (0x%08x)",
690 (int)size_is, (int)size_is,
691 (int)content_size,
692 (int)content_size);
694 r_content_size = content_size;
695 break;
697 case 0xFFFFFC01: {
699 * Common Type Header for the Serialization Stream
700 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
702 uint8_t version;
703 uint8_t drep;
704 uint16_t hdrlen;
705 uint32_t filler;
706 uint32_t content_size;
707 uint32_t reserved;
709 /* version */
710 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
712 if (version != 1) {
713 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
714 "Bad subcontext (PULL) Common Type Header version %d != 1",
715 (int)version);
719 * 0x10 little endian
720 * 0x00 big endian
722 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
723 if (drep == 0x10) {
724 force_le = true;
725 } else if (drep == 0x00) {
726 force_be = true;
727 } else {
728 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
729 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
730 (unsigned int)drep);
733 /* length of the "Private Header for Constructed Type" */
734 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
735 if (hdrlen != 8) {
736 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
737 "Bad subcontext (PULL) Common Type Header length %d != 8",
738 (int)hdrlen);
741 /* filler should be ignored */
742 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
745 * Private Header for Constructed Type
747 /* length - will be updated latter */
748 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
749 if (size_is >= 0 && size_is != content_size) {
750 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
751 (int)size_is, (int)content_size);
753 /* the content size must be a multiple of 8 */
754 if ((content_size % 8) != 0) {
755 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
756 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
757 (int)size_is, (int)content_size);
759 r_content_size = content_size;
761 /* reserved */
762 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
763 break;
765 case 0xFFFFFFFF:
767 * a shallow copy like subcontext
768 * useful for DCERPC pipe chunks.
770 subndr = talloc_zero(ndr, struct ndr_pull);
771 NDR_ERR_HAVE_NO_MEMORY(subndr);
773 subndr->flags = ndr->flags;
774 subndr->current_mem_ctx = ndr->current_mem_ctx;
775 subndr->data = ndr->data;
776 subndr->offset = ndr->offset;
777 subndr->data_size = ndr->data_size;
779 *_subndr = subndr;
780 return NDR_ERR_SUCCESS;
782 default:
783 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
784 (int)header_size);
787 NDR_PULL_NEED_BYTES(ndr, r_content_size);
789 subndr = talloc_zero(ndr, struct ndr_pull);
790 NDR_ERR_HAVE_NO_MEMORY(subndr);
791 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
792 subndr->current_mem_ctx = ndr->current_mem_ctx;
794 subndr->data = ndr->data + ndr->offset;
795 subndr->offset = 0;
796 subndr->data_size = r_content_size;
798 if (force_le) {
799 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
800 } else if (force_be) {
801 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
804 *_subndr = subndr;
805 return NDR_ERR_SUCCESS;
808 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
809 struct ndr_pull *subndr,
810 size_t header_size,
811 ssize_t size_is)
813 uint32_t advance;
814 uint32_t highest_ofs;
816 if (header_size == 0xFFFFFFFF) {
817 advance = subndr->offset - ndr->offset;
818 } else if (size_is >= 0) {
819 advance = size_is;
820 } else if (header_size > 0) {
821 advance = subndr->data_size;
822 } else {
823 advance = subndr->offset;
826 if (subndr->offset > ndr->relative_highest_offset) {
827 highest_ofs = subndr->offset;
828 } else {
829 highest_ofs = subndr->relative_highest_offset;
831 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
833 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
835 highest_ofs = advance;
837 if (highest_ofs < advance) {
838 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
839 "not all bytes consumed ofs[%u] advance[%u]",
840 highest_ofs, advance);
843 NDR_CHECK(ndr_pull_advance(ndr, advance));
844 return NDR_ERR_SUCCESS;
847 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
848 struct ndr_push **_subndr,
849 size_t header_size,
850 ssize_t size_is)
852 struct ndr_push *subndr;
854 subndr = ndr_push_init_ctx(ndr);
855 NDR_ERR_HAVE_NO_MEMORY(subndr);
856 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
858 if (size_is > 0) {
859 NDR_CHECK(ndr_push_zero(subndr, size_is));
860 subndr->offset = 0;
861 subndr->relative_end_offset = size_is;
864 *_subndr = subndr;
865 return NDR_ERR_SUCCESS;
869 push a subcontext header
871 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
872 struct ndr_push *subndr,
873 size_t header_size,
874 ssize_t size_is)
876 ssize_t padding_len;
878 if (size_is >= 0) {
879 padding_len = size_is - subndr->offset;
880 if (padding_len < 0) {
881 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
882 (int)subndr->offset, (int)size_is);
884 subndr->offset = size_is;
887 switch (header_size) {
888 case 0:
889 break;
891 case 2:
892 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
893 break;
895 case 4:
896 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
897 break;
899 case 0xFFFFFC01:
901 * Common Type Header for the Serialization Stream
902 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
904 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
905 if (padding_len > 0) {
906 NDR_CHECK(ndr_push_zero(subndr, padding_len));
909 /* version */
910 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
913 * 0x10 little endian
914 * 0x00 big endian
916 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
918 /* length of the "Private Header for Constructed Type" */
919 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
921 /* filler */
922 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
925 * Private Header for Constructed Type
927 /* length - will be updated latter */
928 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
930 /* reserved */
931 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
932 break;
934 default:
935 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
936 (int)header_size);
939 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
940 return NDR_ERR_SUCCESS;
944 struct ndr_token {
945 const void *key;
946 uint32_t value;
950 store a token in the ndr context, for later retrieval
952 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
953 struct ndr_token_list *list,
954 const void *key,
955 uint32_t value)
957 if (list->tokens == NULL) {
958 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
959 if (list->tokens == NULL) {
960 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
962 } else {
963 uint32_t alloc_count = talloc_array_length(list->tokens);
964 if (list->count == alloc_count) {
965 unsigned new_alloc;
966 unsigned increment = MIN(list->count, 1000);
967 new_alloc = alloc_count + increment;
968 if (new_alloc < alloc_count) {
969 return NDR_ERR_RANGE;
971 list->tokens = talloc_realloc(mem_ctx, list->tokens,
972 struct ndr_token, new_alloc);
973 if (list->tokens == NULL) {
974 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
978 list->tokens[list->count].key = key;
979 list->tokens[list->count].value = value;
980 list->count++;
981 return NDR_ERR_SUCCESS;
985 retrieve a token from a ndr context, using cmp_fn to match the tokens
987 _PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
988 const void *key, uint32_t *v,
989 comparison_fn_t _cmp_fn,
990 bool erase)
992 struct ndr_token *tokens = list->tokens;
993 unsigned i;
994 if (_cmp_fn) {
995 for (i = list->count - 1; i < list->count; i--) {
996 if (_cmp_fn(tokens[i].key, key) == 0) {
997 goto found;
1000 } else {
1001 for (i = list->count - 1; i < list->count; i--) {
1002 if (tokens[i].key == key) {
1003 goto found;
1007 return NDR_ERR_TOKEN;
1008 found:
1009 *v = tokens[i].value;
1010 if (erase) {
1011 if (i != list->count - 1) {
1012 tokens[i] = tokens[list->count - 1];
1014 list->count--;
1016 return NDR_ERR_SUCCESS;
1020 retrieve a token from a ndr context
1022 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1023 const void *key, uint32_t *v)
1025 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
1029 peek at but don't removed a token from a ndr context
1031 _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list *list, const void *key)
1033 unsigned i;
1034 struct ndr_token *tokens = list->tokens;
1036 for (i = list->count - 1; i < list->count; i--) {
1037 if (tokens[i].key == key) {
1038 return tokens[i].value;
1042 return 0;
1046 pull an array size field and add it to the array_size_list token list
1048 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1050 uint32_t size;
1051 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1052 return ndr_token_store(ndr, &ndr->array_size_list, p, size);
1056 get the stored array size field
1058 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
1060 return ndr_token_peek(&ndr->array_size_list, p);
1064 check the stored array size field
1066 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
1068 uint32_t stored;
1069 stored = ndr_token_peek(&ndr->array_size_list, p);
1070 if (stored != size) {
1071 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1072 "Bad array size - got %u expected %u\n",
1073 stored, size);
1075 return NDR_ERR_SUCCESS;
1079 pull an array length field and add it to the array_length_list token list
1081 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1083 uint32_t length, offset;
1084 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1085 if (offset != 0) {
1086 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1087 "non-zero array offset %u\n", offset);
1089 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1090 return ndr_token_store(ndr, &ndr->array_length_list, p, length);
1094 get the stored array length field
1096 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1098 return ndr_token_peek(&ndr->array_length_list, p);
1102 check the stored array length field
1104 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1106 uint32_t stored;
1107 stored = ndr_token_peek(&ndr->array_length_list, p);
1108 if (stored != length) {
1109 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1110 "Bad array length - got %u expected %u\n",
1111 stored, length);
1113 return NDR_ERR_SUCCESS;
1116 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1118 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1119 int64_t tmp = 0 - (int64_t)count;
1120 uint64_t ncount = tmp;
1122 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1125 return NDR_ERR_SUCCESS;
1128 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1130 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1131 int64_t tmp = 0 - (int64_t)count;
1132 uint64_t ncount1 = tmp;
1133 uint64_t ncount2;
1135 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1136 if (ncount1 == ncount2) {
1137 return NDR_ERR_SUCCESS;
1140 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1141 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1142 (unsigned long long)ncount2,
1143 (unsigned long long)ncount1,
1144 (unsigned long)count);
1147 return NDR_ERR_SUCCESS;
1151 store a switch value
1153 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1155 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1158 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1160 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1163 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1165 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1169 retrieve a switch value
1171 _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
1173 return ndr_token_peek(&ndr->switch_list, p);
1176 _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
1178 return ndr_token_peek(&ndr->switch_list, p);
1181 _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
1183 return ndr_token_peek(&ndr->switch_list, p);
1186 /* retrieve a switch value and remove it from the list */
1187 _PUBLIC_ uint32_t ndr_pull_steal_switch_value(struct ndr_pull *ndr, const void *p)
1189 enum ndr_err_code status;
1190 uint32_t v;
1192 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1193 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1194 return 0;
1197 return v;
1201 pull a struct from a blob using NDR
1203 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1204 ndr_pull_flags_fn_t fn)
1206 struct ndr_pull *ndr;
1207 ndr = ndr_pull_init_blob(blob, mem_ctx);
1208 NDR_ERR_HAVE_NO_MEMORY(ndr);
1209 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1210 talloc_free(ndr);
1211 return NDR_ERR_SUCCESS;
1215 pull a struct from a blob using NDR - failing if all bytes are not consumed
1217 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1218 void *p, ndr_pull_flags_fn_t fn)
1220 struct ndr_pull *ndr;
1221 uint32_t highest_ofs;
1222 ndr = ndr_pull_init_blob(blob, mem_ctx);
1223 NDR_ERR_HAVE_NO_MEMORY(ndr);
1224 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1225 if (ndr->offset > ndr->relative_highest_offset) {
1226 highest_ofs = ndr->offset;
1227 } else {
1228 highest_ofs = ndr->relative_highest_offset;
1230 if (highest_ofs < ndr->data_size) {
1231 enum ndr_err_code ret;
1232 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1233 "not all bytes consumed ofs[%u] size[%u]",
1234 highest_ofs, ndr->data_size);
1235 talloc_free(ndr);
1236 return ret;
1238 talloc_free(ndr);
1239 return NDR_ERR_SUCCESS;
1243 pull a struct from a blob using NDR - failing if all bytes are not consumed
1245 This only works for structures with NO allocated memory, like
1246 objectSID and GUID. This helps because we parse these a lot.
1248 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1249 void *p, ndr_pull_flags_fn_t fn)
1252 * We init this structure on the stack here, to avoid a
1253 * talloc() as otherwise this call to the fn() is assured not
1254 * to be doing any allocation, eg SIDs and GUIDs.
1256 * This allows us to keep the safety of the PIDL-generated
1257 * code without the talloc() overhead.
1259 struct ndr_pull ndr = {
1260 .data = blob->data,
1261 .data_size = blob->length,
1262 .current_mem_ctx = (void *)-1
1264 uint32_t highest_ofs;
1265 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1266 if (ndr.offset > ndr.relative_highest_offset) {
1267 highest_ofs = ndr.offset;
1268 } else {
1269 highest_ofs = ndr.relative_highest_offset;
1271 if (highest_ofs < ndr.data_size) {
1272 enum ndr_err_code ret;
1273 ret = ndr_pull_error(&ndr, NDR_ERR_UNREAD_BYTES,
1274 "not all bytes consumed ofs[%u] size[%u]",
1275 highest_ofs, ndr.data_size);
1276 return ret;
1278 return NDR_ERR_SUCCESS;
1282 pull a union from a blob using NDR, given the union discriminator
1284 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1285 void *p,
1286 uint32_t level, ndr_pull_flags_fn_t fn)
1288 struct ndr_pull *ndr;
1289 ndr = ndr_pull_init_blob(blob, mem_ctx);
1290 NDR_ERR_HAVE_NO_MEMORY(ndr);
1291 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1292 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1293 talloc_free(ndr);
1294 return NDR_ERR_SUCCESS;
1298 pull a union from a blob using NDR, given the union discriminator,
1299 failing if all bytes are not consumed
1301 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1302 void *p,
1303 uint32_t level, ndr_pull_flags_fn_t fn)
1305 struct ndr_pull *ndr;
1306 uint32_t highest_ofs;
1307 ndr = ndr_pull_init_blob(blob, mem_ctx);
1308 NDR_ERR_HAVE_NO_MEMORY(ndr);
1309 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1310 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1311 if (ndr->offset > ndr->relative_highest_offset) {
1312 highest_ofs = ndr->offset;
1313 } else {
1314 highest_ofs = ndr->relative_highest_offset;
1316 if (highest_ofs < ndr->data_size) {
1317 enum ndr_err_code ret;
1318 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1319 "not all bytes consumed ofs[%u] size[%u]",
1320 highest_ofs, ndr->data_size);
1321 talloc_free(ndr);
1322 return ret;
1324 talloc_free(ndr);
1325 return NDR_ERR_SUCCESS;
1329 push a struct to a blob using NDR
1331 _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)
1333 struct ndr_push *ndr;
1334 ndr = ndr_push_init_ctx(mem_ctx);
1335 NDR_ERR_HAVE_NO_MEMORY(ndr);
1337 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1339 *blob = ndr_push_blob(ndr);
1340 talloc_steal(mem_ctx, blob->data);
1341 talloc_free(ndr);
1343 return NDR_ERR_SUCCESS;
1347 push a struct into a provided blob using NDR.
1349 We error because we want to have the performance issue (extra
1350 talloc() calls) show up as an error, not just slower code. This is
1351 used for things like GUIDs, which we expect to be a fixed size, and
1352 SIDs that we can pre-calculate the size for.
1354 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1355 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1357 struct ndr_push ndr = {
1358 .data = blob->data,
1359 .alloc_size = blob->length,
1360 .fixed_buf_size = true
1363 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1365 if (ndr.offset != blob->length) {
1366 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1367 "buffer was either to large or small "
1368 "ofs[%u] size[%zu]",
1369 ndr.offset, blob->length);
1372 return NDR_ERR_SUCCESS;
1376 push a union to a blob using NDR
1378 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1379 uint32_t level, ndr_push_flags_fn_t fn)
1381 struct ndr_push *ndr;
1382 ndr = ndr_push_init_ctx(mem_ctx);
1383 NDR_ERR_HAVE_NO_MEMORY(ndr);
1385 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1386 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1388 *blob = ndr_push_blob(ndr);
1389 talloc_steal(mem_ctx, blob->data);
1390 talloc_free(ndr);
1392 return NDR_ERR_SUCCESS;
1396 generic ndr_size_*() handler for structures
1398 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1400 struct ndr_push *ndr;
1401 enum ndr_err_code status;
1402 size_t ret;
1404 /* avoid recursion */
1405 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1407 ndr = ndr_push_init_ctx(NULL);
1408 if (!ndr) return 0;
1409 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1410 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1411 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1412 talloc_free(ndr);
1413 return 0;
1415 ret = ndr->offset;
1416 talloc_free(ndr);
1417 return ret;
1421 generic ndr_size_*() handler for unions
1423 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1425 struct ndr_push *ndr;
1426 enum ndr_err_code status;
1427 size_t ret;
1429 /* avoid recursion */
1430 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1432 ndr = ndr_push_init_ctx(NULL);
1433 if (!ndr) return 0;
1434 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1436 status = ndr_push_set_switch_value(ndr, p, level);
1437 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1438 talloc_free(ndr);
1439 return 0;
1441 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1442 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1443 talloc_free(ndr);
1444 return 0;
1446 ret = ndr->offset;
1447 talloc_free(ndr);
1448 return ret;
1452 get the current base for relative pointers for the push
1454 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1456 return ndr->relative_base_offset;
1460 restore the old base for relative pointers for the push
1462 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1464 ndr->relative_base_offset = offset;
1468 setup the current base for relative pointers for the push
1469 called in the NDR_SCALAR stage
1471 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1473 ndr->relative_base_offset = offset;
1474 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1478 setup the current base for relative pointers for the push
1479 called in the NDR_BUFFERS stage
1481 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1483 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1487 push a relative object - stage1
1488 this is called during SCALARS processing
1490 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1492 if (p == NULL) {
1493 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1494 return NDR_ERR_SUCCESS;
1496 NDR_CHECK(ndr_push_align(ndr, 4));
1497 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1498 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1502 push a short relative object - stage1
1503 this is called during SCALARS processing
1505 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1507 if (p == NULL) {
1508 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1509 return NDR_ERR_SUCCESS;
1511 NDR_CHECK(ndr_push_align(ndr, 2));
1512 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1513 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1516 push a relative object - stage2
1517 this is called during buffers processing
1519 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1521 uint32_t save_offset;
1522 uint32_t ptr_offset = 0xFFFFFFFF;
1523 if (p == NULL) {
1524 return NDR_ERR_SUCCESS;
1526 save_offset = ndr->offset;
1527 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1528 if (ptr_offset > ndr->offset) {
1529 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1530 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1531 ptr_offset, ndr->offset);
1533 ndr->offset = ptr_offset;
1534 if (save_offset < ndr->relative_base_offset) {
1535 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1536 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1537 save_offset, ndr->relative_base_offset);
1539 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1540 ndr->offset = save_offset;
1541 return NDR_ERR_SUCCESS;
1544 push a short relative object - stage2
1545 this is called during buffers processing
1547 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1549 uint32_t save_offset;
1550 uint32_t ptr_offset = 0xFFFF;
1551 uint32_t relative_offset;
1552 size_t pad;
1553 size_t align = 1;
1555 if (p == NULL) {
1556 return NDR_ERR_SUCCESS;
1559 if (ndr->offset < ndr->relative_base_offset) {
1560 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1561 "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
1562 ndr->offset, ndr->relative_base_offset);
1565 relative_offset = ndr->offset - ndr->relative_base_offset;
1567 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1568 align = 1;
1569 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1570 align = 2;
1571 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1572 align = 4;
1573 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1574 align = 8;
1577 pad = ndr_align_size(relative_offset, align);
1578 if (pad != 0) {
1579 NDR_CHECK(ndr_push_zero(ndr, pad));
1582 relative_offset = ndr->offset - ndr->relative_base_offset;
1583 if (relative_offset > UINT16_MAX) {
1584 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1585 "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
1586 relative_offset);
1589 save_offset = ndr->offset;
1590 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1591 if (ptr_offset > ndr->offset) {
1592 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1593 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1594 ptr_offset, ndr->offset);
1596 ndr->offset = ptr_offset;
1597 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1598 ndr->offset = save_offset;
1599 return NDR_ERR_SUCCESS;
1603 push a relative object - stage2 start
1604 this is called during buffers processing
1606 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1608 if (p == NULL) {
1609 return NDR_ERR_SUCCESS;
1611 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1612 uint32_t relative_offset;
1613 size_t pad;
1614 size_t align = 1;
1616 if (ndr->offset < ndr->relative_base_offset) {
1617 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1618 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1619 ndr->offset, ndr->relative_base_offset);
1622 relative_offset = ndr->offset - ndr->relative_base_offset;
1624 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1625 align = 1;
1626 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1627 align = 2;
1628 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1629 align = 4;
1630 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1631 align = 8;
1634 pad = ndr_align_size(relative_offset, align);
1635 if (pad) {
1636 NDR_CHECK(ndr_push_zero(ndr, pad));
1639 return ndr_push_relative_ptr2(ndr, p);
1641 if (ndr->relative_end_offset == -1) {
1642 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1643 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1644 ndr->relative_end_offset);
1646 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
1647 return NDR_ERR_SUCCESS;
1651 push a relative object - stage2 end
1652 this is called during buffers processing
1654 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1656 uint32_t begin_offset = 0xFFFFFFFF;
1657 ssize_t len;
1658 uint32_t correct_offset = 0;
1659 uint32_t align = 1;
1660 uint32_t pad = 0;
1662 if (p == NULL) {
1663 return NDR_ERR_SUCCESS;
1666 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1667 return NDR_ERR_SUCCESS;
1670 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1671 /* better say more than calculation a too small buffer */
1672 NDR_PUSH_ALIGN(ndr, 8);
1673 return NDR_ERR_SUCCESS;
1676 if (ndr->relative_end_offset < ndr->offset) {
1677 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1678 "ndr_push_relative_ptr2_end:"
1679 "relative_end_offset %u < offset %u",
1680 ndr->relative_end_offset, ndr->offset);
1683 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1685 /* we have marshalled a buffer, see how long it was */
1686 len = ndr->offset - begin_offset;
1688 if (len < 0) {
1689 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1690 "ndr_push_relative_ptr2_end:"
1691 "offset %u - begin_offset %u < 0",
1692 ndr->offset, begin_offset);
1695 if (ndr->relative_end_offset < len) {
1696 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1697 "ndr_push_relative_ptr2_end:"
1698 "relative_end_offset %u < len %lld",
1699 ndr->offset, (long long)len);
1702 /* the reversed offset is at the end of the main buffer */
1703 correct_offset = ndr->relative_end_offset - len;
1705 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1706 align = 1;
1707 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1708 align = 2;
1709 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1710 align = 4;
1711 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1712 align = 8;
1715 pad = ndr_align_size(correct_offset, align);
1716 if (pad) {
1717 correct_offset += pad;
1718 correct_offset -= align;
1721 if (correct_offset < begin_offset) {
1722 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1723 "ndr_push_relative_ptr2_end: "
1724 "correct_offset %u < begin_offset %u",
1725 correct_offset, begin_offset);
1728 if (len > 0) {
1729 uint32_t clear_size = correct_offset - begin_offset;
1731 clear_size = MIN(clear_size, len);
1733 /* now move the marshalled buffer to the end of the main buffer */
1734 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1736 if (clear_size) {
1737 /* and wipe out old buffer within the main buffer */
1738 memset(ndr->data + begin_offset, '\0', clear_size);
1742 /* and set the end offset for the next buffer */
1743 ndr->relative_end_offset = correct_offset;
1745 /* finally write the offset to the main buffer */
1746 ndr->offset = correct_offset;
1747 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1749 /* restore to where we were in the main buffer */
1750 ndr->offset = begin_offset;
1752 return NDR_ERR_SUCCESS;
1756 get the current base for relative pointers for the pull
1758 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1760 return ndr->relative_base_offset;
1764 restore the old base for relative pointers for the pull
1766 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1768 ndr->relative_base_offset = offset;
1772 setup the current base for relative pointers for the pull
1773 called in the NDR_SCALAR stage
1775 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1777 ndr->relative_base_offset = offset;
1778 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1782 setup the current base for relative pointers for the pull
1783 called in the NDR_BUFFERS stage
1785 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1787 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1791 pull a relative object - stage1
1792 called during SCALARS processing
1794 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1796 rel_offset += ndr->relative_base_offset;
1797 if (rel_offset > ndr->data_size) {
1798 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1799 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1800 rel_offset, ndr->data_size);
1802 return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1806 pull a relative object - stage2
1807 called during BUFFERS processing
1809 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1811 uint32_t rel_offset;
1812 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1813 return ndr_pull_set_offset(ndr, rel_offset);
1816 const static struct {
1817 enum ndr_err_code err;
1818 const char *string;
1819 } ndr_err_code_strings[] = {
1820 { NDR_ERR_SUCCESS, "Success" },
1821 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1822 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1823 { NDR_ERR_OFFSET, "Offset Error" },
1824 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1825 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1826 { NDR_ERR_LENGTH, "Length Error" },
1827 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1828 { NDR_ERR_COMPRESSION, "Compression Error" },
1829 { NDR_ERR_STRING, "String Error" },
1830 { NDR_ERR_VALIDATE, "Validate Error" },
1831 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1832 { NDR_ERR_ALLOC, "Allocation Error" },
1833 { NDR_ERR_RANGE, "Range Error" },
1834 { NDR_ERR_TOKEN, "Token Error" },
1835 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1836 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1837 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1838 { NDR_ERR_NDR64, "NDR64 assertion error" },
1839 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1840 { 0, NULL }
1843 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1845 int i;
1846 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1847 if (ndr_err_code_strings[i].err == ndr_err)
1848 return ndr_err_code_strings[i].string;
1850 return "Unknown error";