r8108: Fix indentation, and remove a discard_const_p() that we don't need any more.
[ira/wip.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 #include "dlinklist.h"
32
33 #define NDR_BASE_MARSHALL_SIZE 1024
34
35 /*
36   work out the number of bytes needed to align on a n byte boundary
37 */
38 size_t ndr_align_size(uint32_t offset, size_t n)
39 {
40         if ((offset & (n-1)) == 0) return 0;
41         return n - (offset & (n-1));
42 }
43
44 /*
45   initialise a ndr parse structure from a data blob
46 */
47 struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
48 {
49         struct ndr_pull *ndr;
50
51         ndr = talloc_zero(mem_ctx, struct ndr_pull);
52         if (!ndr) return NULL;
53
54         ndr->data = blob->data;
55         ndr->data_size = blob->length;
56
57         return ndr;
58 }
59
60 /*
61   create an ndr sub-context based on an existing context. The new context starts
62   at the current offset, with the given size limit
63 */
64 NTSTATUS ndr_pull_subcontext(struct ndr_pull *ndr, struct ndr_pull *ndr2, uint32_t size)
65 {
66         NDR_PULL_NEED_BYTES(ndr, size);
67         *ndr2 = *ndr;
68         ndr2->data += ndr2->offset;
69         ndr2->offset = 0;
70         ndr2->data_size = size;
71         ndr2->flags = ndr->flags;
72         return NT_STATUS_OK;
73 }
74
75
76 /*
77   advance by 'size' bytes
78 */
79 NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
80 {
81         ndr->offset += size;
82         if (ndr->offset > ndr->data_size) {
83                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
84                                       "ndr_pull_advance by %u failed",
85                                       size);
86         }
87         return NT_STATUS_OK;
88 }
89
90 /*
91   set the parse offset to 'ofs'
92 */
93 static NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
94 {
95         ndr->offset = ofs;
96         if (ndr->offset > ndr->data_size) {
97                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
98                                       "ndr_pull_set_offset %u failed",
99                                       ofs);
100         }
101         return NT_STATUS_OK;
102 }
103
104 /* save the offset/size of the current ndr state */
105 void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
106 {
107         save->offset = ndr->offset;
108         save->data_size = ndr->data_size;
109 }
110
111 /* restore the size/offset of a ndr structure */
112 void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
113 {
114         ndr->offset = save->offset;
115         ndr->data_size = save->data_size;
116 }
117
118
119 /* create a ndr_push structure, ready for some marshalling */
120 struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
121 {
122         struct ndr_push *ndr;
123
124         ndr = talloc_zero(mem_ctx, struct ndr_push);
125         if (!ndr) {
126                 return NULL;
127         }
128
129         ndr->flags = 0;
130         ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
131         ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
132         if (!ndr->data) {
133                 return NULL;
134         }
135
136         return ndr;
137 }
138
139
140 /* create a ndr_push structure, ready for some marshalling */
141 struct ndr_push *ndr_push_init(void)
142 {
143         return ndr_push_init_ctx(NULL);
144 }
145
146 /* free a ndr_push structure */
147 void ndr_push_free(struct ndr_push *ndr)
148 {
149         talloc_free(ndr);
150 }
151
152
153 /* return a DATA_BLOB structure for the current ndr_push marshalled data */
154 DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
155 {
156         DATA_BLOB blob;
157         blob.data = ndr->data;
158         blob.length = ndr->offset;
159         return blob;
160 }
161
162
163 /*
164   expand the available space in the buffer to 'size'
165 */
166 NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size)
167 {
168         if (ndr->alloc_size >= size) {
169                 return NT_STATUS_OK;
170         }
171
172         ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
173         if (size > ndr->alloc_size) {
174                 ndr->alloc_size = size;
175         }
176         ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
177         if (!ndr->data) {
178                 return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
179                                       ndr->alloc_size);
180         }
181
182         return NT_STATUS_OK;
183 }
184
185 void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
186 {
187         va_list ap;
188         char *s = NULL;
189         int i;
190
191         va_start(ap, format);
192         vasprintf(&s, format, ap);
193         va_end(ap);
194
195         for (i=0;i<ndr->depth;i++) {
196                 DEBUG(0,("    "));
197         }
198
199         DEBUG(0,("%s\n", s));
200         free(s);
201 }
202
203 /*
204   a useful helper function for printing idl structures via DEBUG()
205 */
206 void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
207 {
208         struct ndr_print *ndr;
209
210         ndr = talloc_zero(NULL, struct ndr_print);
211         if (!ndr) return;
212         ndr->print = ndr_print_debug_helper;
213         ndr->depth = 1;
214         ndr->flags = 0;
215         fn(ndr, name, ptr);
216         talloc_free(ndr);
217 }
218
219 /*
220   a useful helper function for printing idl unions via DEBUG()
221 */
222 void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
223 {
224         struct ndr_print *ndr;
225
226         ndr = talloc_zero(NULL, struct ndr_print);
227         if (!ndr) return;
228         ndr->print = ndr_print_debug_helper;
229         ndr->depth = 1;
230         ndr->flags = 0;
231         ndr_print_set_switch_value(ndr, ptr, level);
232         fn(ndr, name, ptr);
233         talloc_free(ndr);
234 }
235
236 /*
237   a useful helper function for printing idl function calls via DEBUG()
238 */
239 void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
240 {
241         struct ndr_print *ndr;
242
243         ndr = talloc_zero(NULL, struct ndr_print);
244         if (!ndr) return;
245         ndr->print = ndr_print_debug_helper;
246         ndr->depth = 1;
247         ndr->flags = 0;
248         fn(ndr, name, flags, ptr);
249         talloc_free(ndr);
250 }
251
252 void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
253 {
254         /* the big/little endian flags are inter-dependent */
255         if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
256                 (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
257         }
258         if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
259                 (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
260         }
261         (*pflags) |= new_flags;
262 }
263
264 static NTSTATUS ndr_map_error(enum ndr_err_code err)
265 {
266         switch (err) {
267         case NDR_ERR_BUFSIZE:
268                 return NT_STATUS_BUFFER_TOO_SMALL;
269         case NDR_ERR_TOKEN:
270                 return NT_STATUS_INTERNAL_ERROR;
271         case NDR_ERR_ALLOC:
272                 return NT_STATUS_NO_MEMORY;
273         case NDR_ERR_ARRAY_SIZE:
274                 return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
275         default:
276                 break;
277         }
278
279         /* we should map all error codes to different status codes */
280         return NT_STATUS_INVALID_PARAMETER;
281 }
282
283 /*
284   return and possibly log an NDR error
285 */
286 NTSTATUS ndr_pull_error(struct ndr_pull *ndr, 
287                         enum ndr_err_code err, const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
288 {
289         char *s=NULL;
290         va_list ap;
291
292         va_start(ap, format);
293         vasprintf(&s, format, ap);
294         va_end(ap);
295
296         DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
297
298         free(s);
299
300         return ndr_map_error(err);
301 }
302
303 /*
304   return and possibly log an NDR error
305 */
306 NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char *format, ...)  _PRINTF_ATTRIBUTE(3,4)
307 {
308         char *s=NULL;
309         va_list ap;
310
311         va_start(ap, format);
312         vasprintf(&s, format, ap);
313         va_end(ap);
314
315         DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
316
317         free(s);
318
319         return ndr_map_error(err);
320 }
321
322
323 /*
324   handle subcontext buffers, which in midl land are user-marshalled, but
325   we use magic in pidl to make them easier to cope with
326 */
327 NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr, 
328                                     size_t header_size,
329                                     ssize_t size_is,
330                                     struct ndr_pull *ndr2)
331 {
332         ndr2->flags = ndr->flags;
333
334         switch (header_size) {
335         case 0: {
336                 uint32_t content_size = ndr->data_size - ndr->offset;
337                 if (size_is >= 0) {
338                         content_size = size_is;
339                 }
340                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
341                 break;
342         }
343
344         case 2: {
345                 uint16_t content_size;
346                 NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
347                 if (size_is >= 0 && size_is != content_size) {
348                         return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
349                                                 size_is, content_size);
350                 }
351                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
352                 break;
353         }
354
355         case 4: {
356                 uint32_t content_size;
357                 NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
358                 if (size_is >= 0 && size_is != content_size) {
359                         return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
360                                                 size_is, content_size);
361                 }
362                 NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
363                 break;
364         }
365         default:
366                 return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", 
367                                       header_size);
368         }
369         return NT_STATUS_OK;
370 }
371
372 /*
373   push a subcontext header 
374 */
375 NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr, 
376                                            size_t header_size,
377                                            ssize_t size_is,
378                                            struct ndr_push *ndr2)
379 {
380         if (size_is >= 0) {
381                 ssize_t padding_len = size_is - ndr2->offset;
382                 if (padding_len > 0) {
383                         NDR_CHECK(ndr_push_zero(ndr2, padding_len));
384                 } else if (padding_len < 0) {
385                         return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
386                                               ndr2->offset, size_is);
387                 }
388         }
389
390         switch (header_size) {
391         case 0: 
392                 break;
393
394         case 2: 
395                 NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr2->offset));
396                 break;
397
398         case 4: 
399                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr2->offset));
400                 break;
401
402         default:
403                 return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d", 
404                                       header_size);
405         }
406         return NT_STATUS_OK;
407 }
408
409 /*
410   store a token in the ndr context, for later retrieval
411 */
412 static NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx, 
413                                 struct ndr_token_list **list, 
414                                 const void *key, 
415                                 uint32_t value)
416 {
417         struct ndr_token_list *tok;
418         tok = talloc(mem_ctx, struct ndr_token_list);
419         if (tok == NULL) {
420                 return NT_STATUS_NO_MEMORY;
421         }
422         tok->key = key;
423         tok->value = value;
424         DLIST_ADD((*list), tok);
425         return NT_STATUS_OK;
426 }
427
428 /*
429   retrieve a token from a ndr context
430 */
431 static NTSTATUS ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
432 {
433         struct ndr_token_list *tok;
434         for (tok=*list;tok;tok=tok->next) {
435                 if (tok->key == key) {
436                         DLIST_REMOVE((*list), tok);
437                         *v = tok->value;
438                         return NT_STATUS_OK;
439                 }
440         }
441         return ndr_map_error(NDR_ERR_TOKEN);
442 }
443
444 /*
445   peek at but don't removed a token from a ndr context
446 */
447 static uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
448 {
449         struct ndr_token_list *tok;
450         for (tok=*list;tok;tok=tok->next) {
451                 if (tok->key == key) {
452                         return tok->value;
453                 }
454         }
455         return 0;
456 }
457
458 /*
459   pull an array size field and add it to the array_size_list token list
460 */
461 NTSTATUS ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
462 {
463         uint32_t size;
464         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
465         return ndr_token_store(ndr, &ndr->array_size_list, p, size);
466 }
467
468 /*
469   get the stored array size field
470 */
471 uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
472 {
473         return ndr_token_peek(&ndr->array_size_list, p);
474 }
475
476 /*
477   check the stored array size field
478 */
479 NTSTATUS ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
480 {
481         uint32_t stored;
482         stored = ndr_token_peek(&ndr->array_size_list, p);
483         if (stored != size) {
484                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
485                                       "Bad array size - got %u expected %u\n",
486                                       stored, size);
487         }
488         return NT_STATUS_OK;
489 }
490
491 /*
492   pull an array length field and add it to the array_length_list token list
493 */
494 NTSTATUS ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
495 {
496         uint32_t length, offset;
497         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &offset));
498         if (offset != 0) {
499                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
500                                       "non-zero array offset %u\n", offset);
501         }
502         NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
503         return ndr_token_store(ndr, &ndr->array_length_list, p, length);
504 }
505
506 /*
507   get the stored array length field
508 */
509 uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
510 {
511         return ndr_token_peek(&ndr->array_length_list, p);
512 }
513
514 /*
515   check the stored array length field
516 */
517 NTSTATUS ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
518 {
519         uint32_t stored;
520         stored = ndr_token_peek(&ndr->array_length_list, p);
521         if (stored != length) {
522                 return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
523                                       "Bad array length - got %u expected %u\n",
524                                       stored, length);
525         }
526         return NT_STATUS_OK;
527 }
528
529 /*
530   store a switch value
531  */
532 NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
533 {
534         return ndr_token_store(ndr, &ndr->switch_list, p, val);
535 }
536
537 NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
538 {
539         return ndr_token_store(ndr, &ndr->switch_list, p, val);
540 }
541
542 NTSTATUS ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
543 {
544         return ndr_token_store(ndr, &ndr->switch_list, p, val);
545 }
546
547 /*
548   retrieve a switch value
549  */
550 uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
551 {
552         return ndr_token_peek(&ndr->switch_list, p);
553 }
554
555 uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
556 {
557         return ndr_token_peek(&ndr->switch_list, p);
558 }
559
560 uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
561 {
562         return ndr_token_peek(&ndr->switch_list, p);
563 }
564
565 /*
566   pull a struct from a blob using NDR
567 */
568 NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
569                               ndr_pull_flags_fn_t fn)
570 {
571         struct ndr_pull *ndr;
572         ndr = ndr_pull_init_blob(blob, mem_ctx);
573         if (!ndr) {
574                 return NT_STATUS_NO_MEMORY;
575         }
576         return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
577 }
578
579 /*
580   pull a struct from a blob using NDR - failing if all bytes are not consumed
581 */
582 NTSTATUS ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
583                                   ndr_pull_flags_fn_t fn)
584 {
585         struct ndr_pull *ndr;
586         NTSTATUS status;
587
588         ndr = ndr_pull_init_blob(blob, mem_ctx);
589         if (!ndr) {
590                 return NT_STATUS_NO_MEMORY;
591         }
592         status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
593         if (!NT_STATUS_IS_OK(status)) return status;
594         if (ndr->offset != ndr->data_size) {
595                 return NT_STATUS_BUFFER_TOO_SMALL;
596         }
597         return status;
598 }
599
600 /*
601   pull a union from a blob using NDR, given the union discriminator
602 */
603 NTSTATUS ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
604                              uint32_t level, ndr_pull_flags_fn_t fn)
605 {
606         struct ndr_pull *ndr;
607         NTSTATUS status;
608
609         ndr = ndr_pull_init_blob(blob, mem_ctx);
610         if (!ndr) {
611                 return NT_STATUS_NO_MEMORY;
612         }
613         ndr_pull_set_switch_value(ndr, p, level);
614         status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
615         if (!NT_STATUS_IS_OK(status)) return status;
616         if (ndr->offset != ndr->data_size) {
617                 return NT_STATUS_BUFFER_TOO_SMALL;
618         }
619         return status;
620 }
621
622 /*
623   push a struct to a blob using NDR
624 */
625 NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p,
626                               ndr_push_flags_fn_t fn)
627 {
628         NTSTATUS status;
629         struct ndr_push *ndr;
630         ndr = ndr_push_init_ctx(mem_ctx);
631         if (!ndr) {
632                 return NT_STATUS_NO_MEMORY;
633         }
634         status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
635         if (!NT_STATUS_IS_OK(status)) {
636                 return status;
637         }
638
639         *blob = ndr_push_blob(ndr);
640
641         return NT_STATUS_OK;
642 }
643
644 /*
645   push a union to a blob using NDR
646 */
647 NTSTATUS ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
648                              uint32_t level, ndr_push_flags_fn_t fn)
649 {
650         NTSTATUS status;
651         struct ndr_push *ndr;
652         ndr = ndr_push_init_ctx(mem_ctx);
653         if (!ndr) {
654                 return NT_STATUS_NO_MEMORY;
655         }
656         ndr_push_set_switch_value(ndr, p, level);
657         status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
658         if (!NT_STATUS_IS_OK(status)) {
659                 return status;
660         }
661
662         *blob = ndr_push_blob(ndr);
663
664         return NT_STATUS_OK;
665 }
666
667 /*
668   generic ndr_size_*() handler for structures
669 */
670 size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
671 {
672         struct ndr_push *ndr;
673         NTSTATUS status;
674         size_t ret;
675
676         /* avoid recursion */
677         if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
678
679         ndr = ndr_push_init_ctx(NULL);
680         if (!ndr) return 0;
681         ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
682         status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
683         if (!NT_STATUS_IS_OK(status)) {
684                 return 0;
685         }
686         ret = ndr->offset;
687         talloc_free(ndr);
688         return ret;
689 }
690
691 /*
692   generic ndr_size_*() handler for unions
693 */
694 size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
695 {
696         struct ndr_push *ndr;
697         NTSTATUS status;
698         size_t ret;
699
700         /* avoid recursion */
701         if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
702
703         ndr = ndr_push_init_ctx(NULL);
704         if (!ndr) return 0;
705         ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
706         ndr_push_set_switch_value(ndr, p, level);
707         status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
708         if (!NT_STATUS_IS_OK(status)) {
709                 return 0;
710         }
711         ret = ndr->offset;
712         talloc_free(ndr);
713         return ret;
714 }
715
716 /*
717   get the current base for relative pointers for the push
718 */
719 uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
720 {
721         return ndr->relative_base_offset;
722 }
723
724 /*
725   restore the old base for relative pointers for the push
726 */
727 void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
728 {
729         ndr->relative_base_offset = offset;
730 }
731
732 /*
733   setup the current base for relative pointers for the push
734   called in the NDR_SCALAR stage
735 */
736 NTSTATUS ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
737 {
738         ndr->relative_base_offset = offset;
739         return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
740 }
741
742 /*
743   setup the current base for relative pointers for the push
744   called in the NDR_BUFFERS stage
745 */
746 NTSTATUS ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
747 {
748         return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
749 }
750
751 /*
752   push a relative object - stage1
753   this is called during SCALARS processing
754 */
755 NTSTATUS ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
756 {
757         if (p == NULL) {
758                 NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
759                 return NT_STATUS_OK;
760         }
761         NDR_CHECK(ndr_push_align(ndr, 4));
762         NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
763         return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
764 }
765
766 /*
767   push a relative object - stage2
768   this is called during buffers processing
769 */
770 NTSTATUS ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
771 {
772         struct ndr_push_save save;
773         uint32_t ptr_offset = 0xFFFFFFFF;
774         if (p == NULL) {
775                 return NT_STATUS_OK;
776         }
777         ndr_push_save(ndr, &save);
778         NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
779         if (ptr_offset > ndr->offset) {
780                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
781                                       "ndr_push_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
782                                       ptr_offset, ndr->offset);
783         }
784         ndr->offset = ptr_offset;
785         if (save.offset < ndr->relative_base_offset) {
786                 return ndr_push_error(ndr, NDR_ERR_BUFSIZE, 
787                                       "ndr_push_relative_ptr2 save.offset(%u) < ndr->relative_base_offset(%u)",
788                                       save.offset, ndr->relative_base_offset);
789         }       
790         NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset - ndr->relative_base_offset));
791         ndr_push_restore(ndr, &save);
792         return NT_STATUS_OK;
793 }
794
795 /*
796   get the current base for relative pointers for the pull
797 */
798 uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
799 {
800         return ndr->relative_base_offset;
801 }
802
803 /*
804   restore the old base for relative pointers for the pull
805 */
806 void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
807 {
808         ndr->relative_base_offset = offset;
809 }
810
811 /*
812   setup the current base for relative pointers for the pull
813   called in the NDR_SCALAR stage
814 */
815 NTSTATUS ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
816 {
817         ndr->relative_base_offset = offset;
818         return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
819 }
820
821 /*
822   setup the current base for relative pointers for the pull
823   called in the NDR_BUFFERS stage
824 */
825 NTSTATUS ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
826 {
827         return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
828 }
829
830 /*
831   pull a relative object - stage1
832   called during SCALARS processing
833 */
834 NTSTATUS ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
835 {
836         rel_offset += ndr->relative_base_offset;
837         if (rel_offset > ndr->data_size) {
838                 return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
839                                       "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
840                                       rel_offset, ndr->data_size);
841         }
842         return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
843 }
844
845 /*
846   pull a relative object - stage2
847   called during BUFFERS processing
848 */
849 NTSTATUS ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
850 {
851         uint32_t rel_offset;
852         NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
853         return ndr_pull_set_offset(ndr, rel_offset);
854 }