Added prs_mem_clear(). Clear memory on buffer reallocation. That way
[sfrench/samba-autobuild/.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 #include "includes.h"
25
26 /**
27  * Dump a prs to a file: from the current location through to the end.
28  **/
29 void prs_dump(char *name, int v, prs_struct *ps)
30 {
31         prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size);
32 }
33
34
35 /**
36  * Dump from the start of the prs to the current location.
37  **/
38 void prs_dump_before(char *name, int v, prs_struct *ps)
39 {
40         prs_dump_region(name, v, ps, 0, ps->data_offset);
41 }
42
43
44 /**
45  * Dump everything from the start of the prs up to the current location.
46  **/
47 void prs_dump_region(char *name, int v, prs_struct *ps,
48                      int from_off, int to_off)
49 {
50         int fd, i;
51         pstring fname;
52         if (DEBUGLEVEL < 50) return;
53         for (i=1;i<100;i++) {
54                 if (v != -1) {
55                         slprintf(fname,sizeof(fname)-1, "/tmp/%s_%d.%d.prs", name, v, i);
56                 } else {
57                         slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.prs", name, i);
58                 }
59                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
60                 if (fd != -1 || errno != EEXIST) break;
61         }
62         if (fd != -1) {
63                 write(fd, ps->data_p + from_off, to_off - from_off);
64                 close(fd);
65                 DEBUG(0,("created %s\n", fname));
66         }
67 }
68
69
70
71 /*******************************************************************
72  debug output for parsing info.
73
74  XXXX side-effect of this function is to increase the debug depth XXXX
75
76  ********************************************************************/
77 void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
78 {
79         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
80 }
81
82
83 /**
84  * Initialise an expandable parse structure.
85  *
86  * @param size Initial buffer size.  If >0, a new buffer will be
87  * created with malloc().
88  *
89  * @return False if allocation fails, otherwise True.
90  **/
91 BOOL prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, BOOL io)
92 {
93         ZERO_STRUCTP(ps);
94         ps->io = io;
95         ps->bigendian_data = RPC_LITTLE_ENDIAN;
96         ps->align = RPC_PARSE_ALIGN;
97         ps->is_dynamic = False;
98         ps->data_offset = 0;
99         ps->buffer_size = 0;
100         ps->data_p = NULL;
101         ps->mem_ctx = ctx;
102
103         if (size != 0) {
104                 ps->buffer_size = size;
105                 if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
106                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
107                         return False;
108                 }
109                 memset(ps->data_p, '\0', (size_t)size);
110                 ps->is_dynamic = True; /* We own this memory. */
111         }
112
113         return True;
114 }
115
116 /*******************************************************************
117  read from a socket into memory.
118  ********************************************************************/
119 BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout)
120 {
121         BOOL ok;
122         size_t prev_size = ps->buffer_size;
123         if (!prs_grow(ps, len))
124                 return False;
125
126         if (timeout > 0) {
127                 ok = (read_with_timeout(fd, &ps->data_p[prev_size],
128                                             len, len,timeout) == len);
129         } else {
130                 ok = (read_data(fd, &ps->data_p[prev_size], len) == len);
131         }
132         return ok;
133 }
134
135 /*******************************************************************
136  Delete the memory in a parse structure - if we own it.
137  ********************************************************************/
138
139 void prs_mem_free(prs_struct *ps)
140 {
141         if(ps->is_dynamic)
142                 SAFE_FREE(ps->data_p);
143         ps->is_dynamic = False;
144         ps->buffer_size = 0;
145         ps->data_offset = 0;
146 }
147
148 /*******************************************************************
149  Clear the memory in a parse structure.
150  ********************************************************************/
151
152 void prs_mem_clear(prs_struct *ps)
153 {
154         memset(ps->data_p, '\0', (size_t)ps->buffer_size);
155 }
156
157 /*******************************************************************
158  Allocate memory when unmarshalling... Always zero clears.
159  ********************************************************************/
160
161 char *prs_alloc_mem(prs_struct *ps, size_t size)
162 {
163         char *ret = talloc(ps->mem_ctx, size);
164
165         if (ret)
166                 memset(ret, '\0', size);
167
168         return ret;
169 }
170
171 /*******************************************************************
172  Return the current talloc context we're using.
173  ********************************************************************/
174
175 TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
176 {
177         return ps->mem_ctx;
178 }
179
180 /*******************************************************************
181  Hand some already allocated memory to a prs_struct.
182  ********************************************************************/
183
184 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
185 {
186         ps->is_dynamic = is_dynamic;
187         ps->data_p = buf;
188         ps->buffer_size = size;
189 }
190
191 /*******************************************************************
192  Take some memory back from a prs_struct.
193  ********************************************************************/
194
195 char *prs_take_memory(prs_struct *ps, uint32 *psize)
196 {
197         char *ret = ps->data_p;
198         if(psize)
199                 *psize = ps->buffer_size;
200         ps->is_dynamic = False;
201         prs_mem_free(ps);
202         return ret;
203 }
204
205 /*******************************************************************
206  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
207  ********************************************************************/
208
209 BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
210 {
211         if (newsize > ps->buffer_size)
212                 return prs_force_grow(ps, newsize - ps->buffer_size);
213
214         if (newsize < ps->buffer_size) {
215                 char *new_data_p = Realloc(ps->data_p, newsize);
216                 /* if newsize is zero, Realloc acts like free() & returns NULL*/
217                 if (new_data_p == NULL && newsize != 0) {
218                         DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
219                                 (unsigned int)newsize));
220                         DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
221                         return False;
222                 }
223                 ps->data_p = new_data_p;
224                 ps->buffer_size = newsize;
225         }
226
227         return True;
228 }
229
230 /*******************************************************************
231  Attempt, if needed, to grow a data buffer.
232  Also depends on the data stream mode (io).
233  ********************************************************************/
234
235 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
236 {
237         uint32 new_size;
238         char *new_data;
239
240         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
241
242         if(ps->data_offset + extra_space <= ps->buffer_size)
243                 return True;
244
245         /*
246          * We cannot grow the buffer if we're not reading
247          * into the prs_struct, or if we don't own the memory.
248          */
249
250         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
251                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
252                                 (unsigned int)extra_space));
253                 return False;
254         }
255         
256         /*
257          * Decide how much extra space we really need.
258          */
259
260         extra_space -= (ps->buffer_size - ps->data_offset);
261         if(ps->buffer_size == 0) {
262                 /*
263                  * Ensure we have at least a PDU's length, or extra_space, whichever
264                  * is greater.
265                  */
266
267                 new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
268
269                 if((new_data = malloc(new_size)) == NULL) {
270                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
271                         return False;
272                 }
273                 memset(new_data, '\0', (size_t)new_size );
274         } else {
275                 /*
276                  * If the current buffer size is bigger than the space needed, just 
277                  * double it, else add extra_space.
278                  */
279                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
280
281                 if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
282                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
283                                 (unsigned int)new_size));
284                         return False;
285                 }
286
287                 memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
288         }
289         ps->buffer_size = new_size;
290         ps->data_p = new_data;
291
292         return True;
293 }
294
295 /*******************************************************************
296  Attempt to force a data buffer to grow by len bytes.
297  This is only used when appending more data onto a prs_struct
298  when reading an rpc reply, before unmarshalling it.
299  ********************************************************************/
300
301 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
302 {
303         uint32 new_size = ps->buffer_size + extra_space;
304         char *new_data;
305
306         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
307                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
308                                 (unsigned int)extra_space));
309                 return False;
310         }
311
312         if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
313                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
314                         (unsigned int)new_size));
315                 return False;
316         }
317
318         memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
319
320         ps->buffer_size = new_size;
321         ps->data_p = new_data;
322
323         return True;
324 }
325
326 /*******************************************************************
327  Get the data pointer (external interface).
328  ********************************************************************/
329
330 char *prs_data_p(prs_struct *ps)
331 {
332         return ps->data_p;
333 }
334
335 /*******************************************************************
336  Get the current data size (external interface).
337  ********************************************************************/
338
339 uint32 prs_data_size(prs_struct *ps)
340 {
341         return ps->buffer_size;
342 }
343
344 /*******************************************************************
345  Fetch the current offset (external interface).
346  ********************************************************************/
347
348 uint32 prs_offset(prs_struct *ps)
349 {
350         return ps->data_offset;
351 }
352
353 /*******************************************************************
354  Set the current offset (external interface).
355  ********************************************************************/
356
357 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
358 {
359         if(offset <= ps->data_offset) {
360                 ps->data_offset = offset;
361                 return True;
362         }
363
364         if(!prs_grow(ps, offset - ps->data_offset))
365                 return False;
366
367         ps->data_offset = offset;
368         return True;
369 }
370
371 /*******************************************************************
372  Append the data from one parse_struct into another.
373  ********************************************************************/
374
375 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
376 {
377         if(!prs_grow(dst, prs_offset(src)))
378                 return False;
379
380         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src));
381         dst->data_offset += prs_offset(src);
382
383         return True;
384 }
385
386 /*******************************************************************
387  Append some data from one parse_struct into another.
388  ********************************************************************/
389
390 BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
391 {       
392         if (len == 0)
393                 return True;
394
395         if(!prs_grow(dst, len))
396                 return False;
397         
398         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src)+start, (size_t)len);
399         dst->data_offset += len;
400
401         return True;
402 }
403
404 /*******************************************************************
405  Append the data from a buffer into a parse_struct.
406  ********************************************************************/
407
408 BOOL prs_append_data(prs_struct *dst, char *src, uint32 len)
409 {
410         if(!prs_grow(dst, len))
411                 return False;
412
413         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
414         dst->data_offset += len;
415
416         return True;
417 }
418
419 /*******************************************************************
420  Set the data as X-endian (external interface).
421  ********************************************************************/
422
423 void prs_set_endian_data(prs_struct *ps, BOOL endian)
424 {
425         ps->bigendian_data = endian;
426 }
427
428 /*******************************************************************
429  Align a the data_len to a multiple of align bytes - filling with
430  zeros.
431  ********************************************************************/
432
433 BOOL prs_align(prs_struct *ps)
434 {
435         uint32 mod = ps->data_offset & (ps->align-1);
436
437         if (ps->align != 0 && mod != 0) {
438                 uint32 extra_space = (ps->align - mod);
439                 if(!prs_grow(ps, extra_space))
440                         return False;
441                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
442                 ps->data_offset += extra_space;
443         }
444
445         return True;
446 }
447
448 /*******************************************************************
449  Align only if required (for the unistr2 string mainly)
450  ********************************************************************/
451
452 BOOL prs_align_needed(prs_struct *ps, uint32 needed)
453 {
454         if (needed==0)
455                 return True;
456         else
457                 return prs_align(ps);
458 }
459
460 /*******************************************************************
461  Ensure we can read/write to a given offset.
462  ********************************************************************/
463
464 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
465 {
466         if(UNMARSHALLING(ps)) {
467                 /*
468                  * If reading, ensure that we can read the requested size item.
469                  */
470                 if (ps->data_offset + extra_size > ps->buffer_size) {
471                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
472                                         (unsigned int)extra_size ));
473                         return NULL;
474                 }
475         } else {
476                 /*
477                  * Writing - grow the buffer if needed.
478                  */
479                 if(!prs_grow(ps, extra_size))
480                         return NULL;
481         }
482         return &ps->data_p[ps->data_offset];
483 }
484
485 /*******************************************************************
486  Change the struct type.
487  ********************************************************************/
488
489 void prs_switch_type(prs_struct *ps, BOOL io)
490 {
491         if ((ps->io ^ io) == True)
492                 ps->io=io;
493 }
494
495 /*******************************************************************
496  Force a prs_struct to be dynamic even when it's size is 0.
497  ********************************************************************/
498
499 void prs_force_dynamic(prs_struct *ps)
500 {
501         ps->is_dynamic=True;
502 }
503
504 /*******************************************************************
505  Stream a uint8.
506  ********************************************************************/
507
508 BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
509 {
510         char *q = prs_mem_get(ps, 1);
511         if (q == NULL)
512                 return False;
513
514     if (UNMARSHALLING(ps))
515                 *data8 = CVAL(q,0);
516         else
517                 SCVAL(q,0,*data8);
518
519     DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
520
521         ps->data_offset += 1;
522
523         return True;
524 }
525
526 /*******************************************************************
527  Stream a uint16.
528  ********************************************************************/
529
530 BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
531 {
532         char *q = prs_mem_get(ps, sizeof(uint16));
533         if (q == NULL)
534                 return False;
535
536     if (UNMARSHALLING(ps)) {
537                 if (ps->bigendian_data)
538                         *data16 = RSVAL(q,0);
539                 else
540                         *data16 = SVAL(q,0);
541     } else {
542                 if (ps->bigendian_data)
543                         RSSVAL(q,0,*data16);
544                 else
545                         SSVAL(q,0,*data16);
546         }
547
548         DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16));
549
550         ps->data_offset += sizeof(uint16);
551
552         return True;
553 }
554
555 /*******************************************************************
556  Stream a uint32.
557  ********************************************************************/
558
559 BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
560 {
561         char *q = prs_mem_get(ps, sizeof(uint32));
562         if (q == NULL)
563                 return False;
564
565         if (UNMARSHALLING(ps)) {
566                 if (ps->bigendian_data)
567                         *data32 = RIVAL(q,0);
568                 else
569                         *data32 = IVAL(q,0);
570         } else {
571                 if (ps->bigendian_data)
572                         RSIVAL(q,0,*data32);
573                 else
574                         SIVAL(q,0,*data32);
575         }
576
577         DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
578
579         ps->data_offset += sizeof(uint32);
580
581         return True;
582 }
583
584 /*******************************************************************
585  Stream a NTSTATUS
586  ********************************************************************/
587
588 BOOL prs_ntstatus(char *name, prs_struct *ps, int depth, NTSTATUS *status)
589 {
590         char *q = prs_mem_get(ps, sizeof(uint32));
591         if (q == NULL)
592                 return False;
593
594         if (UNMARSHALLING(ps)) {
595                 if (ps->bigendian_data)
596                         *status = NT_STATUS(RIVAL(q,0));
597                 else
598                         *status = NT_STATUS(IVAL(q,0));
599         } else {
600                 if (ps->bigendian_data)
601                         RSIVAL(q,0,NT_STATUS_V(*status));
602                 else
603                         SIVAL(q,0,NT_STATUS_V(*status));
604         }
605
606         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
607                  get_nt_error_msg(*status)));
608
609         ps->data_offset += sizeof(uint32);
610
611         return True;
612 }
613
614 /*******************************************************************
615  Stream a WERROR
616  ********************************************************************/
617
618 BOOL prs_werror(char *name, prs_struct *ps, int depth, WERROR *status)
619 {
620         char *q = prs_mem_get(ps, sizeof(uint32));
621         if (q == NULL)
622                 return False;
623
624         if (UNMARSHALLING(ps)) {
625                 if (ps->bigendian_data)
626                         *status = W_ERROR(RIVAL(q,0));
627                 else
628                         *status = W_ERROR(IVAL(q,0));
629         } else {
630                 if (ps->bigendian_data)
631                         RSIVAL(q,0,W_ERROR_V(*status));
632                 else
633                         SIVAL(q,0,W_ERROR_V(*status));
634         }
635
636         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
637                  werror_str(*status)));
638
639         ps->data_offset += sizeof(uint32);
640
641         return True;
642 }
643
644
645 /******************************************************************
646  Stream an array of uint8s. Length is number of uint8s.
647  ********************************************************************/
648
649 BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
650 {
651         int i;
652         char *q = prs_mem_get(ps, len);
653         if (q == NULL)
654                 return False;
655
656         if (UNMARSHALLING(ps)) {
657                 for (i = 0; i < len; i++)
658                         data8s[i] = CVAL(q,i);
659         } else {
660                 for (i = 0; i < len; i++)
661                         SCVAL(q, i, data8s[i]);
662         }
663
664     DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
665     if (charmode)
666                 print_asc(5, (unsigned char*)data8s, len);
667         else {
668         for (i = 0; i < len; i++)
669                         DEBUG(5,("%02x ", data8s[i]));
670         }
671     DEBUG(5,("\n"));
672
673         ps->data_offset += len;
674
675         return True;
676 }
677
678 /******************************************************************
679  Stream an array of uint16s. Length is number of uint16s.
680  ********************************************************************/
681
682 BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
683 {
684         int i;
685         char *q = prs_mem_get(ps, len * sizeof(uint16));
686         if (q == NULL)
687                 return False;
688
689         if (UNMARSHALLING(ps)) {
690                 if (ps->bigendian_data) {
691                         for (i = 0; i < len; i++)
692                                 data16s[i] = RSVAL(q, 2*i);
693                 } else {
694                         for (i = 0; i < len; i++)
695                                 data16s[i] = SVAL(q, 2*i);
696                 }
697         } else {
698                 if (ps->bigendian_data) {
699                         for (i = 0; i < len; i++)
700                                 RSSVAL(q, 2*i, data16s[i]);
701                 } else {
702                         for (i = 0; i < len; i++)
703                                 SSVAL(q, 2*i, data16s[i]);
704                 }
705         }
706
707         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
708         if (charmode)
709                 print_asc(5, (unsigned char*)data16s, 2*len);
710         else {
711                 for (i = 0; i < len; i++)
712                         DEBUG(5,("%04x ", data16s[i]));
713         }
714     DEBUG(5,("\n"));
715
716         ps->data_offset += (len * sizeof(uint16));
717
718         return True;
719 }
720
721 /******************************************************************
722  Start using a function for streaming unicode chars. If unmarshalling,
723  output must be little-endian, if marshalling, input must be little-endian.
724  ********************************************************************/
725
726 static void dbg_rw_punival(BOOL charmode, char *name, int depth, prs_struct *ps,
727                                                         char *in_buf, char *out_buf, int len)
728 {
729         int i;
730
731         if (UNMARSHALLING(ps)) {
732                 if (ps->bigendian_data) {
733                         for (i = 0; i < len; i++)
734                                 SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
735                 } else {
736                         for (i = 0; i < len; i++)
737                                 SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
738                 }
739         } else {
740                 if (ps->bigendian_data) {
741                         for (i = 0; i < len; i++)
742                                 RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
743                 } else {
744                         for (i = 0; i < len; i++)
745                                 SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
746                 }
747         }
748
749         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
750         if (charmode)
751                 print_asc(5, (unsigned char*)out_buf, 2*len);
752         else {
753                 for (i = 0; i < len; i++)
754                         DEBUG(5,("%04x ", out_buf[i]));
755         }
756     DEBUG(5,("\n"));
757 }
758
759 /******************************************************************
760  Stream a unistr. Always little endian.
761  ********************************************************************/
762
763 BOOL prs_uint16uni(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
764 {
765         char *q = prs_mem_get(ps, len * sizeof(uint16));
766         if (q == NULL)
767                 return False;
768
769         dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
770         ps->data_offset += (len * sizeof(uint16));
771
772         return True;
773 }
774
775 /******************************************************************
776  Stream an array of uint32s. Length is number of uint32s.
777  ********************************************************************/
778
779 BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
780 {
781         int i;
782         char *q = prs_mem_get(ps, len * sizeof(uint32));
783         if (q == NULL)
784                 return False;
785
786         if (UNMARSHALLING(ps)) {
787                 if (ps->bigendian_data) {
788                         for (i = 0; i < len; i++)
789                                 data32s[i] = RIVAL(q, 4*i);
790                 } else {
791                         for (i = 0; i < len; i++)
792                                 data32s[i] = IVAL(q, 4*i);
793                 }
794         } else {
795                 if (ps->bigendian_data) {
796                         for (i = 0; i < len; i++)
797                                 RSIVAL(q, 4*i, data32s[i]);
798                 } else {
799                         for (i = 0; i < len; i++)
800                                 SIVAL(q, 4*i, data32s[i]);
801                 }
802         }
803
804         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
805         if (charmode)
806                 print_asc(5, (unsigned char*)data32s, 4*len);
807         else {
808                 for (i = 0; i < len; i++)
809                         DEBUG(5,("%08x ", data32s[i]));
810         }
811     DEBUG(5,("\n"));
812
813         ps->data_offset += (len * sizeof(uint32));
814
815         return True;
816 }
817
818 /******************************************************************
819  Stream an array of unicode string, length/buffer specified separately,
820  in uint16 chars. The unicode string is already in little-endian format.
821  ********************************************************************/
822
823 BOOL prs_buffer5(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER5 *str)
824 {
825         char *p;
826         char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
827         if (q == NULL)
828                 return False;
829
830         if (UNMARSHALLING(ps)) {
831                 str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len * sizeof(uint16));
832                 if (str->buffer == NULL)
833                         return False;
834         }
835
836         /* If the string is empty, we don't have anything to stream */
837         if (str->buf_len==0)
838                 return True;
839
840         p = (char *)str->buffer;
841
842         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
843         
844         ps->data_offset += (str->buf_len * sizeof(uint16));
845
846         return True;
847 }
848
849 /******************************************************************
850  Stream a "not" unicode string, length/buffer specified separately,
851  in byte chars. String is in little-endian format.
852  ********************************************************************/
853
854 BOOL prs_buffer2(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER2 *str)
855 {
856         char *p;
857         char *q = prs_mem_get(ps, str->buf_len);
858         if (q == NULL)
859                 return False;
860
861         if (UNMARSHALLING(ps)) {
862                 str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len);
863                 if (str->buffer == NULL)
864                         return False;
865         }
866
867         p = (char *)str->buffer;
868
869         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len/2);
870         ps->data_offset += str->buf_len;
871
872         return True;
873 }
874
875 /******************************************************************
876  Stream a string, length/buffer specified separately,
877  in uint8 chars.
878  ********************************************************************/
879
880 BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str)
881 {
882         int i;
883         char *q = prs_mem_get(ps, str->str_max_len);
884         if (q == NULL)
885                 return False;
886
887         if (UNMARSHALLING(ps)) {
888                 str->buffer = (unsigned char *)prs_alloc_mem(ps,str->str_max_len);
889                 if (str->buffer == NULL)
890                         return False;
891         }
892
893         if (UNMARSHALLING(ps)) {
894                 for (i = 0; i < str->str_str_len; i++)
895                         str->buffer[i] = CVAL(q,i);
896         } else {
897                 for (i = 0; i < str->str_str_len; i++)
898                         SCVAL(q, i, str->buffer[i]);
899         }
900
901     DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
902     if (charmode)
903                 print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
904         else {
905         for (i = 0; i < str->str_str_len; i++)
906                         DEBUG(5,("%02x ", str->buffer[i]));
907         }
908     DEBUG(5,("\n"));
909
910         ps->data_offset += str->str_str_len;
911
912         return True;
913 }
914
915 /******************************************************************
916  Stream a unicode string, length/buffer specified separately,
917  in uint16 chars. The unicode string is already in little-endian format.
918  ********************************************************************/
919
920 BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
921 {
922         char *p;
923         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
924         if (q == NULL)
925                 return False;
926
927         /* If the string is empty, we don't have anything to stream */
928         if (str->uni_str_len==0)
929                 return True;
930
931         if (UNMARSHALLING(ps)) {
932                 str->buffer = (uint16 *)prs_alloc_mem(ps,str->uni_max_len * sizeof(uint16));
933                 if (str->buffer == NULL)
934                         return False;
935         }
936
937         p = (char *)str->buffer;
938
939         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
940         
941         ps->data_offset += (str->uni_str_len * sizeof(uint16));
942
943         return True;
944 }
945
946 /******************************************************************
947  Stream a unicode string, length/buffer specified separately,
948  in uint16 chars. The unicode string is already in little-endian format.
949  ********************************************************************/
950
951 BOOL prs_unistr3(BOOL charmode, char *name, UNISTR3 *str, prs_struct *ps, int depth)
952 {
953         char *p;
954         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
955         if (q == NULL)
956                 return False;
957
958         if (UNMARSHALLING(ps)) {
959                 str->str.buffer = (uint16 *)prs_alloc_mem(ps,str->uni_str_len * sizeof(uint16));
960                 if (str->str.buffer == NULL)
961                         return False;
962         }
963
964         p = (char *)str->str.buffer;
965
966         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
967         ps->data_offset += (str->uni_str_len * sizeof(uint16));
968
969         return True;
970 }
971
972 /*******************************************************************
973  Stream a unicode  null-terminated string. As the string is already
974  in little-endian format then do it as a stream of bytes.
975  ********************************************************************/
976
977 BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
978 {
979         int len = 0;
980         unsigned char *p = (unsigned char *)str->buffer;
981         uint8 *start;
982         char *q;
983         uint32 max_len;
984         uint16* ptr;
985
986         if (MARSHALLING(ps)) {
987
988                 for(len = 0; str->buffer[len] != 0; len++)
989                         ;
990
991                 q = prs_mem_get(ps, (len+1)*2);
992                 if (q == NULL)
993                         return False;
994
995                 start = (uint8*)q;
996
997                 for(len = 0; str->buffer[len] != 0; len++) 
998                 {
999                         if(ps->bigendian_data) 
1000                         {
1001                                 /* swap bytes - p is little endian, q is big endian. */
1002                                 q[0] = (char)p[1];
1003                                 q[1] = (char)p[0];
1004                                 p += 2;
1005                                 q += 2;
1006                         } 
1007                         else 
1008                         {
1009                                 q[0] = (char)p[0];
1010                                 q[1] = (char)p[1];
1011                                 p += 2;
1012                                 q += 2;
1013                         }
1014                 }
1015
1016                 /*
1017                  * even if the string is 'empty' (only an \0 char)
1018                  * at this point the leading \0 hasn't been parsed.
1019                  * so parse it now
1020                  */
1021
1022                 q[0] = 0;
1023                 q[1] = 0;
1024                 q += 2;
1025
1026                 len++;
1027
1028                 dump_data(5+depth, (char *)start, len * 2);
1029         }
1030         else { /* unmarshalling */
1031         
1032                 uint32 alloc_len = 0;
1033                 q = prs_data_p(ps) + prs_offset(ps);
1034
1035                 /*
1036                  * Work out how much space we need and talloc it.
1037                  */
1038                 max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
1039
1040                 /* the test of the value of *ptr helps to catch the circumstance
1041                    where we have an emtpty (non-existent) string in the buffer */
1042                 for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++)
1043                         /* do nothing */ 
1044                         ;
1045
1046                 /* should we allocate anything at all? */
1047                 str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16));
1048                 if ((str->buffer == NULL) && (alloc_len > 0))
1049                         return False;
1050
1051                 p = (unsigned char *)str->buffer;
1052
1053                 len = 0;
1054                 /* the (len < alloc_len) test is to prevent us from overwriting
1055                    memory that is not ours...if we get that far, we have a non-null
1056                    terminated string in the buffer and have messed up somewhere */
1057                 while ((len < alloc_len) && (*(uint16 *)q != 0))
1058                 {
1059                         if(ps->bigendian_data) 
1060                         {
1061                                 /* swap bytes - q is big endian, p is little endian. */
1062                                 p[0] = (unsigned char)q[1];
1063                                 p[1] = (unsigned char)q[0];
1064                                 p += 2;
1065                                 q += 2;
1066                         } else {
1067
1068                                 p[0] = (unsigned char)q[0];
1069                                 p[1] = (unsigned char)q[1];
1070                                 p += 2;
1071                                 q += 2;
1072                         }
1073
1074                         len++;
1075                 } 
1076                 if (len < alloc_len)
1077                 {
1078                         /* NULL terminate the UNISTR */
1079                         str->buffer[len++] = '\0';
1080                 }
1081         }
1082
1083         /* set the offset in the prs_struct; 'len' points to the
1084            terminiating NULL in the UNISTR so we need to go one more
1085            uint16 */
1086         ps->data_offset += (len)*2;
1087         
1088         return True;
1089 }
1090
1091
1092 /*******************************************************************
1093  Stream a null-terminated string.  len is strlen, and therefore does
1094  not include the null-termination character.
1095  ********************************************************************/
1096
1097 BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size)
1098 {
1099         char *q;
1100         int i;
1101
1102         len = MIN(len, (max_buf_size-1));
1103
1104         q = prs_mem_get(ps, len+1);
1105         if (q == NULL)
1106                 return False;
1107
1108         for(i = 0; i < len; i++) {
1109                 if (UNMARSHALLING(ps))
1110                         str[i] = q[i];
1111                 else
1112                         q[i] = str[i];
1113         }
1114
1115         /* The terminating null. */
1116         str[i] = '\0';
1117
1118         if (MARSHALLING(ps)) {
1119                 q[i] = '\0';
1120         }
1121
1122         ps->data_offset += len+1;
1123
1124         dump_data(5+depth, q, len);
1125
1126         return True;
1127 }
1128
1129 /*******************************************************************
1130  prs_uint16 wrapper. Call this and it sets up a pointer to where the
1131  uint16 should be stored, or gets the size if reading.
1132  ********************************************************************/
1133
1134 BOOL prs_uint16_pre(char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
1135 {
1136         *offset = ps->data_offset;
1137         if (UNMARSHALLING(ps)) {
1138                 /* reading. */
1139                 return prs_uint16(name, ps, depth, data16);
1140         } else {
1141                 char *q = prs_mem_get(ps, sizeof(uint16));
1142                 if(q ==NULL)
1143                         return False;
1144                 ps->data_offset += sizeof(uint16);
1145         }
1146         return True;
1147 }
1148
1149 /*******************************************************************
1150  prs_uint16 wrapper.  call this and it retrospectively stores the size.
1151  does nothing on reading, as that is already handled by ...._pre()
1152  ********************************************************************/
1153
1154 BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
1155                                 uint32 ptr_uint16, uint32 start_offset)
1156 {
1157         if (MARSHALLING(ps)) {
1158                 /* 
1159                  * Writing - temporarily move the offset pointer.
1160                  */
1161                 uint16 data_size = ps->data_offset - start_offset;
1162                 uint32 old_offset = ps->data_offset;
1163
1164                 ps->data_offset = ptr_uint16;
1165                 if(!prs_uint16(name, ps, depth, &data_size)) {
1166                         ps->data_offset = old_offset;
1167                         return False;
1168                 }
1169                 ps->data_offset = old_offset;
1170         } else {
1171                 ps->data_offset = start_offset + (uint32)(*data16);
1172         }
1173         return True;
1174 }
1175
1176 /*******************************************************************
1177  prs_uint32 wrapper. Call this and it sets up a pointer to where the
1178  uint32 should be stored, or gets the size if reading.
1179  ********************************************************************/
1180
1181 BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
1182 {
1183         *offset = ps->data_offset;
1184         if (UNMARSHALLING(ps) && (data32 != NULL)) {
1185                 /* reading. */
1186                 return prs_uint32(name, ps, depth, data32);
1187         } else {
1188                 ps->data_offset += sizeof(uint32);
1189         }
1190         return True;
1191 }
1192
1193 /*******************************************************************
1194  prs_uint32 wrapper.  call this and it retrospectively stores the size.
1195  does nothing on reading, as that is already handled by ...._pre()
1196  ********************************************************************/
1197
1198 BOOL prs_uint32_post(char *name, prs_struct *ps, int depth, uint32 *data32,
1199                                 uint32 ptr_uint32, uint32 data_size)
1200 {
1201         if (MARSHALLING(ps)) {
1202                 /* 
1203                  * Writing - temporarily move the offset pointer.
1204                  */
1205                 uint32 old_offset = ps->data_offset;
1206                 ps->data_offset = ptr_uint32;
1207                 if(!prs_uint32(name, ps, depth, &data_size)) {
1208                         ps->data_offset = old_offset;
1209                         return False;
1210                 }
1211                 ps->data_offset = old_offset;
1212         }
1213         return True;
1214 }
1215
1216 /* useful function to store a structure in rpc wire format */
1217 int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
1218 {
1219     TDB_DATA kbuf, dbuf;
1220     kbuf.dptr = keystr;
1221     kbuf.dsize = strlen(keystr)+1;
1222     dbuf.dptr = prs_data_p(ps);
1223     dbuf.dsize = prs_offset(ps);
1224     return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
1225 }
1226
1227 /* useful function to fetch a structure into rpc wire format */
1228 int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx)
1229 {
1230     TDB_DATA kbuf, dbuf;
1231     kbuf.dptr = keystr;
1232     kbuf.dsize = strlen(keystr)+1;
1233
1234     dbuf = tdb_fetch(tdb, kbuf);
1235     if (!dbuf.dptr) return -1;
1236
1237     ZERO_STRUCTP(ps);
1238     prs_init(ps, 0, mem_ctx, UNMARSHALL);
1239     prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
1240
1241     return 0;
1242
1243
1244 /*******************************************************************
1245  hash a stream.
1246  ********************************************************************/
1247 BOOL prs_hash1(prs_struct *ps, uint32 offset, uint8 sess_key[16])
1248 {
1249         char *q;
1250
1251         q = prs_data_p(ps);
1252         q = &q[offset];
1253
1254 #ifdef DEBUG_PASSWORD
1255         DEBUG(100, ("prs_hash1\n"));
1256         dump_data(100, sess_key, 16);
1257         dump_data(100, q, 68);
1258 #endif
1259         SamOEMhash((uchar *) q, sess_key, 68);
1260
1261 #ifdef DEBUG_PASSWORD
1262         dump_data(100, q, 68);
1263 #endif
1264
1265         return True;
1266 }