s3: smbd: Correctly set smb2req->smb1req->posix_pathnames from the calling fsp on...
[Samba.git] / source3 / smbd / smb2_setinfo.c
blobf26fce77a2397bf557cd677a294d4593f1f28b8d
1 /*
2 Unix SMB/CIFS implementation.
3 Core SMB2 server
5 Copyright (C) Stefan Metzmacher 2009
6 Copyright (C) Jeremy Allison 2010
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.
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.
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/>.
22 #include "includes.h"
23 #include "locking/share_mode_lock.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "../libcli/smb/smb_common.h"
27 #include "trans2.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "../librpc/gen_ndr/open_files.h"
30 #include "source3/lib/dbwrap/dbwrap_watch.h"
31 #include "messages.h"
32 #include "librpc/gen_ndr/ndr_quota.h"
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_SMB2
37 static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
38 struct tevent_context *ev,
39 struct smbd_smb2_request *smb2req,
40 struct files_struct *in_fsp,
41 uint8_t in_info_type,
42 uint8_t in_file_info_class,
43 DATA_BLOB in_input_buffer,
44 uint32_t in_additional_information);
45 static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req);
47 static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq);
48 NTSTATUS smbd_smb2_request_process_setinfo(struct smbd_smb2_request *req)
50 struct smbXsrv_connection *xconn = req->xconn;
51 NTSTATUS status;
52 const uint8_t *inbody;
53 uint8_t in_info_type;
54 uint8_t in_file_info_class;
55 uint16_t in_input_buffer_offset;
56 uint32_t in_input_buffer_length;
57 DATA_BLOB in_input_buffer;
58 uint32_t in_additional_information;
59 uint64_t in_file_id_persistent;
60 uint64_t in_file_id_volatile;
61 struct files_struct *in_fsp;
62 struct tevent_req *subreq;
64 status = smbd_smb2_request_verify_sizes(req, 0x21);
65 if (!NT_STATUS_IS_OK(status)) {
66 return smbd_smb2_request_error(req, status);
68 inbody = SMBD_SMB2_IN_BODY_PTR(req);
70 in_info_type = CVAL(inbody, 0x02);
71 in_file_info_class = CVAL(inbody, 0x03);
72 in_input_buffer_length = IVAL(inbody, 0x04);
73 in_input_buffer_offset = SVAL(inbody, 0x08);
74 /* 0x0A 2 bytes reserved */
75 in_additional_information = IVAL(inbody, 0x0C);
76 in_file_id_persistent = BVAL(inbody, 0x10);
77 in_file_id_volatile = BVAL(inbody, 0x18);
79 if (in_input_buffer_offset == 0 && in_input_buffer_length == 0) {
80 /* This is ok */
81 } else if (in_input_buffer_offset !=
82 (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
83 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
86 if (in_input_buffer_length > SMBD_SMB2_IN_DYN_LEN(req)) {
87 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
90 in_input_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
91 in_input_buffer.length = in_input_buffer_length;
93 if (in_input_buffer.length > xconn->smb2.server.max_trans) {
94 DEBUG(2,("smbd_smb2_request_process_setinfo: "
95 "client ignored max trans: %s: 0x%08X: 0x%08X\n",
96 __location__, (unsigned)in_input_buffer.length,
97 (unsigned)xconn->smb2.server.max_trans));
98 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
101 status = smbd_smb2_request_verify_creditcharge(req,
102 in_input_buffer.length);
103 if (!NT_STATUS_IS_OK(status)) {
104 return smbd_smb2_request_error(req, status);
107 in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
108 if (in_fsp == NULL) {
109 return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
112 subreq = smbd_smb2_setinfo_send(req, req->sconn->ev_ctx,
113 req, in_fsp,
114 in_info_type,
115 in_file_info_class,
116 in_input_buffer,
117 in_additional_information);
118 if (subreq == NULL) {
119 return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
121 tevent_req_set_callback(subreq, smbd_smb2_request_setinfo_done, req);
123 return smbd_smb2_request_pending_queue(req, subreq, 500);
126 static void smbd_smb2_request_setinfo_done(struct tevent_req *subreq)
128 struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
129 struct smbd_smb2_request);
130 DATA_BLOB outbody;
131 NTSTATUS status;
132 NTSTATUS error; /* transport error */
134 status = smbd_smb2_setinfo_recv(subreq);
135 TALLOC_FREE(subreq);
136 if (!NT_STATUS_IS_OK(status)) {
137 error = smbd_smb2_request_error(req, status);
138 if (!NT_STATUS_IS_OK(error)) {
139 smbd_server_connection_terminate(req->xconn,
140 nt_errstr(error));
141 return;
143 return;
146 outbody = smbd_smb2_generate_outbody(req, 0x02);
147 if (outbody.data == NULL) {
148 error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
149 if (!NT_STATUS_IS_OK(error)) {
150 smbd_server_connection_terminate(req->xconn,
151 nt_errstr(error));
152 return;
154 return;
157 SSVAL(outbody.data, 0x00, 0x02); /* struct size */
159 error = smbd_smb2_request_done(req, outbody, NULL);
160 if (!NT_STATUS_IS_OK(error)) {
161 smbd_server_connection_terminate(req->xconn,
162 nt_errstr(error));
163 return;
167 struct defer_rename_state {
168 struct tevent_req *req;
169 struct smbd_smb2_request *smb2req;
170 struct tevent_context *ev;
171 struct files_struct *fsp;
172 char *data;
173 int data_size;
176 static int defer_rename_state_destructor(struct defer_rename_state *rename_state)
178 SAFE_FREE(rename_state->data);
179 return 0;
182 static void defer_rename_done(struct tevent_req *subreq);
184 struct delay_rename_lease_break_state {
185 struct files_struct *fsp;
186 bool delay;
189 static bool delay_rename_lease_break_fn(
190 struct share_mode_entry *e,
191 void *private_data)
193 struct delay_rename_lease_break_state *state = private_data;
194 struct files_struct *fsp = state->fsp;
195 uint32_t e_lease_type, break_to;
196 bool ours, stale;
198 ours = smb2_lease_equal(fsp_client_guid(fsp),
199 &fsp->lease->lease.lease_key,
200 &e->client_guid,
201 &e->lease_key);
202 if (ours) {
203 return false;
206 e_lease_type = get_lease_type(e, fsp->file_id);
208 if ((e_lease_type & SMB2_LEASE_HANDLE) == 0) {
209 return false;
212 stale = share_entry_stale_pid(e);
213 if (stale) {
214 return false;
217 state->delay = true;
218 break_to = (e_lease_type & ~SMB2_LEASE_HANDLE);
220 send_break_message(
221 fsp->conn->sconn->msg_ctx, &fsp->file_id, e, break_to);
223 return false;
226 static struct tevent_req *delay_rename_for_lease_break(struct tevent_req *req,
227 struct smbd_smb2_request *smb2req,
228 struct tevent_context *ev,
229 struct files_struct *fsp,
230 struct share_mode_lock *lck,
231 char *data,
232 int data_size)
235 struct tevent_req *subreq;
236 struct defer_rename_state *rename_state;
237 struct delay_rename_lease_break_state state = { .fsp = fsp };
238 struct timeval timeout;
239 bool ok;
241 if (fsp->oplock_type != LEASE_OPLOCK) {
242 return NULL;
245 ok = share_mode_forall_leases(
246 lck, delay_rename_lease_break_fn, &state);
247 if (!ok) {
248 return NULL;
251 if (!state.delay) {
252 return NULL;
255 /* Setup a watch on this record. */
256 rename_state = talloc_zero(req, struct defer_rename_state);
257 if (rename_state == NULL) {
258 return NULL;
261 rename_state->req = req;
262 rename_state->smb2req = smb2req;
263 rename_state->ev = ev;
264 rename_state->fsp = fsp;
265 rename_state->data = data;
266 rename_state->data_size = data_size;
268 talloc_set_destructor(rename_state, defer_rename_state_destructor);
270 subreq = share_mode_watch_send(
271 rename_state,
273 lck,
274 (struct server_id){0});
276 if (subreq == NULL) {
277 exit_server("Could not watch share mode record for rename\n");
280 tevent_req_set_callback(subreq, defer_rename_done, rename_state);
282 timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
283 if (!tevent_req_set_endtime(subreq,
285 timeval_sum(&smb2req->request_time, &timeout))) {
286 exit_server("Could not set rename timeout\n");
289 return subreq;
292 static void defer_rename_done(struct tevent_req *subreq)
294 struct defer_rename_state *state = tevent_req_callback_data(
295 subreq, struct defer_rename_state);
296 NTSTATUS status;
297 struct share_mode_lock *lck;
298 int ret_size = 0;
299 bool ok;
301 status = share_mode_watch_recv(subreq, NULL, NULL);
302 TALLOC_FREE(subreq);
303 if (!NT_STATUS_IS_OK(status)) {
304 DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
305 nt_errstr(status)));
306 tevent_req_nterror(state->req, status);
307 return;
311 * Make sure we run as the user again
313 ok = change_to_user_and_service(
314 state->smb2req->tcon->compat,
315 state->smb2req->session->global->session_wire_id);
316 if (!ok) {
317 tevent_req_nterror(state->req, NT_STATUS_ACCESS_DENIED);
318 return;
321 /* Do we still need to wait ? */
322 lck = get_existing_share_mode_lock(state->req, state->fsp->file_id);
323 if (lck == NULL) {
324 tevent_req_nterror(state->req, NT_STATUS_UNSUCCESSFUL);
325 return;
327 subreq = delay_rename_for_lease_break(state->req,
328 state->smb2req,
329 state->ev,
330 state->fsp,
331 lck,
332 state->data,
333 state->data_size);
334 if (subreq) {
335 /* Yep - keep waiting. */
336 state->data = NULL;
337 TALLOC_FREE(state);
338 TALLOC_FREE(lck);
339 return;
342 /* Do the rename under the lock. */
343 status = smbd_do_setfilepathinfo(state->fsp->conn,
344 state->smb2req->smb1req,
345 state,
346 SMB2_FILE_RENAME_INFORMATION_INTERNAL,
347 state->fsp,
348 state->fsp->fsp_name,
349 &state->data,
350 state->data_size,
351 &ret_size);
353 TALLOC_FREE(lck);
354 SAFE_FREE(state->data);
356 if (!NT_STATUS_IS_OK(status)) {
357 tevent_req_nterror(state->req, status);
358 return;
361 tevent_req_done(state->req);
364 struct smbd_smb2_setinfo_state {
365 struct smbd_smb2_request *smb2req;
368 static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
369 struct tevent_context *ev,
370 struct smbd_smb2_request *smb2req,
371 struct files_struct *fsp,
372 uint8_t in_info_type,
373 uint8_t in_file_info_class,
374 DATA_BLOB in_input_buffer,
375 uint32_t in_additional_information)
377 struct tevent_req *req = NULL;
378 struct smbd_smb2_setinfo_state *state = NULL;
379 struct smb_request *smbreq = NULL;
380 connection_struct *conn = smb2req->tcon->compat;
381 struct share_mode_lock *lck = NULL;
382 NTSTATUS status;
383 int ret;
385 req = tevent_req_create(mem_ctx, &state,
386 struct smbd_smb2_setinfo_state);
387 if (req == NULL) {
388 return NULL;
390 state->smb2req = smb2req;
392 DEBUG(10,("smbd_smb2_setinfo_send: %s - %s\n",
393 fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
395 smbreq = smbd_smb2_fake_smb_request(smb2req, fsp);
396 if (tevent_req_nomem(smbreq, req)) {
397 return tevent_req_post(req, ev);
400 if (IS_IPC(conn)) {
401 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
402 return tevent_req_post(req, ev);
405 switch (in_info_type) {
406 case SMB2_0_INFO_FILE:
408 uint16_t file_info_level;
409 char *data;
410 int data_size;
411 int ret_size = 0;
414 file_info_level = in_file_info_class + 1000;
415 if (file_info_level == SMB_FILE_RENAME_INFORMATION) {
416 /* SMB2_FILE_RENAME_INFORMATION_INTERNAL == 0xFF00 + in_file_info_class */
417 file_info_level = SMB2_FILE_RENAME_INFORMATION_INTERNAL;
420 if (fsp_get_pathref_fd(fsp) == -1) {
422 * This is actually a SETFILEINFO on a directory
423 * handle (returned from an NT SMB). NT5.0 seems
424 * to do this call. JRA.
426 ret = vfs_stat(fsp->conn, fsp->fsp_name);
427 if (ret != 0) {
428 DBG_WARNING("vfs_stat() of %s failed (%s)\n",
429 fsp_str_dbg(fsp),
430 strerror(errno));
431 status = map_nt_error_from_unix(errno);
432 tevent_req_nterror(req, status);
433 return tevent_req_post(req, ev);
435 } else if (fsp->print_file) {
437 * Doing a DELETE_ON_CLOSE should cancel a print job.
439 if ((file_info_level == SMB_SET_FILE_DISPOSITION_INFO)
440 && in_input_buffer.length >= 1
441 && CVAL(in_input_buffer.data,0)) {
442 fsp->fsp_flags.delete_on_close = true;
444 DEBUG(3,("smbd_smb2_setinfo_send: "
445 "Cancelling print job (%s)\n",
446 fsp_str_dbg(fsp)));
448 tevent_req_done(req);
449 return tevent_req_post(req, ev);
451 tevent_req_nterror(req, NT_STATUS_OBJECT_PATH_INVALID);
452 return tevent_req_post(req, ev);
453 } else {
455 * Original code - this is an open file.
458 status = vfs_stat_fsp(fsp);
459 if (!NT_STATUS_IS_OK(status)) {
460 DEBUG(3,("smbd_smb2_setinfo_send: fstat "
461 "of %s failed (%s)\n",
462 fsp_fnum_dbg(fsp),
463 nt_errstr(status)));
464 tevent_req_nterror(req, status);
465 return tevent_req_post(req, ev);
469 data = NULL;
470 data_size = in_input_buffer.length;
471 if (data_size > 0) {
472 data = (char *)SMB_MALLOC_ARRAY(char, data_size);
473 if (tevent_req_nomem(data, req)) {
474 return tevent_req_post(req, ev);
476 memcpy(data, in_input_buffer.data, data_size);
479 if (file_info_level == SMB2_FILE_RENAME_INFORMATION_INTERNAL) {
480 struct tevent_req *subreq;
482 lck = get_existing_share_mode_lock(mem_ctx,
483 fsp->file_id);
484 if (lck == NULL) {
485 SAFE_FREE(data);
486 tevent_req_nterror(req,
487 NT_STATUS_UNSUCCESSFUL);
488 return tevent_req_post(req, ev);
491 subreq = delay_rename_for_lease_break(req,
492 smb2req,
494 fsp,
495 lck,
496 data,
497 data_size);
498 if (subreq) {
499 /* Wait for lease break response. */
501 /* Ensure we can't be closed in flight. */
502 if (!aio_add_req_to_fsp(fsp, req)) {
503 TALLOC_FREE(lck);
504 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
505 return tevent_req_post(req, ev);
508 TALLOC_FREE(lck);
509 return req;
513 status = smbd_do_setfilepathinfo(conn, smbreq, state,
514 file_info_level,
515 fsp,
516 fsp->fsp_name,
517 &data,
518 data_size,
519 &ret_size);
520 TALLOC_FREE(lck);
521 SAFE_FREE(data);
522 if (!NT_STATUS_IS_OK(status)) {
523 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
524 status = NT_STATUS_INVALID_INFO_CLASS;
526 tevent_req_nterror(req, status);
527 return tevent_req_post(req, ev);
529 break;
532 case SMB2_0_INFO_FILESYSTEM:
534 uint16_t file_info_level = in_file_info_class + 1000;
536 status = smbd_do_setfsinfo(conn, smbreq, state,
537 file_info_level,
538 fsp,
539 &in_input_buffer);
540 if (!NT_STATUS_IS_OK(status)) {
541 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
542 status = NT_STATUS_INVALID_INFO_CLASS;
544 tevent_req_nterror(req, status);
545 return tevent_req_post(req, ev);
547 break;
550 case SMB2_0_INFO_SECURITY:
552 if (!CAN_WRITE(conn)) {
553 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
554 return tevent_req_post(req, ev);
557 status = set_sd_blob(fsp,
558 in_input_buffer.data,
559 in_input_buffer.length,
560 in_additional_information &
561 SMB_SUPPORTED_SECINFO_FLAGS);
562 if (!NT_STATUS_IS_OK(status)) {
563 tevent_req_nterror(req, status);
564 return tevent_req_post(req, ev);
566 break;
569 case SMB2_0_INFO_QUOTA:
571 #ifdef HAVE_SYS_QUOTAS
572 struct file_quota_information info = {0};
573 SMB_NTQUOTA_STRUCT qt = {0};
574 enum ndr_err_code err;
576 if (!fsp->fake_file_handle) {
577 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
578 return tevent_req_post(req, ev);
580 err = ndr_pull_struct_blob(
581 &in_input_buffer, state, &info,
582 (ndr_pull_flags_fn_t)ndr_pull_file_quota_information);
583 if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
584 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
585 return tevent_req_post(req, ev);
588 qt.usedspace = info.quota_used;
590 qt.softlim = info.quota_threshold;
592 qt.hardlim = info.quota_limit;
594 qt.sid = info.sid;
595 ret = vfs_set_ntquota(fsp, SMB_USER_QUOTA_TYPE, &qt.sid, &qt);
596 if (ret !=0 ) {
597 status = map_nt_error_from_unix(errno);
598 tevent_req_nterror(req, status);
599 return tevent_req_post(req, ev);
601 status = NT_STATUS_OK;
602 break;
603 #else
604 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
605 return tevent_req_post(req, ev);
606 #endif
608 default:
609 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
610 return tevent_req_post(req, ev);
613 tevent_req_done(req);
614 return tevent_req_post(req, ev);
617 static NTSTATUS smbd_smb2_setinfo_recv(struct tevent_req *req)
619 NTSTATUS status;
621 if (tevent_req_is_nterror(req, &status)) {
622 tevent_req_received(req);
623 return status;
626 tevent_req_received(req);
627 return NT_STATUS_OK;