
/* 
 *  Copyright Luke Kenneth Casson Leighton 1997  Paul Ashton 1997.
 *
 *  This file is freely distributable with absolutely no warranty
 *  as to its fitness for purpose or otherwise.  Please have your
 *  lawyers _not_ contact the authors regarding this file.  Thank you.
 *
 *  Copyright acknowledgment is hereby explicity requested, even in
 *  the United States.
 *
 *  This file contains SMB packet parsing routines for structures described in
 *  http://mailhost.cb1.com/~lkcl/cifsntdomain.txt v0.001, section 2.2.
 */

#include "smbparse.h"

/* some macros and functions not listed here:
   RW_XXXX;
   align_offset;
   unistrcpy.
 */


/*******************************************************************
reads or writes an NTTIME structure.
********************************************************************/
char* smb_io_time(BOOL io, NTTIME *nttime, char *q, char *base, int align)
{
	if (nttime == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, nttime->low , 0); q += 4; /* low part */
	RW_IVAL(io, q, nttime->high, 0); q += 4; /* high part */

	return q;
}

/*******************************************************************
reads or writes a DOM_SID structure.
********************************************************************/
char* smb_io_sid(BOOL io, DOM_SID *sid, char *q, char *base, int align)
{
	int i;

	if (sid == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_CVAL(io, q, sid->sid_no, 0); q++; 
	RW_CVAL(io, q, sid->num_auths, 0); q++;

	for (i = 0; i < 6; i++)
	{
		RW_CVAL(io, q, sid->id_auth[i], 0); q++;
	}

	/* oops! XXXX should really issue a warning here... */
	if (sid->num_auths > MAXSUBAUTHS) sid->num_auths = MAXSUBAUTHS;

	RW_PSVAL(io, q, sid->sub_auths, sid->num_auths); q += sid->num_auths * 2;

	return q;
}

/*******************************************************************
reads or writes a UNIHDR structure.
********************************************************************/
char* smb_io_unihdr(BOOL io, UNIHDR *hdr, char *q, char *base, int align)
{
	if (hdr == NULL) return NULL;

	/* should be value 4, so enforce it. */
	hdr->undoc = 4;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, hdr->uni_max_len, 0); q += 4;
	RW_IVAL(io, q, hdr->uni_str_len, 0); q += 4;
	RW_IVAL(io, q, hdr->undoc      , 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes a UNIHDR2 structure.
********************************************************************/
char* smb_io_unihdr2(BOOL io, UNIHDR2 *hdr2, char *q, char *base, int align)
{
	if (hdr2 == NULL) return NULL;

	q = align_offset(q, base, align);

	q = smb_io_unihdr(io, &(hdr2->unihdr), q, base, align);
	RW_IVAL(io, q, hdr2->undoc_buffer, 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes a UNISTR structure.
XXXX NOTE: UNISTR structures NEED to be null-terminated.
********************************************************************/
char* smb_io_unistr(BOOL io, UNISTR *uni, char *q, char *base, int align)
{
	if (uni == NULL) return NULL;

	q = align_offset(q, base, align);
	
	if (io)
	{
		/* io True indicates read _from_ the SMB buffer into the string */
		q += 2 * unistrcpy((char*)uni->buffer, q);
	}
	else
	{
		/* io True indicates copy _from_ the string into SMB buffer */
		q += 2 * unistrcpy(q, (char*)uni->buffer);
	}
	return q;
}

/*******************************************************************
reads or writes a UNISTR2 structure.
XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
     the uni_str_len member tells you how long the string is;
     the uni_max_len member tells you how large the buffer is.
********************************************************************/
char* smb_io_unistr2(BOOL io, UNISTR2 *uni2, char *q, char *base, int align)
{
	if (uni2 == NULL) return NULL;

	q = align_offset(q, base, align);
	
	/* should be value 0, so enforce it. */
	uni2->undoc = 0;

	RW_IVAL(io, q, uni2->uni_max_len, 0); q += 4;
	RW_IVAL(io, q, uni2->undoc      , 0); q += 4;
	RW_IVAL(io, q, uni2->uni_str_len, 0); q += 4;

	/* oops! XXXX maybe issue a warning that this is happening... */
	if (uni2->uni_max_len > MAX_UNISTRLEN) uni2->uni_max_len = MAX_UNISTRLEN;
	if (uni2->uni_str_len > MAX_UNISTRLEN) uni2->uni_str_len = MAX_UNISTRLEN;

	/* buffer advanced by indicated length of string
       NOT by searching for null-termination */
	RW_PSVAL(io, q, uni2->buffer, uni2->uni_max_len); q += uni2->uni_max_len * 2;

	return q;
}

/*******************************************************************
reads or writes a DOM_SID2 structure.
********************************************************************/
char* smb_io_dom_sid2(BOOL io, DOM_SID2 *sid2, char *q, char *base, int align)
{
	if (sid2 == NULL) return NULL;

	q = align_offset(q, base, align);
	
	/* should be value 5, so enforce it */
	sid2->type = 5;

	/* should be value 0, so enforce it */
	sid2->undoc = 0;

	RW_IVAL(io, q, sid2->type , 0); q += 4;
	RW_IVAL(io, q, sid2->undoc, 0); q += 4;

	q = smb_io_unihdr2(io, &(sid2->hdr), q, base, align);
	q = smb_io_unistr (io, &(sid2->str), q, base, align);

	return q;
}

/*******************************************************************
reads or writes a DOM_RID2 structure.
********************************************************************/
char* smb_io_dom_rid2(BOOL io, DOM_RID2 *rid2, char *q, char *base, int align)
{
	if (rid2 == NULL) return NULL;

	q = align_offset(q, base, align);
	
	/* should be value 5, so enforce it */
	rid2->type = 5;

	/* should be value 5, so enforce it */
	rid2->undoc = 5;

	RW_IVAL(io, q, rid2->type, 0); q += 4;
	RW_IVAL(io, q, rid2->undoc   , 0); q += 4;
	RW_IVAL(io, q, rid2->rid     , 0); q += 4;
	RW_IVAL(io, q, rid2->rid_idx , 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes a DOM_LOG_INFO structure.
********************************************************************/
char* smb_io_log_info(BOOL io, DOM_LOG_INFO *log, char *q, char *base, int align)
{
	if (log == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, log->undoc_buffer, 0); q += 4;

	q = smb_io_unistr2(io, &(log->uni_logon_srv), q, base, align);
	q = smb_io_unistr2(io, &(log->uni_acct_name), q, base, align);

	RW_SVAL(io, q, log->sec_chan, 0); q += 2;

	/* XXXX no alignment required between sec_chan and uni_comp_name */
	q = smb_io_unistr2(io, &(log->uni_comp_name), q, base, 0);

	return q;
}

/*******************************************************************
reads or writes a DOM_CRED structure.
********************************************************************/
char* smb_io_cred(BOOL io, DOM_CRED *cred, char *q, char *base, int align)
{
	if (cred == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_PCVAL(io, q, cred->data, 8); q += 8;
	RW_IVAL (io, q, cred->timestamp, 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes a DOM_CLNT_INFO structure.
********************************************************************/
char* smb_io_clnt_info(BOOL io, DOM_CLNT_INFO *clnt, char *q, char *base, int align)
{
	if (clnt == NULL) return NULL;

	q = align_offset(q, base, align);
	
	q = smb_io_log_info(io, &(clnt->login), q, base, align);
	q = smb_io_cred    (io, &(clnt->cred ), q, base, align);

	return q;
}

/*******************************************************************
reads or writes a DOM_LOGON_ID structure.
********************************************************************/
char* smb_io_logon_id(BOOL io, DOM_LOGON_ID *log, char *q, char *base, int align)
{
	if (log == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, log->low , 0); q += 4;
	RW_IVAL(io, q, log->high, 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes an RC4_OWF structure.
********************************************************************/
char* smb_io_rc4_owf(BOOL io, RC4_OWF *hash, char *q, char *base, int align)
{
	if (hash == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_PCVAL(io, q, hash->data, 16); q += 16;

	return q;
}

/*******************************************************************
reads or writes an DOM_ID_INFO_1 structure.
********************************************************************/
char* smb_io_id_info1(BOOL io, DOM_ID_INFO_1 *id, char *q, char *base, int align)
{
	if (id == NULL) return NULL;

	q = align_offset(q, base, align);
	
	q = smb_io_unihdr(io, &(id->hdr_domain_name   ), q, base, align);

	RW_IVAL(io, q, id->param, 0); q += 4;
	q = smb_io_logon_id(io, &(id->logon_id), q, base, align);

	q = smb_io_unihdr(io, &(id->hdr_user_name     ), q, base, align);
	q = smb_io_unihdr(io, &(id->hdr_workgroup_name), q, base, align);

	q = smb_io_rc4_owf(io, &(id->rc4_lm_owf), q, base, align);
	q = smb_io_rc4_owf(io, &(id->rc4_nt_owf), q, base, align);

	q = smb_io_unistr2(io, &(id->uni_domain_name   ), q, base, align);
	q = smb_io_unistr2(io, &(id->uni_user_name     ), q, base, align);
	q = smb_io_unistr2(io, &(id->uni_workgroup_name), q, base, align);

	return q;
}

/*******************************************************************
reads or writes a DOM_SAM_INFO structure.
********************************************************************/
char* smb_io_sam_info(BOOL io, DOM_SAM_INFO *sam, char *q, char *base, int align)
{
	if (sam == NULL) return NULL;

	q = align_offset(q, base, align);
	
	q = smb_io_clnt_info(io, &(sam->client  ), q, base, align);
	q = smb_io_cred     (io, &(sam->rtn_cred), q, base, align);

	RW_IVAL(io, q, sam->logon_level, 0); q += 4;
	RW_SVAL(io, q, sam->auth_level , 0); q += 4;

	switch (sam->auth_level)
	{
		case 1:
		{
			q = smb_io_id_info1(io, &(sam->auth.id1), q, base, align);
			break;
		}
		default:
		{
			/* PANIC! */
			break;
		}
	}
	return q;
}

/*******************************************************************
reads or writes a DOM_GID structure.
********************************************************************/
char* smb_io_gid(BOOL io, DOM_GID *gid, char *q, char *base, int align)
{
	if (gid == NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, gid->gid , 0); q += 4;
	RW_IVAL(io, q, gid->attr, 0); q += 4;

	return q;
}

#if 0
/*******************************************************************
reads or writes a structure.
********************************************************************/
 char* smb_io_(BOOL io, *, char *q, char *base, int align)
{
	if (== NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, , 0); q += 4;

	return q;
}

/*******************************************************************
reads or writes a structure.
********************************************************************/
 char* smb_io_(BOOL io, *, char *q, char *base, int align)
{
	if (== NULL) return NULL;

	q = align_offset(q, base, align);
	
	RW_IVAL(io, q, , 0); q += 4;

	return q;
}
#endif
