source: trunk/server/librpc/ndr/ndr.c

Last change on this file was 920, checked in by Silvan Scherrer, 9 years ago

Samba Server: apply latest security patches to trunk

File size: 41.4 KB
RevLine 
[918]1/*
2 Unix SMB/CIFS implementation.
3
4 libndr interface
5
6 Copyright (C) Andrew Tridgell 2003
7
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.
12
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.
17
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/>.
20*/
21
22/*
23 this provides the core routines for NDR parsing functions
24
25 see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
26 of NDR encoding rules
27*/
28
29#include "includes.h"
30#include "librpc/ndr/libndr.h"
31#include "../lib/util/dlinklist.h"
32#if _SAMBA_BUILD_ == 4
33#include "param/param.h"
34#endif
35
36#define NDR_BASE_MARSHALL_SIZE 1024
37
38/* this guid indicates NDR encoding in a protocol tower */
39const struct ndr_syntax_id ndr_transfer_syntax = {
40 { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
41 2
42};
43
44const struct ndr_syntax_id ndr64_transfer_syntax = {
45 { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
46 1
47};
48
49const struct ndr_syntax_id null_ndr_syntax_id = {
50 { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
51 0
52};
53
54/*
55 work out the number of bytes needed to align on a n byte boundary
56*/
57_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
58{
59 if ((offset & (n-1)) == 0) return 0;
60 return n - (offset & (n-1));
61}
62
63/*
64 initialise a ndr parse structure from a data blob
65*/
66_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
67{
68 struct ndr_pull *ndr;
69
70 ndr = talloc_zero(mem_ctx, struct ndr_pull);
71 if (!ndr) return NULL;
72 ndr->current_mem_ctx = mem_ctx;
73
74 ndr->data = blob->data;
75 ndr->data_size = blob->length;
76
77 return ndr;
78}
79
[920]80_PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
81{
82 enum ndr_err_code ndr_err;
83 DATA_BLOB b;
84 uint32_t append = 0;
85 bool ok;
86
87 if (blob->length == 0) {
88 return NDR_ERR_SUCCESS;
89 }
90
91 ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
92 if (ndr_err == NDR_ERR_TOKEN) {
93 append = 0;
94 ndr_err = NDR_ERR_SUCCESS;
95 }
96 NDR_CHECK(ndr_err);
97
98 if (ndr->data_size == 0) {
99 ndr->data = NULL;
100 append = UINT32_MAX;
101 }
102
103 if (append == UINT32_MAX) {
104 /*
105 * append == UINT32_MAX means that
106 * ndr->data is either NULL or a valid
107 * talloc child of ndr, which means
108 * we can use data_blob_append() without
109 * data_blob_talloc() of the existing callers data
110 */
111 b = data_blob_const(ndr->data, ndr->data_size);
112 } else {
113 b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
114 if (b.data == NULL) {
115 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
116 }
117 }
118
119 ok = data_blob_append(ndr, &b, blob->data, blob->length);
120 if (!ok) {
121 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
122 }
123
124 ndr->data = b.data;
125 ndr->data_size = b.length;
126
127 return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
128}
129
130_PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
131{
132 uint32_t skip = 0;
133 uint32_t append = 0;
134
135 if (ndr->relative_base_offset != 0) {
136 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
137 "%s", __location__);
138 }
139 if (ndr->relative_highest_offset != 0) {
140 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
141 "%s", __location__);
142 }
143 if (ndr->relative_list != NULL) {
144 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
145 "%s", __location__);
146 }
147 if (ndr->relative_base_list != NULL) {
148 return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
149 "%s", __location__);
150 }
151
152 /*
153 * we need to keep up to 7 bytes
154 * in order to get the aligment right.
155 */
156 skip = ndr->offset & 0xFFFFFFF8;
157
158 if (skip == 0) {
159 return NDR_ERR_SUCCESS;
160 }
161
162 ndr->offset -= skip;
163 ndr->data_size -= skip;
164
165 append = ndr_token_peek(&ndr->array_size_list, ndr);
166 if (append != UINT32_MAX) {
167 /*
168 * here we assume, that ndr->data is not a
169 * talloc child of ndr.
170 */
171 ndr->data += skip;
172 return NDR_ERR_SUCCESS;
173 }
174
175 memmove(ndr->data, ndr->data + skip, ndr->data_size);
176
177 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
178 if (ndr->data_size != 0 && ndr->data == NULL) {
179 return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
180 }
181
182 return NDR_ERR_SUCCESS;
183}
184
[918]185/*
186 advance by 'size' bytes
187*/
188_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
189{
190 ndr->offset += size;
191 if (ndr->offset > ndr->data_size) {
192 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
193 "ndr_pull_advance by %u failed",
194 size);
195 }
196 return NDR_ERR_SUCCESS;
197}
198
199/*
200 set the parse offset to 'ofs'
201*/
202static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
203{
204 ndr->offset = ofs;
205 if (ndr->offset > ndr->data_size) {
206 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
207 "ndr_pull_set_offset %u failed",
208 ofs);
209 }
210 return NDR_ERR_SUCCESS;
211}
212
213/* create a ndr_push structure, ready for some marshalling */
214_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
215{
216 struct ndr_push *ndr;
217
218 ndr = talloc_zero(mem_ctx, struct ndr_push);
219 if (!ndr) {
220 return NULL;
221 }
222
223 ndr->flags = 0;
224 ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
225 ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
226 if (!ndr->data) {
227 return NULL;
228 }
229
230 return ndr;
231}
232
233/* return a DATA_BLOB structure for the current ndr_push marshalled data */
234_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
235{
236 DATA_BLOB blob;
237 blob = data_blob_const(ndr->data, ndr->offset);
238 if (ndr->alloc_size > ndr->offset) {
239 ndr->data[ndr->offset] = 0;
240 }
241 return blob;
242}
243
244
245/*
246 expand the available space in the buffer to ndr->offset + extra_size
247*/
248_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
249{
250 uint32_t size = extra_size + ndr->offset;
251
252 if (size < ndr->offset) {
253 /* extra_size overflowed the offset */
254 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
255 size);
256 }
257
258 if (ndr->alloc_size > size) {
259 return NDR_ERR_SUCCESS;
260 }
261
262 ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
263 if (size+1 > ndr->alloc_size) {
264 ndr->alloc_size = size+1;
265 }
266 ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
267 if (!ndr->data) {
268 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
269 ndr->alloc_size);
270 }
271
272 return NDR_ERR_SUCCESS;
273}
274
[920]275_PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
276{
277 va_list ap;
278 char *s = NULL;
279 uint32_t i;
280 int ret;
281 int dbgc_class;
282
283 va_start(ap, format);
284 ret = vasprintf(&s, format, ap);
285 va_end(ap);
286
287 if (ret == -1) {
288 return;
289 }
290
291 dbgc_class = *(int *)ndr->private_data;
292
293 if (ndr->no_newline) {
294 DEBUGADDC(dbgc_class, 1,("%s", s));
295 free(s);
296 return;
297 }
298
299 for (i=0;i<ndr->depth;i++) {
300 DEBUGADDC(dbgc_class, 1,(" "));
301 }
302
303 DEBUGADDC(dbgc_class, 1,("%s\n", s));
304 free(s);
305}
306
[918]307_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
308{
309 va_list ap;
310 char *s = NULL;
311 uint32_t i;
312 int ret;
313
314 va_start(ap, format);
315 ret = vasprintf(&s, format, ap);
316 va_end(ap);
317
318 if (ret == -1) {
319 return;
320 }
321
322 if (ndr->no_newline) {
323 DEBUGADD(1,("%s", s));
324 free(s);
325 return;
326 }
327
328 for (i=0;i<ndr->depth;i++) {
329 DEBUGADD(1,(" "));
330 }
331
332 DEBUGADD(1,("%s\n", s));
333 free(s);
334}
335
336_PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
337{
338 va_list ap;
339 uint32_t i;
340
341 if (!ndr->no_newline) {
342 for (i=0;i<ndr->depth;i++) {
343 printf(" ");
344 }
345 }
346
347 va_start(ap, format);
348 vprintf(format, ap);
349 va_end(ap);
350 if (!ndr->no_newline) {
351 printf("\n");
352 }
353}
354
355_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
356{
357 va_list ap;
358 uint32_t i;
359
360 if (!ndr->no_newline) {
361 for (i=0;i<ndr->depth;i++) {
362 ndr->private_data = talloc_asprintf_append_buffer(
363 (char *)ndr->private_data, " ");
364 }
365 }
366
367 va_start(ap, format);
368 ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
369 format, ap);
370 va_end(ap);
371 if (!ndr->no_newline) {
372 ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
373 "\n");
374 }
375}
376
377/*
[920]378 a useful helper function for printing idl structures via DEBUGC()
379*/
380_PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
381{
382 struct ndr_print *ndr;
383
384 DEBUGC(dbgc_class, 1,(" "));
385
386 ndr = talloc_zero(NULL, struct ndr_print);
387 if (!ndr) return;
388 ndr->private_data = &dbgc_class;
389 ndr->print = ndr_print_debugc_helper;
390 ndr->depth = 1;
391 ndr->flags = 0;
392 fn(ndr, name, ptr);
393 talloc_free(ndr);
394}
395
396/*
[918]397 a useful helper function for printing idl structures via DEBUG()
398*/
399_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
400{
401 struct ndr_print *ndr;
402
403 DEBUG(1,(" "));
404
405 ndr = talloc_zero(NULL, struct ndr_print);
406 if (!ndr) return;
407 ndr->print = ndr_print_debug_helper;
408 ndr->depth = 1;
409 ndr->flags = 0;
410 fn(ndr, name, ptr);
411 talloc_free(ndr);
412}
413
414/*
415 a useful helper function for printing idl unions via DEBUG()
416*/
417_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
418{
419 struct ndr_print *ndr;
420
421 DEBUG(1,(" "));
422
423 ndr = talloc_zero(NULL, struct ndr_print);
424 if (!ndr) return;
425 ndr->print = ndr_print_debug_helper;
426 ndr->depth = 1;
427 ndr->flags = 0;
428 ndr_print_set_switch_value(ndr, ptr, level);
429 fn(ndr, name, ptr);
430 talloc_free(ndr);
431}
432
433/*
434 a useful helper function for printing idl function calls via DEBUG()
435*/
436_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
437{
438 struct ndr_print *ndr;
439
440 DEBUG(1,(" "));
441
442 ndr = talloc_zero(NULL, struct ndr_print);
443 if (!ndr) return;
444 ndr->print = ndr_print_debug_helper;
445 ndr->depth = 1;
446 ndr->flags = 0;
447
448 fn(ndr, name, flags, ptr);
449 talloc_free(ndr);
450}
451
452/*
453 a useful helper function for printing idl structures to a string
454*/
455_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
456{
457 struct ndr_print *ndr;
458 char *ret = NULL;
459
460 ndr = talloc_zero(mem_ctx, struct ndr_print);
461 if (!ndr) return NULL;
462 ndr->private_data = talloc_strdup(ndr, "");
463 if (!ndr->private_data) {
464 goto failed;
465 }
466 ndr->print = ndr_print_string_helper;
467 ndr->depth = 1;
468 ndr->flags = 0;
469
470 fn(ndr, name, ptr);
471 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
472failed:
473 talloc_free(ndr);
474 return ret;
475}
476
477/*
478 a useful helper function for printing idl unions to a string
479*/
480_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
481{
482 struct ndr_print *ndr;
483 char *ret = NULL;
484
485 ndr = talloc_zero(mem_ctx, struct ndr_print);
486 if (!ndr) return NULL;
487 ndr->private_data = talloc_strdup(ndr, "");
488 if (!ndr->private_data) {
489 goto failed;
490 }
491 ndr->print = ndr_print_string_helper;
492 ndr->depth = 1;
493 ndr->flags = 0;
494 ndr_print_set_switch_value(ndr, ptr, level);
495 fn(ndr, name, ptr);
496 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
497failed:
498 talloc_free(ndr);
499 return ret;
500}
501
502/*
503 a useful helper function for printing idl function calls to a string
504*/
505_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
506 ndr_print_function_t fn, const char *name,
507 int flags, void *ptr)
508{
509 struct ndr_print *ndr;
510 char *ret = NULL;
511
512 ndr = talloc_zero(mem_ctx, struct ndr_print);
513 if (!ndr) return NULL;
514 ndr->private_data = talloc_strdup(ndr, "");
515 if (!ndr->private_data) {
516 goto failed;
517 }
518 ndr->print = ndr_print_string_helper;
519 ndr->depth = 1;
520 ndr->flags = 0;
521 fn(ndr, name, flags, ptr);
522 ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
523failed:
524 talloc_free(ndr);
525 return ret;
526}
527
528_PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
529{
530 /* the big/little endian flags are inter-dependent */
531 if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
532 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
533 (*pflags) &= ~LIBNDR_FLAG_NDR64;
534 }
535 if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
536 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
537 (*pflags) &= ~LIBNDR_FLAG_NDR64;
538 }
539 if (new_flags & LIBNDR_ALIGN_FLAGS) {
540 /* Ensure we only have the passed-in
541 align flag set in the new_flags,
542 remove any old align flag. */
543 (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
544 }
545 if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
546 (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
547 }
548 (*pflags) |= new_flags;
549}
550
551/*
552 return and possibly log an NDR error
553*/
554_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
555 enum ndr_err_code ndr_err,
556 const char *format, ...)
557{
558 char *s=NULL;
559 va_list ap;
560 int ret;
561
[920]562 if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
563 switch (ndr_err) {
564 case NDR_ERR_BUFSIZE:
565 return NDR_ERR_INCOMPLETE_BUFFER;
566 default:
567 break;
568 }
569 }
570
[918]571 va_start(ap, format);
572 ret = vasprintf(&s, format, ap);
573 va_end(ap);
574
575 if (ret == -1) {
576 return NDR_ERR_ALLOC;
577 }
578
579 DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
580
581 free(s);
582
583 return ndr_err;
584}
585
586/*
587 return and possibly log an NDR error
588*/
589_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
590 enum ndr_err_code ndr_err,
591 const char *format, ...)
592{
593 char *s=NULL;
594 va_list ap;
595 int ret;
596
597 va_start(ap, format);
598 ret = vasprintf(&s, format, ap);
599 va_end(ap);
600
601 if (ret == -1) {
602 return NDR_ERR_ALLOC;
603 }
604
605 DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
606
607 free(s);
608
609 return ndr_err;
610}
611
612/*
613 handle subcontext buffers, which in midl land are user-marshalled, but
614 we use magic in pidl to make them easier to cope with
615*/
616_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
617 struct ndr_pull **_subndr,
618 size_t header_size,
619 ssize_t size_is)
620{
621 struct ndr_pull *subndr;
622 uint32_t r_content_size;
623 bool force_le = false;
624 bool force_be = false;
625
626 switch (header_size) {
627 case 0: {
628 uint32_t content_size = ndr->data_size - ndr->offset;
629 if (size_is >= 0) {
630 content_size = size_is;
631 }
632 r_content_size = content_size;
633 break;
634 }
635
636 case 2: {
637 uint16_t content_size;
638 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
639 if (size_is >= 0 && size_is != content_size) {
640 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
641 (int)size_is, (int)content_size);
642 }
643 r_content_size = content_size;
644 break;
645 }
646
647 case 4: {
648 uint32_t content_size;
649 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
650 if (size_is >= 0 && size_is != content_size) {
651 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
652 (int)size_is, (int)content_size);
653 }
654 r_content_size = content_size;
655 break;
656 }
657 case 0xFFFFFC01: {
658 /*
659 * Common Type Header for the Serialization Stream
660 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
661 */
662 uint8_t version;
663 uint8_t drep;
664 uint16_t hdrlen;
665 uint32_t filler;
666 uint32_t content_size;
667 uint32_t reserved;
668
669 /* version */
670 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
671
672 if (version != 1) {
673 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
674 "Bad subcontext (PULL) Common Type Header version %d != 1",
675 (int)version);
676 }
677
678 /*
679 * 0x10 little endian
680 * 0x00 big endian
681 */
682 NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
683 if (drep == 0x10) {
684 force_le = true;
685 } else if (drep == 0x00) {
686 force_be = true;
687 } else {
688 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
689 "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
690 (unsigned int)drep);
691 }
692
693 /* length of the "Private Header for Constructed Type" */
694 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
695 if (hdrlen != 8) {
696 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
697 "Bad subcontext (PULL) Common Type Header length %d != 8",
698 (int)hdrlen);
699 }
700
701 /* filler should be ignored */
702 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
703
704 /*
705 * Private Header for Constructed Type
706 */
707 /* length - will be updated latter */
708 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
709 if (size_is >= 0 && size_is != content_size) {
710 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d",
711 (int)size_is, (int)content_size);
712 }
713 /* the content size must be a multiple of 8 */
714 if ((content_size % 8) != 0) {
715 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
716 "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
717 (int)size_is, (int)content_size);
718 }
719 r_content_size = content_size;
720
721 /* reserved */
722 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
723 break;
724 }
[920]725 case 0xFFFFFFFF:
726 /*
727 * a shallow copy like subcontext
728 * useful for DCERPC pipe chunks.
729 */
730 subndr = talloc_zero(ndr, struct ndr_pull);
731 NDR_ERR_HAVE_NO_MEMORY(subndr);
732
733 subndr->flags = ndr->flags;
734 subndr->current_mem_ctx = ndr->current_mem_ctx;
735 subndr->data = ndr->data;
736 subndr->offset = ndr->offset;
737 subndr->data_size = ndr->data_size;
738
739 *_subndr = subndr;
740 return NDR_ERR_SUCCESS;
741
[918]742 default:
743 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
744 (int)header_size);
745 }
746
747 NDR_PULL_NEED_BYTES(ndr, r_content_size);
748
749 subndr = talloc_zero(ndr, struct ndr_pull);
750 NDR_ERR_HAVE_NO_MEMORY(subndr);
751 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
752 subndr->current_mem_ctx = ndr->current_mem_ctx;
753
754 subndr->data = ndr->data + ndr->offset;
755 subndr->offset = 0;
756 subndr->data_size = r_content_size;
757
758 if (force_le) {
759 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
760 } else if (force_be) {
761 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
762 }
763
764 *_subndr = subndr;
765 return NDR_ERR_SUCCESS;
766}
767
768_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
769 struct ndr_pull *subndr,
770 size_t header_size,
771 ssize_t size_is)
772{
773 uint32_t advance;
[920]774 uint32_t highest_ofs;
775
776 if (header_size == 0xFFFFFFFF) {
777 advance = subndr->offset - ndr->offset;
778 } else if (size_is >= 0) {
[918]779 advance = size_is;
780 } else if (header_size > 0) {
781 advance = subndr->data_size;
782 } else {
783 advance = subndr->offset;
784 }
[920]785
786 if (subndr->offset > ndr->relative_highest_offset) {
787 highest_ofs = subndr->offset;
788 } else {
789 highest_ofs = subndr->relative_highest_offset;
790 }
791 if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
792 /*
793 * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
794 */
795 highest_ofs = advance;
796 }
797 if (highest_ofs < advance) {
798 return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
799 "not all bytes consumed ofs[%u] advance[%u]",
800 highest_ofs, advance);
801 }
802
[918]803 NDR_CHECK(ndr_pull_advance(ndr, advance));
804 return NDR_ERR_SUCCESS;
805}
806
807_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
808 struct ndr_push **_subndr,
809 size_t header_size,
810 ssize_t size_is)
811{
812 struct ndr_push *subndr;
813
814 subndr = ndr_push_init_ctx(ndr);
815 NDR_ERR_HAVE_NO_MEMORY(subndr);
816 subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
817
818 if (size_is > 0) {
819 NDR_CHECK(ndr_push_zero(subndr, size_is));
820 subndr->offset = 0;
821 subndr->relative_end_offset = size_is;
822 }
823
824 *_subndr = subndr;
825 return NDR_ERR_SUCCESS;
826}
827
828/*
829 push a subcontext header
830*/
831_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
832 struct ndr_push *subndr,
833 size_t header_size,
834 ssize_t size_is)
835{
836 ssize_t padding_len;
837
838 if (size_is >= 0) {
839 padding_len = size_is - subndr->offset;
840 if (padding_len < 0) {
841 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
842 (int)subndr->offset, (int)size_is);
843 }
844 subndr->offset = size_is;
845 }
846
847 switch (header_size) {
848 case 0:
849 break;
850
851 case 2:
852 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
853 break;
854
855 case 4:
856 NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
857 break;
858
859 case 0xFFFFFC01:
860 /*
861 * Common Type Header for the Serialization Stream
862 * See [MS-RPCE] 2.2.6 Type Serialization Version 1
863 */
864 padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
865 if (padding_len > 0) {
866 NDR_CHECK(ndr_push_zero(subndr, padding_len));
867 }
868
869 /* version */
870 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
871
872 /*
873 * 0x10 little endian
874 * 0x00 big endian
875 */
876 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
877
878 /* length of the "Private Header for Constructed Type" */
879 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
880
881 /* filler */
882 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
883
884 /*
885 * Private Header for Constructed Type
886 */
887 /* length - will be updated latter */
888 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
889
890 /* reserved */
891 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
892 break;
893
894 default:
895 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
896 (int)header_size);
897 }
898
899 NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
900 return NDR_ERR_SUCCESS;
901}
902
903/*
904 store a token in the ndr context, for later retrieval
905*/
906_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
907 struct ndr_token_list **list,
908 const void *key,
909 uint32_t value)
910{
911 struct ndr_token_list *tok;
912 tok = talloc(mem_ctx, struct ndr_token_list);
913 NDR_ERR_HAVE_NO_MEMORY(tok);
914 tok->key = key;
915 tok->value = value;
916 DLIST_ADD((*list), tok);
917 return NDR_ERR_SUCCESS;
918}
919
920/*
921 retrieve a token from a ndr context, using cmp_fn to match the tokens
922*/
923_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
924 comparison_fn_t _cmp_fn, bool _remove_tok)
925{
926 struct ndr_token_list *tok;
927 for (tok=*list;tok;tok=tok->next) {
928 if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
929 else if (!_cmp_fn && tok->key == key) goto found;
930 }
931 return NDR_ERR_TOKEN;
932found:
933 *v = tok->value;
934 if (_remove_tok) {
935 DLIST_REMOVE((*list), tok);
936 talloc_free(tok);
937 }
938 return NDR_ERR_SUCCESS;
939}
940
941/*
942 retrieve a token from a ndr context
943*/
944_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
945{
946 return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
947}
948
949/*
950 peek at but don't removed a token from a ndr context
951*/
952_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
953{
954 enum ndr_err_code status;
955 uint32_t v;
956
957 status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
958 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
959 return 0;
960 }
961
962 return v;
963}
964
965/*
966 pull an array size field and add it to the array_size_list token list
967*/
968_PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
969{
970 uint32_t size;
971 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
972 return ndr_token_store(ndr, &ndr->array_size_list, p, size);
973}
974
975/*
976 get the stored array size field
977*/
978_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
979{
980 return ndr_token_peek(&ndr->array_size_list, p);
981}
982
983/*
984 check the stored array size field
985*/
986_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
987{
988 uint32_t stored;
989 stored = ndr_token_peek(&ndr->array_size_list, p);
990 if (stored != size) {
991 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
992 "Bad array size - got %u expected %u\n",
993 stored, size);
994 }
995 return NDR_ERR_SUCCESS;
996}
997
998/*
999 pull an array length field and add it to the array_length_list token list
1000*/
1001_PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1002{
1003 uint32_t length, offset;
1004 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1005 if (offset != 0) {
1006 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1007 "non-zero array offset %u\n", offset);
1008 }
1009 NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1010 return ndr_token_store(ndr, &ndr->array_length_list, p, length);
1011}
1012
1013/*
1014 get the stored array length field
1015*/
1016_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1017{
1018 return ndr_token_peek(&ndr->array_length_list, p);
1019}
1020
1021/*
1022 check the stored array length field
1023*/
1024_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1025{
1026 uint32_t stored;
1027 stored = ndr_token_peek(&ndr->array_length_list, p);
1028 if (stored != length) {
1029 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1030 "Bad array length - got %u expected %u\n",
1031 stored, length);
1032 }
1033 return NDR_ERR_SUCCESS;
1034}
1035
1036_PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1037{
1038 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1039 int64_t tmp = 0 - (int64_t)count;
1040 uint64_t ncount = tmp;
1041
1042 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1043 }
1044
1045 return NDR_ERR_SUCCESS;
1046}
1047
1048_PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1049{
1050 if (ndr->flags & LIBNDR_FLAG_NDR64) {
1051 int64_t tmp = 0 - (int64_t)count;
1052 uint64_t ncount1 = tmp;
1053 uint64_t ncount2;
1054
1055 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1056 if (ncount1 == ncount2) {
1057 return NDR_ERR_SUCCESS;
1058 }
1059
1060 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1061 "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1062 (unsigned long long)ncount2,
1063 (unsigned long long)ncount1,
1064 (unsigned long)count);
1065 }
1066
1067 return NDR_ERR_SUCCESS;
1068}
1069
1070/*
1071 store a switch value
1072 */
1073_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1074{
1075 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1076}
1077
1078_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1079{
1080 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1081}
1082
1083_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1084{
1085 return ndr_token_store(ndr, &ndr->switch_list, p, val);
1086}
1087
1088/*
1089 retrieve a switch value
1090 */
1091_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
1092{
1093 return ndr_token_peek(&ndr->switch_list, p);
1094}
1095
1096_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
1097{
1098 return ndr_token_peek(&ndr->switch_list, p);
1099}
1100
1101_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
1102{
1103 return ndr_token_peek(&ndr->switch_list, p);
1104}
1105
1106/*
1107 pull a struct from a blob using NDR
1108*/
1109_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1110 ndr_pull_flags_fn_t fn)
1111{
1112 struct ndr_pull *ndr;
1113 ndr = ndr_pull_init_blob(blob, mem_ctx);
1114 NDR_ERR_HAVE_NO_MEMORY(ndr);
1115 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1116 talloc_free(ndr);
1117 return NDR_ERR_SUCCESS;
1118}
1119
1120/*
1121 pull a struct from a blob using NDR - failing if all bytes are not consumed
1122*/
1123_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1124 void *p, ndr_pull_flags_fn_t fn)
1125{
1126 struct ndr_pull *ndr;
1127 uint32_t highest_ofs;
1128 ndr = ndr_pull_init_blob(blob, mem_ctx);
1129 NDR_ERR_HAVE_NO_MEMORY(ndr);
1130 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1131 if (ndr->offset > ndr->relative_highest_offset) {
1132 highest_ofs = ndr->offset;
1133 } else {
1134 highest_ofs = ndr->relative_highest_offset;
1135 }
1136 if (highest_ofs < ndr->data_size) {
1137 enum ndr_err_code ret;
1138 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1139 "not all bytes consumed ofs[%u] size[%u]",
1140 highest_ofs, ndr->data_size);
1141 talloc_free(ndr);
1142 return ret;
1143 }
1144 talloc_free(ndr);
1145 return NDR_ERR_SUCCESS;
1146}
1147
1148/*
1149 pull a union from a blob using NDR, given the union discriminator
1150*/
1151_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1152 void *p,
1153 uint32_t level, ndr_pull_flags_fn_t fn)
1154{
1155 struct ndr_pull *ndr;
1156 ndr = ndr_pull_init_blob(blob, mem_ctx);
1157 NDR_ERR_HAVE_NO_MEMORY(ndr);
1158 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1159 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1160 talloc_free(ndr);
1161 return NDR_ERR_SUCCESS;
1162}
1163
1164/*
1165 pull a union from a blob using NDR, given the union discriminator,
1166 failing if all bytes are not consumed
1167*/
1168_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
1169 void *p,
1170 uint32_t level, ndr_pull_flags_fn_t fn)
1171{
1172 struct ndr_pull *ndr;
1173 uint32_t highest_ofs;
1174 ndr = ndr_pull_init_blob(blob, mem_ctx);
1175 NDR_ERR_HAVE_NO_MEMORY(ndr);
1176 NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1177 NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1178 if (ndr->offset > ndr->relative_highest_offset) {
1179 highest_ofs = ndr->offset;
1180 } else {
1181 highest_ofs = ndr->relative_highest_offset;
1182 }
1183 if (highest_ofs < ndr->data_size) {
1184 enum ndr_err_code ret;
1185 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1186 "not all bytes consumed ofs[%u] size[%u]",
1187 highest_ofs, ndr->data_size);
1188 talloc_free(ndr);
1189 return ret;
1190 }
1191 talloc_free(ndr);
1192 return NDR_ERR_SUCCESS;
1193}
1194
1195/*
1196 push a struct to a blob using NDR
1197*/
1198_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)
1199{
1200 struct ndr_push *ndr;
1201 ndr = ndr_push_init_ctx(mem_ctx);
1202 NDR_ERR_HAVE_NO_MEMORY(ndr);
1203
1204 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1205
1206 *blob = ndr_push_blob(ndr);
1207 talloc_steal(mem_ctx, blob->data);
1208 talloc_free(ndr);
1209
1210 return NDR_ERR_SUCCESS;
1211}
1212
1213/*
1214 push a union to a blob using NDR
1215*/
1216_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1217 uint32_t level, ndr_push_flags_fn_t fn)
1218{
1219 struct ndr_push *ndr;
1220 ndr = ndr_push_init_ctx(mem_ctx);
1221 NDR_ERR_HAVE_NO_MEMORY(ndr);
1222
1223 NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1224 NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1225
1226 *blob = ndr_push_blob(ndr);
1227 talloc_steal(mem_ctx, blob->data);
1228 talloc_free(ndr);
1229
1230 return NDR_ERR_SUCCESS;
1231}
1232
1233/*
1234 generic ndr_size_*() handler for structures
1235*/
1236_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1237{
1238 struct ndr_push *ndr;
1239 enum ndr_err_code status;
1240 size_t ret;
1241
1242 /* avoid recursion */
1243 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1244
1245 ndr = ndr_push_init_ctx(NULL);
1246 if (!ndr) return 0;
1247 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1248 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1249 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1250 talloc_free(ndr);
1251 return 0;
1252 }
1253 ret = ndr->offset;
1254 talloc_free(ndr);
1255 return ret;
1256}
1257
1258/*
1259 generic ndr_size_*() handler for unions
1260*/
1261_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1262{
1263 struct ndr_push *ndr;
1264 enum ndr_err_code status;
1265 size_t ret;
1266
1267 /* avoid recursion */
1268 if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1269
1270 ndr = ndr_push_init_ctx(NULL);
1271 if (!ndr) return 0;
1272 ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1273
1274 status = ndr_push_set_switch_value(ndr, p, level);
1275 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1276 talloc_free(ndr);
1277 return 0;
1278 }
1279 status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1280 if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1281 talloc_free(ndr);
1282 return 0;
1283 }
1284 ret = ndr->offset;
1285 talloc_free(ndr);
1286 return ret;
1287}
1288
1289/*
1290 get the current base for relative pointers for the push
1291*/
1292_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1293{
1294 return ndr->relative_base_offset;
1295}
1296
1297/*
1298 restore the old base for relative pointers for the push
1299*/
1300_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1301{
1302 ndr->relative_base_offset = offset;
1303}
1304
1305/*
1306 setup the current base for relative pointers for the push
1307 called in the NDR_SCALAR stage
1308*/
1309_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1310{
1311 ndr->relative_base_offset = offset;
1312 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1313}
1314
1315/*
1316 setup the current base for relative pointers for the push
1317 called in the NDR_BUFFERS stage
1318*/
1319_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1320{
1321 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1322}
1323
1324/*
1325 push a relative object - stage1
1326 this is called during SCALARS processing
1327*/
1328_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1329{
1330 if (p == NULL) {
1331 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1332 return NDR_ERR_SUCCESS;
1333 }
1334 NDR_CHECK(ndr_push_align(ndr, 4));
1335 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1336 return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1337}
1338
1339/*
1340 push a short relative object - stage1
1341 this is called during SCALARS processing
1342*/
1343_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1344{
1345 if (p == NULL) {
1346 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1347 return NDR_ERR_SUCCESS;
1348 }
1349 NDR_CHECK(ndr_push_align(ndr, 2));
1350 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1351 return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1352}
1353/*
1354 push a relative object - stage2
1355 this is called during buffers processing
1356*/
1357static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1358{
1359 uint32_t save_offset;
1360 uint32_t ptr_offset = 0xFFFFFFFF;
1361 if (p == NULL) {
1362 return NDR_ERR_SUCCESS;
1363 }
1364 save_offset = ndr->offset;
1365 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1366 if (ptr_offset > ndr->offset) {
1367 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1368 "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1369 ptr_offset, ndr->offset);
1370 }
1371 ndr->offset = ptr_offset;
1372 if (save_offset < ndr->relative_base_offset) {
1373 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1374 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1375 save_offset, ndr->relative_base_offset);
1376 }
1377 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1378 ndr->offset = save_offset;
1379 return NDR_ERR_SUCCESS;
1380}
1381/*
1382 push a short relative object - stage2
1383 this is called during buffers processing
1384*/
1385_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1386{
1387 uint32_t save_offset;
1388 uint32_t ptr_offset = 0xFFFF;
1389 if (p == NULL) {
1390 return NDR_ERR_SUCCESS;
1391 }
1392 save_offset = ndr->offset;
1393 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1394 if (ptr_offset > ndr->offset) {
1395 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1396 "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1397 ptr_offset, ndr->offset);
1398 }
1399 ndr->offset = ptr_offset;
1400 if (save_offset < ndr->relative_base_offset) {
1401 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1402 "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1403 save_offset, ndr->relative_base_offset);
1404 }
1405 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1406 ndr->offset = save_offset;
1407 return NDR_ERR_SUCCESS;
1408}
1409
1410/*
1411 push a relative object - stage2 start
1412 this is called during buffers processing
1413*/
1414_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1415{
1416 if (p == NULL) {
1417 return NDR_ERR_SUCCESS;
1418 }
1419 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1420 uint32_t relative_offset;
1421 size_t pad;
1422 size_t align = 1;
1423
1424 if (ndr->offset < ndr->relative_base_offset) {
1425 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1426 "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1427 ndr->offset, ndr->relative_base_offset);
1428 }
1429
1430 relative_offset = ndr->offset - ndr->relative_base_offset;
1431
1432 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1433 align = 1;
1434 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1435 align = 2;
1436 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1437 align = 4;
1438 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1439 align = 8;
1440 }
1441
1442 pad = ndr_align_size(relative_offset, align);
1443 if (pad) {
1444 NDR_CHECK(ndr_push_zero(ndr, pad));
1445 }
1446
1447 return ndr_push_relative_ptr2(ndr, p);
1448 }
1449 if (ndr->relative_end_offset == -1) {
1450 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1451 "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1452 ndr->relative_end_offset);
1453 }
1454 NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
1455 return NDR_ERR_SUCCESS;
1456}
1457
1458/*
1459 push a relative object - stage2 end
1460 this is called during buffers processing
1461*/
1462_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1463{
1464 uint32_t begin_offset = 0xFFFFFFFF;
1465 ssize_t len;
1466 uint32_t correct_offset = 0;
1467 uint32_t align = 1;
1468 uint32_t pad = 0;
1469
1470 if (p == NULL) {
1471 return NDR_ERR_SUCCESS;
1472 }
1473
1474 if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1475 return NDR_ERR_SUCCESS;
1476 }
1477
1478 if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1479 /* better say more than calculation a too small buffer */
1480 NDR_PUSH_ALIGN(ndr, 8);
1481 return NDR_ERR_SUCCESS;
1482 }
1483
1484 if (ndr->relative_end_offset < ndr->offset) {
1485 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1486 "ndr_push_relative_ptr2_end:"
1487 "relative_end_offset %u < offset %u",
1488 ndr->relative_end_offset, ndr->offset);
1489 }
1490
1491 NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1492
1493 /* we have marshalled a buffer, see how long it was */
1494 len = ndr->offset - begin_offset;
1495
1496 if (len < 0) {
1497 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1498 "ndr_push_relative_ptr2_end:"
1499 "offset %u - begin_offset %u < 0",
1500 ndr->offset, begin_offset);
1501 }
1502
1503 if (ndr->relative_end_offset < len) {
1504 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1505 "ndr_push_relative_ptr2_end:"
1506 "relative_end_offset %u < len %lld",
1507 ndr->offset, (long long)len);
1508 }
1509
1510 /* the reversed offset is at the end of the main buffer */
1511 correct_offset = ndr->relative_end_offset - len;
1512
1513 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1514 align = 1;
1515 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1516 align = 2;
1517 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1518 align = 4;
1519 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1520 align = 8;
1521 }
1522
1523 pad = ndr_align_size(correct_offset, align);
1524 if (pad) {
1525 correct_offset += pad;
1526 correct_offset -= align;
1527 }
1528
1529 if (correct_offset < begin_offset) {
1530 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1531 "ndr_push_relative_ptr2_end: "
1532 "correct_offset %u < begin_offset %u",
1533 correct_offset, begin_offset);
1534 }
1535
1536 if (len > 0) {
1537 uint32_t clear_size = correct_offset - begin_offset;
1538
1539 clear_size = MIN(clear_size, len);
1540
1541 /* now move the marshalled buffer to the end of the main buffer */
1542 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1543
1544 if (clear_size) {
1545 /* and wipe out old buffer within the main buffer */
1546 memset(ndr->data + begin_offset, '\0', clear_size);
1547 }
1548 }
1549
1550 /* and set the end offset for the next buffer */
1551 ndr->relative_end_offset = correct_offset;
1552
1553 /* finally write the offset to the main buffer */
1554 ndr->offset = correct_offset;
1555 NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1556
1557 /* restore to where we were in the main buffer */
1558 ndr->offset = begin_offset;
1559
1560 return NDR_ERR_SUCCESS;
1561}
1562
1563/*
1564 get the current base for relative pointers for the pull
1565*/
1566_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1567{
1568 return ndr->relative_base_offset;
1569}
1570
1571/*
1572 restore the old base for relative pointers for the pull
1573*/
1574_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1575{
1576 ndr->relative_base_offset = offset;
1577}
1578
1579/*
1580 setup the current base for relative pointers for the pull
1581 called in the NDR_SCALAR stage
1582*/
1583_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1584{
1585 ndr->relative_base_offset = offset;
1586 return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1587}
1588
1589/*
1590 setup the current base for relative pointers for the pull
1591 called in the NDR_BUFFERS stage
1592*/
1593_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1594{
1595 return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1596}
1597
1598/*
1599 pull a relative object - stage1
1600 called during SCALARS processing
1601*/
1602_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1603{
1604 rel_offset += ndr->relative_base_offset;
1605 if (rel_offset > ndr->data_size) {
1606 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
1607 "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1608 rel_offset, ndr->data_size);
1609 }
1610 return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1611}
1612
1613/*
1614 pull a relative object - stage2
1615 called during BUFFERS processing
1616*/
1617_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1618{
1619 uint32_t rel_offset;
1620 NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1621 return ndr_pull_set_offset(ndr, rel_offset);
1622}
1623
1624const static struct {
1625 enum ndr_err_code err;
1626 const char *string;
1627} ndr_err_code_strings[] = {
1628 { NDR_ERR_SUCCESS, "Success" },
1629 { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1630 { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1631 { NDR_ERR_OFFSET, "Offset Error" },
1632 { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1633 { NDR_ERR_CHARCNV, "Character Conversion Error" },
1634 { NDR_ERR_LENGTH, "Length Error" },
1635 { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1636 { NDR_ERR_COMPRESSION, "Compression Error" },
1637 { NDR_ERR_STRING, "String Error" },
1638 { NDR_ERR_VALIDATE, "Validate Error" },
1639 { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1640 { NDR_ERR_ALLOC, "Allocation Error" },
1641 { NDR_ERR_RANGE, "Range Error" },
1642 { NDR_ERR_TOKEN, "Token Error" },
1643 { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1644 { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1645 { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1646 { NDR_ERR_NDR64, "NDR64 assertion error" },
[920]1647 { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
[918]1648 { 0, NULL }
1649};
1650
1651_PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1652{
1653 int i;
1654 for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1655 if (ndr_err_code_strings[i].err == ndr_err)
1656 return ndr_err_code_strings[i].string;
1657 }
1658 return "Unknown error";
1659}
Note: See TracBrowser for help on using the repository browser.