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