r4383: in order to cope with overfilled buffers on trans2 findfirst we need to use...
[samba.git] / source4 / smb_server / trans2.c
index b75c8eb71a9900d555d94e5c15d04d505f3015ba..8aa60daa6df43d7028caa215b94fa73477eaf74b 100644 (file)
@@ -22,6 +22,7 @@
 */
 
 #include "includes.h"
+#include "dlinklist.h"
 #include "smb_server/smb_server.h"
 
 
 /* grow the data allocation size of a trans2 reply - this guarantees
    that requests to grow the data size later will not change the
    pointer */
-static void trans2_grow_data_allocation(struct smbsrv_request *req, 
+static BOOL trans2_grow_data_allocation(struct smbsrv_request *req, 
                                        struct smb_trans2 *trans,
-                                       uint16_t new_size)
+                                       uint32_t new_size)
 {
        if (new_size <= trans->out.data.length) {
-               return;
+               return True;
        }
        trans->out.data.data = talloc_realloc(req, trans->out.data.data, new_size);
+       return (trans->out.data.data != NULL);
 }
 
 
 /* grow the data size of a trans2 reply */
-static void trans2_grow_data(struct smbsrv_request *req, 
+static BOOL trans2_grow_data(struct smbsrv_request *req, 
                             struct smb_trans2 *trans,
-                            uint16_t new_size)
+                            uint32_t new_size)
 {
-       trans2_grow_data_allocation(req, trans, new_size);
+       if (!trans2_grow_data_allocation(req, trans, new_size)) {
+               return False;
+       }
        trans->out.data.length = new_size;
+       return True;
 }
 
 /* grow the data, zero filling any new bytes */
-static void trans2_grow_data_fill(struct smbsrv_request *req, 
+static BOOL trans2_grow_data_fill(struct smbsrv_request *req, 
                                  struct smb_trans2 *trans,
-                                 uint16_t new_size)
+                                 uint32_t new_size)
 {
-       uint16_t old_size = trans->out.data.length;
-       trans2_grow_data(req, trans, new_size);
+       uint32_t old_size = trans->out.data.length;
+       if (!trans2_grow_data(req, trans, new_size)) {
+               return False;
+       }
        if (new_size > old_size) {
                memset(trans->out.data.data + old_size, 0, new_size - old_size);
        }
+       return True;
 }
 
 
@@ -111,8 +119,8 @@ static size_t trans2_pull_blob_string(struct smbsrv_request *req,
 */
 static size_t trans2_push_data_string(struct smbsrv_request *req, 
                                      struct smb_trans2 *trans,
-                                     uint16_t len_offset,
-                                     uint16_t offset,
+                                     uint32_t len_offset,
+                                     uint32_t offset,
                                      const WIRE_STRING *str,
                                      int dest_len,
                                      int flags)
@@ -185,7 +193,7 @@ static void trans2_append_data_string(struct smbsrv_request *req,
                                        int flags)
 {
        size_t ret;
-       uint16_t offset;
+       uint32_t offset;
        const int max_bytes_per_char = 3;
 
        offset = trans->out.data.length;
@@ -613,13 +621,22 @@ static NTSTATUS trans2_fileinfo_fill(struct smbsrv_request *req, struct smb_tran
                      st->alignment_information.out.alignment_requirement);
                return NT_STATUS_OK;
 
+       case RAW_FILEINFO_EA_LIST:
+               list_size = ea_list_size(st->ea_list.out.num_eas,
+                                        st->ea_list.out.eas);
+               trans2_setup_reply(req, trans, 2, list_size, 0);
+               SSVAL(trans->out.params.data, 0, 0);
+               ea_put_list(trans->out.data.data, 
+                           st->ea_list.out.num_eas, st->ea_list.out.eas);
+               return NT_STATUS_OK;
+
        case RAW_FILEINFO_ALL_EAS:
                list_size = ea_list_size(st->all_eas.out.num_eas,
-                                                       st->all_eas.out.eas);
-                       trans2_setup_reply(req, trans, 2, list_size, 0);
-                       SSVAL(trans->out.params.data, 0, 0);
-                       ea_put_list(trans->out.data.data, 
-                                   st->all_eas.out.num_eas, st->all_eas.out.eas);
+                                                 st->all_eas.out.eas);
+               trans2_setup_reply(req, trans, 2, list_size, 0);
+               SSVAL(trans->out.params.data, 0, 0);
+               ea_put_list(trans->out.data.data, 
+                           st->all_eas.out.num_eas, st->all_eas.out.eas);
                return NT_STATUS_OK;
 
        case RAW_FILEINFO_ACCESS_INFORMATION:
@@ -701,7 +718,7 @@ static NTSTATUS trans2_fileinfo_fill(struct smbsrv_request *req, struct smb_tran
                SSVAL(trans->out.params.data, 0, 0);
 
                for (i=0;i<st->stream_info.out.num_streams;i++) {
-                       uint16_t data_size = trans->out.data.length;
+                       uint32_t data_size = trans->out.data.length;
                        uint8_t *data;
 
                        trans2_grow_data(req, trans, data_size + 24);
@@ -752,6 +769,15 @@ static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct smb_trans2 *
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       if (st.generic.level == RAW_FILEINFO_EA_LIST) {
+               status = ea_pull_name_list(&trans->in.data, req, 
+                                          &st.ea_list.in.num_names,
+                                          &st.ea_list.in.ea_names);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
        /* call the backend */
        status = ntvfs_qpathinfo(req, &st);
        if (!NT_STATUS_IS_OK(status)) {
@@ -788,6 +814,15 @@ static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct smb_trans2 *
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       if (st.generic.level == RAW_FILEINFO_EA_LIST) {
+               status = ea_pull_name_list(&trans->in.data, req, 
+                                          &st.ea_list.in.num_names,
+                                          &st.ea_list.in.ea_names);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
        /* call the backend */
        status = ntvfs_qfileinfo(req, &st);
        if (!NT_STATUS_IS_OK(status)) {
@@ -826,21 +861,9 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
                return NT_STATUS_OK;
 
        case RAW_SFILEINFO_EA_SET:
-               CHECK_MIN_BLOB_SIZE(blob, 4);
-               len = IVAL(blob->data, 0);
-               if (len > blob->length || len < 4) {
-                       return NT_STATUS_INFO_LENGTH_MISMATCH;
-               }
-               {
-                       DATA_BLOB blob2;
-                       blob2.data = blob->data+4;
-                       blob2.length = len-4;
-                       len = ea_pull_struct(&blob2, req, &st->ea_set.in.ea);
-               }
-               if (len == 0) {
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-               return NT_STATUS_OK;
+               return ea_pull_list(blob, req, 
+                                   &st->ea_set.in.num_eas, 
+                                   &st->ea_set.in.eas);
 
        case SMB_SFILEINFO_BASIC_INFO:
        case SMB_SFILEINFO_BASIC_INFORMATION:
@@ -988,13 +1011,14 @@ struct find_state {
 /*
   fill a single entry in a trans2 find reply 
 */
-static void find_fill_info(struct smbsrv_request *req,
+static BOOL find_fill_info(struct smbsrv_request *req,
                           struct smb_trans2 *trans, 
                           struct find_state *state,
                           union smb_search_data *file)
 {
        uint8_t *data;
        uint_t ofs = trans->out.data.length;
+       uint32_t ea_size;
 
        switch (state->level) {
        case RAW_SEARCH_SEARCH:
@@ -1045,6 +1069,33 @@ static void find_fill_info(struct smbsrv_request *req,
                trans->out.data.data[trans->out.data.length-1] = 0;
                break;
 
+       case RAW_SEARCH_EA_LIST:
+               ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
+               if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
+                       if (!trans2_grow_data(req, trans, ofs + 27 + ea_size)) {
+                               return False;
+                       }
+                       SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
+                       ofs += 4;
+               } else {
+                       if (!trans2_grow_data(req, trans, ofs + 23 + ea_size)) {
+                               return False;
+                       }
+               }
+               data = trans->out.data.data + ofs;
+               srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
+               srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
+               srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
+               SIVAL(data, 12, file->ea_list.size);
+               SIVAL(data, 16, file->ea_list.alloc_size);
+               SSVAL(data, 20, file->ea_list.attrib);
+               ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
+               trans2_append_data_string(req, trans, &file->ea_list.name, 
+                                         ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN);
+               trans2_grow_data(req, trans, trans->out.data.length + 1);
+               trans->out.data.data[trans->out.data.length-1] = 0;
+               break;
+
        case RAW_SEARCH_DIRECTORY_INFO:
                trans2_grow_data(req, trans, ofs + 64);
                data = trans->out.data.data + ofs;
@@ -1160,6 +1211,8 @@ static void find_fill_info(struct smbsrv_request *req,
                SIVAL(data,          0, trans->out.data.length - ofs);
                break;
        }
+
+       return True;
 }
 
 /* callback function for trans2 findfirst/findnext */
@@ -1171,10 +1224,8 @@ static BOOL find_callback(void *private, union smb_search_data *file)
 
        old_length = trans->out.data.length;
 
-       find_fill_info(state->req, trans, state, file);
-
-       /* see if we have gone beyond the user specified maximum */
-       if (trans->out.data.length > trans->in.max_data) {
+       if (!find_fill_info(state->req, trans, state, file) ||
+           trans->out.data.length > trans->in.max_data) {
                /* restore the old length and tell the backend to stop */
                trans2_grow_data(state->req, trans, old_length);
                return False;
@@ -1217,7 +1268,17 @@ static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct smb_trans2 *
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       /* setup the private state structure that the backend will give us in the callback */
+       if (search.t2ffirst.level == RAW_SEARCH_EA_LIST) {
+               status = ea_pull_name_list(&trans->in.data, req,
+                                          &search.t2ffirst.in.num_names, 
+                                          &search.t2ffirst.in.ea_names);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
+       /* setup the private state structure that the backend will
+          give us in the callback */
        state.req = req;
        state.trans = trans;
        state.level = search.t2ffirst.level;
@@ -1278,6 +1339,15 @@ static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct smb_trans2 *t
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       if (search.t2fnext.level == RAW_SEARCH_EA_LIST) {
+               status = ea_pull_name_list(&trans->in.data, req,
+                                          &search.t2fnext.in.num_names, 
+                                          &search.t2fnext.in.ea_names);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+       }
+
        /* setup the private state structure that the backend will give us in the callback */
        state.req = req;
        state.trans = trans;
@@ -1349,76 +1419,53 @@ static NTSTATUS trans2_backend(struct smbsrv_request *req, struct smb_trans2 *tr
        return NT_STATUS_FOOBAR;
 }
 
-/****************************************************************************
- Reply to an SMBtrans or SMBtrans2 request
-****************************************************************************/
-void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
+
+/*
+  send a continue request
+*/
+static void reply_trans_continue(struct smbsrv_request *req, uint8_t command, 
+                                struct smb_trans2 *trans)
 {
-       struct smb_trans2 trans;
-       int i;
-       uint16_t param_ofs, data_ofs;
-       uint16_t param_count, data_count;
-       uint16_t params_left, data_left;
-       uint16_t param_total, data_total;
-       uint8_t *params, *data;
-       NTSTATUS status;
+       struct smbsrv_trans_partial *tp;
+       int count;
 
-       /* parse request */
-       if (req->in.wct < 14) {
-               req_reply_error(req, NT_STATUS_FOOBAR);
+       /* make sure they don't flood us */
+       for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
+       if (count > 100) {
+               req_reply_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
                return;
        }
 
-       param_total          = SVAL(req->in.vwv, VWV(0));
-       data_total           = SVAL(req->in.vwv, VWV(1));
-       trans.in.max_param   = SVAL(req->in.vwv, VWV(2));
-       trans.in.max_data    = SVAL(req->in.vwv, VWV(3));
-       trans.in.max_setup   = CVAL(req->in.vwv, VWV(4));
-       trans.in.flags       = SVAL(req->in.vwv, VWV(5));
-       trans.in.timeout     = IVAL(req->in.vwv, VWV(6));
-       param_count          = SVAL(req->in.vwv, VWV(9));
-       param_ofs            = SVAL(req->in.vwv, VWV(10));
-       data_count           = SVAL(req->in.vwv, VWV(11));
-       data_ofs             = SVAL(req->in.vwv, VWV(12));
-       trans.in.setup_count = CVAL(req->in.vwv, VWV(13));
-
-       if (req->in.wct != 14 + trans.in.setup_count) {
-               req_reply_dos_error(req, ERRSRV, ERRerror);
-               return;
-       }
+       tp = talloc_p(req, struct smbsrv_trans_partial);
 
-       /* parse out the setup words */
-       trans.in.setup = talloc_array_p(req, uint16_t, trans.in.setup_count);
-       if (trans.in.setup_count && !trans.in.setup) {
-               req_reply_error(req, NT_STATUS_NO_MEMORY);
-               return;
-       }
-       for (i=0;i<trans.in.setup_count;i++) {
-               trans.in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
-       }
+       tp->req = talloc_reference(tp, req);
+       tp->trans = trans;
+       tp->command = command;
 
-       if (command == SMBtrans) {
-               req_pull_string(req, &trans.in.trans_name, req->in.data, -1, STR_TERMINATE);
-       }
+       DLIST_ADD(req->smb_conn->trans_partial, tp);
 
-       if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans.in.params) ||
-           !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans.in.data)) {
-               req_reply_error(req, NT_STATUS_FOOBAR);
-               return;
-       }
+       /* send a 'please continue' reply */
+       req_setup_reply(req, 0, 0);
+       req_send_reply(req);
+}
 
-       /* is it a partial request? if so, then send a 'send more' message */
-       if (param_total > param_count ||
-           data_total > data_count) {
-               DEBUG(0,("REWRITE: not handling partial trans requests!\n"));
-               return;
-       }
+
+/*
+  answer a reconstructed trans request
+*/
+static void reply_trans_complete(struct smbsrv_request *req, uint8_t command, 
+                                struct smb_trans2 *trans)
+{
+       uint16_t params_left, data_left;
+       uint8_t *params, *data;
+       NTSTATUS status;
+       int i;
 
        /* its a full request, give it to the backend */
        if (command == SMBtrans) {
-               status = ntvfs_trans(req, &trans);
+               status = ntvfs_trans(req, trans);
        } else {
-               status = trans2_backend(req, &trans);
+               status = trans2_backend(req, trans);
        }
 
        if (NT_STATUS_IS_ERR(status)) {
@@ -1426,13 +1473,12 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
                return;
        }
 
-       params_left = trans.out.params.length;
-       data_left   = trans.out.data.length;
-       params      = trans.out.params.data;
-       data        = trans.out.data.data;
-
+       params_left = trans->out.params.length;
+       data_left   = trans->out.data.length;
+       params      = trans->out.params.data;
+       data        = trans->out.data.data;
 
-       req_setup_reply(req, 10 + trans.out.setup_count, 0);
+       req_setup_reply(req, 10 + trans->out.setup_count, 0);
 
        if (!NT_STATUS_IS_OK(status)) {
                req_setup_error(req, status);
@@ -1468,22 +1514,22 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
 
                req_grow_data(this_req, this_param + this_data + (align1 + align2));
 
-               SSVAL(this_req->out.vwv, VWV(0), trans.out.params.length);
-               SSVAL(this_req->out.vwv, VWV(1), trans.out.data.length);
+               SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
+               SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
                SSVAL(this_req->out.vwv, VWV(2), 0);
 
                SSVAL(this_req->out.vwv, VWV(3), this_param);
                SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
-               SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans.out.params.data));
+               SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
 
                SSVAL(this_req->out.vwv, VWV(6), this_data);
                SSVAL(this_req->out.vwv, VWV(7), align1 + align2 + 
                      PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
-               SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans.out.data.data));
+               SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
 
-               SSVAL(this_req->out.vwv, VWV(9), trans.out.setup_count);
-               for (i=0;i<trans.out.setup_count;i++) {
-                       SSVAL(this_req->out.vwv, VWV(10+i), trans.out.setup[i]);
+               SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
+               for (i=0;i<trans->out.setup_count;i++) {
+                       SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
                }
 
                memset(this_req->out.data, 0, align1);
@@ -1505,28 +1551,213 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
 }
 
 
-/****************************************************************************
- Reply to an SMBtrans2
-****************************************************************************/
+/*
+  Reply to an SMBtrans or SMBtrans2 request
+*/
+void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
+{
+       struct smb_trans2 *trans;
+       int i;
+       uint16_t param_ofs, data_ofs;
+       uint16_t param_count, data_count;
+       uint16_t param_total, data_total;
+
+       trans = talloc_p(req, struct smb_trans2);
+       if (trans == NULL) {
+               req_reply_error(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
+       /* parse request */
+       if (req->in.wct < 14) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       param_total           = SVAL(req->in.vwv, VWV(0));
+       data_total            = SVAL(req->in.vwv, VWV(1));
+       trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
+       trans->in.max_data    = SVAL(req->in.vwv, VWV(3));
+       trans->in.max_setup   = CVAL(req->in.vwv, VWV(4));
+       trans->in.flags       = SVAL(req->in.vwv, VWV(5));
+       trans->in.timeout     = IVAL(req->in.vwv, VWV(6));
+       param_count           = SVAL(req->in.vwv, VWV(9));
+       param_ofs             = SVAL(req->in.vwv, VWV(10));
+       data_count            = SVAL(req->in.vwv, VWV(11));
+       data_ofs              = SVAL(req->in.vwv, VWV(12));
+       trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
+
+       if (req->in.wct != 14 + trans->in.setup_count) {
+               req_reply_dos_error(req, ERRSRV, ERRerror);
+               return;
+       }
+
+       /* parse out the setup words */
+       trans->in.setup = talloc_array_p(req, uint16_t, trans->in.setup_count);
+       if (trans->in.setup_count && !trans->in.setup) {
+               req_reply_error(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+       for (i=0;i<trans->in.setup_count;i++) {
+               trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
+       }
+
+       if (command == SMBtrans) {
+               req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
+       }
+
+       if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
+           !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
+               req_reply_error(req, NT_STATUS_FOOBAR);
+               return;
+       }
+
+       /* is it a partial request? if so, then send a 'send more' message */
+       if (param_total > param_count || data_total > data_count) {
+               reply_trans_continue(req, command, trans);
+               return;
+       }
+
+       reply_trans_complete(req, command, trans);
+}
+
+
+/*
+  Reply to an SMBtranss2 request
+*/
+static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
+{
+       struct smbsrv_trans_partial *tp;
+       struct smb_trans2 *trans = NULL;
+       uint16_t param_ofs, data_ofs;
+       uint16_t param_count, data_count;
+       uint16_t param_disp, data_disp;
+       uint16_t param_total, data_total;
+       DATA_BLOB params, data;
+
+       for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
+               if (tp->command == command &&
+                   SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
+                       break;
+               }
+       }
+
+       if (tp == NULL) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       trans = tp->trans;
+
+       /* parse request */
+       if (req->in.wct < 8) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       param_total           = SVAL(req->in.vwv, VWV(0));
+       data_total            = SVAL(req->in.vwv, VWV(1));
+       param_count           = SVAL(req->in.vwv, VWV(2));
+       param_ofs             = SVAL(req->in.vwv, VWV(3));
+       param_disp            = SVAL(req->in.vwv, VWV(4));
+       data_count            = SVAL(req->in.vwv, VWV(5));
+       data_ofs              = SVAL(req->in.vwv, VWV(6));
+       data_disp             = SVAL(req->in.vwv, VWV(7));
+
+       if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &params) ||
+           !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       /* only allow contiguous requests */
+       if ((param_count != 0 &&
+            param_disp != trans->in.params.length) ||
+           (data_count != 0 && 
+            data_disp != trans->in.data.length)) {
+               req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;         
+       }
+
+       /* add to the existing request */
+       if (param_count != 0) {
+               trans->in.params.data = talloc_realloc_p(trans, 
+                                                        trans->in.params.data, 
+                                                        uint8_t, 
+                                                        param_disp + param_count);
+               if (trans->in.params.data == NULL) {
+                       goto failed;
+               }
+               trans->in.params.length = param_disp + param_count;
+       }
+
+       if (data_count != 0) {
+               trans->in.data.data = talloc_realloc_p(trans, 
+                                                      trans->in.data.data, 
+                                                      uint8_t, 
+                                                      data_disp + data_count);
+               if (trans->in.data.data == NULL) {
+                       goto failed;
+               }
+               trans->in.data.length = data_disp + data_count;
+       }
+
+       memcpy(trans->in.params.data + param_disp, params.data, params.length);
+       memcpy(trans->in.data.data + data_disp, data.data, data.length);
+
+       /* the sequence number of the reply is taken from the last secondary
+          response */
+       tp->req->seq_num = req->seq_num;
+
+       /* we don't reply to Transs2 requests */
+       talloc_free(req);
+
+       if (trans->in.params.length == param_total &&
+           trans->in.data.length == data_total) {
+               /* its now complete */
+               reply_trans_complete(tp->req, command, trans);
+               DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
+               talloc_free(tp);
+       }
+       return;
+
+failed:        
+       req_reply_error(tp->req, NT_STATUS_NO_MEMORY);
+       DLIST_REMOVE(req->smb_conn->trans_partial, tp);
+       talloc_free(req);
+       talloc_free(tp);
+}
+
+
+/*
+  Reply to an SMBtrans2
+*/
 void reply_trans2(struct smbsrv_request *req)
 {
        reply_trans_generic(req, SMBtrans2);
 }
 
-/****************************************************************************
- Reply to an SMBtrans
-****************************************************************************/
+/*
 Reply to an SMBtrans
+*/
 void reply_trans(struct smbsrv_request *req)
 {
        reply_trans_generic(req, SMBtrans);
 }
 
-/****************************************************************************
Reply to an SMBtranss2 request
-****************************************************************************/
-void reply_transs2(struct smbsrv_request *req)
+/*
 Reply to an SMBtranss request
+*/
+void reply_transs(struct smbsrv_request *req)
 {
-       req_reply_error(req, NT_STATUS_FOOBAR);
+       reply_transs_generic(req, SMBtrans);
 }
 
+/*
+  Reply to an SMBtranss2 request
+*/
+void reply_transs2(struct smbsrv_request *req)
+{
+       reply_transs_generic(req, SMBtrans2);
+}