r10656: BIG merge from trunk. Features not copied over
[amitay/samba.git] / source3 / rpc_parse / parse_misc.c
index 203122e73c0ebc150afddb841ac45e64a3cdde31..8bbb97f226db7119a1c0bcf81f2b3c3d40127a32 100644 (file)
@@ -4,6 +4,7 @@
  *  Copyright (C) Andrew Tridgell              1992-1997,
  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
  *  Copyright (C) Paul Ashton                       1997.
+ *  Copyright (C) Gerald (Jerry) Carter             2005
  *  
  *  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
@@ -32,7 +33,7 @@
 
 static TALLOC_CTX *current_rpc_talloc = NULL;
 
-TALLOC_CTX *get_current_rpc_talloc(void)
+static TALLOC_CTX *get_current_rpc_talloc(void)
 {
     return current_rpc_talloc;
 }
@@ -132,25 +133,12 @@ BOOL smb_io_time(const char *desc, NTTIME *nttime, prs_struct *ps, int depth)
 }
 
 /*******************************************************************
- Reads or writes a LOOKUP_LEVEL structure.
+ Reads or writes an NTTIME structure.
 ********************************************************************/
 
-BOOL smb_io_lookup_level(const char *desc, LOOKUP_LEVEL *level, prs_struct *ps, int depth)
+BOOL smb_io_nttime(const char *desc, prs_struct *ps, int depth, NTTIME *nttime)
 {
-       if (level == NULL)
-               return False;
-
-       prs_debug(ps, depth, desc, "smb_io_lookup_level");
-       depth++;
-
-       if(!prs_align(ps))
-               return False;
-       if(!prs_uint16("value", ps, depth, &level->value))
-               return False;
-       if(!prs_align(ps))
-               return False;
-
-       return True;
+       return smb_io_time( desc, nttime, ps, depth );
 }
 
 /*******************************************************************
@@ -302,6 +290,33 @@ void init_dom_sid2(DOM_SID2 *sid2, const DOM_SID *sid)
  Reads or writes a DOM_SID2 structure.
 ********************************************************************/
 
+BOOL smb_io_dom_sid2_p(const char *desc, prs_struct *ps, int depth, DOM_SID2 **sid2)
+{
+       uint32 data_p;
+
+       /* caputure the pointer value to stream */
+
+       data_p = *sid2 ? 0xf000baaa : 0;
+
+       if ( !prs_uint32("dom_sid2_p", ps, depth, &data_p ))
+               return False;
+
+       /* we're done if there is no data */
+
+       if ( !data_p )
+               return True;
+
+       if (UNMARSHALLING(ps)) {
+               if ( !(*sid2 = PRS_ALLOC_MEM(ps, DOM_SID2, 1)) )
+               return False;
+       }
+
+       return True;
+}
+/*******************************************************************
+ Reads or writes a DOM_SID2 structure.
+********************************************************************/
+
 BOOL smb_io_dom_sid2(const char *desc, DOM_SID2 *sid, prs_struct *ps, int depth)
 {
        if (sid == NULL)
@@ -322,6 +337,34 @@ BOOL smb_io_dom_sid2(const char *desc, DOM_SID2 *sid, prs_struct *ps, int depth)
        return True;
 }
 
+/*******************************************************************
+ Reads or writes a struct uuid
+********************************************************************/
+
+BOOL smb_io_uuid(const char *desc, struct uuid *uuid, 
+                prs_struct *ps, int depth)
+{
+       if (uuid == NULL)
+               return False;
+
+       prs_debug(ps, depth, desc, "smb_io_uuid");
+       depth++;
+
+       if(!prs_uint32 ("data   ", ps, depth, &uuid->time_low))
+               return False;
+       if(!prs_uint16 ("data   ", ps, depth, &uuid->time_mid))
+               return False;
+       if(!prs_uint16 ("data   ", ps, depth, &uuid->time_hi_and_version))
+               return False;
+
+       if(!prs_uint8s (False, "data   ", ps, depth, uuid->clock_seq, sizeof(uuid->clock_seq)))
+               return False;
+       if(!prs_uint8s (False, "data   ", ps, depth, uuid->node, sizeof(uuid->node)))
+               return False;
+
+       return True;
+}
+
 /*******************************************************************
 creates a STRHDR structure.
 ********************************************************************/
@@ -478,39 +521,6 @@ BOOL smb_io_hdrbuf(const char *desc, BUFHDR *hdr, prs_struct *ps, int depth)
        return True;
 }
 
-/*******************************************************************
-creates a UNIHDR2 structure.
-********************************************************************/
-
-void init_uni_hdr2(UNIHDR2 *hdr, UNISTR2 *str2)
-{
-       init_uni_hdr(&hdr->unihdr, str2);
-       hdr->buffer = (str2->uni_str_len > 0) ? 1 : 0;
-}
-
-/*******************************************************************
- Reads or writes a UNIHDR2 structure.
-********************************************************************/
-
-BOOL smb_io_unihdr2(const char *desc, UNIHDR2 *hdr2, prs_struct *ps, int depth)
-{
-       if (hdr2 == NULL)
-               return False;
-
-       prs_debug(ps, depth, desc, "smb_io_unihdr2");
-       depth++;
-
-       if(!prs_align(ps))
-               return False;
-
-       if(!smb_io_unihdr("hdr", &hdr2->unihdr, ps, depth))
-               return False;
-       if(!prs_uint32("buffer", ps, depth, &hdr2->buffer))
-               return False;
-
-       return True;
-}
-
 /*******************************************************************
  Inits a UNISTR structure.
 ********************************************************************/
@@ -524,18 +534,13 @@ void init_unistr(UNISTR *str, const char *buf)
                return;
        }
                
-
        len = strlen(buf) + 1;
 
-       if (len < MAX_UNISTRLEN)
-               len = MAX_UNISTRLEN;
-       len *= sizeof(uint16);
-
-       str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+       str->buffer = TALLOC_ZERO_ARRAY(get_talloc_ctx(), uint16, len);
        if (str->buffer == NULL)
                smb_panic("init_unistr: malloc fail\n");
 
-       rpcstr_push(str->buffer, buf, len, STR_TERMINATE);
+       rpcstr_push(str->buffer, buf, len*sizeof(uint16), STR_TERMINATE);
 }
 
 /*******************************************************************
@@ -558,115 +563,69 @@ BOOL smb_io_unistr(const char *desc, UNISTR *uni, prs_struct *ps, int depth)
 }
 
 /*******************************************************************
- Allocate the BUFFER3 memory.
+ Allocate the RPC_DATA_BLOB memory.
 ********************************************************************/
 
-static void create_buffer3(BUFFER3 *str, size_t len)
+size_t create_rpc_blob(RPC_DATA_BLOB *str, size_t len)
 {
-       if (len < MAX_BUFFERLEN)
-               len = MAX_BUFFERLEN;
-
-    str->buffer = talloc_zero(get_talloc_ctx(), len);
+       str->buffer = TALLOC_ZERO(get_talloc_ctx(), len);
        if (str->buffer == NULL)
-               smb_panic("create_buffer3: talloc fail\n");
-
+               smb_panic("create_rpc_blob: talloc fail\n");
+       return len;
 }
 
 /*******************************************************************
- Inits a BUFFER3 structure from a uint32
+ Inits a RPC_DATA_BLOB structure from a uint32
 ********************************************************************/
 
-void init_buffer3_uint32(BUFFER3 *str, uint32 val)
+void init_rpc_blob_uint32(RPC_DATA_BLOB *str, uint32 val)
 {
        ZERO_STRUCTP(str);
 
        /* set up string lengths. */
-       str->buf_max_len = sizeof(uint32);
-       str->buf_len     = sizeof(uint32);
-
-       create_buffer3(str, sizeof(uint32));
+       str->buf_len = create_rpc_blob(str, sizeof(uint32));
        SIVAL(str->buffer, 0, val);
 }
 
 /*******************************************************************
- Inits a BUFFER3 structure.
+ Inits a RPC_DATA_BLOB structure.
 ********************************************************************/
 
-void init_buffer3_str(BUFFER3 *str, const char *buf, int len)
+void init_rpc_blob_str(RPC_DATA_BLOB *str, const char *buf, int len)
 {
        ZERO_STRUCTP(str);
 
        /* set up string lengths. */
-       str->buf_max_len = len * 2;
-       str->buf_len = len * 2;
-
-       create_buffer3(str, str->buf_max_len);
-
-       rpcstr_push(str->buffer, buf, str->buf_max_len, STR_TERMINATE);
+       str->buf_len = create_rpc_blob(str, len*2);
+       rpcstr_push(str->buffer, buf, str->buf_len, STR_TERMINATE);
        
 }
 
 /*******************************************************************
- Inits a BUFFER3 structure from a hex string.
+ Inits a RPC_DATA_BLOB structure from a hex string.
 ********************************************************************/
 
-void init_buffer3_hex(BUFFER3 *str, const char *buf)
+void init_rpc_blob_hex(RPC_DATA_BLOB *str, const char *buf)
 {
        ZERO_STRUCTP(str);
-       create_buffer3(str, strlen(buf));
-       str->buf_max_len = str->buf_len = strhex_to_str((char *)str->buffer, sizeof(str->buffer), buf);
+       str->buf_len = create_rpc_blob(str, strlen(buf));
+       str->buf_len = strhex_to_str((char *)str->buffer, str->buf_len, buf);
 }
 
 /*******************************************************************
- Inits a BUFFER3 structure.
+ Inits a RPC_DATA_BLOB structure.
 ********************************************************************/
 
-void init_buffer3_bytes(BUFFER3 *str, uint8 *buf, int len)
+void init_rpc_blob_bytes(RPC_DATA_BLOB *str, uint8 *buf, size_t len)
 {
        ZERO_STRUCTP(str);
 
        /* max buffer size (allocated size) */
-       str->buf_max_len = len;
        if (buf != NULL) {
-               create_buffer3(str, len);
+               len = create_rpc_blob(str, len);
                memcpy(str->buffer, buf, len);
        }
-       str->buf_len = buf != NULL ? len : 0;
-}
-
-/*******************************************************************
- Reads or writes a BUFFER3 structure.
-   the uni_max_len member tells you how large the buffer is.
-   the uni_str_len member tells you how much of the buffer is really used.
-********************************************************************/
-
-BOOL smb_io_buffer3(const char *desc, BUFFER3 *buf3, prs_struct *ps, int depth)
-{
-       if (buf3 == NULL)
-               return False;
-
-       prs_debug(ps, depth, desc, "smb_io_buffer3");
-       depth++;
-
-       if(!prs_align(ps))
-               return False;
-       
-       if(!prs_uint32("uni_max_len", ps, depth, &buf3->buf_max_len))
-               return False;
-
-       if (UNMARSHALLING(ps)) {
-               buf3->buffer = (unsigned char *)prs_alloc_mem(ps, buf3->buf_max_len);
-               if (buf3->buffer == NULL)
-                       return False;
-       }
-
-       if(!prs_uint8s(True, "buffer     ", ps, depth, buf3->buffer, buf3->buf_max_len))
-               return False;
-
-       if(!prs_uint32("buf_len    ", ps, depth, &buf3->buf_len))
-               return False;
-
-       return True;
+       str->buf_len = len;
 }
 
 /*******************************************************************
@@ -694,10 +653,10 @@ BOOL smb_io_buffer5(const char *desc, BUFFER5 *buf5, prs_struct *ps, int depth)
 }
 
 /*******************************************************************
- Inits a BUFFER2 structure.
+ Inits a REGVAL_BUFFER structure.
 ********************************************************************/
 
-void init_buffer2(BUFFER2 *str, const uint8 *buf, size_t len)
+void init_regval_buffer(REGVAL_BUFFER *str, const uint8 *buf, size_t len)
 {
        ZERO_STRUCTP(str);
 
@@ -707,54 +666,42 @@ void init_buffer2(BUFFER2 *str, const uint8 *buf, size_t len)
        str->buf_len = buf != NULL ? len : 0;
 
        if (buf != NULL) {
-               if (len < MAX_BUFFERLEN)
-                       len = MAX_BUFFERLEN;
-               str->buffer = talloc_zero(get_talloc_ctx(), len);
+               SMB_ASSERT(str->buf_max_len >= str->buf_len);
+               str->buffer = TALLOC_ZERO(get_talloc_ctx(), str->buf_max_len);
                if (str->buffer == NULL)
-                       smb_panic("init_buffer2: talloc fail\n");
-               memcpy(str->buffer, buf, MIN(str->buf_len, len));
+                       smb_panic("init_regval_buffer: talloc fail\n");
+               memcpy(str->buffer, buf, str->buf_len);
        }
 }
 
 /*******************************************************************
- Reads or writes a BUFFER2 structure.
+ Reads or writes a REGVAL_BUFFER structure.
    the uni_max_len member tells you how large the buffer is.
    the uni_str_len member tells you how much of the buffer is really used.
 ********************************************************************/
 
-BOOL smb_io_buffer2(const char *desc, BUFFER2 *buf2, uint32 buffer, prs_struct *ps, int depth)
+BOOL smb_io_regval_buffer(const char *desc, prs_struct *ps, int depth, REGVAL_BUFFER *buf2)
 {
-       if (buf2 == NULL)
-               return False;
 
-       if (buffer) {
-
-               prs_debug(ps, depth, desc, "smb_io_buffer2");
-               depth++;
+       prs_debug(ps, depth, desc, "smb_io_regval_buffer");
+       depth++;
 
-               if(!prs_align(ps))
-                       return False;
+       if(!prs_align(ps))
+               return False;
                
-               if(!prs_uint32("uni_max_len", ps, depth, &buf2->buf_max_len))
-                       return False;
-               if(!prs_uint32("offset     ", ps, depth, &buf2->offset))
-                       return False;
-               if(!prs_uint32("buf_len    ", ps, depth, &buf2->buf_len))
-                       return False;
-
-               /* buffer advanced by indicated length of string
-                  NOT by searching for null-termination */
-
-               if(!prs_buffer2(True, "buffer     ", ps, depth, buf2))
-                       return False;
+       if(!prs_uint32("buf_max_len", ps, depth, &buf2->buf_max_len))
+               return False;
+       if(!prs_uint32("offset     ", ps, depth, &buf2->offset))
+               return False;
+       if(!prs_uint32("buf_len    ", ps, depth, &buf2->buf_len))
+               return False;
 
-       } else {
+       /* buffer advanced by indicated length of string
+          NOT by searching for null-termination */
 
-               prs_debug(ps, depth, desc, "smb_io_buffer2 - NULL");
-               depth++;
-               memset((char *)buf2, '\0', sizeof(*buf2));
+       if(!prs_regval_buffer(True, "buffer     ", ps, depth, buf2))
+               return False;
 
-       }
        return True;
 }
 
@@ -780,52 +727,48 @@ void init_buf_unistr2(UNISTR2 *str, uint32 *ptr, const char *buf)
 
 void copy_unistr2(UNISTR2 *str, const UNISTR2 *from)
 {
+       if (from->buffer == NULL) {
+               ZERO_STRUCTP(str);
+               return;
+       }
+
+       SMB_ASSERT(from->uni_max_len >= from->uni_str_len);
+
        str->uni_max_len = from->uni_max_len;
        str->offset      = from->offset;
        str->uni_str_len = from->uni_str_len;
 
-       if (from->buffer == NULL)
-               return;
-               
        /* the string buffer is allocated to the maximum size
           (the the length of the source string) to prevent
           reallocation of memory. */
        if (str->buffer == NULL) {
-               size_t len = from->uni_max_len * sizeof(uint16);
-
-               if (len < MAX_UNISTRLEN)
-                       len = MAX_UNISTRLEN;
-               len *= sizeof(uint16);
-
-               str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
-               if ((str->buffer == NULL) && (len > 0 )) {
+               str->buffer = (uint16 *)TALLOC_ZERO_ARRAY(get_talloc_ctx(), uint16, str->uni_max_len);
+               if ((str->buffer == NULL)) {
                        smb_panic("copy_unistr2: talloc fail\n");
                        return;
                }
        }
 
        /* copy the string */
-       memcpy(str->buffer, from->buffer, from->uni_max_len*sizeof(uint16));
+       memcpy(str->buffer, from->buffer, str->uni_max_len*sizeof(uint16));
 }
 
 /*******************************************************************
  Creates a STRING2 structure.
 ********************************************************************/
 
-void init_string2(STRING2 *str, const char *buf, int max_len, int str_len)
+void init_string2(STRING2 *str, const char *buf, size_t max_len, size_t str_len)
 {
-       int alloc_len = 0;
-
        /* set up string lengths. */
+       SMB_ASSERT(max_len >= str_len);
+
        str->str_max_len = max_len;
        str->offset = 0;
        str->str_str_len = str_len;
 
        /* store the string */
        if(str_len != 0) {
-               if (str_len < MAX_STRINGLEN)
-                       alloc_len = MAX_STRINGLEN;
-               str->buffer = talloc_zero(get_talloc_ctx(), alloc_len);
+               str->buffer = TALLOC_ZERO(get_talloc_ctx(), str->str_max_len);
                if (str->buffer == NULL)
                        smb_panic("init_string2: malloc fail\n");
                memcpy(str->buffer, buf, str_len);
@@ -887,18 +830,25 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags)
        if (buf) {
                /* We always null terminate the copy. */
                len = strlen(buf) + 1;
-       }
+       } else {
+               /* no buffer -- nothing to do */
+               str->uni_max_len = 0;
+               str->offset = 0;
+               str->uni_str_len = 0;
 
-       if (len < MAX_UNISTRLEN)
-               len = MAX_UNISTRLEN;
-       len *= sizeof(uint16);
+               return;
+       }
+       
 
-       str->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
-       if ((str->buffer == NULL) && (len > 0)) {
+       str->buffer = TALLOC_ZERO_ARRAY(get_talloc_ctx(), uint16, len);
+       if (str->buffer == NULL) {
                smb_panic("init_unistr2: malloc fail\n");
                return;
        }
 
+       /* Ensure len is the length in *bytes* */
+       len *= sizeof(uint16);
+
        /*
         * The UNISTR2 must be initialized !!!
         * jfm, 7/7/2001.
@@ -906,7 +856,7 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags)
        if (buf) {
                rpcstr_push((char *)str->buffer, buf, len, STR_TERMINATE);
                num_chars = strlen_w(str->buffer);
-               if (flags == STR_TERMINATE || flags == UNI_MAXLEN_TERMINATE) {
+               if (flags == UNI_STR_TERMINATE || flags == UNI_MAXLEN_TERMINATE) {
                        num_chars++;
                }
        }
@@ -914,10 +864,32 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags)
        str->uni_max_len = num_chars;
        str->offset = 0;
        str->uni_str_len = num_chars;
-       if (num_chars && (flags == UNI_MAXLEN_TERMINATE))
+       if ( num_chars && ((flags == UNI_MAXLEN_TERMINATE) || (flags == UNI_BROKEN_NON_NULL)) )
                str->uni_max_len++;
 }
 
+/*******************************************************************
+ Inits a UNISTR4 structure.
+********************************************************************/
+
+void init_unistr4(UNISTR4 *uni4, const char *buf, enum unistr2_term_codes flags)
+{
+       uni4->string = TALLOC_P( get_talloc_ctx(), UNISTR2 );
+       init_unistr2( uni4->string, buf, flags );
+
+       uni4->length = 2 * (uni4->string->uni_str_len);
+       uni4->size   = 2 * (uni4->string->uni_max_len);
+}
+
+void init_unistr4_w( TALLOC_CTX *ctx, UNISTR4 *uni4, const smb_ucs2_t *buf )
+{
+       uni4->string = TALLOC_P( ctx, UNISTR2 );
+       init_unistr2_w( ctx, uni4->string, buf );
+
+       uni4->length = 2 * (uni4->string->uni_str_len);
+       uni4->size   = 2 * (uni4->string->uni_max_len);
+}
+
 /** 
  *  Inits a UNISTR2 structure.
  *  @param  ctx talloc context to allocate string on
@@ -928,8 +900,6 @@ void init_unistr2(UNISTR2 *str, const char *buf, enum unistr2_term_codes flags)
 void init_unistr2_w(TALLOC_CTX *ctx, UNISTR2 *str, const smb_ucs2_t *buf)
 {
        uint32 len = strlen_w(buf);
-       uint32 max_len = len;
-       uint32 alloc_len;
 
        ZERO_STRUCTP(str);
 
@@ -938,13 +908,8 @@ void init_unistr2_w(TALLOC_CTX *ctx, UNISTR2 *str, const smb_ucs2_t *buf)
        str->offset = 0;
        str->uni_str_len = len;
 
-       if (max_len < MAX_UNISTRLEN)
-               max_len = MAX_UNISTRLEN;
-
-       alloc_len = (max_len + 1) * sizeof(uint16);
-
-       str->buffer = (uint16 *)talloc_zero(ctx, alloc_len);
-       if ((str->buffer == NULL) && (alloc_len > 0)) {
+       str->buffer = TALLOC_ZERO_ARRAY(ctx, uint16, len + 1);
+       if (str->buffer == NULL) {
                smb_panic("init_unistr2_w: malloc fail\n");
                return;
        }
@@ -993,10 +958,10 @@ void init_unistr2_from_unistr(UNISTR2 *to, const UNISTR *from)
        to->uni_str_len = i;
 
        /* allocate the space and copy the string buffer */
-       to->buffer = (uint16 *)talloc_zero(get_talloc_ctx(), sizeof(uint16)*(to->uni_str_len));
+       to->buffer = TALLOC_ZERO_ARRAY(get_talloc_ctx(), uint16, i);
        if (to->buffer == NULL)
                smb_panic("init_unistr2_from_unistr: malloc fail\n");
-       memcpy(to->buffer, from->buffer, to->uni_max_len*sizeof(uint16));
+       memcpy(to->buffer, from->buffer, i*sizeof(uint16));
        return;
 }
 
@@ -1015,12 +980,67 @@ void init_unistr2_from_datablob(UNISTR2 *str, DATA_BLOB *blob)
        str->uni_str_len = blob->length / sizeof(uint16);
        str->uni_max_len = str->uni_str_len;
        str->offset = 0;
-       str->buffer = (uint16 *) memdup(blob->data, blob->length);
+       if (blob->length) {
+               str->buffer = (uint16 *) memdup(blob->data, blob->length);
+       } else {
+               str->buffer = NULL;
+       }
        if ((str->buffer == NULL) && (blob->length > 0)) {
                smb_panic("init_unistr2_from_datablob: malloc fail\n");
        }
 }
 
+/*******************************************************************
+ UNISTR2* are a little different in that the pointer and the UNISTR2
+ are not necessarily read/written back to back.  So we break it up 
+ into 2 separate functions.
+ See SPOOL_USER_1 in include/rpc_spoolss.h for an example.
+********************************************************************/
+
+BOOL prs_io_unistr2_p(const char *desc, prs_struct *ps, int depth, UNISTR2 **uni2)
+{
+       uint32 data_p;
+
+       /* caputure the pointer value to stream */
+
+       data_p = *uni2 ? 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 ( !(*uni2 = PRS_ALLOC_MEM(ps, UNISTR2, 1)) )
+                       return False;
+       }
+
+       return True;
+}
+
+/*******************************************************************
+ now read/write the actual UNISTR2.  Memory for the UNISTR2 (but
+ not UNISTR2.buffer) has been allocated previously by prs_unistr2_p()
+********************************************************************/
+
+BOOL prs_io_unistr2(const char *desc, prs_struct *ps, int depth, UNISTR2 *uni2 )
+{
+       /* just return true if there is no pointer to deal with.
+          the memory must have been previously allocated on unmarshalling
+          by prs_unistr2_p() */
+
+       if ( !uni2 )
+               return True;
+
+       /* just pass off to smb_io_unstr2() passing the uni2 address as 
+          the pointer (like you would expect) */
+
+       return smb_io_unistr2( desc, uni2, uni2 ? 1 : 0, ps, depth );
+}
+
 /*******************************************************************
  Reads or writes a UNISTR2 structure.
  XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
@@ -1064,84 +1084,167 @@ BOOL smb_io_unistr2(const char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *
        return True;
 }
 
+/*******************************************************************
+ now read/write UNISTR4
+********************************************************************/
 
-/*
-  initialise a UNISTR_ARRAY from a char**
-*/
-BOOL init_unistr2_array(UNISTR2_ARRAY *array, 
-                      uint32 count, const char **strings)
+BOOL prs_unistr4(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
 {
-       unsigned int i;
-
-       array->count = count;
-       array->ref_id = count?1:0;
-       if (array->count == 0) {
-               return True;
-       }
+       prs_debug(ps, depth, desc, "prs_unistr4");
+       depth++;
 
-       array->strings = (UNISTR2_ARRAY_EL *)talloc_zero(get_talloc_ctx(), count * sizeof(UNISTR2_ARRAY_EL));
-       if (!array->strings) {
+       if ( !prs_uint16("length", ps, depth, &uni4->length ))
                return False;
-       }
+       if ( !prs_uint16("size", ps, depth, &uni4->size ))
+               return False;
+               
+       if ( !prs_pointer( desc, ps, depth, (void**)&uni4->string, sizeof(UNISTR2), (PRS_POINTER_CAST)prs_io_unistr2 ) )
+               return False;
+               
+       return True;
+}
 
-       for (i=0;i<count;i++) {
-               init_unistr2(&array->strings[i].string, strings[i], UNI_FLAGS_NONE);
-               array->strings[i].size = array->strings[i].string.uni_max_len*2;
-               array->strings[i].length = array->strings[i].size;
-               array->strings[i].ref_id = 1;
-       }
+/*******************************************************************
+ now read/write UNISTR4 header
+********************************************************************/
 
+BOOL prs_unistr4_hdr(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
+{
+       prs_debug(ps, depth, desc, "prs_unistr4_hdr");
+       depth++;
+
+       if ( !prs_uint16("length", ps, depth, &uni4->length) )
+               return False;
+       if ( !prs_uint16("size", ps, depth, &uni4->size) )
+               return False;
+       if ( !prs_io_unistr2_p(desc, ps, depth, &uni4->string) )
+               return False;
+               
        return True;
 }
 
 /*******************************************************************
- Reads or writes a UNISTR2_ARRAY structure.
+ now read/write UNISTR4 string
 ********************************************************************/
-BOOL smb_io_unistr2_array(const char *desc, UNISTR2_ARRAY *array, prs_struct *ps, int depth)
-{
-       unsigned int i;
 
-       prs_debug(ps, depth, desc, "smb_io_unistr2_array");
+BOOL prs_unistr4_str(const char *desc, prs_struct *ps, int depth, UNISTR4 *uni4)
+{
+       prs_debug(ps, depth, desc, "prs_unistr4_str");
        depth++;
 
-       if(!prs_uint32("ref_id", ps, depth, &array->ref_id))
+       if ( !prs_io_unistr2(desc, ps, depth, uni4->string) )
                return False;
+               
+       return True;
+}
 
-       if (! array->ref_id) {
-               return True;
-       }
+/*******************************************************************
+ Reads or writes a UNISTR4_ARRAY structure.
+********************************************************************/
+
+BOOL prs_unistr4_array(const char *desc, prs_struct *ps, int depth, UNISTR4_ARRAY *array )
+{
+       unsigned int i;
+
+       prs_debug(ps, depth, desc, "prs_unistr4_array");
+       depth++;
 
        if(!prs_uint32("count", ps, depth, &array->count))
                return False;
 
-       if (array->count == 0) {
+       if ( array->count == 0 ) 
                return True;
-       }
-
+       
        if (UNMARSHALLING(ps)) {
-               array->strings = talloc_zero(get_talloc_ctx(), array->count * sizeof(array->strings[0]));
-       }
-       if (! array->strings) {
-               return False;
-       }
-
-       for (i=0;i<array->count;i++) {
-               if(!prs_uint16("length", ps, depth, &array->strings[i].length))
+               if ( !(array->strings = TALLOC_ZERO_ARRAY( get_talloc_ctx(), UNISTR4, array->count)) )
                        return False;
-               if(!prs_uint16("size", ps, depth, &array->strings[i].size))
-                       return False;
-               if(!prs_uint32("ref_id", ps, depth, &array->strings[i].ref_id))
+       }
+       
+       /* write the headers and then the actual string buffer */
+       
+       for ( i=0; i<array->count; i++ ) {
+               if ( !prs_unistr4_hdr( "string", ps, depth, &array->strings[i]) )
                        return False;
        }
 
        for (i=0;i<array->count;i++) {
-               if (! smb_io_unistr2("string", &array->strings[i].string, array->strings[i].ref_id, ps, depth)
+               if ( !prs_unistr4_str("string", ps, depth, &array->strings[i]) 
                        return False;
        }
        
        return True;
 }
 
+/********************************************************************
+  initialise a UNISTR_ARRAY from a char**
+********************************************************************/
+
+BOOL init_unistr4_array( UNISTR4_ARRAY *array, uint32 count, const char **strings )
+{
+       unsigned int i;
+
+       array->count = count;
+
+       if ( array->count == 0 )
+               return True;
+
+       /* allocate memory for the array of UNISTR4 objects */
+
+       if ( !(array->strings = TALLOC_ZERO_ARRAY(get_talloc_ctx(), UNISTR4, count )) )
+               return False;
+
+       for ( i=0; i<count; i++ ) 
+               init_unistr4( &array->strings[i], strings[i], UNI_STR_TERMINATE );
+
+       return True;
+}
+
+BOOL smb_io_lockout_string_hdr(const char *desc, HDR_LOCKOUT_STRING *hdr_account_lockout, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "smb_io_lockout_string_hdr");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+
+       if(!prs_uint16("size", ps, depth, &hdr_account_lockout->size))
+               return False;
+       if(!prs_uint16("length", ps, depth, &hdr_account_lockout->length))
+               return False;
+       if(!prs_uint32("buffer", ps, depth, &hdr_account_lockout->buffer))
+               return False;
+
+       return True;
+}
+
+BOOL smb_io_account_lockout_str(const char *desc, LOCKOUT_STRING *account_lockout, uint32 buffer, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "smb_io_account_lockout_string");
+       depth++;
+
+       if(!prs_uint32("array_size", ps, depth, &account_lockout->array_size))
+               return False;
+
+       if(!prs_uint32("offset", ps, depth, &account_lockout->offset))
+               return False;
+       if(!prs_uint32("length", ps, depth, &account_lockout->length))
+               return False;
+
+       if (!prs_uint64("lockout_duration", ps, depth, &account_lockout->lockout_duration))
+               return False;
+       if (!prs_uint64("reset_count", ps, depth, &account_lockout->reset_count))
+               return False;
+       if (!prs_uint32("bad_attempt_lockout", ps, depth, &account_lockout->bad_attempt_lockout))
+               return False;
+       if (!prs_uint32("dummy", ps, depth, &account_lockout->dummy))
+               return False;
+#if 0
+       if(!prs_uint16s (False, "bindata", ps, depth, &account_lockout->bindata, length))
+               return False;
+#endif
+
+       return True;
+}
 
 /*******************************************************************
  Inits a DOM_RID2 structure.
@@ -1605,28 +1708,19 @@ BOOL smb_io_pol_hnd(const char *desc, POLICY_HND *pol, prs_struct *ps, int depth
 
 void init_unistr3(UNISTR3 *str, const char *buf)
 {
-       size_t len;
-
        if (buf == NULL) {
                str->uni_str_len=0;
                str->str.buffer = NULL;
                return;
        }
 
-       len = strlen(buf) + 1;
-
-       str->uni_str_len=len;
-
-       if (len < MAX_UNISTRLEN)
-               len = MAX_UNISTRLEN;
+       str->uni_str_len = strlen(buf) + 1;
 
-       len *= sizeof(uint16);
-
-       str->str.buffer = (uint16 *)talloc_zero(get_talloc_ctx(), len);
+       str->str.buffer = TALLOC_ZERO_ARRAY(get_talloc_ctx(), uint16, str->uni_str_len);
        if (str->str.buffer == NULL)
                smb_panic("init_unistr3: malloc fail\n");
 
-       rpcstr_push((char *)str->str.buffer, buf, len, STR_TERMINATE);
+       rpcstr_push((char *)str->str.buffer, buf, str->uni_str_len * sizeof(uint16), STR_TERMINATE);
 }
 
 /*******************************************************************
@@ -1646,6 +1740,11 @@ BOOL smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth)
        
        if(!prs_uint32("uni_str_len", ps, depth, &name->uni_str_len))
                return False;
+               
+       /* we're done if there is no string */
+       
+       if ( name->uni_str_len == 0 )
+               return True;
 
        /* don't know if len is specified by uni_str_len member... */
        /* assume unicode string is unicode-null-terminated, instead */
@@ -1656,7 +1755,6 @@ BOOL smb_io_unistr3(const char *desc, UNISTR3 *name, prs_struct *ps, int depth)
        return True;
 }
 
-
 /*******************************************************************
  Stream a uint64_struct
  ********************************************************************/
@@ -1683,22 +1781,45 @@ BOOL smb_io_bufhdr2(const char *desc, BUFHDR2 *hdr, prs_struct *ps, int depth)
 }
 
 /*******************************************************************
-reads or writes a BUFFER4 structure.
+reads or writes a BUFHDR4 structure.
 ********************************************************************/
-BOOL smb_io_buffer4(const char *desc, BUFFER4 *buf4, uint32 buffer, prs_struct *ps, int depth)
+BOOL smb_io_bufhdr4(const char *desc, BUFHDR4 *hdr, prs_struct *ps, int depth)
 {
-       prs_debug(ps, depth, desc, "smb_io_buffer4");
+       prs_debug(ps, depth, desc, "smb_io_bufhdr4");
        depth++;
 
        prs_align(ps);
-       prs_uint32("buf_len", ps, depth, &(buf4->buf_len));
+       prs_uint32("size", ps, depth, &hdr->size);
+       prs_uint32("buffer", ps, depth, &hdr->buffer);
 
-       if (buf4->buf_len > MAX_BUFFERLEN)
-       {
-               buf4->buf_len = MAX_BUFFERLEN;
+       return True;
+}
+
+/*******************************************************************
+reads or writes a RPC_DATA_BLOB structure.
+********************************************************************/
+
+BOOL smb_io_rpc_blob(const char *desc, RPC_DATA_BLOB *blob, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "smb_io_rpc_blob");
+       depth++;
+
+       prs_align(ps);
+       if ( !prs_uint32("buf_len", ps, depth, &blob->buf_len) )
+               return False;
+
+       if ( blob->buf_len == 0 )
+               return True;
+
+       if (UNMARSHALLING(ps)) {
+               blob->buffer = PRS_ALLOC_MEM(ps, uint8, blob->buf_len);
+               if (!blob->buffer) {
+                       return False;
+               }
        }
 
-       prs_uint8s(True, "buffer", ps, depth, buf4->buffer, buf4->buf_len);
+       if ( !prs_uint8s(True, "buffer", ps, depth, blob->buffer, blob->buf_len) )
+               return False;
 
        return True;
 }
@@ -1731,3 +1852,22 @@ BOOL make_bufhdr2(BUFHDR2 *hdr, uint32 info_level, uint32 length, uint32 buffer)
 
        return True;
 }
+
+/*******************************************************************
+return the length of a UNISTR string.
+********************************************************************/  
+
+uint32 str_len_uni(UNISTR *source)
+{
+       uint32 i=0;
+
+       if (!source->buffer)
+               return 0;
+
+       while (source->buffer[i])
+               i++;
+
+       return i;
+}
+
+