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