summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/smb_server/nttrans.c61
-rw-r--r--source4/smb_server/reply.c10
-rw-r--r--source4/smb_server/request.c31
-rw-r--r--source4/smb_server/trans2.c63
4 files changed, 107 insertions, 58 deletions
diff --git a/source4/smb_server/nttrans.c b/source4/smb_server/nttrans.c
index 5a5d9f77e3..336328429b 100644
--- a/source4/smb_server/nttrans.c
+++ b/source4/smb_server/nttrans.c
@@ -188,7 +188,7 @@ void reply_nttrans(struct smbsrv_request *req)
/* its a full request, give it to the backend */
status = nttrans_backend(req, &trans);
- if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_IS_ERR(status)) {
req_reply_error(req, status);
return;
}
@@ -198,14 +198,19 @@ void reply_nttrans(struct smbsrv_request *req)
params = trans.out.params.data;
data = trans.out.data.data;
+ req_setup_reply(req, 18 + trans.out.setup_count, 0);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ req_setup_error(req, status);
+ }
+
/* we need to divide up the reply into chunks that fit into
the negotiated buffer size */
do {
uint16_t this_data, this_param, max_bytes;
uint_t align1 = 1, align2 = (params_left ? 2 : 0);
+ struct smbsrv_request *this_req;
- req_setup_reply(req, 18 + trans.out.setup_count, 0);
-
max_bytes = req_max_data(req) - (align1 + align2);
this_param = params_left;
@@ -219,34 +224,43 @@ void reply_nttrans(struct smbsrv_request *req)
this_data = max_bytes;
}
+ /* don't destroy unless this is the last chunk */
+ if (params_left - this_param != 0 ||
+ data_left - this_data != 0) {
+ this_req = req_setup_secondary(req);
+ } else {
+ this_req = req;
+ }
+
req_grow_data(req, this_param + this_data + (align1 + align2));
- SSVAL(req->out.vwv, 0, 0); /* reserved */
- SCVAL(req->out.vwv, 2, 0); /* reserved */
- SIVAL(req->out.vwv, 3, trans.out.params.length);
- SIVAL(req->out.vwv, 7, trans.out.data.length);
+ SSVAL(this_req->out.vwv, 0, 0); /* reserved */
+ SCVAL(this_req->out.vwv, 2, 0); /* reserved */
+ SIVAL(this_req->out.vwv, 3, trans.out.params.length);
+ SIVAL(this_req->out.vwv, 7, trans.out.data.length);
- SIVAL(req->out.vwv, 11, this_param);
- SIVAL(req->out.vwv, 15, align1 + PTR_DIFF(req->out.data, req->out.hdr));
- SIVAL(req->out.vwv, 19, PTR_DIFF(params, trans.out.params.data));
+ SIVAL(this_req->out.vwv, 11, this_param);
+ SIVAL(this_req->out.vwv, 15, align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
+ SIVAL(this_req->out.vwv, 19, PTR_DIFF(params, trans.out.params.data));
- SIVAL(req->out.vwv, 23, this_data);
- SIVAL(req->out.vwv, 27, align1 + align2 +
- PTR_DIFF(req->out.data + this_param, req->out.hdr));
- SIVAL(req->out.vwv, 31, PTR_DIFF(data, trans.out.data.data));
+ SIVAL(this_req->out.vwv, 23, this_data);
+ SIVAL(this_req->out.vwv, 27, align1 + align2 +
+ PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
+ SIVAL(this_req->out.vwv, 31, PTR_DIFF(data, trans.out.data.data));
- SCVAL(req->out.vwv, 35, trans.out.setup_count);
+ SCVAL(this_req->out.vwv, 35, trans.out.setup_count);
for (i=0;i<trans.out.setup_count;i++) {
- SSVAL(req->out.vwv, VWV(18+i), trans.out.setup[i]);
+ SSVAL(this_req->out.vwv, VWV(18+i), trans.out.setup[i]);
}
- memset(req->out.data, 0, align1);
+ memset(this_req->out.data, 0, align1);
if (this_param != 0) {
- memcpy(req->out.data + align1, params, this_param);
+ memcpy(this_req->out.data + align1, params, this_param);
}
- memset(req->out.data+this_param+align1, 0, align2);
+ memset(this_req->out.data+this_param+align1, 0, align2);
if (this_data != 0) {
- memcpy(req->out.data+this_param+align1+align2, data, this_data);
+ memcpy(this_req->out.data+this_param+align1+align2,
+ data, this_data);
}
params_left -= this_param;
@@ -254,12 +268,7 @@ void reply_nttrans(struct smbsrv_request *req)
params += this_param;
data += this_data;
- /* don't destroy unless this is the last segment */
- if (params_left != 0 || data_left != 0) {
- talloc_increase_ref_count(req);
- }
-
- req_send_reply(req);
+ req_send_reply(this_req);
} while (params_left != 0 || data_left != 0);
}
diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c
index dd1df29573..818d953abb 100644
--- a/source4/smb_server/reply.c
+++ b/source4/smb_server/reply.c
@@ -1369,12 +1369,16 @@ void reply_echo(struct smbsrv_request *req)
memcpy(req->out.data, req->in.data, req->in.data_size);
for (i=1; i <= count;i++) {
+ struct smbsrv_request *this_req;
+
if (i != count) {
- talloc_increase_ref_count(req);
+ this_req = req_setup_secondary(req);
+ } else {
+ this_req = req;
}
- SSVAL(req->out.vwv, VWV(0), i);
- req_send_reply(req);
+ SSVAL(this_req->out.vwv, VWV(0), i);
+ req_send_reply(this_req);
}
}
diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c
index 5b137b4c53..5d5b397dd3 100644
--- a/source4/smb_server/request.c
+++ b/source4/smb_server/request.c
@@ -155,6 +155,37 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen)
}
}
+
+/*
+ setup a copy of a request, used when the server needs to send
+ more than one reply for a single request packet
+*/
+struct smbsrv_request *req_setup_secondary(struct smbsrv_request *old_req)
+{
+ struct smbsrv_request *req;
+ ptrdiff_t diff;
+
+ req = talloc_memdup(old_req, old_req, sizeof(struct smbsrv_request));
+ if (req == NULL) {
+ return NULL;
+ }
+
+ req->out.buffer = talloc_memdup(req, req->out.buffer, req->out.allocated);
+ if (req->out.buffer == NULL) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ diff = req->out.buffer - old_req->out.buffer;
+
+ req->out.hdr += diff;
+ req->out.vwv += diff;
+ req->out.data += diff;
+ req->out.ptr += diff;
+
+ return req;
+}
+
/*
work out the maximum data size we will allow for this reply, given
the negotiated max_xmit. The basic reply packet must be setup before
diff --git a/source4/smb_server/trans2.c b/source4/smb_server/trans2.c
index ed58791fbe..c5c48d3f64 100644
--- a/source4/smb_server/trans2.c
+++ b/source4/smb_server/trans2.c
@@ -1326,18 +1326,20 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
params = trans.out.params.data;
data = trans.out.data.data;
+
+ req_setup_reply(req, 10 + trans.out.setup_count, 0);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ req_setup_error(req, status);
+ }
+
/* we need to divide up the reply into chunks that fit into
the negotiated buffer size */
do {
uint16_t this_data, this_param, max_bytes;
uint_t align1 = 1, align2 = (params_left ? 2 : 0);
+ struct smbsrv_request *this_req;
- req_setup_reply(req, 10 + trans.out.setup_count, 0);
-
- if (!NT_STATUS_IS_OK(status)) {
- req_setup_error(req, status);
- }
-
max_bytes = req_max_data(req) - (align1 + align2);
this_param = params_left;
@@ -1351,33 +1353,41 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
this_data = max_bytes;
}
- req_grow_data(req, this_param + this_data + (align1 + align2));
+ /* don't destroy unless this is the last chunk */
+ if (params_left - this_param != 0 ||
+ data_left - this_data != 0) {
+ this_req = req_setup_secondary(req);
+ } else {
+ this_req = req;
+ }
+
+ req_grow_data(this_req, this_param + this_data + (align1 + align2));
- SSVAL(req->out.vwv, VWV(0), trans.out.params.length);
- SSVAL(req->out.vwv, VWV(1), trans.out.data.length);
- SSVAL(req->out.vwv, VWV(2), 0);
+ 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(req->out.vwv, VWV(3), this_param);
- SSVAL(req->out.vwv, VWV(4), align1 + PTR_DIFF(req->out.data, req->out.hdr));
- SSVAL(req->out.vwv, VWV(5), PTR_DIFF(params, trans.out.params.data));
+ 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(req->out.vwv, VWV(6), this_data);
- SSVAL(req->out.vwv, VWV(7), align1 + align2 +
- PTR_DIFF(req->out.data + this_param, req->out.hdr));
- SSVAL(req->out.vwv, VWV(8), PTR_DIFF(data, trans.out.data.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(req->out.vwv, VWV(9), trans.out.setup_count);
+ SSVAL(this_req->out.vwv, VWV(9), trans.out.setup_count);
for (i=0;i<trans.out.setup_count;i++) {
- SSVAL(req->out.vwv, VWV(10+i), trans.out.setup[i]);
+ SSVAL(this_req->out.vwv, VWV(10+i), trans.out.setup[i]);
}
- memset(req->out.data, 0, align1);
+ memset(this_req->out.data, 0, align1);
if (this_param != 0) {
- memcpy(req->out.data + align1, params, this_param);
+ memcpy(this_req->out.data + align1, params, this_param);
}
- memset(req->out.data+this_param+align1, 0, align2);
+ memset(this_req->out.data+this_param+align1, 0, align2);
if (this_data != 0) {
- memcpy(req->out.data+this_param+align1+align2, data, this_data);
+ memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
}
params_left -= this_param;
@@ -1385,12 +1395,7 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
params += this_param;
data += this_data;
- /* don't destroy unless this is the last chunk */
- if (params_left != 0 || data_left != 0) {
- talloc_increase_ref_count(req);
- }
-
- req_send_reply(req);
+ req_send_reply(this_req);
} while (params_left != 0 || data_left != 0);
}