r3322: fixed a bunch of warnings in the build, including one case where it was a...
[bbaumbach/samba-autobuild/.git] / source4 / librpc / ndr / ndr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    libndr interface
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
32 #define NDR_BASE_MARSHALL_SIZE 1024
33
34 /*
35   work out the number of bytes needed to align on a n byte boundary
36 */
37 size_t ndr_align_size(uint32_t offset, size_t n)
38 {
39         if ((offset & (n-1)) == 0) return 0;
40         return n - (offset & (n-1));
41 }
42
43 /*
44   initialise a ndr parse structure from a data blob
45 */
46 struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
47 {
48         struct ndr_pull *ndr;
49
50         ndr = talloc_p(mem_ctx, struct ndr_pull);
51         if (!ndr) return NULL;
52
53         ndr->flags = 0;
54         ndr->data = blob->data;
55         ndr->data_size = blob->length;
56         ndr->offset = 0;
57         ndr->ptr_count = 0;
58         ndr->relative_list = NULL;
59
60         return ndr;
61 }
62
63 /*
64   create an ndr sub-context based on an existing context. The new context starts
65   at the current offset, with the given size limit
66 */
67 NTSTATUS ndr_pull_subcontext(struct ndr_pull *ndr, struct ndr_pull *ndr2, uint32_t size)
68 {
69         NDR_PULL_NEED_BYTES(ndr, size);
70         *ndr2 = *ndr;
71         ndr2->data += ndr2->offset;
72         ndr2->offset = 0;
73         ndr2->data_size = size;
74         ndr2->flags = ndr->flags;
75         return NT_STATUS_OK;
76 }
77
78
79 /*
80   advance by 'size' bytes
81 */
82 NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
83 {
84         ndr->offset += size;
85         if (ndr->offset > ndr->data_size) {
86                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
87                                       "ndr_pull_advance by %u failed",
88                                       size);
89         }
90         return NT_STATUS_OK;
91 }
92
93 /*
94   set the parse offset to 'ofs'
95 */
96 NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
97 {
98         ndr->offset = ofs;
99         if (ndr->offset > ndr->data_size) {
100                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
101                                       "ndr_pull_set_offset %u failed",
102                                       ofs);
103         }
104         return NT_STATUS_OK;
105 }
106
107 /* save the offset/size of the current ndr state */
108 void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
109 {
110         save->offset = ndr->offset;
111         save->data_size = ndr->data_size;
112 }
113
114 /* restore the size/offset of a ndr structure */
115 void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
116 {
117         ndr->offset = save->offset;
118         ndr->data_size = save->data_size;
119 }
120
121
122 /* create a ndr_push structure, ready for some marshalling */
123 struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
124 {
125         struct ndr_push *ndr;
126
127         ndr = talloc(mem_ctx, sizeof(*ndr));
128         if (!ndr) {
129                 return NULL;
130         }
131
132         ndr->flags = 0;
133         ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
134         ndr->data = talloc(ndr, ndr->alloc_size);
135         if (!ndr->data) {
136                 return NULL;
137         }
138         ndr->offset = 0;
139         ndr->ptr_count = 0;
140         ndr->relative_list = NULL;
141
142         return ndr;
143 }
144
145
146 /* create a ndr_push structure, ready for some marshalling */
147 struct ndr_push *ndr_push_init(void)
148 {
149         return ndr_push_init_ctx(NULL);
150 }
151
152 /* free a ndr_push structure */
153 void ndr_push_free(struct ndr_push *ndr)
154 {
155         talloc_free(ndr);
156 }
157
158
159 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
160 DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
161 {
162         DATA_BLOB blob;
163         blob.data = ndr->data;
164         blob.length = ndr->offset;
165         return blob;
166 }
167
168
169 /*
170   expand the available space in the buffer to 'size'
171 */
172 NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size)
173 {
174         if (ndr->alloc_size >= size) {
175                 return NT_STATUS_OK;
176         }
177
178         ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
179         if (size > ndr->alloc_size) {
180                 ndr->alloc_size = size;
181         }
182         ndr->data = talloc_realloc(ndr, ndr->data, ndr->alloc_size);
183         if (!ndr->data) {
184                 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
185                                       ndr->alloc_size);
186         }
187
188         return NT_STATUS_OK;
189 }
190
191 /*
192   set the push offset to 'ofs'
193 */
194 NTSTATUS ndr_push_set_offset(struct ndr_push *ndr, uint32_t ofs)
195 {
196         NDR_CHECK(ndr_push_expand(ndr, ofs));
197         ndr->offset = ofs;
198         return NT_STATUS_OK;
199 }
200
201 /*
202   push a generic array
203 */
204 NTSTATUS ndr_push_array(struct ndr_push *ndr, int ndr_flags, void *base, 
205                         size_t elsize, uint32_t count, 
206                         NTSTATUS (*push_fn)(struct ndr_push *, int, void *))
207 {
208         int i;
209         char *p = base;
210         if (!(ndr_flags & NDR_SCALARS)) goto buffers;
211         for (i=0;i<count;i++) {
212                 NDR_CHECK(push_fn(ndr, NDR_SCALARS, p));
213                 p += elsize;
214         }
215         if (!(ndr_flags & NDR_BUFFERS)) goto done;
216 buffers:
217         p = base;
218         for (i=0;i<count;i++) {
219                 NDR_CHECK(push_fn(ndr, NDR_BUFFERS, p));
220                 p += elsize;
221         }
222 done:
223         return NT_STATUS_OK;
224 }
225
226 /*
227   pull a constant sized array
228 */
229 NTSTATUS ndr_pull_array(struct ndr_pull *ndr, int ndr_flags, void *base, 
230                         size_t elsize, uint32_t count, 
231                         NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
232 {
233         int i;
234         char *p;
235         p = base;
236         if (!(ndr_flags & NDR_SCALARS)) goto buffers;
237         for (i=0;i<count;i++) {
238                 NDR_CHECK(pull_fn(ndr, NDR_SCALARS, p));
239                 p += elsize;
240         }
241         if (!(ndr_flags & NDR_BUFFERS)) goto done;
242 buffers:
243         p = base;
244         for (i=0;i<count;i++) {
245                 NDR_CHECK(pull_fn(ndr, NDR_BUFFERS, p));
246                 p += elsize;
247         }
248 done:
249         return NT_STATUS_OK;
250 }
251
252 /*
253   pull a constant size array of structures
254 */
255 NTSTATUS ndr_pull_struct_array(struct ndr_pull *ndr, uint32_t count,
256                                size_t elsize, void **info,
257                                NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
258 {
259         int i;
260         char *base;
261
262         NDR_ALLOC_N_SIZE(ndr, *info, count, elsize);
263         base = (char *)*info;
264
265         for (i = 0; i < count; i++) {
266                 ndr->data += ndr->offset;
267                 ndr->offset = 0;
268                 NDR_CHECK(pull_fn(ndr, NDR_SCALARS|NDR_BUFFERS, &base[count * elsize]));
269         }
270
271         return NT_STATUS_OK;
272 }
273
274 /*
275   print a generic array
276 */
277 void ndr_print_array(struct ndr_print *ndr, const char *name, void *base, 
278                      size_t elsize, uint32_t count, 
279                      void (*print_fn)(struct ndr_print *, const char *, void *))
280 {
281         int i;
282         char *p = base;
283         ndr->print(ndr, "%s: ARRAY(%d)", name, count);
284         ndr->depth++;
285         for (i=0;i<count;i++) {
286                 char *idx=NULL;
287                 asprintf(&idx, "[%d]", i);
288                 if (idx) {
289                         print_fn(ndr, idx, p);
290                         free(idx);
291                 }
292                 p += elsize;
293         }
294         ndr->depth--;
295 }
296
297
298
299 void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
300 {
301         va_list ap;
302         char *s = NULL;
303         int i;
304
305         va_start(ap, format);
306         vasprintf(&s, format, ap);
307         va_end(ap);
308
309         for (i=0;i<ndr->depth;i++) {
310                 DEBUG(0,("    "));
311         }
312
313         DEBUG(0,("%s\n", s));
314         free(s);
315 }
316
317 /*
318   a useful helper function for printing idl structures via DEBUG()
319 */
320 void ndr_print_debug(void (*fn)(struct ndr_print *, const char *, void *),
321                      const char *name,
322                      void *ptr)
323 {
324         struct ndr_print *ndr;
325
326         ndr = talloc_p(NULL, struct ndr_print);
327         if (!ndr) return;
328         ndr->print = ndr_print_debug_helper;
329         ndr->depth = 1;
330         ndr->flags = 0;
331         fn(ndr, name, ptr);
332         talloc_free(ndr);
333 }
334
335
336 /*
337   a useful helper function for printing idl unions via DEBUG()
338 */
339 void ndr_print_union_debug(void (*fn)(struct ndr_print *, const char *, uint32_t, void *),
340                            const char *name,
341                            uint32_t level,
342                            void *ptr)
343 {
344         struct ndr_print *ndr;
345
346         ndr = talloc_p(NULL, struct ndr_print);
347         if (!ndr) return;
348         ndr->print = ndr_print_debug_helper;
349         ndr->depth = 1;
350         ndr->flags = 0;
351         fn(ndr, name, level, ptr);
352         talloc_free(ndr);
353 }
354
355 /*
356   a useful helper function for printing idl function calls via DEBUG()
357 */
358 void ndr_print_function_debug(void (*fn)(struct ndr_print *, const char *, int , void *),
359                               const char *name,
360                               int flags,
361                               void *ptr)
362 {
363         struct ndr_print *ndr;
364
365         ndr = talloc_p(NULL, struct ndr_print);
366         if (!ndr) return;
367         ndr->print = ndr_print_debug_helper;
368         ndr->depth = 1;
369         ndr->flags = 0;
370         fn(ndr, name, flags, ptr);
371         talloc_free(ndr);
372 }
373
374 void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
375 {
376         /* the big/little endian flags are inter-dependent */
377         if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
378                 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
379         }
380         if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
381                 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
382         }
383         (*pflags) |= new_flags;
384 }
385
386 static NTSTATUS ndr_map_error(enum ndr_err_code err)
387 {
388         switch (err) {
389         case NDR_ERR_BUFSIZE:
390                 return NT_STATUS_BUFFER_TOO_SMALL;
391         case NDR_ERR_ALLOC:
392                 return NT_STATUS_NO_MEMORY;
393         default:
394                 break;
395         }
396
397         /* we should all error codes to different status codes */
398         return NT_STATUS_INVALID_PARAMETER;
399 }
400
401 /*
402   return and possibly log an NDR error
403 */
404 NTSTATUS ndr_pull_error(struct ndr_pull *ndr, 
405                         enum ndr_err_code err, const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
406 {
407         char *s=NULL;
408         va_list ap;
409
410         va_start(ap, format);
411         vasprintf(&s, format, ap);
412         va_end(ap);
413
414         DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
415
416         free(s);
417
418         return ndr_map_error(err);
419 }
420
421 /*
422   return and possibly log an NDR error
423 */
424 NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char *format, ...)  _PRINTF_ATTRIBUTE(3,4)
425 {
426         char *s=NULL;
427         va_list ap;
428
429         va_start(ap, format);
430         vasprintf(&s, format, ap);
431         va_end(ap);
432
433         DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
434
435         free(s);
436
437         return ndr_map_error(err);
438 }
439
440
441 /*
442   handle subcontext buffers, which in midl land are user-marshalled, but
443   we use magic in pidl to make them easier to cope with
444 */
445 static NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr, 
446                                            size_t sub_size,
447                                            struct ndr_pull *ndr2)
448 {
449         switch (sub_size) {
450         case 0: {
451                 uint32_t size = ndr->data_size - ndr->offset;
452                 if (size == 0) return NT_STATUS_OK;
453                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
454                 break;
455         }
456
457         case 2: {
458                 uint16_t size;
459                 NDR_CHECK(ndr_pull_uint16(ndr, &size));
460                 if (size == 0) return NT_STATUS_OK;
461                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
462                 break;
463         }
464
465         case 4: {
466                 uint32_t size;
467                 NDR_CHECK(ndr_pull_uint32(ndr, &size));
468                 if (size == 0) return NT_STATUS_OK;
469                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
470                 break;
471         }
472         default:
473                 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d", 
474                                       sub_size);
475         }
476         return NT_STATUS_OK;
477 }
478
479 /*
480   handle subcontext buffers, which in midl land are user-marshalled, but
481   we use magic in pidl to make them easier to cope with
482 */
483 NTSTATUS ndr_pull_subcontext_fn(struct ndr_pull *ndr, 
484                                 size_t sub_size,
485                                 void *base,
486                                 NTSTATUS (*fn)(struct ndr_pull *, void *))
487 {
488         struct ndr_pull *ndr2;
489         NDR_ALLOC(ndr, ndr2);
490         NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, ndr2));
491         NDR_CHECK(fn(ndr2, base));
492         if (sub_size) {
493                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->data_size));
494         } else {
495                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->offset));
496         }
497         return NT_STATUS_OK;
498 }
499
500
501 NTSTATUS ndr_pull_subcontext_flags_fn(struct ndr_pull *ndr, 
502                                       size_t sub_size,
503                                       void *base,
504                                       NTSTATUS (*fn)(struct ndr_pull *, int , void *))
505 {
506         struct ndr_pull *ndr2;
507         NDR_ALLOC(ndr, ndr2);
508         NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, ndr2));
509         NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, base));
510         if (sub_size) {
511                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->data_size));
512         } else {
513                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->offset));
514         }
515         return NT_STATUS_OK;
516 }
517
518 NTSTATUS ndr_pull_subcontext_union_fn(struct ndr_pull *ndr, 
519                                       size_t sub_size,
520                                       uint32_t level,
521                                       void *base,
522                                       NTSTATUS (*fn)(struct ndr_pull *, int , uint32_t , void *))
523 {
524         struct ndr_pull *ndr2;
525
526         NDR_ALLOC(ndr, ndr2);
527         NDR_CHECK(ndr_pull_subcontext_header(ndr, sub_size, ndr2));
528         NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
529         if (sub_size) {
530                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->data_size));
531         } else {
532                 NDR_CHECK(ndr_pull_advance(ndr, ndr2->offset));
533         }
534         return NT_STATUS_OK;
535 }
536
537
538 /*
539   push a subcontext header 
540 */
541 static NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr, 
542                                            size_t sub_size,
543                                            struct ndr_push *ndr2)
544 {
545         switch (sub_size) {
546         case 0: 
547                 break;
548
549         case 2: 
550                 NDR_CHECK(ndr_push_uint16(ndr, ndr2->offset));
551                 break;
552
553         case 4: 
554                 NDR_CHECK(ndr_push_uint32(ndr, ndr2->offset));
555                 break;
556
557         default:
558                 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d", 
559                                       sub_size);
560         }
561         return NT_STATUS_OK;
562 }
563
564 /*
565   handle subcontext buffers, which in midl land are user-marshalled, but
566   we use magic in pidl to make them easier to cope with
567 */
568 NTSTATUS ndr_push_subcontext_fn(struct ndr_push *ndr, 
569                                 size_t sub_size,
570                                 void *base,
571                                 NTSTATUS (*fn)(struct ndr_push *, void *))
572 {
573         struct ndr_push *ndr2;
574
575         ndr2 = ndr_push_init_ctx(ndr);
576         if (!ndr2) return NT_STATUS_NO_MEMORY;
577
578         ndr2->flags = ndr->flags;
579         NDR_CHECK(fn(ndr2, base));
580         NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
581         NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
582         return NT_STATUS_OK;
583 }
584
585 /*
586   handle subcontext buffers for function that take a flags arg
587 */
588 NTSTATUS ndr_push_subcontext_flags_fn(struct ndr_push *ndr, 
589                                       size_t sub_size,
590                                       void *base,
591                                       NTSTATUS (*fn)(struct ndr_push *, int, void *))
592 {
593         struct ndr_push *ndr2;
594
595         ndr2 = ndr_push_init_ctx(ndr);
596         if (!ndr2) return NT_STATUS_NO_MEMORY;
597
598         ndr2->flags = ndr->flags;
599         NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, base));
600         NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
601         NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
602         return NT_STATUS_OK;
603 }
604
605 /*
606   handle subcontext buffers for function that take a union
607 */
608 NTSTATUS ndr_push_subcontext_union_fn(struct ndr_push *ndr, 
609                                       size_t sub_size,
610                                       uint32_t level,
611                                       void *base,
612                                       NTSTATUS (*fn)(struct ndr_push *, int, uint32_t, void *))
613 {
614         struct ndr_push *ndr2;
615
616         ndr2 = ndr_push_init_ctx(ndr);
617         if (!ndr2) return NT_STATUS_NO_MEMORY;
618
619         ndr2->flags = ndr->flags;
620         NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
621         NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
622         NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
623         return NT_STATUS_OK;
624 }
625
626
627 /*
628   mark the start of a structure
629 */
630 NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
631 {
632         return NT_STATUS_OK;
633 }
634
635 /*
636   mark the end of a structure
637 */
638 void ndr_pull_struct_end(struct ndr_pull *ndr)
639 {
640 }
641
642 /*
643   mark the start of a structure
644 */
645 NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
646 {
647         return NT_STATUS_OK;
648 }
649
650 /*
651   mark the end of a structure
652 */
653 void ndr_push_struct_end(struct ndr_push *ndr)
654 {
655 }
656
657 /*
658   store a token in the ndr context, for later retrieval
659 */
660 static NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx, 
661                                 struct ndr_token_list **list, 
662                                 const void *key, 
663                                 uint32_t value)
664 {
665         struct ndr_token_list *tok;
666         tok = talloc_p(mem_ctx, struct ndr_token_list);
667         if (tok == NULL) {
668                 return NT_STATUS_NO_MEMORY;
669         }
670         tok->key = key;
671         tok->value = value;
672         DLIST_ADD((*list), tok);
673         return NT_STATUS_OK;
674 }
675
676 /*
677   retrieve a token from a ndr context
678 */
679 static uint32_t ndr_token_retrieve(struct ndr_token_list **list, const void *key)
680 {
681         struct ndr_token_list *tok;
682         for (tok=*list;tok;tok=tok->next) {
683                 if (tok->key == key) {
684                         DLIST_REMOVE((*list), tok);
685                         return tok->value;
686                 }
687         }
688         return 0;
689 }
690
691
692 /*
693   pull a relative object - stage1
694   called during SCALARS processing
695 */
696 NTSTATUS ndr_pull_relative1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
697 {
698         if (ndr->flags & LIBNDR_FLAG_RELATIVE_CURRENT) {
699                 return ndr_token_store(ndr, &ndr->relative_list, p, 
700                                        rel_offset + ndr->offset - 4);
701         } else {
702                 return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
703         }
704 }
705
706 /*
707   pull a relative object - stage2
708   called during BUFFERS processing
709 */
710 NTSTATUS ndr_pull_relative2(struct ndr_pull *ndr, const void *p)
711 {
712         uint32_t rel_offset;
713         rel_offset = ndr_token_retrieve(&ndr->relative_list, p);
714         if (rel_offset == 0) {
715                 return NT_STATUS_INTERNAL_ERROR;
716         }
717         return ndr_pull_set_offset(ndr, rel_offset);
718 }
719
720 /*
721   push a relative object - stage1
722   this is called during SCALARS processing
723 */
724 NTSTATUS ndr_push_relative1(struct ndr_push *ndr, const void *p)
725 {
726         if (p == NULL) {
727                 NDR_CHECK(ndr_push_uint32(ndr, 0));
728                 return NT_STATUS_OK;
729         }
730         NDR_CHECK(ndr_push_align(ndr, 4));
731         NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
732         return ndr_push_uint32(ndr, 0xFFFFFFFF);
733 }
734
735 /*
736   push a relative object - stage2
737   this is called during buffers processing
738 */
739 NTSTATUS ndr_push_relative2(struct ndr_push *ndr, const void *p)
740 {
741         struct ndr_push_save save;
742         if (p == NULL) {
743                 return NT_STATUS_OK;
744         }
745         NDR_CHECK(ndr_push_align(ndr, 4));
746         ndr_push_save(ndr, &save);
747         ndr->offset = ndr_token_retrieve(&ndr->relative_list, p);
748         if (ndr->offset == 0) {
749                 return NT_STATUS_INTERNAL_ERROR;
750         }
751         if (ndr->flags & LIBNDR_FLAG_RELATIVE_CURRENT) {
752                 NDR_CHECK(ndr_push_uint32(ndr, save.offset - ndr->offset));
753         } else {
754                 NDR_CHECK(ndr_push_uint32(ndr, save.offset));
755         }
756         ndr_push_restore(ndr, &save);
757         return NT_STATUS_OK;
758 }
759
760
761 /*
762   pull a union from a blob using NDR
763 */
764 NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32_t level, void *p,
765                              NTSTATUS (*fn)(struct ndr_pull *, int ndr_flags, uint32_t, void *))
766 {
767         struct ndr_pull *ndr;
768         ndr = ndr_pull_init_blob(blob, mem_ctx);
769         if (!ndr) {
770                 return NT_STATUS_NO_MEMORY;
771         }
772         return fn(ndr, NDR_SCALARS|NDR_BUFFERS, level, p);
773 }
774
775 /*
776   pull a struct from a blob using NDR
777 */
778 NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
779                               NTSTATUS (*fn)(struct ndr_pull *, int , void *))
780 {
781         struct ndr_pull *ndr;
782         ndr = ndr_pull_init_blob(blob, mem_ctx);
783         if (!ndr) {
784                 return NT_STATUS_NO_MEMORY;
785         }
786         return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
787 }
788
789 /*
790   push a struct to a blob using NDR
791 */
792 NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
793                               NTSTATUS (*fn)(struct ndr_push *, int , void *))
794 {
795         NTSTATUS status;
796         struct ndr_push *ndr;
797         ndr = ndr_push_init_ctx(mem_ctx);
798         if (!ndr) {
799                 return NT_STATUS_NO_MEMORY;
800         }
801         status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
802         if (!NT_STATUS_IS_OK(status)) {
803                 return status;
804         }
805
806         *blob = ndr_push_blob(ndr);
807
808         return NT_STATUS_OK;
809 }