#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
struct raw_trans_state {
uint8_t command;
+ uint8_t align;
+
// uint32_t num_req;
uint32_t params_left;
uint32_t data_left;
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;
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;
/* 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;
/* 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) {
}
#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;
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;
}
parms->in.setup_count * VWV(1));
}
-/*TODO: grow alloc */
-/*TODO: params align */
+ smbcli_req_append_blob(req, ¶ms_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
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;
/* 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);
/* 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) {
}
#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, ¶ms_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
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) {
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)
{
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;
/****************************************************************************
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);
}