rawtrans align... v4-0-recv-helper
authorStefan Metzmacher <metze@samba.org>
Wed, 16 Jul 2008 12:56:15 +0000 (14:56 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 14 Aug 2008 11:35:34 +0000 (13:35 +0200)
source/libcli/raw/rawtrans.c

index b225a35a3c77d757e683b8b4ae9ef95d21808929..9361be54ec168e621173aa572ab956c20b27b1af 100644 (file)
@@ -22,6 +22,7 @@
 #include "lib/util/dlinklist.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/raw/raw_proto.h"
+#include "librpc/ndr/libndr.h"
 
 #define TORTURE_TRANS_DATA 0
 
@@ -76,6 +77,8 @@ struct raw_trans_ops {
 struct raw_trans_state {
        uint8_t command;
 
+       uint8_t align;
+
 //     uint32_t num_req;
        uint32_t params_left;
        uint32_t data_left;
@@ -85,12 +88,15 @@ struct raw_trans_state {
        uint32_t data_recvd;
 
        struct {
+               uint8_t setup_max;
                uint8_t setup_count;
                uint8_t setup_vwv_ofs;
+               uint32_t params_max;
                uint32_t params_total;
                DATA_BLOB params_chunk;
                uint32_t params_ofs;
                uint32_t params_disp;
+               uint32_t data_max;
                uint32_t data_total;
                DATA_BLOB data_chunk;
                uint32_t data_ofs;
@@ -120,21 +126,34 @@ static enum smbcli_request_state raw_trans_recv_helper(struct smbcli_request *re
 
 static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
                                     struct smb_nttrans *parms,
+                                    uint8_t align,
                                     const struct raw_trans_ops *ops,
                                     void *ops_private)
 {
        struct raw_trans_state *s;
        size_t space_left;
        uint32_t ofs;
+       uint8_t zeros[16];
+       DATA_BLOB params_align;
+       DATA_BLOB data_align;
+
+       ZERO_STRUCT(zeros);
 
        s = talloc_zero(req, struct raw_trans_state);
        if (!s) {
                goto nomem;
        }
 
+       s->align = align;
+
        s->ops = ops;
        s->ops_private = ops_private;
 
+       s->req.setup_max = parms->in.max_setup;
+       s->req.params_max = parms->in.max_param;
+       s->req.data_max = parms->in.max_data;
+
+       s->req.setup_count = parms->in.setup_count;
        s->req.params_total = parms->in.params.length;
        s->req.data_total = parms->in.data.length;
 
@@ -146,8 +165,18 @@ static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
        /* see how much bytes of the params block we can ship in the first request */
        space_left = raw_trans_space_left(req);
 
-/*TODO: align params */
+       /* params alignment */
+       params_align.data = zeros;
+       params_align.length = ndr_align_size(ofs, s->align);
+       if (params_align.length > space_left) {
+               params_align.length = space_left;
+               space_left = 0;
+       } else {
+               space_left -= params_align.length;
+               ofs += params_align.length;
+       }
 
+       /* params */
        s->req.params_disp = 0;
        s->req.params_chunk.length = MIN(s->params_left, space_left);
        s->req.params_chunk.data = parms->in.params.data + s->req.params_disp;
@@ -168,6 +197,7 @@ static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
 
        /* see how much bytes of the data block we can ship in the first request */
        space_left -= s->req.params_chunk.length;
+       ofs += s->req.params_chunk.length;
 
 #if TORTURE_TRANS_DATA
        if (space_left > 1) {
@@ -175,12 +205,22 @@ static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
        }
 #endif
 
-/*TODO: align data */
+       /* data alignment */
+       data_align.data = zeros;
+       data_align.length = ndr_align_size(ofs, s->align);
+       if (data_align.length > space_left) {
+               data_align.length = space_left;
+               space_left = 0;
+       } else {
+               space_left -= data_align.length;
+               ofs += data_align.length;
+       }
 
+       /* data */
        s->req.data_disp = 0;
        s->req.data_chunk.length = MIN(s->data_left, space_left);
        s->req.data_chunk.data = parms->in.data.data + s->req.data_disp;
-       s->req.data_ofs = s->req.params_ofs + s->req.params_chunk.length;
+       s->req.data_ofs = ofs;
 
        s->data_left -= s->req.data_chunk.length;
 
@@ -195,6 +235,9 @@ static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
                       parms->in.data.length);
        }
 
+       space_left -= s->req.data_chunk.length;
+       ofs += s->req.data_chunk.length;
+
        if (!s->ops->format_first(req, s)) {
                goto failed;
        }
@@ -205,10 +248,9 @@ static NTSTATUS raw_trans_ship_first(struct smbcli_request *req,
                       parms->in.setup_count * VWV(1));
        }
 
-/*TODO: grow alloc */
-/*TODO: params align */
+       smbcli_req_append_blob(req, &params_align);
        smbcli_req_append_blob(req, &s->req.params_chunk);
-/*TODO: data align */
+       smbcli_req_append_blob(req, &data_align);
        smbcli_req_append_blob(req, &s->req.data_chunk);
 
        /* add the helper which will check that all multi-part replies are
@@ -233,6 +275,11 @@ static enum smbcli_request_state raw_trans_ship_next(struct smbcli_request *req,
        struct smbcli_request *req2 = NULL;
        size_t space_left;
        uint32_t ofs;
+       uint8_t zeros[16];
+       DATA_BLOB params_align;
+       DATA_BLOB data_align;
+
+       ZERO_STRUCT(zeros);
 
        if (!s->ops->create_next(req, &req2, s)) {
                goto failed;
@@ -243,7 +290,16 @@ static enum smbcli_request_state raw_trans_ship_next(struct smbcli_request *req,
        /* see how much bytes of the params block we can ship in the first request */
        space_left = raw_trans_space_left(req2);
 
-/*TODO: align params */
+       /* params alignment */
+       params_align.data = zeros;
+       params_align.length = ndr_align_size(ofs, s->align);
+       if (params_align.length > space_left) {
+               params_align.length = space_left;
+               space_left = 0;
+       } else {
+               space_left -= params_align.length;
+               ofs += params_align.length;
+       }
 
        s->req.params_disp = s->io.in.params.length - s->params_left;
        s->req.params_chunk.length = MIN(s->params_left, space_left);
@@ -254,6 +310,7 @@ static enum smbcli_request_state raw_trans_ship_next(struct smbcli_request *req,
 
        /* see how much bytes of the data block we can ship in the first request */
        space_left -= s->req.params_chunk.length;
+       ofs += s->req.params_chunk.length;
 
 #if TORTURE_TRANS_DATA
        if (space_left > 1) {
@@ -261,24 +318,35 @@ static enum smbcli_request_state raw_trans_ship_next(struct smbcli_request *req,
        }
 #endif
 
-/*TODO: align data */
+       /* data alignment */
+       data_align.data = zeros;
+       data_align.length = ndr_align_size(ofs, s->align);
+       if (data_align.length > space_left) {
+               data_align.length = space_left;
+               space_left = 0;
+       } else {
+               space_left -= data_align.length;
+               ofs += data_align.length;
+       }
 
        s->req.data_disp = s->io.in.data.length - s->data_left;
        s->req.data_chunk.length = MIN(s->data_left, space_left);
        s->req.data_chunk.data = s->io.in.data.data + s->req.data_disp;
-       s->req.data_ofs = s->req.params_ofs + s->req.params_chunk.length;
+       s->req.data_ofs = ofs;
 
        s->data_left -= s->req.data_chunk.length;
 
+       space_left -= s->req.data_chunk.length;
+       ofs += s->req.data_chunk.length;
+
        if (!s->ops->format_next(req, req2, s)) {
                goto failed;
        }
 
-/*TODO: grow alloc */
-/*TODO: params align */
-       smbcli_req_append_blob(req2, &s->req.params_chunk);
-/*TODO: data align */
-       smbcli_req_append_blob(req2, &s->req.data_chunk);
+       smbcli_req_append_blob(req, &params_align);
+       smbcli_req_append_blob(req, &s->req.params_chunk);
+       smbcli_req_append_blob(req, &data_align);
+       smbcli_req_append_blob(req, &s->req.data_chunk);
 
        /*
         * it's a one way request but we need
@@ -358,30 +426,30 @@ static enum smbcli_request_state raw_trans_recv_helper(struct smbcli_request *re
                goto failed;
        }
 
-       if (s->rep.setup_count > s->io.in.max_setup) {
+       if (s->rep.setup_count > s->req.setup_max) {
                DEBUG(1,("raw_trans_recv_helper: setup[%u] > max[%u]\n",
-                       s->rep.setup_count, s->io.in.max_setup));
+                       s->rep.setup_count, s->req.setup_max));
                req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
                goto failed;
        }
 
-       if (s->rep.params_total > s->io.in.max_param) {
+       if (s->rep.params_total > s->req.params_max) {
                DEBUG(1,("raw_trans_recv_helper: params[%u] > max[%u]\n",
-                       s->rep.params_total, s->io.in.max_param));
+                       s->rep.params_total, s->req.params_max));
                req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
                goto failed;
        }
 
-       if (s->rep.data_total > s->io.in.max_data) {
+       if (s->rep.data_total > s->req.data_max) {
                DEBUG(1,("raw_trans_recv_helper: data[%u] > max[%u]\n",
-                       s->rep.data_total, s->io.in.max_data));
+                       s->rep.data_total, s->req.data_max));
                req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
                goto failed;
        }
 
        if (s->num_rep == 1) {
                if (s->rep.setup_count > 0 &&
-                   s->io.in.max_setup != s->io.out.setup_count) {
+                   s->req.....max_setup != s->io.out.setup_count) {
                        s->io.out.setup = talloc_array(s, uint8_t,
                                                       s->rep.setup_count * VWV(1));
                        if (!s->io.out.setup) {
@@ -988,7 +1056,7 @@ struct smb_raw_nttrans_recv_state {
        struct smb_nttrans io;
 };
 
-NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
+NTSTATUS smb_raw_nttrans_old_recv(struct smbcli_request *req,
                              TALLOC_CTX *mem_ctx,
                              struct smb_nttrans *parms)
 {
@@ -1163,7 +1231,7 @@ failed:
  nttrans raw - only BLOBs used in this interface.
  at the moment we only handle a single primary request 
 ****************************************************************************/
-struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
+struct smbcli_request *smb_raw_nttrans_old_send(struct smbcli_tree *tree,
                                         struct smb_nttrans *parms)
 {
        struct smbcli_request *req; 
@@ -1387,16 +1455,171 @@ static enum smbcli_request_state smb_raw_nttrans_ship_rest(struct smbcli_request
 /****************************************************************************
   receive a SMB nttrans response allocating the necessary memory
   ****************************************************************************/
-NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree,
+NTSTATUS smb_raw_nttrans_old(struct smbcli_tree *tree,
                         TALLOC_CTX *mem_ctx,
                         struct smb_nttrans *parms)
 {
        struct smbcli_request *req;
 
-       req = smb_raw_nttrans_send(tree, parms);
+       req = smb_raw_nttrans_old_send(tree, parms);
        if (!req) {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       return smb_raw_nttrans_old_recv(req, mem_ctx, parms);
+}
+
+static bool raw_nttrans_format_first(struct smbcli_request *req,
+                                    struct raw_trans_state *s)
+{
+       struct smb_nttrans *parms = (struct smb_nttrans *)s->ops_private;
+
+       SCVAL(req->out.vwv,  0, s->req.setup_max);
+       SSVAL(req->out.vwv,  1, 0); /* reserved */
+       SIVAL(req->out.vwv,  3, s->req.params_total);
+       SIVAL(req->out.vwv,  7, s->req.data_total);
+       SIVAL(req->out.vwv, 11, s->req.params_max);
+       SIVAL(req->out.vwv, 15, s->req.data_max);
+       SIVAL(req->out.vwv, 19, s->req.params_chunk.length);
+       SIVAL(req->out.vwv, 23, s->req.params_ofs);
+       SIVAL(req->out.vwv, 27, s->req.data_chunk.length);
+       SIVAL(req->out.vwv, 31, s->req.data_ofs);
+       SCVAL(req->out.vwv, 35, s->req.setup_count);
+       SSVAL(req->out.vwv, 36, parms->in.function);
+
+       s->req.setup_vwv_ofs = VWV(19);
+
+       return true;
+}
+
+static bool raw_nttrans_create_next(struct smbcli_request *req,
+                                   struct smbcli_request **_req2,
+                                   struct raw_trans_state *s)
+{
+       struct smbcli_request *req2;
+
+       req2 = smbcli_request_setup(req->tree, SMBnttranss, 18, 0);
+       if (!req2) {
+               goto nomem;
+       }
+       req2->mid = req->mid;
+       SSVAL(req2->out.hdr, HDR_MID, req2->mid);
+
+       *_req2 = req2;
+       return true;
+
+nomem:
+       req->status = NT_STATUS_NO_MEMORY;
+       return false;
+}
+
+static bool raw_nttrans_format_next(struct smbcli_request *req,
+                                   struct smbcli_request *req2,
+                                   struct raw_trans_state *s)
+{
+       SSVAL(req2->out.vwv,0, 0); /* reserved */
+       SCVAL(req2->out.vwv,2, 0); /* reserved */
+       SIVAL(req2->out.vwv,3, s->req.params_total);
+       SIVAL(req2->out.vwv,7, s->req.data_total);
+       SIVAL(req2->out.vwv,11, s->req.params_chunk.length);
+       SIVAL(req2->out.vwv,15, s->req.params_ofs);
+       SIVAL(req2->out.vwv,19, s->req.params_disp);
+       SIVAL(req2->out.vwv,23, s->req.data_chunk.length);
+       SIVAL(req2->out.vwv,27, s->req.data_ofs);
+       SIVAL(req2->out.vwv,31, s->req.data_disp);
+       SCVAL(req2->out.vwv,35, 0); /* reserved */
+
+       return true;
+}
+
+static bool raw_nttrans_parse_rep(struct smbcli_request *req,
+                                 struct raw_trans_state *s)
+{
+       /* this is the first packet of the response */
+       SMBCLI_CHECK_MIN_WCT(req, 18);
+
+       /* 1-3 reserved */
+       s->rep.params_total     = IVAL(req->in.vwv, 3);
+       s->rep.data_total       = IVAL(req->in.vwv, 7);
+       s->rep.params_count     = IVAL(req->in.vwv, 11);
+       s->rep.params_ofs       = IVAL(req->in.vwv, 15);
+       s->rep.params_disp      = IVAL(req->in.vwv, 19);
+       s->rep.data_count       = IVAL(req->in.vwv, 23);
+       s->rep.data_ofs         = IVAL(req->in.vwv, 27);
+       s->rep.data_disp        = IVAL(req->in.vwv, 31);
+       s->rep.setup_count      = CVAL(req->in.vwv, 35);
+
+       return true;
+
+failed:
+       return false;
+}
+
+const struct raw_trans_ops raw_nttrans_ops = {
+       .format_first   = raw_nttrans_format_first,
+       .create_next    = raw_nttrans_create_next,
+       .format_next    = raw_nttrans_format_next,
+       .parse_rep      = raw_nttrans_parse_rep
+};
+
+struct smbcli_request *smb_raw_nttrans_send(struct smbcli_tree *tree,
+                                        struct smb_nttrans *parms)
+{
+       struct smbcli_request *req;
+       NTSTATUS status;
+
+//     return smb_raw_nttrans_old_send(tree, parms);
+
+       req = smbcli_request_setup(tree, SMBnttrans,
+                                  19 + parms->in.setup_count, 0);
+       if (!req) {
+               return NULL;
+       }
+
+       status = raw_trans_ship_first(req, parms, 4, &raw_nttrans_ops, parms);
+       if (!NT_STATUS_IS_OK(status)) {
+               smbcli_request_destroy(req);
+               return NULL;
+       }
+
+       return req;
+}
+
+NTSTATUS smb_raw_nttrans_recv(struct smbcli_request *req,
+                             TALLOC_CTX *mem_ctx,
+                             struct smb_nttrans *parms)
+{
+       struct raw_trans_state *s;
+
+//     return smb_raw_nttrans_old_recv(req, mem_ctx, parms);
+
+       if (!smbcli_request_receive(req) ||
+           smbcli_request_is_error(req)) {
+               goto failed;
+       }
+
+       s = talloc_get_type(req->recv_helper.private_data,
+                           struct raw_trans_state);
+
+       parms->out = s->io.out;
+       talloc_steal(mem_ctx, parms->out.setup);
+       talloc_steal(mem_ctx, parms->out.params.data);
+       talloc_steal(mem_ctx, parms->out.data.data);
+       talloc_free(s);
+
+       ZERO_STRUCT(req->recv_helper);
+
+failed:
+       return smbcli_request_destroy(req);
+}
+
+/****************************************************************************
+  receive a SMB nttrans response allocating the necessary memory
+  ****************************************************************************/
+NTSTATUS smb_raw_nttrans(struct smbcli_tree *tree,
+                        TALLOC_CTX *mem_ctx,
+                        struct smb_nttrans *parms)
+{
+       struct smbcli_request *req = smb_raw_nttrans_send(tree, parms);
        return smb_raw_nttrans_recv(req, mem_ctx, parms);
 }