/* grow the data buffer portion of a reply packet. Note that as this can reallocate the packet buffer this invalidates any local pointers into the packet. To cope with this req->out.ptr is supplied. This will be updated to point at the same offset into the packet as before this call */ void req_grow_data(struct smbsrv_request *req, size_t new_size) { int delta; if (!(req->control_flags & SMBSRV_REQ_CONTROL_LARGE) && new_size > req_max_data(req)) { smb_panic("reply buffer too large!"); } req_grow_allocation(req, new_size); delta = new_size - req->out.data_size; req->out.size += delta; req->out.data_size += delta; /* set the BCC to the new data size */ SSVAL(req->out.vwv, VWV(req->out.wct), new_size); }
/* answer a reconstructed trans request */ static void reply_trans_send(struct ntvfs_request *ntvfs) { struct smbsrv_request *req; struct trans_op *op; struct smb_trans2 *trans; uint16_t params_left, data_left; uint8_t *params, *data; int i; SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op); trans = op->trans; /* if this function needs work to form the nttrans reply buffer, then call that now */ if (op->send_fn != NULL) { NTSTATUS status; status = op->send_fn(op); if (!NT_STATUS_IS_OK(status)) { smbsrv_send_error(req, status); return; } } params_left = trans->out.params.length; data_left = trans->out.data.length; params = trans->out.params.data; data = trans->out.data.data; smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0); if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { smbsrv_setup_error(req, req->ntvfs->async_states->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; unsigned int align1 = 1, align2 = (params_left ? 2 : 0); struct smbsrv_request *this_req; max_bytes = req_max_data(req) - (align1 + align2); this_param = params_left; if (this_param > max_bytes) { this_param = max_bytes; } max_bytes -= this_param; this_data = data_left; if (this_data > max_bytes) { 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 = smbsrv_setup_secondary_request(req); } else { this_req = req; } 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(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(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)); SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count); SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */ 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); if (this_param != 0) { memcpy(this_req->out.data + align1, params, this_param); } memset(this_req->out.data+this_param+align1, 0, align2); if (this_data != 0) { memcpy(this_req->out.data+this_param+align1+align2, data, this_data); } params_left -= this_param; data_left -= this_data; params += this_param; data += this_data; smbsrv_send_reply(this_req); } while (params_left != 0 || data_left != 0); }