s3:smbd: make use of smbXsrv_tcon and smbXsrv_session for smb2
[Samba/gebeck_regimport.git] / source3 / smbd / smb2_write.c
blob0150b0cd25d62e6a5ef6dcc60ef770d3c60036d9
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "smbd/globals.h"
24 #include "../libcli/smb/smb_common.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "rpc_server/srv_pipe_hnd.h"
28 static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx,
29 struct tevent_context *ev,
30 struct smbd_smb2_request *smb2req,
31 struct files_struct *in_fsp,
32 uint32_t in_smbpid,
33 DATA_BLOB in_data,
34 uint64_t in_offset,
35 uint32_t in_flags);
36 static NTSTATUS smbd_smb2_write_recv(struct tevent_req *req,
37 uint32_t *out_count);
39 static void smbd_smb2_request_write_done(struct tevent_req *subreq);
40 NTSTATUS smbd_smb2_request_process_write(struct smbd_smb2_request *req)
42 NTSTATUS status;
43 const uint8_t *inhdr;
44 const uint8_t *inbody;
45 int i = req->current_idx;
46 uint32_t in_smbpid;
47 uint16_t in_data_offset;
48 uint32_t in_data_length;
49 DATA_BLOB in_data_buffer;
50 uint64_t in_offset;
51 uint64_t in_file_id_persistent;
52 uint64_t in_file_id_volatile;
53 struct files_struct *in_fsp;
54 uint32_t in_flags;
55 struct tevent_req *subreq;
57 status = smbd_smb2_request_verify_sizes(req, 0x31);
58 if (!NT_STATUS_IS_OK(status)) {
59 return smbd_smb2_request_error(req, status);
61 inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
62 inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
64 in_smbpid = IVAL(inhdr, SMB2_HDR_PID);
66 in_data_offset = SVAL(inbody, 0x02);
67 in_data_length = IVAL(inbody, 0x04);
68 in_offset = BVAL(inbody, 0x08);
69 in_file_id_persistent = BVAL(inbody, 0x10);
70 in_file_id_volatile = BVAL(inbody, 0x18);
71 in_flags = IVAL(inbody, 0x2C);
73 if (in_data_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
74 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
77 if (in_data_length > req->in.vector[i+2].iov_len) {
78 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
81 /* check the max write size */
82 if (in_data_length > req->sconn->smb2.max_write) {
83 DEBUG(2,("smbd_smb2_request_process_write : "
84 "client ignored max write :%s: 0x%08X: 0x%08X\n",
85 __location__, in_data_length, req->sconn->smb2.max_write));
86 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
89 in_data_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
90 in_data_buffer.length = in_data_length;
92 status = smbd_smb2_request_verify_creditcharge(req, in_data_length);
93 if (!NT_STATUS_IS_OK(status)) {
94 return smbd_smb2_request_error(req, status);
97 in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
98 if (in_fsp == NULL) {
99 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
102 subreq = smbd_smb2_write_send(req, req->sconn->ev_ctx,
103 req, in_fsp,
104 in_smbpid,
105 in_data_buffer,
106 in_offset,
107 in_flags);
108 if (subreq == NULL) {
109 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
111 tevent_req_set_callback(subreq, smbd_smb2_request_write_done, req);
113 return smbd_smb2_request_pending_queue(req, subreq, 500);
116 static void smbd_smb2_request_write_done(struct tevent_req *subreq)
118 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
119 struct smbd_smb2_request);
120 DATA_BLOB outbody;
121 DATA_BLOB outdyn;
122 uint32_t out_count = 0;
123 NTSTATUS status;
124 NTSTATUS error; /* transport error */
126 status = smbd_smb2_write_recv(subreq, &out_count);
127 TALLOC_FREE(subreq);
128 if (!NT_STATUS_IS_OK(status)) {
129 error = smbd_smb2_request_error(req, status);
130 if (!NT_STATUS_IS_OK(error)) {
131 smbd_server_connection_terminate(req->sconn,
132 nt_errstr(error));
133 return;
135 return;
138 outbody = data_blob_talloc(req->out.vector, NULL, 0x10);
139 if (outbody.data == NULL) {
140 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
141 if (!NT_STATUS_IS_OK(error)) {
142 smbd_server_connection_terminate(req->sconn,
143 nt_errstr(error));
144 return;
146 return;
149 SSVAL(outbody.data, 0x00, 0x10 + 1); /* struct size */
150 SSVAL(outbody.data, 0x02, 0); /* reserved */
151 SIVAL(outbody.data, 0x04, out_count); /* count */
152 SIVAL(outbody.data, 0x08, 0); /* remaining */
153 SSVAL(outbody.data, 0x0C, 0); /* write channel info offset */
154 SSVAL(outbody.data, 0x0E, 0); /* write channel info length */
156 outdyn = data_blob_const(NULL, 0);
158 error = smbd_smb2_request_done(req, outbody, &outdyn);
159 if (!NT_STATUS_IS_OK(error)) {
160 smbd_server_connection_terminate(req->sconn, nt_errstr(error));
161 return;
165 struct smbd_smb2_write_state {
166 struct smbd_smb2_request *smb2req;
167 struct smb_request *smbreq;
168 files_struct *fsp;
169 bool write_through;
170 uint32_t in_length;
171 uint64_t in_offset;
172 uint32_t out_count;
175 static void smbd_smb2_write_pipe_done(struct tevent_req *subreq);
177 NTSTATUS smb2_write_complete(struct tevent_req *req, ssize_t nwritten, int err)
179 NTSTATUS status;
180 struct smbd_smb2_write_state *state = tevent_req_data(req,
181 struct smbd_smb2_write_state);
182 files_struct *fsp = state->fsp;
184 if (nwritten == -1) {
185 status = map_nt_error_from_unix(err);
187 DEBUG(2, ("smb2_write failed: %s, file %s, "
188 "length=%lu offset=%lu nwritten=-1: %s\n",
189 fsp_fnum_dbg(fsp),
190 fsp_str_dbg(fsp),
191 (unsigned long)state->in_length,
192 (unsigned long)state->in_offset,
193 nt_errstr(status)));
195 return status;
198 DEBUG(3,("smb2: %s, file %s, "
199 "length=%lu offset=%lu wrote=%lu\n",
200 fsp_fnum_dbg(fsp),
201 fsp_str_dbg(fsp),
202 (unsigned long)state->in_length,
203 (unsigned long)state->in_offset,
204 (unsigned long)nwritten));
206 if ((nwritten == 0) && (state->in_length != 0)) {
207 DEBUG(5,("smb2: write [%s] disk full\n",
208 fsp_str_dbg(fsp)));
209 return NT_STATUS_DISK_FULL;
212 status = sync_file(fsp->conn, fsp, state->write_through);
213 if (!NT_STATUS_IS_OK(status)) {
214 DEBUG(5,("smb2: sync_file for %s returned %s\n",
215 fsp_str_dbg(fsp),
216 nt_errstr(status)));
217 return status;
220 state->out_count = nwritten;
222 return NT_STATUS_OK;
225 static bool smbd_smb2_write_cancel(struct tevent_req *req)
227 struct smbd_smb2_write_state *state =
228 tevent_req_data(req,
229 struct smbd_smb2_write_state);
231 state->smb2req->cancelled = true;
233 return cancel_smb2_aio(state->smbreq);
236 static struct tevent_req *smbd_smb2_write_send(TALLOC_CTX *mem_ctx,
237 struct tevent_context *ev,
238 struct smbd_smb2_request *smb2req,
239 struct files_struct *fsp,
240 uint32_t in_smbpid,
241 DATA_BLOB in_data,
242 uint64_t in_offset,
243 uint32_t in_flags)
245 NTSTATUS status;
246 struct tevent_req *req = NULL;
247 struct smbd_smb2_write_state *state = NULL;
248 struct smb_request *smbreq = NULL;
249 connection_struct *conn = smb2req->tcon->compat;
250 ssize_t nwritten;
251 struct lock_struct lock;
253 req = tevent_req_create(mem_ctx, &state,
254 struct smbd_smb2_write_state);
255 if (req == NULL) {
256 return NULL;
258 state->smb2req = smb2req;
259 if (in_flags & SMB2_WRITEFLAG_WRITE_THROUGH) {
260 state->write_through = true;
262 state->in_length = in_data.length;
263 state->out_count = 0;
265 DEBUG(10,("smbd_smb2_write: %s - %s\n",
266 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
268 smbreq = smbd_smb2_fake_smb_request(smb2req);
269 if (tevent_req_nomem(smbreq, req)) {
270 return tevent_req_post(req, ev);
272 state->smbreq = smbreq;
274 state->fsp = fsp;
276 if (IS_IPC(smbreq->conn)) {
277 struct tevent_req *subreq = NULL;
279 if (!fsp_is_np(fsp)) {
280 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
281 return tevent_req_post(req, ev);
284 subreq = np_write_send(state, ev,
285 fsp->fake_file_handle,
286 in_data.data,
287 in_data.length);
288 if (tevent_req_nomem(subreq, req)) {
289 return tevent_req_post(req, ev);
291 tevent_req_set_callback(subreq,
292 smbd_smb2_write_pipe_done,
293 req);
294 return req;
297 if (!CHECK_WRITE(fsp)) {
298 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
299 return tevent_req_post(req, ev);
302 /* Try and do an asynchronous write. */
303 status = schedule_aio_smb2_write(conn,
304 smbreq,
305 fsp,
306 in_offset,
307 in_data,
308 state->write_through);
310 if (NT_STATUS_IS_OK(status)) {
312 * Doing an async write, allow this
313 * request to be canceled
315 tevent_req_set_cancel_fn(req, smbd_smb2_write_cancel);
316 return req;
319 if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
320 /* Real error in setting up aio. Fail. */
321 tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
322 return tevent_req_post(req, ev);
325 /* Fallback to synchronous. */
326 init_strict_lock_struct(fsp,
327 fsp->fnum,
328 in_offset,
329 in_data.length,
330 WRITE_LOCK,
331 &lock);
333 if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
334 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
335 return tevent_req_post(req, ev);
338 nwritten = write_file(smbreq, fsp,
339 (const char *)in_data.data,
340 in_offset,
341 in_data.length);
343 status = smb2_write_complete(req, nwritten, errno);
345 SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
347 DEBUG(10,("smb2: write on "
348 "file %s, offset %.0f, requested %u, written = %u\n",
349 fsp_str_dbg(fsp),
350 (double)in_offset,
351 (unsigned int)in_data.length,
352 (unsigned int)nwritten ));
354 if (!NT_STATUS_IS_OK(status)) {
355 tevent_req_nterror(req, status);
356 } else {
357 /* Success. */
358 tevent_req_done(req);
361 return tevent_req_post(req, ev);
364 static void smbd_smb2_write_pipe_done(struct tevent_req *subreq)
366 struct tevent_req *req = tevent_req_callback_data(subreq,
367 struct tevent_req);
368 struct smbd_smb2_write_state *state = tevent_req_data(req,
369 struct smbd_smb2_write_state);
370 NTSTATUS status;
371 ssize_t nwritten = -1;
373 status = np_write_recv(subreq, &nwritten);
374 TALLOC_FREE(subreq);
375 if (!NT_STATUS_IS_OK(status)) {
376 NTSTATUS old = status;
377 status = nt_status_np_pipe(old);
378 tevent_req_nterror(req, status);
379 return;
382 if ((nwritten == 0 && state->in_length != 0) || (nwritten < 0)) {
383 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
384 return;
387 state->out_count = nwritten;
389 tevent_req_done(req);
392 static NTSTATUS smbd_smb2_write_recv(struct tevent_req *req,
393 uint32_t *out_count)
395 NTSTATUS status;
396 struct smbd_smb2_write_state *state = tevent_req_data(req,
397 struct smbd_smb2_write_state);
399 if (tevent_req_is_nterror(req, &status)) {
400 tevent_req_received(req);
401 return status;
404 *out_count = state->out_count;
406 tevent_req_received(req);
407 return NT_STATUS_OK;