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