libndr: Use UINT32_MAX -- no need to count F's
[samba4-gss.git] / librpc / ndr / ndr.c
blob918b76713cad592260fd64149e7fd6ba942bf718
1 /*
2 Unix SMB/CIFS implementation.
4 libndr interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2005-2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 this provides the core routines for NDR parsing functions
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
27 of NDR encoding rules
30 #include "includes.h"
31 #include "librpc/ndr/libndr.h"
32 #include "librpc/ndr/ndr_private.h"
33 #include "../lib/util/dlinklist.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_RPC_PARSE
38 #define NDR_BASE_MARSHALL_SIZE 1024
41 * This value is arbitrary, but designed to reduce the memory a client
42 * can allocate and the work the client can force in processing a
43 * malicious packet.
45 * In an ideal world this would be controlled by range() restrictions
46 * on array sizes and careful IDL construction to avoid arbitrary
47 * linked lists, but this is a backstop for now.
49 #define NDR_TOKEN_MAX_LIST_SIZE 65535
51 size_t ndr_token_max_list_size(void) {
52 return NDR_TOKEN_MAX_LIST_SIZE;
55 /* this guid indicates NDR encoding in a protocol tower */
56 const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
57 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
61 const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
62 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
66 const struct ndr_syntax_id ndr_syntax_id_null = {
67 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
72 work out the number of bytes needed to align on a n byte boundary
74 _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
76 if ((offset & (n-1)) == 0) return 0;
77 return n - (offset & (n-1));
81 initialise a ndr parse structure from a data blob
83 _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
85 struct ndr_pull *ndr;
87 ndr = talloc_zero(mem_ctx, struct ndr_pull);
88 if (!ndr) return NULL;
89 ndr->current_mem_ctx = mem_ctx;
91 ndr->data = blob->data;
92 ndr->data_size = blob->length;
94 return ndr;
97 _PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
99 enum ndr_err_code ndr_err;
100 DATA_BLOB b;
101 uint32_t append = 0;
102 bool ok;
104 if (blob->length == 0) {
105 return NDR_ERR_SUCCESS;
108 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
109 if (ndr_err == NDR_ERR_TOKEN) {
110 append = 0;
111 ndr_err = NDR_ERR_SUCCESS;
113 NDR_CHECK(ndr_err);
115 if (ndr->data_size == 0) {
116 ndr->data = NULL;
117 append = UINT32_MAX;
120 if (append == UINT32_MAX) {
122 * append == UINT32_MAX means that
123 * ndr->data is either NULL or a valid
124 * talloc child of ndr, which means
125 * we can use data_blob_append() without
126 * data_blob_talloc() of the existing callers data
128 b = data_blob_const(ndr->data, ndr->data_size);
129 } else {
130 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
131 if (b.data == NULL) {
132 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
136 ok = data_blob_append(ndr, &b, blob->data, blob->length);
137 if (!ok) {
138 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
141 ndr->data = b.data;
142 ndr->data_size = b.length;
144 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
147 _PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
149 uint32_t skip = 0;
150 uint32_t append = 0;
151 enum ndr_err_code ndr_err;
153 if (ndr->relative_base_offset != 0) {
154 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
155 "%s", __location__);
157 if (ndr->relative_highest_offset != 0) {
158 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
159 "%s", __location__);
161 if (ndr->relative_list.count != 0) {
162 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
163 "%s", __location__);
165 if (ndr->relative_base_list.count != 0) {
166 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
167 "%s", __location__);
171 * we need to keep up to 7 bytes
172 * in order to get the alignment right.
174 skip = ndr->offset & 0xFFFFFFF8;
176 if (skip == 0) {
177 return NDR_ERR_SUCCESS;
180 ndr->offset -= skip;
181 ndr->data_size -= skip;
183 ndr_err = ndr_token_peek(&ndr->array_size_list, ndr, &append);
184 if (ndr_err == NDR_ERR_TOKEN) {
186 * here we assume, that ndr->data is not a
187 * talloc child of ndr.
189 ndr->data += skip;
190 return NDR_ERR_SUCCESS;
193 memmove(ndr->data, ndr->data + skip, ndr->data_size);
195 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
196 if (ndr->data_size != 0 && ndr->data == NULL) {
197 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
200 return NDR_ERR_SUCCESS;
204 advance by 'size' bytes
206 _PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
208 NDR_PULL_NEED_BYTES(ndr, size);
209 ndr->offset += size;
210 return NDR_ERR_SUCCESS;
214 set the parse offset to 'ofs'
216 static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
218 ndr->offset = ofs;
219 if (ndr->offset > ndr->data_size) {
220 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
221 "ndr_pull_set_offset %"PRIu32" failed",
222 ofs);
224 return NDR_ERR_SUCCESS;
227 /* create a ndr_push structure, ready for some marshalling */
228 _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
230 struct ndr_push *ndr;
232 ndr = talloc_zero(mem_ctx, struct ndr_push);
233 if (!ndr) {
234 return NULL;
237 ndr->flags = 0;
238 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
239 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
240 if (!ndr->data) {
241 talloc_free(ndr);
242 return NULL;
245 return ndr;
248 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
249 _PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
251 DATA_BLOB blob;
252 blob = data_blob_const(ndr->data, ndr->offset);
253 if (ndr->alloc_size > ndr->offset) {
254 ndr->data[ndr->offset] = 0;
256 return blob;
261 expand the available space in the buffer to ndr->offset + extra_size
263 _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
265 uint32_t size = extra_size + ndr->offset;
267 if (size < ndr->offset) {
268 /* extra_size overflowed the offset */
269 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %"PRIu32,
270 size);
273 if (ndr->fixed_buf_size) {
274 if (ndr->alloc_size >= size) {
275 return NDR_ERR_SUCCESS;
277 return ndr_push_error(ndr,
278 NDR_ERR_BUFSIZE,
279 "Overflow of fixed buffer in "
280 "push_expand to %"PRIu32,
281 size);
284 if (ndr->alloc_size > size) {
285 return NDR_ERR_SUCCESS;
288 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
289 if (size == UINT32_MAX) {
290 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand");
292 if (size+1 > ndr->alloc_size) {
293 ndr->alloc_size = size+1;
295 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
296 if (!ndr->data) {
297 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %"PRIu32,
298 ndr->alloc_size);
301 return NDR_ERR_SUCCESS;
304 _PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
306 va_list ap;
307 char *s = NULL;
308 uint32_t i;
309 int ret;
310 int dbgc_class;
312 va_start(ap, format);
313 ret = vasprintf(&s, format, ap);
314 va_end(ap);
316 if (ret == -1) {
317 return;
320 dbgc_class = *(int *)ndr->private_data;
322 if (ndr->no_newline) {
323 DEBUGADDC(dbgc_class, 1,("%s", s));
324 free(s);
325 return;
328 for (i=0;i<ndr->depth;i++) {
329 DEBUGADDC(dbgc_class, 1,(" "));
332 DEBUGADDC(dbgc_class, 1,("%s\n", s));
333 free(s);
336 _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
338 va_list ap;
339 char *s = NULL;
340 uint32_t i;
341 int ret;
343 va_start(ap, format);
344 ret = vasprintf(&s, format, ap);
345 va_end(ap);
347 if (ret == -1) {
348 return;
351 if (ndr->no_newline) {
352 DEBUGADD(1,("%s", s));
353 free(s);
354 return;
357 for (i=0;i<ndr->depth;i++) {
358 DEBUGADD(1,(" "));
361 DEBUGADD(1,("%s\n", s));
362 free(s);
365 _PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
367 va_list ap;
368 uint32_t i;
370 if (!ndr->no_newline) {
371 for (i=0;i<ndr->depth;i++) {
372 printf(" ");
376 va_start(ap, format);
377 vprintf(format, ap);
378 va_end(ap);
379 if (!ndr->no_newline) {
380 printf("\n");
384 _PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
386 va_list ap;
387 uint32_t i;
389 if (!ndr->no_newline) {
390 for (i=0;i<ndr->depth;i++) {
391 ndr->private_data = talloc_asprintf_append_buffer(
392 (char *)ndr->private_data, " ");
396 va_start(ap, format);
397 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
398 format, ap);
399 va_end(ap);
400 if (!ndr->no_newline) {
401 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
402 "\n");
407 a useful helper function for printing idl structures via DEBUGC()
409 _PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
411 struct ndr_print *ndr;
413 DEBUGC(dbgc_class, 1,(" "));
415 ndr = talloc_zero(NULL, struct ndr_print);
416 if (!ndr) return;
417 ndr->private_data = &dbgc_class;
418 ndr->print = ndr_print_debugc_helper;
419 ndr->depth = 1;
420 ndr->flags = 0;
421 #ifdef DEBUG_PASSWORD
422 if (CHECK_DEBUGLVL(100)) {
423 ndr->print_secrets = true;
425 #endif
427 fn(ndr, name, ptr);
428 talloc_free(ndr);
432 a useful helper function for printing idl structures via DEBUG()
434 _PUBLIC_ bool ndr_print_debug(int level,
435 ndr_print_fn_t fn,
436 const char *name,
437 void *ptr,
438 const char *location,
439 const char *function)
441 struct ndr_print *ndr;
442 bool ret = false;
444 ndr = talloc_zero(NULL, struct ndr_print);
445 if (!ndr) return false;
446 ndr->private_data = talloc_strdup(ndr, "");
447 if (ndr->private_data == NULL) {
448 goto fail;
450 ndr->print = ndr_print_string_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 fn(ndr, name, ptr);
460 DEBUGLF(level, (" %s", (char *)ndr->private_data), location, function);
462 ret = true;
463 fail:
464 talloc_free(ndr);
465 return ret;
469 a useful helper function for printing idl unions via DEBUG()
471 _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
473 struct ndr_print *ndr;
475 DEBUG(1,(" "));
477 ndr = talloc_zero(NULL, struct ndr_print);
478 if (!ndr) return;
479 ndr->print = ndr_print_debug_helper;
480 ndr->depth = 1;
481 ndr->flags = 0;
482 #ifdef DEBUG_PASSWORD
483 if (CHECK_DEBUGLVL(100)) {
484 ndr->print_secrets = true;
486 #endif
488 ndr_print_set_switch_value(ndr, ptr, level);
489 fn(ndr, name, ptr);
490 talloc_free(ndr);
494 a useful helper function for printing idl function calls via DEBUG()
496 _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, ndr_flags_type flags, void *ptr)
498 struct ndr_print *ndr;
500 DEBUG(1,(" "));
502 ndr = talloc_zero(NULL, struct ndr_print);
503 if (!ndr) return;
504 ndr->print = ndr_print_debug_helper;
505 ndr->depth = 1;
506 ndr->flags = 0;
507 #ifdef DEBUG_PASSWORD
508 if (CHECK_DEBUGLVL(100)) {
509 ndr->print_secrets = true;
511 #endif
513 fn(ndr, name, flags, ptr);
514 talloc_free(ndr);
518 a useful helper function for printing idl structures to a string
520 _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
522 struct ndr_print *ndr;
523 char *ret = NULL;
525 ndr = talloc_zero(mem_ctx, struct ndr_print);
526 if (!ndr) return NULL;
527 ndr->private_data = talloc_strdup(ndr, "");
528 if (!ndr->private_data) {
529 goto failed;
531 ndr->print = ndr_print_string_helper;
532 ndr->depth = 1;
533 ndr->flags = 0;
535 fn(ndr, name, ptr);
536 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
537 failed:
538 talloc_free(ndr);
539 return ret;
543 a useful helper function for printing idl unions to a string
545 _PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
547 struct ndr_print *ndr;
548 char *ret = NULL;
550 ndr = talloc_zero(mem_ctx, struct ndr_print);
551 if (!ndr) return NULL;
552 ndr->private_data = talloc_strdup(ndr, "");
553 if (!ndr->private_data) {
554 goto failed;
556 ndr->print = ndr_print_string_helper;
557 ndr->depth = 1;
558 ndr->flags = 0;
559 ndr_print_set_switch_value(ndr, ptr, level);
560 fn(ndr, name, ptr);
561 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
562 failed:
563 talloc_free(ndr);
564 return ret;
568 a useful helper function for printing idl function calls to a string
570 _PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
571 ndr_print_function_t fn, const char *name,
572 ndr_flags_type flags, void *ptr)
574 struct ndr_print *ndr;
575 char *ret = NULL;
577 ndr = talloc_zero(mem_ctx, struct ndr_print);
578 if (!ndr) return NULL;
579 ndr->private_data = talloc_strdup(ndr, "");
580 if (!ndr->private_data) {
581 goto failed;
583 ndr->print = ndr_print_string_helper;
584 ndr->depth = 1;
585 ndr->flags = 0;
586 fn(ndr, name, flags, ptr);
587 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
588 failed:
589 talloc_free(ndr);
590 return ret;
593 _PUBLIC_ void ndr_set_flags(libndr_flags *pflags, libndr_flags new_flags)
595 /* the big/little endian flags are inter-dependent */
596 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
597 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
598 (*pflags) &= ~LIBNDR_FLAG_NDR64;
600 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
601 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
602 (*pflags) &= ~LIBNDR_FLAG_NDR64;
604 if (new_flags & LIBNDR_ALIGN_FLAGS) {
605 /* Ensure we only have the passed-in
606 align flag set in the new_flags,
607 remove any old align flag. */
608 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
610 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
611 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
613 (*pflags) |= new_flags;
617 return and possibly log an NDR error
619 _PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
620 enum ndr_err_code ndr_err,
621 const char *function,
622 const char *location,
623 const char *format, ...)
625 char *s=NULL;
626 va_list ap;
627 int ret;
629 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
630 switch (ndr_err) {
631 case NDR_ERR_BUFSIZE:
632 return NDR_ERR_INCOMPLETE_BUFFER;
633 default:
634 break;
638 va_start(ap, format);
639 ret = vasprintf(&s, format, ap);
640 va_end(ap);
642 if (ret == -1) {
643 return NDR_ERR_ALLOC;
646 D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
647 function,
648 ndr_map_error2string(ndr_err),
650 location);
652 free(s);
654 return ndr_err;
658 return and possibly log an NDR error
660 _PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
661 enum ndr_err_code ndr_err,
662 const char *function,
663 const char *location,
664 const char *format, ...)
666 char *s=NULL;
667 va_list ap;
668 int ret;
670 va_start(ap, format);
671 ret = vasprintf(&s, format, ap);
672 va_end(ap);
674 if (ret == -1) {
675 return NDR_ERR_ALLOC;
678 D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
679 function,
680 ndr_map_error2string(ndr_err),
682 location);
684 free(s);
686 return ndr_err;
690 handle subcontext buffers, which in midl land are user-marshalled, but
691 we use magic in pidl to make them easier to cope with
693 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
694 struct ndr_pull **_subndr,
695 size_t header_size,
696 ssize_t size_is)
698 struct ndr_pull *subndr;
699 uint32_t r_content_size;
700 bool force_le = false;
701 bool force_be = false;
703 switch (header_size) {
704 case 0: {
705 uint32_t content_size = ndr->data_size - ndr->offset;
706 if (size_is >= 0) {
707 content_size = size_is;
709 r_content_size = content_size;
710 break;
713 case 2: {
714 uint16_t content_size;
715 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
716 if (size_is >= 0 && size_is != content_size) {
717 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%04zx) mismatch content_size %"PRIu16" (0x%04"PRIx16")",
718 size_is, size_is,
719 content_size,
720 content_size);
722 r_content_size = content_size;
723 break;
726 case 4: {
727 uint32_t content_size;
728 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
729 if (size_is >= 0 && size_is != content_size) {
730 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%08zx) mismatch content_size %"PRIu32" (0x%08"PRIx32")",
731 size_is, size_is,
732 content_size,
733 content_size);
735 r_content_size = content_size;
736 break;
738 case 0xFFFFFC01: {
740 * Common Type Header for the Serialization Stream
741 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
743 uint8_t version;
744 uint8_t drep;
745 uint16_t hdrlen;
746 uint32_t filler;
747 uint32_t content_size;
748 uint32_t reserved;
750 /* version */
751 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
753 if (version != 1) {
754 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
755 "Bad subcontext (PULL) Common Type Header version %"PRIu8" != 1",
756 version);
760 * 0x10 little endian
761 * 0x00 big endian
763 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
764 if (drep == 0x10) {
765 force_le = true;
766 } else if (drep == 0x00) {
767 force_be = true;
768 } else {
769 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
770 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02"PRIX8,
771 drep);
774 /* length of the "Private Header for Constructed Type" */
775 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
776 if (hdrlen != 8) {
777 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
778 "Bad subcontext (PULL) Common Type Header length %"PRIu16" != 8",
779 hdrlen);
782 /* filler should be ignored */
783 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
786 * Private Header for Constructed Type
788 /* length - will be updated later */
789 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
790 if (size_is >= 0 && size_is != content_size) {
791 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) mismatch content_size %"PRIu32,
792 size_is, content_size);
794 /* the content size must be a multiple of 8 */
795 if ((content_size % 8) != 0) {
796 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
797 "Bad subcontext (PULL) size_is(%zd) not padded to 8 content_size %"PRIu32,
798 size_is, content_size);
800 r_content_size = content_size;
802 /* reserved */
803 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
804 break;
806 case 0xFFFFFFFF:
808 * a shallow copy like subcontext
809 * useful for DCERPC pipe chunks.
811 subndr = talloc_zero(ndr, struct ndr_pull);
812 NDR_ERR_HAVE_NO_MEMORY(subndr);
814 subndr->flags = ndr->flags;
815 subndr->current_mem_ctx = ndr->current_mem_ctx;
816 subndr->data = ndr->data;
817 subndr->offset = ndr->offset;
818 subndr->data_size = ndr->data_size;
820 *_subndr = subndr;
821 return NDR_ERR_SUCCESS;
823 default:
824 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %zu",
825 header_size);
828 NDR_PULL_NEED_BYTES(ndr, r_content_size);
830 subndr = talloc_zero(ndr, struct ndr_pull);
831 NDR_ERR_HAVE_NO_MEMORY(subndr);
832 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
833 subndr->current_mem_ctx = ndr->current_mem_ctx;
835 subndr->data = ndr->data + ndr->offset;
836 subndr->offset = 0;
837 subndr->data_size = r_content_size;
839 if (force_le) {
840 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
841 } else if (force_be) {
842 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
845 *_subndr = subndr;
846 return NDR_ERR_SUCCESS;
849 _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
850 struct ndr_pull *subndr,
851 size_t header_size,
852 ssize_t size_is)
854 uint32_t advance;
855 uint32_t highest_ofs;
857 if (header_size == 0xFFFFFFFF) {
858 advance = subndr->offset - ndr->offset;
859 } else if (size_is >= 0) {
860 advance = size_is;
861 } else if (header_size > 0) {
862 advance = subndr->data_size;
863 } else {
864 advance = subndr->offset;
867 if (subndr->offset > ndr->relative_highest_offset) {
868 highest_ofs = subndr->offset;
869 } else {
870 highest_ofs = subndr->relative_highest_offset;
872 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
874 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
876 highest_ofs = advance;
878 if (highest_ofs < advance) {
879 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
880 "not all bytes consumed ofs[%"PRIu32"] advance[%"PRIu32"]",
881 highest_ofs, advance);
884 NDR_CHECK(ndr_pull_advance(ndr, advance));
885 return NDR_ERR_SUCCESS;
888 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
889 struct ndr_push **_subndr,
890 size_t header_size,
891 ssize_t size_is)
893 struct ndr_push *subndr;
895 subndr = ndr_push_init_ctx(ndr);
896 NDR_ERR_HAVE_NO_MEMORY(subndr);
897 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
899 if (size_is > 0) {
900 enum ndr_err_code status;
902 status = ndr_push_zero(subndr, size_is);
903 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
904 talloc_free(subndr);
905 return status;
907 subndr->offset = 0;
908 subndr->relative_end_offset = size_is;
911 *_subndr = subndr;
912 return NDR_ERR_SUCCESS;
916 push a subcontext header
918 _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
919 struct ndr_push *subndr,
920 size_t header_size,
921 ssize_t size_is)
923 ssize_t padding_len;
925 if (size_is >= 0) {
926 padding_len = size_is - subndr->offset;
927 if (padding_len < 0) {
928 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %"PRIu32" is larger than size_is(%zd)",
929 subndr->offset, size_is);
931 subndr->offset = size_is;
934 switch (header_size) {
935 case 0:
936 break;
938 case 2:
939 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
940 break;
942 case 4:
943 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
944 break;
946 case 0xFFFFFC01:
948 * Common Type Header for the Serialization Stream
949 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
951 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
952 if (padding_len > 0) {
953 NDR_CHECK(ndr_push_zero(subndr, padding_len));
956 /* version */
957 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
960 * 0x10 little endian
961 * 0x00 big endian
963 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
965 /* length of the "Private Header for Constructed Type" */
966 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
968 /* filler */
969 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
972 * Private Header for Constructed Type
974 /* length - will be updated later */
975 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
977 /* reserved */
978 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
979 break;
981 default:
982 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %zu",
983 header_size);
986 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
987 return NDR_ERR_SUCCESS;
991 struct ndr_token {
992 const void *key;
993 uint32_t value;
997 store a token in the ndr context, for later retrieval
999 _PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
1000 struct ndr_token_list *list,
1001 const void *key,
1002 uint32_t value)
1004 if (list->tokens == NULL) {
1005 list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
1006 if (list->tokens == NULL) {
1007 NDR_ERR_HAVE_NO_MEMORY(list->tokens);
1009 } else {
1010 struct ndr_token *new_tokens = NULL;
1011 uint32_t alloc_count = talloc_array_length(list->tokens);
1014 * Check every time we have not allocated too many
1015 * tokens. This ensures developer sanity when
1016 * debugging the boundary condition
1018 if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
1019 return NDR_ERR_RANGE;
1021 if (list->count == alloc_count) {
1022 uint32_t new_alloc;
1024 * Double the list, until we start in chunks
1025 * of 1000
1027 uint32_t increment = MIN(list->count, 1000);
1028 new_alloc = alloc_count + increment;
1029 if (new_alloc < alloc_count) {
1030 return NDR_ERR_RANGE;
1032 new_tokens = talloc_realloc(mem_ctx, list->tokens,
1033 struct ndr_token, new_alloc);
1034 NDR_ERR_HAVE_NO_MEMORY(new_tokens);
1035 list->tokens = new_tokens;
1038 list->tokens[list->count].key = key;
1039 list->tokens[list->count].value = value;
1040 list->count++;
1041 return NDR_ERR_SUCCESS;
1045 retrieve a token from a ndr context, using cmp_fn to match the tokens
1047 static enum ndr_err_code ndr_token_find(struct ndr_token_list *list,
1048 const void *key,
1049 uint32_t *v,
1050 comparison_fn_t _cmp_fn,
1051 unsigned *_i)
1053 struct ndr_token *tokens = list->tokens;
1054 unsigned i;
1055 for (i = list->count - 1; i < list->count; i--) {
1056 if (_cmp_fn(tokens[i].key, key) == 0) {
1057 *_i = i;
1058 *v = tokens[i].value;
1059 return NDR_ERR_SUCCESS;
1062 return NDR_ERR_TOKEN;
1065 _PUBLIC_ enum ndr_err_code ndr_token_peek_cmp_fn(struct ndr_token_list *list,
1066 const void *key,
1067 uint32_t *v,
1068 comparison_fn_t _cmp_fn)
1070 unsigned i;
1071 return ndr_token_find(list, key, v, _cmp_fn, &i);
1074 static int token_cmp_ptr(const void *a, const void *b)
1076 return (a == b) ? 0 : 1;
1080 retrieve a token from a ndr context
1082 _PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
1083 const void *key, uint32_t *v)
1085 enum ndr_err_code err;
1086 uint32_t last;
1087 unsigned i;
1089 err = ndr_token_find(list, key, v, token_cmp_ptr, &i);
1090 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
1091 return err;
1094 last = list->count - 1;
1095 if (i != last) {
1096 list->tokens[i] = list->tokens[last];
1098 list->count--;
1100 return NDR_ERR_SUCCESS;
1104 peek at but don't removed a token from a ndr context
1106 _PUBLIC_ enum ndr_err_code ndr_token_peek(struct ndr_token_list *list,
1107 const void *key, uint32_t *v)
1109 unsigned i;
1110 return ndr_token_find(list, key, v, token_cmp_ptr, &i);
1114 pull an array size field and add it to the array_size_list token list
1116 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
1118 enum ndr_err_code ret;
1119 uint32_t size;
1120 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
1121 ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
1122 if (ret == NDR_ERR_RANGE) {
1123 return ndr_pull_error(ndr, ret,
1124 "More than %d NDR tokens stored for array_size",
1125 NDR_TOKEN_MAX_LIST_SIZE);
1127 return ret;
1131 get the stored array size field
1133 _PUBLIC_ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1135 return ndr_token_peek(&ndr->array_size_list, p, size);
1139 get and remove from the stored list the stored array size field
1141 _PUBLIC_ enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
1143 return ndr_token_retrieve(&ndr->array_size_list, p, size);
1147 * check the stored array size field and remove from the stored list
1148 * (the array_size NDR token list). We try to remove when possible to
1149 * avoid the list growing towards the bounds check
1151 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1153 uint32_t stored;
1154 NDR_CHECK(ndr_steal_array_size(ndr, p, &stored));
1155 if (stored != size) {
1156 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1157 "Bad array size - got %u expected %u\n",
1158 stored, size);
1160 return NDR_ERR_SUCCESS;
1164 * check the stored array size field (leaving it on the array_size
1165 * token list)
1167 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
1169 uint32_t stored;
1170 NDR_CHECK(ndr_get_array_size(ndr, p, &stored));
1171 if (stored != size) {
1172 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1173 "Bad array size - got %"PRIu32" expected %"PRIu32"\n",
1174 stored, size);
1176 return NDR_ERR_SUCCESS;
1180 pull an array length field and add it to the array_length_list token list
1182 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1184 enum ndr_err_code ret;
1185 uint32_t length, offset;
1186 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1187 if (offset != 0) {
1188 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1189 "non-zero array offset %"PRIu32"\n", offset);
1191 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1192 ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
1193 if (ret == NDR_ERR_RANGE) {
1194 return ndr_pull_error(ndr, ret,
1195 "More than %d NDR tokens stored for array_length_list",
1196 NDR_TOKEN_MAX_LIST_SIZE);
1198 return ret;
1202 get the stored array length field
1204 _PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1206 return ndr_token_peek(&ndr->array_length_list, p, length);
1210 * check the stored array length field and remove from the stored list
1211 * (the array_size NDR token list). We try to remove when possible to
1212 * avoid the list growing towards the bounds check
1214 _PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
1216 return ndr_token_retrieve(&ndr->array_length_list, p, length);
1219 check the stored array length field, removing it from the list
1221 _PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
1223 uint32_t stored;
1224 NDR_CHECK(ndr_steal_array_length(ndr, p, &stored));
1225 if (stored != length) {
1226 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1227 "Bad array length: got %"PRIu32" expected %"PRIu32"\n",
1228 stored, length);
1230 return NDR_ERR_SUCCESS;
1233 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t count)
1235 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1236 int64_t tmp = 0 - (int64_t)count;
1237 uint64_t ncount = tmp;
1239 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1242 return NDR_ERR_SUCCESS;
1245 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t count)
1247 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1248 int64_t tmp = 0 - (int64_t)count;
1249 uint64_t ncount1 = tmp;
1250 uint64_t ncount2;
1252 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1253 if (ncount1 == ncount2) {
1254 return NDR_ERR_SUCCESS;
1257 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1258 "Bad pipe trailer[%"PRIu64" should be %"PRIu64"] size was %"PRIu32"\"",
1259 ncount2,
1260 ncount1,
1261 count);
1264 return NDR_ERR_SUCCESS;
1268 store a switch value
1270 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1272 enum ndr_err_code ret =
1273 ndr_token_store(ndr, &ndr->switch_list, p, val);
1274 if (ret == NDR_ERR_RANGE) {
1275 return ndr_push_error(ndr, ret,
1276 "More than %d NDR tokens stored for switch_list",
1277 NDR_TOKEN_MAX_LIST_SIZE);
1279 return ret;
1282 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1285 enum ndr_err_code ret =
1286 ndr_token_store(ndr, &ndr->switch_list, p, val);
1287 if (ret == NDR_ERR_RANGE) {
1288 return ndr_pull_error(ndr, ret,
1289 "More than %d NDR tokens stored for switch_list",
1290 NDR_TOKEN_MAX_LIST_SIZE);
1292 return ret;
1295 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1297 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1300 /* retrieve a switch value (for push) and remove it from the list */
1301 _PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
1302 const void *p,
1303 uint32_t *v)
1305 return ndr_token_retrieve(&ndr->switch_list, p, v);
1308 /* retrieve a switch value and remove it from the list */
1309 _PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
1311 enum ndr_err_code status;
1312 uint32_t v;
1314 status = ndr_token_retrieve(&ndr->switch_list, p, &v);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1316 return 0;
1319 return v;
1322 /* retrieve a switch value and remove it from the list */
1323 _PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
1324 const void *p,
1325 uint32_t *v)
1327 return ndr_token_retrieve(&ndr->switch_list, p, v);
1331 pull a struct from a blob using NDR
1333 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1334 ndr_pull_flags_fn_t fn)
1336 struct ndr_pull *ndr;
1337 ndr = ndr_pull_init_blob(blob, mem_ctx);
1338 NDR_ERR_HAVE_NO_MEMORY(ndr);
1339 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1340 talloc_free(ndr);
1341 return NDR_ERR_SUCCESS;
1345 pull a struct from a blob using NDR - failing if all bytes are not consumed
1347 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1348 void *p, ndr_pull_flags_fn_t fn)
1350 struct ndr_pull *ndr;
1351 uint32_t highest_ofs;
1352 ndr = ndr_pull_init_blob(blob, mem_ctx);
1353 NDR_ERR_HAVE_NO_MEMORY(ndr);
1354 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1355 if (ndr->offset > ndr->relative_highest_offset) {
1356 highest_ofs = ndr->offset;
1357 } else {
1358 highest_ofs = ndr->relative_highest_offset;
1360 if (highest_ofs < ndr->data_size) {
1361 enum ndr_err_code ret;
1362 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1363 "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]",
1364 highest_ofs, ndr->data_size);
1365 talloc_free(ndr);
1366 return ret;
1368 talloc_free(ndr);
1369 return NDR_ERR_SUCCESS;
1373 * pull a struct from a blob using NDR
1375 * This only works for structures with NO allocated memory, like
1376 * objectSID and GUID. This helps because we parse these a lot.
1378 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf,
1379 size_t buflen,
1380 void *p,
1381 ndr_pull_flags_fn_t fn,
1382 size_t *consumed)
1385 * We init this structure on the stack here, to avoid a
1386 * talloc() as otherwise this call to the fn() is assured not
1387 * to be doing any allocation, eg SIDs and GUIDs.
1389 * This allows us to keep the safety of the PIDL-generated
1390 * code without the talloc() overhead.
1392 struct ndr_pull ndr = {
1393 .data = discard_const_p(uint8_t, buf),
1394 .data_size = buflen,
1395 .current_mem_ctx = (void *)-1,
1398 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1399 *consumed = MAX(ndr.offset, ndr.relative_highest_offset);
1401 return NDR_ERR_SUCCESS;
1405 pull a struct from a blob using NDR - failing if all bytes are not consumed
1407 This only works for structures with NO allocated memory, like
1408 objectSID and GUID. This helps because we parse these a lot.
1410 _PUBLIC_ enum ndr_err_code
1411 ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
1412 void *p,
1413 ndr_pull_flags_fn_t fn)
1415 size_t consumed;
1416 enum ndr_err_code ndr_err;
1418 ndr_err = ndr_pull_struct_blob_noalloc(blob->data,
1419 blob->length,
1422 &consumed);
1423 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1424 return ndr_err;
1427 if (consumed < blob->length) {
1428 D_WARNING("not all bytes consumed ofs[%zu] size[%zu]",
1429 consumed,
1430 blob->length);
1431 return NDR_ERR_UNREAD_BYTES;
1434 return NDR_ERR_SUCCESS;
1438 pull a union from a blob using NDR, given the union discriminator
1440 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1441 void *p,
1442 uint32_t level, ndr_pull_flags_fn_t fn)
1444 struct ndr_pull *ndr;
1445 ndr = ndr_pull_init_blob(blob, mem_ctx);
1446 NDR_ERR_HAVE_NO_MEMORY(ndr);
1447 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1448 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1449 talloc_free(ndr);
1450 return NDR_ERR_SUCCESS;
1454 pull a union from a blob using NDR, given the union discriminator,
1455 failing if all bytes are not consumed
1457 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1458 void *p,
1459 uint32_t level, ndr_pull_flags_fn_t fn)
1461 struct ndr_pull *ndr;
1462 uint32_t highest_ofs;
1463 ndr = ndr_pull_init_blob(blob, mem_ctx);
1464 NDR_ERR_HAVE_NO_MEMORY(ndr);
1465 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1466 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1467 if (ndr->offset > ndr->relative_highest_offset) {
1468 highest_ofs = ndr->offset;
1469 } else {
1470 highest_ofs = ndr->relative_highest_offset;
1472 if (highest_ofs < ndr->data_size) {
1473 enum ndr_err_code ret;
1474 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1475 "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]",
1476 highest_ofs, ndr->data_size);
1477 talloc_free(ndr);
1478 return ret;
1480 talloc_free(ndr);
1481 return NDR_ERR_SUCCESS;
1485 push a struct to a blob using NDR
1487 _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)
1489 struct ndr_push *ndr;
1490 ndr = ndr_push_init_ctx(mem_ctx);
1491 NDR_ERR_HAVE_NO_MEMORY(ndr);
1493 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1495 *blob = ndr_push_blob(ndr);
1496 talloc_steal(mem_ctx, blob->data);
1497 talloc_free(ndr);
1499 return NDR_ERR_SUCCESS;
1503 push a struct into a provided blob using NDR.
1505 We error because we want to have the performance issue (extra
1506 talloc() calls) show up as an error, not just slower code. This is
1507 used for things like GUIDs, which we expect to be a fixed size, and
1508 SIDs that we can pre-calculate the size for.
1510 _PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
1511 DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
1513 struct ndr_push ndr = {
1514 .data = blob->data,
1515 .alloc_size = blob->length,
1516 .fixed_buf_size = true
1519 NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
1521 if (ndr.offset != blob->length) {
1522 return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
1523 "buffer was either too large or small "
1524 "ofs[%"PRIu32"] size[%zu]",
1525 ndr.offset, blob->length);
1528 return NDR_ERR_SUCCESS;
1532 push a union to a blob using NDR
1534 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1535 uint32_t level, ndr_push_flags_fn_t fn)
1537 struct ndr_push *ndr;
1538 ndr = ndr_push_init_ctx(mem_ctx);
1539 NDR_ERR_HAVE_NO_MEMORY(ndr);
1541 NDR_CHECK_FREE(ndr_push_set_switch_value(ndr, p, level));
1542 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1544 *blob = ndr_push_blob(ndr);
1545 talloc_steal(mem_ctx, blob->data);
1546 talloc_free(ndr);
1548 return NDR_ERR_SUCCESS;
1552 generic ndr_size_*() handler for structures
1554 _PUBLIC_ size_t ndr_size_struct(const void *p, libndr_flags flags, ndr_push_flags_fn_t push)
1556 struct ndr_push *ndr;
1557 enum ndr_err_code status;
1558 size_t ret;
1560 /* avoid recursion */
1561 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1563 /* Avoid following a NULL pointer */
1564 if (p == NULL) {
1565 return 0;
1568 ndr = ndr_push_init_ctx(NULL);
1569 if (!ndr) return 0;
1570 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1571 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1572 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1573 talloc_free(ndr);
1574 return 0;
1576 ret = ndr->offset;
1577 talloc_free(ndr);
1578 return ret;
1582 generic ndr_size_*() handler for unions
1584 _PUBLIC_ size_t ndr_size_union(const void *p, libndr_flags flags, uint32_t level, ndr_push_flags_fn_t push)
1586 struct ndr_push *ndr;
1587 enum ndr_err_code status;
1588 size_t ret;
1590 /* avoid recursion */
1591 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1593 /* Avoid following a NULL pointer */
1594 if (p == NULL) {
1595 return 0;
1598 ndr = ndr_push_init_ctx(NULL);
1599 if (!ndr) return 0;
1600 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1602 status = ndr_push_set_switch_value(ndr, p, level);
1603 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1604 talloc_free(ndr);
1605 return 0;
1607 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1608 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1609 talloc_free(ndr);
1610 return 0;
1612 ret = ndr->offset;
1613 talloc_free(ndr);
1614 return ret;
1618 get the current base for relative pointers for the push
1620 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1622 return ndr->relative_base_offset;
1626 restore the old base for relative pointers for the push
1628 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1630 ndr->relative_base_offset = offset;
1634 setup the current base for relative pointers for the push
1635 called in the NDR_SCALAR stage
1637 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1639 enum ndr_err_code ret;
1640 ndr->relative_base_offset = offset;
1641 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1642 if (ret == NDR_ERR_RANGE) {
1643 return ndr_push_error(ndr, ret,
1644 "More than %d NDR tokens stored for relative_base_list",
1645 NDR_TOKEN_MAX_LIST_SIZE);
1647 return ret;
1651 setup the current base for relative pointers for the push
1652 called in the NDR_BUFFERS stage
1654 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1656 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1660 push a relative object - stage1
1661 this is called during SCALARS processing
1663 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1665 enum ndr_err_code ret;
1666 if (p == NULL) {
1667 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1668 return NDR_ERR_SUCCESS;
1670 NDR_CHECK(ndr_push_align(ndr, 4));
1671 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1672 if (ret == NDR_ERR_RANGE) {
1673 return ndr_push_error(ndr, ret,
1674 "More than %d NDR tokens stored for relative_list",
1675 NDR_TOKEN_MAX_LIST_SIZE);
1677 NDR_CHECK(ret);
1678 return ndr_push_uint32(ndr, NDR_SCALARS, UINT32_MAX);
1682 push a short relative object - stage1
1683 this is called during SCALARS processing
1685 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1687 enum ndr_err_code ret;
1688 if (p == NULL) {
1689 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1690 return NDR_ERR_SUCCESS;
1692 NDR_CHECK(ndr_push_align(ndr, 2));
1693 ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
1694 if (ret == NDR_ERR_RANGE) {
1695 return ndr_push_error(ndr, ret,
1696 "More than %d NDR tokens stored for relative_list",
1697 NDR_TOKEN_MAX_LIST_SIZE);
1699 NDR_CHECK(ret);
1700 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1703 push a relative object - stage2
1704 this is called during buffers processing
1706 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1708 uint32_t save_offset;
1709 uint32_t ptr_offset = 0xFFFFFFFF;
1710 if (p == NULL) {
1711 return NDR_ERR_SUCCESS;
1713 save_offset = ndr->offset;
1714 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1715 if (ptr_offset > ndr->offset) {
1716 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1717 "ndr_push_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")",
1718 ptr_offset, ndr->offset);
1720 ndr->offset = ptr_offset;
1721 if (save_offset < ndr->relative_base_offset) {
1722 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1723 "ndr_push_relative_ptr2 save_offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
1724 save_offset, ndr->relative_base_offset);
1726 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1727 ndr->offset = save_offset;
1728 return NDR_ERR_SUCCESS;
1731 push a short relative object - stage2
1732 this is called during buffers processing
1734 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1736 uint32_t save_offset;
1737 uint32_t ptr_offset = 0xFFFF;
1738 uint32_t relative_offset;
1739 size_t pad;
1740 size_t align = 1;
1742 if (p == NULL) {
1743 return NDR_ERR_SUCCESS;
1746 if (ndr->offset < ndr->relative_base_offset) {
1747 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1748 "ndr_push_relative_ptr2 ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
1749 ndr->offset, ndr->relative_base_offset);
1752 relative_offset = ndr->offset - ndr->relative_base_offset;
1754 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1755 align = 1;
1756 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1757 align = 2;
1758 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1759 align = 4;
1760 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1761 align = 8;
1764 pad = ndr_align_size(relative_offset, align);
1765 if (pad != 0) {
1766 NDR_CHECK(ndr_push_zero(ndr, pad));
1769 relative_offset = ndr->offset - ndr->relative_base_offset;
1770 if (relative_offset > UINT16_MAX) {
1771 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1772 "ndr_push_relative_ptr2 relative_offset(%"PRIu32") > UINT16_MAX",
1773 relative_offset);
1776 save_offset = ndr->offset;
1777 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1778 if (ptr_offset > ndr->offset) {
1779 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1780 "ndr_push_short_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")",
1781 ptr_offset, ndr->offset);
1783 ndr->offset = ptr_offset;
1784 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
1785 ndr->offset = save_offset;
1786 return NDR_ERR_SUCCESS;
1790 push a relative object - stage2 start
1791 this is called during buffers processing
1793 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1795 enum ndr_err_code ret;
1796 if (p == NULL) {
1797 return NDR_ERR_SUCCESS;
1799 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1800 uint32_t relative_offset;
1801 size_t pad;
1802 size_t align = 1;
1804 if (ndr->offset < ndr->relative_base_offset) {
1805 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1806 "ndr_push_relative_ptr2_start ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
1807 ndr->offset, ndr->relative_base_offset);
1810 relative_offset = ndr->offset - ndr->relative_base_offset;
1812 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1813 align = 1;
1814 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1815 align = 2;
1816 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1817 align = 4;
1818 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1819 align = 8;
1822 pad = ndr_align_size(relative_offset, align);
1823 if (pad) {
1824 NDR_CHECK(ndr_push_zero(ndr, pad));
1827 return ndr_push_relative_ptr2(ndr, p);
1829 if (ndr->relative_end_offset == -1) {
1830 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1831 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %"PRIu32,
1832 ndr->relative_end_offset);
1834 ret = ndr_token_store(ndr,
1835 &ndr->relative_begin_list,
1837 ndr->offset);
1838 if (ret == NDR_ERR_RANGE) {
1839 return ndr_push_error(ndr, ret,
1840 "More than %d NDR tokens stored for array_size",
1841 NDR_TOKEN_MAX_LIST_SIZE);
1843 return ret;
1847 push a relative object - stage2 end
1848 this is called during buffers processing
1850 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1852 uint32_t begin_offset = 0xFFFFFFFF;
1853 ssize_t len;
1854 uint32_t correct_offset = 0;
1855 uint32_t align = 1;
1856 uint32_t pad = 0;
1858 if (p == NULL) {
1859 return NDR_ERR_SUCCESS;
1862 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1863 return NDR_ERR_SUCCESS;
1866 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1867 /* better say more than calculation a too small buffer */
1868 NDR_PUSH_ALIGN(ndr, 8);
1869 return NDR_ERR_SUCCESS;
1872 if (ndr->relative_end_offset < ndr->offset) {
1873 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1874 "ndr_push_relative_ptr2_end:"
1875 "relative_end_offset %"PRIu32" < offset %"PRIu32,
1876 ndr->relative_end_offset, ndr->offset);
1879 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1881 /* we have marshalled a buffer, see how long it was */
1882 len = ndr->offset - begin_offset;
1884 if (len < 0) {
1885 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1886 "ndr_push_relative_ptr2_end:"
1887 "offset %"PRIu32" - begin_offset %"PRIu32" < 0",
1888 ndr->offset, begin_offset);
1891 if (ndr->relative_end_offset < len) {
1892 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1893 "ndr_push_relative_ptr2_end:"
1894 "relative_end_offset %"PRIu32" < len %zd",
1895 ndr->offset, len);
1898 /* the reversed offset is at the end of the main buffer */
1899 correct_offset = ndr->relative_end_offset - len;
1901 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1902 align = 1;
1903 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1904 align = 2;
1905 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1906 align = 4;
1907 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1908 align = 8;
1911 pad = ndr_align_size(correct_offset, align);
1912 if (pad) {
1913 correct_offset += pad;
1914 correct_offset -= align;
1917 if (correct_offset < begin_offset) {
1918 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1919 "ndr_push_relative_ptr2_end: "
1920 "correct_offset %"PRIu32" < begin_offset %"PRIu32,
1921 correct_offset, begin_offset);
1924 if (len > 0) {
1925 uint32_t clear_size = correct_offset - begin_offset;
1927 clear_size = MIN(clear_size, len);
1929 /* now move the marshalled buffer to the end of the main buffer */
1930 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1932 if (clear_size) {
1933 /* and wipe out old buffer within the main buffer */
1934 memset(ndr->data + begin_offset, '\0', clear_size);
1938 /* and set the end offset for the next buffer */
1939 ndr->relative_end_offset = correct_offset;
1941 /* finally write the offset to the main buffer */
1942 ndr->offset = correct_offset;
1943 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1945 /* restore to where we were in the main buffer */
1946 ndr->offset = begin_offset;
1948 return NDR_ERR_SUCCESS;
1952 get the current base for relative pointers for the pull
1954 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1956 return ndr->relative_base_offset;
1960 restore the old base for relative pointers for the pull
1962 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1964 ndr->relative_base_offset = offset;
1968 setup the current base for relative pointers for the pull
1969 called in the NDR_SCALAR stage
1971 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1973 enum ndr_err_code ret;
1974 ndr->relative_base_offset = offset;
1975 ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1976 if (ret == NDR_ERR_RANGE) {
1977 return ndr_pull_error(ndr, ret,
1978 "More than %d NDR tokens stored for relative_base_list",
1979 NDR_TOKEN_MAX_LIST_SIZE);
1981 return ret;
1985 setup the current base for relative pointers for the pull
1986 called in the NDR_BUFFERS stage
1988 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1990 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1994 pull a relative object - stage1
1995 called during SCALARS processing
1997 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1999 enum ndr_err_code ret;
2000 rel_offset += ndr->relative_base_offset;
2001 if (rel_offset > ndr->data_size) {
2002 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
2003 "ndr_pull_relative_ptr1 rel_offset(%"PRIu32") > ndr->data_size(%"PRIu32")",
2004 rel_offset, ndr->data_size);
2006 ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
2007 if (ret == NDR_ERR_RANGE) {
2008 return ndr_pull_error(ndr, ret,
2009 "More than %d NDR tokens stored for relative_list",
2010 NDR_TOKEN_MAX_LIST_SIZE);
2012 return ret;
2016 pull a relative object - stage2
2017 called during BUFFERS processing
2019 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
2021 uint32_t rel_offset;
2022 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
2023 return ndr_pull_set_offset(ndr, rel_offset);
2026 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
2028 const char *ret = "Unknown error";
2030 switch (ndr_err) {
2031 case NDR_ERR_SUCCESS:
2032 ret = "Success";
2033 break;
2034 case NDR_ERR_ARRAY_SIZE:
2035 ret = "Bad Array Size";
2036 break;
2037 case NDR_ERR_BAD_SWITCH:
2038 ret = "Bad Switch";
2039 break;
2040 case NDR_ERR_OFFSET:
2041 ret = "Offset Error";
2042 break;
2043 case NDR_ERR_RELATIVE:
2044 ret = "Relative Pointer Error";
2045 break;
2046 case NDR_ERR_CHARCNV:
2047 ret = "Character Conversion Error";
2048 break;
2049 case NDR_ERR_LENGTH:
2050 ret = "Length Error";
2051 break;
2052 case NDR_ERR_SUBCONTEXT:
2053 ret = "Subcontext Error";
2054 break;
2055 case NDR_ERR_COMPRESSION:
2056 ret = "Compression Error";
2057 break;
2058 case NDR_ERR_STRING:
2059 ret = "String Error";
2060 break;
2061 case NDR_ERR_VALIDATE:
2062 ret = "Validate Error";
2063 break;
2064 case NDR_ERR_BUFSIZE:
2065 ret = "Buffer Size Error";
2066 break;
2067 case NDR_ERR_ALLOC:
2068 ret = "Allocation Error";
2069 break;
2070 case NDR_ERR_RANGE:
2071 ret = "Range Error";
2072 break;
2073 case NDR_ERR_TOKEN:
2074 ret = "Token Error";
2075 break;
2076 case NDR_ERR_IPV4ADDRESS:
2077 ret = "IPv4 Address Error";
2078 break;
2079 case NDR_ERR_INVALID_POINTER:
2080 ret = "Invalid Pointer";
2081 break;
2082 case NDR_ERR_UNREAD_BYTES:
2083 ret = "Unread Bytes";
2084 break;
2085 case NDR_ERR_NDR64:
2086 ret = "NDR64 assertion error";
2087 break;
2088 case NDR_ERR_INCOMPLETE_BUFFER:
2089 ret = "Incomplete Buffer";
2090 break;
2091 case NDR_ERR_MAX_RECURSION_EXCEEDED:
2092 ret = "Maximum Recursion Exceeded";
2093 break;
2094 case NDR_ERR_UNDERFLOW:
2095 ret = "Underflow";
2096 break;
2097 case NDR_ERR_IPV6ADDRESS:
2098 ret = "Invalid IPv6 address";
2099 break;
2100 case NDR_ERR_FLAGS:
2101 ret = "Invalid NDR flags";
2102 break;
2104 return ret;