static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_smb2_request *smb2req,
- uint32_t in_smbpid,
- uint64_t in_file_id_volatile,
+ struct files_struct *in_fsp,
DATA_BLOB in_data,
uint64_t in_offset,
uint32_t in_flags);
static void smbd_smb2_request_write_done(struct tevent_req *subreq);
NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req)
{
+ struct smbXsrv_connection *xconn = req->xconn;
NTSTATUS status;
- const uint8_t *inhdr;
const uint8_t *inbody;
- int i = req->current_idx;
- uint32_t in_smbpid;
uint16_t in_data_offset;
uint32_t in_data_length;
DATA_BLOB in_data_buffer;
uint64_t in_offset;
uint64_t in_file_id_persistent;
uint64_t in_file_id_volatile;
+ struct files_struct *in_fsp;
uint32_t in_flags;
+ size_t in_dyn_len = 0;
+ uint8_t *in_dyn_ptr = NULL;
struct tevent_req *subreq;
status = smbd_smb2_request_verify_sizes(req, 0x31);
if (!NT_STATUS_IS_OK(status)) {
return smbd_smb2_request_error(req, status);
}
- inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
- inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
-
- in_smbpid = IVAL(inhdr, SMB2_HDR_PID);
+ inbody = SMBD_SMB2_IN_BODY_PTR(req);
in_data_offset = SVAL(inbody, 0x02);
in_data_length = IVAL(inbody, 0x04);
in_file_id_volatile = BVAL(inbody, 0x18);
in_flags = IVAL(inbody, 0x2C);
- if (in_data_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
+ if (in_data_offset != (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
- if (in_data_length > req->in.vector[i+2].iov_len) {
+ if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) {
+ in_dyn_ptr = NULL;
+ in_dyn_len = req->smb1req->unread_bytes;
+ } else {
+ in_dyn_ptr = SMBD_SMB2_IN_DYN_PTR(req);
+ in_dyn_len = SMBD_SMB2_IN_DYN_LEN(req);
+ }
+
+ if (in_data_length > in_dyn_len) {
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
/* check the max write size */
- if (in_data_length > req->sconn->smb2.max_write) {
+ if (in_data_length > xconn->smb2.server.max_write) {
DEBUG(2,("smbd_smb2_request_process_write : "
"client ignored max write :%s: 0x%08X: 0x%08X\n",
- __location__, in_data_length, req->sconn->smb2.max_write));
+ __location__, in_data_length, xconn->smb2.server.max_write));
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
- in_data_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
+ /*
+ * Note: that in_dyn_ptr is NULL for the recvfile case.
+ */
+ in_data_buffer.data = in_dyn_ptr;
in_data_buffer.length = in_data_length;
- if (req->compat_chain_fsp) {
- /* skip check */
- } else if (in_file_id_persistent != in_file_id_volatile) {
+ status = smbd_smb2_request_verify_creditcharge(req, in_data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return smbd_smb2_request_error(req, status);
+ }
+
+ in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
+ if (in_fsp == NULL) {
return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
}
- subreq = smbd_smb2_write_send(req,
- req->sconn->ev_ctx,
- req,
- in_smbpid,
- in_file_id_volatile,
+ subreq = smbd_smb2_write_send(req, req->sconn->ev_ctx,
+ req, in_fsp,
in_data_buffer,
in_offset,
in_flags);
if (!NT_STATUS_IS_OK(status)) {
error = smbd_smb2_request_error(req, status);
if (!NT_STATUS_IS_OK(error)) {
- smbd_server_connection_terminate(req->sconn,
+ smbd_server_connection_terminate(req->xconn,
nt_errstr(error));
return;
}
return;
}
- outbody = data_blob_talloc(req->out.vector, NULL, 0x10);
+ outbody = smbd_smb2_generate_outbody(req, 0x10);
if (outbody.data == NULL) {
error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
if (!NT_STATUS_IS_OK(error)) {
- smbd_server_connection_terminate(req->sconn,
+ smbd_server_connection_terminate(req->xconn,
nt_errstr(error));
return;
}
error = smbd_smb2_request_done(req, outbody, &outdyn);
if (!NT_STATUS_IS_OK(error)) {
- smbd_server_connection_terminate(req->sconn, nt_errstr(error));
+ smbd_server_connection_terminate(req->xconn, nt_errstr(error));
return;
}
}
static void smbd_smb2_write_pipe_done(struct tevent_req *subreq);
-NTSTATUS smb2_write_complete(struct tevent_req *req, ssize_t nwritten, int err)
+static NTSTATUS smb2_write_complete_internal(struct tevent_req *req,
+ ssize_t nwritten, int err,
+ bool do_sync)
{
NTSTATUS status;
struct smbd_smb2_write_state *state = tevent_req_data(req,
struct smbd_smb2_write_state);
files_struct *fsp = state->fsp;
- DEBUG(3,("smb2: fnum=[%d/%s] "
+ if (nwritten == -1) {
+ status = map_nt_error_from_unix(err);
+
+ DEBUG(2, ("smb2_write failed: %s, file %s, "
+ "length=%lu offset=%lu nwritten=-1: %s\n",
+ fsp_fnum_dbg(fsp),
+ fsp_str_dbg(fsp),
+ (unsigned long)state->in_length,
+ (unsigned long)state->in_offset,
+ nt_errstr(status)));
+
+ return status;
+ }
+
+ DEBUG(3,("smb2: %s, file %s, "
"length=%lu offset=%lu wrote=%lu\n",
- fsp->fnum,
+ fsp_fnum_dbg(fsp),
fsp_str_dbg(fsp),
(unsigned long)state->in_length,
(unsigned long)state->in_offset,
(unsigned long)nwritten));
- if (nwritten == -1) {
- return map_nt_error_from_unix(err);
- }
-
if ((nwritten == 0) && (state->in_length != 0)) {
DEBUG(5,("smb2: write [%s] disk full\n",
fsp_str_dbg(fsp)));
return NT_STATUS_DISK_FULL;
}
- status = sync_file(fsp->conn, fsp, state->write_through);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5,("smb2: sync_file for %s returned %s\n",
- fsp_str_dbg(fsp),
- nt_errstr(status)));
- return status;
+ if (do_sync) {
+ status = sync_file(fsp->conn, fsp, state->write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("smb2: sync_file for %s returned %s\n",
+ fsp_str_dbg(fsp),
+ nt_errstr(status)));
+ return status;
+ }
}
state->out_count = nwritten;
return NT_STATUS_OK;
}
+NTSTATUS smb2_write_complete(struct tevent_req *req, ssize_t nwritten, int err)
+{
+ return smb2_write_complete_internal(req, nwritten, err, true);
+}
+
+NTSTATUS smb2_write_complete_nosync(struct tevent_req *req, ssize_t nwritten,
+ int err)
+{
+ return smb2_write_complete_internal(req, nwritten, err, false);
+}
+
+
static bool smbd_smb2_write_cancel(struct tevent_req *req)
{
struct smbd_smb2_write_state *state =
tevent_req_data(req,
struct smbd_smb2_write_state);
- state->smb2req->cancelled = true;
-
return cancel_smb2_aio(state->smbreq);
}
static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_smb2_request *smb2req,
- uint32_t in_smbpid,
- uint64_t in_file_id_volatile,
+ struct files_struct *fsp,
DATA_BLOB in_data,
uint64_t in_offset,
uint32_t in_flags)
struct tevent_req *req = NULL;
struct smbd_smb2_write_state *state = NULL;
struct smb_request *smbreq = NULL;
- connection_struct *conn = smb2req->tcon->compat_conn;
- files_struct *fsp = NULL;
+ connection_struct *conn = smb2req->tcon->compat;
ssize_t nwritten;
struct lock_struct lock;
return NULL;
}
state->smb2req = smb2req;
+ if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
+ if (in_flags & SMB2_WRITEFLAG_WRITE_UNBUFFERED) {
+ state->write_through = true;
+ }
+ }
if (in_flags & SMB2_WRITEFLAG_WRITE_THROUGH) {
state->write_through = true;
}
state->in_length = in_data.length;
state->out_count = 0;
- DEBUG(10,("smbd_smb2_write: file_id[0x%016llX]\n",
- (unsigned long long)in_file_id_volatile));
+ DEBUG(10,("smbd_smb2_write: %s - %s\n",
+ fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
smbreq = smbd_smb2_fake_smb_request(smb2req);
if (tevent_req_nomem(smbreq, req)) {
}
state->smbreq = smbreq;
- fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
- if (fsp == NULL) {
- tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
- return tevent_req_post(req, ev);
- }
- if (conn != fsp->conn) {
- tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
- return tevent_req_post(req, ev);
- }
- if (smb2req->session->vuid != fsp->vuid) {
- tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
- return tevent_req_post(req, ev);
- }
-
state->fsp = fsp;
if (IS_IPC(smbreq->conn)) {
if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
/* Real error in setting up aio. Fail. */
- tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
+ tevent_req_nterror(req, status);
return tevent_req_post(req, ev);
}
/* Fallback to synchronous. */
init_strict_lock_struct(fsp,
- in_file_id_volatile,
+ fsp->op->global->open_persistent_id,
in_offset,
in_data.length,
WRITE_LOCK,
return tevent_req_post(req, ev);
}
+ /*
+ * Note: in_data.data is NULL for the recvfile case.
+ */
nwritten = write_file(smbreq, fsp,
(const char *)in_data.data,
in_offset,
status = smb2_write_complete(req, nwritten, errno);
- SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
DEBUG(10,("smb2: write on "
"file %s, offset %.0f, requested %u, written = %u\n",
fsp_str_dbg(fsp),
status = np_write_recv(subreq, &nwritten);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
+ NTSTATUS old = status;
+ status = nt_status_np_pipe(old);
tevent_req_nterror(req, status);
return;
}