smbd: Remove "file_sync_all" function
[bbaumbach/samba-autobuild/.git] / source3 / smbd / smb2_setinfo.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6    Copyright (C) Jeremy Allison 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "../libcli/smb/smb_common.h"
26 #include "trans2.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "../librpc/gen_ndr/open_files.h"
29 #include "source3/lib/dbwrap/dbwrap_watch.h"
30 #include "messages.h"
31 #include "librpc/gen_ndr/ndr_quota.h"
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_SMB2
35
36 static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
37                                                  struct tevent_context *ev,
38                                                  struct smbd_smb2_request *smb2req,
39                                                  struct files_struct *in_fsp,
40                                                  uint8_t in_info_type,
41                                                  uint8_t in_file_info_class,
42                                                  DATA_BLOB in_input_buffer,
43                                                  uint32_t in_additional_information);
44 static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req);
45
46 static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq);
47 NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req)
48 {
49         struct smbXsrv_connection *xconn = req->xconn;
50         NTSTATUS status;
51         const uint8_t *inbody;
52         uint8_t in_info_type;
53         uint8_t in_file_info_class;
54         uint16_t in_input_buffer_offset;
55         uint32_t in_input_buffer_length;
56         DATA_BLOB in_input_buffer;
57         uint32_t in_additional_information;
58         uint64_t in_file_id_persistent;
59         uint64_t in_file_id_volatile;
60         struct files_struct *in_fsp;
61         struct tevent_req *subreq;
62
63         status = smbd_smb2_request_verify_sizes(req, 0x21);
64         if (!NT_STATUS_IS_OK(status)) {
65                 return smbd_smb2_request_error(req, status);
66         }
67         inbody = SMBD_SMB2_IN_BODY_PTR(req);
68
69         in_info_type                    = CVAL(inbody, 0x02);
70         in_file_info_class              = CVAL(inbody, 0x03);
71         in_input_buffer_length          = IVAL(inbody, 0x04);
72         in_input_buffer_offset          = SVAL(inbody, 0x08);
73         /* 0x0A 2 bytes reserved */
74         in_additional_information       = IVAL(inbody, 0x0C);
75         in_file_id_persistent           = BVAL(inbody, 0x10);
76         in_file_id_volatile             = BVAL(inbody, 0x18);
77
78         if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
79                 /* This is ok */
80         } else if (in_input_buffer_offset !=
81                    (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
82                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
83         }
84
85         if (in_input_buffer_length > SMBD_SMB2_IN_DYN_LEN(req)) {
86                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
87         }
88
89         in_input_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
90         in_input_buffer.length = in_input_buffer_length;
91
92         if (in_input_buffer.length > xconn->smb2.server.max_trans) {
93                 DEBUG(2,("smbd_smb2_request_process_setinfo: "
94                          "client ignored max trans: %s: 0x%08X: 0x%08X\n",
95                          __location__, (unsigned)in_input_buffer.length,
96                          (unsigned)xconn->smb2.server.max_trans));
97                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
98         }
99
100         status = smbd_smb2_request_verify_creditcharge(req,
101                                                 in_input_buffer.length);
102         if (!NT_STATUS_IS_OK(status)) {
103                 return smbd_smb2_request_error(req, status);
104         }
105
106         in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
107         if (in_fsp == NULL) {
108                 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
109         }
110
111         subreq = smbd_smb2_setinfo_send(req, req->ev_ctx,
112                                         req, in_fsp,
113                                         in_info_type,
114                                         in_file_info_class,
115                                         in_input_buffer,
116                                         in_additional_information);
117         if (subreq == NULL) {
118                 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
119         }
120         tevent_req_set_callback(subreq, smbd_smb2_request_setinfo_done, req);
121
122         return smbd_smb2_request_pending_queue(req, subreq, 500);
123 }
124
125 static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq)
126 {
127         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
128                                         struct smbd_smb2_request);
129         DATA_BLOB outbody;
130         NTSTATUS status;
131         NTSTATUS error; /* transport error */
132
133         status = smbd_smb2_setinfo_recv(subreq);
134         TALLOC_FREE(subreq);
135         if (!NT_STATUS_IS_OK(status)) {
136                 error = smbd_smb2_request_error(req, status);
137                 if (!NT_STATUS_IS_OK(error)) {
138                         smbd_server_connection_terminate(req->xconn,
139                                                          nt_errstr(error));
140                         return;
141                 }
142                 return;
143         }
144
145         outbody = smbd_smb2_generate_outbody(req, 0x02);
146         if (outbody.data == NULL) {
147                 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
148                 if (!NT_STATUS_IS_OK(error)) {
149                         smbd_server_connection_terminate(req->xconn,
150                                                          nt_errstr(error));
151                         return;
152                 }
153                 return;
154         }
155
156         SSVAL(outbody.data, 0x00, 0x02);        /* struct size */
157
158         error = smbd_smb2_request_done(req, outbody, NULL);
159         if (!NT_STATUS_IS_OK(error)) {
160                 smbd_server_connection_terminate(req->xconn,
161                                                  nt_errstr(error));
162                 return;
163         }
164 }
165
166 struct defer_rename_state {
167         struct tevent_req *req;
168         struct smbd_smb2_request *smb2req;
169         struct tevent_context *ev;
170         struct files_struct *fsp;
171         char *data;
172         int data_size;
173 };
174
175 static int defer_rename_state_destructor(struct defer_rename_state *rename_state)
176 {
177         SAFE_FREE(rename_state->data);
178         return 0;
179 }
180
181 static void defer_rename_done(struct tevent_req *subreq);
182
183 static struct tevent_req *delay_rename_for_lease_break(struct tevent_req *req,
184                                 struct smbd_smb2_request *smb2req,
185                                 struct tevent_context *ev,
186                                 struct files_struct *fsp,
187                                 struct share_mode_lock *lck,
188                                 char *data,
189                                 int data_size)
190
191 {
192         struct tevent_req *subreq;
193         uint32_t i;
194         struct share_mode_data *d = lck->data;
195         struct defer_rename_state *rename_state;
196         bool delay = false;
197         struct timeval timeout;
198
199         if (fsp->oplock_type != LEASE_OPLOCK) {
200                 return NULL;
201         }
202
203         for (i=0; i<d->num_share_modes; i++) {
204                 struct share_mode_entry *e = &d->share_modes[i];
205                 struct share_mode_lease *l = NULL;
206                 uint32_t e_lease_type = get_lease_type(d, e);
207                 uint32_t break_to;
208
209                 if (e->op_type != LEASE_OPLOCK) {
210                         continue;
211                 }
212
213                 l = &d->leases[e->lease_idx];
214
215                 if (smb2_lease_equal(fsp_client_guid(fsp),
216                                 &fsp->lease->lease.lease_key,
217                                 &l->client_guid,
218                                 &l->lease_key)) {
219                         continue;
220                 }
221
222                 if (share_mode_stale_pid(d, i)) {
223                         continue;
224                 }
225
226                 if (!(e_lease_type & SMB2_LEASE_HANDLE)) {
227                         continue;
228                 }
229
230                 delay = true;
231                 break_to = (e_lease_type & ~SMB2_LEASE_HANDLE);
232
233                 send_break_message(fsp->conn->sconn->msg_ctx, &fsp->file_id,
234                                    e, break_to);
235         }
236
237         if (!delay) {
238                 return NULL;
239         }
240
241         /* Setup a watch on this record. */
242         rename_state = talloc_zero(req, struct defer_rename_state);
243         if (rename_state == NULL) {
244                 return NULL;
245         }
246
247         rename_state->req = req;
248         rename_state->smb2req = smb2req;
249         rename_state->ev = ev;
250         rename_state->fsp = fsp;
251         rename_state->data = data;
252         rename_state->data_size = data_size;
253
254         talloc_set_destructor(rename_state, defer_rename_state_destructor);
255
256         subreq = dbwrap_watched_watch_send(
257                                 rename_state,
258                                 ev,
259                                 lck->data->record,
260                                 (struct server_id){0});
261
262         if (subreq == NULL) {
263                 exit_server("Could not watch share mode record for rename\n");
264         }
265
266         tevent_req_set_callback(subreq, defer_rename_done, rename_state);
267
268         timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
269         if (!tevent_req_set_endtime(subreq,
270                         ev,
271                         timeval_sum(&smb2req->request_time, &timeout))) {
272                 exit_server("Could not set rename timeout\n");
273         }
274
275         return subreq;
276 }
277
278 static void defer_rename_done(struct tevent_req *subreq)
279 {
280         struct defer_rename_state *state = tevent_req_callback_data(
281                 subreq, struct defer_rename_state);
282         NTSTATUS status;
283         struct share_mode_lock *lck;
284         int ret_size = 0;
285
286         status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
287         TALLOC_FREE(subreq);
288         if (!NT_STATUS_IS_OK(status)) {
289                 DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
290                         nt_errstr(status)));
291                 tevent_req_nterror(state->req, status);
292                 return;
293         }
294
295         /* Do we still need to wait ? */
296         lck = get_existing_share_mode_lock(state->req, state->fsp->file_id);
297         if (lck == NULL) {
298                 tevent_req_nterror(state->req, NT_STATUS_UNSUCCESSFUL);
299                 return;
300         }
301         subreq = delay_rename_for_lease_break(state->req,
302                                 state->smb2req,
303                                 state->ev,
304                                 state->fsp,
305                                 lck,
306                                 state->data,
307                                 state->data_size);
308         if (subreq) {
309                 /* Yep - keep waiting. */
310                 state->data = NULL;
311                 TALLOC_FREE(state);
312                 TALLOC_FREE(lck);
313                 return;
314         }
315
316         /* Do the rename under the lock. */
317         status = smbd_do_setfilepathinfo(state->fsp->conn,
318                                 state->smb2req->smb1req,
319                                 state,
320                                 SMB2_FILE_RENAME_INFORMATION_INTERNAL,
321                                 state->fsp,
322                                 state->fsp->fsp_name,
323                                 &state->data,
324                                 state->data_size,
325                                 &ret_size);
326
327         TALLOC_FREE(lck);
328         SAFE_FREE(state->data);
329
330         if (!NT_STATUS_IS_OK(status)) {
331                 tevent_req_nterror(state->req, status);
332                 return;
333         }
334
335         tevent_req_done(state->req);
336 }
337
338 struct smbd_smb2_setinfo_state {
339         struct smbd_smb2_request *smb2req;
340 };
341
342 static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
343                                                  struct tevent_context *ev,
344                                                  struct smbd_smb2_request *smb2req,
345                                                  struct files_struct *fsp,
346                                                  uint8_t in_info_type,
347                                                  uint8_t in_file_info_class,
348                                                  DATA_BLOB in_input_buffer,
349                                                  uint32_t in_additional_information)
350 {
351         struct tevent_req *req = NULL;
352         struct smbd_smb2_setinfo_state *state = NULL;
353         struct smb_request *smbreq = NULL;
354         connection_struct *conn = smb2req->tcon->compat;
355         struct share_mode_lock *lck = NULL;
356         NTSTATUS status;
357
358         req = tevent_req_create(mem_ctx, &state,
359                                 struct smbd_smb2_setinfo_state);
360         if (req == NULL) {
361                 return NULL;
362         }
363         state->smb2req = smb2req;
364
365         DEBUG(10,("smbd_smb2_setinfo_send: %s - %s\n",
366                   fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
367
368         smbreq = smbd_smb2_fake_smb_request(smb2req);
369         if (tevent_req_nomem(smbreq, req)) {
370                 return tevent_req_post(req, ev);
371         }
372
373         if (IS_IPC(conn)) {
374                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
375                 return tevent_req_post(req, ev);
376         }
377
378         switch (in_info_type) {
379         case 0x01:/* SMB2_SETINFO_FILE */
380         {
381                 uint16_t file_info_level;
382                 char *data;
383                 int data_size;
384                 int ret_size = 0;
385
386
387                 file_info_level = in_file_info_class + 1000;
388                 if (file_info_level == SMB_FILE_RENAME_INFORMATION) {
389                         /* SMB2_FILE_RENAME_INFORMATION_INTERNAL == 0xFF00 + in_file_info_class */
390                         file_info_level = SMB2_FILE_RENAME_INFORMATION_INTERNAL;
391                 }
392
393                 if (fsp->fh->fd == -1) {
394                         /*
395                          * This is actually a SETFILEINFO on a directory
396                          * handle (returned from an NT SMB). NT5.0 seems
397                          * to do this call. JRA.
398                          */
399                         if (INFO_LEVEL_IS_UNIX(file_info_level)) {
400                                 /* Always do lstat for UNIX calls. */
401                                 if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) {
402                                         DEBUG(3,("smbd_smb2_setinfo_send: "
403                                                  "SMB_VFS_LSTAT of %s failed "
404                                                  "(%s)\n", fsp_str_dbg(fsp),
405                                                  strerror(errno)));
406                                         status = map_nt_error_from_unix(errno);
407                                         tevent_req_nterror(req, status);
408                                         return tevent_req_post(req, ev);
409                                 }
410                         } else {
411                                 if (SMB_VFS_STAT(conn, fsp->fsp_name) != 0) {
412                                         DEBUG(3,("smbd_smb2_setinfo_send: "
413                                                  "fileinfo of %s failed (%s)\n",
414                                                  fsp_str_dbg(fsp),
415                                                  strerror(errno)));
416                                         status = map_nt_error_from_unix(errno);
417                                         tevent_req_nterror(req, status);
418                                         return tevent_req_post(req, ev);
419                                 }
420                         }
421                 } else if (fsp->print_file) {
422                         /*
423                          * Doing a DELETE_ON_CLOSE should cancel a print job.
424                          */
425                         if ((file_info_level == SMB_SET_FILE_DISPOSITION_INFO)
426                             && in_input_buffer.length >= 1
427                             && CVAL(in_input_buffer.data,0)) {
428                                 fsp->fh->private_options |= NTCREATEX_OPTIONS_PRIVATE_DELETE_ON_CLOSE;
429
430                                 DEBUG(3,("smbd_smb2_setinfo_send: "
431                                          "Cancelling print job (%s)\n",
432                                          fsp_str_dbg(fsp)));
433
434                                 tevent_req_done(req);
435                                 return tevent_req_post(req, ev);
436                         } else {
437                                 tevent_req_nterror(req,
438                                         NT_STATUS_OBJECT_PATH_INVALID);
439                                 return tevent_req_post(req, ev);
440                         }
441                 } else {
442                         /*
443                          * Original code - this is an open file.
444                          */
445
446                         if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
447                                 DEBUG(3,("smbd_smb2_setinfo_send: fstat "
448                                          "of %s failed (%s)\n",
449                                          fsp_fnum_dbg(fsp),
450                                          strerror(errno)));
451                                 status = map_nt_error_from_unix(errno);
452                                 tevent_req_nterror(req, status);
453                                 return tevent_req_post(req, ev);
454                         }
455                 }
456
457                 data = NULL;
458                 data_size = in_input_buffer.length;
459                 if (data_size > 0) {
460                         data = (char *)SMB_MALLOC_ARRAY(char, data_size);
461                         if (tevent_req_nomem(data, req)) {
462                                 return tevent_req_post(req, ev);
463                         }
464                         memcpy(data, in_input_buffer.data, data_size);
465                 }
466
467                 if (file_info_level == SMB2_FILE_RENAME_INFORMATION_INTERNAL) {
468                         struct tevent_req *subreq;
469
470                         lck = get_existing_share_mode_lock(mem_ctx,
471                                                         fsp->file_id);
472                         if (lck == NULL) {
473                                 SAFE_FREE(data);
474                                 tevent_req_nterror(req,
475                                         NT_STATUS_UNSUCCESSFUL);
476                                 return tevent_req_post(req, ev);
477                         }
478
479                         subreq = delay_rename_for_lease_break(req,
480                                                         smb2req,
481                                                         ev,
482                                                         fsp,
483                                                         lck,
484                                                         data,
485                                                         data_size);
486                         if (subreq) {
487                                 /* Wait for lease break response. */
488
489                                 /* Ensure we can't be closed in flight. */
490                                 if (!aio_add_req_to_fsp(fsp, req)) {
491                                         TALLOC_FREE(lck);
492                                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
493                                         return tevent_req_post(req, ev);
494                                 }
495
496                                 TALLOC_FREE(lck);
497                                 return req;
498                         }
499                 }
500
501                 status = smbd_do_setfilepathinfo(conn, smbreq, state,
502                                                  file_info_level,
503                                                  fsp,
504                                                  fsp->fsp_name,
505                                                  &data,
506                                                  data_size,
507                                                  &ret_size);
508                 TALLOC_FREE(lck);
509                 SAFE_FREE(data);
510                 if (!NT_STATUS_IS_OK(status)) {
511                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
512                                 status = NT_STATUS_INVALID_INFO_CLASS;
513                         }
514                         tevent_req_nterror(req, status);
515                         return tevent_req_post(req, ev);
516                 }
517                 break;
518         }
519
520         case 0x02:/* SMB2_SETINFO_FS */
521         {
522                 uint16_t file_info_level = in_file_info_class + 1000;
523
524                 status = smbd_do_setfsinfo(conn, smbreq, state,
525                                         file_info_level,
526                                         fsp,
527                                         &in_input_buffer);
528                 if (!NT_STATUS_IS_OK(status)) {
529                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
530                                 status = NT_STATUS_INVALID_INFO_CLASS;
531                         }
532                         tevent_req_nterror(req, status);
533                         return tevent_req_post(req, ev);
534                 }
535                 break;
536         }
537
538         case 0x03:/* SMB2_SETINFO_SECURITY */
539         {
540                 if (!CAN_WRITE(conn)) {
541                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
542                         return tevent_req_post(req, ev);
543                 }
544
545                 status = set_sd_blob(fsp,
546                                 in_input_buffer.data,
547                                 in_input_buffer.length,
548                                 in_additional_information &
549                                 SMB_SUPPORTED_SECINFO_FLAGS);
550                 if (!NT_STATUS_IS_OK(status)) {
551                         tevent_req_nterror(req, status);
552                         return tevent_req_post(req, ev);
553                 }
554                 break;
555         }
556
557         case 0x04:/* SMB2_SETINFO_QUOTA */
558         {
559 #ifdef HAVE_SYS_QUOTAS
560                 struct file_quota_information info = {0};
561                 SMB_NTQUOTA_STRUCT qt = {0};
562                 enum ndr_err_code err;
563                 int ret;
564
565                 if (!fsp->fake_file_handle) {
566                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
567                         return tevent_req_post(req, ev);
568                 }
569                 err = ndr_pull_struct_blob(
570                         &in_input_buffer, state, &info,
571                         (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
572                 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
573                         tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
574                         return tevent_req_post(req, ev);
575                 }
576
577                 qt.usedspace = info.quota_used;
578
579                 qt.softlim = info.quota_threshold;
580
581                 qt.hardlim = info.quota_limit;
582
583                 qt.sid = info.sid;
584                 ret = vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &qt.sid, &qt);
585                 if (ret !=0 ) {
586                         status = map_nt_error_from_unix(errno);
587                         tevent_req_nterror(req, status);
588                         return tevent_req_post(req, ev);
589                 }
590                 status = NT_STATUS_OK;
591                 break;
592 #else
593                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
594                 return tevent_req_post(req, ev);
595 #endif
596         }
597         default:
598                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
599                 return tevent_req_post(req, ev);
600         }
601
602         tevent_req_done(req);
603         return tevent_req_post(req, ev);
604 }
605
606 static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req)
607 {
608         NTSTATUS status;
609
610         if (tevent_req_is_nterror(req, &status)) {
611                 tevent_req_received(req);
612                 return status;
613         }
614
615         tevent_req_received(req);
616         return NT_STATUS_OK;
617 }