Define GNU_SOURCE, required if libreplace doesn't provide comparison_fn_t,
[ira/wip.git] / source3 / 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    Copyright (C) Andrew Bartlett              2003.
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 3 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, see <http://www.gnu.org/licenses/>.
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(const 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  * Dump from the start of the prs to the current location.
38  **/
39 void prs_dump_before(const char *name, int v, prs_struct *ps)
40 {
41         prs_dump_region(name, v, ps, 0, ps->data_offset);
42 }
43
44 /**
45  * Dump everything from the start of the prs up to the current location.
46  **/
47 void prs_dump_region(const char *name, int v, prs_struct *ps,
48                      int from_off, int to_off)
49 {
50         int fd, i;
51         char *fname = NULL;
52         ssize_t sz;
53         if (DEBUGLEVEL < 50) return;
54         for (i=1;i<100;i++) {
55                 if (v != -1) {
56                         if (asprintf(&fname,"/tmp/%s_%d.%d.prs", name, v, i) < 0) {
57                                 return;
58                         }
59                 } else {
60                         if (asprintf(&fname,"/tmp/%s.%d.prs", name, i) < 0) {
61                                 return;
62                         }
63                 }
64                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
65                 if (fd != -1 || errno != EEXIST) break;
66         }
67         if (fd != -1) {
68                 sz = write(fd, ps->data_p + from_off, to_off - from_off);
69                 i = close(fd);
70                 if ( (sz != to_off-from_off) || (i != 0) ) {
71                         DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i ));
72                 } else {
73                         DEBUG(0,("created %s\n", fname));
74                 }
75         }
76         SAFE_FREE(fname);
77 }
78
79 /*******************************************************************
80  Debug output for parsing info
81
82  XXXX side-effect of this function is to increase the debug depth XXXX.
83
84 ********************************************************************/
85
86 void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
87 {
88         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(5+depth,depth), ps->data_offset, fn_name, desc));
89 }
90
91 /**
92  * Initialise an expandable parse structure.
93  *
94  * @param size Initial buffer size.  If >0, a new buffer will be
95  * created with malloc().
96  *
97  * @return False if allocation fails, otherwise True.
98  **/
99
100 bool prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, bool io)
101 {
102         ZERO_STRUCTP(ps);
103         ps->io = io;
104         ps->bigendian_data = RPC_LITTLE_ENDIAN;
105         ps->align = RPC_PARSE_ALIGN;
106         ps->is_dynamic = False;
107         ps->data_offset = 0;
108         ps->buffer_size = 0;
109         ps->data_p = NULL;
110         ps->mem_ctx = ctx;
111
112         if (size != 0) {
113                 ps->buffer_size = size;
114                 if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) {
115                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
116                         return False;
117                 }
118                 memset(ps->data_p, '\0', (size_t)size);
119                 ps->is_dynamic = True; /* We own this memory. */
120         } else if (MARSHALLING(ps)) {
121                 /* If size is zero and we're marshalling we should allocate memory on demand. */
122                 ps->is_dynamic = True;
123         }
124
125         return True;
126 }
127
128 /*******************************************************************
129  Delete the memory in a parse structure - if we own it.
130
131  NOTE: Contrary to the somewhat confusing naming, this function is not
132        intended for freeing memory allocated by prs_alloc_mem().  That memory
133        is attached to the talloc context given by ps->mem_ctx.
134  ********************************************************************/
135
136 void prs_mem_free(prs_struct *ps)
137 {
138         if(ps->is_dynamic)
139                 SAFE_FREE(ps->data_p);
140         ps->is_dynamic = False;
141         ps->buffer_size = 0;
142         ps->data_offset = 0;
143 }
144
145 /*******************************************************************
146  Clear the memory in a parse structure.
147  ********************************************************************/
148
149 void prs_mem_clear(prs_struct *ps)
150 {
151         if (ps->buffer_size)
152                 memset(ps->data_p, '\0', (size_t)ps->buffer_size);
153 }
154
155 /*******************************************************************
156  Allocate memory when unmarshalling... Always zero clears.
157  ********************************************************************/
158
159 #if defined(PARANOID_MALLOC_CHECKER)
160 char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
161 #else
162 char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
163 #endif
164 {
165         char *ret = NULL;
166
167         if (size && count) {
168                 /* We can't call the type-safe version here. */
169                 ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
170                                                  "parse_prs");
171         }
172         return ret;
173 }
174
175 /*******************************************************************
176  Return the current talloc context we're using.
177  ********************************************************************/
178
179 TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
180 {
181         return ps->mem_ctx;
182 }
183
184 /*******************************************************************
185  Hand some already allocated memory to a prs_struct.
186  ********************************************************************/
187
188 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, bool is_dynamic)
189 {
190         ps->is_dynamic = is_dynamic;
191         ps->data_p = buf;
192         ps->buffer_size = size;
193 }
194
195 /*******************************************************************
196  Take some memory back from a prs_struct.
197  ********************************************************************/
198
199 char *prs_take_memory(prs_struct *ps, uint32 *psize)
200 {
201         char *ret = ps->data_p;
202         if(psize)
203                 *psize = ps->buffer_size;
204         ps->is_dynamic = False;
205         prs_mem_free(ps);
206         return ret;
207 }
208
209 /*******************************************************************
210  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
211  ********************************************************************/
212
213 bool prs_set_buffer_size(prs_struct *ps, uint32 newsize)
214 {
215         if (newsize > ps->buffer_size)
216                 return prs_force_grow(ps, newsize - ps->buffer_size);
217
218         if (newsize < ps->buffer_size) {
219                 ps->buffer_size = newsize;
220
221                 /* newsize == 0 acts as a free and set pointer to NULL */
222                 if (newsize == 0) {
223                         SAFE_FREE(ps->data_p);
224                 } else {
225                         ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize);
226
227                         if (ps->data_p == NULL) {
228                                 DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
229                                         (unsigned int)newsize));
230                                 DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
231                                 return False;
232                         }
233                 }
234         }
235
236         return True;
237 }
238
239 /*******************************************************************
240  Attempt, if needed, to grow a data buffer.
241  Also depends on the data stream mode (io).
242  ********************************************************************/
243
244 bool prs_grow(prs_struct *ps, uint32 extra_space)
245 {
246         uint32 new_size;
247
248         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
249
250         if(ps->data_offset + extra_space <= ps->buffer_size)
251                 return True;
252
253         /*
254          * We cannot grow the buffer if we're not reading
255          * into the prs_struct, or if we don't own the memory.
256          */
257
258         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
259                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
260                                 (unsigned int)extra_space));
261                 return False;
262         }
263         
264         /*
265          * Decide how much extra space we really need.
266          */
267
268         extra_space -= (ps->buffer_size - ps->data_offset);
269         if(ps->buffer_size == 0) {
270                 /*
271                  * Ensure we have at least a PDU's length, or extra_space, whichever
272                  * is greater.
273                  */
274
275                 new_size = MAX(RPC_MAX_PDU_FRAG_LEN,extra_space);
276
277                 if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) {
278                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
279                         return False;
280                 }
281                 memset(ps->data_p, '\0', (size_t)new_size );
282         } else {
283                 /*
284                  * If the current buffer size is bigger than the space needed, just 
285                  * double it, else add extra_space.
286                  */
287                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
288
289                 if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
290                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
291                                 (unsigned int)new_size));
292                         return False;
293                 }
294
295                 memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
296         }
297         ps->buffer_size = new_size;
298
299         return True;
300 }
301
302 /*******************************************************************
303  Attempt to force a data buffer to grow by len bytes.
304  This is only used when appending more data onto a prs_struct
305  when reading an rpc reply, before unmarshalling it.
306  ********************************************************************/
307
308 bool prs_force_grow(prs_struct *ps, uint32 extra_space)
309 {
310         uint32 new_size = ps->buffer_size + extra_space;
311
312         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
313                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
314                                 (unsigned int)extra_space));
315                 return False;
316         }
317
318         if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
319                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
320                         (unsigned int)new_size));
321                 return False;
322         }
323
324         memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
325
326         ps->buffer_size = new_size;
327
328         return True;
329 }
330
331 /*******************************************************************
332  Get the data pointer (external interface).
333 ********************************************************************/
334
335 char *prs_data_p(prs_struct *ps)
336 {
337         return ps->data_p;
338 }
339
340 /*******************************************************************
341  Get the current data size (external interface).
342  ********************************************************************/
343
344 uint32 prs_data_size(prs_struct *ps)
345 {
346         return ps->buffer_size;
347 }
348
349 /*******************************************************************
350  Fetch the current offset (external interface).
351  ********************************************************************/
352
353 uint32 prs_offset(prs_struct *ps)
354 {
355         return ps->data_offset;
356 }
357
358 /*******************************************************************
359  Set the current offset (external interface).
360  ********************************************************************/
361
362 bool prs_set_offset(prs_struct *ps, uint32 offset)
363 {
364         if ((offset > ps->data_offset)
365             && !prs_grow(ps, offset - ps->data_offset)) {
366                 return False;
367         }
368
369         ps->data_offset = offset;
370         return True;
371 }
372
373 /*******************************************************************
374  Append the data from one parse_struct into another.
375  ********************************************************************/
376
377 bool prs_append_prs_data(prs_struct *dst, prs_struct *src)
378 {
379         if (prs_offset(src) == 0)
380                 return True;
381
382         if(!prs_grow(dst, prs_offset(src)))
383                 return False;
384
385         memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src));
386         dst->data_offset += prs_offset(src);
387
388         return True;
389 }
390
391 /*******************************************************************
392  Append some data from one parse_struct into another.
393  ********************************************************************/
394
395 bool prs_append_some_data(prs_struct *dst, void *src_base, uint32_t start,
396                           uint32_t len)
397 {
398         if (len == 0) {
399                 return true;
400         }
401
402         if(!prs_grow(dst, len)) {
403                 return false;
404         }
405
406         memcpy(&dst->data_p[dst->data_offset], ((char *)src_base) + start, (size_t)len);
407         dst->data_offset += len;
408         return true;
409 }
410
411 bool prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start,
412                               uint32 len)
413 {
414         return prs_append_some_data(dst, src->data_p, start, len);
415 }
416
417 /*******************************************************************
418  Append the data from a buffer into a parse_struct.
419  ********************************************************************/
420
421 bool prs_copy_data_in(prs_struct *dst, const char *src, uint32 len)
422 {
423         if (len == 0)
424                 return True;
425
426         if(!prs_grow(dst, len))
427                 return False;
428
429         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
430         dst->data_offset += len;
431
432         return True;
433 }
434
435 /*******************************************************************
436  Copy some data from a parse_struct into a buffer.
437  ********************************************************************/
438
439 bool prs_copy_data_out(char *dst, prs_struct *src, uint32 len)
440 {
441         if (len == 0)
442                 return True;
443
444         if(!prs_mem_get(src, len))
445                 return False;
446
447         memcpy(dst, &src->data_p[src->data_offset], (size_t)len);
448         src->data_offset += len;
449
450         return True;
451 }
452
453 /*******************************************************************
454  Copy all the data from a parse_struct into a buffer.
455  ********************************************************************/
456
457 bool prs_copy_all_data_out(char *dst, prs_struct *src)
458 {
459         uint32 len = prs_offset(src);
460
461         if (!len)
462                 return True;
463
464         prs_set_offset(src, 0);
465         return prs_copy_data_out(dst, src, len);
466 }
467
468 /*******************************************************************
469  Set the data as X-endian (external interface).
470  ********************************************************************/
471
472 void prs_set_endian_data(prs_struct *ps, bool endian)
473 {
474         ps->bigendian_data = endian;
475 }
476
477 /*******************************************************************
478  Align a the data_len to a multiple of align bytes - filling with
479  zeros.
480  ********************************************************************/
481
482 bool prs_align(prs_struct *ps)
483 {
484         uint32 mod = ps->data_offset & (ps->align-1);
485
486         if (ps->align != 0 && mod != 0) {
487                 uint32 extra_space = (ps->align - mod);
488                 if(!prs_grow(ps, extra_space))
489                         return False;
490                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
491                 ps->data_offset += extra_space;
492         }
493
494         return True;
495 }
496
497 /******************************************************************
498  Align on a 2 byte boundary
499  *****************************************************************/
500  
501 bool prs_align_uint16(prs_struct *ps)
502 {
503         bool ret;
504         uint8 old_align = ps->align;
505
506         ps->align = 2;
507         ret = prs_align(ps);
508         ps->align = old_align;
509         
510         return ret;
511 }
512
513 /******************************************************************
514  Align on a 8 byte boundary
515  *****************************************************************/
516  
517 bool prs_align_uint64(prs_struct *ps)
518 {
519         bool ret;
520         uint8 old_align = ps->align;
521
522         ps->align = 8;
523         ret = prs_align(ps);
524         ps->align = old_align;
525         
526         return ret;
527 }
528
529 /******************************************************************
530  Align on a specific byte boundary
531  *****************************************************************/
532  
533 bool prs_align_custom(prs_struct *ps, uint8 boundary)
534 {
535         bool ret;
536         uint8 old_align = ps->align;
537
538         ps->align = boundary;
539         ret = prs_align(ps);
540         ps->align = old_align;
541         
542         return ret;
543 }
544
545
546
547 /*******************************************************************
548  Align only if required (for the unistr2 string mainly)
549  ********************************************************************/
550
551 bool prs_align_needed(prs_struct *ps, uint32 needed)
552 {
553         if (needed==0)
554                 return True;
555         else
556                 return prs_align(ps);
557 }
558
559 /*******************************************************************
560  Ensure we can read/write to a given offset.
561  ********************************************************************/
562
563 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
564 {
565         if(UNMARSHALLING(ps)) {
566                 /*
567                  * If reading, ensure that we can read the requested size item.
568                  */
569                 if (ps->data_offset + extra_size > ps->buffer_size) {
570                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
571                                 "buffer by %u bytes.\n",
572                                 (unsigned int)extra_size,
573                                 (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
574                         return NULL;
575                 }
576         } else {
577                 /*
578                  * Writing - grow the buffer if needed.
579                  */
580                 if(!prs_grow(ps, extra_size))
581                         return NULL;
582         }
583         return &ps->data_p[ps->data_offset];
584 }
585
586 /*******************************************************************
587  Change the struct type.
588  ********************************************************************/
589
590 void prs_switch_type(prs_struct *ps, bool io)
591 {
592         if ((ps->io ^ io) == True)
593                 ps->io=io;
594 }
595
596 /*******************************************************************
597  Force a prs_struct to be dynamic even when it's size is 0.
598  ********************************************************************/
599
600 void prs_force_dynamic(prs_struct *ps)
601 {
602         ps->is_dynamic=True;
603 }
604
605 /*******************************************************************
606  Associate a session key with a parse struct.
607  ********************************************************************/
608
609 void prs_set_session_key(prs_struct *ps, const char sess_key[16])
610 {
611         ps->sess_key = sess_key;
612 }
613
614 /*******************************************************************
615  Stream a uint8.
616  ********************************************************************/
617
618 bool prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8)
619 {
620         char *q = prs_mem_get(ps, 1);
621         if (q == NULL)
622                 return False;
623
624         if (UNMARSHALLING(ps))
625                 *data8 = CVAL(q,0);
626         else
627                 SCVAL(q,0,*data8);
628
629         DEBUGADD(5,("%s%04x %s: %02x\n", tab_depth(5,depth), ps->data_offset, name, *data8));
630
631         ps->data_offset += 1;
632
633         return True;
634 }
635
636 /*******************************************************************
637  Stream a uint16* (allocate memory if unmarshalling)
638  ********************************************************************/
639
640 bool prs_pointer( const char *name, prs_struct *ps, int depth, 
641                  void *dta, size_t data_size,
642                  bool (*prs_fn)(const char*, prs_struct*, int, void*) )
643 {
644         void ** data = (void **)dta;
645         uint32 data_p;
646
647         /* output f000baaa to stream if the pointer is non-zero. */
648
649         data_p = *data ? 0xf000baaa : 0;
650
651         if ( !prs_uint32("ptr", ps, depth, &data_p ))
652                 return False;
653
654         /* we're done if there is no data */
655
656         if ( !data_p )
657                 return True;
658
659         if (UNMARSHALLING(ps)) {
660                 if (data_size) {
661                         if ( !(*data = PRS_ALLOC_MEM(ps, char, data_size)) )
662                                 return False;
663                 } else {
664                         *data = NULL;
665                 }
666         }
667
668         return prs_fn(name, ps, depth, *data);
669 }
670
671
672 /*******************************************************************
673  Stream a uint16.
674  ********************************************************************/
675
676 bool prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16)
677 {
678         char *q = prs_mem_get(ps, sizeof(uint16));
679         if (q == NULL)
680                 return False;
681
682         if (UNMARSHALLING(ps)) {
683                 if (ps->bigendian_data)
684                         *data16 = RSVAL(q,0);
685                 else
686                         *data16 = SVAL(q,0);
687         } else {
688                 if (ps->bigendian_data)
689                         RSSVAL(q,0,*data16);
690                 else
691                         SSVAL(q,0,*data16);
692         }
693
694         DEBUGADD(5,("%s%04x %s: %04x\n", tab_depth(5,depth), ps->data_offset, name, *data16));
695
696         ps->data_offset += sizeof(uint16);
697
698         return True;
699 }
700
701 /*******************************************************************
702  Stream a uint32.
703  ********************************************************************/
704
705 bool prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
706 {
707         char *q = prs_mem_get(ps, sizeof(uint32));
708         if (q == NULL)
709                 return False;
710
711         if (UNMARSHALLING(ps)) {
712                 if (ps->bigendian_data)
713                         *data32 = RIVAL(q,0);
714                 else
715                         *data32 = IVAL(q,0);
716         } else {
717                 if (ps->bigendian_data)
718                         RSIVAL(q,0,*data32);
719                 else
720                         SIVAL(q,0,*data32);
721         }
722
723         DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
724
725         ps->data_offset += sizeof(uint32);
726
727         return True;
728 }
729
730 /*******************************************************************
731  Stream an int32.
732  ********************************************************************/
733
734 bool prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32)
735 {
736         char *q = prs_mem_get(ps, sizeof(int32));
737         if (q == NULL)
738                 return False;
739
740         if (UNMARSHALLING(ps)) {
741                 if (ps->bigendian_data)
742                         *data32 = RIVALS(q,0);
743                 else
744                         *data32 = IVALS(q,0);
745         } else {
746                 if (ps->bigendian_data)
747                         RSIVALS(q,0,*data32);
748                 else
749                         SIVALS(q,0,*data32);
750         }
751
752         DEBUGADD(5,("%s%04x %s: %08x\n", tab_depth(5,depth), ps->data_offset, name, *data32));
753
754         ps->data_offset += sizeof(int32);
755
756         return True;
757 }
758
759 /*******************************************************************
760  Stream a NTSTATUS
761  ********************************************************************/
762
763 bool prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
764 {
765         char *q = prs_mem_get(ps, sizeof(uint32));
766         if (q == NULL)
767                 return False;
768
769         if (UNMARSHALLING(ps)) {
770                 if (ps->bigendian_data)
771                         *status = NT_STATUS(RIVAL(q,0));
772                 else
773                         *status = NT_STATUS(IVAL(q,0));
774         } else {
775                 if (ps->bigendian_data)
776                         RSIVAL(q,0,NT_STATUS_V(*status));
777                 else
778                         SIVAL(q,0,NT_STATUS_V(*status));
779         }
780
781         DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
782                  nt_errstr(*status)));
783
784         ps->data_offset += sizeof(uint32);
785
786         return True;
787 }
788
789 /*******************************************************************
790  Stream a DCE error code
791  ********************************************************************/
792
793 bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
794 {
795         char *q = prs_mem_get(ps, sizeof(uint32));
796         if (q == NULL)
797                 return False;
798
799         if (UNMARSHALLING(ps)) {
800                 if (ps->bigendian_data)
801                         *status = NT_STATUS(RIVAL(q,0));
802                 else
803                         *status = NT_STATUS(IVAL(q,0));
804         } else {
805                 if (ps->bigendian_data)
806                         RSIVAL(q,0,NT_STATUS_V(*status));
807                 else
808                         SIVAL(q,0,NT_STATUS_V(*status));
809         }
810
811         DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
812                  dcerpc_errstr(debug_ctx(), NT_STATUS_V(*status))));
813
814         ps->data_offset += sizeof(uint32);
815
816         return True;
817 }
818
819
820 /*******************************************************************
821  Stream a WERROR
822  ********************************************************************/
823
824 bool prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
825 {
826         char *q = prs_mem_get(ps, sizeof(uint32));
827         if (q == NULL)
828                 return False;
829
830         if (UNMARSHALLING(ps)) {
831                 if (ps->bigendian_data)
832                         *status = W_ERROR(RIVAL(q,0));
833                 else
834                         *status = W_ERROR(IVAL(q,0));
835         } else {
836                 if (ps->bigendian_data)
837                         RSIVAL(q,0,W_ERROR_V(*status));
838                 else
839                         SIVAL(q,0,W_ERROR_V(*status));
840         }
841
842         DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
843                  win_errstr(*status)));
844
845         ps->data_offset += sizeof(uint32);
846
847         return True;
848 }
849
850
851 /******************************************************************
852  Stream an array of uint8s. Length is number of uint8s.
853  ********************************************************************/
854
855 bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
856 {
857         int i;
858         char *q = prs_mem_get(ps, len);
859         if (q == NULL)
860                 return False;
861
862         if (UNMARSHALLING(ps)) {
863                 for (i = 0; i < len; i++)
864                         data8s[i] = CVAL(q,i);
865         } else {
866                 for (i = 0; i < len; i++)
867                         SCVAL(q, i, data8s[i]);
868         }
869
870         DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset ,name));
871         if (charmode)
872                 print_asc(5, (unsigned char*)data8s, len);
873         else {
874                 for (i = 0; i < len; i++)
875                         DEBUGADD(5,("%02x ", data8s[i]));
876         }
877         DEBUGADD(5,("\n"));
878
879         ps->data_offset += len;
880
881         return True;
882 }
883
884 /******************************************************************
885  Stream an array of uint16s. Length is number of uint16s.
886  ********************************************************************/
887
888 bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
889 {
890         int i;
891         char *q = prs_mem_get(ps, len * sizeof(uint16));
892         if (q == NULL)
893                 return False;
894
895         if (UNMARSHALLING(ps)) {
896                 if (ps->bigendian_data) {
897                         for (i = 0; i < len; i++)
898                                 data16s[i] = RSVAL(q, 2*i);
899                 } else {
900                         for (i = 0; i < len; i++)
901                                 data16s[i] = SVAL(q, 2*i);
902                 }
903         } else {
904                 if (ps->bigendian_data) {
905                         for (i = 0; i < len; i++)
906                                 RSSVAL(q, 2*i, data16s[i]);
907                 } else {
908                         for (i = 0; i < len; i++)
909                                 SSVAL(q, 2*i, data16s[i]);
910                 }
911         }
912
913         DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
914         if (charmode)
915                 print_asc(5, (unsigned char*)data16s, 2*len);
916         else {
917                 for (i = 0; i < len; i++)
918                         DEBUGADD(5,("%04x ", data16s[i]));
919         }
920         DEBUGADD(5,("\n"));
921
922         ps->data_offset += (len * sizeof(uint16));
923
924         return True;
925 }
926
927 /******************************************************************
928  Start using a function for streaming unicode chars. If unmarshalling,
929  output must be little-endian, if marshalling, input must be little-endian.
930  ********************************************************************/
931
932 static void dbg_rw_punival(bool charmode, const char *name, int depth, prs_struct *ps,
933                                                         char *in_buf, char *out_buf, int len)
934 {
935         int i;
936
937         if (UNMARSHALLING(ps)) {
938                 if (ps->bigendian_data) {
939                         for (i = 0; i < len; i++)
940                                 SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
941                 } else {
942                         for (i = 0; i < len; i++)
943                                 SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
944                 }
945         } else {
946                 if (ps->bigendian_data) {
947                         for (i = 0; i < len; i++)
948                                 RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
949                 } else {
950                         for (i = 0; i < len; i++)
951                                 SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
952                 }
953         }
954
955         DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
956         if (charmode)
957                 print_asc(5, (unsigned char*)out_buf, 2*len);
958         else {
959                 for (i = 0; i < len; i++)
960                         DEBUGADD(5,("%04x ", out_buf[i]));
961         }
962         DEBUGADD(5,("\n"));
963 }
964
965 /******************************************************************
966  Stream a unistr. Always little endian.
967  ********************************************************************/
968
969 bool prs_uint16uni(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
970 {
971         char *q = prs_mem_get(ps, len * sizeof(uint16));
972         if (q == NULL)
973                 return False;
974
975         dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
976         ps->data_offset += (len * sizeof(uint16));
977
978         return True;
979 }
980
981 /******************************************************************
982  Stream an array of uint32s. Length is number of uint32s.
983  ********************************************************************/
984
985 bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
986 {
987         int i;
988         char *q = prs_mem_get(ps, len * sizeof(uint32));
989         if (q == NULL)
990                 return False;
991
992         if (UNMARSHALLING(ps)) {
993                 if (ps->bigendian_data) {
994                         for (i = 0; i < len; i++)
995                                 data32s[i] = RIVAL(q, 4*i);
996                 } else {
997                         for (i = 0; i < len; i++)
998                                 data32s[i] = IVAL(q, 4*i);
999                 }
1000         } else {
1001                 if (ps->bigendian_data) {
1002                         for (i = 0; i < len; i++)
1003                                 RSIVAL(q, 4*i, data32s[i]);
1004                 } else {
1005                         for (i = 0; i < len; i++)
1006                                 SIVAL(q, 4*i, data32s[i]);
1007                 }
1008         }
1009
1010         DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
1011         if (charmode)
1012                 print_asc(5, (unsigned char*)data32s, 4*len);
1013         else {
1014                 for (i = 0; i < len; i++)
1015                         DEBUGADD(5,("%08x ", data32s[i]));
1016         }
1017         DEBUGADD(5,("\n"));
1018
1019         ps->data_offset += (len * sizeof(uint32));
1020
1021         return True;
1022 }
1023
1024 /******************************************************************
1025  Stream an array of unicode string, length/buffer specified separately,
1026  in uint16 chars. The unicode string is already in little-endian format.
1027  ********************************************************************/
1028
1029 bool prs_buffer5(bool charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str)
1030 {
1031         char *p;
1032         char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
1033         if (q == NULL)
1034                 return False;
1035
1036         /* If the string is empty, we don't have anything to stream */
1037         if (str->buf_len==0)
1038                 return True;
1039
1040         if (UNMARSHALLING(ps)) {
1041                 str->buffer = PRS_ALLOC_MEM(ps,uint16,str->buf_len);
1042                 if (str->buffer == NULL)
1043                         return False;
1044         }
1045
1046         p = (char *)str->buffer;
1047
1048         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
1049         
1050         ps->data_offset += (str->buf_len * sizeof(uint16));
1051
1052         return True;
1053 }
1054
1055 /******************************************************************
1056  Stream a string, length/buffer specified separately,
1057  in uint8 chars.
1058  ********************************************************************/
1059
1060 bool prs_string2(bool charmode, const char *name, prs_struct *ps, int depth, STRING2 *str)
1061 {
1062         unsigned int i;
1063         char *q = prs_mem_get(ps, str->str_str_len);
1064         if (q == NULL)
1065                 return False;
1066
1067         if (UNMARSHALLING(ps)) {
1068                 if (str->str_str_len > str->str_max_len) {
1069                         return False;
1070                 }
1071                 if (str->str_max_len) {
1072                         str->buffer = PRS_ALLOC_MEM(ps,unsigned char, str->str_max_len);
1073                         if (str->buffer == NULL)
1074                                 return False;
1075                 } else {
1076                         str->buffer = NULL;
1077                         /* Return early to ensure Coverity isn't confused. */
1078                         DEBUGADD(5,("%s%04x %s: \n", tab_depth(5,depth), ps->data_offset, name));
1079                         return True;
1080                 }
1081         }
1082
1083         if (UNMARSHALLING(ps)) {
1084                 for (i = 0; i < str->str_str_len; i++)
1085                         str->buffer[i] = CVAL(q,i);
1086         } else {
1087                 for (i = 0; i < str->str_str_len; i++)
1088                         SCVAL(q, i, str->buffer[i]);
1089         }
1090
1091         DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
1092         if (charmode)
1093                 print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
1094         else {
1095                 for (i = 0; i < str->str_str_len; i++)
1096                         DEBUG(5,("%02x ", str->buffer[i]));
1097         }
1098         DEBUGADD(5,("\n"));
1099
1100         ps->data_offset += str->str_str_len;
1101
1102         return True;
1103 }
1104
1105 /******************************************************************
1106  Stream a unicode string, length/buffer specified separately,
1107  in uint16 chars. The unicode string is already in little-endian format.
1108  ********************************************************************/
1109
1110 bool prs_unistr2(bool charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str)
1111 {
1112         char *p;
1113         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
1114         if (q == NULL)
1115                 return False;
1116
1117         /* If the string is empty, we don't have anything to stream */
1118         if (str->uni_str_len==0)
1119                 return True;
1120
1121         if (UNMARSHALLING(ps)) {
1122                 if (str->uni_str_len > str->uni_max_len) {
1123                         return False;
1124                 }
1125                 if (str->uni_max_len) {
1126                         str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len);
1127                         if (str->buffer == NULL)
1128                                 return False;
1129                 } else {
1130                         str->buffer = NULL;
1131                 }
1132         }
1133
1134         p = (char *)str->buffer;
1135
1136         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
1137         
1138         ps->data_offset += (str->uni_str_len * sizeof(uint16));
1139
1140         return True;
1141 }
1142
1143 /******************************************************************
1144  Stream a unicode string, length/buffer specified separately,
1145  in uint16 chars. The unicode string is already in little-endian format.
1146  ********************************************************************/
1147
1148 bool prs_unistr3(bool charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth)
1149 {
1150         char *p;
1151         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
1152         if (q == NULL)
1153                 return False;
1154
1155         if (UNMARSHALLING(ps)) {
1156                 if (str->uni_str_len) {
1157                         str->str.buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_str_len);
1158                         if (str->str.buffer == NULL)
1159                                 return False;
1160                 } else {
1161                         str->str.buffer = NULL;
1162                 }
1163         }
1164
1165         p = (char *)str->str.buffer;
1166
1167         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
1168         ps->data_offset += (str->uni_str_len * sizeof(uint16));
1169
1170         return True;
1171 }
1172
1173 /*******************************************************************
1174  Stream a unicode  null-terminated string. As the string is already
1175  in little-endian format then do it as a stream of bytes.
1176  ********************************************************************/
1177
1178 bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
1179 {
1180         unsigned int len = 0;
1181         unsigned char *p = (unsigned char *)str->buffer;
1182         uint8 *start;
1183         char *q;
1184         uint32 max_len;
1185         uint16* ptr;
1186
1187         if (MARSHALLING(ps)) {
1188
1189                 for(len = 0; str->buffer[len] != 0; len++)
1190                         ;
1191
1192                 q = prs_mem_get(ps, (len+1)*2);
1193                 if (q == NULL)
1194                         return False;
1195
1196                 start = (uint8*)q;
1197
1198                 for(len = 0; str->buffer[len] != 0; len++) {
1199                         if(ps->bigendian_data) {
1200                                 /* swap bytes - p is little endian, q is big endian. */
1201                                 q[0] = (char)p[1];
1202                                 q[1] = (char)p[0];
1203                                 p += 2;
1204                                 q += 2;
1205                         } 
1206                         else 
1207                         {
1208                                 q[0] = (char)p[0];
1209                                 q[1] = (char)p[1];
1210                                 p += 2;
1211                                 q += 2;
1212                         }
1213                 }
1214
1215                 /*
1216                  * even if the string is 'empty' (only an \0 char)
1217                  * at this point the leading \0 hasn't been parsed.
1218                  * so parse it now
1219                  */
1220
1221                 q[0] = 0;
1222                 q[1] = 0;
1223                 q += 2;
1224
1225                 len++;
1226
1227                 DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
1228                 print_asc(5, (unsigned char*)start, 2*len);     
1229                 DEBUGADD(5, ("\n"));
1230         }
1231         else { /* unmarshalling */
1232         
1233                 uint32 alloc_len = 0;
1234                 q = ps->data_p + prs_offset(ps);
1235
1236                 /*
1237                  * Work out how much space we need and talloc it.
1238                  */
1239                 max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
1240
1241                 /* the test of the value of *ptr helps to catch the circumstance
1242                    where we have an emtpty (non-existent) string in the buffer */
1243                 for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
1244                         /* do nothing */ 
1245                         ;
1246
1247                 if (alloc_len < max_len)
1248                         alloc_len += 1;
1249
1250                 /* should we allocate anything at all? */
1251                 str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len);
1252                 if ((str->buffer == NULL) && (alloc_len > 0))
1253                         return False;
1254
1255                 p = (unsigned char *)str->buffer;
1256
1257                 len = 0;
1258                 /* the (len < alloc_len) test is to prevent us from overwriting
1259                    memory that is not ours...if we get that far, we have a non-null
1260                    terminated string in the buffer and have messed up somewhere */
1261                 while ((len < alloc_len) && (*(uint16 *)q != 0)) {
1262                         if(ps->bigendian_data) 
1263                         {
1264                                 /* swap bytes - q is big endian, p is little endian. */
1265                                 p[0] = (unsigned char)q[1];
1266                                 p[1] = (unsigned char)q[0];
1267                                 p += 2;
1268                                 q += 2;
1269                         } else {
1270
1271                                 p[0] = (unsigned char)q[0];
1272                                 p[1] = (unsigned char)q[1];
1273                                 p += 2;
1274                                 q += 2;
1275                         }
1276
1277                         len++;
1278                 } 
1279                 if (len < alloc_len) {
1280                         /* NULL terminate the UNISTR */
1281                         str->buffer[len++] = '\0';
1282                 }
1283
1284                 DEBUGADD(5,("%s%04x %s: ", tab_depth(5,depth), ps->data_offset, name));
1285                 print_asc(5, (unsigned char*)str->buffer, 2*len);       
1286                 DEBUGADD(5, ("\n"));
1287         }
1288
1289         /* set the offset in the prs_struct; 'len' points to the
1290            terminiating NULL in the UNISTR so we need to go one more
1291            uint16 */
1292         ps->data_offset += (len)*2;
1293         
1294         return True;
1295 }
1296
1297
1298 /*******************************************************************
1299  Stream a null-terminated string.  len is strlen, and therefore does
1300  not include the null-termination character.
1301  ********************************************************************/
1302
1303 bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size)
1304 {
1305         char *q;
1306         int i;
1307         int len;
1308
1309         if (UNMARSHALLING(ps))
1310                 len = strlen(&ps->data_p[ps->data_offset]);
1311         else
1312                 len = strlen(str);
1313
1314         len = MIN(len, (max_buf_size-1));
1315
1316         q = prs_mem_get(ps, len+1);
1317         if (q == NULL)
1318                 return False;
1319
1320         for(i = 0; i < len; i++) {
1321                 if (UNMARSHALLING(ps))
1322                         str[i] = q[i];
1323                 else
1324                         q[i] = str[i];
1325         }
1326
1327         /* The terminating null. */
1328         str[i] = '\0';
1329
1330         if (MARSHALLING(ps)) {
1331                 q[i] = '\0';
1332         }
1333
1334         ps->data_offset += len+1;
1335
1336         dump_data(5+depth, (uint8 *)q, len);
1337
1338         return True;
1339 }
1340
1341 bool prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str)
1342 {
1343         size_t len;
1344         char *tmp_str;
1345
1346         if (UNMARSHALLING(ps)) {
1347                 len = strlen(&ps->data_p[ps->data_offset]);
1348         } else {
1349                 len = strlen(*str);
1350         }
1351
1352         tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
1353
1354         if (tmp_str == NULL) {
1355                 return False;
1356         }
1357
1358         if (MARSHALLING(ps)) {
1359                 strncpy(tmp_str, *str, len);
1360         }
1361
1362         if (!prs_string(name, ps, depth, tmp_str, len+1)) {
1363                 return False;
1364         }
1365
1366         *str = tmp_str;
1367         return True;
1368 }
1369
1370 /*******************************************************************
1371  prs_uint16 wrapper. Call this and it sets up a pointer to where the
1372  uint16 should be stored, or gets the size if reading.
1373  ********************************************************************/
1374
1375 bool prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
1376 {
1377         *offset = ps->data_offset;
1378         if (UNMARSHALLING(ps)) {
1379                 /* reading. */
1380                 return prs_uint16(name, ps, depth, data16);
1381         } else {
1382                 char *q = prs_mem_get(ps, sizeof(uint16));
1383                 if(q ==NULL)
1384                         return False;
1385                 ps->data_offset += sizeof(uint16);
1386         }
1387         return True;
1388 }
1389
1390 /*******************************************************************
1391  prs_uint16 wrapper.  call this and it retrospectively stores the size.
1392  does nothing on reading, as that is already handled by ...._pre()
1393  ********************************************************************/
1394
1395 bool prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
1396                                 uint32 ptr_uint16, uint32 start_offset)
1397 {
1398         if (MARSHALLING(ps)) {
1399                 /* 
1400                  * Writing - temporarily move the offset pointer.
1401                  */
1402                 uint16 data_size = ps->data_offset - start_offset;
1403                 uint32 old_offset = ps->data_offset;
1404
1405                 ps->data_offset = ptr_uint16;
1406                 if(!prs_uint16(name, ps, depth, &data_size)) {
1407                         ps->data_offset = old_offset;
1408                         return False;
1409                 }
1410                 ps->data_offset = old_offset;
1411         } else {
1412                 ps->data_offset = start_offset + (uint32)(*data16);
1413         }
1414         return True;
1415 }
1416
1417 /*******************************************************************
1418  prs_uint32 wrapper. Call this and it sets up a pointer to where the
1419  uint32 should be stored, or gets the size if reading.
1420  ********************************************************************/
1421
1422 bool prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
1423 {
1424         *offset = ps->data_offset;
1425         if (UNMARSHALLING(ps) && (data32 != NULL)) {
1426                 /* reading. */
1427                 return prs_uint32(name, ps, depth, data32);
1428         } else {
1429                 ps->data_offset += sizeof(uint32);
1430         }
1431         return True;
1432 }
1433
1434 /*******************************************************************
1435  prs_uint32 wrapper.  call this and it retrospectively stores the size.
1436  does nothing on reading, as that is already handled by ...._pre()
1437  ********************************************************************/
1438
1439 bool prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
1440                                 uint32 ptr_uint32, uint32 data_size)
1441 {
1442         if (MARSHALLING(ps)) {
1443                 /* 
1444                  * Writing - temporarily move the offset pointer.
1445                  */
1446                 uint32 old_offset = ps->data_offset;
1447                 ps->data_offset = ptr_uint32;
1448                 if(!prs_uint32(name, ps, depth, &data_size)) {
1449                         ps->data_offset = old_offset;
1450                         return False;
1451                 }
1452                 ps->data_offset = old_offset;
1453         }
1454         return True;
1455 }
1456
1457 /* useful function to store a structure in rpc wire format */
1458 int tdb_prs_store(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps)
1459 {
1460         TDB_DATA dbuf;
1461         dbuf.dptr = (uint8 *)ps->data_p;
1462         dbuf.dsize = prs_offset(ps);
1463         return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE);
1464 }
1465
1466 /* useful function to fetch a structure into rpc wire format */
1467 int tdb_prs_fetch(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps, TALLOC_CTX *mem_ctx)
1468 {
1469         TDB_DATA dbuf;
1470
1471         prs_init_empty(ps, mem_ctx, UNMARSHALL);
1472
1473         dbuf = tdb_fetch(tdb, kbuf);
1474         if (!dbuf.dptr)
1475                 return -1;
1476
1477         prs_give_memory(ps, (char *)dbuf.dptr, dbuf.dsize, True);
1478
1479         return 0;
1480 }
1481
1482 /*******************************************************************
1483  hash a stream.
1484  ********************************************************************/
1485
1486 bool prs_hash1(prs_struct *ps, uint32 offset, int len)
1487 {
1488         char *q;
1489
1490         q = ps->data_p;
1491         q = &q[offset];
1492
1493 #ifdef DEBUG_PASSWORD
1494         DEBUG(100, ("prs_hash1\n"));
1495         dump_data(100, (uint8 *)ps->sess_key, 16);
1496         dump_data(100, (uint8 *)q, len);
1497 #endif
1498         SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);
1499
1500 #ifdef DEBUG_PASSWORD
1501         dump_data(100, (uint8 *)q, len);
1502 #endif
1503
1504         return True;
1505 }
1506
1507 /*******************************************************************
1508  Create a digest over the entire packet (including the data), and 
1509  MD5 it with the session key.
1510  ********************************************************************/
1511
1512 static void schannel_digest(struct schannel_auth_struct *a,
1513                           enum pipe_auth_level auth_level,
1514                           RPC_AUTH_SCHANNEL_CHK * verf,
1515                           char *data, size_t data_len,
1516                           uchar digest_final[16]) 
1517 {
1518         uchar whole_packet_digest[16];
1519         uchar zeros[4];
1520         struct MD5Context ctx3;
1521
1522         ZERO_STRUCT(zeros);
1523
1524         /* verfiy the signature on the packet by MD5 over various bits */
1525         MD5Init(&ctx3);
1526         /* use our sequence number, which ensures the packet is not
1527            out of order */
1528         MD5Update(&ctx3, zeros, sizeof(zeros));
1529         MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
1530         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
1531                 MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder));
1532         }
1533         MD5Update(&ctx3, (const unsigned char *)data, data_len);
1534         MD5Final(whole_packet_digest, &ctx3);
1535         dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
1536         
1537         /* MD5 this result and the session key, to prove that
1538            only a valid client could had produced this */
1539         hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
1540 }
1541
1542 /*******************************************************************
1543  Calculate the key with which to encode the data payload 
1544  ********************************************************************/
1545
1546 static void schannel_get_sealing_key(struct schannel_auth_struct *a,
1547                                    RPC_AUTH_SCHANNEL_CHK *verf,
1548                                    uchar sealing_key[16]) 
1549 {
1550         uchar zeros[4];
1551         uchar digest2[16];
1552         uchar sess_kf0[16];
1553         int i;
1554
1555         ZERO_STRUCT(zeros);
1556
1557         for (i = 0; i < sizeof(sess_kf0); i++) {
1558                 sess_kf0[i] = a->sess_key[i] ^ 0xf0;
1559         }
1560         
1561         dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
1562         
1563         /* MD5 of sess_kf0 and 4 zero bytes */
1564         hmac_md5(sess_kf0, zeros, 0x4, digest2);
1565         dump_data_pw("digest2:\n", digest2, sizeof(digest2));
1566         
1567         /* MD5 of the above result, plus 8 bytes of sequence number */
1568         hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
1569         dump_data_pw("sealing_key:\n", sealing_key, 16);
1570 }
1571
1572 /*******************************************************************
1573  Encode or Decode the sequence number (which is symmetric)
1574  ********************************************************************/
1575
1576 static void schannel_deal_with_seq_num(struct schannel_auth_struct *a,
1577                                      RPC_AUTH_SCHANNEL_CHK *verf)
1578 {
1579         uchar zeros[4];
1580         uchar sequence_key[16];
1581         uchar digest1[16];
1582
1583         ZERO_STRUCT(zeros);
1584
1585         hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
1586         dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
1587
1588         hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
1589
1590         dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
1591
1592         dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
1593         SamOEMhash(verf->seq_num, sequence_key, 8);
1594         dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
1595 }
1596
1597 /*******************************************************************
1598 creates an RPC_AUTH_SCHANNEL_CHK structure.
1599 ********************************************************************/
1600
1601 static bool init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk,
1602                               const uchar sig[8],
1603                               const uchar packet_digest[8],
1604                               const uchar seq_num[8], const uchar confounder[8])
1605 {
1606         if (chk == NULL)
1607                 return False;
1608
1609         memcpy(chk->sig, sig, sizeof(chk->sig));
1610         memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
1611         memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
1612         memcpy(chk->confounder, confounder, sizeof(chk->confounder));
1613
1614         return True;
1615 }
1616
1617 /*******************************************************************
1618  Encode a blob of data using the schannel alogrithm, also produceing
1619  a checksum over the original data.  We currently only support
1620  signing and sealing togeather - the signing-only code is close, but not
1621  quite compatible with what MS does.
1622  ********************************************************************/
1623
1624 void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
1625                    enum schannel_direction direction,
1626                    RPC_AUTH_SCHANNEL_CHK * verf,
1627                    char *data, size_t data_len)
1628 {
1629         uchar digest_final[16];
1630         uchar confounder[8];
1631         uchar seq_num[8];
1632         static const uchar nullbytes[8] = { 0, };
1633
1634         static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
1635         static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
1636         const uchar *schannel_sig = NULL;
1637
1638         DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
1639         
1640         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
1641                 schannel_sig = schannel_seal_sig;
1642         } else {
1643                 schannel_sig = schannel_sign_sig;
1644         }
1645
1646         /* fill the 'confounder' with random data */
1647         generate_random_buffer(confounder, sizeof(confounder));
1648
1649         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
1650
1651         RSIVAL(seq_num, 0, a->seq_num);
1652
1653         switch (direction) {
1654         case SENDER_IS_INITIATOR:
1655                 SIVAL(seq_num, 4, 0x80);
1656                 break;
1657         case SENDER_IS_ACCEPTOR:
1658                 SIVAL(seq_num, 4, 0x0);
1659                 break;
1660         }
1661
1662         dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));
1663
1664         init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes,
1665                                  seq_num, confounder);
1666                                 
1667         /* produce a digest of the packet to prove it's legit (before we seal it) */
1668         schannel_digest(a, auth_level, verf, data, data_len, digest_final);
1669         memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
1670
1671         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
1672                 uchar sealing_key[16];
1673
1674                 /* get the key to encode the data with */
1675                 schannel_get_sealing_key(a, verf, sealing_key);
1676
1677                 /* encode the verification data */
1678                 dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
1679                 SamOEMhash(verf->confounder, sealing_key, 8);
1680
1681                 dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
1682                 
1683                 /* encode the packet payload */
1684                 dump_data_pw("data:\n", (const unsigned char *)data, data_len);
1685                 SamOEMhash((unsigned char *)data, sealing_key, data_len);
1686                 dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
1687         }
1688
1689         /* encode the sequence number (key based on packet digest) */
1690         /* needs to be done after the sealing, as the original version 
1691            is used in the sealing stuff... */
1692         schannel_deal_with_seq_num(a, verf);
1693
1694         return;
1695 }
1696
1697 /*******************************************************************
1698  Decode a blob of data using the schannel alogrithm, also verifiying
1699  a checksum over the original data.  We currently can verify signed messages,
1700  as well as decode sealed messages
1701  ********************************************************************/
1702
1703 bool schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
1704                    enum schannel_direction direction, 
1705                    RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len)
1706 {
1707         uchar digest_final[16];
1708
1709         static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
1710         static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
1711         const uchar *schannel_sig = NULL;
1712
1713         uchar seq_num[8];
1714
1715         DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
1716         
1717         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
1718                 schannel_sig = schannel_seal_sig;
1719         } else {
1720                 schannel_sig = schannel_sign_sig;
1721         }
1722
1723         /* Create the expected sequence number for comparison */
1724         RSIVAL(seq_num, 0, a->seq_num);
1725
1726         switch (direction) {
1727         case SENDER_IS_INITIATOR:
1728                 SIVAL(seq_num, 4, 0x80);
1729                 break;
1730         case SENDER_IS_ACCEPTOR:
1731                 SIVAL(seq_num, 4, 0x0);
1732                 break;
1733         }
1734
1735         DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
1736         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
1737
1738         dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
1739
1740         /* extract the sequence number (key based on supplied packet digest) */
1741         /* needs to be done before the sealing, as the original version 
1742            is used in the sealing stuff... */
1743         schannel_deal_with_seq_num(a, verf);
1744
1745         if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
1746                 /* don't even bother with the below if the sequence number is out */
1747                 /* The sequence number is MD5'ed with a key based on the whole-packet
1748                    digest, as supplied by the client.  We check that it's a valid 
1749                    checksum after the decode, below
1750                 */
1751                 DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n"));
1752                 dump_data(2, verf->seq_num, sizeof(verf->seq_num));
1753                 DEBUG(2, ("should be:\n"));
1754                 dump_data(2, seq_num, sizeof(seq_num));
1755
1756                 return False;
1757         }
1758
1759         if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) {
1760                 /* Validate that the other end sent the expected header */
1761                 DEBUG(2, ("schannel_decode: FAILED: packet header:\n"));
1762                 dump_data(2, verf->sig, sizeof(verf->sig));
1763                 DEBUG(2, ("should be:\n"));
1764                 dump_data(2, schannel_sig, sizeof(schannel_sig));
1765                 return False;
1766         }
1767
1768         if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
1769                 uchar sealing_key[16];
1770                 
1771                 /* get the key to extract the data with */
1772                 schannel_get_sealing_key(a, verf, sealing_key);
1773
1774                 /* extract the verification data */
1775                 dump_data_pw("verf->confounder:\n", verf->confounder, 
1776                              sizeof(verf->confounder));
1777                 SamOEMhash(verf->confounder, sealing_key, 8);
1778
1779                 dump_data_pw("verf->confounder_dec:\n", verf->confounder, 
1780                              sizeof(verf->confounder));
1781                 
1782                 /* extract the packet payload */
1783                 dump_data_pw("data   :\n", (const unsigned char *)data, data_len);
1784                 SamOEMhash((unsigned char *)data, sealing_key, data_len);
1785                 dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);      
1786         }
1787
1788         /* digest includes 'data' after unsealing */
1789         schannel_digest(a, auth_level, verf, data, data_len, digest_final);
1790
1791         dump_data_pw("Calculated digest:\n", digest_final, 
1792                      sizeof(digest_final));
1793         dump_data_pw("verf->packet_digest:\n", verf->packet_digest, 
1794                      sizeof(verf->packet_digest));
1795         
1796         /* compare - if the client got the same result as us, then
1797            it must know the session key */
1798         return (memcmp(digest_final, verf->packet_digest, 
1799                        sizeof(verf->packet_digest)) == 0);
1800 }
1801
1802 /*******************************************************************
1803 creates a new prs_struct containing a DATA_BLOB
1804 ********************************************************************/
1805 bool prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
1806 {
1807         if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL ))
1808                 return False;
1809
1810
1811         if (!prs_copy_data_in(prs, (char *)blob->data, blob->length))
1812                 return False;
1813
1814         return True;
1815 }
1816
1817 /*******************************************************************
1818 return the contents of a prs_struct in a DATA_BLOB
1819 ********************************************************************/
1820 bool prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
1821 {
1822         blob->length = prs_data_size(prs);
1823         blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length);
1824         
1825         /* set the pointer at the end of the buffer */
1826         prs_set_offset( prs, prs_data_size(prs) );
1827
1828         if (!prs_copy_all_data_out((char *)blob->data, prs))
1829                 return False;
1830         
1831         return True;
1832 }