s3: smbd: Cleanup - Make rmdir_internals() use NTSTATUS internally without depending...
[samba.git] / source3 / smbd / close.c
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 static NTSTATUS check_magic(struct files_struct *fsp)
43 {
44         int ret;
45         const struct loadparm_substitution *lp_sub =
46                 loadparm_s3_global_substitution();
47         const char *magic_output = NULL;
48         SMB_STRUCT_STAT st;
49         int tmp_fd, outfd;
50         TALLOC_CTX *ctx = NULL;
51         const char *p;
52         struct connection_struct *conn = fsp->conn;
53         char *fname = NULL;
54         NTSTATUS status;
55
56         if (!*lp_magic_script(talloc_tos(), lp_sub, SNUM(conn))) {
57                 return NT_STATUS_OK;
58         }
59
60         DEBUG(5,("checking magic for %s\n", fsp_str_dbg(fsp)));
61
62         ctx = talloc_stackframe();
63
64         fname = fsp->fsp_name->base_name;
65
66         if (!(p = strrchr_m(fname,'/'))) {
67                 p = fname;
68         } else {
69                 p++;
70         }
71
72         if (!strequal(lp_magic_script(talloc_tos(), lp_sub, SNUM(conn)),p)) {
73                 status = NT_STATUS_OK;
74                 goto out;
75         }
76
77         if (*lp_magic_output(talloc_tos(), lp_sub, SNUM(conn))) {
78                 magic_output = lp_magic_output(talloc_tos(), lp_sub, SNUM(conn));
79         } else {
80                 magic_output = talloc_asprintf(ctx,
81                                 "%s.out",
82                                 fname);
83         }
84         if (!magic_output) {
85                 status = NT_STATUS_NO_MEMORY;
86                 goto out;
87         }
88
89         /* Ensure we don't depend on user's PATH. */
90         p = talloc_asprintf(ctx, "./%s", fname);
91         if (!p) {
92                 status = NT_STATUS_NO_MEMORY;
93                 goto out;
94         }
95
96         if (chmod(fname, 0755) == -1) {
97                 status = map_nt_error_from_unix(errno);
98                 goto out;
99         }
100         ret = smbrun(p, &tmp_fd, NULL);
101         DEBUG(3,("Invoking magic command %s gave %d\n",
102                 p,ret));
103
104         unlink(fname);
105         if (ret != 0 || tmp_fd == -1) {
106                 if (tmp_fd != -1) {
107                         close(tmp_fd);
108                 }
109                 status = NT_STATUS_UNSUCCESSFUL;
110                 goto out;
111         }
112         outfd = open(magic_output, O_CREAT|O_EXCL|O_RDWR, 0600);
113         if (outfd == -1) {
114                 int err = errno;
115                 close(tmp_fd);
116                 status = map_nt_error_from_unix(err);
117                 goto out;
118         }
119
120         if (sys_fstat(tmp_fd, &st, false) == -1) {
121                 int err = errno;
122                 close(tmp_fd);
123                 close(outfd);
124                 status = map_nt_error_from_unix(err);
125                 goto out;
126         }
127
128         if (transfer_file(tmp_fd,outfd,(off_t)st.st_ex_size) == (off_t)-1) {
129                 int err = errno;
130                 close(tmp_fd);
131                 close(outfd);
132                 status = map_nt_error_from_unix(err);
133                 goto out;
134         }
135         close(tmp_fd);
136         if (close(outfd) == -1) {
137                 status = map_nt_error_from_unix(errno);
138                 goto out;
139         }
140
141         status = NT_STATUS_OK;
142
143  out:
144         TALLOC_FREE(ctx);
145         return status;
146 }
147
148 /****************************************************************************
149  Delete all streams
150 ****************************************************************************/
151
152 NTSTATUS delete_all_streams(connection_struct *conn,
153                         const struct smb_filename *smb_fname)
154 {
155         struct stream_struct *stream_info = NULL;
156         unsigned int i;
157         unsigned int num_streams = 0;
158         TALLOC_CTX *frame = talloc_stackframe();
159         NTSTATUS status;
160
161         status = vfs_fstreaminfo(smb_fname->fsp, talloc_tos(),
162                                 &num_streams, &stream_info);
163
164         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
165                 DEBUG(10, ("no streams around\n"));
166                 TALLOC_FREE(frame);
167                 return NT_STATUS_OK;
168         }
169
170         if (!NT_STATUS_IS_OK(status)) {
171                 DEBUG(10, ("vfs_fstreaminfo failed: %s\n",
172                            nt_errstr(status)));
173                 goto fail;
174         }
175
176         DEBUG(10, ("delete_all_streams found %d streams\n",
177                    num_streams));
178
179         if (num_streams == 0) {
180                 TALLOC_FREE(frame);
181                 return NT_STATUS_OK;
182         }
183
184         for (i=0; i<num_streams; i++) {
185                 int res;
186                 struct smb_filename *smb_fname_stream;
187
188                 if (strequal(stream_info[i].name, "::$DATA")) {
189                         continue;
190                 }
191
192                 status = synthetic_pathref(talloc_tos(),
193                                            conn->cwd_fsp,
194                                            smb_fname->base_name,
195                                            stream_info[i].name,
196                                            NULL,
197                                            smb_fname->twrp,
198                                            (smb_fname->flags &
199                                             ~SMB_FILENAME_POSIX_PATH),
200                                            &smb_fname_stream);
201                 if (!NT_STATUS_IS_OK(status)) {
202                         DEBUG(0, ("talloc_aprintf failed\n"));
203                         status = NT_STATUS_NO_MEMORY;
204                         goto fail;
205                 }
206
207                 res = SMB_VFS_UNLINKAT(conn,
208                                 conn->cwd_fsp,
209                                 smb_fname_stream,
210                                 0);
211
212                 if (res == -1) {
213                         status = map_nt_error_from_unix(errno);
214                         DEBUG(10, ("Could not delete stream %s: %s\n",
215                                    smb_fname_str_dbg(smb_fname_stream),
216                                    strerror(errno)));
217                         TALLOC_FREE(smb_fname_stream);
218                         break;
219                 }
220                 TALLOC_FREE(smb_fname_stream);
221         }
222
223  fail:
224         TALLOC_FREE(frame);
225         return status;
226 }
227
228 struct has_other_nonposix_opens_state {
229         files_struct *fsp;
230         bool found_another;
231 };
232
233 static bool has_other_nonposix_opens_fn(
234         struct share_mode_entry *e,
235         bool *modified,
236         void *private_data)
237 {
238         struct has_other_nonposix_opens_state *state = private_data;
239         struct files_struct *fsp = state->fsp;
240
241         if (e->name_hash != fsp->name_hash) {
242                 return false;
243         }
244         if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
245             (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
246                 return false;
247         }
248         if (e->share_file_id == fh_get_gen_id(fsp->fh)) {
249                 struct server_id self = messaging_server_id(
250                         fsp->conn->sconn->msg_ctx);
251                 if (server_id_equal(&self, &e->pid)) {
252                         return false;
253                 }
254         }
255         if (share_entry_stale_pid(e)) {
256                 return false;
257         }
258
259         state->found_another = true;
260         return true;
261 }
262
263 bool has_other_nonposix_opens(struct share_mode_lock *lck,
264                               struct files_struct *fsp)
265 {
266         struct has_other_nonposix_opens_state state = { .fsp = fsp };
267         bool ok;
268
269         ok = share_mode_forall_entries(
270                 lck, has_other_nonposix_opens_fn, &state);
271         if (!ok) {
272                 return false;
273         }
274         return state.found_another;
275 }
276
277 /****************************************************************************
278  Deal with removing a share mode on last close.
279 ****************************************************************************/
280
281 static NTSTATUS close_remove_share_mode(files_struct *fsp,
282                                         enum file_close_type close_type)
283 {
284         connection_struct *conn = fsp->conn;
285         bool delete_file = false;
286         bool changed_user = false;
287         struct share_mode_lock *lck = NULL;
288         NTSTATUS status = NT_STATUS_OK;
289         NTSTATUS tmp_status;
290         struct file_id id;
291         const struct security_unix_token *del_token = NULL;
292         const struct security_token *del_nt_token = NULL;
293         struct smb_filename *parent_fname = NULL;
294         struct smb_filename *base_fname = NULL;
295         bool got_tokens = false;
296         bool normal_close;
297         int ret;
298
299         /* Ensure any pending write time updates are done. */
300         if (fsp->update_write_time_event) {
301                 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         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
311         if (lck == NULL) {
312                 DEBUG(0, ("close_remove_share_mode: Could not get share mode "
313                           "lock for file %s\n", fsp_str_dbg(fsp)));
314                 return NT_STATUS_INVALID_PARAMETER;
315         }
316
317         /* Remove the oplock before potentially deleting the file. */
318         if(fsp->oplock_type) {
319                 remove_oplock(fsp);
320         }
321
322         if (fsp->fsp_flags.write_time_forced) {
323                 NTTIME mtime = share_mode_changed_write_time(lck);
324                 struct timespec ts = nt_time_to_full_timespec(mtime);
325
326                 DEBUG(10,("close_remove_share_mode: write time forced "
327                         "for file %s\n",
328                         fsp_str_dbg(fsp)));
329                 set_close_write_time(fsp, ts);
330         } else if (fsp->fsp_flags.update_write_time_on_close) {
331                 /* Someone had a pending write. */
332                 if (is_omit_timespec(&fsp->close_write_time)) {
333                         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                         set_close_write_time(fsp, timespec_current());
338                 } else {
339                         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                         set_close_write_time(fsp, fsp->close_write_time);
344                 }
345         }
346
347         if (fsp->fsp_flags.initial_delete_on_close &&
348                         !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                 fsp->fsp_flags.delete_on_close = true;
353                 set_delete_on_close_lck(fsp, lck,
354                                         fsp->conn->session_info->security_token,
355                                         fsp->conn->session_info->unix_token);
356         }
357
358         delete_file = is_delete_on_close_set(lck, fsp->name_hash) &&
359                 !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         normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);
367
368         if (!normal_close || !delete_file) {
369                 status = NT_STATUS_OK;
370                 goto done;
371         }
372
373         /*
374          * Ok, we have to delete the file
375          */
376
377         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         fsp->fsp_flags.update_write_time_on_close = false;
384
385         got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
386                                         &del_nt_token, &del_token);
387         SMB_ASSERT(got_tokens);
388
389         if (!unix_token_equal(del_token, get_current_utok(conn))) {
390                 /* Become the user who requested the delete. */
391
392                 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                 if (!push_sec_ctx()) {
398                         smb_panic("close_remove_share_mode: file %s. failed to push "
399                                   "sec_ctx.\n");
400                 }
401
402                 set_sec_ctx(del_token->uid,
403                             del_token->gid,
404                             del_token->ngroups,
405                             del_token->groups,
406                             del_nt_token);
407
408                 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         tmp_status = vfs_stat_fsp(fsp);
415         if (!NT_STATUS_IS_OK(tmp_status)) {
416                 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                 goto done;
423         }
424
425         id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
426
427         if (!file_id_equal(&fsp->file_id, &id)) {
428                 struct file_id_buf ftmp1, ftmp2;
429                 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                 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                 goto done;
441         }
442
443         if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
444             && !fsp_is_alternate_stream(fsp)) {
445
446                 status = delete_all_streams(conn, fsp->fsp_name);
447
448                 if (!NT_STATUS_IS_OK(status)) {
449                         DEBUG(5, ("delete_all_streams failed: %s\n",
450                                   nt_errstr(status)));
451                         goto done;
452                 }
453         }
454
455         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                 ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
461                 if (ret == -1) {
462                         DBG_INFO("Removing file system sharemode for %s "
463                                  "failed: %s\n",
464                                  fsp_str_dbg(fsp), strerror(errno));
465                 }
466
467                 fsp->fsp_flags.kernel_share_modes_taken = false;
468         }
469
470         status = parent_pathref(talloc_tos(),
471                                 conn->cwd_fsp,
472                                 fsp->fsp_name,
473                                 &parent_fname,
474                                 &base_fname);
475         if (!NT_STATUS_IS_OK(status)) {
476                 goto done;
477         }
478
479         ret = SMB_VFS_UNLINKAT(conn,
480                                parent_fname->fsp,
481                                base_fname,
482                                0);
483         TALLOC_FREE(parent_fname);
484         base_fname = NULL;
485         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                 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                 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         fsp->fsp_flags.delete_on_close = false;
509         reset_delete_on_close_lck(fsp, lck);
510
511  done:
512
513         if (changed_user) {
514                 /* unbecome user. */
515                 pop_sec_ctx();
516         }
517
518         if (fsp->fsp_flags.kernel_share_modes_taken) {
519                 /* remove filesystem sharemodes */
520                 ret = SMB_VFS_FILESYSTEM_SHAREMODE(fsp, 0, 0);
521                 if (ret == -1) {
522                         DBG_INFO("Removing file system sharemode for "
523                                  "%s failed: %s\n",
524                                  fsp_str_dbg(fsp), strerror(errno));
525                 }
526         }
527
528         if (!del_share_mode(lck, fsp)) {
529                 DEBUG(0, ("close_remove_share_mode: Could not delete share "
530                           "entry for file %s\n", fsp_str_dbg(fsp)));
531         }
532
533         TALLOC_FREE(lck);
534
535         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                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
548                              FILE_NOTIFY_CHANGE_FILE_NAME,
549                              fsp->fsp_name->base_name);
550         }
551
552         return status;
553 }
554
555 void set_close_write_time(struct files_struct *fsp, struct timespec ts)
556 {
557         DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
558
559         if (is_omit_timespec(&ts)) {
560                 return;
561         }
562         fsp->fsp_flags.write_time_forced = false;
563         fsp->fsp_flags.update_write_time_on_close = true;
564         fsp->close_write_time = ts;
565 }
566
567 static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
568 {
569         struct smb_file_time ft;
570         NTSTATUS status;
571         struct share_mode_lock *lck = NULL;
572
573         init_smb_file_time(&ft);
574
575         if (!(fsp->fsp_flags.update_write_time_on_close)) {
576                 return NT_STATUS_OK;
577         }
578
579         if (is_omit_timespec(&fsp->close_write_time)) {
580                 fsp->close_write_time = timespec_current();
581         }
582
583         /* Ensure we have a valid stat struct for the source. */
584         status = vfs_stat_fsp(fsp);
585         if (!NT_STATUS_IS_OK(status)) {
586                 return status;
587         }
588
589         if (!VALID_STAT(fsp->fsp_name->st)) {
590                 /* if it doesn't seem to be a real file */
591                 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         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
607         if (lck) {
608                 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                 (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                 if (!null_nttime(share_mtime)) {
616                         (void)set_sticky_write_time(fsp->file_id, fsp->close_write_time);
617                 }
618                 TALLOC_FREE(lck);
619         }
620
621         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         status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
625         if (!NT_STATUS_IS_OK(status)) {
626                 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                 return status;
631         }
632
633         return status;
634 }
635
636 static NTSTATUS ntstatus_keeperror(NTSTATUS s1, NTSTATUS s2)
637 {
638         if (!NT_STATUS_IS_OK(s1)) {
639                 return s1;
640         }
641         return s2;
642 }
643
644 static void assert_no_pending_aio(struct files_struct *fsp,
645                                   enum file_close_type close_type)
646 {
647         struct smbXsrv_client *client = global_smbXsrv_client;
648         size_t num_connections_alive;
649         unsigned num_requests = fsp->num_aio_requests;
650
651         if (num_requests == 0) {
652                 return;
653         }
654
655         num_connections_alive = smbXsrv_client_valid_connections(client);
656
657         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                 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                         talloc_free(fsp->aio_requests[0]);
687                 }
688                 return;
689         }
690
691         DBG_ERR("fsp->num_aio_requests=%u\n", num_requests);
692         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 static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
705                                   enum file_close_type close_type)
706 {
707         NTSTATUS status = NT_STATUS_OK;
708         NTSTATUS tmp;
709         connection_struct *conn = fsp->conn;
710         bool is_durable = false;
711
712         SMB_ASSERT(fsp->fsp_flags.is_fsa);
713
714         assert_no_pending_aio(fsp, close_type);
715
716         while (talloc_array_length(fsp->blocked_smb1_lock_reqs) != 0) {
717                 smbd_smb1_brl_finish_by_req(
718                         fsp->blocked_smb1_lock_reqs[0],
719                         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         if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
728                 is_durable = fsp->op->global->durable;
729         }
730
731         if (close_type != SHUTDOWN_CLOSE) {
732                 is_durable = false;
733         }
734
735         if (is_durable) {
736                 DATA_BLOB new_cookie = data_blob_null;
737
738                 tmp = SMB_VFS_DURABLE_DISCONNECT(fsp,
739                                         fsp->op->global->backend_cookie,
740                                         fsp->op,
741                                         &new_cookie);
742                 if (NT_STATUS_IS_OK(tmp)) {
743                         struct timeval tv;
744                         NTTIME now;
745
746                         if (req != NULL) {
747                                 tv = req->request_time;
748                         } else {
749                                 tv = timeval_current();
750                         }
751                         now = timeval_to_nttime(&tv);
752
753                         data_blob_free(&fsp->op->global->backend_cookie);
754                         fsp->op->global->backend_cookie = new_cookie;
755
756                         fsp->op->compat = NULL;
757                         tmp = smbXsrv_open_close(fsp->op, now);
758                         if (!NT_STATUS_IS_OK(tmp)) {
759                                 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                         scavenger_schedule_disconnected(fsp);
766                 } else {
767                         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                 if (!NT_STATUS_IS_OK(tmp)) {
772                         is_durable = false;
773                 }
774         }
775
776         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                 DEBUG(10, ("%s disconnected durable handle for file %s\n",
783                            conn->session_info->unix_info->unix_name,
784                            fsp_str_dbg(fsp)));
785                 return NT_STATUS_OK;
786         }
787
788         if (fsp->op != NULL) {
789                 /*
790                  * Make sure the handle is not marked as durable anymore
791                  */
792                 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         if (fh_get_refcount(fsp->fh) == 1) {
800                 /* Should we return on error here... ? */
801                 tmp = close_remove_share_mode(fsp, close_type);
802                 status = ntstatus_keeperror(status, tmp);
803         }
804
805         locking_close_file(fsp, close_type);
806
807         /*
808          * Ensure pending modtime is set before closing underlying fd.
809          */
810
811         tmp = update_write_time_on_close(fsp);
812         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                 tmp = NT_STATUS_OK;
818         }
819         status = ntstatus_keeperror(status, tmp);
820
821         tmp = fd_close(fsp);
822         status = ntstatus_keeperror(status, tmp);
823
824         /* check for magic scripts */
825         if (close_type == NORMAL_CLOSE) {
826                 tmp = check_magic(fsp);
827                 status = ntstatus_keeperror(status, tmp);
828         }
829
830         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         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 NTSTATUS recursive_rmdir(TALLOC_CTX *ctx,
843                      connection_struct *conn,
844                      struct smb_filename *smb_dname)
845 {
846         const char *dname = NULL;
847         char *talloced = NULL;
848         long offset = 0;
849         SMB_STRUCT_STAT st;
850         struct smb_Dir *dir_hnd = NULL;
851         struct files_struct *dirfsp = NULL;
852         int retval;
853         NTSTATUS status = NT_STATUS_OK;
854
855         SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
856
857         status = OpenDir(talloc_tos(),
858                          conn,
859                          smb_dname,
860                          NULL,
861                          0,
862                          &dir_hnd);
863         if (!NT_STATUS_IS_OK(status)) {
864                 return status;
865         }
866
867         dirfsp = dir_hnd_fetch_fsp(dir_hnd);
868
869         while ((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
870                 struct smb_filename *atname = NULL;
871                 struct smb_filename *smb_dname_full = NULL;
872                 char *fullname = NULL;
873                 bool do_break = true;
874                 int unlink_flags = 0;
875
876                 if (ISDOT(dname) || ISDOTDOT(dname)) {
877                         TALLOC_FREE(talloced);
878                         continue;
879                 }
880
881                 /* Construct the full name. */
882                 fullname = talloc_asprintf(ctx,
883                                 "%s/%s",
884                                 smb_dname->base_name,
885                                 dname);
886                 if (!fullname) {
887                         status = NT_STATUS_NO_MEMORY;
888                         goto err_break;
889                 }
890
891                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
892                                                 fullname,
893                                                 NULL,
894                                                 NULL,
895                                                 smb_dname->twrp,
896                                                 smb_dname->flags);
897                 if (smb_dname_full == NULL) {
898                         status = NT_STATUS_NO_MEMORY;
899                         goto err_break;
900                 }
901
902                 if (SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
903                         status = map_nt_error_from_unix(errno);
904                         goto err_break;
905                 }
906
907                 if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
908                         status = recursive_rmdir(ctx, conn, smb_dname_full);
909                         if (!NT_STATUS_IS_OK(status)) {
910                                 goto err_break;
911                         }
912                         unlink_flags = AT_REMOVEDIR;
913                 }
914
915                 status = synthetic_pathref(talloc_tos(),
916                                            dirfsp,
917                                            dname,
918                                            NULL,
919                                            &smb_dname_full->st,
920                                            smb_dname_full->twrp,
921                                            smb_dname_full->flags,
922                                            &atname);
923                 if (!NT_STATUS_IS_OK(status)) {
924                         goto err_break;
925                 }
926
927                 if (!is_visible_fsp(atname->fsp)) {
928                         TALLOC_FREE(smb_dname_full);
929                         TALLOC_FREE(fullname);
930                         TALLOC_FREE(talloced);
931                         TALLOC_FREE(atname);
932                         continue;
933                 }
934
935                 retval = SMB_VFS_UNLINKAT(conn,
936                                           dirfsp,
937                                           atname,
938                                           unlink_flags);
939                 if (retval != 0) {
940                         status = map_nt_error_from_unix(errno);
941                         goto err_break;
942                 }
943
944                 /* Successful iteration. */
945                 do_break = false;
946
947          err_break:
948                 TALLOC_FREE(smb_dname_full);
949                 TALLOC_FREE(fullname);
950                 TALLOC_FREE(talloced);
951                 TALLOC_FREE(atname);
952                 if (do_break) {
953                         break;
954                 }
955         }
956         TALLOC_FREE(dir_hnd);
957         return status;
958 }
959
960 /****************************************************************************
961  The internals of the rmdir code - called elsewhere.
962 ****************************************************************************/
963
964 static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
965 {
966         struct connection_struct *conn = fsp->conn;
967         struct smb_filename *smb_dname = fsp->fsp_name;
968         struct smb_filename *parent_fname = NULL;
969         struct smb_filename *at_fname = NULL;
970         SMB_STRUCT_STAT st;
971         const char *dname = NULL;
972         char *talloced = NULL;
973         long dirpos = 0;
974         struct smb_Dir *dir_hnd = NULL;
975         struct files_struct *dirfsp = NULL;
976         int unlink_flags = 0;
977         NTSTATUS status;
978         int ret;
979
980         SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
981
982         status = parent_pathref(talloc_tos(),
983                                 conn->cwd_fsp,
984                                 fsp->fsp_name,
985                                 &parent_fname,
986                                 &at_fname);
987         if (!NT_STATUS_IS_OK(status)) {
988                 return status;
989         }
990
991         /*
992          * Todo: use SMB_VFS_STATX() once it's available.
993          */
994
995         /* Might be a symlink. */
996         ret = SMB_VFS_LSTAT(conn, smb_dname);
997         if (ret != 0) {
998                 TALLOC_FREE(parent_fname);
999                 return map_nt_error_from_unix(errno);
1000         }
1001
1002         if (S_ISLNK(smb_dname->st.st_ex_mode)) {
1003                 /* Is what it points to a directory ? */
1004                 ret = SMB_VFS_STAT(conn, smb_dname);
1005                 if (ret != 0) {
1006                         TALLOC_FREE(parent_fname);
1007                         return map_nt_error_from_unix(errno);
1008                 }
1009                 if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
1010                         TALLOC_FREE(parent_fname);
1011                         return NT_STATUS_NOT_A_DIRECTORY;
1012                 }
1013         } else {
1014                 unlink_flags = AT_REMOVEDIR;
1015         }
1016
1017         ret = SMB_VFS_UNLINKAT(conn,
1018                                parent_fname->fsp,
1019                                at_fname,
1020                                unlink_flags);
1021         if (ret == 0) {
1022                 TALLOC_FREE(parent_fname);
1023                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
1024                              FILE_NOTIFY_CHANGE_DIR_NAME,
1025                              smb_dname->base_name);
1026                 return NT_STATUS_OK;
1027         }
1028
1029         if (!((errno == ENOTEMPTY) || (errno == EEXIST))) {
1030                 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
1031                          "%s\n", smb_fname_str_dbg(smb_dname),
1032                          strerror(errno)));
1033                 TALLOC_FREE(parent_fname);
1034                 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         if (!lp_delete_veto_files(SNUM(conn))) {
1045                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1046                 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         status = OpenDir(talloc_tos(),
1055                          conn,
1056                          smb_dname,
1057                          NULL,
1058                          0,
1059                          &dir_hnd);
1060         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                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1067                 goto err;
1068         }
1069
1070         dirfsp = dir_hnd_fetch_fsp(dir_hnd);
1071
1072         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
1073                 struct smb_filename *smb_dname_full = NULL;
1074                 struct smb_filename *direntry_fname = NULL;
1075                 char *fullname = NULL;
1076                 int retval;
1077
1078                 if (ISDOT(dname) || ISDOTDOT(dname)) {
1079                         TALLOC_FREE(talloced);
1080                         continue;
1081                 }
1082                 if (IS_VETO_PATH(conn, dname)) {
1083                         TALLOC_FREE(talloced);
1084                         continue;
1085                 }
1086
1087                 fullname = talloc_asprintf(talloc_tos(),
1088                                            "%s/%s",
1089                                            smb_dname->base_name,
1090                                            dname);
1091
1092                 if (fullname == NULL) {
1093                         TALLOC_FREE(talloced);
1094                         status = NT_STATUS_NO_MEMORY;
1095                         goto err;
1096                 }
1097
1098                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1099                                                      fullname,
1100                                                      NULL,
1101                                                      NULL,
1102                                                      smb_dname->twrp,
1103                                                      smb_dname->flags);
1104                 if (smb_dname_full == NULL) {
1105                         TALLOC_FREE(talloced);
1106                         TALLOC_FREE(fullname);
1107                         status = NT_STATUS_NO_MEMORY;
1108                         goto err;
1109                 }
1110
1111                 retval = SMB_VFS_LSTAT(conn, smb_dname_full);
1112                 if (retval != 0) {
1113                         status = map_nt_error_from_unix(errno);
1114                         TALLOC_FREE(talloced);
1115                         TALLOC_FREE(fullname);
1116                         TALLOC_FREE(smb_dname_full);
1117                         goto err;
1118                 }
1119
1120                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1121                         /* Could it be an msdfs link ? */
1122                         if (lp_host_msdfs() &&
1123                             lp_msdfs_root(SNUM(conn))) {
1124                                 struct smb_filename *smb_atname;
1125                                 smb_atname = synthetic_smb_fname(talloc_tos(),
1126                                                         dname,
1127                                                         NULL,
1128                                                         &smb_dname_full->st,
1129                                                         fsp->fsp_name->twrp,
1130                                                         fsp->fsp_name->flags);
1131                                 if (smb_atname == NULL) {
1132                                         TALLOC_FREE(talloced);
1133                                         TALLOC_FREE(fullname);
1134                                         TALLOC_FREE(smb_dname_full);
1135                                         status = NT_STATUS_NO_MEMORY;
1136                                         goto err;
1137                                 }
1138                                 if (is_msdfs_link(fsp, smb_atname)) {
1139                                         TALLOC_FREE(talloced);
1140                                         TALLOC_FREE(fullname);
1141                                         TALLOC_FREE(smb_dname_full);
1142                                         TALLOC_FREE(smb_atname);
1143                                         DBG_DEBUG("got msdfs link name %s "
1144                                                 "- can't delete directory %s\n",
1145                                                 dname,
1146                                                 fsp_str_dbg(fsp));
1147                                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1148                                         goto err;
1149                                 }
1150                                 TALLOC_FREE(smb_atname);
1151                         }
1152
1153                         /* Not a DFS link - could it be a dangling symlink ? */
1154                         retval = SMB_VFS_STAT(conn, smb_dname_full);
1155                         if (retval == -1 && (errno == ENOENT || errno == ELOOP)) {
1156                                 /*
1157                                  * Dangling symlink.
1158                                  * Allow delete as "delete veto files = yes"
1159                                  */
1160                                 TALLOC_FREE(talloced);
1161                                 TALLOC_FREE(fullname);
1162                                 TALLOC_FREE(smb_dname_full);
1163                                 continue;
1164                         }
1165
1166                         DBG_DEBUG("got symlink name %s - "
1167                                 "can't delete directory %s\n",
1168                                 dname,
1169                                 fsp_str_dbg(fsp));
1170                         TALLOC_FREE(talloced);
1171                         TALLOC_FREE(fullname);
1172                         TALLOC_FREE(smb_dname_full);
1173                         status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1174                         goto err;
1175                 }
1176
1177                 /* Not a symlink, get a pathref. */
1178                 status = synthetic_pathref(talloc_tos(),
1179                                            dirfsp,
1180                                            dname,
1181                                            NULL,
1182                                            &smb_dname_full->st,
1183                                            smb_dname->twrp,
1184                                            smb_dname->flags,
1185                                            &direntry_fname);
1186                 if (!NT_STATUS_IS_OK(status)) {
1187                         TALLOC_FREE(talloced);
1188                         TALLOC_FREE(fullname);
1189                         TALLOC_FREE(smb_dname_full);
1190                         goto err;
1191                 }
1192
1193                 if (!is_visible_fsp(direntry_fname->fsp)) {
1194                         TALLOC_FREE(talloced);
1195                         TALLOC_FREE(fullname);
1196                         TALLOC_FREE(smb_dname_full);
1197                         TALLOC_FREE(direntry_fname);
1198                         continue;
1199                 }
1200
1201                 /*
1202                  * We found a client visible name.
1203                  * We cannot delete this directory.
1204                  */
1205                 DBG_DEBUG("got name %s - "
1206                         "can't delete directory %s\n",
1207                         dname,
1208                         fsp_str_dbg(fsp));
1209                 TALLOC_FREE(talloced);
1210                 TALLOC_FREE(fullname);
1211                 TALLOC_FREE(smb_dname_full);
1212                 TALLOC_FREE(direntry_fname);
1213                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1214                 goto err;
1215         }
1216
1217         /* Do a recursive delete. */
1218         RewindDir(dir_hnd,&dirpos);
1219
1220         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) {
1221                 struct smb_filename *direntry_fname = NULL;
1222                 struct smb_filename *smb_dname_full = NULL;
1223                 char *fullname = NULL;
1224                 bool do_break = true;
1225                 int retval;
1226
1227                 if (ISDOT(dname) || ISDOTDOT(dname)) {
1228                         TALLOC_FREE(talloced);
1229                         continue;
1230                 }
1231
1232                 fullname = talloc_asprintf(ctx,
1233                                            "%s/%s",
1234                                            smb_dname->base_name,
1235                                            dname);
1236
1237                 if (fullname == NULL) {
1238                         status = NT_STATUS_NO_MEMORY;
1239                         goto err_break;
1240                 }
1241
1242                 smb_dname_full = synthetic_smb_fname(talloc_tos(),
1243                                                      fullname,
1244                                                      NULL,
1245                                                      NULL,
1246                                                      smb_dname->twrp,
1247                                                      smb_dname->flags);
1248                 if (smb_dname_full == NULL) {
1249                         status = NT_STATUS_NO_MEMORY;
1250                         goto err_break;
1251                 }
1252
1253                 /*
1254                  * Todo: use SMB_VFS_STATX() once that's available.
1255                  */
1256
1257                 retval = SMB_VFS_LSTAT(conn, smb_dname_full);
1258                 if (retval != 0) {
1259                         status = map_nt_error_from_unix(errno);
1260                         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                 if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1270                         direntry_fname = synthetic_smb_fname(talloc_tos(),
1271                                                         dname,
1272                                                         NULL,
1273                                                         &smb_dname_full->st,
1274                                                         smb_dname->twrp,
1275                                                         smb_dname->flags);
1276                         if (direntry_fname == NULL) {
1277                                 status = NT_STATUS_NO_MEMORY;
1278                                 goto err_break;
1279                         }
1280                 } else {
1281                         status = synthetic_pathref(talloc_tos(),
1282                                                    dirfsp,
1283                                                    dname,
1284                                                    NULL,
1285                                                    &smb_dname_full->st,
1286                                                    smb_dname->twrp,
1287                                                    smb_dname->flags,
1288                                                    &direntry_fname);
1289                         if (!NT_STATUS_IS_OK(status)) {
1290                                 goto err_break;
1291                         }
1292
1293                         if (!is_visible_fsp(direntry_fname->fsp)) {
1294                                 TALLOC_FREE(fullname);
1295                                 TALLOC_FREE(smb_dname_full);
1296                                 TALLOC_FREE(talloced);
1297                                 TALLOC_FREE(direntry_fname);
1298                                 continue;
1299                         }
1300                 }
1301
1302                 unlink_flags = 0;
1303
1304                 if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
1305                         status = recursive_rmdir(ctx, conn, smb_dname_full);
1306                         if (!NT_STATUS_IS_OK(status)) {
1307                                 goto err_break;
1308                         }
1309                         unlink_flags = AT_REMOVEDIR;
1310                 }
1311
1312                 retval = SMB_VFS_UNLINKAT(conn,
1313                                           dirfsp,
1314                                           direntry_fname,
1315                                           unlink_flags);
1316                 if (retval != 0) {
1317                         status = map_nt_error_from_unix(errno);
1318                         goto err_break;
1319                 }
1320
1321                 /* Successful iteration. */
1322                 do_break = false;
1323
1324         err_break:
1325                 TALLOC_FREE(fullname);
1326                 TALLOC_FREE(smb_dname_full);
1327                 TALLOC_FREE(talloced);
1328                 TALLOC_FREE(direntry_fname);
1329                 if (do_break) {
1330                         break;
1331                 }
1332         }
1333
1334         /* If we get here, we know NT_STATUS_IS_OK(status) */
1335         SMB_ASSERT(NT_STATUS_IS_OK(status));
1336
1337         /* Retry the rmdir */
1338         ret = SMB_VFS_UNLINKAT(conn,
1339                                parent_fname->fsp,
1340                                at_fname,
1341                                AT_REMOVEDIR);
1342         if (ret != 0) {
1343                 status = map_nt_error_from_unix(errno);
1344         }
1345
1346   err:
1347
1348         TALLOC_FREE(dir_hnd);
1349         TALLOC_FREE(parent_fname);
1350
1351         if (!NT_STATUS_IS_OK(status)) {
1352                 DBG_NOTICE("couldn't remove directory %s : "
1353                          "%s\n", smb_fname_str_dbg(smb_dname),
1354                          nt_errstr(status));
1355                 return status;
1356         }
1357
1358         notify_fname(conn, NOTIFY_ACTION_REMOVED,
1359                      FILE_NOTIFY_CHANGE_DIR_NAME,
1360                      smb_dname->base_name);
1361
1362         return status;
1363 }
1364
1365 /****************************************************************************
1366  Close a directory opened by an NT SMB call. 
1367 ****************************************************************************/
1368   
1369 static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
1370                                 enum file_close_type close_type)
1371 {
1372         struct share_mode_lock *lck = NULL;
1373         bool delete_dir = False;
1374         NTSTATUS status = NT_STATUS_OK;
1375         NTSTATUS status1 = NT_STATUS_OK;
1376         const struct security_token *del_nt_token = NULL;
1377         const struct security_unix_token *del_token = NULL;
1378         NTSTATUS notify_status;
1379
1380         SMB_ASSERT(fsp->fsp_flags.is_fsa);
1381
1382         if (fsp->conn->sconn->using_smb2) {
1383                 notify_status = NT_STATUS_NOTIFY_CLEANUP;
1384         } else {
1385                 notify_status = NT_STATUS_OK;
1386         }
1387
1388         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         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1396         if (lck == NULL) {
1397                 DEBUG(0, ("close_directory: Could not get share mode lock for "
1398                           "%s\n", fsp_str_dbg(fsp)));
1399                 return NT_STATUS_INVALID_PARAMETER;
1400         }
1401
1402         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                 send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
1408                                                fsp->fsp_name->base_name);
1409                 set_delete_on_close_lck(fsp, lck,
1410                                         fsp->conn->session_info->security_token,
1411                                         fsp->conn->session_info->unix_token);
1412                 fsp->fsp_flags.delete_on_close = true;
1413         }
1414
1415         delete_dir = get_delete_on_close_token(
1416                 lck, fsp->name_hash, &del_nt_token, &del_token) &&
1417                 !has_other_nonposix_opens(lck, fsp);
1418
1419         if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
1420                                 delete_dir) {
1421         
1422                 /* Become the user who requested the delete. */
1423
1424                 if (!push_sec_ctx()) {
1425                         smb_panic("close_directory: failed to push sec_ctx.\n");
1426                 }
1427
1428                 set_sec_ctx(del_token->uid,
1429                                 del_token->gid,
1430                                 del_token->ngroups,
1431                                 del_token->groups,
1432                                 del_nt_token);
1433
1434                 if (!del_share_mode(lck, fsp)) {
1435                         DEBUG(0, ("close_directory: Could not delete share entry for "
1436                                   "%s\n", fsp_str_dbg(fsp)));
1437                 }
1438
1439                 TALLOC_FREE(lck);
1440
1441                 if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
1442                     && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {
1443
1444                         status = delete_all_streams(fsp->conn, fsp->fsp_name);
1445                         if (!NT_STATUS_IS_OK(status)) {
1446                                 DEBUG(5, ("delete_all_streams failed: %s\n",
1447                                           nt_errstr(status)));
1448                                 /* unbecome user. */
1449                                 pop_sec_ctx();
1450                                 return status;
1451                         }
1452                 }
1453
1454                 status = rmdir_internals(talloc_tos(), fsp);
1455
1456                 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                 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                 if (NT_STATUS_IS_OK(status)) {
1469                         notify_status = NT_STATUS_DELETE_PENDING;
1470                 }
1471         } else {
1472                 if (!del_share_mode(lck, fsp)) {
1473                         DEBUG(0, ("close_directory: Could not delete share entry for "
1474                                   "%s\n", fsp_str_dbg(fsp)));
1475                 }
1476
1477                 TALLOC_FREE(lck);
1478         }
1479
1480         remove_pending_change_notify_requests_by_fid(fsp, notify_status);
1481
1482         status1 = fd_close(fsp);
1483
1484         if (!NT_STATUS_IS_OK(status1)) {
1485                 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         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
1491                 status = status1;
1492         }
1493         return status;
1494 }
1495
1496 /****************************************************************************
1497  Rundown all SMB-related dependencies of a files struct
1498 ****************************************************************************/
1499   
1500 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         SMB_ASSERT(!fsp->fsp_flags.is_dirfsp);
1511
1512         /*
1513          * Never call directly on a base fsp
1514          */
1515         SMB_ASSERT(fsp->stream_fsp == NULL);
1516
1517         if (fsp->fake_file_handle != NULL) {
1518                 status = close_fake_file(req, fsp);
1519         } else if (fsp->print_file != NULL) {
1520                 /* FIXME: return spool errors */
1521                 print_spool_end(fsp, close_type);
1522                 fd_close(fsp);
1523                 status = NT_STATUS_OK;
1524         } else if (!fsp->fsp_flags.is_fsa) {
1525                 if (close_type == NORMAL_CLOSE) {
1526                         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                 SMB_ASSERT(close_type != NORMAL_CLOSE);
1534                 fd_close(fsp);
1535                 status = NT_STATUS_OK;
1536         } else if (fsp->fsp_flags.is_directory) {
1537                 status = close_directory(req, fsp, close_type);
1538         } else {
1539                 status = close_normal_file(req, fsp, close_type);
1540         }
1541
1542         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                 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                 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
1553
1554                 /*
1555                  * Make base_fsp look standalone now
1556                  */
1557                 fsp->base_fsp->stream_fsp = NULL;
1558
1559                 close_file_free(req, &fsp->base_fsp, close_type);
1560         }
1561
1562         fsp_unbind_smb(req, fsp);
1563
1564         return status;
1565 }
1566
1567 NTSTATUS close_file_free(struct smb_request *req,
1568                          struct files_struct **_fsp,
1569                          enum file_close_type close_type)
1570 {
1571         struct files_struct *fsp = *_fsp;
1572         NTSTATUS status;
1573
1574         status = close_file_smb(req, fsp, close_type);
1575
1576         file_free(req, fsp);
1577         *_fsp = NULL;
1578
1579         return status;
1580 }
1581
1582 /****************************************************************************
1583  Deal with an (authorized) message to close a file given the share mode
1584  entry.
1585 ****************************************************************************/
1586
1587 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         files_struct *fsp = NULL;
1594         struct file_id id;
1595         struct share_mode_entry e;
1596         struct smbd_server_connection *sconn =
1597                 talloc_get_type_abort(private_data,
1598                 struct smbd_server_connection);
1599
1600         message_to_share_mode_entry(&id, &e, (char *)data->data);
1601
1602         if(DEBUGLVL(10)) {
1603                 char *sm_str = share_mode_str(NULL, 0, &id, &e);
1604                 if (!sm_str) {
1605                         smb_panic("talloc failed");
1606                 }
1607                 DEBUG(10,("msg_close_file: got request to close share mode "
1608                         "entry %s\n", sm_str));
1609                 TALLOC_FREE(sm_str);
1610         }
1611
1612         fsp = file_find_dif(sconn, id, e.share_file_id);
1613         if (!fsp) {
1614                 DEBUG(10,("msg_close_file: failed to find file.\n"));
1615                 return;
1616         }
1617         close_file_free(NULL, &fsp, NORMAL_CLOSE);
1618 }