talloc: Fix a documentation typo
[obnox/samba/samba-obnox.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         enum ndr_err_code status;
958         uint32_t v;
959
960         status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
961         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
962                 return 0;
963         }
964
965         return v;
966 }
967
968 /*
969   pull an array size field and add it to the array_size_list token list
970 */
971 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
972 {
973         uint32_t size;
974         NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
975         return ndr_token_store(ndr, &ndr->array_size_list, p, size);
976 }
977
978 /*
979   get the stored array size field
980 */
981 _PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
982 {
983         return ndr_token_peek(&ndr->array_size_list, p);
984 }
985
986 /*
987   check the stored array size field
988 */
989 _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
990 {
991         uint32_t stored;
992         stored = ndr_token_peek(&ndr->array_size_list, p);
993         if (stored != size) {
994                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
995                                       "Bad array size - got %u expected %u\n",
996                                       stored, size);
997         }
998         return NDR_ERR_SUCCESS;
999 }
1000
1001 /*
1002   pull an array length field and add it to the array_length_list token list
1003 */
1004 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
1005 {
1006         uint32_t length, offset;
1007         NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
1008         if (offset != 0) {
1009                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
1010                                       "non-zero array offset %u\n", offset);
1011         }
1012         NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
1013         return ndr_token_store(ndr, &ndr->array_length_list, p, length);
1014 }
1015
1016 /*
1017   get the stored array length field
1018 */
1019 _PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
1020 {
1021         return ndr_token_peek(&ndr->array_length_list, p);
1022 }
1023
1024 /*
1025   check the stored array length field
1026 */
1027 _PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
1028 {
1029         uint32_t stored;
1030         stored = ndr_token_peek(&ndr->array_length_list, p);
1031         if (stored != length) {
1032                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
1033                                       "Bad array length - got %u expected %u\n",
1034                                       stored, length);
1035         }
1036         return NDR_ERR_SUCCESS;
1037 }
1038
1039 _PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count)
1040 {
1041         if (ndr->flags & LIBNDR_FLAG_NDR64) {
1042                 int64_t tmp = 0 - (int64_t)count;
1043                 uint64_t ncount = tmp;
1044
1045                 NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
1046         }
1047
1048         return NDR_ERR_SUCCESS;
1049 }
1050
1051 _PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count)
1052 {
1053         if (ndr->flags & LIBNDR_FLAG_NDR64) {
1054                 int64_t tmp = 0 - (int64_t)count;
1055                 uint64_t ncount1 = tmp;
1056                 uint64_t ncount2;
1057
1058                 NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
1059                 if (ncount1 == ncount2) {
1060                         return NDR_ERR_SUCCESS;
1061                 }
1062
1063                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
1064                         "Bad pipe trailer[%lld should be %lld] size was %lu\"",
1065                         (unsigned long long)ncount2,
1066                         (unsigned long long)ncount1,
1067                         (unsigned long)count);
1068         }
1069
1070         return NDR_ERR_SUCCESS;
1071 }
1072
1073 /*
1074   store a switch value
1075  */
1076 _PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
1077 {
1078         return ndr_token_store(ndr, &ndr->switch_list, p, val);
1079 }
1080
1081 _PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
1082 {
1083         return ndr_token_store(ndr, &ndr->switch_list, p, val);
1084 }
1085
1086 _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
1087 {
1088         return ndr_token_store(ndr, &ndr->switch_list, p, val);
1089 }
1090
1091 /*
1092   retrieve a switch value
1093  */
1094 _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
1095 {
1096         return ndr_token_peek(&ndr->switch_list, p);
1097 }
1098
1099 _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
1100 {
1101         return ndr_token_peek(&ndr->switch_list, p);
1102 }
1103
1104 _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
1105 {
1106         return ndr_token_peek(&ndr->switch_list, p);
1107 }
1108
1109 /*
1110   pull a struct from a blob using NDR
1111 */
1112 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1113                               ndr_pull_flags_fn_t fn)
1114 {
1115         struct ndr_pull *ndr;
1116         ndr = ndr_pull_init_blob(blob, mem_ctx);
1117         NDR_ERR_HAVE_NO_MEMORY(ndr);
1118         NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1119         talloc_free(ndr);
1120         return NDR_ERR_SUCCESS;
1121 }
1122
1123 /*
1124   pull a struct from a blob using NDR - failing if all bytes are not consumed
1125 */
1126 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
1127                                                     void *p, ndr_pull_flags_fn_t fn)
1128 {
1129         struct ndr_pull *ndr;
1130         uint32_t highest_ofs;
1131         ndr = ndr_pull_init_blob(blob, mem_ctx);
1132         NDR_ERR_HAVE_NO_MEMORY(ndr);
1133         NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1134         if (ndr->offset > ndr->relative_highest_offset) {
1135                 highest_ofs = ndr->offset;
1136         } else {
1137                 highest_ofs = ndr->relative_highest_offset;
1138         }
1139         if (highest_ofs < ndr->data_size) {
1140                 enum ndr_err_code ret;
1141                 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1142                                      "not all bytes consumed ofs[%u] size[%u]",
1143                                      highest_ofs, ndr->data_size);
1144                 talloc_free(ndr);
1145                 return ret;
1146         }
1147         talloc_free(ndr);
1148         return NDR_ERR_SUCCESS;
1149 }
1150
1151 /*
1152   pull a union from a blob using NDR, given the union discriminator
1153 */
1154 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
1155                                                void *p,
1156                              uint32_t level, ndr_pull_flags_fn_t fn)
1157 {
1158         struct ndr_pull *ndr;
1159         ndr = ndr_pull_init_blob(blob, mem_ctx);
1160         NDR_ERR_HAVE_NO_MEMORY(ndr);
1161         NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1162         NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1163         talloc_free(ndr);
1164         return NDR_ERR_SUCCESS;
1165 }
1166
1167 /*
1168   pull a union from a blob using NDR, given the union discriminator,
1169   failing if all bytes are not consumed
1170 */
1171 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
1172                                                    void *p,
1173                              uint32_t level, ndr_pull_flags_fn_t fn)
1174 {
1175         struct ndr_pull *ndr;
1176         uint32_t highest_ofs;
1177         ndr = ndr_pull_init_blob(blob, mem_ctx);
1178         NDR_ERR_HAVE_NO_MEMORY(ndr);
1179         NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
1180         NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1181         if (ndr->offset > ndr->relative_highest_offset) {
1182                 highest_ofs = ndr->offset;
1183         } else {
1184                 highest_ofs = ndr->relative_highest_offset;
1185         }
1186         if (highest_ofs < ndr->data_size) {
1187                 enum ndr_err_code ret;
1188                 ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
1189                                      "not all bytes consumed ofs[%u] size[%u]",
1190                                      highest_ofs, ndr->data_size);
1191                 talloc_free(ndr);
1192                 return ret;
1193         }
1194         talloc_free(ndr);
1195         return NDR_ERR_SUCCESS;
1196 }
1197
1198 /*
1199   push a struct to a blob using NDR
1200 */
1201 _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)
1202 {
1203         struct ndr_push *ndr;
1204         ndr = ndr_push_init_ctx(mem_ctx);
1205         NDR_ERR_HAVE_NO_MEMORY(ndr);
1206
1207         NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1208
1209         *blob = ndr_push_blob(ndr);
1210         talloc_steal(mem_ctx, blob->data);
1211         talloc_free(ndr);
1212
1213         return NDR_ERR_SUCCESS;
1214 }
1215
1216 /*
1217   push a union to a blob using NDR
1218 */
1219 _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
1220                              uint32_t level, ndr_push_flags_fn_t fn)
1221 {
1222         struct ndr_push *ndr;
1223         ndr = ndr_push_init_ctx(mem_ctx);
1224         NDR_ERR_HAVE_NO_MEMORY(ndr);
1225
1226         NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
1227         NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
1228
1229         *blob = ndr_push_blob(ndr);
1230         talloc_steal(mem_ctx, blob->data);
1231         talloc_free(ndr);
1232
1233         return NDR_ERR_SUCCESS;
1234 }
1235
1236 /*
1237   generic ndr_size_*() handler for structures
1238 */
1239 _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
1240 {
1241         struct ndr_push *ndr;
1242         enum ndr_err_code status;
1243         size_t ret;
1244
1245         /* avoid recursion */
1246         if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1247
1248         ndr = ndr_push_init_ctx(NULL);
1249         if (!ndr) return 0;
1250         ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1251         status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
1252         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1253                 talloc_free(ndr);
1254                 return 0;
1255         }
1256         ret = ndr->offset;
1257         talloc_free(ndr);
1258         return ret;
1259 }
1260
1261 /*
1262   generic ndr_size_*() handler for unions
1263 */
1264 _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
1265 {
1266         struct ndr_push *ndr;
1267         enum ndr_err_code status;
1268         size_t ret;
1269
1270         /* avoid recursion */
1271         if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
1272
1273         ndr = ndr_push_init_ctx(NULL);
1274         if (!ndr) return 0;
1275         ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
1276
1277         status = ndr_push_set_switch_value(ndr, p, level);
1278         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1279                 talloc_free(ndr);
1280                 return 0;
1281         }
1282         status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
1283         if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
1284                 talloc_free(ndr);
1285                 return 0;
1286         }
1287         ret = ndr->offset;
1288         talloc_free(ndr);
1289         return ret;
1290 }
1291
1292 /*
1293   get the current base for relative pointers for the push
1294 */
1295 _PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
1296 {
1297         return ndr->relative_base_offset;
1298 }
1299
1300 /*
1301   restore the old base for relative pointers for the push
1302 */
1303 _PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
1304 {
1305         ndr->relative_base_offset = offset;
1306 }
1307
1308 /*
1309   setup the current base for relative pointers for the push
1310   called in the NDR_SCALAR stage
1311 */
1312 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
1313 {
1314         ndr->relative_base_offset = offset;
1315         return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1316 }
1317
1318 /*
1319   setup the current base for relative pointers for the push
1320   called in the NDR_BUFFERS stage
1321 */
1322 _PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
1323 {
1324         return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1325 }
1326
1327 /*
1328   push a relative object - stage1
1329   this is called during SCALARS processing
1330 */
1331 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
1332 {
1333         if (p == NULL) {
1334                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
1335                 return NDR_ERR_SUCCESS;
1336         }
1337         NDR_CHECK(ndr_push_align(ndr, 4));
1338         NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1339         return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
1340 }
1341
1342 /*
1343   push a short relative object - stage1
1344   this is called during SCALARS processing
1345 */
1346 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
1347 {
1348         if (p == NULL) {
1349                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
1350                 return NDR_ERR_SUCCESS;
1351         }
1352         NDR_CHECK(ndr_push_align(ndr, 2));
1353         NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
1354         return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
1355 }
1356 /*
1357   push a relative object - stage2
1358   this is called during buffers processing
1359 */
1360 static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
1361 {
1362         uint32_t save_offset;
1363         uint32_t ptr_offset = 0xFFFFFFFF;
1364         if (p == NULL) {
1365                 return NDR_ERR_SUCCESS;
1366         }
1367         save_offset = ndr->offset;
1368         NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1369         if (ptr_offset > ndr->offset) {
1370                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
1371                                       "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1372                                       ptr_offset, ndr->offset);
1373         }
1374         ndr->offset = ptr_offset;
1375         if (save_offset < ndr->relative_base_offset) {
1376                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
1377                                       "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1378                                       save_offset, ndr->relative_base_offset);
1379         }       
1380         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1381         ndr->offset = save_offset;
1382         return NDR_ERR_SUCCESS;
1383 }
1384 /*
1385   push a short relative object - stage2
1386   this is called during buffers processing
1387 */
1388 _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
1389 {
1390         uint32_t save_offset;
1391         uint32_t ptr_offset = 0xFFFF;
1392         if (p == NULL) {
1393                 return NDR_ERR_SUCCESS;
1394         }
1395         save_offset = ndr->offset;
1396         NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
1397         if (ptr_offset > ndr->offset) {
1398                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1399                                       "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
1400                                       ptr_offset, ndr->offset);
1401         }
1402         ndr->offset = ptr_offset;
1403         if (save_offset < ndr->relative_base_offset) {
1404                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1405                                       "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
1406                                       save_offset, ndr->relative_base_offset);
1407         }
1408         NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
1409         ndr->offset = save_offset;
1410         return NDR_ERR_SUCCESS;
1411 }
1412
1413 /*
1414   push a relative object - stage2 start
1415   this is called during buffers processing
1416 */
1417 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
1418 {
1419         if (p == NULL) {
1420                 return NDR_ERR_SUCCESS;
1421         }
1422         if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1423                 uint32_t relative_offset;
1424                 size_t pad;
1425                 size_t align = 1;
1426
1427                 if (ndr->offset < ndr->relative_base_offset) {
1428                         return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
1429                                       "ndr_push_relative_ptr2_start ndr->offset(%u) < ndr->relative_base_offset(%u)",
1430                                       ndr->offset, ndr->relative_base_offset);
1431                 }
1432
1433                 relative_offset = ndr->offset - ndr->relative_base_offset;
1434
1435                 if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1436                         align = 1;
1437                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1438                         align = 2;
1439                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1440                         align = 4;
1441                 } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1442                         align = 8;
1443                 }
1444
1445                 pad = ndr_align_size(relative_offset, align);
1446                 if (pad) {
1447                         NDR_CHECK(ndr_push_zero(ndr, pad));
1448                 }
1449
1450                 return ndr_push_relative_ptr2(ndr, p);
1451         }
1452         if (ndr->relative_end_offset == -1) {
1453                 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1454                               "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
1455                               ndr->relative_end_offset);
1456         }
1457         NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
1458         return NDR_ERR_SUCCESS;
1459 }
1460
1461 /*
1462   push a relative object - stage2 end
1463   this is called during buffers processing
1464 */
1465 _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
1466 {
1467         uint32_t begin_offset = 0xFFFFFFFF;
1468         ssize_t len;
1469         uint32_t correct_offset = 0;
1470         uint32_t align = 1;
1471         uint32_t pad = 0;
1472
1473         if (p == NULL) {
1474                 return NDR_ERR_SUCCESS;
1475         }
1476
1477         if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
1478                 return NDR_ERR_SUCCESS;
1479         }
1480
1481         if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
1482                 /* better say more than calculation a too small buffer */
1483                 NDR_PUSH_ALIGN(ndr, 8);
1484                 return NDR_ERR_SUCCESS;
1485         }
1486
1487         if (ndr->relative_end_offset < ndr->offset) {
1488                 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1489                                       "ndr_push_relative_ptr2_end:"
1490                                       "relative_end_offset %u < offset %u",
1491                                       ndr->relative_end_offset, ndr->offset);
1492         }
1493
1494         NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
1495
1496         /* we have marshalled a buffer, see how long it was */
1497         len = ndr->offset - begin_offset;
1498
1499         if (len < 0) {
1500                 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1501                                       "ndr_push_relative_ptr2_end:"
1502                                       "offset %u - begin_offset %u < 0",
1503                                       ndr->offset, begin_offset);
1504         }
1505
1506         if (ndr->relative_end_offset < len) {
1507                 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1508                                       "ndr_push_relative_ptr2_end:"
1509                                       "relative_end_offset %u < len %lld",
1510                                       ndr->offset, (long long)len);
1511         }
1512
1513         /* the reversed offset is at the end of the main buffer */
1514         correct_offset = ndr->relative_end_offset - len;
1515
1516         if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
1517                 align = 1;
1518         } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
1519                 align = 2;
1520         } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
1521                 align = 4;
1522         } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
1523                 align = 8;
1524         }
1525
1526         pad = ndr_align_size(correct_offset, align);
1527         if (pad) {
1528                 correct_offset += pad;
1529                 correct_offset -= align;
1530         }
1531
1532         if (correct_offset < begin_offset) {
1533                 return ndr_push_error(ndr, NDR_ERR_RELATIVE,
1534                                       "ndr_push_relative_ptr2_end: "
1535                                       "correct_offset %u < begin_offset %u",
1536                                       correct_offset, begin_offset);
1537         }
1538
1539         if (len > 0) {
1540                 uint32_t clear_size = correct_offset - begin_offset;
1541
1542                 clear_size = MIN(clear_size, len);
1543
1544                 /* now move the marshalled buffer to the end of the main buffer */
1545                 memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
1546
1547                 if (clear_size) {
1548                         /* and wipe out old buffer within the main buffer */
1549                         memset(ndr->data + begin_offset, '\0', clear_size);
1550                 }
1551         }
1552
1553         /* and set the end offset for the next buffer */
1554         ndr->relative_end_offset = correct_offset;
1555
1556         /* finally write the offset to the main buffer */
1557         ndr->offset = correct_offset;
1558         NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
1559
1560         /* restore to where we were in the main buffer */
1561         ndr->offset = begin_offset;
1562
1563         return NDR_ERR_SUCCESS;
1564 }
1565
1566 /*
1567   get the current base for relative pointers for the pull
1568 */
1569 _PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
1570 {
1571         return ndr->relative_base_offset;
1572 }
1573
1574 /*
1575   restore the old base for relative pointers for the pull
1576 */
1577 _PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
1578 {
1579         ndr->relative_base_offset = offset;
1580 }
1581
1582 /*
1583   setup the current base for relative pointers for the pull
1584   called in the NDR_SCALAR stage
1585 */
1586 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
1587 {
1588         ndr->relative_base_offset = offset;
1589         return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
1590 }
1591
1592 /*
1593   setup the current base for relative pointers for the pull
1594   called in the NDR_BUFFERS stage
1595 */
1596 _PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
1597 {
1598         return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
1599 }
1600
1601 /*
1602   pull a relative object - stage1
1603   called during SCALARS processing
1604 */
1605 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
1606 {
1607         rel_offset += ndr->relative_base_offset;
1608         if (rel_offset > ndr->data_size) {
1609                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
1610                                       "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
1611                                       rel_offset, ndr->data_size);
1612         }
1613         return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
1614 }
1615
1616 /*
1617   pull a relative object - stage2
1618   called during BUFFERS processing
1619 */
1620 _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
1621 {
1622         uint32_t rel_offset;
1623         NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
1624         return ndr_pull_set_offset(ndr, rel_offset);
1625 }
1626
1627 const static struct {
1628         enum ndr_err_code err;
1629         const char *string;
1630 } ndr_err_code_strings[] = {
1631         { NDR_ERR_SUCCESS, "Success" },
1632         { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
1633         { NDR_ERR_BAD_SWITCH, "Bad Switch" },
1634         { NDR_ERR_OFFSET, "Offset Error" },
1635         { NDR_ERR_RELATIVE, "Relative Pointer Error" },
1636         { NDR_ERR_CHARCNV, "Character Conversion Error" },
1637         { NDR_ERR_LENGTH, "Length Error" },
1638         { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
1639         { NDR_ERR_COMPRESSION, "Compression Error" },
1640         { NDR_ERR_STRING, "String Error" },
1641         { NDR_ERR_VALIDATE, "Validate Error" },
1642         { NDR_ERR_BUFSIZE, "Buffer Size Error" },
1643         { NDR_ERR_ALLOC, "Allocation Error" },
1644         { NDR_ERR_RANGE, "Range Error" },
1645         { NDR_ERR_TOKEN, "Token Error" },
1646         { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
1647         { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
1648         { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
1649         { NDR_ERR_NDR64, "NDR64 assertion error" },
1650         { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
1651         { 0, NULL }
1652 };
1653
1654 _PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
1655 {
1656         int i;
1657         for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
1658                 if (ndr_err_code_strings[i].err == ndr_err)
1659                         return ndr_err_code_strings[i].string;
1660         }
1661         return "Unknown error";
1662 }