r26439: Require tdr_pull users to specify a smb_iconv convenience context.
[bbaumbach/samba-autobuild/.git] / source4 / lib / tdr / tdr.c
index e1e54622acaece74d4ba67671959af85a1538a8c..f75cac9810ced35160bab17f03e6a6d3808bcb08 100644 (file)
@@ -8,7 +8,7 @@
    
    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"
+#include "system/filesys.h"
 #include "system/network.h"
+#include "tdr/tdr.h"
+#include "param/param.h"
 
 #define TDR_BASE_MARSHALL_SIZE 1024
 
-#define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->offset+(n)))
+#define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->data.length+(n)))
 
 #define TDR_PULL_NEED_BYTES(tdr, n) do { \
        if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \
 #define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs)
 #define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs))
 #define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs))
-#define TDR_IVALS(tdr, ofs) (TDR_BE(tdr)?RIVALS(tdr->data.data,ofs):IVALS(tdr->data.data,ofs))
 #define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v)
 #define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0)
 #define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0)
-#define TDR_SIVALS(tdr, ofs, v) do { if (TDR_BE(tdr))  { RSIVALS(tdr->data.data,ofs,v); } else SIVALS(tdr->data.data,ofs,v); } while (0)
 
-/*
+/**
   expand the available space in the buffer to 'size'
 */
 NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
@@ -63,7 +63,7 @@ NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
 }
 
 
-NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, uint8_t *v)
+NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v)
 {
        TDR_PULL_NEED_BYTES(tdr, 1);
        *v = TDR_CVAL(tdr, tdr->offset);
@@ -74,8 +74,8 @@ NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, uint8_t *v)
 NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v)
 {
        TDR_PUSH_NEED_BYTES(tdr, 1);
-       TDR_SCVAL(tdr, tdr->offset, *v);
-       tdr->offset += 1;
+       TDR_SCVAL(tdr, tdr->data.length, *v);
+       tdr->data.length += 1;
        return NT_STATUS_OK;
 }
 
@@ -85,7 +85,7 @@ NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v)
        return NT_STATUS_OK;
 }
 
-NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, uint16_t *v)
+NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
 {
        TDR_PULL_NEED_BYTES(tdr, 2);
        *v = TDR_SVAL(tdr, tdr->offset);
@@ -96,8 +96,8 @@ NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, uint16_t *v)
 NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v)
 {
        TDR_PUSH_NEED_BYTES(tdr, 2);
-       TDR_SSVAL(tdr, tdr->offset, *v);
-       tdr->offset += 2;
+       TDR_SSVAL(tdr, tdr->data.length, *v);
+       tdr->data.length += 2;
        return NT_STATUS_OK;
 }
 
@@ -107,7 +107,7 @@ NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v)
        return NT_STATUS_OK;
 }
 
-NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, uint32_t *v)
+NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v)
 {
        TDR_PULL_NEED_BYTES(tdr, 4);
        *v = TDR_IVAL(tdr, tdr->offset);
@@ -118,8 +118,8 @@ NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, uint32_t *v)
 NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v)
 {
        TDR_PUSH_NEED_BYTES(tdr, 4);
-       TDR_SIVAL(tdr, tdr->offset, *v);
-       tdr->offset += 4;
+       TDR_SIVAL(tdr, tdr->data.length, *v);
+       tdr->data.length += 4;
        return NT_STATUS_OK;
 }
 
@@ -129,7 +129,7 @@ NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v)
        return NT_STATUS_OK;
 }
 
-NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, const char **v, uint32_t length, uint32_t el_size, int chset)
+NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
 {
        int ret;
 
@@ -148,13 +148,13 @@ NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, const char **v, uint32_t length,
        }
 
        if (length == 0) {
-               *v = talloc_strdup(tdr, "");
+               *v = talloc_strdup(ctx, "");
                return NT_STATUS_OK;
        }
 
        TDR_PULL_NEED_BYTES(tdr, el_size*length);
        
-       ret = convert_string_talloc(tdr, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, discard_const_p(void *, v));
+       ret = convert_string_talloc(ctx, lp_iconv_convenience(global_loadparm), chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, discard_const_p(void *, v));
 
        if (ret == -1) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -165,14 +165,18 @@ NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, const char **v, uint32_t length,
        return NT_STATUS_OK;
 }
 
-NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, int chset)
+NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
 {
        ssize_t ret, required;
 
+       if (length == -1) {
+               length = strlen(*v) + 1; /* Extra element for null character */
+       }
+
        required = el_size * length;
        TDR_PUSH_NEED_BYTES(tdr, required);
 
-       ret = convert_string(CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->offset, required);
+       ret = convert_string(tdr->iconv_convenience, CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->data.length, required);
 
        if (ret == -1) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -180,34 +184,35 @@ NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length,
 
        /* Make sure the remaining part of the string is filled with zeroes */
        if (ret < required) {
-               memset(tdr->data.data+tdr->offset+ret, 0, required-ret);
+               memset(tdr->data.data+tdr->data.length+ret, 0, required-ret);
        }
        
-       tdr->offset += required;
+       tdr->data.length += required;
                                                 
        return NT_STATUS_OK;
 }
 
-NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, int chset)
+NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
 {
        tdr->print(tdr, "%-25s: %s", name, *v);
        return NT_STATUS_OK;
 }
 
-/*
+/**
   pull a ipv4address
 */
-NTSTATUS tdr_pull_ipv4address(struct tdr_pull *tdr, const char **address)
+NTSTATUS tdr_pull_ipv4address(struct tdr_pull *tdr, TALLOC_CTX *ctx, 
+                                                         const char **address)
 {
-       struct ipv4_addr in;
-       TDR_CHECK(tdr_pull_uint32(tdr, &in.addr));
-       in.addr = htonl(in.addr);
-       *address = talloc_strdup(tdr, sys_inet_ntoa(in));
+       struct in_addr in;
+       TDR_CHECK(tdr_pull_uint32(tdr, ctx, &in.s_addr));
+       in.s_addr = htonl(in.s_addr);
+       *address = talloc_strdup(tdr, inet_ntoa(in));
        NT_STATUS_HAVE_NO_MEMORY(*address);
        return NT_STATUS_OK;
 }
 
-/*
+/**
   push a ipv4address
 */
 NTSTATUS tdr_push_ipv4address(struct tdr_push *tdr, const char **address)
@@ -217,7 +222,7 @@ NTSTATUS tdr_push_ipv4address(struct tdr_push *tdr, const char **address)
        return NT_STATUS_OK;
 }
 
-/*
+/**
   print a ipv4address
 */
 NTSTATUS tdr_print_ipv4address(struct tdr_print *tdr, const char *name, 
@@ -227,10 +232,10 @@ NTSTATUS tdr_print_ipv4address(struct tdr_print *tdr, const char *name,
        return NT_STATUS_OK;
 }
 
-/*
+/**
   parse a hyper
 */
-NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, uint64_t *v)
+NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v)
 {
        TDR_PULL_NEED_BYTES(tdr, 8);
        *v = TDR_IVAL(tdr, tdr->offset);
@@ -239,21 +244,19 @@ NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, uint64_t *v)
        return NT_STATUS_OK;
 }
 
-/*
+/**
   push a hyper
 */
 NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v)
 {
        TDR_PUSH_NEED_BYTES(tdr, 8);
-       TDR_SIVAL(tdr, tdr->offset, ((*v) & 0xFFFFFFFF));
-       TDR_SIVAL(tdr, tdr->offset+4, ((*v)>>32));
-       tdr->offset += 8;
+       TDR_SIVAL(tdr, tdr->data.length, ((*v) & 0xFFFFFFFF));
+       TDR_SIVAL(tdr, tdr->data.length+4, ((*v)>>32));
+       tdr->data.length += 8;
        return NT_STATUS_OK;
 }
 
-
-
-/*
+/**
   push a NTTIME
 */
 NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
@@ -262,16 +265,16 @@ NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
        return NT_STATUS_OK;
 }
 
-/*
+/**
   pull a NTTIME
 */
-NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, NTTIME *t)
+NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t)
 {
-       TDR_CHECK(tdr_pull_hyper(tdr, t));
+       TDR_CHECK(tdr_pull_hyper(tdr, ctx, t));
        return NT_STATUS_OK;
 }
 
-/*
+/**
   push a time_t
 */
 NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
@@ -279,13 +282,13 @@ NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
        return tdr_push_uint32(tdr, (uint32_t *)t);
 }
 
-/*
+/**
   pull a time_t
 */
-NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, time_t *t)
+NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t)
 {
        uint32_t tt;
-       TDR_CHECK(tdr_pull_uint32(tdr, &tt));
+       TDR_CHECK(tdr_pull_uint32(tdr, ctx, &tt));
        *t = tt;
        return NT_STATUS_OK;
 }
@@ -318,7 +321,7 @@ NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB
        return NT_STATUS_OK;
 }
 
-#define TDR_ALIGN(tdr,n) (((tdr)->offset & ((n)-1)) == 0?0:((n)-((tdr)->offset&((n)-1))))
+#define TDR_ALIGN(l,n) (((l) & ((n)-1)) == 0?0:((n)-((l)&((n)-1))))
 
 /*
   push a DATA_BLOB onto the wire. 
@@ -326,32 +329,32 @@ NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB
 NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob)
 {
        if (tdr->flags & TDR_ALIGN2) {
-               blob->length = TDR_ALIGN(tdr, 2);
+               blob->length = TDR_ALIGN(tdr->data.length, 2);
        } else if (tdr->flags & TDR_ALIGN4) {
-               blob->length = TDR_ALIGN(tdr, 4);
+               blob->length = TDR_ALIGN(tdr->data.length, 4);
        } else if (tdr->flags & TDR_ALIGN8) {
-               blob->length = TDR_ALIGN(tdr, 8);
+               blob->length = TDR_ALIGN(tdr->data.length, 8);
        }
 
        TDR_PUSH_NEED_BYTES(tdr, blob->length);
        
-       memcpy(tdr->data.data+tdr->offset, blob->data, blob->length);
+       memcpy(tdr->data.data+tdr->data.length, blob->data, blob->length);
        return NT_STATUS_OK;
 }
 
 /*
   pull a DATA_BLOB from the wire. 
 */
-NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, DATA_BLOB *blob)
+NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob)
 {
        uint32_t length;
 
        if (tdr->flags & TDR_ALIGN2) {
-               length = TDR_ALIGN(tdr, 2);
+               length = TDR_ALIGN(tdr->offset, 2);
        } else if (tdr->flags & TDR_ALIGN4) {
-               length = TDR_ALIGN(tdr, 4);
+               length = TDR_ALIGN(tdr->offset, 4);
        } else if (tdr->flags & TDR_ALIGN8) {
-               length = TDR_ALIGN(tdr, 8);
+               length = TDR_ALIGN(tdr->offset, 8);
        } else if (tdr->flags & TDR_REMAINING) {
                length = tdr->data.length - tdr->offset;
        } else {
@@ -368,3 +371,66 @@ NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, DATA_BLOB *blob)
        tdr->offset += length;
        return NT_STATUS_OK;
 }
+
+struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic)
+{
+       struct tdr_push *push = talloc_zero(mem_ctx, struct tdr_push);
+
+       if (push == NULL)
+               return NULL;
+
+       push->iconv_convenience = talloc_reference(push, ic);
+
+       return push;
+}
+
+struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic)
+{
+       struct tdr_pull *pull = talloc_zero(mem_ctx, struct tdr_pull);
+
+       if (pull == NULL)
+               return NULL;
+
+       pull->iconv_convenience = talloc_reference(pull, ic);
+
+       return pull;
+}
+
+NTSTATUS tdr_push_to_fd(int fd, struct smb_iconv_convenience *iconv_convenience, tdr_push_fn_t push_fn, const void *p)
+{
+       struct tdr_push *push = tdr_push_init(NULL, iconv_convenience);
+
+       if (push == NULL)
+               return NT_STATUS_NO_MEMORY;
+
+       if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+               DEBUG(1, ("Error pushing data\n"));
+               talloc_free(push);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       if (write(fd, push->data.data, push->data.length) < push->data.length) {
+               DEBUG(1, ("Error writing all data\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       talloc_free(push);
+
+       return NT_STATUS_OK;
+}
+
+void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+       va_list ap;
+       char *s = NULL;
+       int i;
+
+       va_start(ap, format);
+       vasprintf(&s, format, ap);
+       va_end(ap);
+
+       for (i=0;i<tdr->level;i++) { DEBUG(0,("    ")); }
+
+       DEBUG(0,("%s\n", s));
+       free(s);
+}