94a6100aa1a0a873c9159784c25ae0b98aca5eb7
[abartlet/samba.git/.git] / source3 / rpc_parse / parse_prs.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba memory buffer functions
5    Copyright (C) Andrew Tridgell              1992-1997
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1997
7    Copyright (C) Jeremy Allison 1999.
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 extern int DEBUGLEVEL;
25
26 #include "includes.h"
27
28
29 /*******************************************************************
30 dump a prs to a file
31  ********************************************************************/
32 void prs_dump(char *name, int v, prs_struct *ps)
33 {
34         int fd, i;
35         pstring fname;
36         if (DEBUGLEVEL < 50) return;
37         for (i=1;i<100;i++) {
38                 if (v != -1) {
39                         slprintf(fname,sizeof(fname), "/tmp/%s_%d.%d.prs", name, v, i);
40                 } else {
41                         slprintf(fname,sizeof(fname), "/tmp/%s.%d.prs", name, i);
42                 }
43                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
44                 if (fd != -1 || errno != EEXIST) break;
45         }
46         if (fd != -1) {
47                 write(fd, ps->data_p + ps->data_offset, ps->grow_size - ps->data_offset);
48                 close(fd);
49                 DEBUG(0,("created %s\n", fname));
50         }
51 }
52
53
54
55 /*******************************************************************
56  debug output for parsing info.
57
58  XXXX side-effect of this function is to increase the debug depth XXXX
59
60  ********************************************************************/
61 void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
62 {
63         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
64 }
65
66 /*******************************************************************
67  Initialise a parse structure - malloc the data if requested.
68  ********************************************************************/
69
70 BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io)
71 {
72         ZERO_STRUCTP(ps);
73         ps->io = io;
74         ps->bigendian_data = False;
75         ps->align = align;
76         ps->is_dynamic = False;
77         ps->data_offset = 0;
78         ps->buffer_size = 0;
79         ps->data_p = NULL;
80
81         if (size != 0) {
82                 ps->buffer_size = size;
83                 if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
84                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
85                         return False;
86                 }
87                 ps->is_dynamic = True; /* We own this memory. */
88         }
89
90         return True;
91 }
92
93 /*******************************************************************
94  read from a socket into memory.
95  ********************************************************************/
96 BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout)
97 {
98         BOOL ok;
99         size_t prev_size = ps->buffer_size;
100         if (!prs_grow(ps, len))
101         {
102                 return False;
103         }
104
105         if (timeout > 0)
106         {
107                 ok = (read_with_timeout(fd, &ps->data_p[prev_size],
108                                             len, len,timeout) == len);
109         }
110         else 
111         {
112                 ok = (read_data(fd, &ps->data_p[prev_size], len) == len);
113         }
114         return ok;
115 }
116
117 /*******************************************************************
118  Delete the memory in a parse structure - if we own it.
119  ********************************************************************/
120
121 void prs_mem_free(prs_struct *ps)
122 {
123         if(ps->is_dynamic && (ps->data_p != NULL))
124                 free(ps->data_p);
125         ps->is_dynamic = False;
126         ps->data_p = NULL;
127         ps->buffer_size = 0;
128         ps->data_offset = 0;
129 }
130
131 /*******************************************************************
132  Hand some already allocated memory to a prs_struct.
133  ********************************************************************/
134
135 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
136 {
137         ps->is_dynamic = is_dynamic;
138         ps->data_p = buf;
139         ps->buffer_size = size;
140 }
141
142 /*******************************************************************
143  Take some memory back from a prs_struct.
144  ********************************************************************/
145
146 char *prs_take_memory(prs_struct *ps, uint32 *psize)
147 {
148         char *ret = ps->data_p;
149         if(psize)
150                 *psize = ps->buffer_size;
151         ps->is_dynamic = False;
152         prs_mem_free(ps);
153         return ret;
154 }
155
156 /*******************************************************************
157  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
158  ********************************************************************/
159
160 BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
161 {
162         if (newsize > ps->buffer_size)
163                 return prs_force_grow(ps, newsize - ps->buffer_size);
164
165         if (newsize < ps->buffer_size) {
166                 char *new_data_p = Realloc(ps->data_p, newsize);
167                 /* if newsize is zero, Realloc acts like free() & returns NULL*/
168                 if (new_data_p == NULL && newsize != 0) {
169                         DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
170                                 (unsigned int)newsize));
171                         DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
172                         return False;
173                 }
174                 ps->data_p = new_data_p;
175                 ps->buffer_size = newsize;
176         }
177
178         return True;
179 }
180
181 /*******************************************************************
182  Attempt, if needed, to grow a data buffer.
183  Also depends on the data stream mode (io).
184  ********************************************************************/
185
186 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
187 {
188         uint32 new_size;
189         char *new_data;
190
191         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
192
193         if(ps->data_offset + extra_space <= ps->buffer_size)
194                 return True;
195
196         /*
197          * We cannot grow the buffer if we're not reading
198          * into the prs_struct, or if we don't own the memory.
199          */
200
201         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
202                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
203                                 (unsigned int)extra_space));
204                 return False;
205         }
206         
207         /*
208          * Decide how much extra space we really need.
209          */
210
211         extra_space -= (ps->buffer_size - ps->data_offset);
212         if(ps->buffer_size == 0) {
213                 /*
214                  * Ensure we have at least a PDU's length, or extra_space, whichever
215                  * is greater.
216                  */
217
218                 new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
219
220                 if((new_data = malloc(new_size)) == NULL) {
221                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
222                         return False;
223                 }
224                 memset(new_data, '\0', new_size );
225         } else {
226                 /*
227                  * If the current buffer size is bigger than the space needed, just 
228                  * double it, else add extra_space.
229                  */
230                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
231
232                 if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
233                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
234                                 (unsigned int)new_size));
235                         return False;
236                 }
237
238                 memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
239         }
240         ps->buffer_size = new_size;
241         ps->data_p = new_data;
242
243         return True;
244 }
245
246 /*******************************************************************
247  Attempt to force a data buffer to grow by len bytes.
248  This is only used when appending more data onto a prs_struct
249  when reading an rpc reply, before unmarshalling it.
250  ********************************************************************/
251
252 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
253 {
254         uint32 new_size = ps->buffer_size + extra_space;
255         char *new_data;
256
257         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
258                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
259                                 (unsigned int)extra_space));
260                 return False;
261         }
262
263         if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
264                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
265                         (unsigned int)new_size));
266                 return False;
267         }
268
269         memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
270
271         ps->buffer_size = new_size;
272         ps->data_p = new_data;
273
274         return True;
275 }
276
277 /*******************************************************************
278  Get the data pointer (external interface).
279  ********************************************************************/
280
281 char *prs_data_p(prs_struct *ps)
282 {
283         return ps->data_p;
284 }
285
286 /*******************************************************************
287  Get the current data size (external interface).
288  ********************************************************************/
289
290 uint32 prs_data_size(prs_struct *ps)
291 {
292         return ps->buffer_size;
293 }
294
295 /*******************************************************************
296  Fetch the current offset (external interface).
297  ********************************************************************/
298
299 uint32 prs_offset(prs_struct *ps)
300 {
301         return ps->data_offset;
302 }
303
304 /*******************************************************************
305  Set the current offset (external interface).
306  ********************************************************************/
307
308 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
309 {
310         if(offset <= ps->data_offset) {
311                 ps->data_offset = offset;
312                 return True;
313         }
314
315         if(!prs_grow(ps, offset - ps->data_offset))
316                 return False;
317
318         ps->data_offset = offset;
319         return True;
320 }
321
322 /*******************************************************************
323  Append the data from one parse_struct into another.
324  ********************************************************************/
325
326 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
327 {
328         if(!prs_grow(dst, prs_offset(src)))
329                 return False;
330
331         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src));
332         dst->data_offset += prs_offset(src);
333
334         return True;
335 }
336
337 /*******************************************************************
338  Append some data from one parse_struct into another.
339  ********************************************************************/
340
341 BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
342 {       
343         if (len == 0)
344                 return True;
345
346         if(!prs_grow(dst, len))
347                 return False;
348         
349         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src)+start, (size_t)len);
350         dst->data_offset += len;
351
352         return True;
353 }
354
355 /*******************************************************************
356  Append the data from a buffer into a parse_struct.
357  ********************************************************************/
358
359 BOOL prs_append_data(prs_struct *dst, char *src, uint32 len)
360 {
361         if(!prs_grow(dst, len))
362                 return False;
363
364         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
365         dst->data_offset += len;
366
367         return True;
368 }
369
370 /*******************************************************************
371  Set the data as big-endian (external interface).
372  ********************************************************************/
373
374 void prs_set_bigendian_data(prs_struct *ps)
375 {
376         ps->bigendian_data = True;
377 }
378
379 /*******************************************************************
380  Align a the data_len to a multiple of align bytes - filling with
381  zeros.
382  ********************************************************************/
383
384 BOOL prs_align(prs_struct *ps)
385 {
386         uint32 mod = ps->data_offset & (ps->align-1);
387
388         if (ps->align != 0 && mod != 0) {
389                 uint32 extra_space = (ps->align - mod);
390                 if(!prs_grow(ps, extra_space))
391                         return False;
392                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
393                 ps->data_offset += extra_space;
394         }
395
396         return True;
397 }
398
399 /*******************************************************************
400  Ensure we can read/write to a given offset.
401  ********************************************************************/
402
403 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
404 {
405         if(UNMARSHALLING(ps)) {
406                 /*
407                  * If reading, ensure that we can read the requested size item.
408                  */
409                 if (ps->data_offset + extra_size > ps->buffer_size) {
410                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
411                                         (unsigned int)extra_size ));
412                         return NULL;
413                 }
414         } else {
415                 /*
416                  * Writing - grow the buffer if needed.
417                  */
418                 if(!prs_grow(ps, extra_size))
419                         return False;
420         }
421         return &ps->data_p[ps->data_offset];
422 }
423
424 /*******************************************************************
425  Change the struct type.
426  ********************************************************************/
427
428 void prs_switch_type(prs_struct *ps, BOOL io)
429 {
430         if ((ps->io ^ io) == True)
431                 ps->io=io;
432 }
433
434 /*******************************************************************
435  Force a prs_struct to be dynamic even when it's size is 0.
436  ********************************************************************/
437
438 void prs_force_dynamic(prs_struct *ps)
439 {
440         ps->is_dynamic=True;
441 }
442
443 /*******************************************************************
444  Stream a uint8.
445  ********************************************************************/
446
447 BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
448 {
449         char *q = prs_mem_get(ps, sizeof(uint8));
450         if (q == NULL)
451                 return False;
452
453         DBG_RW_CVAL(name, depth, ps->data_offset, ps->io, q, *data8)
454         ps->data_offset += sizeof(uint8);
455
456         return True;
457 }
458
459 /*******************************************************************
460  Stream a uint16.
461  ********************************************************************/
462
463 BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
464 {
465         char *q = prs_mem_get(ps, sizeof(uint16));
466         if (q == NULL)
467                 return False;
468
469         DBG_RW_SVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data16)
470         ps->data_offset += sizeof(uint16);
471
472         return True;
473 }
474
475 /*******************************************************************
476  Stream a uint32.
477  ********************************************************************/
478
479 BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
480 {
481         char *q = prs_mem_get(ps, sizeof(uint32));
482         if (q == NULL)
483                 return False;
484
485         DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data32)
486         ps->data_offset += sizeof(uint32);
487
488         return True;
489 }
490
491 /******************************************************************
492  Stream an array of uint8s. Length is number of uint8s.
493  ********************************************************************/
494
495 BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
496 {
497         char *q = prs_mem_get(ps, len * sizeof(uint8));
498         if (q == NULL)
499                 return False;
500
501         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, data8s, len)
502         ps->data_offset += (len * sizeof(uint8));
503
504         return True;
505 }
506
507 /******************************************************************
508  Stream an array of uint16s. Length is number of uint16s.
509  ********************************************************************/
510
511 BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
512 {
513         char *q = prs_mem_get(ps, len * sizeof(uint16));
514         if (q == NULL)
515                 return False;
516
517         DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data16s, len)
518         ps->data_offset += (len * sizeof(uint16));
519
520         return True;
521 }
522
523 /******************************************************************
524  Stream an array of uint32s. Length is number of uint32s.
525  ********************************************************************/
526
527 BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
528 {
529         char *q = prs_mem_get(ps, len * sizeof(uint32));
530         if (q == NULL)
531                 return False;
532
533         DBG_RW_PIVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data32s, len)
534         ps->data_offset += (len * sizeof(uint32));
535
536         return True;
537 }
538
539 /******************************************************************
540  Stream a "not" unicode string, length/buffer specified separately,
541  in byte chars. String is in little-endian format.
542  ********************************************************************/
543
544 BOOL prs_buffer2(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER2 *str)
545 {
546         char *p = (char *)str->buffer;
547         char *q = prs_mem_get(ps, str->buf_len);
548         if (q == NULL)
549                 return False;
550
551         /* If we're using big-endian, reverse to get little-endian. */
552         if(ps->bigendian_data)
553                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->buf_len/2)
554         else
555                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->buf_len)
556         ps->data_offset += str->buf_len;
557
558         return True;
559 }
560
561 /******************************************************************
562  Stream a string, length/buffer specified separately,
563  in uint8 chars.
564  ********************************************************************/
565
566 BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str)
567 {
568         char *q = prs_mem_get(ps, str->str_str_len * sizeof(uint8));
569         if (q == NULL)
570                 return False;
571
572         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, str->buffer, str->str_max_len)
573         ps->data_offset += (str->str_str_len * sizeof(uint8));
574
575         return True;
576 }
577
578 /******************************************************************
579  Stream a unicode string, length/buffer specified separately,
580  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
581  as the unicode string is already in little-endian format.
582  ********************************************************************/
583
584 BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
585 {
586         char *p = (char *)str->buffer;
587         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
588         if (q == NULL)
589                 return False;
590
591         /* If we're using big-endian, reverse to get little-endian. */
592         if(ps->bigendian_data)
593                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
594         else
595                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
596         ps->data_offset += (str->uni_str_len * sizeof(uint16));
597
598         return True;
599 }
600
601 /******************************************************************
602  Stream a unicode string, length/buffer specified separately,
603  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
604  as the unicode string is already in little-endian format.
605  ********************************************************************/
606
607 BOOL prs_unistr3(BOOL charmode, char *name, UNISTR3 *str, prs_struct *ps, int depth)
608 {
609         char *p = (char *)str->str.buffer;
610         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
611         if (q == NULL)
612                 return False;
613
614         /* If we're using big-endian, reverse to get little-endian. */
615         if(ps->bigendian_data)
616                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
617         else
618                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
619         ps->data_offset += (str->uni_str_len * sizeof(uint16));
620
621         return True;
622 }
623
624 /*******************************************************************
625  Stream a unicode  null-terminated string. As the string is already
626  in little-endian format then do it as a stream of bytes.
627  ********************************************************************/
628
629 BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
630 {
631         int len = 0;
632         unsigned char *p = (unsigned char *)str->buffer;
633         uint8 *start;
634         char *q;
635         char zero=0;
636
637         for(len = 0; len < (sizeof(str->buffer) / sizeof(str->buffer[0])) &&
638                            str->buffer[len] != 0; len++)
639                 ;
640
641         q = prs_mem_get(ps, (len+1)*2);
642         if (q == NULL)
643                 return False;
644
645         start = (uint8*)q;
646
647         for(len = 0; len < (sizeof(str->buffer) / sizeof(str->buffer[0])) &&
648                            str->buffer[len] != 0; len++) {
649                 if(ps->bigendian_data) {
650                         RW_SVAL(ps->io, ps->bigendian_data, q, *p, 0);
651                         p += 2;
652                         q += 2;
653                 } else {
654                         RW_CVAL(ps->io, q, *p, 0);
655                         p++;
656                         q++;
657                         RW_CVAL(ps->io, q, *p, 0);
658                         p++;
659                         q++;
660                 }
661         }
662         
663         /*
664          * even if the string is 'empty' (only an \0 char)
665          * at this point the leading \0 hasn't been parsed.
666          * so parse it now
667          */
668
669         RW_CVAL(ps->io, q, zero, 0);
670         q++;
671         RW_CVAL(ps->io, q, zero, 0);
672         q++;
673
674         len++;
675                 
676         ps->data_offset += len*2;
677
678         dump_data(5+depth, (char *)start, len * 2);
679
680         return True;
681 }
682
683 /*******************************************************************
684  Stream a null-terminated string.  len is strlen, and therefore does
685  not include the null-termination character.
686  ********************************************************************/
687
688 BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size)
689 {
690         char *q;
691         uint8 *start;
692         int i;
693
694         len = MIN(len, (max_buf_size-1));
695
696         q = prs_mem_get(ps, len+1);
697         if (q == NULL)
698                 return False;
699
700         start = (uint8*)q;
701
702         for(i = 0; i < len; i++) {
703                 RW_CVAL(ps->io, q, str[i],0);
704                 q++;
705         }
706
707         /* The terminating null. */
708         str[i] = '\0';
709
710         if (MARSHALLING(ps)) {
711                 RW_CVAL(ps->io, q, str[i], 0);
712         }
713
714         ps->data_offset += len+1;
715
716         dump_data(5+depth, (char *)start, len);
717
718         return True;
719 }
720
721 /*******************************************************************
722  prs_uint16 wrapper. Call this and it sets up a pointer to where the
723  uint16 should be stored, or gets the size if reading.
724  ********************************************************************/
725
726 BOOL prs_uint16_pre(char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
727 {
728         (*offset) = ps->data_offset;
729         if (UNMARSHALLING(ps)) {
730                 /* reading. */
731                 return prs_uint16(name, ps, depth, data16);
732         } else {
733                 char *q = prs_mem_get(ps, sizeof(uint16));
734                 if(q ==NULL)
735                         return False;
736                 ps->data_offset += sizeof(uint16);
737         }
738         return True;
739 }
740
741 /*******************************************************************
742  prs_uint16 wrapper.  call this and it retrospectively stores the size.
743  does nothing on reading, as that is already handled by ...._pre()
744  ********************************************************************/
745
746 BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
747                                 uint32 ptr_uint16, uint32 start_offset)
748 {
749         if (MARSHALLING(ps)) {
750                 /* 
751                  * Writing - temporarily move the offset pointer.
752                  */
753                 uint16 data_size = ps->data_offset - start_offset;
754                 uint32 old_offset = ps->data_offset;
755
756                 ps->data_offset = ptr_uint16;
757                 if(!prs_uint16(name, ps, depth, &data_size)) {
758                         ps->data_offset = old_offset;
759                         return False;
760                 }
761                 ps->data_offset = old_offset;
762         } else {
763                 ps->data_offset = start_offset + (uint32)(*data16);
764         }
765         return True;
766 }
767
768 /*******************************************************************
769  prs_uint32 wrapper. Call this and it sets up a pointer to where the
770  uint32 should be stored, or gets the size if reading.
771  ********************************************************************/
772
773 BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
774 {
775         (*offset) = ps->data_offset;
776         if (UNMARSHALLING(ps)) {
777                 /* reading. */
778                 return prs_uint32(name, ps, depth, data32);
779         } else {
780                 ps->data_offset += sizeof(uint32);
781         }
782         return True;
783 }
784
785 /*******************************************************************
786  prs_uint32 wrapper.  call this and it retrospectively stores the size.
787  does nothing on reading, as that is already handled by ...._pre()
788  ********************************************************************/
789
790 BOOL prs_uint32_post(char *name, prs_struct *ps, int depth, uint32 *data32,
791                                 uint32 ptr_uint32, uint32 data_size)
792 {
793         if (MARSHALLING(ps)) {
794                 /* 
795                  * Writing - temporarily move the offset pointer.
796                  */
797                 uint32 old_offset = ps->data_offset;
798                 ps->data_offset = ptr_uint32;
799                 if(!prs_uint32(name, ps, depth, &data_size)) {
800                         ps->data_offset = old_offset;
801                         return False;
802                 }
803                 ps->data_offset = old_offset;
804         }
805         return True;
806 }
807
808 /* useful function to store a structure in rpc wire format */
809 int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
810 {
811     TDB_DATA kbuf, dbuf;
812     kbuf.dptr = keystr;
813     kbuf.dsize = strlen(keystr)+1;
814     dbuf.dptr = prs_data_p(ps);
815     dbuf.dsize = prs_offset(ps);
816     return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
817 }
818
819 /* useful function to fetch a structure into rpc wire format */
820 int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
821 {
822     TDB_DATA kbuf, dbuf;
823     kbuf.dptr = keystr;
824     kbuf.dsize = strlen(keystr)+1;
825
826     dbuf = tdb_fetch(tdb, kbuf);
827     if (!dbuf.dptr) return -1;
828
829     ZERO_STRUCTP(ps);
830     prs_init(ps, 0, 4, UNMARSHALL);
831     prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
832
833     return 0;
834