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
32 #define NDR_BASE_MARSHALL_SIZE 1024
35 work out the number of bytes needed to align on a n byte boundary
37 size_t ndr_align_size(uint32 offset, size_t n)
39 if ((offset & (n-1)) == 0) return 0;
40 return n - (offset & (n-1));
44 initialise a ndr parse structure from a data blob
46 struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
50 ndr = talloc(mem_ctx, sizeof(*ndr));
51 if (!ndr) return NULL;
54 ndr->data = blob->data;
55 ndr->data_size = blob->length;
57 ndr->mem_ctx = mem_ctx;
63 create an ndr sub-context based on an existing context. The new context starts
64 at the current offset, with the given size limit
66 NTSTATUS ndr_pull_subcontext(struct ndr_pull *ndr, struct ndr_pull *ndr2, uint32 size)
68 NDR_PULL_NEED_BYTES(ndr, size);
70 ndr2->data += ndr2->offset;
72 ndr2->data_size = size;
73 ndr2->flags = ndr->flags;
79 advance by 'size' bytes
81 NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32 size)
84 if (ndr->offset > ndr->data_size) {
85 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
86 "ndr_pull_advance by %u failed",
93 set the parse offset to 'ofs'
95 NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32 ofs)
98 if (ndr->offset > ndr->data_size) {
99 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
100 "ndr_pull_set_offset %u failed",
106 /* save the offset/size of the current ndr state */
107 void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
109 save->offset = ndr->offset;
110 save->data_size = ndr->data_size;
113 /* restore the size/offset of a ndr structure */
114 void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
116 ndr->offset = save->offset;
117 ndr->data_size = save->data_size;
121 /* create a ndr_push structure, ready for some marshalling */
122 struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
124 struct ndr_push *ndr;
126 ndr = talloc(mem_ctx, sizeof(*ndr));
131 ndr->mem_ctx = mem_ctx;
133 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
134 ndr->data = talloc(ndr->mem_ctx, ndr->alloc_size);
140 ndr->relative_list = NULL;
141 ndr->relative_list_end = NULL;
147 /* create a ndr_push structure, ready for some marshalling */
148 struct ndr_push *ndr_push_init(void)
150 struct ndr_push *ndr;
151 TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
152 if (!mem_ctx) return NULL;
153 ndr = ndr_push_init_ctx(mem_ctx);
155 talloc_destroy(mem_ctx);
160 /* free a ndr_push structure */
161 void ndr_push_free(struct ndr_push *ndr)
163 talloc_destroy(ndr->mem_ctx);
167 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
168 DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
171 blob.data = ndr->data;
172 blob.length = ndr->offset;
178 expand the available space in the buffer to 'size'
180 NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32 size)
182 if (ndr->alloc_size >= size) {
186 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
187 if (size > ndr->alloc_size) {
188 ndr->alloc_size = size;
190 ndr->data = talloc_realloc(ndr->mem_ctx, ndr->data, ndr->alloc_size);
192 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
200 set the push offset to 'ofs'
202 NTSTATUS ndr_push_set_offset(struct ndr_push *ndr, uint32 ofs)
204 NDR_CHECK(ndr_push_expand(ndr, ofs));
212 NTSTATUS ndr_push_array(struct ndr_push *ndr, int ndr_flags, void *base,
213 size_t elsize, uint32 count,
214 NTSTATUS (*push_fn)(struct ndr_push *, int, void *))
218 if (!(ndr_flags & NDR_SCALARS)) goto buffers;
219 for (i=0;i<count;i++) {
220 NDR_CHECK(push_fn(ndr, NDR_SCALARS, p));
223 if (!(ndr_flags & NDR_BUFFERS)) goto done;
226 for (i=0;i<count;i++) {
227 NDR_CHECK(push_fn(ndr, NDR_BUFFERS, p));
235 pull a constant sized array
237 NTSTATUS ndr_pull_array(struct ndr_pull *ndr, int ndr_flags, void *base,
238 size_t elsize, uint32 count,
239 NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
244 if (!(ndr_flags & NDR_SCALARS)) goto buffers;
245 for (i=0;i<count;i++) {
246 NDR_CHECK(pull_fn(ndr, NDR_SCALARS, p));
249 if (!(ndr_flags & NDR_BUFFERS)) goto done;
252 for (i=0;i<count;i++) {
253 NDR_CHECK(pull_fn(ndr, NDR_BUFFERS, p));
262 print a generic array
264 void ndr_print_array(struct ndr_print *ndr, const char *name, void *base,
265 size_t elsize, uint32 count,
266 void (*print_fn)(struct ndr_print *, const char *, void *))
270 ndr->print(ndr, "%s: ARRAY(%d)", name, count);
272 for (i=0;i<count;i++) {
274 asprintf(&idx, "[%d]", i);
276 print_fn(ndr, idx, p);
286 void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
292 va_start(ap, format);
293 vasprintf(&s, format, ap);
296 for (i=0;i<ndr->depth;i++) {
300 DEBUG(0,("%s\n", s));
305 a useful helper function for printing idl structures via DEBUG()
307 void ndr_print_debug(void (*fn)(struct ndr_print *, const char *, void *),
311 struct ndr_print ndr;
313 ndr.mem_ctx = talloc_init("ndr_print_debug");
314 if (!ndr.mem_ctx) return;
315 ndr.print = ndr_print_debug_helper;
318 talloc_destroy(ndr.mem_ctx);
323 a useful helper function for printing idl unions via DEBUG()
325 void ndr_print_union_debug(void (*fn)(struct ndr_print *, const char *, uint32, void *),
330 struct ndr_print ndr;
332 ndr.mem_ctx = talloc_init("ndr_print_union");
333 if (!ndr.mem_ctx) return;
334 ndr.print = ndr_print_debug_helper;
336 fn(&ndr, name, level, ptr);
337 talloc_destroy(ndr.mem_ctx);
341 a useful helper function for printing idl function calls via DEBUG()
343 void ndr_print_function_debug(void (*fn)(struct ndr_print *, const char *, int , void *),
348 struct ndr_print ndr;
354 ndr.mem_ctx = talloc_init("ndr_print_function");
355 if (!ndr.mem_ctx) return;
356 ndr.print = ndr_print_debug_helper;
358 fn(&ndr, name, flags, ptr);
359 talloc_destroy(ndr.mem_ctx);
363 static NTSTATUS ndr_map_error(enum ndr_err_code err)
366 case NDR_ERR_BUFSIZE:
367 return NT_STATUS_BUFFER_TOO_SMALL;
369 return NT_STATUS_NO_MEMORY;
372 /* we should all error codes to different status codes */
373 return NT_STATUS_INVALID_PARAMETER;
377 return and possibly log an NDR error
379 NTSTATUS ndr_pull_error(struct ndr_pull *ndr, enum ndr_err_code err, const char *format, ...)
384 va_start(ap, format);
385 vasprintf(&s, format, ap);
388 DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
392 return ndr_map_error(err);
396 return and possibly log an NDR error
398 NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char *format, ...)
403 va_start(ap, format);
404 vasprintf(&s, format, ap);
407 DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
411 return ndr_map_error(err);
416 handle subcontext buffers, which in midl land are user-marshalled, but
417 we use magic in pidl to make them easier to cope with
419 static NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr,
421 struct ndr_pull *ndr2)
425 uint32 size = ndr->data_size - ndr->offset;
426 if (size == 0) return NT_STATUS_OK;
427 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
433 NDR_CHECK(ndr_pull_uint16(ndr, &size));
434 if (size == 0) return NT_STATUS_OK;
435 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
441 NDR_CHECK(ndr_pull_uint32(ndr, &size));
442 if (size == 0) return NT_STATUS_OK;
443 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
447 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
454 handle subcontext buffers, which in midl land are user-marshalled, but
455 we use magic in pidl to make them easier to cope with
457 NTSTATUS ndr_pull_subcontext_fn(struct ndr_pull *ndr,
460 NTSTATUS (*fn)(struct ndr_pull *, void *))
462 struct ndr_pull ndr2;
464 NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, &ndr2));
465 NDR_CHECK(fn(&ndr2, base));
467 NDR_CHECK(ndr_pull_advance(ndr, ndr2.data_size));
469 NDR_CHECK(ndr_pull_advance(ndr, ndr2.offset));
475 NTSTATUS ndr_pull_subcontext_flags_fn(struct ndr_pull *ndr,
478 NTSTATUS (*fn)(struct ndr_pull *, int , void *))
480 struct ndr_pull ndr2;
482 NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, &ndr2));
483 NDR_CHECK(fn(&ndr2, NDR_SCALARS|NDR_BUFFERS, base));
485 NDR_CHECK(ndr_pull_advance(ndr, ndr2.data_size));
487 NDR_CHECK(ndr_pull_advance(ndr, ndr2.offset));
492 NTSTATUS ndr_pull_subcontext_union_fn(struct ndr_pull *ndr,
496 NTSTATUS (*fn)(struct ndr_pull *, int , uint32 , void *))
498 struct ndr_pull ndr2;
500 NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, &ndr2));
501 NDR_CHECK(fn(&ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
503 NDR_CHECK(ndr_pull_advance(ndr, ndr2.data_size));
505 NDR_CHECK(ndr_pull_advance(ndr, ndr2.offset));
512 push a subcontext header
514 static NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr,
516 struct ndr_push *ndr2)
523 NDR_CHECK(ndr_push_uint16(ndr, ndr2->offset));
527 NDR_CHECK(ndr_push_uint32(ndr, ndr2->offset));
531 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
538 handle subcontext buffers, which in midl land are user-marshalled, but
539 we use magic in pidl to make them easier to cope with
541 NTSTATUS ndr_push_subcontext_fn(struct ndr_push *ndr,
544 NTSTATUS (*fn)(struct ndr_push *, void *))
546 struct ndr_push *ndr2;
548 ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
549 if (!ndr2) return NT_STATUS_NO_MEMORY;
551 ndr2->flags = ndr->flags;
552 NDR_CHECK(fn(ndr2, base));
553 NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
554 NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
559 handle subcontext buffers for function that take a flags arg
561 NTSTATUS ndr_push_subcontext_flags_fn(struct ndr_push *ndr,
564 NTSTATUS (*fn)(struct ndr_push *, int, void *))
566 struct ndr_push *ndr2;
568 ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
569 if (!ndr2) return NT_STATUS_NO_MEMORY;
571 ndr2->flags = ndr->flags;
572 NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, base));
573 NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
574 NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
579 handle subcontext buffers for function that take a union
581 NTSTATUS ndr_push_subcontext_union_fn(struct ndr_push *ndr,
585 NTSTATUS (*fn)(struct ndr_push *, int, uint32, void *))
587 struct ndr_push *ndr2;
589 ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
590 if (!ndr2) return NT_STATUS_NO_MEMORY;
592 ndr2->flags = ndr->flags;
593 NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
594 NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
595 NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
601 mark the start of a structure
603 NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
605 struct ndr_ofs_list *ofs;
607 ofs->offset = ndr->offset;
608 ofs->next = ndr->ofs_list;
614 mark the end of a structure
616 void ndr_pull_struct_end(struct ndr_pull *ndr)
618 ndr->ofs_list = ndr->ofs_list->next;
622 mark the start of a structure
624 NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
626 struct ndr_ofs_list *ofs;
627 NDR_PUSH_ALLOC(ndr, ofs);
628 ofs->offset = ndr->offset;
629 ofs->next = ndr->ofs_list;
635 mark the end of a structure
637 void ndr_push_struct_end(struct ndr_push *ndr)
639 ndr->ofs_list = ndr->ofs_list->next;
644 pull a relative structure
646 NTSTATUS ndr_pull_relative(struct ndr_pull *ndr, const void **buf, size_t size,
647 NTSTATUS (*fn)(struct ndr_pull *, int ndr_flags, void *))
649 struct ndr_pull ndr2;
651 struct ndr_pull_save save;
654 NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
659 ndr_pull_save(ndr, &save);
660 NDR_CHECK(ndr_pull_set_offset(ndr, ofs + ndr->ofs_list->offset));
661 NDR_CHECK(ndr_pull_subcontext(ndr, &ndr2, ndr->data_size - ndr->offset));
662 /* strings must be allocated by the backend functions */
663 if (ndr->flags & LIBNDR_STRING_FLAGS) {
664 NDR_CHECK(fn(&ndr2, NDR_SCALARS|NDR_BUFFERS, &p));
666 NDR_ALLOC_SIZE(ndr, p, size);
667 NDR_CHECK(fn(&ndr2, NDR_SCALARS|NDR_BUFFERS, p));
670 ndr_pull_restore(ndr, &save);
675 push a relative structure
677 NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p,
678 NTSTATUS (*fn)(struct ndr_push *, int , const void *))
680 struct ndr_ofs_list *ofs;
681 if (ndr_flags & NDR_SCALARS) {
683 NDR_CHECK(ndr_push_uint32(ndr, 0));
686 NDR_PUSH_ALLOC(ndr, ofs);
687 NDR_CHECK(ndr_push_align(ndr, 4));
688 ofs->offset = ndr->offset;
689 NDR_CHECK(ndr_push_uint32(ndr, 0xFFFFFFFF));
691 if (ndr->relative_list_end) {
692 ndr->relative_list_end->next = ofs;
694 ndr->relative_list = ofs;
696 ndr->relative_list_end = ofs;
698 if (ndr_flags & NDR_BUFFERS) {
699 struct ndr_push_save save;
703 ofs = ndr->relative_list;
705 return ndr_push_error(ndr, NDR_ERR_RELATIVE, "Empty relative stack");
707 ndr->relative_list = ndr->relative_list->next;
708 if (ndr->relative_list == NULL) {
709 ndr->relative_list_end = NULL;
711 NDR_CHECK(ndr_push_align(ndr, 8));
712 ndr_push_save(ndr, &save);
713 ndr->offset = ofs->offset;
714 NDR_CHECK(ndr_push_uint32(ndr, save.offset - ndr->ofs_list->offset));
715 ndr_push_restore(ndr, &save);
716 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
723 pull a union from a blob using NDR
725 NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32 level, void *p,
726 NTSTATUS (*fn)(struct ndr_pull *, int ndr_flags, uint32, void *))
728 struct ndr_pull *ndr;
729 ndr = ndr_pull_init_blob(blob, mem_ctx);
731 return NT_STATUS_NO_MEMORY;
733 return fn(ndr, NDR_SCALARS|NDR_BUFFERS, level, p);
737 pull a struct from a blob using NDR
739 NTSTATUS ndr_pull_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
740 NTSTATUS (*fn)(struct ndr_pull *, int , void *))
742 struct ndr_pull *ndr;
743 ndr = ndr_pull_init_blob(blob, mem_ctx);
745 return NT_STATUS_NO_MEMORY;
747 return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
751 push a struct to a blob using NDR
753 NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
754 NTSTATUS (*fn)(struct ndr_push *, int , void *))
757 struct ndr_push *ndr;
758 ndr = ndr_push_init_ctx(mem_ctx);
760 return NT_STATUS_NO_MEMORY;
762 status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
763 if (!NT_STATUS_IS_OK(status)) {
767 *blob = ndr_push_blob(ndr);