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