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