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