25c44c9da9b910532567e0154f44ee0182647c6c
[tprouty/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         if (ps->buffer_size)
138                 memset(ps->data_p, '\0', (size_t)ps->buffer_size);
139 }
140
141 /*******************************************************************
142  Allocate memory when unmarshalling... Always zero clears.
143  ********************************************************************/
144
145 char *prs_alloc_mem(prs_struct *ps, size_t size)
146 {
147         char *ret = NULL;
148
149         if (size) {
150                 ret = talloc(ps->mem_ctx, size);
151                 if (ret)
152                         memset(ret, '\0', size);
153         }
154         return ret;
155 }
156
157 /*******************************************************************
158  Return the current talloc context we're using.
159  ********************************************************************/
160
161 TALLOC_CTX *prs_get_mem_context(prs_struct *ps)
162 {
163         return ps->mem_ctx;
164 }
165
166 /*******************************************************************
167  Hand some already allocated memory to a prs_struct.
168  ********************************************************************/
169
170 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
171 {
172         ps->is_dynamic = is_dynamic;
173         ps->data_p = buf;
174         ps->buffer_size = size;
175 }
176
177 /*******************************************************************
178  Take some memory back from a prs_struct.
179  ********************************************************************/
180
181 char *prs_take_memory(prs_struct *ps, uint32 *psize)
182 {
183         char *ret = ps->data_p;
184         if(psize)
185                 *psize = ps->buffer_size;
186         ps->is_dynamic = False;
187         prs_mem_free(ps);
188         return ret;
189 }
190
191 /*******************************************************************
192  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
193  ********************************************************************/
194
195 BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
196 {
197         if (newsize > ps->buffer_size)
198                 return prs_force_grow(ps, newsize - ps->buffer_size);
199
200         if (newsize < ps->buffer_size) {
201                 char *new_data_p = Realloc(ps->data_p, newsize);
202                 /* if newsize is zero, Realloc acts like free() & returns NULL*/
203                 if (new_data_p == NULL && newsize != 0) {
204                         DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
205                                 (unsigned int)newsize));
206                         DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
207                         return False;
208                 }
209                 ps->data_p = new_data_p;
210                 ps->buffer_size = newsize;
211         }
212
213         return True;
214 }
215
216 /*******************************************************************
217  Attempt, if needed, to grow a data buffer.
218  Also depends on the data stream mode (io).
219  ********************************************************************/
220
221 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
222 {
223         uint32 new_size;
224         char *new_data;
225
226         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
227
228         if(ps->data_offset + extra_space <= ps->buffer_size)
229                 return True;
230
231         /*
232          * We cannot grow the buffer if we're not reading
233          * into the prs_struct, or if we don't own the memory.
234          */
235
236         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
237                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
238                                 (unsigned int)extra_space));
239                 return False;
240         }
241         
242         /*
243          * Decide how much extra space we really need.
244          */
245
246         extra_space -= (ps->buffer_size - ps->data_offset);
247         if(ps->buffer_size == 0) {
248                 /*
249                  * Ensure we have at least a PDU's length, or extra_space, whichever
250                  * is greater.
251                  */
252
253                 new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
254
255                 if((new_data = malloc(new_size)) == NULL) {
256                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
257                         return False;
258                 }
259                 memset(new_data, '\0', (size_t)new_size );
260         } else {
261                 /*
262                  * If the current buffer size is bigger than the space needed, just 
263                  * double it, else add extra_space.
264                  */
265                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
266
267                 if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
268                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
269                                 (unsigned int)new_size));
270                         return False;
271                 }
272
273                 memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
274         }
275         ps->buffer_size = new_size;
276         ps->data_p = new_data;
277
278         return True;
279 }
280
281 /*******************************************************************
282  Attempt to force a data buffer to grow by len bytes.
283  This is only used when appending more data onto a prs_struct
284  when reading an rpc reply, before unmarshalling it.
285  ********************************************************************/
286
287 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
288 {
289         uint32 new_size = ps->buffer_size + extra_space;
290         char *new_data;
291
292         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
293                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
294                                 (unsigned int)extra_space));
295                 return False;
296         }
297
298         if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
299                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
300                         (unsigned int)new_size));
301                 return False;
302         }
303
304         memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
305
306         ps->buffer_size = new_size;
307         ps->data_p = new_data;
308
309         return True;
310 }
311
312 /*******************************************************************
313  Get the data pointer (external interface).
314 ********************************************************************/
315
316 char *prs_data_p(prs_struct *ps)
317 {
318         return ps->data_p;
319 }
320
321 /*******************************************************************
322  Get the current data size (external interface).
323  ********************************************************************/
324
325 uint32 prs_data_size(prs_struct *ps)
326 {
327         return ps->buffer_size;
328 }
329
330 /*******************************************************************
331  Fetch the current offset (external interface).
332  ********************************************************************/
333
334 uint32 prs_offset(prs_struct *ps)
335 {
336         return ps->data_offset;
337 }
338
339 /*******************************************************************
340  Set the current offset (external interface).
341  ********************************************************************/
342
343 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
344 {
345         if(offset <= ps->data_offset) {
346                 ps->data_offset = offset;
347                 return True;
348         }
349
350         if(!prs_grow(ps, offset - ps->data_offset))
351                 return False;
352
353         ps->data_offset = offset;
354         return True;
355 }
356
357 /*******************************************************************
358  Append the data from one parse_struct into another.
359  ********************************************************************/
360
361 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
362 {
363         if (prs_offset(src) == 0)
364                 return True;
365
366         if(!prs_grow(dst, prs_offset(src)))
367                 return False;
368
369         memcpy(&dst->data_p[dst->data_offset], src->data_p, (size_t)prs_offset(src));
370         dst->data_offset += prs_offset(src);
371
372         return True;
373 }
374
375 /*******************************************************************
376  Append some data from one parse_struct into another.
377  ********************************************************************/
378
379 BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
380 {       
381         if (len == 0)
382                 return True;
383
384         if(!prs_grow(dst, len))
385                 return False;
386         
387         memcpy(&dst->data_p[dst->data_offset], src->data_p + start, (size_t)len);
388         dst->data_offset += len;
389
390         return True;
391 }
392
393 /*******************************************************************
394  Append the data from a buffer into a parse_struct.
395  ********************************************************************/
396
397 BOOL prs_copy_data_in(prs_struct *dst, char *src, uint32 len)
398 {
399         if (len == 0)
400                 return True;
401
402         if(!prs_grow(dst, len))
403                 return False;
404
405         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
406         dst->data_offset += len;
407
408         return True;
409 }
410
411 /*******************************************************************
412  Copy some data from a parse_struct into a buffer.
413  ********************************************************************/
414
415 BOOL prs_copy_data_out(char *dst, prs_struct *src, uint32 len)
416 {
417         if (len == 0)
418                 return True;
419
420         if(!prs_mem_get(src, len))
421                 return False;
422
423         memcpy(dst, &src->data_p[src->data_offset], (size_t)len);
424         src->data_offset += len;
425
426         return True;
427 }
428
429 /*******************************************************************
430  Copy all the data from a parse_struct into a buffer.
431  ********************************************************************/
432
433 BOOL prs_copy_all_data_out(char *dst, prs_struct *src)
434 {
435         uint32 len = prs_offset(src);
436
437         if (!len)
438                 return True;
439
440         prs_set_offset(src, 0);
441         return prs_copy_data_out(dst, src, len);
442 }
443
444 /*******************************************************************
445  Set the data as X-endian (external interface).
446  ********************************************************************/
447
448 void prs_set_endian_data(prs_struct *ps, BOOL endian)
449 {
450         ps->bigendian_data = endian;
451 }
452
453 /*******************************************************************
454  Align a the data_len to a multiple of align bytes - filling with
455  zeros.
456  ********************************************************************/
457
458 BOOL prs_align(prs_struct *ps)
459 {
460         uint32 mod = ps->data_offset & (ps->align-1);
461
462         if (ps->align != 0 && mod != 0) {
463                 uint32 extra_space = (ps->align - mod);
464                 if(!prs_grow(ps, extra_space))
465                         return False;
466                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
467                 ps->data_offset += extra_space;
468         }
469
470         return True;
471 }
472
473 /******************************************************************
474  Align on a 2 byte boundary
475  *****************************************************************/
476  
477 BOOL prs_align_uint16(prs_struct *ps)
478 {
479         BOOL ret;
480         uint8 old_align = ps->align;
481
482         ps->align = 2;
483         ret = prs_align(ps);
484         ps->align = old_align;
485         
486         return ret;
487 }
488
489 /******************************************************************
490  Align on a 8 byte boundary
491  *****************************************************************/
492  
493 BOOL prs_align_uint64(prs_struct *ps)
494 {
495         BOOL ret;
496         uint8 old_align = ps->align;
497
498         ps->align = 8;
499         ret = prs_align(ps);
500         ps->align = old_align;
501         
502         return ret;
503 }
504
505 /*******************************************************************
506  Align only if required (for the unistr2 string mainly)
507  ********************************************************************/
508
509 BOOL prs_align_needed(prs_struct *ps, uint32 needed)
510 {
511         if (needed==0)
512                 return True;
513         else
514                 return prs_align(ps);
515 }
516
517 /*******************************************************************
518  Ensure we can read/write to a given offset.
519  ********************************************************************/
520
521 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
522 {
523         if(UNMARSHALLING(ps)) {
524                 /*
525                  * If reading, ensure that we can read the requested size item.
526                  */
527                 if (ps->data_offset + extra_size > ps->buffer_size) {
528                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
529                                         (unsigned int)extra_size ));
530                         return NULL;
531                 }
532         } else {
533                 /*
534                  * Writing - grow the buffer if needed.
535                  */
536                 if(!prs_grow(ps, extra_size))
537                         return NULL;
538         }
539         return &ps->data_p[ps->data_offset];
540 }
541
542 /*******************************************************************
543  Change the struct type.
544  ********************************************************************/
545
546 void prs_switch_type(prs_struct *ps, BOOL io)
547 {
548         if ((ps->io ^ io) == True)
549                 ps->io=io;
550 }
551
552 /*******************************************************************
553  Force a prs_struct to be dynamic even when it's size is 0.
554  ********************************************************************/
555
556 void prs_force_dynamic(prs_struct *ps)
557 {
558         ps->is_dynamic=True;
559 }
560
561 /*******************************************************************
562  Stream a uint8.
563  ********************************************************************/
564
565 BOOL prs_uint8(const char *name, prs_struct *ps, int depth, uint8 *data8)
566 {
567         char *q = prs_mem_get(ps, 1);
568         if (q == NULL)
569                 return False;
570
571     if (UNMARSHALLING(ps))
572                 *data8 = CVAL(q,0);
573         else
574                 SCVAL(q,0,*data8);
575
576     DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
577
578         ps->data_offset += 1;
579
580         return True;
581 }
582
583 /*******************************************************************
584  Stream a uint16.
585  ********************************************************************/
586
587 BOOL prs_uint16(const char *name, prs_struct *ps, int depth, uint16 *data16)
588 {
589         char *q = prs_mem_get(ps, sizeof(uint16));
590         if (q == NULL)
591                 return False;
592
593     if (UNMARSHALLING(ps)) {
594                 if (ps->bigendian_data)
595                         *data16 = RSVAL(q,0);
596                 else
597                         *data16 = SVAL(q,0);
598     } else {
599                 if (ps->bigendian_data)
600                         RSSVAL(q,0,*data16);
601                 else
602                         SSVAL(q,0,*data16);
603         }
604
605         DEBUG(5,("%s%04x %s: %04x\n", tab_depth(depth), ps->data_offset, name, *data16));
606
607         ps->data_offset += sizeof(uint16);
608
609         return True;
610 }
611
612 /*******************************************************************
613  Stream a uint32.
614  ********************************************************************/
615
616 BOOL prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
617 {
618         char *q = prs_mem_get(ps, sizeof(uint32));
619         if (q == NULL)
620                 return False;
621
622         if (UNMARSHALLING(ps)) {
623                 if (ps->bigendian_data)
624                         *data32 = RIVAL(q,0);
625                 else
626                         *data32 = IVAL(q,0);
627         } else {
628                 if (ps->bigendian_data)
629                         RSIVAL(q,0,*data32);
630                 else
631                         SIVAL(q,0,*data32);
632         }
633
634         DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
635
636         ps->data_offset += sizeof(uint32);
637
638         return True;
639 }
640
641 /*******************************************************************
642  Stream a NTSTATUS
643  ********************************************************************/
644
645 BOOL prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
646 {
647         char *q = prs_mem_get(ps, sizeof(uint32));
648         if (q == NULL)
649                 return False;
650
651         if (UNMARSHALLING(ps)) {
652                 if (ps->bigendian_data)
653                         *status = NT_STATUS(RIVAL(q,0));
654                 else
655                         *status = NT_STATUS(IVAL(q,0));
656         } else {
657                 if (ps->bigendian_data)
658                         RSIVAL(q,0,NT_STATUS_V(*status));
659                 else
660                         SIVAL(q,0,NT_STATUS_V(*status));
661         }
662
663         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
664                  nt_errstr(*status)));
665
666         ps->data_offset += sizeof(uint32);
667
668         return True;
669 }
670
671 /*******************************************************************
672  Stream a WERROR
673  ********************************************************************/
674
675 BOOL prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
676 {
677         char *q = prs_mem_get(ps, sizeof(uint32));
678         if (q == NULL)
679                 return False;
680
681         if (UNMARSHALLING(ps)) {
682                 if (ps->bigendian_data)
683                         *status = W_ERROR(RIVAL(q,0));
684                 else
685                         *status = W_ERROR(IVAL(q,0));
686         } else {
687                 if (ps->bigendian_data)
688                         RSIVAL(q,0,W_ERROR_V(*status));
689                 else
690                         SIVAL(q,0,W_ERROR_V(*status));
691         }
692
693         DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
694                  dos_errstr(*status)));
695
696         ps->data_offset += sizeof(uint32);
697
698         return True;
699 }
700
701
702 /******************************************************************
703  Stream an array of uint8s. Length is number of uint8s.
704  ********************************************************************/
705
706 BOOL prs_uint8s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
707 {
708         int i;
709         char *q = prs_mem_get(ps, len);
710         if (q == NULL)
711                 return False;
712
713         if (UNMARSHALLING(ps)) {
714                 for (i = 0; i < len; i++)
715                         data8s[i] = CVAL(q,i);
716         } else {
717                 for (i = 0; i < len; i++)
718                         SCVAL(q, i, data8s[i]);
719         }
720
721     DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
722     if (charmode)
723                 print_asc(5, (unsigned char*)data8s, len);
724         else {
725         for (i = 0; i < len; i++)
726                         DEBUG(5,("%02x ", data8s[i]));
727         }
728     DEBUG(5,("\n"));
729
730         ps->data_offset += len;
731
732         return True;
733 }
734
735 /******************************************************************
736  Stream an array of uint16s. Length is number of uint16s.
737  ********************************************************************/
738
739 BOOL prs_uint16s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
740 {
741         int i;
742         char *q = prs_mem_get(ps, len * sizeof(uint16));
743         if (q == NULL)
744                 return False;
745
746         if (UNMARSHALLING(ps)) {
747                 if (ps->bigendian_data) {
748                         for (i = 0; i < len; i++)
749                                 data16s[i] = RSVAL(q, 2*i);
750                 } else {
751                         for (i = 0; i < len; i++)
752                                 data16s[i] = SVAL(q, 2*i);
753                 }
754         } else {
755                 if (ps->bigendian_data) {
756                         for (i = 0; i < len; i++)
757                                 RSSVAL(q, 2*i, data16s[i]);
758                 } else {
759                         for (i = 0; i < len; i++)
760                                 SSVAL(q, 2*i, data16s[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*)data16s, 2*len);
767         else {
768                 for (i = 0; i < len; i++)
769                         DEBUG(5,("%04x ", data16s[i]));
770         }
771     DEBUG(5,("\n"));
772
773         ps->data_offset += (len * sizeof(uint16));
774
775         return True;
776 }
777
778 /******************************************************************
779  Start using a function for streaming unicode chars. If unmarshalling,
780  output must be little-endian, if marshalling, input must be little-endian.
781  ********************************************************************/
782
783 static void dbg_rw_punival(BOOL charmode, const char *name, int depth, prs_struct *ps,
784                                                         char *in_buf, char *out_buf, int len)
785 {
786         int i;
787
788         if (UNMARSHALLING(ps)) {
789                 if (ps->bigendian_data) {
790                         for (i = 0; i < len; i++)
791                                 SSVAL(out_buf,2*i,RSVAL(in_buf, 2*i));
792                 } else {
793                         for (i = 0; i < len; i++)
794                                 SSVAL(out_buf, 2*i, SVAL(in_buf, 2*i));
795                 }
796         } else {
797                 if (ps->bigendian_data) {
798                         for (i = 0; i < len; i++)
799                                 RSSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
800                 } else {
801                         for (i = 0; i < len; i++)
802                                 SSVAL(in_buf, 2*i, SVAL(out_buf,2*i));
803                 }
804         }
805
806         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
807         if (charmode)
808                 print_asc(5, (unsigned char*)out_buf, 2*len);
809         else {
810                 for (i = 0; i < len; i++)
811                         DEBUG(5,("%04x ", out_buf[i]));
812         }
813     DEBUG(5,("\n"));
814 }
815
816 /******************************************************************
817  Stream a unistr. Always little endian.
818  ********************************************************************/
819
820 BOOL prs_uint16uni(BOOL charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
821 {
822         char *q = prs_mem_get(ps, len * sizeof(uint16));
823         if (q == NULL)
824                 return False;
825
826         dbg_rw_punival(charmode, name, depth, ps, q, (char *)data16s, len);
827         ps->data_offset += (len * sizeof(uint16));
828
829         return True;
830 }
831
832 /******************************************************************
833  Stream an array of uint32s. Length is number of uint32s.
834  ********************************************************************/
835
836 BOOL prs_uint32s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
837 {
838         int i;
839         char *q = prs_mem_get(ps, len * sizeof(uint32));
840         if (q == NULL)
841                 return False;
842
843         if (UNMARSHALLING(ps)) {
844                 if (ps->bigendian_data) {
845                         for (i = 0; i < len; i++)
846                                 data32s[i] = RIVAL(q, 4*i);
847                 } else {
848                         for (i = 0; i < len; i++)
849                                 data32s[i] = IVAL(q, 4*i);
850                 }
851         } else {
852                 if (ps->bigendian_data) {
853                         for (i = 0; i < len; i++)
854                                 RSIVAL(q, 4*i, data32s[i]);
855                 } else {
856                         for (i = 0; i < len; i++)
857                                 SIVAL(q, 4*i, data32s[i]);
858                 }
859         }
860
861         DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
862         if (charmode)
863                 print_asc(5, (unsigned char*)data32s, 4*len);
864         else {
865                 for (i = 0; i < len; i++)
866                         DEBUG(5,("%08x ", data32s[i]));
867         }
868     DEBUG(5,("\n"));
869
870         ps->data_offset += (len * sizeof(uint32));
871
872         return True;
873 }
874
875 /******************************************************************
876  Stream an array of unicode string, length/buffer specified separately,
877  in uint16 chars. The unicode string is already in little-endian format.
878  ********************************************************************/
879
880 BOOL prs_buffer5(BOOL charmode, const char *name, prs_struct *ps, int depth, BUFFER5 *str)
881 {
882         char *p;
883         char *q = prs_mem_get(ps, str->buf_len * sizeof(uint16));
884         if (q == NULL)
885                 return False;
886
887         if (UNMARSHALLING(ps)) {
888                 str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len * sizeof(uint16));
889                 if (str->buffer == NULL)
890                         return False;
891         }
892
893         /* If the string is empty, we don't have anything to stream */
894         if (str->buf_len==0)
895                 return True;
896
897         p = (char *)str->buffer;
898
899         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
900         
901         ps->data_offset += (str->buf_len * sizeof(uint16));
902
903         return True;
904 }
905
906 /******************************************************************
907  Stream a "not" unicode string, length/buffer specified separately,
908  in byte chars. String is in little-endian format.
909  ********************************************************************/
910
911 BOOL prs_buffer2(BOOL charmode, const char *name, prs_struct *ps, int depth, BUFFER2 *str)
912 {
913         char *p;
914         char *q = prs_mem_get(ps, str->buf_len);
915         if (q == NULL)
916                 return False;
917
918         if (UNMARSHALLING(ps)) {
919                 if ( str->buf_len ) {
920                         str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len);
921                         if ( str->buffer == NULL )
922                                 return False;
923                 }
924         }
925
926         p = (char *)str->buffer;
927
928         dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len/2);
929         ps->data_offset += str->buf_len;
930
931         return True;
932 }
933
934 /******************************************************************
935  Stream a string, length/buffer specified separately,
936  in uint8 chars.
937  ********************************************************************/
938
939 BOOL prs_string2(BOOL charmode, const char *name, prs_struct *ps, int depth, STRING2 *str)
940 {
941         unsigned int i;
942         char *q = prs_mem_get(ps, str->str_max_len);
943         if (q == NULL)
944                 return False;
945
946         if (UNMARSHALLING(ps)) {
947                 str->buffer = (unsigned char *)prs_alloc_mem(ps,str->str_max_len);
948                 if (str->buffer == NULL)
949                         return False;
950         }
951
952         if (UNMARSHALLING(ps)) {
953                 for (i = 0; i < str->str_str_len; i++)
954                         str->buffer[i] = CVAL(q,i);
955         } else {
956                 for (i = 0; i < str->str_str_len; i++)
957                         SCVAL(q, i, str->buffer[i]);
958         }
959
960     DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
961     if (charmode)
962                 print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
963         else {
964         for (i = 0; i < str->str_str_len; i++)
965                         DEBUG(5,("%02x ", str->buffer[i]));
966         }
967     DEBUG(5,("\n"));
968
969         ps->data_offset += str->str_str_len;
970
971         return True;
972 }
973
974 /******************************************************************
975  Stream a unicode string, length/buffer specified separately,
976  in uint16 chars. The unicode string is already in little-endian format.
977  ********************************************************************/
978
979 BOOL prs_unistr2(BOOL charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str)
980 {
981         char *p;
982         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
983         if (q == NULL)
984                 return False;
985
986         /* If the string is empty, we don't have anything to stream */
987         if (str->uni_str_len==0)
988                 return True;
989
990         if (UNMARSHALLING(ps)) {
991                 str->buffer = (uint16 *)prs_alloc_mem(ps,str->uni_max_len * sizeof(uint16));
992                 if (str->buffer == NULL)
993                         return False;
994         }
995
996         p = (char *)str->buffer;
997
998         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
999         
1000         ps->data_offset += (str->uni_str_len * sizeof(uint16));
1001
1002         return True;
1003 }
1004
1005 /******************************************************************
1006  Stream a unicode string, length/buffer specified separately,
1007  in uint16 chars. The unicode string is already in little-endian format.
1008  ********************************************************************/
1009
1010 BOOL prs_unistr3(BOOL charmode, const char *name, UNISTR3 *str, prs_struct *ps, int depth)
1011 {
1012         char *p;
1013         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
1014         if (q == NULL)
1015                 return False;
1016
1017         if (UNMARSHALLING(ps)) {
1018                 str->str.buffer = (uint16 *)prs_alloc_mem(ps,str->uni_str_len * sizeof(uint16));
1019                 if (str->str.buffer == NULL)
1020                         return False;
1021         }
1022
1023         p = (char *)str->str.buffer;
1024
1025         dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len);
1026         ps->data_offset += (str->uni_str_len * sizeof(uint16));
1027
1028         return True;
1029 }
1030
1031 /*******************************************************************
1032  Stream a unicode  null-terminated string. As the string is already
1033  in little-endian format then do it as a stream of bytes.
1034  ********************************************************************/
1035
1036 BOOL prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str)
1037 {
1038         unsigned int len = 0;
1039         unsigned char *p = (unsigned char *)str->buffer;
1040         uint8 *start;
1041         char *q;
1042         uint32 max_len;
1043         uint16* ptr;
1044
1045         if (MARSHALLING(ps)) {
1046
1047                 for(len = 0; str->buffer[len] != 0; len++)
1048                         ;
1049
1050                 q = prs_mem_get(ps, (len+1)*2);
1051                 if (q == NULL)
1052                         return False;
1053
1054                 start = (uint8*)q;
1055
1056                 for(len = 0; str->buffer[len] != 0; len++) 
1057                 {
1058                         if(ps->bigendian_data) 
1059                         {
1060                                 /* swap bytes - p is little endian, q is big endian. */
1061                                 q[0] = (char)p[1];
1062                                 q[1] = (char)p[0];
1063                                 p += 2;
1064                                 q += 2;
1065                         } 
1066                         else 
1067                         {
1068                                 q[0] = (char)p[0];
1069                                 q[1] = (char)p[1];
1070                                 p += 2;
1071                                 q += 2;
1072                         }
1073                 }
1074
1075                 /*
1076                  * even if the string is 'empty' (only an \0 char)
1077                  * at this point the leading \0 hasn't been parsed.
1078                  * so parse it now
1079                  */
1080
1081                 q[0] = 0;
1082                 q[1] = 0;
1083                 q += 2;
1084
1085                 len++;
1086
1087                 DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
1088                 print_asc(5, (unsigned char*)start, 2*len);     
1089                 DEBUG(5, ("\n"));
1090         }
1091         else { /* unmarshalling */
1092         
1093                 uint32 alloc_len = 0;
1094                 q = ps->data_p + prs_offset(ps);
1095
1096                 /*
1097                  * Work out how much space we need and talloc it.
1098                  */
1099                 max_len = (ps->buffer_size - ps->data_offset)/sizeof(uint16);
1100
1101                 /* the test of the value of *ptr helps to catch the circumstance
1102                    where we have an emtpty (non-existent) string in the buffer */
1103                 for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++)
1104                         /* do nothing */ 
1105                         ;
1106
1107                 /* should we allocate anything at all? */
1108                 str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16));
1109                 if ((str->buffer == NULL) && (alloc_len > 0))
1110                         return False;
1111
1112                 p = (unsigned char *)str->buffer;
1113
1114                 len = 0;
1115                 /* the (len < alloc_len) test is to prevent us from overwriting
1116                    memory that is not ours...if we get that far, we have a non-null
1117                    terminated string in the buffer and have messed up somewhere */
1118                 while ((len < alloc_len) && (*(uint16 *)q != 0))
1119                 {
1120                         if(ps->bigendian_data) 
1121                         {
1122                                 /* swap bytes - q is big endian, p is little endian. */
1123                                 p[0] = (unsigned char)q[1];
1124                                 p[1] = (unsigned char)q[0];
1125                                 p += 2;
1126                                 q += 2;
1127                         } else {
1128
1129                                 p[0] = (unsigned char)q[0];
1130                                 p[1] = (unsigned char)q[1];
1131                                 p += 2;
1132                                 q += 2;
1133                         }
1134
1135                         len++;
1136                 } 
1137                 if (len < alloc_len)
1138                 {
1139                         /* NULL terminate the UNISTR */
1140                         str->buffer[len++] = '\0';
1141                 }
1142
1143                 DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
1144                 print_asc(5, (unsigned char*)str->buffer, 2*len);       
1145                 DEBUG(5, ("\n"));
1146         }
1147
1148         /* set the offset in the prs_struct; 'len' points to the
1149            terminiating NULL in the UNISTR so we need to go one more
1150            uint16 */
1151         ps->data_offset += (len)*2;
1152         
1153         return True;
1154 }
1155
1156
1157 /*******************************************************************
1158  Stream a null-terminated string.  len is strlen, and therefore does
1159  not include the null-termination character.
1160  ********************************************************************/
1161
1162 BOOL prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size)
1163 {
1164         char *q;
1165         int i;
1166         int len;
1167
1168         if (UNMARSHALLING(ps))
1169                 len = strlen(&ps->data_p[ps->data_offset]);
1170         else
1171                 len = strlen(str);
1172
1173         len = MIN(len, (max_buf_size-1));
1174
1175         q = prs_mem_get(ps, len+1);
1176         if (q == NULL)
1177                 return False;
1178
1179         for(i = 0; i < len; i++) {
1180                 if (UNMARSHALLING(ps))
1181                         str[i] = q[i];
1182                 else
1183                         q[i] = str[i];
1184         }
1185
1186         /* The terminating null. */
1187         str[i] = '\0';
1188
1189         if (MARSHALLING(ps)) {
1190                 q[i] = '\0';
1191         }
1192
1193         ps->data_offset += len+1;
1194
1195         dump_data(5+depth, q, len);
1196
1197         return True;
1198 }
1199
1200 /*******************************************************************
1201  prs_uint16 wrapper. Call this and it sets up a pointer to where the
1202  uint16 should be stored, or gets the size if reading.
1203  ********************************************************************/
1204
1205 BOOL prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
1206 {
1207         *offset = ps->data_offset;
1208         if (UNMARSHALLING(ps)) {
1209                 /* reading. */
1210                 return prs_uint16(name, ps, depth, data16);
1211         } else {
1212                 char *q = prs_mem_get(ps, sizeof(uint16));
1213                 if(q ==NULL)
1214                         return False;
1215                 ps->data_offset += sizeof(uint16);
1216         }
1217         return True;
1218 }
1219
1220 /*******************************************************************
1221  prs_uint16 wrapper.  call this and it retrospectively stores the size.
1222  does nothing on reading, as that is already handled by ...._pre()
1223  ********************************************************************/
1224
1225 BOOL prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16,
1226                                 uint32 ptr_uint16, uint32 start_offset)
1227 {
1228         if (MARSHALLING(ps)) {
1229                 /* 
1230                  * Writing - temporarily move the offset pointer.
1231                  */
1232                 uint16 data_size = ps->data_offset - start_offset;
1233                 uint32 old_offset = ps->data_offset;
1234
1235                 ps->data_offset = ptr_uint16;
1236                 if(!prs_uint16(name, ps, depth, &data_size)) {
1237                         ps->data_offset = old_offset;
1238                         return False;
1239                 }
1240                 ps->data_offset = old_offset;
1241         } else {
1242                 ps->data_offset = start_offset + (uint32)(*data16);
1243         }
1244         return True;
1245 }
1246
1247 /*******************************************************************
1248  prs_uint32 wrapper. Call this and it sets up a pointer to where the
1249  uint32 should be stored, or gets the size if reading.
1250  ********************************************************************/
1251
1252 BOOL prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
1253 {
1254         *offset = ps->data_offset;
1255         if (UNMARSHALLING(ps) && (data32 != NULL)) {
1256                 /* reading. */
1257                 return prs_uint32(name, ps, depth, data32);
1258         } else {
1259                 ps->data_offset += sizeof(uint32);
1260         }
1261         return True;
1262 }
1263
1264 /*******************************************************************
1265  prs_uint32 wrapper.  call this and it retrospectively stores the size.
1266  does nothing on reading, as that is already handled by ...._pre()
1267  ********************************************************************/
1268
1269 BOOL prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32,
1270                                 uint32 ptr_uint32, uint32 data_size)
1271 {
1272         if (MARSHALLING(ps)) {
1273                 /* 
1274                  * Writing - temporarily move the offset pointer.
1275                  */
1276                 uint32 old_offset = ps->data_offset;
1277                 ps->data_offset = ptr_uint32;
1278                 if(!prs_uint32(name, ps, depth, &data_size)) {
1279                         ps->data_offset = old_offset;
1280                         return False;
1281                 }
1282                 ps->data_offset = old_offset;
1283         }
1284         return True;
1285 }
1286
1287 /* useful function to store a structure in rpc wire format */
1288 int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
1289 {
1290     TDB_DATA kbuf, dbuf;
1291     kbuf.dptr = keystr;
1292     kbuf.dsize = strlen(keystr)+1;
1293     dbuf.dptr = ps->data_p;
1294     dbuf.dsize = prs_offset(ps);
1295     return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
1296 }
1297
1298 /* useful function to fetch a structure into rpc wire format */
1299 int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx)
1300 {
1301     TDB_DATA kbuf, dbuf;
1302     kbuf.dptr = keystr;
1303     kbuf.dsize = strlen(keystr)+1;
1304
1305     dbuf = tdb_fetch(tdb, kbuf);
1306     if (!dbuf.dptr)
1307             return -1;
1308
1309     ZERO_STRUCTP(ps);
1310     prs_init(ps, 0, mem_ctx, UNMARSHALL);
1311     prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
1312
1313     return 0;
1314
1315
1316 /*******************************************************************
1317  hash a stream.
1318  ********************************************************************/
1319 BOOL prs_hash1(prs_struct *ps, uint32 offset, uint8 sess_key[16], int len)
1320 {
1321         char *q;
1322
1323         q = ps->data_p;
1324         q = &q[offset];
1325
1326 #ifdef DEBUG_PASSWORD
1327         DEBUG(100, ("prs_hash1\n"));
1328         dump_data(100, sess_key, 16);
1329         dump_data(100, q, len);
1330 #endif
1331         SamOEMhash((uchar *) q, sess_key, len);
1332
1333 #ifdef DEBUG_PASSWORD
1334         dump_data(100, q, len);
1335 #endif
1336
1337         return True;
1338 }
1339
1340 static void netsechash(uchar * key, uchar * data, int data_len)
1341 {
1342         uchar hash[256];
1343         uchar index_i = 0;
1344         uchar index_j = 0;
1345         uchar j = 0;
1346         int ind;
1347
1348         for (ind = 0; ind < 256; ind++)
1349         {
1350                 hash[ind] = (uchar) ind;
1351         }
1352
1353         for (ind = 0; ind < 256; ind++)
1354         {
1355                 uchar tc;
1356
1357                 j += (hash[ind] + key[ind % 16]);
1358
1359                 tc = hash[ind];
1360                 hash[ind] = hash[j];
1361                 hash[j] = tc;
1362         }
1363
1364         for (ind = 0; ind < data_len; ind++)
1365         {
1366                 uchar tc;
1367                 uchar t;
1368
1369                 index_i++;
1370                 index_j += hash[index_i];
1371
1372                 tc = hash[index_i];
1373                 hash[index_i] = hash[index_j];
1374                 hash[index_j] = tc;
1375
1376                 t = hash[index_i] + hash[index_j];
1377                 data[ind] ^= hash[t];
1378         }
1379 }
1380
1381
1382 /*******************************************************************
1383  Create a digest over the entire packet (including the data), and 
1384  MD5 it with the session key.
1385  ********************************************************************/
1386 static void netsec_digest(struct netsec_auth_struct *a,
1387                           int auth_flags,
1388                           RPC_AUTH_NETSEC_CHK * verf,
1389                           char *data, size_t data_len,
1390                           uchar digest_final[16]) 
1391 {
1392         uchar whole_packet_digest[16];
1393         static uchar zeros[4];
1394         struct MD5Context ctx3;
1395         
1396         /* verfiy the signature on the packet by MD5 over various bits */
1397         MD5Init(&ctx3);
1398         /* use our sequence number, which ensures the packet is not
1399            out of order */
1400         MD5Update(&ctx3, zeros, sizeof(zeros));
1401         MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
1402         if (auth_flags & AUTH_PIPE_SEAL) {
1403                 MD5Update(&ctx3, verf->data8, sizeof(verf->data8));
1404         }
1405         MD5Update(&ctx3, data, data_len);
1406         MD5Final(whole_packet_digest, &ctx3);
1407         dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
1408         
1409         /* MD5 this result and the session key, to prove that
1410            only a valid client could had produced this */
1411         hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);
1412 }
1413
1414 /*******************************************************************
1415  Calculate the key with which to encode the data payload 
1416  ********************************************************************/
1417 static void netsec_get_sealing_key(struct netsec_auth_struct *a,
1418                                    RPC_AUTH_NETSEC_CHK *verf,
1419                                    uchar sealing_key[16]) 
1420 {
1421         static uchar zeros[4];
1422         uchar digest2[16];
1423         uchar sess_kf0[16];
1424         int i;
1425
1426         for (i = 0; i < sizeof(sess_kf0); i++) {
1427                 sess_kf0[i] = a->sess_key[i] ^ 0xf0;
1428         }
1429         
1430         dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
1431         
1432         /* MD5 of sess_kf0 and the high bytes of the sequence number */
1433         hmac_md5(sess_kf0, zeros, 0x4, digest2);
1434         dump_data_pw("digest2:\n", digest2, sizeof(digest2));
1435         
1436         /* MD5 of the above result, plus 8 bytes of sequence number */
1437         hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key);
1438         dump_data_pw("sealing_key:\n", sealing_key, 16);
1439 }
1440
1441 /*******************************************************************
1442  Encode or Decode the sequence number (which is symmetric)
1443  ********************************************************************/
1444 static void netsec_deal_with_seq_num(struct netsec_auth_struct *a,
1445                                      RPC_AUTH_NETSEC_CHK *verf)
1446 {
1447         static uchar zeros[4];
1448         uchar sequence_key[16];
1449         uchar digest1[16];
1450
1451         hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1);
1452         dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1));
1453
1454         hmac_md5(digest1, verf->packet_digest, 8, sequence_key);
1455
1456         dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
1457
1458         dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
1459         netsechash(sequence_key, verf->seq_num, 8);
1460         dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
1461 }
1462
1463
1464 /*******************************************************************
1465  Encode a blob of data using the netsec (schannel) alogrithm, also produceing
1466  a checksum over the original data.  We currently only support
1467  signing and sealing togeather - the signing-only code is close, but not
1468  quite compatible with what MS does.
1469  ********************************************************************/
1470 void netsec_encode(struct netsec_auth_struct *a, int auth_flags, 
1471                    enum netsec_direction direction,
1472                    RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
1473 {
1474         uchar digest_final[16];
1475
1476         DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%l\n", a->seq_num, data_len));
1477         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
1478
1479         RSIVAL(verf->seq_num, 0, a->seq_num);
1480
1481         switch (direction) {
1482         case SENDER_IS_INITIATOR:
1483                 SIVAL(verf->seq_num, 4, 0x80);
1484                 break;
1485         case SENDER_IS_ACCEPTOR:
1486                 SIVAL(verf->seq_num, 4, 0x0);
1487                 break;
1488         }
1489
1490         dump_data_pw("verf->seq_num:\n", verf->seq_num, sizeof(verf->seq_num));
1491
1492         /* produce a digest of the packet to prove it's legit (before we seal it) */
1493         netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
1494         memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
1495
1496         if (auth_flags & AUTH_PIPE_SEAL) {
1497                 uchar sealing_key[16];
1498
1499                 /* get the key to encode the data with */
1500                 netsec_get_sealing_key(a, verf, sealing_key);
1501
1502                 /* encode the verification data */
1503                 dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
1504                 netsechash(sealing_key, verf->data8, 8);
1505
1506                 dump_data_pw("verf->data8_enc:\n", verf->data8, sizeof(verf->data8));
1507                 
1508                 /* encode the packet payload */
1509                 dump_data_pw("data:\n", data, data_len);
1510                 netsechash(sealing_key, data, data_len);
1511                 dump_data_pw("data_enc:\n", data, data_len);
1512         }
1513
1514         /* encode the sequence number (key based on packet digest) */
1515         /* needs to be done after the sealing, as the original version 
1516            is used in the sealing stuff... */
1517         netsec_deal_with_seq_num(a, verf);
1518
1519         return;
1520 }
1521
1522 /*******************************************************************
1523  Decode a blob of data using the netsec (schannel) alogrithm, also verifiying
1524  a checksum over the original data.  We currently can verify signed messages,
1525  as well as decode sealed messages
1526  ********************************************************************/
1527
1528 BOOL netsec_decode(struct netsec_auth_struct *a, int auth_flags,
1529                    enum netsec_direction direction, 
1530                    RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
1531 {
1532         uchar digest_final[16];
1533
1534         /* Create the expected sequence number for comparison */
1535         uchar seq_num[8];
1536         RSIVAL(seq_num, 0, a->seq_num);
1537
1538         switch (direction) {
1539         case SENDER_IS_INITIATOR:
1540                 SIVAL(seq_num, 4, 0x80);
1541                 break;
1542         case SENDER_IS_ACCEPTOR:
1543                 SIVAL(seq_num, 4, 0x0);
1544                 break;
1545         }
1546
1547         DEBUG(10,("SCHANNEL: netsec_decode seq_num=%d data_len=%l\n", a->seq_num, data_len));
1548         dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
1549
1550         dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
1551
1552         /* extract the sequence number (key based on supplied packet digest) */
1553         /* needs to be done before the sealing, as the original version 
1554            is used in the sealing stuff... */
1555         netsec_deal_with_seq_num(a, verf);
1556
1557         if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
1558                 /* don't even bother with the below if the sequence number is out */
1559                 /* The sequence number is MD5'ed with a key based on the whole-packet
1560                    digest, as supplied by the client.  We check that it's a valid 
1561                    checksum after the decode, below
1562                 */
1563                 return False;
1564         }
1565
1566         if (auth_flags & AUTH_PIPE_SEAL) {
1567                 uchar sealing_key[16];
1568                 
1569                 /* get the key to extract the data with */
1570                 netsec_get_sealing_key(a, verf, sealing_key);
1571
1572                 /* extract the verification data */
1573                 dump_data_pw("verf->data8:\n", verf->data8, 
1574                              sizeof(verf->data8));
1575                 netsechash(sealing_key, verf->data8, 8);
1576
1577                 dump_data_pw("verf->data8_dec:\n", verf->data8, 
1578                              sizeof(verf->data8));
1579                 
1580                 /* extract the packet payload */
1581                 dump_data_pw("data   :\n", data, data_len);
1582                 netsechash(sealing_key, data, data_len);
1583                 dump_data_pw("datadec:\n", data, data_len);     
1584         }
1585
1586         /* digest includes 'data' after unsealing */
1587         netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
1588
1589         dump_data_pw("Calculated digest:\n", digest_final, 
1590                      sizeof(digest_final));
1591         dump_data_pw("verf->packet_digest:\n", verf->packet_digest, 
1592                      sizeof(verf->packet_digest));
1593         
1594         /* compare - if the client got the same result as us, then
1595            it must know the session key */
1596         return (memcmp(digest_final, verf->packet_digest, 
1597                        sizeof(verf->packet_digest)) == 0);
1598 }