s3:smbd: send SMB2 interim responses for async calls
[metze/samba/wip.git] / source3 / smbd / smb2_create.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/globals.h"
23 #include "../source4/libcli/smb2/smb2_constants.h"
24
25 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
26                                                 struct tevent_context *ev,
27                                                 struct smbd_smb2_request *smb2req,
28                                                 uint8_t in_oplock_level,
29                                                 uint32_t in_impersonation_level,
30                                                 uint32_t in_desired_access,
31                                                 uint32_t in_file_attributes,
32                                                 uint32_t in_share_access,
33                                                 uint32_t in_create_disposition,
34                                                 uint32_t in_create_options,
35                                                 const char *in_name);
36 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
37                                       uint8_t *out_oplock_level,
38                                       uint32_t *out_create_action,
39                                       NTTIME *out_creation_time,
40                                       NTTIME *out_last_access_time,
41                                       NTTIME *out_last_write_time,
42                                       NTTIME *out_change_time,
43                                       uint64_t *out_allocation_size,
44                                       uint64_t *out_end_of_file,
45                                       uint32_t *out_file_attributes,
46                                       uint64_t *out_file_id_volatile);
47
48 static void smbd_smb2_request_create_done(struct tevent_req *subreq);
49 NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *req)
50 {
51         const uint8_t *inbody;
52         int i = req->current_idx;
53         size_t expected_body_size = 0x39;
54         size_t body_size;
55         uint8_t in_oplock_level;
56         uint32_t in_impersonation_level;
57         uint32_t in_desired_access;
58         uint32_t in_file_attributes;
59         uint32_t in_share_access;
60         uint32_t in_create_disposition;
61         uint32_t in_create_options;
62         uint16_t in_name_offset;
63         uint16_t in_name_length;
64         DATA_BLOB in_name_buffer;
65         char *in_name_string;
66         size_t in_name_string_size;
67         bool ok;
68         struct tevent_req *subreq;
69
70         if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
71                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
72         }
73
74         inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
75
76         body_size = SVAL(inbody, 0x00);
77         if (body_size != expected_body_size) {
78                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
79         }
80
81         in_oplock_level         = CVAL(inbody, 0x03);
82         in_impersonation_level  = IVAL(inbody, 0x04);
83         in_desired_access       = IVAL(inbody, 0x18);
84         in_file_attributes      = IVAL(inbody, 0x1C);
85         in_share_access         = IVAL(inbody, 0x20);
86         in_create_disposition   = IVAL(inbody, 0x24);
87         in_create_options       = IVAL(inbody, 0x28);
88         in_name_offset          = SVAL(inbody, 0x2C);
89         in_name_length          = SVAL(inbody, 0x2E);
90
91         if (in_name_offset != (SMB2_HDR_BODY + (body_size & 0xFFFFFFFE))) {
92                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
93         }
94
95         if (in_name_length > req->in.vector[i+2].iov_len) {
96                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
97         }
98
99         in_name_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
100         in_name_buffer.length = in_name_length;
101
102         ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
103                                    in_name_buffer.data,
104                                    in_name_buffer.length,
105                                    &in_name_string,
106                                    &in_name_string_size, false);
107         if (!ok) {
108                 return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
109         }
110
111         subreq = smbd_smb2_create_send(req,
112                                        req->conn->smb2.event_ctx,
113                                        req,
114                                        in_oplock_level,
115                                        in_impersonation_level,
116                                        in_desired_access,
117                                        in_file_attributes,
118                                        in_share_access,
119                                        in_create_disposition,
120                                        in_create_options,
121                                        in_name_string);
122         if (subreq == NULL) {
123                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
124         }
125         tevent_req_set_callback(subreq, smbd_smb2_request_create_done, req);
126
127         if (tevent_req_is_in_progress(subreq)) {
128                 return smbd_smb2_request_pending_queue(req);
129         }
130
131         return NT_STATUS_OK;
132 }
133
134 static void smbd_smb2_request_create_done(struct tevent_req *subreq)
135 {
136         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
137                                         struct smbd_smb2_request);
138         int i = req->current_idx;
139         uint8_t *outhdr;
140         DATA_BLOB outbody;
141         DATA_BLOB outdyn;
142         uint8_t out_oplock_level;
143         uint32_t out_create_action;
144         NTTIME out_creation_time;
145         NTTIME out_last_access_time;
146         NTTIME out_last_write_time;
147         NTTIME out_change_time;
148         uint64_t out_allocation_size;
149         uint64_t out_end_of_file;
150         uint32_t out_file_attributes;
151         uint64_t out_file_id_volatile;
152         NTSTATUS status;
153         NTSTATUS error; /* transport error */
154
155         status = smbd_smb2_create_recv(subreq,
156                                        &out_oplock_level,
157                                        &out_create_action,
158                                        &out_creation_time,
159                                        &out_last_access_time,
160                                        &out_last_write_time,
161                                        &out_change_time,
162                                        &out_allocation_size,
163                                        &out_end_of_file,
164                                        &out_file_attributes,
165                                        &out_file_id_volatile);
166         TALLOC_FREE(subreq);
167         if (!NT_STATUS_IS_OK(status)) {
168                 error = smbd_smb2_request_error(req, status);
169                 if (!NT_STATUS_IS_OK(error)) {
170                         smbd_server_connection_terminate(req->conn,
171                                                          nt_errstr(error));
172                         return;
173                 }
174                 return;
175         }
176
177         outhdr = (uint8_t *)req->out.vector[i].iov_base;
178
179         outbody = data_blob_talloc(req->out.vector, NULL, 0x58);
180         if (outbody.data == NULL) {
181                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
182                 if (!NT_STATUS_IS_OK(error)) {
183                         smbd_server_connection_terminate(req->conn,
184                                                          nt_errstr(error));
185                         return;
186                 }
187                 return;
188         }
189
190         SSVAL(outbody.data, 0x00, 0x58 + 1);    /* struct size */
191         SCVAL(outbody.data, 0x02,
192               out_oplock_level);                /* oplock level */
193         SCVAL(outbody.data, 0x03, 0);           /* reserved */
194         SIVAL(outbody.data, 0x04,
195               out_create_action);               /* create action */
196         SBVAL(outbody.data, 0x08,
197               out_creation_time);               /* creation time */
198         SBVAL(outbody.data, 0x10,
199               out_last_access_time);            /* last access time */
200         SBVAL(outbody.data, 0x18,
201               out_last_write_time);             /* last write time */
202         SBVAL(outbody.data, 0x20,
203               out_change_time);                 /* change time */
204         SBVAL(outbody.data, 0x28,
205               out_allocation_size);             /* allocation size */
206         SBVAL(outbody.data, 0x30,
207               out_end_of_file);                 /* end of file */
208         SIVAL(outbody.data, 0x38,
209               out_file_attributes);             /* file attributes */
210         SIVAL(outbody.data, 0x3C, 0);           /* reserved */
211         SBVAL(outbody.data, 0x40, 0);           /* file id (persistent) */
212         SBVAL(outbody.data, 0x48,
213               out_file_id_volatile);            /* file id (volatile) */
214         SIVAL(outbody.data, 0x50, 0);           /* create contexts offset */
215         SIVAL(outbody.data, 0x54, 0);           /* create contexts length */
216
217         outdyn = data_blob_const(NULL, 0);
218
219         error = smbd_smb2_request_done(req, outbody, &outdyn);
220         if (!NT_STATUS_IS_OK(error)) {
221                 smbd_server_connection_terminate(req->conn,
222                                                  nt_errstr(error));
223                 return;
224         }
225 }
226
227 struct smbd_smb2_create_state {
228         struct smbd_smb2_request *smb2req;
229         uint8_t out_oplock_level;
230         uint32_t out_create_action;
231         NTTIME out_creation_time;
232         NTTIME out_last_access_time;
233         NTTIME out_last_write_time;
234         NTTIME out_change_time;
235         uint64_t out_allocation_size;
236         uint64_t out_end_of_file;
237         uint32_t out_file_attributes;
238         uint64_t out_file_id_volatile;
239 };
240
241 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
242                                                 struct tevent_context *ev,
243                                                 struct smbd_smb2_request *smb2req,
244                                                 uint8_t in_oplock_level,
245                                                 uint32_t in_impersonation_level,
246                                                 uint32_t in_desired_access,
247                                                 uint32_t in_file_attributes,
248                                                 uint32_t in_share_access,
249                                                 uint32_t in_create_disposition,
250                                                 uint32_t in_create_options,
251                                                 const char *in_name)
252 {
253         struct tevent_req *req;
254         struct smbd_smb2_create_state *state;
255         NTSTATUS status;
256         struct smb_request *smbreq;
257         files_struct *result;
258         int info;
259         SMB_STRUCT_STAT sbuf;
260         struct smb_filename *smb_fname = NULL;
261
262         req = tevent_req_create(mem_ctx, &state,
263                                 struct smbd_smb2_create_state);
264         if (req == NULL) {
265                 return NULL;
266         }
267         state->smb2req = smb2req;
268
269         DEBUG(10,("smbd_smb2_create: name[%s]\n",
270                   in_name));
271
272         smbreq = smbd_smb2_fake_smb_request(smb2req);
273         if (tevent_req_nomem(smbreq, req)) {
274                 goto out;
275         }
276
277         if (IS_IPC(smbreq->conn)) {
278                 const char *pipe_name = in_name;
279
280                 if (!lp_nt_pipe_support()) {
281                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
282                         goto out;
283                 }
284
285                 /* Strip \\ off the name. */
286                 if (pipe_name[0] == '\\') {
287                         pipe_name++;
288                 }
289
290                 status = open_np_file(smbreq, pipe_name, &result);
291                 if (!NT_STATUS_IS_OK(status)) {
292                         tevent_req_nterror(req, status);
293                         goto out;
294                 }
295                 info = FILE_WAS_OPENED;
296                 ZERO_STRUCT(sbuf);
297         } else if (CAN_PRINT(smbreq->conn)) {
298                 status = file_new(smbreq, smbreq->conn, &result);
299                 if(!NT_STATUS_IS_OK(status)) {
300                         tevent_req_nterror(req, status);
301                         goto out;
302                 }
303
304                 status = print_fsp_open(smbreq,
305                                         smbreq->conn,
306                                         in_name,
307                                         smbreq->vuid,
308                                         result,
309                                         &sbuf);
310                 if (!NT_STATUS_IS_OK(status)) {
311                         file_free(smbreq, result);
312                         tevent_req_nterror(req, status);
313                         goto out;
314                 }
315                 info = FILE_WAS_CREATED;
316         } else {
317                 char *fname = NULL;
318
319                 /* these are ignored for SMB2 */
320                 in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
321                 in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
322
323                 status = filename_convert(talloc_tos(),
324                                         smbreq->conn,
325                                         smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
326                                         in_name,
327                                         &smb_fname,
328                                         &fname);
329                 if (!NT_STATUS_IS_OK(status)) {
330                         tevent_req_nterror(req, status);
331                         goto out;
332                 }
333
334                 status = SMB_VFS_CREATE_FILE(smbreq->conn,
335                                              smbreq,
336                                              0, /* root_dir_fid */
337                                              smb_fname,
338                                              in_desired_access,
339                                              in_share_access,
340                                              in_create_disposition,
341                                              in_create_options,
342                                              in_file_attributes,
343                                              0, /* oplock_request */
344                                              0, /* allocation_size */
345                                              NULL, /* security_descriptor */
346                                              NULL, /* ea_list */
347                                              &result,
348                                              &info);
349                 if (!NT_STATUS_IS_OK(status)) {
350                         tevent_req_nterror(req, status);
351                         goto out;
352                 }
353                 sbuf = smb_fname->st;
354         }
355
356         smb2req->compat_chain_fsp = smbreq->chain_fsp;
357
358         state->out_oplock_level = 0;
359         if ((in_create_disposition == FILE_SUPERSEDE)
360             && (info == FILE_WAS_OVERWRITTEN)) {
361                 state->out_create_action = FILE_WAS_SUPERSEDED;
362         } else {
363                 state->out_create_action = info;
364         }
365         unix_timespec_to_nt_time(&state->out_creation_time, sbuf.st_ex_btime);
366         unix_timespec_to_nt_time(&state->out_last_access_time, sbuf.st_ex_atime);
367         unix_timespec_to_nt_time(&state->out_last_write_time,sbuf.st_ex_mtime);
368         unix_timespec_to_nt_time(&state->out_change_time, sbuf.st_ex_ctime);
369         state->out_allocation_size      = sbuf.st_ex_blksize * sbuf.st_ex_blocks;
370         state->out_end_of_file          = sbuf.st_ex_size;
371         state->out_file_attributes      = dos_mode(result->conn,
372                                                    result->fsp_name,
373                                                    &sbuf);
374         if (state->out_file_attributes == 0) {
375                 state->out_file_attributes = FILE_ATTRIBUTE_NORMAL;
376         }
377         state->out_file_id_volatile = result->fnum;
378
379         tevent_req_done(req);
380  out:
381         TALLOC_FREE(smb_fname);
382         return tevent_req_post(req, ev);
383 }
384
385 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
386                                       uint8_t *out_oplock_level,
387                                       uint32_t *out_create_action,
388                                       NTTIME *out_creation_time,
389                                       NTTIME *out_last_access_time,
390                                       NTTIME *out_last_write_time,
391                                       NTTIME *out_change_time,
392                                       uint64_t *out_allocation_size,
393                                       uint64_t *out_end_of_file,
394                                       uint32_t *out_file_attributes,
395                                       uint64_t *out_file_id_volatile)
396 {
397         NTSTATUS status;
398         struct smbd_smb2_create_state *state = tevent_req_data(req,
399                                                struct smbd_smb2_create_state);
400
401         if (tevent_req_is_nterror(req, &status)) {
402                 tevent_req_received(req);
403                 return status;
404         }
405
406         *out_oplock_level       = state->out_oplock_level;
407         *out_create_action      = state->out_create_action;
408         *out_creation_time      = state->out_creation_time;
409         *out_last_access_time   = state->out_last_access_time;
410         *out_last_write_time    = state->out_last_write_time;
411         *out_change_time        = state->out_change_time;
412         *out_allocation_size    = state->out_allocation_size;
413         *out_end_of_file        = state->out_end_of_file;
414         *out_file_attributes    = state->out_file_attributes;
415         *out_file_id_volatile   = state->out_file_id_volatile;
416
417         tevent_req_received(req);
418         return NT_STATUS_OK;
419 }