Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Core SMB2 server
4 :
5 : Copyright (C) Stefan Metzmacher 2009
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
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 "libcli/security/security.h"
27 :
28 : #undef DBGC_CLASS
29 : #define DBGC_CLASS DBGC_SMB2
30 :
31 : static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
32 : struct tevent_context *ev,
33 : struct smbd_smb2_request *smb2req,
34 : struct files_struct *fsp);
35 : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req);
36 :
37 : static void smbd_smb2_request_flush_done(struct tevent_req *subreq);
38 88 : NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
39 : {
40 0 : NTSTATUS status;
41 0 : const uint8_t *inbody;
42 0 : uint64_t in_file_id_persistent;
43 0 : uint64_t in_file_id_volatile;
44 0 : struct files_struct *in_fsp;
45 0 : struct tevent_req *subreq;
46 :
47 88 : status = smbd_smb2_request_verify_sizes(req, 0x18);
48 88 : if (!NT_STATUS_IS_OK(status)) {
49 0 : return smbd_smb2_request_error(req, status);
50 : }
51 88 : inbody = SMBD_SMB2_IN_BODY_PTR(req);
52 :
53 88 : in_file_id_persistent = BVAL(inbody, 0x08);
54 88 : in_file_id_volatile = BVAL(inbody, 0x10);
55 :
56 88 : in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
57 88 : if (in_fsp == NULL) {
58 0 : return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
59 : }
60 :
61 88 : subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
62 : req, in_fsp);
63 88 : if (subreq == NULL) {
64 0 : return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
65 : }
66 88 : tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
67 :
68 88 : return smbd_smb2_request_pending_queue(req, subreq, 500);
69 : }
70 :
71 88 : static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
72 : {
73 88 : struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
74 : struct smbd_smb2_request);
75 0 : DATA_BLOB outbody;
76 0 : NTSTATUS status;
77 0 : NTSTATUS error; /* transport error */
78 :
79 88 : status = smbd_smb2_flush_recv(subreq);
80 88 : TALLOC_FREE(subreq);
81 88 : if (!NT_STATUS_IS_OK(status)) {
82 16 : error = smbd_smb2_request_error(req, status);
83 16 : if (!NT_STATUS_IS_OK(error)) {
84 0 : smbd_server_connection_terminate(req->xconn,
85 : nt_errstr(error));
86 16 : return;
87 : }
88 16 : return;
89 : }
90 :
91 72 : outbody = smbd_smb2_generate_outbody(req, 0x04);
92 72 : if (outbody.data == NULL) {
93 0 : error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
94 0 : if (!NT_STATUS_IS_OK(error)) {
95 0 : smbd_server_connection_terminate(req->xconn,
96 : nt_errstr(error));
97 0 : return;
98 : }
99 0 : return;
100 : }
101 :
102 72 : SSVAL(outbody.data, 0x00, 0x04); /* struct size */
103 72 : SSVAL(outbody.data, 0x02, 0); /* reserved */
104 :
105 72 : error = smbd_smb2_request_done(req, outbody, NULL);
106 72 : if (!NT_STATUS_IS_OK(error)) {
107 0 : smbd_server_connection_terminate(req->xconn,
108 : nt_errstr(error));
109 0 : return;
110 : }
111 : }
112 :
113 : struct smbd_smb2_flush_state {
114 : struct smbd_smb2_request *smb2req;
115 : struct files_struct *fsp;
116 : };
117 :
118 : static void smbd_smb2_flush_done(struct tevent_req *subreq);
119 :
120 88 : static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
121 : struct tevent_context *ev,
122 : struct smbd_smb2_request *smb2req,
123 : struct files_struct *fsp)
124 : {
125 0 : struct tevent_req *req;
126 0 : struct tevent_req *subreq;
127 0 : struct smbd_smb2_flush_state *state;
128 0 : struct smb_request *smbreq;
129 88 : bool is_compound = false;
130 88 : bool is_last_in_compound = false;
131 0 : NTSTATUS status;
132 :
133 88 : req = tevent_req_create(mem_ctx, &state,
134 : struct smbd_smb2_flush_state);
135 88 : if (req == NULL) {
136 0 : return NULL;
137 : }
138 88 : state->smb2req = smb2req;
139 88 : state->fsp = fsp;
140 :
141 88 : DEBUG(10,("smbd_smb2_flush: %s - %s\n",
142 : fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
143 :
144 88 : smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
145 88 : if (tevent_req_nomem(smbreq, req)) {
146 0 : return tevent_req_post(req, ev);
147 : }
148 :
149 88 : if (IS_IPC(smbreq->conn)) {
150 0 : tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
151 0 : return tevent_req_post(req, ev);
152 : }
153 :
154 88 : status = check_any_access_fsp(fsp, FILE_WRITE_DATA|FILE_APPEND_DATA);
155 88 : if (!NT_STATUS_IS_OK(status)) {
156 16 : bool allow_dir_flush = false;
157 16 : uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
158 :
159 16 : if (!fsp->fsp_flags.is_directory) {
160 0 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
161 0 : return tevent_req_post(req, ev);
162 : }
163 :
164 : /*
165 : * Directories are not writable in the conventional
166 : * sense, but if opened with *either*
167 : * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
168 : * they can be flushed.
169 : */
170 :
171 16 : status = check_any_access_fsp(fsp, flush_access);
172 16 : if (NT_STATUS_IS_OK(status)) {
173 0 : allow_dir_flush = true;
174 : }
175 :
176 16 : if (allow_dir_flush == false) {
177 16 : tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
178 16 : return tevent_req_post(req, ev);
179 : }
180 : }
181 :
182 72 : if (fsp_get_io_fd(fsp) == -1) {
183 0 : tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
184 0 : return tevent_req_post(req, ev);
185 : }
186 :
187 72 : if (!lp_strict_sync(SNUM(smbreq->conn))) {
188 : /*
189 : * No strict sync. Don't really do
190 : * anything here.
191 : */
192 0 : tevent_req_done(req);
193 0 : return tevent_req_post(req, ev);
194 : }
195 :
196 72 : subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
197 72 : if (tevent_req_nomem(subreq, req)) {
198 0 : return tevent_req_post(req, ev);
199 : }
200 :
201 72 : tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
202 :
203 72 : is_compound = smbd_smb2_is_compound(smb2req);
204 72 : is_last_in_compound = smbd_smb2_is_last_in_compound(smb2req);
205 :
206 72 : if (is_compound && !is_last_in_compound) {
207 : /*
208 : * Can't go async if we're not the
209 : * last request in a compound request.
210 : * Cause this request to complete synchronously.
211 : */
212 4 : smb2_request_set_async_internal(state->smb2req, true);
213 : }
214 :
215 : /* Ensure any close request knows about this outstanding IO. */
216 72 : if (!aio_add_req_to_fsp(fsp, req)) {
217 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
218 0 : return tevent_req_post(req, ev);
219 : }
220 :
221 72 : return req;
222 :
223 : }
224 :
225 72 : static void smbd_smb2_flush_done(struct tevent_req *subreq)
226 : {
227 72 : struct tevent_req *req = tevent_req_callback_data(
228 : subreq, struct tevent_req);
229 72 : struct smbd_smb2_flush_state *state = tevent_req_data(
230 : req, struct smbd_smb2_flush_state);
231 0 : int ret;
232 0 : struct vfs_aio_state vfs_aio_state;
233 :
234 72 : ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
235 72 : TALLOC_FREE(subreq);
236 72 : if (ret == -1) {
237 0 : tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
238 0 : return;
239 : }
240 72 : if (state->fsp->fsp_flags.modified) {
241 42 : trigger_write_time_update_immediate(state->fsp);
242 : }
243 72 : tevent_req_done(req);
244 : }
245 :
246 88 : static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
247 : {
248 0 : NTSTATUS status;
249 :
250 88 : if (tevent_req_is_nterror(req, &status)) {
251 16 : tevent_req_received(req);
252 16 : return status;
253 : }
254 :
255 72 : tevent_req_received(req);
256 72 : return NT_STATUS_OK;
257 : }
|