diff options
-rw-r--r-- | source4/smb_server/nttrans.c | 61 | ||||
-rw-r--r-- | source4/smb_server/reply.c | 10 | ||||
-rw-r--r-- | source4/smb_server/request.c | 31 | ||||
-rw-r--r-- | source4/smb_server/trans2.c | 63 |
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); } |