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