2 Unix SMB/CIFS implementation.
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/>.
23 #include "locking/share_mode_lock.h"
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "../libcli/smb/smb_common.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "../librpc/gen_ndr/open_files.h"
30 #include "source3/lib/dbwrap/dbwrap_watch.h"
32 #include "librpc/gen_ndr/ndr_quota.h"
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
,
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
;
52 const uint8_t *inbody
;
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) {
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
,
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
);
132 NTSTATUS error
; /* transport error */
134 status
= smbd_smb2_setinfo_recv(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
,
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
,
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
,
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
;
176 static int defer_rename_state_destructor(struct defer_rename_state
*rename_state
)
178 SAFE_FREE(rename_state
->data
);
182 static void defer_rename_done(struct tevent_req
*subreq
);
184 struct delay_rename_lease_break_state
{
185 struct files_struct
*fsp
;
189 static bool delay_rename_lease_break_fn(
190 struct share_mode_entry
*e
,
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
;
198 ours
= smb2_lease_equal(fsp_client_guid(fsp
),
199 &fsp
->lease
->lease
.lease_key
,
206 e_lease_type
= get_lease_type(e
, fsp
->file_id
);
208 if ((e_lease_type
& SMB2_LEASE_HANDLE
) == 0) {
212 stale
= share_entry_stale_pid(e
);
218 break_to
= (e_lease_type
& ~SMB2_LEASE_HANDLE
);
221 fsp
->conn
->sconn
->msg_ctx
, &fsp
->file_id
, e
, break_to
);
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
,
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
;
241 if (fsp
->oplock_type
!= LEASE_OPLOCK
) {
245 ok
= share_mode_forall_leases(
246 lck
, delay_rename_lease_break_fn
, &state
);
255 /* Setup a watch on this record. */
256 rename_state
= talloc_zero(req
, struct defer_rename_state
);
257 if (rename_state
== 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(
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");
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
);
297 struct share_mode_lock
*lck
;
301 status
= share_mode_watch_recv(subreq
, NULL
, NULL
);
303 if (!NT_STATUS_IS_OK(status
)) {
304 DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
306 tevent_req_nterror(state
->req
, status
);
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
);
317 tevent_req_nterror(state
->req
, NT_STATUS_ACCESS_DENIED
);
321 /* Do we still need to wait ? */
322 lck
= get_existing_share_mode_lock(state
->req
, state
->fsp
->file_id
);
324 tevent_req_nterror(state
->req
, NT_STATUS_UNSUCCESSFUL
);
327 subreq
= delay_rename_for_lease_break(state
->req
,
335 /* Yep - keep waiting. */
342 /* Do the rename under the lock. */
343 status
= smbd_do_setfilepathinfo(state
->fsp
->conn
,
344 state
->smb2req
->smb1req
,
346 SMB2_FILE_RENAME_INFORMATION_INTERNAL
,
348 state
->fsp
->fsp_name
,
354 SAFE_FREE(state
->data
);
356 if (!NT_STATUS_IS_OK(status
)) {
357 tevent_req_nterror(state
->req
, status
);
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
;
385 req
= tevent_req_create(mem_ctx
, &state
,
386 struct smbd_smb2_setinfo_state
);
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
);
396 if (tevent_req_nomem(smbreq
, req
)) {
397 return tevent_req_post(req
, ev
);
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
;
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
);
428 DBG_WARNING("vfs_stat() of %s failed (%s)\n",
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",
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
);
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",
464 tevent_req_nterror(req
, status
);
465 return tevent_req_post(req
, ev
);
470 data_size
= in_input_buffer
.length
;
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
,
486 tevent_req_nterror(req
,
487 NT_STATUS_UNSUCCESSFUL
);
488 return tevent_req_post(req
, ev
);
491 subreq
= delay_rename_for_lease_break(req
,
499 /* Wait for lease break response. */
501 /* Ensure we can't be closed in flight. */
502 if (!aio_add_req_to_fsp(fsp
, req
)) {
504 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
505 return tevent_req_post(req
, ev
);
513 status
= smbd_do_setfilepathinfo(conn
, smbreq
, state
,
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
);
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
,
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
);
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
);
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
;
595 ret
= vfs_set_ntquota(fsp
, SMB_USER_QUOTA_TYPE
, &qt
.sid
, &qt
);
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
;
604 tevent_req_nterror(req
, NT_STATUS_NOT_SUPPORTED
);
605 return tevent_req_post(req
, ev
);
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
)
621 if (tevent_req_is_nterror(req
, &status
)) {
622 tevent_req_received(req
);
626 tevent_req_received(req
);