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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 this provides the core routines for NDR parsing functions
26 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
31 #include "dlinklist.h"
33 #define NDR_BASE_MARSHALL_SIZE 1024
36 work out the number of bytes needed to align on a n byte boundary
38 size_t ndr_align_size(uint32_t offset
, size_t n
)
40 if ((offset
& (n
-1)) == 0) return 0;
41 return n
- (offset
& (n
-1));
45 initialise a ndr parse structure from a data blob
47 struct ndr_pull
*ndr_pull_init_blob(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
)
51 ndr
= talloc_zero(mem_ctx
, struct ndr_pull
);
52 if (!ndr
) return NULL
;
54 ndr
->data
= blob
->data
;
55 ndr
->data_size
= blob
->length
;
61 create an ndr sub-context based on an existing context. The new context starts
62 at the current offset, with the given size limit
64 NTSTATUS
ndr_pull_subcontext(struct ndr_pull
*ndr
, struct ndr_pull
*ndr2
, uint32_t size
)
66 NDR_PULL_NEED_BYTES(ndr
, size
);
68 ndr2
->data
+= ndr2
->offset
;
70 ndr2
->data_size
= size
;
71 ndr2
->flags
= ndr
->flags
;
77 advance by 'size' bytes
79 NTSTATUS
ndr_pull_advance(struct ndr_pull
*ndr
, uint32_t size
)
82 if (ndr
->offset
> ndr
->data_size
) {
83 return ndr_pull_error(ndr
, NDR_ERR_BUFSIZE
,
84 "ndr_pull_advance by %u failed",
91 set the parse offset to 'ofs'
93 NTSTATUS
ndr_pull_set_offset(struct ndr_pull
*ndr
, uint32_t ofs
)
96 if (ndr
->offset
> ndr
->data_size
) {
97 return ndr_pull_error(ndr
, NDR_ERR_BUFSIZE
,
98 "ndr_pull_set_offset %u failed",
104 /* save the offset/size of the current ndr state */
105 void ndr_pull_save(struct ndr_pull
*ndr
, struct ndr_pull_save
*save
)
107 save
->offset
= ndr
->offset
;
108 save
->data_size
= ndr
->data_size
;
111 /* restore the size/offset of a ndr structure */
112 void ndr_pull_restore(struct ndr_pull
*ndr
, struct ndr_pull_save
*save
)
114 ndr
->offset
= save
->offset
;
115 ndr
->data_size
= save
->data_size
;
119 /* create a ndr_push structure, ready for some marshalling */
120 struct ndr_push
*ndr_push_init_ctx(TALLOC_CTX
*mem_ctx
)
122 struct ndr_push
*ndr
;
124 ndr
= talloc_zero(mem_ctx
, struct ndr_push
);
130 ndr
->alloc_size
= NDR_BASE_MARSHALL_SIZE
;
131 ndr
->data
= talloc_array(ndr
, uint8_t, ndr
->alloc_size
);
140 /* create a ndr_push structure, ready for some marshalling */
141 struct ndr_push
*ndr_push_init(void)
143 return ndr_push_init_ctx(NULL
);
146 /* free a ndr_push structure */
147 void ndr_push_free(struct ndr_push
*ndr
)
153 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
154 DATA_BLOB
ndr_push_blob(struct ndr_push
*ndr
)
157 blob
.data
= ndr
->data
;
158 blob
.length
= ndr
->offset
;
164 expand the available space in the buffer to 'size'
166 NTSTATUS
ndr_push_expand(struct ndr_push
*ndr
, uint32_t size
)
168 if (ndr
->alloc_size
>= size
) {
172 ndr
->alloc_size
+= NDR_BASE_MARSHALL_SIZE
;
173 if (size
> ndr
->alloc_size
) {
174 ndr
->alloc_size
= size
;
176 ndr
->data
= talloc_realloc(ndr
, ndr
->data
, uint8_t, ndr
->alloc_size
);
178 return ndr_push_error(ndr
, NDR_ERR_ALLOC
, "Failed to push_expand to %u",
186 set the push offset to 'ofs'
188 NTSTATUS
ndr_push_set_offset(struct ndr_push
*ndr
, uint32_t ofs
)
190 NDR_CHECK(ndr_push_expand(ndr
, ofs
));
198 NTSTATUS
ndr_push_array(struct ndr_push
*ndr
, int ndr_flags
, void *base
,
199 size_t elsize
, uint32_t count
,
200 NTSTATUS (*push_fn
)(struct ndr_push
*, int, void *))
204 if (!(ndr_flags
& NDR_SCALARS
)) goto buffers
;
205 for (i
=0;i
<count
;i
++) {
206 NDR_CHECK(push_fn(ndr
, NDR_SCALARS
, p
));
209 if (!(ndr_flags
& NDR_BUFFERS
)) goto done
;
212 for (i
=0;i
<count
;i
++) {
213 NDR_CHECK(push_fn(ndr
, NDR_BUFFERS
, p
));
221 pull a constant sized array
223 NTSTATUS
ndr_pull_array(struct ndr_pull
*ndr
, int ndr_flags
, void *base
,
224 size_t elsize
, uint32_t count
,
225 NTSTATUS (*pull_fn
)(struct ndr_pull
*, int, void *))
230 if (!(ndr_flags
& NDR_SCALARS
)) goto buffers
;
231 for (i
=0;i
<count
;i
++) {
232 NDR_CHECK(pull_fn(ndr
, NDR_SCALARS
, p
));
235 if (!(ndr_flags
& NDR_BUFFERS
)) goto done
;
238 for (i
=0;i
<count
;i
++) {
239 NDR_CHECK(pull_fn(ndr
, NDR_BUFFERS
, p
));
247 pull a constant size array of structures
249 NTSTATUS
ndr_pull_struct_array(struct ndr_pull
*ndr
, uint32_t count
,
250 size_t elsize
, void **info
,
251 NTSTATUS (*pull_fn
)(struct ndr_pull
*, int, void *))
256 NDR_ALLOC_N_SIZE(ndr
, *info
, count
, elsize
);
257 base
= (char *)*info
;
259 for (i
= 0; i
< count
; i
++) {
260 ndr
->data
+= ndr
->offset
;
262 NDR_CHECK(pull_fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, &base
[count
* elsize
]));
269 print a generic array
271 void ndr_print_array(struct ndr_print
*ndr
, const char *name
, void *base
,
272 size_t elsize
, uint32_t count
,
273 void (*print_fn
)(struct ndr_print
*, const char *, void *))
277 ndr
->print(ndr
, "%s: ARRAY(%d)", name
, count
);
279 for (i
=0;i
<count
;i
++) {
281 asprintf(&idx
, "[%d]", i
);
283 print_fn(ndr
, idx
, p
);
293 void ndr_print_debug_helper(struct ndr_print
*ndr
, const char *format
, ...) _PRINTF_ATTRIBUTE(2,3)
299 va_start(ap
, format
);
300 vasprintf(&s
, format
, ap
);
303 for (i
=0;i
<ndr
->depth
;i
++) {
307 DEBUG(0,("%s\n", s
));
312 a useful helper function for printing idl structures via DEBUG()
314 void ndr_print_debug(ndr_print_fn_t fn
, const char *name
, void *ptr
)
316 struct ndr_print
*ndr
;
318 ndr
= talloc(NULL
, struct ndr_print
);
320 ndr
->print
= ndr_print_debug_helper
;
329 a useful helper function for printing idl unions via DEBUG()
331 void ndr_print_union_debug(ndr_print_union_fn_t fn
, const char *name
, uint32_t level
, void *ptr
)
333 struct ndr_print
*ndr
;
335 ndr
= talloc(NULL
, struct ndr_print
);
337 ndr
->print
= ndr_print_debug_helper
;
340 fn(ndr
, name
, level
, ptr
);
345 a useful helper function for printing idl function calls via DEBUG()
347 void ndr_print_function_debug(ndr_print_function_t fn
, const char *name
, int flags
, void *ptr
)
349 struct ndr_print
*ndr
;
351 ndr
= talloc(NULL
, struct ndr_print
);
353 ndr
->print
= ndr_print_debug_helper
;
356 fn(ndr
, name
, flags
, ptr
);
360 void ndr_set_flags(uint32_t *pflags
, uint32_t new_flags
)
362 /* the big/little endian flags are inter-dependent */
363 if (new_flags
& LIBNDR_FLAG_LITTLE_ENDIAN
) {
364 (*pflags
) &= ~LIBNDR_FLAG_BIGENDIAN
;
366 if (new_flags
& LIBNDR_FLAG_BIGENDIAN
) {
367 (*pflags
) &= ~LIBNDR_FLAG_LITTLE_ENDIAN
;
369 (*pflags
) |= new_flags
;
372 static NTSTATUS
ndr_map_error(enum ndr_err_code err
)
375 case NDR_ERR_BUFSIZE
:
376 return NT_STATUS_BUFFER_TOO_SMALL
;
378 return NT_STATUS_INTERNAL_ERROR
;
380 return NT_STATUS_NO_MEMORY
;
381 case NDR_ERR_ARRAY_SIZE
:
382 return NT_STATUS_ARRAY_BOUNDS_EXCEEDED
;
387 /* we should all error codes to different status codes */
388 return NT_STATUS_INVALID_PARAMETER
;
392 return and possibly log an NDR error
394 NTSTATUS
ndr_pull_error(struct ndr_pull
*ndr
,
395 enum ndr_err_code err
, const char *format
, ...) _PRINTF_ATTRIBUTE(3,4)
400 va_start(ap
, format
);
401 vasprintf(&s
, format
, ap
);
404 DEBUG(3,("ndr_pull_error(%u): %s\n", err
, s
));
408 return ndr_map_error(err
);
412 return and possibly log an NDR error
414 NTSTATUS
ndr_push_error(struct ndr_push
*ndr
, enum ndr_err_code err
, const char *format
, ...) _PRINTF_ATTRIBUTE(3,4)
419 va_start(ap
, format
);
420 vasprintf(&s
, format
, ap
);
423 DEBUG(3,("ndr_push_error(%u): %s\n", err
, s
));
427 return ndr_map_error(err
);
432 handle subcontext buffers, which in midl land are user-marshalled, but
433 we use magic in pidl to make them easier to cope with
435 static NTSTATUS
ndr_pull_subcontext_header(struct ndr_pull
*ndr
,
437 struct ndr_pull
*ndr2
)
439 ndr2
->flags
= ndr
->flags
;
443 uint32_t size
= ndr
->data_size
- ndr
->offset
;
444 NDR_CHECK(ndr_pull_subcontext(ndr
, ndr2
, size
));
450 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &size
));
451 NDR_CHECK(ndr_pull_subcontext(ndr
, ndr2
, size
));
457 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &size
));
458 NDR_CHECK(ndr_pull_subcontext(ndr
, ndr2
, size
));
462 return ndr_pull_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext size %d",
469 handle subcontext buffers, which in midl land are user-marshalled, but
470 we use magic in pidl to make them easier to cope with
472 NTSTATUS
ndr_pull_subcontext_flags_fn(struct ndr_pull
*ndr
, size_t sub_size
,
473 void *base
, ndr_pull_flags_fn_t fn
)
475 struct ndr_pull
*ndr2
;
476 NDR_ALLOC(ndr
, ndr2
);
477 NDR_CHECK(ndr_pull_subcontext_header(ndr
, sub_size
, ndr2
));
478 NDR_CHECK(fn(ndr2
, NDR_SCALARS
|NDR_BUFFERS
, base
));
480 NDR_CHECK(ndr_pull_advance(ndr
, ndr2
->data_size
));
482 NDR_CHECK(ndr_pull_advance(ndr
, ndr2
->offset
));
487 NTSTATUS
ndr_pull_subcontext_union_fn(struct ndr_pull
*ndr
, size_t sub_size
,
488 uint32_t level
, void *base
, ndr_pull_union_fn_t fn
)
490 struct ndr_pull
*ndr2
;
492 NDR_ALLOC(ndr
, ndr2
);
493 NDR_CHECK(ndr_pull_subcontext_header(ndr
, sub_size
, ndr2
));
494 NDR_CHECK(fn(ndr2
, NDR_SCALARS
|NDR_BUFFERS
, level
, base
));
496 NDR_CHECK(ndr_pull_advance(ndr
, ndr2
->data_size
));
498 NDR_CHECK(ndr_pull_advance(ndr
, ndr2
->offset
));
505 push a subcontext header
507 static NTSTATUS
ndr_push_subcontext_header(struct ndr_push
*ndr
,
509 struct ndr_push
*ndr2
)
516 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, ndr2
->offset
));
520 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, ndr2
->offset
));
524 return ndr_push_error(ndr
, NDR_ERR_SUBCONTEXT
, "Bad subcontext size %d",
531 handle subcontext buffers, which in midl land are user-marshalled, but
532 we use magic in pidl to make them easier to cope with
534 NTSTATUS
ndr_push_subcontext_flags_fn(struct ndr_push
*ndr
, size_t sub_size
,
535 void *base
, ndr_push_flags_fn_t fn
)
537 struct ndr_push
*ndr2
;
539 ndr2
= ndr_push_init_ctx(ndr
);
540 if (!ndr2
) return NT_STATUS_NO_MEMORY
;
542 ndr2
->flags
= ndr
->flags
;
543 NDR_CHECK(fn(ndr2
, NDR_SCALARS
|NDR_BUFFERS
, base
));
544 NDR_CHECK(ndr_push_subcontext_header(ndr
, sub_size
, ndr2
));
545 NDR_CHECK(ndr_push_bytes(ndr
, ndr2
->data
, ndr2
->offset
));
550 handle subcontext buffers for function that take a union
552 NTSTATUS
ndr_push_subcontext_union_fn(struct ndr_push
*ndr
, size_t sub_size
,
553 uint32_t level
, void *base
, ndr_push_union_fn_t fn
)
555 struct ndr_push
*ndr2
;
557 ndr2
= ndr_push_init_ctx(ndr
);
558 if (!ndr2
) return NT_STATUS_NO_MEMORY
;
560 ndr2
->flags
= ndr
->flags
;
561 NDR_CHECK(fn(ndr2
, NDR_SCALARS
|NDR_BUFFERS
, level
, base
));
562 NDR_CHECK(ndr_push_subcontext_header(ndr
, sub_size
, ndr2
));
563 NDR_CHECK(ndr_push_bytes(ndr
, ndr2
->data
, ndr2
->offset
));
569 mark the start of a structure
571 NTSTATUS
ndr_pull_struct_start(struct ndr_pull
*ndr
)
577 mark the end of a structure
579 void ndr_pull_struct_end(struct ndr_pull
*ndr
)
584 mark the start of a structure
586 NTSTATUS
ndr_push_struct_start(struct ndr_push
*ndr
)
592 mark the end of a structure
594 void ndr_push_struct_end(struct ndr_push
*ndr
)
599 store a token in the ndr context, for later retrieval
601 static NTSTATUS
ndr_token_store(TALLOC_CTX
*mem_ctx
,
602 struct ndr_token_list
**list
,
606 struct ndr_token_list
*tok
;
607 tok
= talloc(mem_ctx
, struct ndr_token_list
);
609 return NT_STATUS_NO_MEMORY
;
613 DLIST_ADD((*list
), tok
);
618 retrieve a token from a ndr context
620 static NTSTATUS
ndr_token_retrieve(struct ndr_token_list
**list
, const void *key
, uint32_t *v
)
622 struct ndr_token_list
*tok
;
623 for (tok
=*list
;tok
;tok
=tok
->next
) {
624 if (tok
->key
== key
) {
625 DLIST_REMOVE((*list
), tok
);
630 return ndr_map_error(NDR_ERR_TOKEN
);
634 peek at but don't removed a token from a ndr context
636 static uint32_t ndr_token_peek(struct ndr_token_list
**list
, const void *key
)
638 struct ndr_token_list
*tok
;
639 for (tok
=*list
;tok
;tok
=tok
->next
) {
640 if (tok
->key
== key
) {
648 pull an array size field and add it to the array_size_list token list
650 NTSTATUS
ndr_pull_array_size(struct ndr_pull
*ndr
, const void *p
)
653 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &size
));
654 return ndr_token_store(ndr
, &ndr
->array_size_list
, p
, size
);
658 get the stored array size field
660 uint32_t ndr_get_array_size(struct ndr_pull
*ndr
, const void *p
)
662 return ndr_token_peek(&ndr
->array_size_list
, p
);
666 check the stored array size field
668 NTSTATUS
ndr_check_array_size(struct ndr_pull
*ndr
, void *p
, uint32_t size
)
671 NDR_CHECK(ndr_token_retrieve(&ndr
->array_size_list
, p
, &stored
));
672 if (stored
!= size
) {
673 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
674 "Bad array size - got %u expected %u\n",
681 pull an array length field and add it to the array_length_list token list
683 NTSTATUS
ndr_pull_array_length(struct ndr_pull
*ndr
, const void *p
)
685 uint32_t length
, offset
;
686 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &offset
));
688 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
689 "non-zero array offset %u\n", offset
);
691 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &length
));
692 return ndr_token_store(ndr
, &ndr
->array_length_list
, p
, length
);
696 get the stored array length field
698 uint32_t ndr_get_array_length(struct ndr_pull
*ndr
, const void *p
)
700 return ndr_token_peek(&ndr
->array_length_list
, p
);
704 check the stored array length field
706 NTSTATUS
ndr_check_array_length(struct ndr_pull
*ndr
, void *p
, uint32_t length
)
709 NDR_CHECK(ndr_token_retrieve(&ndr
->array_length_list
, p
, &stored
));
710 if (stored
!= length
) {
711 return ndr_pull_error(ndr
, NDR_ERR_ARRAY_SIZE
,
712 "Bad array length - got %u expected %u\n",
719 pull a relative object - stage1
720 called during SCALARS processing
722 NTSTATUS
ndr_pull_relative_ptr1(struct ndr_pull
*ndr
, const void *p
, uint32_t rel_offset
)
724 if (ndr
->flags
& LIBNDR_FLAG_RELATIVE_CURRENT
) {
725 return ndr_token_store(ndr
, &ndr
->relative_list
, p
,
726 rel_offset
+ ndr
->offset
- 4);
728 return ndr_token_store(ndr
, &ndr
->relative_list
, p
, rel_offset
);
733 pull a relative object - stage2
734 called during BUFFERS processing
736 NTSTATUS
ndr_pull_relative_ptr2(struct ndr_pull
*ndr
, const void *p
)
739 NDR_CHECK(ndr_token_retrieve(&ndr
->relative_list
, p
, &rel_offset
));
740 return ndr_pull_set_offset(ndr
, rel_offset
);
744 push a relative object - stage1
745 this is called during SCALARS processing
747 NTSTATUS
ndr_push_relative_ptr1(struct ndr_push
*ndr
, const void *p
)
750 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, 0));
753 NDR_CHECK(ndr_push_align(ndr
, 4));
754 NDR_CHECK(ndr_token_store(ndr
, &ndr
->relative_list
, p
, ndr
->offset
));
755 return ndr_push_uint32(ndr
, NDR_SCALARS
, 0xFFFFFFFF);
759 push a relative object - stage2
760 this is called during buffers processing
762 NTSTATUS
ndr_push_relative_ptr2(struct ndr_push
*ndr
, const void *p
)
764 struct ndr_push_save save
;
768 NDR_CHECK(ndr_push_align(ndr
, 4));
769 ndr_push_save(ndr
, &save
);
770 NDR_CHECK(ndr_token_retrieve(&ndr
->relative_list
, p
, &ndr
->offset
));
771 if (ndr
->flags
& LIBNDR_FLAG_RELATIVE_CURRENT
) {
772 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, save
.offset
- ndr
->offset
));
774 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, save
.offset
));
776 ndr_push_restore(ndr
, &save
);
782 pull a union from a blob using NDR
784 NTSTATUS
ndr_pull_union_blob(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, uint32_t level
, void *p
,
785 ndr_pull_union_fn_t fn
)
787 struct ndr_pull
*ndr
;
788 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
790 return NT_STATUS_NO_MEMORY
;
792 return fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, level
, p
);
796 pull a struct from a blob using NDR
798 NTSTATUS
ndr_pull_struct_blob(const DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
799 ndr_pull_flags_fn_t fn
)
801 struct ndr_pull
*ndr
;
802 ndr
= ndr_pull_init_blob(blob
, mem_ctx
);
804 return NT_STATUS_NO_MEMORY
;
806 return fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
);
810 push a struct to a blob using NDR
812 NTSTATUS
ndr_push_struct_blob(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
, void *p
,
813 ndr_push_flags_fn_t fn
)
816 struct ndr_push
*ndr
;
817 ndr
= ndr_push_init_ctx(mem_ctx
);
819 return NT_STATUS_NO_MEMORY
;
821 status
= fn(ndr
, NDR_SCALARS
|NDR_BUFFERS
, p
);
822 if (!NT_STATUS_IS_OK(status
)) {
826 *blob
= ndr_push_blob(ndr
);
832 generic ndr_size_*() handler for structures
834 size_t ndr_size_struct(const void *p
, int flags
, ndr_push_flags_fn_t push
)
836 struct ndr_push
*ndr
;
840 ndr
= ndr_push_init_ctx(NULL
);
843 status
= push(ndr
, NDR_SCALARS
|NDR_BUFFERS
, discard_const(p
));
844 if (!NT_STATUS_IS_OK(status
)) {
853 generic ndr_size_*() handler for unions
855 size_t ndr_size_union(const void *p
, int flags
, uint32_t level
, ndr_push_union_fn_t push
)
857 struct ndr_push
*ndr
;
861 ndr
= ndr_push_init_ctx(NULL
);
864 status
= push(ndr
, NDR_SCALARS
|NDR_BUFFERS
, level
, discard_const(p
));
865 if (!NT_STATUS_IS_OK(status
)) {