Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : file closing
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Jeremy Allison 1992-2007.
6 : Copyright (C) Volker Lendecke 2005
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 "system/filesys.h"
24 : #include "lib/util/server_id.h"
25 : #include "printing.h"
26 : #include "locking/share_mode_lock.h"
27 : #include "smbd/smbd.h"
28 : #include "smbd/globals.h"
29 : #include "smbd/smbXsrv_open.h"
30 : #include "smbd/scavenger.h"
31 : #include "fake_file.h"
32 : #include "transfer_file.h"
33 : #include "auth.h"
34 : #include "messages.h"
35 : #include "../librpc/gen_ndr/open_files.h"
36 : #include "lib/util/tevent_ntstatus.h"
37 :
38 : /****************************************************************************
39 : Run a file if it is a magic script.
40 : ****************************************************************************/
41 :
42 1838 : static NTSTATUS check_magic(struct files_struct *fsp)
43 : {
44 : int ret;
45 1552 : const struct loadparm_substitution *lp_sub =
46 286 : loadparm_s3_global_substitution();
47 1838 : const char *magic_output = NULL;
48 : SMB_STRUCT_STAT st;
49 : int tmp_fd, outfd;
50 1838 : TALLOC_CTX *ctx = NULL;
51 : const char *p;
52 1838 : struct connection_struct *conn = fsp->conn;
53 1838 : char *fname = NULL;
54 : NTSTATUS status;
55 :
56 1838 : if (!*lp_magic_script(talloc_tos(), lp_sub, SNUM(conn))) {
57 1838 : return NT_STATUS_OK;
58 : }
59 :
60 0 : DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp)));
61 :
62 0 : ctx = talloc_stackframe();
63 :
64 0 : fname = fsp->fsp_name->base_name;
65 :
66 0 : if (!(p = strrchr_m(fname,'/'))) {
67 0 : p = fname;
68 : } else {
69 0 : p++;
70 : }
71 :
72 0 : if (!strequal(lp_magic_script(talloc_tos(), lp_sub, SNUM(conn)),p)) {
73 0 : status = NT_STATUS_OK;
74 0 : goto out;
75 : }
76 :
77 0 : if (*lp_magic_output(talloc_tos(), lp_sub, SNUM(conn))) {
78 0 : magic_output = lp_magic_output(talloc_tos(), lp_sub, SNUM(conn));
79 : } else {
80 0 : magic_output = talloc_asprintf(ctx,
81 : "%s.out",
82 : fname);
83 : }
84 0 : if (!magic_output) {
85 0 : status = NT_STATUS_NO_MEMORY;
86 0 : goto out;
87 : }
88 :
89 : /* Ensure we don't depend on user's PATH. */
90 0 : p = talloc_asprintf(ctx, "./%s", fname);
91 0 : if (!p) {
92 0 : status = NT_STATUS_NO_MEMORY;
93 0 : goto out;
94 : }
95 :
96 0 : if (chmod(fname, 0755) == -1) {
97 0 : status = map_nt_error_from_unix(errno);
98 0 : goto out;
99 : }
100 0 : ret = smbrun(p, &tmp_fd, NULL);
101 0 : DEBUG(3,("Invoking magic command %s gave %d\n",
102 : p,ret));
103 :
104 0 : unlink(fname);
105 0 : if (ret != 0 || tmp_fd == -1) {
106 0 : if (tmp_fd != -1) {
107 0 : close(tmp_fd);
108 : }
109 0 : status = NT_STATUS_UNSUCCESSFUL;
110 0 : goto out;
111 : }
112 0 : outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
113 0 : if (outfd == -1) {
114 0 : int err = errno;
115 0 : close(tmp_fd);
116 0 : status = map_nt_error_from_unix(err);
117 0 : goto out;
118 : }
119 :
120 0 : if (sys_fstat(tmp_fd, &st, false) == -1) {
121 0 : int err = errno;
122 0 : close(tmp_fd);
123 0 : close(outfd);
124 0 : status = map_nt_error_from_unix(err);
125 0 : goto out;
126 : }
127 :
128 0 : if (transfer_file(tmp_fd,outfd,(off_t)st.st_ex_size) == (off_t)-1) {
129 0 : int err = errno;
130 0 : close(tmp_fd);
131 0 : close(outfd);
132 0 : status = map_nt_error_from_unix(err);
133 0 : goto out;
134 : }
135 0 : close(tmp_fd);
136 0 : if (close(outfd) == -1) {
137 0 : status = map_nt_error_from_unix(errno);
138 0 : goto out;
139 : }
140 :
141 0 : status = NT_STATUS_OK;
142 :
143 0 : out:
144 0 : TALLOC_FREE(ctx);
145 0 : return status;
146 : }
147 :
148 : /****************************************************************************
149 : Delete all streams
150 : ****************************************************************************/
151 :
152 1432 : NTSTATUS delete_all_streams(connection_struct *conn,
153 : const struct smb_filename *smb_fname)
154 : {
155 1432 : struct stream_struct *stream_info = NULL;
156 : unsigned int i;
157 1432 : unsigned int num_streams = 0;
158 1432 : TALLOC_CTX *frame = talloc_stackframe();
159 : NTSTATUS status;
160 :
161 1432 : status = vfs_fstreaminfo(smb_fname->fsp, talloc_tos(),
162 : &num_streams, &stream_info);
163 :
164 1432 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
165 0 : DEBUG(10, ("no streams around\n"));
166 0 : TALLOC_FREE(frame);
167 0 : return NT_STATUS_OK;
168 : }
169 :
170 1432 : if (!NT_STATUS_IS_OK(status)) {
171 0 : DEBUG(10, ("vfs_fstreaminfo failed: %s\n",
172 : nt_errstr(status)));
173 0 : goto fail;
174 : }
175 :
176 1432 : DEBUG(10, ("delete_all_streams found %d streams\n",
177 : num_streams));
178 :
179 1432 : if (num_streams == 0) {
180 800 : TALLOC_FREE(frame);
181 800 : return NT_STATUS_OK;
182 : }
183 :
184 1272 : for (i=0; i<num_streams; i++) {
185 : int res;
186 : struct smb_filename *smb_fname_stream;
187 :
188 640 : if (strequal(stream_info[i].name, "::$DATA")) {
189 624 : continue;
190 : }
191 :
192 24 : status = synthetic_pathref(talloc_tos(),
193 : conn->cwd_fsp,
194 16 : smb_fname->base_name,
195 16 : stream_info[i].name,
196 : NULL,
197 8 : smb_fname->twrp,
198 16 : (smb_fname->flags &
199 : ~SMB_FILENAME_POSIX_PATH),
200 : &smb_fname_stream);
201 16 : if (!NT_STATUS_IS_OK(status)) {
202 0 : DEBUG(0, ("talloc_aprintf failed\n"));
203 0 : status = NT_STATUS_NO_MEMORY;
204 0 : goto fail;
205 : }
206 :
207 16 : res = SMB_VFS_UNLINKAT(conn,
208 : conn->cwd_fsp,
209 : smb_fname_stream,
210 : 0);
211 :
212 16 : if (res == -1) {
213 0 : status = map_nt_error_from_unix(errno);
214 0 : DEBUG(10, ("Could not delete stream %s: %s\n",
215 : smb_fname_str_dbg(smb_fname_stream),
216 : strerror(errno)));
217 0 : TALLOC_FREE(smb_fname_stream);
218 0 : break;
219 : }
220 16 : TALLOC_FREE(smb_fname_stream);
221 : }
222 :
223 632 : fail:
224 632 : TALLOC_FREE(frame);
225 632 : return status;
226 : }
227 :
228 : struct has_other_nonposix_opens_state {
229 : files_struct *fsp;
230 : bool found_another;
231 : };
232 :
233 1369 : static bool has_other_nonposix_opens_fn(
234 : struct share_mode_entry *e,
235 : bool *modified,
236 : void *private_data)
237 : {
238 1369 : struct has_other_nonposix_opens_state *state = private_data;
239 1369 : struct files_struct *fsp = state->fsp;
240 :
241 1369 : if (e->name_hash != fsp->name_hash) {
242 0 : return false;
243 : }
244 1369 : if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
245 0 : (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
246 0 : return false;
247 : }
248 1369 : if (e->share_file_id == fh_get_gen_id(fsp->fh)) {
249 1368 : struct server_id self = messaging_server_id(
250 1368 : fsp->conn->sconn->msg_ctx);
251 1368 : if (server_id_equal(&self, &e->pid)) {
252 1368 : return false;
253 : }
254 : }
255 1 : if (share_entry_stale_pid(e)) {
256 0 : return false;
257 : }
258 :
259 1 : state->found_another = true;
260 1 : return true;
261 : }
262 :
263 1369 : bool has_other_nonposix_opens(struct share_mode_lock *lck,
264 : struct files_struct *fsp)
265 : {
266 1369 : struct has_other_nonposix_opens_state state = { .fsp = fsp };
267 : bool ok;
268 :
269 1369 : ok = share_mode_forall_entries(
270 : lck, has_other_nonposix_opens_fn, &state);
271 1369 : if (!ok) {
272 0 : return false;
273 : }
274 1369 : return state.found_another;
275 : }
276 :
277 : /****************************************************************************
278 : Deal with removing a share mode on last close.
279 : ****************************************************************************/
280 :
281 1850 : static NTSTATUS close_remove_share_mode(files_struct *fsp,
282 : enum file_close_type close_type)
283 : {
284 1850 : connection_struct *conn = fsp->conn;
285 1850 : bool delete_file = false;
286 1850 : bool changed_user = false;
287 1850 : struct share_mode_lock *lck = NULL;
288 1850 : NTSTATUS status = NT_STATUS_OK;
289 : NTSTATUS tmp_status;
290 : struct file_id id;
291 1850 : const struct security_unix_token *del_token = NULL;
292 1850 : const struct security_token *del_nt_token = NULL;
293 1850 : struct smb_filename *parent_fname = NULL;
294 1850 : struct smb_filename *base_fname = NULL;
295 1850 : bool got_tokens = false;
296 : bool normal_close;
297 : int ret;
298 :
299 : /* Ensure any pending write time updates are done. */
300 1850 : if (fsp->update_write_time_event) {
301 436 : fsp_flush_write_time_update(fsp);
302 : }
303 :
304 : /*
305 : * Lock the share entries, and determine if we should delete
306 : * on close. If so delete whilst the lock is still in effect.
307 : * This prevents race conditions with the file being created. JRA.
308 : */
309 :
310 1850 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
311 1850 : if (lck == NULL) {
312 0 : DEBUG(0, ("close_remove_share_mode: Could not get share mode "
313 : "lock for file %s\n", fsp_str_dbg(fsp)));
314 0 : return NT_STATUS_INVALID_PARAMETER;
315 : }
316 :
317 : /* Remove the oplock before potentially deleting the file. */
318 1850 : if(fsp->oplock_type) {
319 124 : remove_oplock(fsp);
320 : }
321 :
322 1850 : if (fsp->fsp_flags.write_time_forced) {
323 1 : NTTIME mtime = share_mode_changed_write_time(lck);
324 1 : struct timespec ts = nt_time_to_full_timespec(mtime);
325 :
326 1 : DEBUG(10,("close_remove_share_mode: write time forced "
327 : "for file %s\n",
328 : fsp_str_dbg(fsp)));
329 1 : set_close_write_time(fsp, ts);
330 1849 : } else if (fsp->fsp_flags.update_write_time_on_close) {
331 : /* Someone had a pending write. */
332 0 : if (is_omit_timespec(&fsp->close_write_time)) {
333 0 : DEBUG(10,("close_remove_share_mode: update to current time "
334 : "for file %s\n",
335 : fsp_str_dbg(fsp)));
336 : /* Update to current time due to "normal" write. */
337 0 : set_close_write_time(fsp, timespec_current());
338 : } else {
339 0 : DEBUG(10,("close_remove_share_mode: write time pending "
340 : "for file %s\n",
341 : fsp_str_dbg(fsp)));
342 : /* Update to time set on close call. */
343 0 : set_close_write_time(fsp, fsp->close_write_time);
344 : }
345 : }
346 :
347 2314 : if (fsp->fsp_flags.initial_delete_on_close &&
348 556 : !is_delete_on_close_set(lck, fsp->name_hash)) {
349 : /* Initial delete on close was set and no one else
350 : * wrote a real delete on close. */
351 :
352 556 : fsp->fsp_flags.delete_on_close = true;
353 556 : set_delete_on_close_lck(fsp, lck,
354 556 : fsp->conn->session_info->security_token,
355 556 : fsp->conn->session_info->unix_token);
356 : }
357 :
358 2411 : delete_file = is_delete_on_close_set(lck, fsp->name_hash) &&
359 561 : !has_other_nonposix_opens(lck, fsp);
360 :
361 : /*
362 : * NT can set delete_on_close of the last open
363 : * reference to a file.
364 : */
365 :
366 1850 : normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);
367 :
368 1850 : if (!normal_close || !delete_file) {
369 1290 : status = NT_STATUS_OK;
370 1290 : goto done;
371 : }
372 :
373 : /*
374 : * Ok, we have to delete the file
375 : */
376 :
377 560 : DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
378 : "- deleting file.\n", fsp_str_dbg(fsp)));
379 :
380 : /*
381 : * Don't try to update the write time when we delete the file
382 : */
383 560 : fsp->fsp_flags.update_write_time_on_close = false;
384 :
385 560 : got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
386 : &del_nt_token, &del_token);
387 560 : SMB_ASSERT(got_tokens);
388 :
389 560 : if (!unix_token_equal(del_token, get_current_utok(conn))) {
390 : /* Become the user who requested the delete. */
391 :
392 5 : DEBUG(5,("close_remove_share_mode: file %s. "
393 : "Change user to uid %u\n",
394 : fsp_str_dbg(fsp),
395 : (unsigned int)del_token->uid));
396 :
397 5 : if (!push_sec_ctx()) {
398 0 : smb_panic("close_remove_share_mode: file %s. failed to push "
399 : "sec_ctx.\n");
400 : }
401 :
402 14 : set_sec_ctx(del_token->uid,
403 5 : del_token->gid,
404 5 : del_token->ngroups,
405 5 : del_token->groups,
406 : del_nt_token);
407 :
408 5 : changed_user = true;
409 : }
410 :
411 : /* We can only delete the file if the name we have is still valid and
412 : hasn't been renamed. */
413 :
414 560 : tmp_status = vfs_stat_fsp(fsp);
415 560 : if (!NT_STATUS_IS_OK(tmp_status)) {
416 0 : DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
417 : "was set and stat failed with error %s\n",
418 : fsp_str_dbg(fsp), nt_errstr(tmp_status)));
419 : /*
420 : * Don't save the errno here, we ignore this error
421 : */
422 0 : goto done;
423 : }
424 :
425 560 : id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
426 :
427 560 : if (!file_id_equal(&fsp->file_id, &id)) {
428 : struct file_id_buf ftmp1, ftmp2;
429 0 : DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
430 : "was set and dev and/or inode does not match\n",
431 : fsp_str_dbg(fsp)));
432 0 : DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
433 : "stat file_id %s\n",
434 : fsp_str_dbg(fsp),
435 : file_id_str_buf(fsp->file_id, &ftmp1),
436 : file_id_str_buf(id, &ftmp2)));
437 : /*
438 : * Don't save the errno here, we ignore this error
439 : */
440 0 : goto done;
441 : }
442 :
443 560 : if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
444 560 : && !fsp_is_alternate_stream(fsp)) {
445 :
446 560 : status = delete_all_streams(conn, fsp->fsp_name);
447 :
448 560 : if (!NT_STATUS_IS_OK(status)) {
449 0 : DEBUG(5, ("delete_all_streams failed: %s\n",
450 : nt_errstr(status)));
451 0 : goto done;
452 : }
453 : }
454 :
455 560 : if (fsp->fsp_flags.kernel_share_modes_taken) {
456 : /*
457 : * A file system sharemode could block the unlink;
458 : * remove filesystem sharemodes first.
459 : */
460 0 : ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
461 0 : if (ret == -1) {
462 0 : DBG_INFO("Removing file system sharemode for %s "
463 : "failed: %s\n",
464 : fsp_str_dbg(fsp), strerror(errno));
465 : }
466 :
467 0 : fsp->fsp_flags.kernel_share_modes_taken = false;
468 : }
469 :
470 560 : status = parent_pathref(talloc_tos(),
471 : conn->cwd_fsp,
472 560 : fsp->fsp_name,
473 : &parent_fname,
474 : &base_fname);
475 560 : if (!NT_STATUS_IS_OK(status)) {
476 0 : goto done;
477 : }
478 :
479 560 : ret = SMB_VFS_UNLINKAT(conn,
480 : parent_fname->fsp,
481 : base_fname,
482 : 0);
483 560 : TALLOC_FREE(parent_fname);
484 560 : base_fname = NULL;
485 560 : if (ret != 0) {
486 : /*
487 : * This call can potentially fail as another smbd may
488 : * have had the file open with delete on close set and
489 : * deleted it when its last reference to this file
490 : * went away. Hence we log this but not at debug level
491 : * zero.
492 : */
493 :
494 0 : DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
495 : "was set and unlink failed with error %s\n",
496 : fsp_str_dbg(fsp), strerror(errno)));
497 :
498 0 : status = map_nt_error_from_unix(errno);
499 : }
500 :
501 : /* As we now have POSIX opens which can unlink
502 : * with other open files we may have taken
503 : * this code path with more than one share mode
504 : * entry - ensure we only delete once by resetting
505 : * the delete on close flag. JRA.
506 : */
507 :
508 560 : fsp->fsp_flags.delete_on_close = false;
509 560 : reset_delete_on_close_lck(fsp, lck);
510 :
511 1850 : done:
512 :
513 1850 : if (changed_user) {
514 : /* unbecome user. */
515 5 : pop_sec_ctx();
516 : }
517 :
518 1850 : if (fsp->fsp_flags.kernel_share_modes_taken) {
519 : /* remove filesystem sharemodes */
520 0 : ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
521 0 : if (ret == -1) {
522 0 : DBG_INFO("Removing file system sharemode for "
523 : "%s failed: %s\n",
524 : fsp_str_dbg(fsp), strerror(errno));
525 : }
526 : }
527 :
528 1850 : if (!del_share_mode(lck, fsp)) {
529 0 : DEBUG(0, ("close_remove_share_mode: Could not delete share "
530 : "entry for file %s\n", fsp_str_dbg(fsp)));
531 : }
532 :
533 1850 : TALLOC_FREE(lck);
534 :
535 1850 : if (delete_file) {
536 : /*
537 : * Do the notification after we released the share
538 : * mode lock. Inside notify_fname we take out another
539 : * tdb lock. With ctdb also accessing our databases,
540 : * this can lead to deadlocks. Putting this notify
541 : * after the TALLOC_FREE(lck) above we avoid locking
542 : * two records simultaneously. Notifies are async and
543 : * informational only, so calling the notify_fname
544 : * without holding the share mode lock should not do
545 : * any harm.
546 : */
547 560 : notify_fname(conn, NOTIFY_ACTION_REMOVED,
548 : FILE_NOTIFY_CHANGE_FILE_NAME,
549 560 : fsp->fsp_name->base_name);
550 : }
551 :
552 1850 : return status;
553 : }
554 :
555 1 : void set_close_write_time(struct files_struct *fsp, struct timespec ts)
556 : {
557 1 : DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
558 :
559 1 : if (is_omit_timespec(&ts)) {
560 0 : return;
561 : }
562 1 : fsp->fsp_flags.write_time_forced = false;
563 1 : fsp->fsp_flags.update_write_time_on_close = true;
564 1 : fsp->close_write_time = ts;
565 : }
566 :
567 1850 : static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
568 : {
569 : struct smb_file_time ft;
570 : NTSTATUS status;
571 1850 : struct share_mode_lock *lck = NULL;
572 :
573 1850 : init_smb_file_time(&ft);
574 :
575 1850 : if (!(fsp->fsp_flags.update_write_time_on_close)) {
576 1849 : return NT_STATUS_OK;
577 : }
578 :
579 1 : if (is_omit_timespec(&fsp->close_write_time)) {
580 0 : fsp->close_write_time = timespec_current();
581 : }
582 :
583 : /* Ensure we have a valid stat struct for the source. */
584 1 : status = vfs_stat_fsp(fsp);
585 1 : if (!NT_STATUS_IS_OK(status)) {
586 0 : return status;
587 : }
588 :
589 1 : if (!VALID_STAT(fsp->fsp_name->st)) {
590 : /* if it doesn't seem to be a real file */
591 0 : return NT_STATUS_OK;
592 : }
593 :
594 : /*
595 : * get_existing_share_mode_lock() isn't really the right
596 : * call here, as we're being called after
597 : * close_remove_share_mode() inside close_normal_file()
598 : * so it's quite normal to not have an existing share
599 : * mode here. However, get_share_mode_lock() doesn't
600 : * work because that will create a new share mode if
601 : * one doesn't exist - so stick with this call (just
602 : * ignore any error we get if the share mode doesn't
603 : * exist.
604 : */
605 :
606 1 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
607 1 : if (lck) {
608 0 : NTTIME share_mtime = share_mode_changed_write_time(lck);
609 : /* On close if we're changing the real file time we
610 : * must update it in the open file db too. */
611 0 : (void)set_write_time(fsp->file_id, fsp->close_write_time);
612 :
613 : /* Close write times overwrite sticky write times
614 : so we must replace any sticky write time here. */
615 0 : if (!null_nttime(share_mtime)) {
616 0 : (void)set_sticky_write_time(fsp->file_id, fsp->close_write_time);
617 : }
618 0 : TALLOC_FREE(lck);
619 : }
620 :
621 1 : ft.mtime = fsp->close_write_time;
622 : /* As this is a close based update, we are not directly changing the
623 : file attributes from a client call, but indirectly from a write. */
624 1 : status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
625 1 : if (!NT_STATUS_IS_OK(status)) {
626 0 : DEBUG(10,("update_write_time_on_close: smb_set_file_time "
627 : "on file %s returned %s\n",
628 : fsp_str_dbg(fsp),
629 : nt_errstr(status)));
630 0 : return status;
631 : }
632 :
633 1 : return status;
634 : }
635 :
636 7388 : static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2)
637 : {
638 7388 : if (!NT_STATUS_IS_OK(s1)) {
639 0 : return s1;
640 : }
641 7388 : return s2;
642 : }
643 :
644 12066 : static void assert_no_pending_aio(struct files_struct *fsp,
645 : enum file_close_type close_type)
646 : {
647 12066 : struct smbXsrv_client *client = global_smbXsrv_client;
648 : size_t num_connections_alive;
649 12066 : unsigned num_requests = fsp->num_aio_requests;
650 :
651 12066 : if (num_requests == 0) {
652 12066 : return;
653 : }
654 :
655 0 : num_connections_alive = smbXsrv_client_valid_connections(client);
656 :
657 0 : if (close_type == SHUTDOWN_CLOSE && num_connections_alive == 0) {
658 : /*
659 : * fsp->aio_requests and the contents (fsp->aio_requests[x])
660 : * are both independently owned by fsp and are not in a
661 : * talloc heirarchy. This allows the fsp->aio_requests array to
662 : * be reallocated independently of the array contents so it can
663 : * grow on demand.
664 : *
665 : * This means we must ensure order of deallocation
666 : * on a SHUTDOWN_CLOSE by deallocating the fsp->aio_requests[x]
667 : * contents first, as their destructors access the
668 : * fsp->aio_request array. If we don't deallocate them
669 : * first, when fsp is deallocated fsp->aio_requests
670 : * could have been deallocated *before* its contents
671 : * fsp->aio_requests[x], causing a crash.
672 : */
673 0 : while (fsp->num_aio_requests != 0) {
674 : /*
675 : * NB. We *MUST* use
676 : * talloc_free(fsp->aio_requests[0]),
677 : * and *NOT* TALLOC_FREE() here, as
678 : * TALLOC_FREE(fsp->aio_requests[0])
679 : * will overwrite any new contents of
680 : * fsp->aio_requests[0] that were
681 : * copied into it via the destructor
682 : * aio_del_req_from_fsp().
683 : *
684 : * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14515
685 : */
686 0 : talloc_free(fsp->aio_requests[0]);
687 : }
688 0 : return;
689 : }
690 :
691 0 : DBG_ERR("fsp->num_aio_requests=%u\n", num_requests);
692 0 : smb_panic("can not close with outstanding aio requests");
693 : return;
694 : }
695 :
696 : /****************************************************************************
697 : Close a file.
698 :
699 : close_type can be NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE.
700 : printing and magic scripts are only run on normal close.
701 : delete on close is done on normal and shutdown close.
702 : ****************************************************************************/
703 :
704 1850 : static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
705 : enum file_close_type close_type)
706 : {
707 1850 : NTSTATUS status = NT_STATUS_OK;
708 : NTSTATUS tmp;
709 1850 : connection_struct *conn = fsp->conn;
710 1850 : bool is_durable = false;
711 :
712 1850 : SMB_ASSERT(fsp->fsp_flags.is_fsa);
713 :
714 1850 : assert_no_pending_aio(fsp, close_type);
715 :
716 3410 : while (talloc_array_length(fsp->blocked_smb1_lock_reqs) != 0) {
717 0 : smbd_smb1_brl_finish_by_req(
718 0 : fsp->blocked_smb1_lock_reqs[0],
719 0 : NT_STATUS_RANGE_NOT_LOCKED);
720 : }
721 :
722 : /*
723 : * If we're flushing on a close we can get a write
724 : * error here, we must remember this.
725 : */
726 :
727 1850 : if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
728 1818 : is_durable = fsp->op->global->durable;
729 : }
730 :
731 1850 : if (close_type != SHUTDOWN_CLOSE) {
732 1838 : is_durable = false;
733 : }
734 :
735 1850 : if (is_durable) {
736 0 : DATA_BLOB new_cookie = data_blob_null;
737 :
738 0 : tmp = SMB_VFS_DURABLE_DISCONNECT(fsp,
739 : fsp->op->global->backend_cookie,
740 : fsp->op,
741 : &new_cookie);
742 0 : if (NT_STATUS_IS_OK(tmp)) {
743 : struct timeval tv;
744 : NTTIME now;
745 :
746 0 : if (req != NULL) {
747 0 : tv = req->request_time;
748 : } else {
749 0 : tv = timeval_current();
750 : }
751 0 : now = timeval_to_nttime(&tv);
752 :
753 0 : data_blob_free(&fsp->op->global->backend_cookie);
754 0 : fsp->op->global->backend_cookie = new_cookie;
755 :
756 0 : fsp->op->compat = NULL;
757 0 : tmp = smbXsrv_open_close(fsp->op, now);
758 0 : if (!NT_STATUS_IS_OK(tmp)) {
759 0 : DEBUG(1, ("Failed to update smbXsrv_open "
760 : "record when disconnecting durable "
761 : "handle for file %s: %s - "
762 : "proceeding with normal close\n",
763 : fsp_str_dbg(fsp), nt_errstr(tmp)));
764 : }
765 0 : scavenger_schedule_disconnected(fsp);
766 : } else {
767 0 : DEBUG(1, ("Failed to disconnect durable handle for "
768 : "file %s: %s - proceeding with normal "
769 : "close\n", fsp_str_dbg(fsp), nt_errstr(tmp)));
770 : }
771 0 : if (!NT_STATUS_IS_OK(tmp)) {
772 0 : is_durable = false;
773 : }
774 : }
775 :
776 1850 : if (is_durable) {
777 : /*
778 : * This is the case where we successfully disconnected
779 : * a durable handle and closed the underlying file.
780 : * In all other cases, we proceed with a genuine close.
781 : */
782 0 : DEBUG(10, ("%s disconnected durable handle for file %s\n",
783 : conn->session_info->unix_info->unix_name,
784 : fsp_str_dbg(fsp)));
785 0 : return NT_STATUS_OK;
786 : }
787 :
788 1850 : if (fsp->op != NULL) {
789 : /*
790 : * Make sure the handle is not marked as durable anymore
791 : */
792 1818 : fsp->op->global->durable = false;
793 : }
794 :
795 : /* If this is an old DOS or FCB open and we have multiple opens on
796 : the same handle we only have one share mode. Ensure we only remove
797 : the share mode on the last close. */
798 :
799 1850 : if (fh_get_refcount(fsp->fh) == 1) {
800 : /* Should we return on error here... ? */
801 1850 : tmp = close_remove_share_mode(fsp, close_type);
802 1850 : status = ntstatus_keeperror(status, tmp);
803 : }
804 :
805 1850 : locking_close_file(fsp, close_type);
806 :
807 : /*
808 : * Ensure pending modtime is set before closing underlying fd.
809 : */
810 :
811 1850 : tmp = update_write_time_on_close(fsp);
812 1850 : if (NT_STATUS_EQUAL(tmp, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
813 : /*
814 : * Someone renamed the file or a parent directory containing
815 : * this file. We can't do anything about this, eat the error.
816 : */
817 0 : tmp = NT_STATUS_OK;
818 : }
819 1850 : status = ntstatus_keeperror(status, tmp);
820 :
821 1850 : tmp = fd_close(fsp);
822 1850 : status = ntstatus_keeperror(status, tmp);
823 :
824 : /* check for magic scripts */
825 1850 : if (close_type == NORMAL_CLOSE) {
826 1838 : tmp = check_magic(fsp);
827 1838 : status = ntstatus_keeperror(status, tmp);
828 : }
829 :
830 1850 : DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
831 : conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
832 : conn->num_files_open - 1,
833 : nt_errstr(status) ));
834 :
835 1850 : return status;
836 : }
837 : /****************************************************************************
838 : Function used by reply_rmdir to delete an entire directory
839 : tree recursively. Return True on ok, False on fail.
840 : ****************************************************************************/
841 :
842 0 : NTSTATUS recursive_rmdir(TALLOC_CTX *ctx,
843 : connection_struct *conn,
844 : struct smb_filename *smb_dname)
845 : {
846 0 : const char *dname = NULL;
847 0 : char *talloced = NULL;
848 0 : long offset = 0;
849 : SMB_STRUCT_STAT st;
850 0 : struct smb_Dir *dir_hnd = NULL;
851 0 : struct files_struct *dirfsp = NULL;
852 : int retval;
853 0 : NTSTATUS status = NT_STATUS_OK;
854 :
855 0 : SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
856 :
857 0 : status = OpenDir(talloc_tos(),
858 : conn,
859 : smb_dname,
860 : NULL,
861 : 0,
862 : &dir_hnd);
863 0 : if (!NT_STATUS_IS_OK(status)) {
864 0 : return status;
865 : }
866 :
867 0 : dirfsp = dir_hnd_fetch_fsp(dir_hnd);
868 :
869 0 : while ((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
870 0 : struct smb_filename *atname = NULL;
871 0 : struct smb_filename *smb_dname_full = NULL;
872 0 : char *fullname = NULL;
873 0 : bool do_break = true;
874 0 : int unlink_flags = 0;
875 :
876 0 : if (ISDOT(dname) || ISDOTDOT(dname)) {
877 0 : TALLOC_FREE(talloced);
878 0 : continue;
879 : }
880 :
881 : /* Construct the full name. */
882 0 : fullname = talloc_asprintf(ctx,
883 : "%s/%s",
884 : smb_dname->base_name,
885 : dname);
886 0 : if (!fullname) {
887 0 : status = NT_STATUS_NO_MEMORY;
888 0 : goto err_break;
889 : }
890 :
891 0 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
892 : fullname,
893 : NULL,
894 : NULL,
895 : smb_dname->twrp,
896 : smb_dname->flags);
897 0 : if (smb_dname_full == NULL) {
898 0 : status = NT_STATUS_NO_MEMORY;
899 0 : goto err_break;
900 : }
901 :
902 0 : if (SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
903 0 : status = map_nt_error_from_unix(errno);
904 0 : goto err_break;
905 : }
906 :
907 0 : if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
908 0 : status = recursive_rmdir(ctx, conn, smb_dname_full);
909 0 : if (!NT_STATUS_IS_OK(status)) {
910 0 : goto err_break;
911 : }
912 0 : unlink_flags = AT_REMOVEDIR;
913 : }
914 :
915 0 : status = synthetic_pathref(talloc_tos(),
916 : dirfsp,
917 : dname,
918 : NULL,
919 0 : &smb_dname_full->st,
920 : smb_dname_full->twrp,
921 : smb_dname_full->flags,
922 : &atname);
923 0 : if (!NT_STATUS_IS_OK(status)) {
924 0 : goto err_break;
925 : }
926 :
927 0 : if (!is_visible_fsp(atname->fsp)) {
928 0 : TALLOC_FREE(smb_dname_full);
929 0 : TALLOC_FREE(fullname);
930 0 : TALLOC_FREE(talloced);
931 0 : TALLOC_FREE(atname);
932 0 : continue;
933 : }
934 :
935 0 : retval = SMB_VFS_UNLINKAT(conn,
936 : dirfsp,
937 : atname,
938 : unlink_flags);
939 0 : if (retval != 0) {
940 0 : status = map_nt_error_from_unix(errno);
941 0 : goto err_break;
942 : }
943 :
944 : /* Successful iteration. */
945 0 : do_break = false;
946 :
947 0 : err_break:
948 0 : TALLOC_FREE(smb_dname_full);
949 0 : TALLOC_FREE(fullname);
950 0 : TALLOC_FREE(talloced);
951 0 : TALLOC_FREE(atname);
952 0 : if (do_break) {
953 0 : break;
954 : }
955 : }
956 0 : TALLOC_FREE(dir_hnd);
957 0 : return status;
958 : }
959 :
960 : /****************************************************************************
961 : The internals of the rmdir code - called elsewhere.
962 : ****************************************************************************/
963 :
964 808 : static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
965 : {
966 808 : struct connection_struct *conn = fsp->conn;
967 808 : struct smb_filename *smb_dname = fsp->fsp_name;
968 808 : struct smb_filename *parent_fname = NULL;
969 808 : struct smb_filename *at_fname = NULL;
970 : SMB_STRUCT_STAT st;
971 808 : const char *dname = NULL;
972 808 : char *talloced = NULL;
973 808 : long dirpos = 0;
974 808 : struct smb_Dir *dir_hnd = NULL;
975 808 : struct files_struct *dirfsp = NULL;
976 808 : int unlink_flags = 0;
977 : NTSTATUS status;
978 : int ret;
979 :
980 808 : SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
981 :
982 808 : status = parent_pathref(talloc_tos(),
983 : conn->cwd_fsp,
984 808 : fsp->fsp_name,
985 : &parent_fname,
986 : &at_fname);
987 808 : if (!NT_STATUS_IS_OK(status)) {
988 0 : return status;
989 : }
990 :
991 : /*
992 : * Todo: use SMB_VFS_STATX() once it's available.
993 : */
994 :
995 : /* Might be a symlink. */
996 808 : ret = SMB_VFS_LSTAT(conn, smb_dname);
997 808 : if (ret != 0) {
998 0 : TALLOC_FREE(parent_fname);
999 0 : return map_nt_error_from_unix(errno);
1000 : }
1001 :
1002 808 : if (S_ISLNK(smb_dname->st.st_ex_mode)) {
1003 : /* Is what it points to a directory ? */
1004 0 : ret = SMB_VFS_STAT(conn, smb_dname);
1005 0 : if (ret != 0) {
1006 0 : TALLOC_FREE(parent_fname);
1007 0 : return map_nt_error_from_unix(errno);
1008 : }
1009 0 : if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
1010 0 : TALLOC_FREE(parent_fname);
1011 0 : return NT_STATUS_NOT_A_DIRECTORY;
1012 : }
1013 : } else {
1014 808 : unlink_flags = AT_REMOVEDIR;
1015 : }
1016 :
1017 808 : ret = SMB_VFS_UNLINKAT(conn,
1018 : parent_fname->fsp,
1019 : at_fname,
1020 : unlink_flags);
1021 808 : if (ret == 0) {
1022 808 : TALLOC_FREE(parent_fname);
1023 808 : notify_fname(conn, NOTIFY_ACTION_REMOVED,
1024 : FILE_NOTIFY_CHANGE_DIR_NAME,
1025 808 : smb_dname->base_name);
1026 808 : return NT_STATUS_OK;
1027 : }
1028 :
1029 0 : if (!((errno == ENOTEMPTY) || (errno == EEXIST))) {
1030 0 : DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
1031 : "%s\n", smb_fname_str_dbg(smb_dname),
1032 : strerror(errno)));
1033 0 : TALLOC_FREE(parent_fname);
1034 0 : return map_nt_error_from_unix(errno);
1035 : }
1036 :
1037 : /*
1038 : * Here we know the initial directory unlink failed with
1039 : * ENOTEMPTY or EEXIST so we know there are objects within.
1040 : * If we don't have permission to delete files non
1041 : * visible to the client just fail the directory delete.
1042 : */
1043 :
1044 0 : if (!lp_delete_veto_files(SNUM(conn))) {
1045 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1046 0 : goto err;
1047 : }
1048 :
1049 : /*
1050 : * Check to see if the only thing in this directory are
1051 : * files non-visible to the client. If not, fail the delete.
1052 : */
1053 :
1054 0 : status = OpenDir(talloc_tos(),
1055 : conn,
1056 : smb_dname,
1057 : NULL,
1058 : 0,
1059 : &dir_hnd);
1060 0 : if (!NT_STATUS_IS_OK(status)) {
1061 : /*
1062 : * Note, we deliberately squash the error here
1063 : * to avoid leaking information about what we
1064 : * can't delete.
1065 : */
1066 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1067 0 : goto err;
1068 : }
1069 :
1070 0 : dirfsp = dir_hnd_fetch_fsp(dir_hnd);
1071 :
1072 0 : while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
1073 0 : struct smb_filename *smb_dname_full = NULL;
1074 0 : struct smb_filename *direntry_fname = NULL;
1075 0 : char *fullname = NULL;
1076 : int retval;
1077 :
1078 0 : if (ISDOT(dname) || ISDOTDOT(dname)) {
1079 0 : TALLOC_FREE(talloced);
1080 0 : continue;
1081 : }
1082 0 : if (IS_VETO_PATH(conn, dname)) {
1083 0 : TALLOC_FREE(talloced);
1084 0 : continue;
1085 : }
1086 :
1087 0 : fullname = talloc_asprintf(talloc_tos(),
1088 : "%s/%s",
1089 : smb_dname->base_name,
1090 : dname);
1091 :
1092 0 : if (fullname == NULL) {
1093 0 : TALLOC_FREE(talloced);
1094 0 : status = NT_STATUS_NO_MEMORY;
1095 0 : goto err;
1096 : }
1097 :
1098 0 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1099 : fullname,
1100 : NULL,
1101 : NULL,
1102 : smb_dname->twrp,
1103 : smb_dname->flags);
1104 0 : if (smb_dname_full == NULL) {
1105 0 : TALLOC_FREE(talloced);
1106 0 : TALLOC_FREE(fullname);
1107 0 : status = NT_STATUS_NO_MEMORY;
1108 0 : goto err;
1109 : }
1110 :
1111 0 : retval = SMB_VFS_LSTAT(conn, smb_dname_full);
1112 0 : if (retval != 0) {
1113 0 : status = map_nt_error_from_unix(errno);
1114 0 : TALLOC_FREE(talloced);
1115 0 : TALLOC_FREE(fullname);
1116 0 : TALLOC_FREE(smb_dname_full);
1117 0 : goto err;
1118 : }
1119 :
1120 0 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1121 : /* Could it be an msdfs link ? */
1122 0 : if (lp_host_msdfs() &&
1123 0 : lp_msdfs_root(SNUM(conn))) {
1124 : struct smb_filename *smb_atname;
1125 0 : smb_atname = synthetic_smb_fname(talloc_tos(),
1126 : dname,
1127 : NULL,
1128 0 : &smb_dname_full->st,
1129 0 : fsp->fsp_name->twrp,
1130 0 : fsp->fsp_name->flags);
1131 0 : if (smb_atname == NULL) {
1132 0 : TALLOC_FREE(talloced);
1133 0 : TALLOC_FREE(fullname);
1134 0 : TALLOC_FREE(smb_dname_full);
1135 0 : status = NT_STATUS_NO_MEMORY;
1136 0 : goto err;
1137 : }
1138 0 : if (is_msdfs_link(fsp, smb_atname)) {
1139 0 : TALLOC_FREE(talloced);
1140 0 : TALLOC_FREE(fullname);
1141 0 : TALLOC_FREE(smb_dname_full);
1142 0 : TALLOC_FREE(smb_atname);
1143 0 : DBG_DEBUG("got msdfs link name %s "
1144 : "- can't delete directory %s\n",
1145 : dname,
1146 : fsp_str_dbg(fsp));
1147 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1148 0 : goto err;
1149 : }
1150 0 : TALLOC_FREE(smb_atname);
1151 : }
1152 :
1153 : /* Not a DFS link - could it be a dangling symlink ? */
1154 0 : retval = SMB_VFS_STAT(conn, smb_dname_full);
1155 0 : if (retval == -1 && (errno == ENOENT || errno == ELOOP)) {
1156 : /*
1157 : * Dangling symlink.
1158 : * Allow delete as "delete veto files = yes"
1159 : */
1160 0 : TALLOC_FREE(talloced);
1161 0 : TALLOC_FREE(fullname);
1162 0 : TALLOC_FREE(smb_dname_full);
1163 0 : continue;
1164 : }
1165 :
1166 0 : DBG_DEBUG("got symlink name %s - "
1167 : "can't delete directory %s\n",
1168 : dname,
1169 : fsp_str_dbg(fsp));
1170 0 : TALLOC_FREE(talloced);
1171 0 : TALLOC_FREE(fullname);
1172 0 : TALLOC_FREE(smb_dname_full);
1173 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1174 0 : goto err;
1175 : }
1176 :
1177 : /* Not a symlink, get a pathref. */
1178 0 : status = synthetic_pathref(talloc_tos(),
1179 : dirfsp,
1180 : dname,
1181 : NULL,
1182 0 : &smb_dname_full->st,
1183 : smb_dname->twrp,
1184 : smb_dname->flags,
1185 : &direntry_fname);
1186 0 : if (!NT_STATUS_IS_OK(status)) {
1187 0 : TALLOC_FREE(talloced);
1188 0 : TALLOC_FREE(fullname);
1189 0 : TALLOC_FREE(smb_dname_full);
1190 0 : goto err;
1191 : }
1192 :
1193 0 : if (!is_visible_fsp(direntry_fname->fsp)) {
1194 0 : TALLOC_FREE(talloced);
1195 0 : TALLOC_FREE(fullname);
1196 0 : TALLOC_FREE(smb_dname_full);
1197 0 : TALLOC_FREE(direntry_fname);
1198 0 : continue;
1199 : }
1200 :
1201 : /*
1202 : * We found a client visible name.
1203 : * We cannot delete this directory.
1204 : */
1205 0 : DBG_DEBUG("got name %s - "
1206 : "can't delete directory %s\n",
1207 : dname,
1208 : fsp_str_dbg(fsp));
1209 0 : TALLOC_FREE(talloced);
1210 0 : TALLOC_FREE(fullname);
1211 0 : TALLOC_FREE(smb_dname_full);
1212 0 : TALLOC_FREE(direntry_fname);
1213 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1214 0 : goto err;
1215 : }
1216 :
1217 : /* Do a recursive delete. */
1218 0 : RewindDir(dir_hnd,&dirpos);
1219 :
1220 0 : while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
1221 0 : struct smb_filename *direntry_fname = NULL;
1222 0 : struct smb_filename *smb_dname_full = NULL;
1223 0 : char *fullname = NULL;
1224 0 : bool do_break = true;
1225 : int retval;
1226 :
1227 0 : if (ISDOT(dname) || ISDOTDOT(dname)) {
1228 0 : TALLOC_FREE(talloced);
1229 0 : continue;
1230 : }
1231 :
1232 0 : fullname = talloc_asprintf(ctx,
1233 : "%s/%s",
1234 : smb_dname->base_name,
1235 : dname);
1236 :
1237 0 : if (fullname == NULL) {
1238 0 : status = NT_STATUS_NO_MEMORY;
1239 0 : goto err_break;
1240 : }
1241 :
1242 0 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1243 : fullname,
1244 : NULL,
1245 : NULL,
1246 : smb_dname->twrp,
1247 : smb_dname->flags);
1248 0 : if (smb_dname_full == NULL) {
1249 0 : status = NT_STATUS_NO_MEMORY;
1250 0 : goto err_break;
1251 : }
1252 :
1253 : /*
1254 : * Todo: use SMB_VFS_STATX() once that's available.
1255 : */
1256 :
1257 0 : retval = SMB_VFS_LSTAT(conn, smb_dname_full);
1258 0 : if (retval != 0) {
1259 0 : status = map_nt_error_from_unix(errno);
1260 0 : goto err_break;
1261 : }
1262 :
1263 : /*
1264 : * We are only dealing with VETO'ed objects
1265 : * here. If it's a symlink, just delete the
1266 : * link without caring what it is pointing
1267 : * to.
1268 : */
1269 0 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1270 0 : direntry_fname = synthetic_smb_fname(talloc_tos(),
1271 : dname,
1272 : NULL,
1273 0 : &smb_dname_full->st,
1274 : smb_dname->twrp,
1275 : smb_dname->flags);
1276 0 : if (direntry_fname == NULL) {
1277 0 : status = NT_STATUS_NO_MEMORY;
1278 0 : goto err_break;
1279 : }
1280 : } else {
1281 0 : status = synthetic_pathref(talloc_tos(),
1282 : dirfsp,
1283 : dname,
1284 : NULL,
1285 0 : &smb_dname_full->st,
1286 : smb_dname->twrp,
1287 : smb_dname->flags,
1288 : &direntry_fname);
1289 0 : if (!NT_STATUS_IS_OK(status)) {
1290 0 : goto err_break;
1291 : }
1292 :
1293 0 : if (!is_visible_fsp(direntry_fname->fsp)) {
1294 0 : TALLOC_FREE(fullname);
1295 0 : TALLOC_FREE(smb_dname_full);
1296 0 : TALLOC_FREE(talloced);
1297 0 : TALLOC_FREE(direntry_fname);
1298 0 : continue;
1299 : }
1300 : }
1301 :
1302 0 : unlink_flags = 0;
1303 :
1304 0 : if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
1305 0 : status = recursive_rmdir(ctx, conn, smb_dname_full);
1306 0 : if (!NT_STATUS_IS_OK(status)) {
1307 0 : goto err_break;
1308 : }
1309 0 : unlink_flags = AT_REMOVEDIR;
1310 : }
1311 :
1312 0 : retval = SMB_VFS_UNLINKAT(conn,
1313 : dirfsp,
1314 : direntry_fname,
1315 : unlink_flags);
1316 0 : if (retval != 0) {
1317 0 : status = map_nt_error_from_unix(errno);
1318 0 : goto err_break;
1319 : }
1320 :
1321 : /* Successful iteration. */
1322 0 : do_break = false;
1323 :
1324 0 : err_break:
1325 0 : TALLOC_FREE(fullname);
1326 0 : TALLOC_FREE(smb_dname_full);
1327 0 : TALLOC_FREE(talloced);
1328 0 : TALLOC_FREE(direntry_fname);
1329 0 : if (do_break) {
1330 0 : break;
1331 : }
1332 : }
1333 :
1334 : /* If we get here, we know NT_STATUS_IS_OK(status) */
1335 0 : SMB_ASSERT(NT_STATUS_IS_OK(status));
1336 :
1337 : /* Retry the rmdir */
1338 0 : ret = SMB_VFS_UNLINKAT(conn,
1339 : parent_fname->fsp,
1340 : at_fname,
1341 : AT_REMOVEDIR);
1342 0 : if (ret != 0) {
1343 0 : status = map_nt_error_from_unix(errno);
1344 : }
1345 :
1346 0 : err:
1347 :
1348 0 : TALLOC_FREE(dir_hnd);
1349 0 : TALLOC_FREE(parent_fname);
1350 :
1351 0 : if (!NT_STATUS_IS_OK(status)) {
1352 0 : DBG_NOTICE("couldn't remove directory %s : "
1353 : "%s\n", smb_fname_str_dbg(smb_dname),
1354 : nt_errstr(status));
1355 0 : return status;
1356 : }
1357 :
1358 0 : notify_fname(conn, NOTIFY_ACTION_REMOVED,
1359 : FILE_NOTIFY_CHANGE_DIR_NAME,
1360 0 : smb_dname->base_name);
1361 :
1362 0 : return status;
1363 : }
1364 :
1365 : /****************************************************************************
1366 : Close a directory opened by an NT SMB call.
1367 : ****************************************************************************/
1368 :
1369 10216 : static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
1370 : enum file_close_type close_type)
1371 : {
1372 10216 : struct share_mode_lock *lck = NULL;
1373 10216 : bool delete_dir = False;
1374 10216 : NTSTATUS status = NT_STATUS_OK;
1375 10216 : NTSTATUS status1 = NT_STATUS_OK;
1376 10216 : const struct security_token *del_nt_token = NULL;
1377 10216 : const struct security_unix_token *del_token = NULL;
1378 : NTSTATUS notify_status;
1379 :
1380 10216 : SMB_ASSERT(fsp->fsp_flags.is_fsa);
1381 :
1382 10216 : if (fsp->conn->sconn->using_smb2) {
1383 10216 : notify_status = NT_STATUS_NOTIFY_CLEANUP;
1384 : } else {
1385 0 : notify_status = NT_STATUS_OK;
1386 : }
1387 :
1388 10216 : assert_no_pending_aio(fsp, close_type);
1389 :
1390 : /*
1391 : * NT can set delete_on_close of the last open
1392 : * reference to a directory also.
1393 : */
1394 :
1395 10216 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1396 10216 : if (lck == NULL) {
1397 0 : DEBUG(0, ("close_directory: Could not get share mode lock for "
1398 : "%s\n", fsp_str_dbg(fsp)));
1399 0 : return NT_STATUS_INVALID_PARAMETER;
1400 : }
1401 :
1402 10216 : if (fsp->fsp_flags.initial_delete_on_close) {
1403 : /* Initial delete on close was set - for
1404 : * directories we don't care if anyone else
1405 : * wrote a real delete on close. */
1406 :
1407 10 : send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
1408 10 : fsp->fsp_name->base_name);
1409 10 : set_delete_on_close_lck(fsp, lck,
1410 10 : fsp->conn->session_info->security_token,
1411 10 : fsp->conn->session_info->unix_token);
1412 10 : fsp->fsp_flags.delete_on_close = true;
1413 : }
1414 :
1415 19534 : delete_dir = get_delete_on_close_token(
1416 11024 : lck, fsp->name_hash, &del_nt_token, &del_token) &&
1417 808 : !has_other_nonposix_opens(lck, fsp);
1418 :
1419 10216 : if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
1420 : delete_dir) {
1421 :
1422 : /* Become the user who requested the delete. */
1423 :
1424 808 : if (!push_sec_ctx()) {
1425 0 : smb_panic("close_directory: failed to push sec_ctx.\n");
1426 : }
1427 :
1428 3097 : set_sec_ctx(del_token->uid,
1429 808 : del_token->gid,
1430 808 : del_token->ngroups,
1431 808 : del_token->groups,
1432 : del_nt_token);
1433 :
1434 808 : if (!del_share_mode(lck, fsp)) {
1435 0 : DEBUG(0, ("close_directory: Could not delete share entry for "
1436 : "%s\n", fsp_str_dbg(fsp)));
1437 : }
1438 :
1439 808 : TALLOC_FREE(lck);
1440 :
1441 808 : if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
1442 808 : && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
1443 :
1444 808 : status = delete_all_streams(fsp->conn, fsp->fsp_name);
1445 808 : if (!NT_STATUS_IS_OK(status)) {
1446 0 : DEBUG(5, ("delete_all_streams failed: %s\n",
1447 : nt_errstr(status)));
1448 : /* unbecome user. */
1449 0 : pop_sec_ctx();
1450 0 : return status;
1451 : }
1452 : }
1453 :
1454 808 : status = rmdir_internals(talloc_tos(), fsp);
1455 :
1456 808 : DEBUG(5,("close_directory: %s. Delete on close was set - "
1457 : "deleting directory returned %s.\n",
1458 : fsp_str_dbg(fsp), nt_errstr(status)));
1459 :
1460 : /* unbecome user. */
1461 808 : pop_sec_ctx();
1462 :
1463 : /*
1464 : * Ensure we remove any change notify requests that would
1465 : * now fail as the directory has been deleted.
1466 : */
1467 :
1468 1571 : if (NT_STATUS_IS_OK(status)) {
1469 808 : notify_status = NT_STATUS_DELETE_PENDING;
1470 : }
1471 : } else {
1472 9408 : if (!del_share_mode(lck, fsp)) {
1473 0 : DEBUG(0, ("close_directory: Could not delete share entry for "
1474 : "%s\n", fsp_str_dbg(fsp)));
1475 : }
1476 :
1477 9408 : TALLOC_FREE(lck);
1478 : }
1479 :
1480 10216 : remove_pending_change_notify_requests_by_fid(fsp, notify_status);
1481 :
1482 10216 : status1 = fd_close(fsp);
1483 :
1484 10216 : if (!NT_STATUS_IS_OK(status1)) {
1485 0 : DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
1486 : fsp_str_dbg(fsp), fsp_get_pathref_fd(fsp), errno,
1487 : strerror(errno)));
1488 : }
1489 :
1490 10216 : if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
1491 0 : status = status1;
1492 : }
1493 10216 : return status;
1494 : }
1495 :
1496 : /****************************************************************************
1497 : Rundown all SMB-related dependencies of a files struct
1498 : ****************************************************************************/
1499 :
1500 16416 : NTSTATUS close_file_smb(struct smb_request *req,
1501 : struct files_struct *fsp,
1502 : enum file_close_type close_type)
1503 : {
1504 : NTSTATUS status;
1505 :
1506 : /*
1507 : * This fsp can never be an internal dirfsp. They must
1508 : * be explicitly closed by TALLOC_FREE of the dir handle.
1509 : */
1510 16416 : SMB_ASSERT(!fsp->fsp_flags.is_dirfsp);
1511 :
1512 : /*
1513 : * Never call directly on a base fsp
1514 : */
1515 16416 : SMB_ASSERT(fsp->stream_fsp == NULL);
1516 :
1517 16416 : if (fsp->fake_file_handle != NULL) {
1518 3438 : status = close_fake_file(req, fsp);
1519 12978 : } else if (fsp->print_file != NULL) {
1520 : /* FIXME: return spool errors */
1521 0 : print_spool_end(fsp, close_type);
1522 0 : fd_close(fsp);
1523 0 : status = NT_STATUS_OK;
1524 12978 : } else if (!fsp->fsp_flags.is_fsa) {
1525 912 : if (close_type == NORMAL_CLOSE) {
1526 0 : DBG_ERR("unexpected NORMAL_CLOSE for [%s] "
1527 : "is_fsa[%u] is_pathref[%u] is_directory[%u]\n",
1528 : fsp_str_dbg(fsp),
1529 : fsp->fsp_flags.is_fsa,
1530 : fsp->fsp_flags.is_pathref,
1531 : fsp->fsp_flags.is_directory);
1532 : }
1533 912 : SMB_ASSERT(close_type != NORMAL_CLOSE);
1534 912 : fd_close(fsp);
1535 912 : status = NT_STATUS_OK;
1536 12066 : } else if (fsp->fsp_flags.is_directory) {
1537 10216 : status = close_directory(req, fsp, close_type);
1538 : } else {
1539 1850 : status = close_normal_file(req, fsp, close_type);
1540 : }
1541 :
1542 16416 : if (fsp_is_alternate_stream(fsp)) {
1543 : /*
1544 : * fsp was a stream, its base_fsp can't be a stream
1545 : * as well
1546 : */
1547 64 : SMB_ASSERT(!fsp_is_alternate_stream(fsp->base_fsp));
1548 :
1549 : /*
1550 : * There's a 1:1 relationship between fsp and a base_fsp
1551 : */
1552 64 : SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
1553 :
1554 : /*
1555 : * Make base_fsp look standalone now
1556 : */
1557 64 : fsp->base_fsp->stream_fsp = NULL;
1558 :
1559 64 : close_file_free(req, &fsp->base_fsp, close_type);
1560 : }
1561 :
1562 16416 : fsp_unbind_smb(req, fsp);
1563 :
1564 16416 : return status;
1565 : }
1566 :
1567 358 : NTSTATUS close_file_free(struct smb_request *req,
1568 : struct files_struct **_fsp,
1569 : enum file_close_type close_type)
1570 : {
1571 358 : struct files_struct *fsp = *_fsp;
1572 : NTSTATUS status;
1573 :
1574 358 : status = close_file_smb(req, fsp, close_type);
1575 :
1576 358 : file_free(req, fsp);
1577 358 : *_fsp = NULL;
1578 :
1579 358 : return status;
1580 : }
1581 :
1582 : /****************************************************************************
1583 : Deal with an (authorized) message to close a file given the share mode
1584 : entry.
1585 : ****************************************************************************/
1586 :
1587 0 : void msg_close_file(struct messaging_context *msg_ctx,
1588 : void *private_data,
1589 : uint32_t msg_type,
1590 : struct server_id server_id,
1591 : DATA_BLOB *data)
1592 : {
1593 0 : files_struct *fsp = NULL;
1594 : struct file_id id;
1595 : struct share_mode_entry e;
1596 0 : struct smbd_server_connection *sconn =
1597 0 : talloc_get_type_abort(private_data,
1598 : struct smbd_server_connection);
1599 :
1600 0 : message_to_share_mode_entry(&id, &e, (char *)data->data);
1601 :
1602 0 : if(DEBUGLVL(10)) {
1603 0 : char *sm_str = share_mode_str(NULL, 0, &id, &e);
1604 0 : if (!sm_str) {
1605 0 : smb_panic("talloc failed");
1606 : }
1607 0 : DEBUG(10,("msg_close_file: got request to close share mode "
1608 : "entry %s\n", sm_str));
1609 0 : TALLOC_FREE(sm_str);
1610 : }
1611 :
1612 0 : fsp = file_find_dif(sconn, id, e.share_file_id);
1613 0 : if (!fsp) {
1614 0 : DEBUG(10,("msg_close_file: failed to find file.\n"));
1615 0 : return;
1616 : }
1617 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
1618 : }
|