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 initialise a ndr parse structure from a data blob
37 struct ndr_pull *ndr_pull_init_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
41 ndr = talloc(mem_ctx, sizeof(*ndr));
42 if (!ndr) return NULL;
45 ndr->data = blob->data;
46 ndr->data_size = blob->length;
48 ndr->mem_ctx = mem_ctx;
54 /* limit the remaining size of the current ndr parse structure to the
55 given size, starting at the given offset
57 this is used when a ndr packet has an explicit size on the wire, and we
58 need to make sure that we don't use more data than is indicated
60 the 'ofs' parameter indicates how many bytes back from the current
61 offset in the buffer the 'size' number of bytes starts
63 NTSTATUS ndr_pull_limit_size(struct ndr_pull *ndr, uint32 size, uint32 ofs)
66 new_size = ndr->offset + size - ofs;
68 if (new_size > ndr->data_size) {
69 return NT_STATUS_BUFFER_TOO_SMALL;
71 ndr->data_size = new_size;
78 advance by 'size' bytes
80 NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32 size)
83 if (ndr->offset > ndr->data_size) {
84 return NT_STATUS_BUFFER_TOO_SMALL;
90 set the parse offset to 'ofs'
92 NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32 ofs)
95 if (ndr->offset > ndr->data_size) {
96 return NT_STATUS_BUFFER_TOO_SMALL;
101 /* save the offset/size of the current ndr state */
102 void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
104 save->offset = ndr->offset;
105 save->data_size = ndr->data_size;
108 /* restore the size/offset of a ndr structure */
109 void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
111 ndr->offset = save->offset;
112 ndr->data_size = save->data_size;
118 /* create a ndr_push structure, ready for some marshalling */
119 struct ndr_push *ndr_push_init(void)
121 struct ndr_push *ndr;
122 TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
123 if (!mem_ctx) return NULL;
125 ndr = talloc(mem_ctx, sizeof(*ndr));
127 talloc_destroy(mem_ctx);
131 ndr->mem_ctx = mem_ctx;
133 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
134 ndr->data = talloc(ndr->mem_ctx, ndr->alloc_size);
144 /* free a ndr_push structure */
145 void ndr_push_free(struct ndr_push *ndr)
147 talloc_destroy(ndr->mem_ctx);
151 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
152 DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
155 blob.data = ndr->data;
156 blob.length = ndr->offset;
162 expand the available space in the buffer to 'size'
164 NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32 size)
166 if (ndr->alloc_size >= size) {
170 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
171 if (size > ndr->alloc_size) {
172 ndr->alloc_size = size;
174 ndr->data = talloc_realloc(ndr->mem_ctx, ndr->data, ndr->alloc_size);
176 return NT_STATUS_NO_MEMORY;
183 set the push offset to 'ofs'
185 NTSTATUS ndr_push_set_offset(struct ndr_push *ndr, uint32 ofs)
187 NDR_CHECK(ndr_push_expand(ndr, ofs));
195 NTSTATUS ndr_push_array(struct ndr_push *ndr, int ndr_flags, void *base,
196 size_t elsize, uint32 count,
197 NTSTATUS (*push_fn)(struct ndr_push *, int, void *))
201 if (!(ndr_flags & NDR_SCALARS)) goto buffers;
202 for (i=0;i<count;i++) {
203 NDR_CHECK(push_fn(ndr, NDR_SCALARS, p));
206 if (!(ndr_flags & NDR_BUFFERS)) goto done;
209 for (i=0;i<count;i++) {
210 NDR_CHECK(push_fn(ndr, NDR_BUFFERS, p));
218 pull a constant sized array
220 NTSTATUS ndr_pull_array(struct ndr_pull *ndr, int ndr_flags, void *base,
221 size_t elsize, uint32 count,
222 NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
227 if (!(ndr_flags & NDR_SCALARS)) goto buffers;
228 for (i=0;i<count;i++) {
229 NDR_CHECK(pull_fn(ndr, NDR_SCALARS, p));
232 if (!(ndr_flags & NDR_BUFFERS)) goto done;
235 for (i=0;i<count;i++) {
236 NDR_CHECK(pull_fn(ndr, NDR_BUFFERS, p));
245 print a generic array
247 void ndr_print_array(struct ndr_print *ndr, const char *name, void *base,
248 size_t elsize, uint32 count,
249 void (*print_fn)(struct ndr_print *, const char *, void *))
253 ndr->print(ndr, "%s: ARRAY(%d)", name, count);
255 for (i=0;i<count;i++) {
257 asprintf(&idx, "[%d]", i);
259 print_fn(ndr, idx, p);
269 static void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
275 va_start(ap, format);
276 vasprintf(&s, format, ap);
279 for (i=0;i<ndr->depth;i++) {
283 DEBUG(0,("%s\n", s));
288 a useful helper function for printing idl structures via DEBUG()
290 void ndr_print_debug(void (*fn)(struct ndr_print *, const char *, void *),
294 struct ndr_print ndr;
296 ndr.mem_ctx = talloc_init("ndr_print_debug");
297 if (!ndr.mem_ctx) return;
298 ndr.print = ndr_print_debug_helper;
301 talloc_destroy(ndr.mem_ctx);
305 a useful helper function for printing idl unions via DEBUG()
307 void ndr_print_union_debug(void (*fn)(struct ndr_print *, const char *, uint16, void *),
312 struct ndr_print ndr;
314 ndr.mem_ctx = talloc_init("ndr_print_debug");
315 if (!ndr.mem_ctx) return;
316 ndr.print = ndr_print_debug_helper;
318 fn(&ndr, name, level, ptr);
319 talloc_destroy(ndr.mem_ctx);
323 return and possibly log an NDR error
325 NTSTATUS ndr_pull_error(struct ndr_pull *ndr, enum ndr_err_code err, const char *format, ...)
330 va_start(ap, format);
331 vasprintf(&s, format, ap);
334 DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
337 /* we should map to different status codes */
338 return NT_STATUS_INVALID_PARAMETER;