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