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