mirror of
https://github.com/samba-team/samba.git
synced 2025-12-02 00:23:50 +03:00
r3350: fixed a bug with sending multiple replies for the one request, as
happens with trans2, trans and echo. Now that smbd is async we queue the multiples replies all at once, and now need a way to ensure each reply gets it own smbsrv_request buffer. I have added req_setup_secondary() to cope with this.
This commit is contained in:
committed by
Gerald (Jerry) Carter
parent
915faf4935
commit
2dbd2abc5f
@@ -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,13 +198,18 @@ 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);
|
||||
|
||||
req_setup_reply(req, 18 + trans.out.setup_count, 0);
|
||||
struct smbsrv_request *this_req;
|
||||
|
||||
max_bytes = req_max_data(req) - (align1 + align2);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1326,11 +1326,6 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
|
||||
params = trans.out.params.data;
|
||||
data = trans.out.data.data;
|
||||
|
||||
/* 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);
|
||||
|
||||
req_setup_reply(req, 10 + trans.out.setup_count, 0);
|
||||
|
||||
@@ -1338,6 +1333,13 @@ void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
req_grow_data(this_req, this_param + this_data + (align1 + align2));
|
||||
|
||||
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(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(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(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(9), trans.out.setup_count);
|
||||
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(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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user