Samba memory buffer functions
Copyright (C) Andrew Tridgell 1992-1997
Copyright (C) Luke Kenneth Casson Leighton 1996-1997
- Copyright (C) Jeremy Allison 1999.
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Andrew Bartlett 2003.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
prs_dump_region(name, v, ps, ps->data_offset, ps->buffer_size);
}
-
/**
* Dump from the start of the prs to the current location.
**/
prs_dump_region(name, v, ps, 0, ps->data_offset);
}
-
/**
* Dump everything from the start of the prs up to the current location.
**/
{
int fd, i;
pstring fname;
+ ssize_t sz;
if (DEBUGLEVEL < 50) return;
for (i=1;i<100;i++) {
if (v != -1) {
if (fd != -1 || errno != EEXIST) break;
}
if (fd != -1) {
- write(fd, ps->data_p + from_off, to_off - from_off);
- close(fd);
- DEBUG(0,("created %s\n", fname));
+ sz = write(fd, ps->data_p + from_off, to_off - from_off);
+ i = close(fd);
+ if ( (sz != to_off-from_off) || (i != 0) ) {
+ DEBUG(0,("Error writing/closing %s: %ld!=%ld %d\n", fname, (unsigned long)sz, (unsigned long)to_off-from_off, i ));
+ } else {
+ DEBUG(0,("created %s\n", fname));
+ }
}
}
-
-
/*******************************************************************
- debug output for parsing info.
+ Debug output for parsing info
- XXXX side-effect of this function is to increase the debug depth XXXX
+ XXXX side-effect of this function is to increase the debug depth XXXX.
+
+********************************************************************/
- ********************************************************************/
void prs_debug(prs_struct *ps, int depth, const char *desc, const char *fn_name)
{
DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
}
-
/**
* Initialise an expandable parse structure.
*
*
* @return False if allocation fails, otherwise True.
**/
+
BOOL prs_init(prs_struct *ps, uint32 size, TALLOC_CTX *ctx, BOOL io)
{
ZERO_STRUCTP(ps);
if (size != 0) {
ps->buffer_size = size;
- if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
+ if((ps->data_p = (char *)SMB_MALLOC((size_t)size)) == NULL) {
DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
return False;
}
memset(ps->data_p, '\0', (size_t)size);
ps->is_dynamic = True; /* We own this memory. */
+ } else if (MARSHALLING(ps)) {
+ /* If size is zero and we're marshalling we should allocate memory on demand. */
+ ps->is_dynamic = True;
}
return True;
/*******************************************************************
Delete the memory in a parse structure - if we own it.
+
+ NOTE: Contrary to the somewhat confusing naming, this function is not
+ intended for freeing memory allocated by prs_alloc_mem(). That memory
+ is attached to the talloc context given by ps->mem_ctx.
********************************************************************/
void prs_mem_free(prs_struct *ps)
Allocate memory when unmarshalling... Always zero clears.
********************************************************************/
-char *prs_alloc_mem(prs_struct *ps, size_t size)
+#if defined(PARANOID_MALLOC_CHECKER)
+char *prs_alloc_mem_(prs_struct *ps, size_t size, unsigned int count)
+#else
+char *prs_alloc_mem(prs_struct *ps, size_t size, unsigned int count)
+#endif
{
char *ret = NULL;
- if (size) {
- ret = talloc(ps->mem_ctx, size);
- if (ret)
- memset(ret, '\0', size);
+ if (size && count) {
+ /* We can't call the type-safe version here. */
+ ret = (char *)_talloc_zero_array(ps->mem_ctx, size, count,
+ "parse_prs");
}
return ret;
}
return prs_force_grow(ps, newsize - ps->buffer_size);
if (newsize < ps->buffer_size) {
- char *new_data_p = Realloc(ps->data_p, newsize);
- /* if newsize is zero, Realloc acts like free() & returns NULL*/
- if (new_data_p == NULL && newsize != 0) {
- DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
- (unsigned int)newsize));
- DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
- return False;
- }
- ps->data_p = new_data_p;
ps->buffer_size = newsize;
+
+ /* newsize == 0 acts as a free and set pointer to NULL */
+ if (newsize == 0) {
+ SAFE_FREE(ps->data_p);
+ } else {
+ ps->data_p = (char *)SMB_REALLOC(ps->data_p, newsize);
+
+ if (ps->data_p == NULL) {
+ DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
+ (unsigned int)newsize));
+ DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
+ return False;
+ }
+ }
}
return True;
BOOL prs_grow(prs_struct *ps, uint32 extra_space)
{
uint32 new_size;
- char *new_data;
ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
* is greater.
*/
- new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
+ new_size = MAX(RPC_MAX_PDU_FRAG_LEN,extra_space);
- if((new_data = malloc(new_size)) == NULL) {
+ if((ps->data_p = (char *)SMB_MALLOC(new_size)) == NULL) {
DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
return False;
}
- memset(new_data, '\0', (size_t)new_size );
+ memset(ps->data_p, '\0', (size_t)new_size );
} else {
/*
* If the current buffer size is bigger than the space needed, just
*/
new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);
- if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+ if ((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
(unsigned int)new_size));
return False;
}
- memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
+ memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
}
ps->buffer_size = new_size;
- ps->data_p = new_data;
return True;
}
BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
{
uint32 new_size = ps->buffer_size + extra_space;
- char *new_data;
if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
return False;
}
- if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+ if((ps->data_p = (char *)SMB_REALLOC(ps->data_p, new_size)) == NULL) {
DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
(unsigned int)new_size));
return False;
}
- memset(&new_data[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
+ memset(&ps->data_p[ps->buffer_size], '\0', (size_t)(new_size - ps->buffer_size));
ps->buffer_size = new_size;
- ps->data_p = new_data;
return True;
}
Append the data from a buffer into a parse_struct.
********************************************************************/
-BOOL prs_copy_data_in(prs_struct *dst, char *src, uint32 len)
+BOOL prs_copy_data_in(prs_struct *dst, const char *src, uint32 len)
{
if (len == 0)
return True;
return ret;
}
+/******************************************************************
+ Align on a specific byte boundary
+ *****************************************************************/
+
+BOOL prs_align_custom(prs_struct *ps, uint8 boundary)
+{
+ BOOL ret;
+ uint8 old_align = ps->align;
+
+ ps->align = boundary;
+ ret = prs_align(ps);
+ ps->align = old_align;
+
+ return ret;
+}
+
+
+
/*******************************************************************
Align only if required (for the unistr2 string mainly)
********************************************************************/
* If reading, ensure that we can read the requested size item.
*/
if (ps->data_offset + extra_size > ps->buffer_size) {
- DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
- (unsigned int)extra_size ));
+ DEBUG(0,("prs_mem_get: reading data of size %u would overrun "
+ "buffer by %u bytes.\n",
+ (unsigned int)extra_size,
+ (unsigned int)(ps->data_offset + extra_size - ps->buffer_size) ));
return NULL;
}
} else {
ps->is_dynamic=True;
}
+/*******************************************************************
+ Associate a session key with a parse struct.
+ ********************************************************************/
+
+void prs_set_session_key(prs_struct *ps, const char sess_key[16])
+{
+ ps->sess_key = sess_key;
+}
+
/*******************************************************************
Stream a uint8.
********************************************************************/
if (q == NULL)
return False;
- if (UNMARSHALLING(ps))
+ if (UNMARSHALLING(ps))
*data8 = CVAL(q,0);
else
SCVAL(q,0,*data8);
- DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
+ DEBUG(5,("%s%04x %s: %02x\n", tab_depth(depth), ps->data_offset, name, *data8));
ps->data_offset += 1;
return True;
}
+/*******************************************************************
+ Stream a uint16* (allocate memory if unmarshalling)
+ ********************************************************************/
+
+BOOL prs_pointer( const char *name, prs_struct *ps, int depth,
+ void *dta, size_t data_size,
+ BOOL(*prs_fn)(const char*, prs_struct*, int, void*) )
+{
+ void ** data = (void **)dta;
+ uint32 data_p;
+
+ /* output f000baaa to stream if the pointer is non-zero. */
+
+ data_p = *data ? 0xf000baaa : 0;
+
+ if ( !prs_uint32("ptr", ps, depth, &data_p ))
+ return False;
+
+ /* we're done if there is no data */
+
+ if ( !data_p )
+ return True;
+
+ if (UNMARSHALLING(ps)) {
+ if (data_size) {
+ if ( !(*data = PRS_ALLOC_MEM(ps, char, data_size)) )
+ return False;
+ } else {
+ *data = NULL;
+ }
+ }
+
+ return prs_fn(name, ps, depth, *data);
+}
+
+
/*******************************************************************
Stream a uint16.
********************************************************************/
if (q == NULL)
return False;
- if (UNMARSHALLING(ps)) {
+ if (UNMARSHALLING(ps)) {
if (ps->bigendian_data)
*data16 = RSVAL(q,0);
else
*data16 = SVAL(q,0);
- } else {
+ } else {
if (ps->bigendian_data)
RSSVAL(q,0,*data16);
else
return True;
}
+/*******************************************************************
+ Stream an int32.
+ ********************************************************************/
+
+BOOL prs_int32(const char *name, prs_struct *ps, int depth, int32 *data32)
+{
+ char *q = prs_mem_get(ps, sizeof(int32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *data32 = RIVALS(q,0);
+ else
+ *data32 = IVALS(q,0);
+ } else {
+ if (ps->bigendian_data)
+ RSIVALS(q,0,*data32);
+ else
+ SIVALS(q,0,*data32);
+ }
+
+ DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));
+
+ ps->data_offset += sizeof(int32);
+
+ return True;
+}
+
/*******************************************************************
Stream a NTSTATUS
********************************************************************/
return True;
}
+/*******************************************************************
+ Stream a DCE error code
+ ********************************************************************/
+
+BOOL prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
+{
+ char *q = prs_mem_get(ps, sizeof(uint32));
+ if (q == NULL)
+ return False;
+
+ if (UNMARSHALLING(ps)) {
+ if (ps->bigendian_data)
+ *status = NT_STATUS(RIVAL(q,0));
+ else
+ *status = NT_STATUS(IVAL(q,0));
+ } else {
+ if (ps->bigendian_data)
+ RSIVAL(q,0,NT_STATUS_V(*status));
+ else
+ SIVAL(q,0,NT_STATUS_V(*status));
+ }
+
+ DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name,
+ dcerpc_errstr(NT_STATUS_V(*status))));
+
+ ps->data_offset += sizeof(uint32);
+
+ return True;
+}
+
+
/*******************************************************************
Stream a WERROR
********************************************************************/
SCVAL(q, i, data8s[i]);
}
- DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
- if (charmode)
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset ,name));
+ if (charmode)
print_asc(5, (unsigned char*)data8s, len);
else {
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i++)
DEBUG(5,("%02x ", data8s[i]));
}
- DEBUG(5,("\n"));
+ DEBUG(5,("\n"));
ps->data_offset += len;
for (i = 0; i < len; i++)
DEBUG(5,("%04x ", data16s[i]));
}
- DEBUG(5,("\n"));
+ DEBUG(5,("\n"));
ps->data_offset += (len * sizeof(uint16));
for (i = 0; i < len; i++)
DEBUG(5,("%04x ", out_buf[i]));
}
- DEBUG(5,("\n"));
+ DEBUG(5,("\n"));
}
/******************************************************************
for (i = 0; i < len; i++)
DEBUG(5,("%08x ", data32s[i]));
}
- DEBUG(5,("\n"));
+ DEBUG(5,("\n"));
ps->data_offset += (len * sizeof(uint32));
if (q == NULL)
return False;
+ /* If the string is empty, we don't have anything to stream */
+ if (str->buf_len==0)
+ return True;
+
if (UNMARSHALLING(ps)) {
- str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len * sizeof(uint16));
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,str->buf_len);
if (str->buffer == NULL)
return False;
}
- /* If the string is empty, we don't have anything to stream */
- if (str->buf_len==0)
- return True;
-
p = (char *)str->buffer;
dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len);
in byte chars. String is in little-endian format.
********************************************************************/
-BOOL prs_buffer2(BOOL charmode, const char *name, prs_struct *ps, int depth, BUFFER2 *str)
+BOOL prs_regval_buffer(BOOL charmode, const char *name, prs_struct *ps, int depth, REGVAL_BUFFER *buf)
{
char *p;
- char *q = prs_mem_get(ps, str->buf_len);
+ char *q = prs_mem_get(ps, buf->buf_len);
if (q == NULL)
return False;
if (UNMARSHALLING(ps)) {
- if ( str->buf_len ) {
- str->buffer = (uint16 *)prs_alloc_mem(ps,str->buf_len);
- if ( str->buffer == NULL )
+ if (buf->buf_len > buf->buf_max_len) {
+ return False;
+ }
+ if ( buf->buf_max_len ) {
+ buf->buffer = PRS_ALLOC_MEM(ps, uint16, buf->buf_max_len);
+ if ( buf->buffer == NULL )
return False;
+ } else {
+ buf->buffer = NULL;
}
}
- p = (char *)str->buffer;
+ p = (char *)buf->buffer;
- dbg_rw_punival(charmode, name, depth, ps, q, p, str->buf_len/2);
- ps->data_offset += str->buf_len;
+ dbg_rw_punival(charmode, name, depth, ps, q, p, buf->buf_len/2);
+ ps->data_offset += buf->buf_len;
return True;
}
BOOL prs_string2(BOOL charmode, const char *name, prs_struct *ps, int depth, STRING2 *str)
{
unsigned int i;
- char *q = prs_mem_get(ps, str->str_max_len);
+ char *q = prs_mem_get(ps, str->str_str_len);
if (q == NULL)
return False;
if (UNMARSHALLING(ps)) {
- str->buffer = (unsigned char *)prs_alloc_mem(ps,str->str_max_len);
- if (str->buffer == NULL)
+ if (str->str_str_len > str->str_max_len) {
return False;
+ }
+ if (str->str_max_len) {
+ str->buffer = PRS_ALLOC_MEM(ps,unsigned char, str->str_max_len);
+ if (str->buffer == NULL)
+ return False;
+ } else {
+ str->buffer = NULL;
+ /* Return early to ensure Coverity isn't confused. */
+ DEBUG(5,("%s%04x %s: \n", tab_depth(depth), ps->data_offset, name));
+ return True;
+ }
}
if (UNMARSHALLING(ps)) {
SCVAL(q, i, str->buffer[i]);
}
- DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
- if (charmode)
+ DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
+ if (charmode)
print_asc(5, (unsigned char*)str->buffer, str->str_str_len);
else {
- for (i = 0; i < str->str_str_len; i++)
+ for (i = 0; i < str->str_str_len; i++)
DEBUG(5,("%02x ", str->buffer[i]));
}
- DEBUG(5,("\n"));
+ DEBUG(5,("\n"));
ps->data_offset += str->str_str_len;
return True;
if (UNMARSHALLING(ps)) {
- str->buffer = (uint16 *)prs_alloc_mem(ps,str->uni_max_len * sizeof(uint16));
- if (str->buffer == NULL)
+ if (str->uni_str_len > str->uni_max_len) {
return False;
+ }
+ if (str->uni_max_len) {
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len);
+ if (str->buffer == NULL)
+ return False;
+ } else {
+ str->buffer = NULL;
+ }
}
p = (char *)str->buffer;
return False;
if (UNMARSHALLING(ps)) {
- str->str.buffer = (uint16 *)prs_alloc_mem(ps,str->uni_str_len * sizeof(uint16));
- if (str->str.buffer == NULL)
- return False;
+ if (str->uni_str_len) {
+ str->str.buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_str_len);
+ if (str->str.buffer == NULL)
+ return False;
+ } else {
+ str->str.buffer = NULL;
+ }
}
p = (char *)str->str.buffer;
start = (uint8*)q;
- for(len = 0; str->buffer[len] != 0; len++)
- {
- if(ps->bigendian_data)
- {
+ for(len = 0; str->buffer[len] != 0; len++) {
+ if(ps->bigendian_data) {
/* swap bytes - p is little endian, q is big endian. */
q[0] = (char)p[1];
q[1] = (char)p[0];
/* the test of the value of *ptr helps to catch the circumstance
where we have an emtpty (non-existent) string in the buffer */
- for ( ptr = (uint16 *)q; *ptr && (alloc_len <= max_len); alloc_len++)
+ for ( ptr = (uint16 *)q; *ptr++ && (alloc_len <= max_len); alloc_len++)
/* do nothing */
;
+ if (alloc_len < max_len)
+ alloc_len += 1;
+
/* should we allocate anything at all? */
- str->buffer = (uint16 *)prs_alloc_mem(ps,alloc_len * sizeof(uint16));
+ str->buffer = PRS_ALLOC_MEM(ps,uint16,alloc_len);
if ((str->buffer == NULL) && (alloc_len > 0))
return False;
/* the (len < alloc_len) test is to prevent us from overwriting
memory that is not ours...if we get that far, we have a non-null
terminated string in the buffer and have messed up somewhere */
- while ((len < alloc_len) && (*(uint16 *)q != 0))
- {
+ while ((len < alloc_len) && (*(uint16 *)q != 0)) {
if(ps->bigendian_data)
{
/* swap bytes - q is big endian, p is little endian. */
len++;
}
- if (len < alloc_len)
- {
+ if (len < alloc_len) {
/* NULL terminate the UNISTR */
str->buffer[len++] = '\0';
}
ps->data_offset += len+1;
- dump_data(5+depth, q, len);
+ dump_data(5+depth, (uint8 *)q, len);
return True;
}
+BOOL prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str)
+{
+ size_t len;
+ char *tmp_str;
+
+ if (UNMARSHALLING(ps)) {
+ len = strlen(&ps->data_p[ps->data_offset]);
+ } else {
+ len = strlen(*str);
+ }
+
+ tmp_str = PRS_ALLOC_MEM(ps, char, len+1);
+
+ if (tmp_str == NULL) {
+ return False;
+ }
+
+ if (MARSHALLING(ps)) {
+ strncpy(tmp_str, *str, len);
+ }
+
+ if (!prs_string(name, ps, depth, tmp_str, len+1)) {
+ return False;
+ }
+
+ *str = tmp_str;
+ return True;
+}
+
/*******************************************************************
prs_uint16 wrapper. Call this and it sets up a pointer to where the
uint16 should be stored, or gets the size if reading.
}
/* useful function to store a structure in rpc wire format */
-int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
+int tdb_prs_store(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps)
{
- TDB_DATA kbuf, dbuf;
- kbuf.dptr = keystr;
- kbuf.dsize = strlen(keystr)+1;
- dbuf.dptr = ps->data_p;
- dbuf.dsize = prs_offset(ps);
- return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
+ TDB_DATA dbuf;
+ dbuf.dptr = (uint8 *)ps->data_p;
+ dbuf.dsize = prs_offset(ps);
+ return tdb_trans_store(tdb, kbuf, dbuf, TDB_REPLACE);
}
/* useful function to fetch a structure into rpc wire format */
-int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx)
+int tdb_prs_fetch(TDB_CONTEXT *tdb, TDB_DATA kbuf, prs_struct *ps, TALLOC_CTX *mem_ctx)
{
- TDB_DATA kbuf, dbuf;
- kbuf.dptr = keystr;
- kbuf.dsize = strlen(keystr)+1;
+ TDB_DATA dbuf;
+
+ prs_init(ps, 0, mem_ctx, UNMARSHALL);
- dbuf = tdb_fetch(tdb, kbuf);
- if (!dbuf.dptr)
- return -1;
+ dbuf = tdb_fetch(tdb, kbuf);
+ if (!dbuf.dptr)
+ return -1;
- ZERO_STRUCTP(ps);
- prs_init(ps, 0, mem_ctx, UNMARSHALL);
- prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
+ prs_give_memory(ps, (char *)dbuf.dptr, dbuf.dsize, True);
- return 0;
-}
+ return 0;
+}
/*******************************************************************
hash a stream.
********************************************************************/
-BOOL prs_hash1(prs_struct *ps, uint32 offset, uint8 sess_key[16], int len)
+
+BOOL prs_hash1(prs_struct *ps, uint32 offset, int len)
{
char *q;
#ifdef DEBUG_PASSWORD
DEBUG(100, ("prs_hash1\n"));
- dump_data(100, sess_key, 16);
- dump_data(100, q, len);
+ dump_data(100, (uint8 *)ps->sess_key, 16);
+ dump_data(100, (uint8 *)q, len);
#endif
- SamOEMhash((uchar *) q, sess_key, len);
+ SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);
#ifdef DEBUG_PASSWORD
- dump_data(100, q, len);
+ dump_data(100, (uint8 *)q, len);
#endif
return True;
}
-static void netsechash(uchar * key, uchar * data, int data_len)
-{
- uchar hash[256];
- uchar index_i = 0;
- uchar index_j = 0;
- uchar j = 0;
- int ind;
-
- for (ind = 0; ind < 256; ind++)
- {
- hash[ind] = (uchar) ind;
- }
-
- for (ind = 0; ind < 256; ind++)
- {
- uchar tc;
-
- j += (hash[ind] + key[ind % 16]);
-
- tc = hash[ind];
- hash[ind] = hash[j];
- hash[j] = tc;
- }
-
- for (ind = 0; ind < data_len; ind++)
- {
- uchar tc;
- uchar t;
-
- index_i++;
- index_j += hash[index_i];
-
- tc = hash[index_i];
- hash[index_i] = hash[index_j];
- hash[index_j] = tc;
-
- t = hash[index_i] + hash[index_j];
- data[ind] ^= hash[t];
- }
-}
-
-
/*******************************************************************
Create a digest over the entire packet (including the data), and
MD5 it with the session key.
********************************************************************/
-static void netsec_digest(struct netsec_auth_struct *a,
- int auth_flags,
- RPC_AUTH_NETSEC_CHK * verf,
+
+static void schannel_digest(struct schannel_auth_struct *a,
+ enum pipe_auth_level auth_level,
+ RPC_AUTH_SCHANNEL_CHK * verf,
char *data, size_t data_len,
uchar digest_final[16])
{
uchar whole_packet_digest[16];
- static uchar zeros[4];
+ static const uchar zeros[4] = { 0, };
struct MD5Context ctx3;
/* verfiy the signature on the packet by MD5 over various bits */
out of order */
MD5Update(&ctx3, zeros, sizeof(zeros));
MD5Update(&ctx3, verf->sig, sizeof(verf->sig));
- if (auth_flags & AUTH_PIPE_SEAL) {
- MD5Update(&ctx3, verf->data8, sizeof(verf->data8));
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder));
}
- MD5Update(&ctx3, data, data_len);
+ MD5Update(&ctx3, (const unsigned char *)data, data_len);
MD5Final(whole_packet_digest, &ctx3);
dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest));
/*******************************************************************
Calculate the key with which to encode the data payload
********************************************************************/
-static void netsec_get_sealing_key(struct netsec_auth_struct *a,
- RPC_AUTH_NETSEC_CHK *verf,
+
+static void schannel_get_sealing_key(struct schannel_auth_struct *a,
+ RPC_AUTH_SCHANNEL_CHK *verf,
uchar sealing_key[16])
{
- static uchar zeros[4];
+ static const uchar zeros[4] = { 0, };
uchar digest2[16];
uchar sess_kf0[16];
int i;
dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0));
- /* MD5 of sess_kf0 and the high bytes of the sequence number */
+ /* MD5 of sess_kf0 and 4 zero bytes */
hmac_md5(sess_kf0, zeros, 0x4, digest2);
dump_data_pw("digest2:\n", digest2, sizeof(digest2));
/*******************************************************************
Encode or Decode the sequence number (which is symmetric)
********************************************************************/
-static void netsec_deal_with_seq_num(struct netsec_auth_struct *a,
- RPC_AUTH_NETSEC_CHK *verf)
+
+static void schannel_deal_with_seq_num(struct schannel_auth_struct *a,
+ RPC_AUTH_SCHANNEL_CHK *verf)
{
- static uchar zeros[4];
+ static const uchar zeros[4] = { 0, };
uchar sequence_key[16];
uchar digest1[16];
dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key));
dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num));
- netsechash(sequence_key, verf->seq_num, 8);
+ SamOEMhash(verf->seq_num, sequence_key, 8);
dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));
}
+/*******************************************************************
+creates an RPC_AUTH_SCHANNEL_CHK structure.
+********************************************************************/
+
+static BOOL init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk,
+ const uchar sig[8],
+ const uchar packet_digest[8],
+ const uchar seq_num[8], const uchar confounder[8])
+{
+ if (chk == NULL)
+ return False;
+
+ memcpy(chk->sig, sig, sizeof(chk->sig));
+ memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest));
+ memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num));
+ memcpy(chk->confounder, confounder, sizeof(chk->confounder));
+
+ return True;
+}
/*******************************************************************
- Encode a blob of data using the netsec (schannel) alogrithm, also produceing
+ Encode a blob of data using the schannel alogrithm, also produceing
a checksum over the original data. We currently only support
signing and sealing togeather - the signing-only code is close, but not
quite compatible with what MS does.
********************************************************************/
-void netsec_encode(struct netsec_auth_struct *a, int auth_flags,
- enum netsec_direction direction,
- RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
+
+void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf,
+ char *data, size_t data_len)
{
uchar digest_final[16];
+ uchar confounder[8];
+ uchar seq_num[8];
+ static const uchar nullbytes[8] = { 0, };
+
+ static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
+ static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
+ const uchar *schannel_sig = NULL;
+
+ DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ schannel_sig = schannel_seal_sig;
+ } else {
+ schannel_sig = schannel_sign_sig;
+ }
+
+ /* fill the 'confounder' with random data */
+ generate_random_buffer(confounder, sizeof(confounder));
- DEBUG(10,("SCHANNEL: netsec_encode seq_num=%d data_len=%l\n", a->seq_num, data_len));
dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
- RSIVAL(verf->seq_num, 0, a->seq_num);
+ RSIVAL(seq_num, 0, a->seq_num);
switch (direction) {
case SENDER_IS_INITIATOR:
- SIVAL(verf->seq_num, 4, 0x80);
+ SIVAL(seq_num, 4, 0x80);
break;
case SENDER_IS_ACCEPTOR:
- SIVAL(verf->seq_num, 4, 0x0);
+ SIVAL(seq_num, 4, 0x0);
break;
}
- dump_data_pw("verf->seq_num:\n", verf->seq_num, sizeof(verf->seq_num));
+ dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num));
+ init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes,
+ seq_num, confounder);
+
/* produce a digest of the packet to prove it's legit (before we seal it) */
- netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
+ schannel_digest(a, auth_level, verf, data, data_len, digest_final);
memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest));
- if (auth_flags & AUTH_PIPE_SEAL) {
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
uchar sealing_key[16];
/* get the key to encode the data with */
- netsec_get_sealing_key(a, verf, sealing_key);
+ schannel_get_sealing_key(a, verf, sealing_key);
/* encode the verification data */
- dump_data_pw("verf->data8:\n", verf->data8, sizeof(verf->data8));
- netsechash(sealing_key, verf->data8, 8);
+ dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder));
+ SamOEMhash(verf->confounder, sealing_key, 8);
- dump_data_pw("verf->data8_enc:\n", verf->data8, sizeof(verf->data8));
+ dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder));
/* encode the packet payload */
- dump_data_pw("data:\n", data, data_len);
- netsechash(sealing_key, data, data_len);
- dump_data_pw("data_enc:\n", data, data_len);
+ dump_data_pw("data:\n", (const unsigned char *)data, data_len);
+ SamOEMhash((unsigned char *)data, sealing_key, data_len);
+ dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len);
}
/* encode the sequence number (key based on packet digest) */
/* needs to be done after the sealing, as the original version
is used in the sealing stuff... */
- netsec_deal_with_seq_num(a, verf);
+ schannel_deal_with_seq_num(a, verf);
return;
}
/*******************************************************************
- Decode a blob of data using the netsec (schannel) alogrithm, also verifiying
+ Decode a blob of data using the schannel alogrithm, also verifiying
a checksum over the original data. We currently can verify signed messages,
as well as decode sealed messages
********************************************************************/
-BOOL netsec_decode(struct netsec_auth_struct *a, int auth_flags,
- enum netsec_direction direction,
- RPC_AUTH_NETSEC_CHK * verf, char *data, size_t data_len)
+BOOL schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level,
+ enum schannel_direction direction,
+ RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len)
{
uchar digest_final[16];
- /* Create the expected sequence number for comparison */
+ static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE;
+ static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE;
+ const uchar *schannel_sig = NULL;
+
uchar seq_num[8];
+
+ DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
+ schannel_sig = schannel_seal_sig;
+ } else {
+ schannel_sig = schannel_sign_sig;
+ }
+
+ /* Create the expected sequence number for comparison */
RSIVAL(seq_num, 0, a->seq_num);
switch (direction) {
break;
}
- DEBUG(10,("SCHANNEL: netsec_decode seq_num=%d data_len=%l\n", a->seq_num, data_len));
+ DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len));
dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key));
dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num));
/* extract the sequence number (key based on supplied packet digest) */
/* needs to be done before the sealing, as the original version
is used in the sealing stuff... */
- netsec_deal_with_seq_num(a, verf);
+ schannel_deal_with_seq_num(a, verf);
if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) {
/* don't even bother with the below if the sequence number is out */
digest, as supplied by the client. We check that it's a valid
checksum after the decode, below
*/
+ DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n"));
+ dump_data(2, verf->seq_num, sizeof(verf->seq_num));
+ DEBUG(2, ("should be:\n"));
+ dump_data(2, seq_num, sizeof(seq_num));
+
return False;
}
- if (auth_flags & AUTH_PIPE_SEAL) {
+ if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) {
+ /* Validate that the other end sent the expected header */
+ DEBUG(2, ("schannel_decode: FAILED: packet header:\n"));
+ dump_data(2, verf->sig, sizeof(verf->sig));
+ DEBUG(2, ("should be:\n"));
+ dump_data(2, schannel_sig, sizeof(schannel_sig));
+ return False;
+ }
+
+ if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) {
uchar sealing_key[16];
/* get the key to extract the data with */
- netsec_get_sealing_key(a, verf, sealing_key);
+ schannel_get_sealing_key(a, verf, sealing_key);
/* extract the verification data */
- dump_data_pw("verf->data8:\n", verf->data8,
- sizeof(verf->data8));
- netsechash(sealing_key, verf->data8, 8);
+ dump_data_pw("verf->confounder:\n", verf->confounder,
+ sizeof(verf->confounder));
+ SamOEMhash(verf->confounder, sealing_key, 8);
- dump_data_pw("verf->data8_dec:\n", verf->data8,
- sizeof(verf->data8));
+ dump_data_pw("verf->confounder_dec:\n", verf->confounder,
+ sizeof(verf->confounder));
/* extract the packet payload */
- dump_data_pw("data :\n", data, data_len);
- netsechash(sealing_key, data, data_len);
- dump_data_pw("datadec:\n", data, data_len);
+ dump_data_pw("data :\n", (const unsigned char *)data, data_len);
+ SamOEMhash((unsigned char *)data, sealing_key, data_len);
+ dump_data_pw("datadec:\n", (const unsigned char *)data, data_len);
}
/* digest includes 'data' after unsealing */
- netsec_digest(a, auth_flags, verf, data, data_len, digest_final);
+ schannel_digest(a, auth_level, verf, data, data_len, digest_final);
dump_data_pw("Calculated digest:\n", digest_final,
sizeof(digest_final));
return (memcmp(digest_final, verf->packet_digest,
sizeof(verf->packet_digest)) == 0);
}
+
+/*******************************************************************
+creates a new prs_struct containing a DATA_BLOB
+********************************************************************/
+BOOL prs_init_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ if (!prs_init( prs, RPC_MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL ))
+ return False;
+
+
+ if (!prs_copy_data_in(prs, (char *)blob->data, blob->length))
+ return False;
+
+ return True;
+}
+
+/*******************************************************************
+return the contents of a prs_struct in a DATA_BLOB
+********************************************************************/
+BOOL prs_data_blob(prs_struct *prs, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ blob->length = prs_data_size(prs);
+ blob->data = (uint8 *)TALLOC_ZERO_SIZE(mem_ctx, blob->length);
+
+ /* set the pointer at the end of the buffer */
+ prs_set_offset( prs, prs_data_size(prs) );
+
+ if (!prs_copy_all_data_out((char *)blob->data, prs))
+ return False;
+
+ return True;
+}