pyldb: avoid segfault when adding an element with no name
[nivanova/samba-autobuild/.git] / source3 / smbd / smb2_flush.c
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 NTSTATUS smbd_smb2_request_process_flush(struct smbd_smb2_request *req)
39 {
40         NTSTATUS status;
41         const uint8_t *inbody;
42         uint64_t in_file_id_persistent;
43         uint64_t in_file_id_volatile;
44         struct files_struct *in_fsp;
45         struct tevent_req *subreq;
46
47         status = smbd_smb2_request_verify_sizes(req, 0x18);
48         if (!NT_STATUS_IS_OK(status)) {
49                 return smbd_smb2_request_error(req, status);
50         }
51         inbody = SMBD_SMB2_IN_BODY_PTR(req);
52
53         in_file_id_persistent   = BVAL(inbody, 0x08);
54         in_file_id_volatile     = BVAL(inbody, 0x10);
55
56         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
57         if (in_fsp == NULL) {
58                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
59         }
60
61         subreq = smbd_smb2_flush_send(req, req->sconn->ev_ctx,
62                                       req, in_fsp);
63         if (subreq == NULL) {
64                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
65         }
66         tevent_req_set_callback(subreq, smbd_smb2_request_flush_done, req);
67
68         return smbd_smb2_request_pending_queue(req, subreq, 500);
69 }
70
71 static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
72 {
73         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
74                                         struct smbd_smb2_request);
75         DATA_BLOB outbody;
76         NTSTATUS status;
77         NTSTATUS error; /* transport error */
78
79         status = smbd_smb2_flush_recv(subreq);
80         TALLOC_FREE(subreq);
81         if (!NT_STATUS_IS_OK(status)) {
82                 error = smbd_smb2_request_error(req, status);
83                 if (!NT_STATUS_IS_OK(error)) {
84                         smbd_server_connection_terminate(req->xconn,
85                                                          nt_errstr(error));
86                         return;
87                 }
88                 return;
89         }
90
91         outbody = smbd_smb2_generate_outbody(req, 0x04);
92         if (outbody.data == NULL) {
93                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
94                 if (!NT_STATUS_IS_OK(error)) {
95                         smbd_server_connection_terminate(req->xconn,
96                                                          nt_errstr(error));
97                         return;
98                 }
99                 return;
100         }
101
102         SSVAL(outbody.data, 0x00, 0x04);        /* struct size */
103         SSVAL(outbody.data, 0x02, 0);           /* reserved */
104
105         error = smbd_smb2_request_done(req, outbody, NULL);
106         if (!NT_STATUS_IS_OK(error)) {
107                 smbd_server_connection_terminate(req->xconn,
108                                                  nt_errstr(error));
109                 return;
110         }
111 }
112
113 struct smbd_smb2_flush_state {
114         struct smbd_smb2_request *smb2req;
115 };
116
117 static void smbd_smb2_flush_done(struct tevent_req *subreq);
118
119 static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
120                                                struct tevent_context *ev,
121                                                struct smbd_smb2_request *smb2req,
122                                                struct files_struct *fsp)
123 {
124         struct tevent_req *req;
125         struct tevent_req *subreq;
126         struct smbd_smb2_flush_state *state;
127         struct smb_request *smbreq;
128         int ret;
129
130         req = tevent_req_create(mem_ctx, &state,
131                                 struct smbd_smb2_flush_state);
132         if (req == NULL) {
133                 return NULL;
134         }
135         state->smb2req = smb2req;
136
137         DEBUG(10,("smbd_smb2_flush: %s - %s\n",
138                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
139
140         smbreq = smbd_smb2_fake_smb_request(smb2req);
141         if (tevent_req_nomem(smbreq, req)) {
142                 return tevent_req_post(req, ev);
143         }
144
145         if (IS_IPC(smbreq->conn)) {
146                 tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
147                 return tevent_req_post(req, ev);
148         }
149
150         if (!CHECK_WRITE(fsp)) {
151                 bool allow_dir_flush = false;
152                 uint32_t flush_access = FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY;
153
154                 if (!fsp->is_directory) {
155                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
156                         return tevent_req_post(req, ev);
157                 }
158
159                 /*
160                  * Directories are not writable in the conventional
161                  * sense, but if opened with *either*
162                  * FILE_ADD_FILE or FILE_ADD_SUBDIRECTORY
163                  * they can be flushed.
164                  */
165
166                 if ((fsp->access_mask & flush_access) != 0) {
167                         allow_dir_flush = true;
168                 }
169
170                 if (allow_dir_flush == false) {
171                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
172                         return tevent_req_post(req, ev);
173                 }
174         }
175
176         if (fsp->fh->fd == -1) {
177                 tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
178                 return tevent_req_post(req, ev);
179         }
180
181         if (!lp_strict_sync(SNUM(smbreq->conn))) {
182                 /*
183                  * No strict sync. Don't really do
184                  * anything here.
185                  */
186                 tevent_req_done(req);
187                 return tevent_req_post(req, ev);
188         }
189
190         ret = flush_write_cache(fsp, SAMBA_SYNC_FLUSH);
191         if (ret == -1) {
192                 tevent_req_nterror(req,  map_nt_error_from_unix(errno));
193                 return tevent_req_post(req, ev);
194         }
195
196         subreq = SMB_VFS_FSYNC_SEND(state, ev, fsp);
197         if (tevent_req_nomem(subreq, req)) {
198                 return tevent_req_post(req, ev);
199         }
200
201         tevent_req_set_callback(subreq, smbd_smb2_flush_done, req);
202
203         /* Ensure any close request knows about this outstanding IO. */
204         if (!aio_add_req_to_fsp(fsp, req)) {
205                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
206                 return tevent_req_post(req, ev);
207         }
208
209         return req;
210
211 }
212
213 static void smbd_smb2_flush_done(struct tevent_req *subreq)
214 {
215         struct tevent_req *req = tevent_req_callback_data(
216                 subreq, struct tevent_req);
217         int ret;
218         struct vfs_aio_state vfs_aio_state;
219
220         ret = SMB_VFS_FSYNC_RECV(subreq, &vfs_aio_state);
221         TALLOC_FREE(subreq);
222         if (ret == -1) {
223                 tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
224                 return;
225         }
226         tevent_req_done(req);
227 }
228
229 static NTSTATUS smbd_smb2_flush_recv(struct tevent_req *req)
230 {
231         NTSTATUS status;
232
233         if (tevent_req_is_nterror(req, &status)) {
234                 tevent_req_received(req);
235                 return status;
236         }
237
238         tevent_req_received(req);
239         return NT_STATUS_OK;
240 }