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