2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 this provides the core routines for NDR parsing functions
25 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
31 #define NDR_BASE_MARSHALL_SIZE 1024
33 /* this guid indicates NDR encoding in a protocol tower */
34 const struct ndr_syntax_id ndr_transfer_syntax
= {
35 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
39 const struct ndr_syntax_id ndr64_transfer_syntax
= {
40 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
45 work out the number of bytes needed to align on a n byte boundary
47 _PUBLIC_
size_t ndr_align_size(uint32_t offset
, size_t n
)
49 if ((offset
& (n
-1)) == 0) return 0;
50 return n
- (offset
& (n
-1));
54 initialise a ndr parse structure from a data blob
56 _PUBLIC_
struct ndr_pull
*ndr_pull_init_blob(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
60 ndr
= talloc_zero(mem_ctx
, struct ndr_pull
);
61 if (!ndr
) return NULL
;
62 ndr
->current_mem_ctx
= mem_ctx
;
64 ndr
->data
= blob
->data
;
65 ndr
->data_size
= blob
->length
;
71 advance by 'size' bytes
73 _PUBLIC_
enum ndr_err_code
ndr_pull_advance(struct ndr_pull
*ndr
, uint32_t size
)
76 if (ndr
->offset
> ndr
->data_size
) {
77 return ndr_pull_error(ndr
, NDR_ERR_BUFSIZE
,
78 "ndr_pull_advance by %u failed",
81 return NDR_ERR_SUCCESS
;
85 set the parse offset to 'ofs'
87 static enum ndr_err_code
ndr_pull_set_offset(struct ndr_pull
*ndr
, uint32_t ofs
)
90 if (ndr
->offset
> ndr
->data_size
) {
91 return ndr_pull_error(ndr
, NDR_ERR_BUFSIZE
,
92 "ndr_pull_set_offset %u failed",
95 return NDR_ERR_SUCCESS
;
98 /* save the offset/size of the current ndr state */
99 _PUBLIC_
void ndr_pull_save(struct ndr_pull
*ndr
, struct ndr_pull_save
*save
)
101 save
->offset
= ndr
->offset
;
102 save
->data_size
= ndr
->data_size
;
105 /* restore the size/offset of a ndr structure */
106 _PUBLIC_
void ndr_pull_restore(struct ndr_pull
*ndr
, struct ndr_pull_save
*save
)
108 ndr
->offset
= save
->offset
;
109 ndr
->data_size
= save
->data_size
;
113 /* create a ndr_push structure, ready for some marshalling */
114 _PUBLIC_
struct ndr_push
*ndr_push_init_ctx(TALLOC_CTX
*mem_ctx
)
116 struct ndr_push
*ndr
;
118 ndr
= talloc_zero(mem_ctx
, struct ndr_push
);
124 ndr
->alloc_size
= NDR_BASE_MARSHALL_SIZE
;
125 ndr
->data
= talloc_array(ndr
, uint8_t, ndr
->alloc_size
);
133 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
134 _PUBLIC_ DATA_BLOB
ndr_push_blob(struct ndr_push
*ndr
)
137 blob
= data_blob_const(ndr
->data
, ndr
->offset
);
138 if (ndr
->alloc_size
> ndr
->offset
) {
139 ndr
->data
[ndr
->offset
] = 0;
146 expand the available space in the buffer to ndr->offset + extra_size
148 _PUBLIC_
enum ndr_err_code
ndr_push_expand(struct ndr_push
*ndr
, uint32_t extra_size
)
150 uint32_t size
= extra_size
+ ndr
->offset
;
152 if (size
< ndr
->offset
) {
153 /* extra_size overflowed the offset */
154 return ndr_push_error(ndr
, NDR_ERR_BUFSIZE
, "Overflow in push_expand to %u",
158 if (ndr
->alloc_size
> size
) {
159 return NDR_ERR_SUCCESS
;
162 ndr
->alloc_size
+= NDR_BASE_MARSHALL_SIZE
;
163 if (size
+1 > ndr
->alloc_size
) {
164 ndr
->alloc_size
= size
+1;
166 ndr
->data
= talloc_realloc(ndr
, ndr
->data
, uint8_t, ndr
->alloc_size
);
168 return ndr_push_error(ndr
, NDR_ERR_ALLOC
, "Failed to push_expand to %u",
172 return NDR_ERR_SUCCESS
;
175 _PUBLIC_
void ndr_print_debug_helper(struct ndr_print
*ndr
, const char *format
, ...) _PRINTF_ATTRIBUTE(2,3)
181 va_start(ap
, format
);
182 ret
= vasprintf(&s
, format
, ap
);
189 for (i
=0;i
<ndr
->depth
;i
++) {
193 DEBUGADD(1,("%s\n", s
));
197 _PUBLIC_
void ndr_print_string_helper(struct ndr_print
*ndr
, const char *format
, ...) _PRINTF_ATTRIBUTE(2,3)
202 for (i
=0;i
<ndr
->depth
;i
++) {
203 ndr
->private_data
= talloc_asprintf_append_buffer(
204 (char *)ndr
->private_data
, " ");
207 va_start(ap
, format
);
208 ndr
->private_data
= talloc_vasprintf_append_buffer((char *)ndr
->private_data
,
211 ndr
->private_data
= talloc_asprintf_append_buffer((char *)ndr
->private_data
,
216 a useful helper function for printing idl structures via DEBUG()
218 _PUBLIC_
void ndr_print_debug(ndr_print_fn_t fn
, const char *name
, void *ptr
)
220 struct ndr_print
*ndr
;
222 ndr
= talloc_zero(NULL
, struct ndr_print
);
224 ndr
->print
= ndr_print_debug_helper
;
232 a useful helper function for printing idl unions via DEBUG()
234 _PUBLIC_
void ndr_print_union_debug(ndr_print_fn_t fn
, const char *name
, uint32_t level
, void *ptr
)
236 struct ndr_print
*ndr
;
238 ndr
= talloc_zero(NULL
, struct ndr_print
);
240 ndr
->print
= ndr_print_debug_helper
;
243 ndr_print_set_switch_value(ndr
, ptr
, level
);
249 a useful helper function for printing idl function calls via DEBUG()
251 _PUBLIC_
void ndr_print_function_debug(ndr_print_function_t fn
, const char *name
, int flags
, void *ptr
)
253 struct ndr_print
*ndr
;
255 ndr
= talloc_zero(NULL
, struct ndr_print
);
257 ndr
->print
= ndr_print_debug_helper
;
260 fn(ndr
, name
, flags
, ptr
);
265 a useful helper function for printing idl structures to a string
267 _PUBLIC_
char *ndr_print_struct_string(TALLOC_CTX
*mem_ctx
, ndr_print_fn_t fn
, const char *name
, void *ptr
)
269 struct ndr_print
*ndr
;
272 ndr
= talloc_zero(mem_ctx
, struct ndr_print
);
273 if (!ndr
) return NULL
;
274 ndr
->private_data
= talloc_strdup(ndr
, "");
275 if (!ndr
->private_data
) {
278 ndr
->print
= ndr_print_string_helper
;
282 ret
= talloc_steal(mem_ctx
, (char *)ndr
->private_data
);
289 a useful helper function for printing idl unions to a string
291 _PUBLIC_
char *ndr_print_union_string(TALLOC_CTX
*mem_ctx
, ndr_print_fn_t fn
, const char *name
, uint32_t level
, void *ptr
)
293 struct ndr_print
*ndr
;
296 ndr
= talloc_zero(mem_ctx
, struct ndr_print
);
297 if (!ndr
) return NULL
;
298 ndr
->private_data
= talloc_strdup(ndr
, "");
299 if (!ndr
->private_data
) {
302 ndr
->print
= ndr_print_string_helper
;
305 ndr_print_set_switch_value(ndr
, ptr
, level
);
307 ret
= talloc_steal(mem_ctx
, (char *)ndr
->private_data
);
314 a useful helper function for printing idl function calls to a string
316 _PUBLIC_
char *ndr_print_function_string(TALLOC_CTX
*mem_ctx
,
317 ndr_print_function_t fn
, const char *name
,
318 int flags
, void *ptr
)
320 struct ndr_print
*ndr
;
323 ndr
= talloc_zero(mem_ctx
, struct ndr_print
);
324 if (!ndr
) return NULL
;
325 ndr
->private_data
= talloc_strdup(ndr
, "");
326 if (!ndr
->private_data
) {
329 ndr
->print
= ndr_print_string_helper
;
332 fn(ndr
, name
, flags
, ptr
);
333 ret
= talloc_steal(mem_ctx
, (char *)ndr
->private_data
);
339 _PUBLIC_
void ndr_set_flags(uint32_t *pflags
, uint32_t new_flags
)
341 /* the big/little endian flags are inter-dependent */
342 if (new_flags
& LIBNDR_FLAG_LITTLE_ENDIAN
) {
343 (*pflags
) &= ~LIBNDR_FLAG_BIGENDIAN
;
345 if (new_flags
& LIBNDR_FLAG_BIGENDIAN
) {
346 (*pflags
) &= ~LIBNDR_FLAG_LITTLE_ENDIAN
;
348 if (new_flags
& LIBNDR_FLAG_REMAINING
) {
349 (*pflags
) &= ~LIBNDR_ALIGN_FLAGS
;
351 if (new_flags
& LIBNDR_ALIGN_FLAGS
) {
352 (*pflags
) &= ~LIBNDR_FLAG_REMAINING
;
354 (*pflags
) |= new_flags
;
357 NTSTATUS
ndr_map_error2ntstatus(enum ndr_err_code ndr_err
)
360 case NDR_ERR_SUCCESS
:
362 case NDR_ERR_BUFSIZE
:
363 return NT_STATUS_BUFFER_TOO_SMALL
;
365 return NT_STATUS_INTERNAL_ERROR
;
367 return NT_STATUS_NO_MEMORY
;
368 case NDR_ERR_ARRAY_SIZE
:
369 return NT_STATUS_ARRAY_BOUNDS_EXCEEDED
;
370 case NDR_ERR_INVALID_POINTER
:
371 return NT_STATUS_INVALID_PARAMETER_MIX
;
372 case NDR_ERR_UNREAD_BYTES
:
373 return NT_STATUS_PORT_MESSAGE_TOO_LONG
;
378 /* we should map all error codes to different status codes */
379 return NT_STATUS_INVALID_PARAMETER
;
383 * Convert an ndr error to string
386 const char *ndr_errstr(enum ndr_err_code err
)
389 case NDR_ERR_SUCCESS
:
390 return "NDR_ERR_SUCCESS";
392 case NDR_ERR_ARRAY_SIZE
:
393 return "NDR_ERR_ARRAY_SIZE";
395 case NDR_ERR_BAD_SWITCH
:
396 return "NDR_ERR_BAD_SWITCH";
399 return "NDR_ERR_OFFSET";
401 case NDR_ERR_RELATIVE
:
402 return "NDR_ERR_RELATIVE";
404 case NDR_ERR_CHARCNV
:
405 return "NDR_ERR_CHARCNV";
408 return "NDR_ERR_LENGTH";
410 case NDR_ERR_SUBCONTEXT
:
411 return "NDR_ERR_SUBCONTEXT";
413 case NDR_ERR_COMPRESSION
:
414 return "NDR_ERR_COMPRESSION";
417 return "NDR_ERR_STRING";
419 case NDR_ERR_VALIDATE
:
420 return "NDR_ERR_VALIDATE";
422 case NDR_ERR_BUFSIZE
:
423 return "NDR_ERR_BUFSIZE";
426 return "NDR_ERR_ALLOC";
429 return "NDR_ERR_RANGE";
432 return "NDR_ERR_TOKEN";
434 case NDR_ERR_IPV4ADDRESS
:
435 return "NDR_ERR_IPV4ADDRESS";
437 case NDR_ERR_INVALID_POINTER
:
438 return "NDR_ERR_INVALID_POINTER";
440 case NDR_ERR_UNREAD_BYTES
:
441 return "NDR_ERR_UNREAD_BYTES";
445 return talloc_asprintf(talloc_tos(), "Unknown NDR error: %d", err
);
449 return and possibly log an NDR error
451 _PUBLIC_
enum ndr_err_code
ndr_pull_error(struct ndr_pull
*ndr
,
452 enum ndr_err_code ndr_err
,
453 const char *format
, ...) _PRINTF_ATTRIBUTE(3,4)
459 va_start(ap
, format
);
460 ret
= vasprintf(&s
, format
, ap
);
464 return NDR_ERR_ALLOC
;
467 DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err
, s
));
475 return and possibly log an NDR error
477 _PUBLIC_
enum ndr_err_code
ndr_push_error(struct ndr_push
*ndr
,
478 enum ndr_err_code ndr_err
,
479 const char *format
, ...) _PRINTF_ATTRIBUTE(3,4)
485 va_start(ap
, format
);
486 ret
= vasprintf(&s
, format
, ap
);
490 return NDR_ERR_ALLOC
;
493 DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err
, s
));
501 handle subcontext buffers, which in midl land are user-marshalled, but
502 we use magic in pidl to make them easier to cope with
504 _PUBLIC_
enum ndr_err_code
ndr_pull_subcontext_start(struct ndr_pull
*ndr
,
505 struct ndr_pull
**_subndr
,
509 struct ndr_pull
*subndr
;
510 uint32_t r_content_size
;
512 switch (header_size
) {
514 uint32_t content_size
= ndr
->data_size
- ndr
->offset
;
516 content_size
= size_is
;
518 r_content_size
= content_size
;
523 uint16_t content_size
;
524 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &content_size
));
525 if (size_is
>= 0 && size_is
!= content_size
) {
526 return ndr_pull_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
527 (int)size_is
, (int)content_size
);
529 r_content_size
= content_size
;
534 uint32_t content_size
;
535 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &content_size
));
536 if (size_is
>= 0 && size_is
!= content_size
) {
537 return ndr_pull_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
538 (int)size_is
, (int)content_size
);
540 r_content_size
= content_size
;
544 return ndr_pull_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext (PULL) header_size %d",
548 NDR_PULL_NEED_BYTES(ndr
, r_content_size
);
550 subndr
= talloc_zero(ndr
, struct ndr_pull
);
551 NDR_ERR_HAVE_NO_MEMORY(subndr
);
552 subndr
->flags
= ndr
->flags
;
553 subndr
->current_mem_ctx
= ndr
->current_mem_ctx
;
555 subndr
->data
= ndr
->data
+ ndr
->offset
;
557 subndr
->data_size
= r_content_size
;
560 return NDR_ERR_SUCCESS
;
563 _PUBLIC_
enum ndr_err_code
ndr_pull_subcontext_end(struct ndr_pull
*ndr
,
564 struct ndr_pull
*subndr
,
571 } else if (header_size
> 0) {
572 advance
= subndr
->data_size
;
574 advance
= subndr
->offset
;
576 NDR_CHECK(ndr_pull_advance(ndr
, advance
));
577 return NDR_ERR_SUCCESS
;
580 _PUBLIC_
enum ndr_err_code
ndr_push_subcontext_start(struct ndr_push
*ndr
,
581 struct ndr_push
**_subndr
,
585 struct ndr_push
*subndr
;
587 subndr
= ndr_push_init_ctx(ndr
);
588 NDR_ERR_HAVE_NO_MEMORY(subndr
);
589 subndr
->flags
= ndr
->flags
;
592 return NDR_ERR_SUCCESS
;
596 push a subcontext header
598 _PUBLIC_
enum ndr_err_code
ndr_push_subcontext_end(struct ndr_push
*ndr
,
599 struct ndr_push
*subndr
,
604 ssize_t padding_len
= size_is
- subndr
->offset
;
605 if (padding_len
> 0) {
606 NDR_CHECK(ndr_push_zero(subndr
, padding_len
));
607 } else if (padding_len
< 0) {
608 return ndr_push_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
609 (int)subndr
->offset
, (int)size_is
);
613 switch (header_size
) {
618 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, subndr
->offset
));
622 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, subndr
->offset
));
626 return ndr_push_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext header size %d",
630 NDR_CHECK(ndr_push_bytes(ndr
, subndr
->data
, subndr
->offset
));
631 return NDR_ERR_SUCCESS
;
635 store a token in the ndr context, for later retrieval
637 _PUBLIC_
enum ndr_err_code
ndr_token_store(TALLOC_CTX
*mem_ctx
,
638 struct ndr_token_list
**list
,
642 struct ndr_token_list
*tok
;
643 tok
= talloc(mem_ctx
, struct ndr_token_list
);
644 NDR_ERR_HAVE_NO_MEMORY(tok
);
647 DLIST_ADD((*list
), tok
);
648 return NDR_ERR_SUCCESS
;
652 retrieve a token from a ndr context, using cmp_fn to match the tokens
654 _PUBLIC_
enum ndr_err_code
ndr_token_retrieve_cmp_fn(struct ndr_token_list
**list
, const void *key
, uint32_t *v
,
655 comparison_fn_t _cmp_fn
, bool _remove_tok
)
657 struct ndr_token_list
*tok
;
658 for (tok
=*list
;tok
;tok
=tok
->next
) {
659 if (_cmp_fn
&& _cmp_fn(tok
->key
,key
)==0) goto found
;
660 else if (!_cmp_fn
&& tok
->key
== key
) goto found
;
662 return NDR_ERR_TOKEN
;
666 DLIST_REMOVE((*list
), tok
);
669 return NDR_ERR_SUCCESS
;
673 retrieve a token from a ndr context
675 _PUBLIC_
enum ndr_err_code
ndr_token_retrieve(struct ndr_token_list
**list
, const void *key
, uint32_t *v
)
677 return ndr_token_retrieve_cmp_fn(list
, key
, v
, NULL
, true);
681 peek at but don't removed a token from a ndr context
683 _PUBLIC_
uint32_t ndr_token_peek(struct ndr_token_list
**list
, const void *key
)
685 enum ndr_err_code status
;
688 status
= ndr_token_retrieve_cmp_fn(list
, key
, &v
, NULL
, false);
689 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
697 pull an array size field and add it to the array_size_list token list
699 _PUBLIC_
enum ndr_err_code
ndr_pull_array_size(struct ndr_pull
*ndr
, const void *p
)
702 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &size
));
703 return ndr_token_store(ndr
, &ndr
->array_size_list
, p
, size
);
707 get the stored array size field
709 _PUBLIC_
uint32_t ndr_get_array_size(struct ndr_pull
*ndr
, const void *p
)
711 return ndr_token_peek(&ndr
->array_size_list
, p
);
715 check the stored array size field
717 _PUBLIC_
enum ndr_err_code
ndr_check_array_size(struct ndr_pull
*ndr
, void *p
, uint32_t size
)
720 stored
= ndr_token_peek(&ndr
->array_size_list
, p
);
721 if (stored
!= size
) {
722 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
723 "Bad array size - got %u expected %u\n",
726 return NDR_ERR_SUCCESS
;
730 pull an array length field and add it to the array_length_list token list
732 _PUBLIC_
enum ndr_err_code
ndr_pull_array_length(struct ndr_pull
*ndr
, const void *p
)
734 uint32_t length
, offset
;
735 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &offset
));
737 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
738 "non-zero array offset %u\n", offset
);
740 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &length
));
741 return ndr_token_store(ndr
, &ndr
->array_length_list
, p
, length
);
745 get the stored array length field
747 _PUBLIC_
uint32_t ndr_get_array_length(struct ndr_pull
*ndr
, const void *p
)
749 return ndr_token_peek(&ndr
->array_length_list
, p
);
753 check the stored array length field
755 _PUBLIC_
enum ndr_err_code
ndr_check_array_length(struct ndr_pull
*ndr
, void *p
, uint32_t length
)
758 stored
= ndr_token_peek(&ndr
->array_length_list
, p
);
759 if (stored
!= length
) {
760 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
761 "Bad array length - got %u expected %u\n",
764 return NDR_ERR_SUCCESS
;
770 _PUBLIC_
enum ndr_err_code
ndr_push_set_switch_value(struct ndr_push
*ndr
, const void *p
, uint32_t val
)
772 return ndr_token_store(ndr
, &ndr
->switch_list
, p
, val
);
775 _PUBLIC_
enum ndr_err_code
ndr_pull_set_switch_value(struct ndr_pull
*ndr
, const void *p
, uint32_t val
)
777 return ndr_token_store(ndr
, &ndr
->switch_list
, p
, val
);
780 _PUBLIC_
enum ndr_err_code
ndr_print_set_switch_value(struct ndr_print
*ndr
, const void *p
, uint32_t val
)
782 return ndr_token_store(ndr
, &ndr
->switch_list
, p
, val
);
786 retrieve a switch value
788 _PUBLIC_
uint32_t ndr_push_get_switch_value(struct ndr_push
*ndr
, const void *p
)
790 return ndr_token_peek(&ndr
->switch_list
, p
);
793 _PUBLIC_
uint32_t ndr_pull_get_switch_value(struct ndr_pull
*ndr
, const void *p
)
795 return ndr_token_peek(&ndr
->switch_list
, p
);
798 _PUBLIC_
uint32_t ndr_print_get_switch_value(struct ndr_print
*ndr
, const void *p
)
800 return ndr_token_peek(&ndr
->switch_list
, p
);
804 pull a struct from a blob using NDR
806 _PUBLIC_
enum ndr_err_code
ndr_pull_struct_blob(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
807 ndr_pull_flags_fn_t fn
)
809 struct ndr_pull
*ndr
;
810 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
811 NDR_ERR_HAVE_NO_MEMORY(ndr
);
812 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
813 return NDR_ERR_SUCCESS
;
817 pull a struct from a blob using NDR - failing if all bytes are not consumed
819 _PUBLIC_
enum ndr_err_code
ndr_pull_struct_blob_all(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
820 ndr_pull_flags_fn_t fn
)
822 struct ndr_pull
*ndr
;
823 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
824 NDR_ERR_HAVE_NO_MEMORY(ndr
);
825 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
826 if (ndr
->offset
< ndr
->data_size
) {
827 return ndr_pull_error(ndr
, NDR_ERR_UNREAD_BYTES
,
828 "not all bytes consumed ofs[%u] size[%u]",
829 ndr
->offset
, ndr
->data_size
);
831 return NDR_ERR_SUCCESS
;
835 pull a union from a blob using NDR, given the union discriminator
837 _PUBLIC_
enum ndr_err_code
ndr_pull_union_blob(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
838 uint32_t level
, ndr_pull_flags_fn_t fn
)
840 struct ndr_pull
*ndr
;
841 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
842 NDR_ERR_HAVE_NO_MEMORY(ndr
);
843 NDR_CHECK(ndr_pull_set_switch_value(ndr
, p
, level
));
844 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
845 return NDR_ERR_SUCCESS
;
849 pull a union from a blob using NDR, given the union discriminator,
850 failing if all bytes are not consumed
852 _PUBLIC_
enum ndr_err_code
ndr_pull_union_blob_all(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
853 uint32_t level
, ndr_pull_flags_fn_t fn
)
855 struct ndr_pull
*ndr
;
856 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
857 NDR_ERR_HAVE_NO_MEMORY(ndr
);
858 NDR_CHECK(ndr_pull_set_switch_value(ndr
, p
, level
));
859 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
860 if (ndr
->offset
< ndr
->data_size
) {
861 return ndr_pull_error(ndr
, NDR_ERR_UNREAD_BYTES
,
862 "not all bytes consumed ofs[%u] size[%u]",
863 ndr
->offset
, ndr
->data_size
);
865 return NDR_ERR_SUCCESS
;
869 push a struct to a blob using NDR
871 _PUBLIC_
enum ndr_err_code
ndr_push_struct_blob(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, const void *p
,
872 ndr_push_flags_fn_t fn
)
874 struct ndr_push
*ndr
;
875 ndr
= ndr_push_init_ctx(mem_ctx
);
876 NDR_ERR_HAVE_NO_MEMORY(ndr
);
878 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
880 *blob
= ndr_push_blob(ndr
);
881 talloc_steal(mem_ctx
, blob
->data
);
884 return NDR_ERR_SUCCESS
;
888 push a union to a blob using NDR
890 _PUBLIC_
enum ndr_err_code
ndr_push_union_blob(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
891 uint32_t level
, ndr_push_flags_fn_t fn
)
893 struct ndr_push
*ndr
;
894 ndr
= ndr_push_init_ctx(mem_ctx
);
895 NDR_ERR_HAVE_NO_MEMORY(ndr
);
897 NDR_CHECK(ndr_push_set_switch_value(ndr
, p
, level
));
898 NDR_CHECK(fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
));
900 *blob
= ndr_push_blob(ndr
);
901 talloc_steal(mem_ctx
, blob
->data
);
904 return NDR_ERR_SUCCESS
;
908 generic ndr_size_*() handler for structures
910 _PUBLIC_
size_t ndr_size_struct(const void *p
, int flags
, ndr_push_flags_fn_t push
)
912 struct ndr_push
*ndr
;
913 enum ndr_err_code status
;
916 /* avoid recursion */
917 if (flags
& LIBNDR_FLAG_NO_NDR_SIZE
) return 0;
919 ndr
= ndr_push_init_ctx(NULL
);
921 ndr
->flags
|= flags
| LIBNDR_FLAG_NO_NDR_SIZE
;
922 status
= push(ndr
, NDR_SCALARS
|NDR_BUFFERS
, discard_const(p
));
923 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
933 generic ndr_size_*() handler for unions
935 _PUBLIC_
size_t ndr_size_union(const void *p
, int flags
, uint32_t level
, ndr_push_flags_fn_t push
)
937 struct ndr_push
*ndr
;
938 enum ndr_err_code status
;
941 /* avoid recursion */
942 if (flags
& LIBNDR_FLAG_NO_NDR_SIZE
) return 0;
944 ndr
= ndr_push_init_ctx(NULL
);
946 ndr
->flags
|= flags
| LIBNDR_FLAG_NO_NDR_SIZE
;
948 status
= ndr_push_set_switch_value(ndr
, p
, level
);
949 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
953 status
= push(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
);
954 if (!NDR_ERR_CODE_IS_SUCCESS(status
)) {
964 get the current base for relative pointers for the push
966 _PUBLIC_
uint32_t ndr_push_get_relative_base_offset(struct ndr_push
*ndr
)
968 return ndr
->relative_base_offset
;
972 restore the old base for relative pointers for the push
974 _PUBLIC_
void ndr_push_restore_relative_base_offset(struct ndr_push
*ndr
, uint32_t offset
)
976 ndr
->relative_base_offset
= offset
;
980 setup the current base for relative pointers for the push
981 called in the NDR_SCALAR stage
983 _PUBLIC_
enum ndr_err_code
ndr_push_setup_relative_base_offset1(struct ndr_push
*ndr
, const void *p
, uint32_t offset
)
985 ndr
->relative_base_offset
= offset
;
986 return ndr_token_store(ndr
, &ndr
->relative_base_list
, p
, offset
);
990 setup the current base for relative pointers for the push
991 called in the NDR_BUFFERS stage
993 _PUBLIC_
enum ndr_err_code
ndr_push_setup_relative_base_offset2(struct ndr_push
*ndr
, const void *p
)
995 return ndr_token_retrieve(&ndr
->relative_base_list
, p
, &ndr
->relative_base_offset
);
999 push a relative object - stage1
1000 this is called during SCALARS processing
1002 _PUBLIC_
enum ndr_err_code
ndr_push_relative_ptr1(struct ndr_push
*ndr
, const void *p
)
1005 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, 0));
1006 return NDR_ERR_SUCCESS
;
1008 NDR_CHECK(ndr_push_align(ndr
, 4));
1009 NDR_CHECK(ndr_token_store(ndr
, &ndr
->relative_list
, p
, ndr
->offset
));
1010 return ndr_push_uint32(ndr
, NDR_SCALARS
, 0xFFFFFFFF);
1014 push a relative object - stage2
1015 this is called during buffers processing
1017 _PUBLIC_
enum ndr_err_code
ndr_push_relative_ptr2(struct ndr_push
*ndr
, const void *p
)
1019 struct ndr_push_save save
;
1020 uint32_t ptr_offset
= 0xFFFFFFFF;
1022 return NDR_ERR_SUCCESS
;
1024 ndr_push_save(ndr
, &save
);
1025 NDR_CHECK(ndr_token_retrieve(&ndr
->relative_list
, p
, &ptr_offset
));
1026 if (ptr_offset
> ndr
->offset
) {
1027 return ndr_push_error(ndr
, NDR_ERR_BUFSIZE
,
1028 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1029 ptr_offset
, ndr
->offset
);
1031 ndr
->offset
= ptr_offset
;
1032 if (save
.offset
< ndr
->relative_base_offset
) {
1033 return ndr_push_error(ndr
, NDR_ERR_BUFSIZE
,
1034 "ndr_push_relative_ptr2 save.offset(%u) < ndr->relative_base_offset(%u)",
1035 save
.offset
, ndr
->relative_base_offset
);
1037 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, save
.offset
- ndr
->relative_base_offset
));
1038 ndr_push_restore(ndr
, &save
);
1039 return NDR_ERR_SUCCESS
;
1043 get the current base for relative pointers for the pull
1045 _PUBLIC_
uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull
*ndr
)
1047 return ndr
->relative_base_offset
;
1051 restore the old base for relative pointers for the pull
1053 _PUBLIC_
void ndr_pull_restore_relative_base_offset(struct ndr_pull
*ndr
, uint32_t offset
)
1055 ndr
->relative_base_offset
= offset
;
1059 setup the current base for relative pointers for the pull
1060 called in the NDR_SCALAR stage
1062 _PUBLIC_
enum ndr_err_code
ndr_pull_setup_relative_base_offset1(struct ndr_pull
*ndr
, const void *p
, uint32_t offset
)
1064 ndr
->relative_base_offset
= offset
;
1065 return ndr_token_store(ndr
, &ndr
->relative_base_list
, p
, offset
);
1069 setup the current base for relative pointers for the pull
1070 called in the NDR_BUFFERS stage
1072 _PUBLIC_
enum ndr_err_code
ndr_pull_setup_relative_base_offset2(struct ndr_pull
*ndr
, const void *p
)
1074 return ndr_token_retrieve(&ndr
->relative_base_list
, p
, &ndr
->relative_base_offset
);
1078 pull a relative object - stage1
1079 called during SCALARS processing
1081 _PUBLIC_
enum ndr_err_code
ndr_pull_relative_ptr1(struct ndr_pull
*ndr
, const void *p
, uint32_t rel_offset
)
1083 rel_offset
+= ndr
->relative_base_offset
;
1084 if (rel_offset
> ndr
->data_size
) {
1085 return ndr_pull_error(ndr
, NDR_ERR_BUFSIZE
,
1086 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1087 rel_offset
, ndr
->data_size
);
1089 return ndr_token_store(ndr
, &ndr
->relative_list
, p
, rel_offset
);
1093 pull a relative object - stage2
1094 called during BUFFERS processing
1096 _PUBLIC_
enum ndr_err_code
ndr_pull_relative_ptr2(struct ndr_pull
*ndr
, const void *p
)
1098 uint32_t rel_offset
;
1099 NDR_CHECK(ndr_token_retrieve(&ndr
->relative_list
, p
, &rel_offset
));
1100 return ndr_pull_set_offset(ndr
, rel_offset
);