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