Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Directory handling routines
4 : Copyright (C) Andrew Tridgell 1992-1998
5 : Copyright (C) Jeremy Allison 2007
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "system/filesys.h"
23 : #include "locking/share_mode_lock.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "libcli/security/security.h"
27 : #include "lib/util/bitmap.h"
28 : #include "../lib/util/memcache.h"
29 : #include "../librpc/gen_ndr/open_files.h"
30 : #include "lib/util/string_wrappers.h"
31 : #include "libcli/smb/reparse.h"
32 : #include "source3/smbd/dir.h"
33 :
34 : /*
35 : This module implements directory related functions for Samba.
36 : */
37 :
38 : /* "Special" directory offsets. */
39 : #define END_OF_DIRECTORY_OFFSET ((long)-1)
40 : #define START_OF_DIRECTORY_OFFSET ((long)0)
41 : #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
42 :
43 : /* Make directory handle internals available. */
44 :
45 : struct smb_Dir {
46 : connection_struct *conn;
47 : DIR *dir;
48 : struct smb_filename *dir_smb_fname;
49 : unsigned int file_number;
50 : bool case_sensitive;
51 : files_struct *fsp; /* Back pointer to containing fsp, only
52 : set from OpenDir_fsp(). */
53 : };
54 :
55 : struct dptr_struct {
56 : struct dptr_struct *next, *prev;
57 : int dnum;
58 : struct smb_Dir *dir_hnd;
59 : char *wcard;
60 : uint32_t attr;
61 : bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
62 : bool did_stat; /* Optimisation for non-wcard searches. */
63 : bool priv; /* Directory handle opened with privilege. */
64 : uint32_t counter;
65 :
66 : char *last_name_sent; /* for name-based trans2 resume */
67 :
68 : struct {
69 : char *fname;
70 : struct smb_filename *smb_fname;
71 : uint32_t mode;
72 : } overflow;
73 : };
74 :
75 : static NTSTATUS OpenDir_fsp(
76 : TALLOC_CTX *mem_ctx,
77 : connection_struct *conn,
78 : files_struct *fsp,
79 : const char *mask,
80 : uint32_t attr,
81 : struct smb_Dir **_dir_hnd);
82 :
83 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
84 :
85 : #define INVALID_DPTR_KEY (-3)
86 :
87 : /****************************************************************************
88 : Initialise the dir bitmap.
89 : ****************************************************************************/
90 :
91 31563 : bool init_dptrs(struct smbd_server_connection *sconn)
92 : {
93 31563 : if (sconn->searches.dptr_bmap) {
94 0 : return true;
95 : }
96 :
97 31563 : sconn->searches.dptr_bmap = bitmap_talloc(
98 : sconn, MAX_DIRECTORY_HANDLES);
99 :
100 31563 : if (sconn->searches.dptr_bmap == NULL) {
101 0 : return false;
102 : }
103 :
104 30721 : return true;
105 : }
106 :
107 : /****************************************************************************
108 : Get the struct dptr_struct for a dir index.
109 : ****************************************************************************/
110 :
111 8496 : static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
112 : int key)
113 : {
114 0 : struct dptr_struct *dptr;
115 :
116 13056 : for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
117 13048 : if(dptr->dnum != key) {
118 4560 : continue;
119 : }
120 8488 : DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
121 8488 : return dptr;
122 : }
123 8 : return(NULL);
124 : }
125 :
126 : /****************************************************************************
127 : Get the dir path for a dir index.
128 : ****************************************************************************/
129 :
130 2224 : const char *dptr_path(struct smbd_server_connection *sconn, int key)
131 : {
132 2224 : struct dptr_struct *dptr = dptr_get(sconn, key);
133 2224 : if (dptr)
134 2224 : return(dptr->dir_hnd->dir_smb_fname->base_name);
135 0 : return(NULL);
136 : }
137 :
138 : /****************************************************************************
139 : Get the dir wcard for a dir index.
140 : ****************************************************************************/
141 :
142 2168 : const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
143 : {
144 2168 : struct dptr_struct *dptr = dptr_get(sconn, key);
145 2168 : if (dptr)
146 2168 : return(dptr->wcard);
147 0 : return(NULL);
148 : }
149 :
150 : /****************************************************************************
151 : Get the dir attrib for a dir index.
152 : ****************************************************************************/
153 :
154 2048 : uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
155 : {
156 2048 : struct dptr_struct *dptr = dptr_get(sconn, key);
157 2048 : if (dptr)
158 2048 : return(dptr->attr);
159 0 : return(0);
160 : }
161 :
162 : /****************************************************************************
163 : Close all dptrs for a cnum.
164 : ****************************************************************************/
165 :
166 0 : void dptr_closecnum(connection_struct *conn)
167 : {
168 0 : struct dptr_struct *dptr, *next;
169 0 : struct smbd_server_connection *sconn = conn->sconn;
170 :
171 0 : if (sconn == NULL) {
172 0 : return;
173 : }
174 :
175 0 : for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
176 0 : next = dptr->next;
177 0 : if (dptr->dir_hnd->conn == conn) {
178 : /*
179 : * Need to make a copy, "dptr" will be gone
180 : * after close_file_free() returns
181 : */
182 0 : struct files_struct *fsp = dptr->dir_hnd->fsp;
183 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
184 : }
185 : }
186 : }
187 :
188 : /****************************************************************************
189 : Create a new dir ptr. If the flag old_handle is true then we must allocate
190 : from the bitmap range 0 - 255 as old SMBsearch directory handles are only
191 : one byte long. If old_handle is false we allocate from the range
192 : 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
193 : a directory handle is never zero.
194 : wcard must not be zero.
195 : ****************************************************************************/
196 :
197 18775 : NTSTATUS dptr_create(connection_struct *conn,
198 : struct smb_request *req,
199 : files_struct *fsp,
200 : bool old_handle,
201 : const char *wcard,
202 : uint32_t attr,
203 : struct dptr_struct **dptr_ret)
204 : {
205 18775 : struct smbd_server_connection *sconn = conn->sconn;
206 18775 : struct dptr_struct *dptr = NULL;
207 18775 : struct smb_Dir *dir_hnd = NULL;
208 176 : NTSTATUS status;
209 :
210 18775 : DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
211 :
212 18775 : if (sconn == NULL) {
213 0 : DEBUG(0,("dptr_create: called with fake connection_struct\n"));
214 0 : return NT_STATUS_INTERNAL_ERROR;
215 : }
216 :
217 18775 : if (!wcard) {
218 0 : return NT_STATUS_INVALID_PARAMETER;
219 : }
220 :
221 18775 : status = check_any_access_fsp(fsp, SEC_DIR_LIST);
222 18775 : if (!NT_STATUS_IS_OK(status)) {
223 0 : DBG_INFO("dptr_create: directory %s "
224 : "not open for LIST access\n",
225 : fsp_str_dbg(fsp));
226 0 : return status;
227 : }
228 18775 : status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
229 18775 : if (!NT_STATUS_IS_OK(status)) {
230 0 : return status;
231 : }
232 :
233 18775 : dptr = talloc_zero(NULL, struct dptr_struct);
234 18775 : if(!dptr) {
235 0 : DEBUG(0,("talloc fail in dptr_create.\n"));
236 0 : TALLOC_FREE(dir_hnd);
237 0 : return NT_STATUS_NO_MEMORY;
238 : }
239 :
240 18775 : dptr->dir_hnd = dir_hnd;
241 18775 : dptr->wcard = talloc_strdup(dptr, wcard);
242 18775 : if (!dptr->wcard) {
243 0 : TALLOC_FREE(dptr);
244 0 : TALLOC_FREE(dir_hnd);
245 0 : return NT_STATUS_NO_MEMORY;
246 : }
247 18775 : if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
248 96 : dptr->has_wild = True;
249 : } else {
250 18679 : dptr->has_wild = ms_has_wild(dptr->wcard);
251 : }
252 :
253 18775 : dptr->attr = attr;
254 :
255 18775 : if (conn_using_smb2(sconn)) {
256 10096 : goto done;
257 : }
258 :
259 8679 : if(old_handle) {
260 :
261 : /*
262 : * This is an old-style SMBsearch request. Ensure the
263 : * value we return will fit in the range 1-255.
264 : */
265 :
266 176 : dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
267 :
268 176 : if(dptr->dnum == -1 || dptr->dnum > 254) {
269 0 : DBG_ERR("returned %d: Error - all old "
270 : "dirptrs in use ?\n",
271 : dptr->dnum);
272 0 : TALLOC_FREE(dptr);
273 0 : TALLOC_FREE(dir_hnd);
274 0 : return NT_STATUS_TOO_MANY_OPENED_FILES;
275 : }
276 : } else {
277 :
278 : /*
279 : * This is a new-style trans2 request. Allocate from
280 : * a range that will return 256 - MAX_DIRECTORY_HANDLES.
281 : */
282 :
283 8503 : dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
284 :
285 8503 : if(dptr->dnum == -1 || dptr->dnum < 255) {
286 0 : DBG_ERR("returned %d: Error - all new "
287 : "dirptrs in use ?\n",
288 : dptr->dnum);
289 0 : TALLOC_FREE(dptr);
290 0 : TALLOC_FREE(dir_hnd);
291 0 : return NT_STATUS_TOO_MANY_OPENED_FILES;
292 : }
293 : }
294 :
295 8679 : bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
296 :
297 8679 : dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
298 :
299 8679 : DLIST_ADD(sconn->searches.dirptrs, dptr);
300 :
301 18775 : done:
302 18775 : DBG_INFO("creating new dirptr [%d] for path [%s]\n",
303 : dptr->dnum, fsp_str_dbg(fsp));
304 :
305 18775 : *dptr_ret = dptr;
306 :
307 18775 : return NT_STATUS_OK;
308 : }
309 :
310 :
311 : /****************************************************************************
312 : Wrapper functions to access the lower level directory handles.
313 : ****************************************************************************/
314 :
315 18775 : void dptr_CloseDir(files_struct *fsp)
316 : {
317 18775 : struct smbd_server_connection *sconn = NULL;
318 :
319 18775 : if (fsp->dptr == NULL) {
320 0 : return;
321 : }
322 18775 : sconn = fsp->conn->sconn;
323 :
324 : /*
325 : * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
326 : * now handles all resource deallocation.
327 : */
328 :
329 18775 : DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
330 :
331 18775 : if (sconn != NULL && !conn_using_smb2(sconn)) {
332 8679 : DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
333 :
334 : /*
335 : * Free the dnum in the bitmap. Remember the dnum value is
336 : * always biased by one with respect to the bitmap.
337 : */
338 :
339 8679 : if (!bitmap_query(sconn->searches.dptr_bmap,
340 8679 : fsp->dptr->dnum - 1))
341 : {
342 0 : DBG_ERR("closing dnum = %d and bitmap not set !\n",
343 : fsp->dptr->dnum);
344 : }
345 :
346 8679 : bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
347 : }
348 :
349 18775 : TALLOC_FREE(fsp->dptr->dir_hnd);
350 18775 : TALLOC_FREE(fsp->dptr);
351 : }
352 :
353 2728 : void dptr_RewindDir(struct dptr_struct *dptr)
354 : {
355 2728 : RewindDir(dptr->dir_hnd);
356 2728 : dptr->did_stat = false;
357 2728 : TALLOC_FREE(dptr->overflow.fname);
358 2728 : TALLOC_FREE(dptr->overflow.smb_fname);
359 2728 : }
360 :
361 83464 : unsigned int dptr_FileNumber(struct dptr_struct *dptr)
362 : {
363 83464 : return dptr->dir_hnd->file_number;
364 : }
365 :
366 500 : bool dptr_has_wild(struct dptr_struct *dptr)
367 : {
368 500 : return dptr->has_wild;
369 : }
370 :
371 8679 : int dptr_dnum(struct dptr_struct *dptr)
372 : {
373 8679 : return dptr->dnum;
374 : }
375 :
376 1724 : bool dptr_get_priv(struct dptr_struct *dptr)
377 : {
378 1724 : return dptr->priv;
379 : }
380 :
381 0 : void dptr_set_priv(struct dptr_struct *dptr)
382 : {
383 0 : dptr->priv = true;
384 0 : }
385 :
386 1302967 : bool dptr_case_sensitive(struct dptr_struct *dptr)
387 : {
388 1302967 : return dptr->dir_hnd->case_sensitive;
389 : }
390 :
391 : /****************************************************************************
392 : Return the next visible file name, skipping veto'd and invisible files.
393 : ****************************************************************************/
394 :
395 1336186 : char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
396 : {
397 1336186 : struct stat_ex st = {
398 : .st_ex_nlink = 0,
399 : };
400 1336186 : struct smb_Dir *dir_hnd = dptr->dir_hnd;
401 1336186 : struct files_struct *dir_fsp = dir_hnd->fsp;
402 1336186 : struct smb_filename *dir_name = dir_fsp->fsp_name;
403 404 : struct smb_filename smb_fname_base;
404 1336186 : bool retry_scanning = false;
405 404 : int ret;
406 1336186 : int flags = 0;
407 :
408 1336186 : if (dptr->has_wild) {
409 1332146 : const char *name_temp = NULL;
410 1332146 : char *talloced = NULL;
411 1332146 : name_temp = ReadDirName(dir_hnd, &talloced);
412 1332146 : if (name_temp == NULL) {
413 26444 : return NULL;
414 : }
415 1305613 : if (talloced != NULL) {
416 430 : return talloc_move(ctx, &talloced);
417 : }
418 1305183 : return talloc_strdup(ctx, name_temp);
419 : }
420 :
421 4040 : if (dptr->did_stat) {
422 : /*
423 : * No wildcard, this is not a real directory traverse
424 : * but a "stat" call behind a query_directory. We've
425 : * been here, nothing else to look at.
426 : */
427 2012 : return NULL;
428 : }
429 2028 : dptr->did_stat = true;
430 :
431 : /* Create an smb_filename with stream_name == NULL. */
432 2028 : smb_fname_base = (struct smb_filename){
433 2028 : .base_name = dptr->wcard,
434 2028 : .flags = dir_name->flags,
435 2028 : .twrp = dir_name->twrp,
436 : };
437 :
438 2028 : if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
439 6 : flags |= AT_SYMLINK_NOFOLLOW;
440 : }
441 :
442 2028 : ret = SMB_VFS_FSTATAT(
443 : dir_hnd->conn, dir_fsp, &smb_fname_base, &st, flags);
444 2028 : if (ret == 0) {
445 1712 : return talloc_strdup(ctx, dptr->wcard);
446 : }
447 :
448 : /*
449 : * If we get any other error than ENOENT or ENOTDIR
450 : * then the file exists, we just can't stat it.
451 : */
452 316 : if (errno != ENOENT && errno != ENOTDIR) {
453 0 : return talloc_strdup(ctx, dptr->wcard);
454 : }
455 :
456 : /*
457 : * A scan will find the long version of a mangled name as
458 : * wildcard.
459 : */
460 632 : retry_scanning |= mangle_is_mangled(dptr->wcard,
461 316 : dir_hnd->conn->params);
462 :
463 : /*
464 : * Also retry scanning if the client requested case
465 : * insensitive semantics and the file system does not provide
466 : * it.
467 : */
468 632 : retry_scanning |= (!dir_hnd->case_sensitive &&
469 316 : (dir_hnd->conn->fs_capabilities &
470 : FILE_CASE_SENSITIVE_SEARCH));
471 :
472 316 : if (retry_scanning) {
473 316 : char *found_name = NULL;
474 0 : NTSTATUS status;
475 :
476 316 : status = get_real_filename_at(dir_fsp,
477 316 : dptr->wcard,
478 : ctx,
479 : &found_name);
480 316 : if (NT_STATUS_IS_OK(status)) {
481 47 : return found_name;
482 : }
483 : }
484 :
485 269 : return NULL;
486 : }
487 :
488 6 : struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
489 : {
490 6 : return dir_hnd->fsp;
491 : }
492 :
493 : /****************************************************************************
494 : Fetch the fsp associated with the dptr_num.
495 : ****************************************************************************/
496 :
497 2056 : files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
498 : int dptr_num)
499 : {
500 2056 : struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
501 2056 : if (dptr == NULL) {
502 8 : return NULL;
503 : }
504 2048 : DBG_NOTICE("fetching dirptr %d for path %s\n",
505 : dptr_num,
506 : dptr->dir_hnd->dir_smb_fname->base_name);
507 2048 : return dptr->dir_hnd->fsp;
508 : }
509 :
510 944715 : bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
511 : struct dptr_struct *dirptr,
512 : const char *mask,
513 : uint32_t dirtype,
514 : bool dont_descend,
515 : bool ask_sharemode,
516 : bool get_dosmode_in,
517 : bool (*match_fn)(TALLOC_CTX *ctx,
518 : void *private_data,
519 : const char *dname,
520 : const char *mask,
521 : char **_fname),
522 : void *private_data,
523 : char **_fname,
524 : struct smb_filename **_smb_fname,
525 : uint32_t *_mode)
526 : {
527 944715 : struct smb_Dir *dir_hnd = dirptr->dir_hnd;
528 944715 : connection_struct *conn = dir_hnd->conn;
529 944715 : struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
530 944715 : bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
531 944715 : const bool toplevel = ISDOT(dir_fname->base_name);
532 316 : NTSTATUS status;
533 :
534 944715 : *_smb_fname = NULL;
535 944715 : *_mode = 0;
536 :
537 944715 : if (dirptr->overflow.smb_fname != NULL) {
538 668 : *_fname = talloc_move(ctx, &dirptr->overflow.fname);
539 668 : *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
540 668 : *_mode = dirptr->overflow.mode;
541 668 : return true;
542 : }
543 :
544 944047 : if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
545 : /*
546 : * . and .. were returned first, we're done showing
547 : * the directory as empty.
548 : */
549 0 : return false;
550 : }
551 :
552 24005 : while (true) {
553 967648 : char *dname = NULL;
554 967648 : char *fname = NULL;
555 967648 : struct smb_filename *smb_fname = NULL;
556 967648 : uint32_t mode = 0;
557 967648 : bool get_dosmode = get_dosmode_in;
558 404 : bool toplevel_dotdot;
559 404 : bool visible;
560 404 : bool ok;
561 :
562 967648 : dname = dptr_ReadDirName(ctx, dirptr);
563 :
564 967648 : DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
565 : "dname [%s]\n",
566 : smb_fname_str_dbg(dir_fname),
567 : dirptr,
568 : dir_hnd->file_number,
569 : dname ? dname : "(finished)");
570 :
571 967648 : if (dname == NULL) {
572 944047 : return false;
573 : }
574 :
575 939878 : if (IS_VETO_PATH(conn, dname)) {
576 6 : TALLOC_FREE(dname);
577 23601 : continue;
578 : }
579 :
580 : /*
581 : * fname may get mangled, dname is never mangled.
582 : * Whenever we're accessing the filesystem we use
583 : * pathreal which is composed from dname.
584 : */
585 :
586 939872 : ok = match_fn(ctx, private_data, dname, mask, &fname);
587 939872 : if (!ok) {
588 6525 : TALLOC_FREE(dname);
589 6525 : continue;
590 : }
591 :
592 933347 : toplevel_dotdot = toplevel && ISDOTDOT(dname);
593 :
594 933662 : smb_fname = synthetic_smb_fname(talloc_tos(),
595 : toplevel_dotdot ? "." : dname,
596 : NULL,
597 : NULL,
598 : dir_fname->twrp,
599 : dir_fname->flags);
600 933347 : if (smb_fname == NULL) {
601 0 : TALLOC_FREE(dname);
602 0 : return false;
603 : }
604 :
605 : /*
606 : * UCF_POSIX_PATHNAMES to avoid the readdir fallback
607 : * if we get raced between readdir and unlink.
608 : */
609 933347 : status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
610 : smb_fname,
611 : UCF_POSIX_PATHNAMES);
612 933347 : if (!NT_STATUS_IS_OK(status)) {
613 6 : DBG_DEBUG("Could not open %s: %s\n",
614 : dname,
615 : nt_errstr(status));
616 6 : TALLOC_FREE(smb_fname);
617 6 : TALLOC_FREE(fname);
618 6 : TALLOC_FREE(dname);
619 6 : continue;
620 : }
621 :
622 933341 : visible = is_visible_fsp(smb_fname->fsp);
623 933341 : if (!visible) {
624 32 : TALLOC_FREE(smb_fname);
625 32 : TALLOC_FREE(fname);
626 32 : TALLOC_FREE(dname);
627 32 : continue;
628 : }
629 :
630 933309 : if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
631 930567 : goto done;
632 : }
633 :
634 3114 : if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
635 372 : is_msdfs_link(dir_hnd->fsp, smb_fname))
636 : {
637 370 : DBG_INFO("Masquerading msdfs link %s as a directory\n",
638 : smb_fname->base_name);
639 :
640 370 : smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
641 370 : ~S_IFMT) |
642 : S_IFDIR;
643 :
644 370 : mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
645 370 : get_dosmode = false;
646 370 : ask_sharemode = false;
647 370 : goto done;
648 : }
649 :
650 2372 : if (posix) {
651 : /*
652 : * Posix always wants to see symlinks.
653 : */
654 52 : ask_sharemode = false;
655 52 : goto done;
656 : }
657 :
658 2320 : if (!lp_follow_symlinks(SNUM(conn))) {
659 : /*
660 : * Hide symlinks not followed
661 : */
662 0 : TALLOC_FREE(smb_fname);
663 0 : TALLOC_FREE(fname);
664 0 : TALLOC_FREE(dname);
665 0 : continue;
666 : }
667 :
668 : /*
669 : * We have to find out if it's a dangling
670 : * symlink. Use the fat logic behind
671 : * openat_pathref_fsp().
672 : */
673 :
674 : {
675 2320 : struct files_struct *fsp = smb_fname->fsp;
676 2320 : smb_fname_fsp_unlink(smb_fname);
677 2320 : fd_close(fsp);
678 2320 : file_free(NULL, fsp);
679 : }
680 :
681 2320 : status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
682 :
683 2320 : if (!NT_STATUS_IS_OK(status)) {
684 : /*
685 : * Dangling symlink. Hide.
686 : */
687 492 : TALLOC_FREE(smb_fname);
688 492 : TALLOC_FREE(fname);
689 492 : TALLOC_FREE(dname);
690 492 : continue;
691 : }
692 :
693 1828 : done:
694 932817 : if (get_dosmode) {
695 912304 : mode = fdos_mode(smb_fname->fsp);
696 912304 : smb_fname->st = smb_fname->fsp->fsp_name->st;
697 : }
698 :
699 932817 : if (!dir_check_ftype(mode, dirtype)) {
700 16540 : DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
701 : "0x%" PRIx32 "\n",
702 : fname,
703 : mode,
704 : dirtype);
705 16540 : TALLOC_FREE(smb_fname);
706 16540 : TALLOC_FREE(dname);
707 16540 : TALLOC_FREE(fname);
708 16540 : continue;
709 : }
710 :
711 916277 : if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
712 115 : struct timespec write_time_ts;
713 115 : struct file_id fileid;
714 :
715 716929 : fileid = vfs_file_id_from_sbuf(conn,
716 716929 : &smb_fname->st);
717 716929 : get_file_infos(fileid, 0, NULL, &write_time_ts);
718 716929 : if (!is_omit_timespec(&write_time_ts)) {
719 918 : update_stat_ex_mtime(&smb_fname->st,
720 : write_time_ts);
721 : }
722 : }
723 :
724 916277 : if (toplevel_dotdot) {
725 : /*
726 : * Ensure posix fileid and sids are hidden
727 : */
728 1489 : smb_fname->st.st_ex_ino = 0;
729 1489 : smb_fname->st.st_ex_dev = 0;
730 1489 : smb_fname->st.st_ex_uid = -1;
731 1489 : smb_fname->st.st_ex_gid = -1;
732 : }
733 :
734 916277 : DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
735 : mask,
736 : smb_fname_str_dbg(smb_fname),
737 : dname,
738 : fname);
739 :
740 916277 : TALLOC_FREE(dname);
741 :
742 916277 : *_smb_fname = talloc_move(ctx, &smb_fname);
743 916277 : *_fname = fname;
744 916277 : *_mode = mode;
745 :
746 916277 : return true;
747 : }
748 :
749 : return false;
750 : }
751 :
752 668 : void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
753 : char **_fname,
754 : struct smb_filename **_smb_fname,
755 : uint32_t mode)
756 : {
757 668 : SMB_ASSERT(dirptr->overflow.fname == NULL);
758 668 : SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
759 :
760 668 : dirptr->overflow.fname = talloc_move(dirptr, _fname);
761 668 : dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
762 668 : dirptr->overflow.mode = mode;
763 668 : }
764 :
765 895392 : void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
766 : char **_fname)
767 : {
768 895392 : TALLOC_FREE(dirptr->last_name_sent);
769 895392 : dirptr->last_name_sent = talloc_move(dirptr, _fname);
770 895392 : }
771 :
772 1424 : char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
773 : {
774 1424 : return dirptr->last_name_sent;
775 : }
776 :
777 : /*******************************************************************
778 : Check to see if a user can read an fsp . This is only approximate,
779 : it is used as part of the "hide unreadable" option. Don't
780 : use it for anything security sensitive.
781 : ********************************************************************/
782 :
783 118 : static bool user_can_read_fsp(struct files_struct *fsp)
784 : {
785 0 : NTSTATUS status;
786 118 : uint32_t rejected_share_access = 0;
787 118 : uint32_t rejected_mask = 0;
788 118 : struct security_descriptor *sd = NULL;
789 118 : uint32_t access_mask = FILE_READ_DATA|
790 : FILE_READ_EA|
791 : FILE_READ_ATTRIBUTES|
792 : SEC_STD_READ_CONTROL;
793 :
794 : /*
795 : * Never hide files from the root user.
796 : * We use (uid_t)0 here not sec_initial_uid()
797 : * as make test uses a single user context.
798 : */
799 :
800 118 : if (get_current_uid(fsp->conn) == (uid_t)0) {
801 0 : return true;
802 : }
803 :
804 : /*
805 : * We can't directly use smbd_check_access_rights_fsp()
806 : * here, as this implicitly grants FILE_READ_ATTRIBUTES
807 : * which the Windows access-based-enumeration code
808 : * explicitly checks for on the file security descriptor.
809 : * See bug:
810 : *
811 : * https://bugzilla.samba.org/show_bug.cgi?id=10252
812 : *
813 : * and the smb2.acl2.ACCESSBASED test for details.
814 : */
815 :
816 118 : rejected_share_access = access_mask & ~(fsp->conn->share_access);
817 118 : if (rejected_share_access) {
818 0 : DBG_DEBUG("rejected share access 0x%x "
819 : "on %s (0x%x)\n",
820 : (unsigned int)access_mask,
821 : fsp_str_dbg(fsp),
822 : (unsigned int)rejected_share_access);
823 0 : return false;
824 : }
825 :
826 118 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
827 : (SECINFO_OWNER |
828 : SECINFO_GROUP |
829 : SECINFO_DACL),
830 : talloc_tos(),
831 : &sd);
832 :
833 118 : if (!NT_STATUS_IS_OK(status)) {
834 0 : DBG_DEBUG("Could not get acl "
835 : "on %s: %s\n",
836 : fsp_str_dbg(fsp),
837 : nt_errstr(status));
838 0 : return false;
839 : }
840 :
841 118 : status = se_file_access_check(sd,
842 118 : get_current_nttok(fsp->conn),
843 : false,
844 : access_mask,
845 : &rejected_mask);
846 :
847 118 : TALLOC_FREE(sd);
848 :
849 118 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
850 14 : DBG_DEBUG("rejected bits 0x%x read access for %s\n",
851 : (unsigned int)rejected_mask,
852 : fsp_str_dbg(fsp));
853 14 : return false;
854 : }
855 104 : return true;
856 : }
857 :
858 : /*******************************************************************
859 : Check to see if a user can write to an fsp.
860 : Always return true for directories.
861 : This is only approximate,
862 : it is used as part of the "hide unwriteable" option. Don't
863 : use it for anything security sensitive.
864 : ********************************************************************/
865 :
866 110 : static bool user_can_write_fsp(struct files_struct *fsp)
867 : {
868 : /*
869 : * Never hide files from the root user.
870 : * We use (uid_t)0 here not sec_initial_uid()
871 : * as make test uses a single user context.
872 : */
873 :
874 110 : if (get_current_uid(fsp->conn) == (uid_t)0) {
875 0 : return true;
876 : }
877 :
878 110 : if (fsp->fsp_flags.is_directory) {
879 18 : return true;
880 : }
881 :
882 92 : return can_write_to_fsp(fsp);
883 : }
884 :
885 : /*******************************************************************
886 : Is a file a "special" type ?
887 : ********************************************************************/
888 :
889 0 : static bool file_is_special(connection_struct *conn,
890 : const struct smb_filename *smb_fname)
891 : {
892 : /*
893 : * Never hide files from the root user.
894 : * We use (uid_t)0 here not sec_initial_uid()
895 : * as make test uses a single user context.
896 : */
897 :
898 0 : if (get_current_uid(conn) == (uid_t)0) {
899 0 : return False;
900 : }
901 :
902 0 : SMB_ASSERT(VALID_STAT(smb_fname->st));
903 :
904 0 : if (S_ISREG(smb_fname->st.st_ex_mode) ||
905 0 : S_ISDIR(smb_fname->st.st_ex_mode) ||
906 0 : S_ISLNK(smb_fname->st.st_ex_mode))
907 0 : return False;
908 :
909 0 : return True;
910 : }
911 :
912 : /*******************************************************************
913 : Should the file be seen by the client?
914 : ********************************************************************/
915 :
916 933489 : bool is_visible_fsp(struct files_struct *fsp)
917 : {
918 933489 : bool hide_unreadable = false;
919 933489 : bool hide_unwriteable = false;
920 933489 : bool hide_special = false;
921 933489 : int hide_new_files_timeout = 0;
922 933489 : const char *last_component = NULL;
923 :
924 : /*
925 : * If the file does not exist, there's no point checking
926 : * the configuration options. We succeed, on the basis that the
927 : * checks *might* have passed if the file was present.
928 : */
929 933489 : if (fsp == NULL) {
930 0 : return true;
931 : }
932 :
933 933489 : hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
934 933489 : hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
935 933489 : hide_special = lp_hide_special_files(SNUM(fsp->conn));
936 933489 : hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
937 :
938 933489 : if (!hide_unreadable &&
939 932998 : !hide_unwriteable &&
940 933189 : !hide_special &&
941 321 : (hide_new_files_timeout == 0))
942 : {
943 932476 : return true;
944 : }
945 :
946 692 : fsp = metadata_fsp(fsp);
947 :
948 : /* Get the last component of the base name. */
949 692 : last_component = strrchr_m(fsp->fsp_name->base_name, '/');
950 692 : if (!last_component) {
951 620 : last_component = fsp->fsp_name->base_name;
952 : } else {
953 72 : last_component++; /* Go past '/' */
954 : }
955 :
956 692 : if (ISDOT(last_component) || ISDOTDOT(last_component)) {
957 100 : return true; /* . and .. are always visible. */
958 : }
959 :
960 592 : if (fsp_get_pathref_fd(fsp) == -1) {
961 : /*
962 : * Symlink in POSIX mode or MS-DFS.
963 : * We've checked veto files so the
964 : * only thing we can check is the
965 : * hide_new_files_timeout.
966 : */
967 7 : if ((hide_new_files_timeout != 0) &&
968 7 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
969 0 : double age = timespec_elapsed(
970 0 : &fsp->fsp_name->st.st_ex_mtime);
971 :
972 0 : if (age < (double)hide_new_files_timeout) {
973 0 : return false;
974 : }
975 : }
976 7 : return true;
977 : }
978 :
979 : /* Honour _hide unreadable_ option */
980 585 : if (hide_unreadable && !user_can_read_fsp(fsp)) {
981 14 : DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
982 14 : return false;
983 : }
984 :
985 : /* Honour _hide unwriteable_ option */
986 571 : if (hide_unwriteable && !user_can_write_fsp(fsp)) {
987 12 : DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
988 12 : return false;
989 : }
990 :
991 : /* Honour _hide_special_ option */
992 559 : if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
993 0 : DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
994 0 : return false;
995 : }
996 :
997 559 : if ((hide_new_files_timeout != 0) &&
998 357 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
999 12 : double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1000 :
1001 12 : if (age < (double)hide_new_files_timeout) {
1002 10 : return false;
1003 : }
1004 : }
1005 :
1006 549 : return true;
1007 : }
1008 :
1009 305490 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1010 : {
1011 305490 : files_struct *fsp = dir_hnd->fsp;
1012 :
1013 305490 : SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1014 305490 : fsp_set_fd(fsp, -1);
1015 305490 : if (fsp->dptr != NULL) {
1016 18775 : SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1017 18775 : fsp->dptr->dir_hnd = NULL;
1018 : }
1019 305490 : dir_hnd->fsp = NULL;
1020 305490 : return 0;
1021 : }
1022 :
1023 : /*******************************************************************
1024 : Open a directory.
1025 : ********************************************************************/
1026 :
1027 286715 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1028 : {
1029 286715 : files_struct *fsp = dir_hnd->fsp;
1030 :
1031 286715 : smb_Dir_destructor(dir_hnd);
1032 286715 : file_free(NULL, fsp);
1033 286715 : return 0;
1034 : }
1035 :
1036 13167 : NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1037 : connection_struct *conn,
1038 : const struct smb_filename *smb_dname,
1039 : const char *mask,
1040 : uint32_t attr,
1041 : struct smb_Dir **_dir_hnd)
1042 : {
1043 13167 : struct files_struct *fsp = NULL;
1044 13167 : struct smb_Dir *dir_hnd = NULL;
1045 74 : NTSTATUS status;
1046 :
1047 13167 : status = open_internal_dirfsp(conn,
1048 : smb_dname,
1049 : O_RDONLY,
1050 : &fsp);
1051 13167 : if (!NT_STATUS_IS_OK(status)) {
1052 0 : return status;
1053 : }
1054 :
1055 13167 : status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1056 13167 : if (!NT_STATUS_IS_OK(status)) {
1057 0 : return status;
1058 : }
1059 :
1060 : /*
1061 : * This overwrites the destructor set by OpenDir_fsp() but
1062 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1063 : * destructor.
1064 : */
1065 13167 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1066 :
1067 13167 : *_dir_hnd = dir_hnd;
1068 13167 : return NT_STATUS_OK;
1069 : }
1070 :
1071 273549 : NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1072 : struct files_struct *dirfsp,
1073 : const char *mask,
1074 : uint32_t attr,
1075 : struct smb_Dir **_dir_hnd)
1076 : {
1077 273549 : struct files_struct *fsp = NULL;
1078 273549 : struct smb_Dir *dir_hnd = NULL;
1079 883 : NTSTATUS status;
1080 :
1081 273549 : status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1082 273549 : if (!NT_STATUS_IS_OK(status)) {
1083 1 : return status;
1084 : }
1085 :
1086 273548 : status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1087 273548 : if (!NT_STATUS_IS_OK(status)) {
1088 0 : return status;
1089 : }
1090 :
1091 : /*
1092 : * This overwrites the destructor set by OpenDir_fsp() but
1093 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1094 : * destructor.
1095 : */
1096 273548 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1097 :
1098 273548 : *_dir_hnd = dir_hnd;
1099 273548 : return NT_STATUS_OK;
1100 : }
1101 :
1102 : /*******************************************************************
1103 : Open a directory from an fsp.
1104 : ********************************************************************/
1105 :
1106 305490 : static NTSTATUS OpenDir_fsp(
1107 : TALLOC_CTX *mem_ctx,
1108 : connection_struct *conn,
1109 : files_struct *fsp,
1110 : const char *mask,
1111 : uint32_t attr,
1112 : struct smb_Dir **_dir_hnd)
1113 : {
1114 305490 : struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1115 1133 : NTSTATUS status;
1116 :
1117 305490 : if (!dir_hnd) {
1118 0 : return NT_STATUS_NO_MEMORY;
1119 : }
1120 :
1121 305490 : if (!fsp->fsp_flags.is_directory) {
1122 0 : status = NT_STATUS_INVALID_HANDLE;
1123 0 : goto fail;
1124 : }
1125 :
1126 305490 : if (fsp_get_io_fd(fsp) == -1) {
1127 0 : status = NT_STATUS_INVALID_HANDLE;
1128 0 : goto fail;
1129 : }
1130 :
1131 305490 : dir_hnd->conn = conn;
1132 :
1133 305490 : dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1134 305490 : if (!dir_hnd->dir_smb_fname) {
1135 0 : status = NT_STATUS_NO_MEMORY;
1136 0 : goto fail;
1137 : }
1138 :
1139 305490 : dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1140 305490 : if (dir_hnd->dir == NULL) {
1141 0 : status = map_nt_error_from_unix(errno);
1142 0 : goto fail;
1143 : }
1144 305490 : dir_hnd->fsp = fsp;
1145 305490 : if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1146 12 : dir_hnd->case_sensitive = true;
1147 : } else {
1148 305478 : dir_hnd->case_sensitive = conn->case_sensitive;
1149 : }
1150 :
1151 305490 : talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1152 :
1153 305490 : *_dir_hnd = dir_hnd;
1154 305490 : return NT_STATUS_OK;
1155 :
1156 0 : fail:
1157 0 : TALLOC_FREE(dir_hnd);
1158 0 : return status;
1159 : }
1160 :
1161 :
1162 : /*******************************************************************
1163 : Read from a directory.
1164 : Return directory entry, current offset, and optional stat information.
1165 : Don't check for veto or invisible files.
1166 : ********************************************************************/
1167 :
1168 161016211 : const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
1169 : {
1170 7211 : const char *n;
1171 161016211 : char *talloced = NULL;
1172 161016211 : connection_struct *conn = dir_hnd->conn;
1173 :
1174 161016211 : if (dir_hnd->file_number < 2) {
1175 612338 : if (dir_hnd->file_number == 0) {
1176 305126 : n = ".";
1177 : } else {
1178 306166 : n = "..";
1179 : }
1180 612338 : dir_hnd->file_number++;
1181 612338 : *ptalloced = NULL;
1182 612338 : return n;
1183 : }
1184 :
1185 321402702 : while ((n = vfs_readdirname(conn,
1186 161003948 : dir_hnd->fsp,
1187 : dir_hnd->dir,
1188 : &talloced))) {
1189 : /* Ignore . and .. - we've already returned them. */
1190 160697064 : if (ISDOT(n) || ISDOTDOT(n)) {
1191 600075 : TALLOC_FREE(talloced);
1192 600075 : continue;
1193 : }
1194 160096989 : *ptalloced = talloced;
1195 160096989 : dir_hnd->file_number++;
1196 160096989 : return n;
1197 : }
1198 306884 : *ptalloced = NULL;
1199 306884 : return NULL;
1200 : }
1201 :
1202 : /*******************************************************************
1203 : Rewind to the start.
1204 : ********************************************************************/
1205 :
1206 2732 : void RewindDir(struct smb_Dir *dir_hnd)
1207 : {
1208 2732 : SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1209 2732 : dir_hnd->file_number = 0;
1210 2732 : }
1211 :
1212 : struct files_below_forall_state {
1213 : char *dirpath;
1214 : ssize_t dirpath_len;
1215 : int (*fn)(struct file_id fid, const struct share_mode_data *data,
1216 : void *private_data);
1217 : void *private_data;
1218 : };
1219 :
1220 18759 : static int files_below_forall_fn(struct file_id fid,
1221 : const struct share_mode_data *data,
1222 : void *private_data)
1223 : {
1224 18759 : struct files_below_forall_state *state = private_data;
1225 0 : char tmpbuf[PATH_MAX];
1226 0 : char *fullpath, *to_free;
1227 0 : ssize_t len;
1228 :
1229 18759 : len = full_path_tos(data->servicepath, data->base_name,
1230 : tmpbuf, sizeof(tmpbuf),
1231 : &fullpath, &to_free);
1232 18759 : if (len == -1) {
1233 0 : return 0;
1234 : }
1235 18759 : if (state->dirpath_len >= len) {
1236 : /*
1237 : * Filter files above dirpath
1238 : */
1239 16453 : goto out;
1240 : }
1241 2306 : if (fullpath[state->dirpath_len] != '/') {
1242 : /*
1243 : * Filter file that don't have a path separator at the end of
1244 : * dirpath's length
1245 : */
1246 2252 : goto out;
1247 : }
1248 :
1249 54 : if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1250 : /*
1251 : * Not a parent
1252 : */
1253 42 : goto out;
1254 : }
1255 :
1256 12 : TALLOC_FREE(to_free);
1257 12 : return state->fn(fid, data, state->private_data);
1258 :
1259 18747 : out:
1260 18747 : TALLOC_FREE(to_free);
1261 18747 : return 0;
1262 : }
1263 :
1264 6299 : static int files_below_forall(connection_struct *conn,
1265 : const struct smb_filename *dir_name,
1266 : int (*fn)(struct file_id fid,
1267 : const struct share_mode_data *data,
1268 : void *private_data),
1269 : void *private_data)
1270 : {
1271 6299 : struct files_below_forall_state state = {
1272 : .fn = fn,
1273 : .private_data = private_data,
1274 : };
1275 0 : int ret;
1276 0 : char tmpbuf[PATH_MAX];
1277 0 : char *to_free;
1278 :
1279 12598 : state.dirpath_len = full_path_tos(conn->connectpath,
1280 6299 : dir_name->base_name,
1281 : tmpbuf, sizeof(tmpbuf),
1282 : &state.dirpath, &to_free);
1283 6299 : if (state.dirpath_len == -1) {
1284 0 : return -1;
1285 : }
1286 :
1287 6299 : ret = share_mode_forall(files_below_forall_fn, &state);
1288 6299 : TALLOC_FREE(to_free);
1289 6299 : return ret;
1290 : }
1291 :
1292 : struct have_file_open_below_state {
1293 : bool found_one;
1294 : };
1295 :
1296 12 : static int have_file_open_below_fn(struct file_id fid,
1297 : const struct share_mode_data *data,
1298 : void *private_data)
1299 : {
1300 12 : struct have_file_open_below_state *state = private_data;
1301 12 : state->found_one = true;
1302 12 : return 1;
1303 : }
1304 :
1305 6299 : bool have_file_open_below(connection_struct *conn,
1306 : const struct smb_filename *name)
1307 : {
1308 6299 : struct have_file_open_below_state state = {
1309 : .found_one = false,
1310 : };
1311 0 : int ret;
1312 :
1313 6299 : if (!VALID_STAT(name->st)) {
1314 0 : return false;
1315 : }
1316 6299 : if (!S_ISDIR(name->st.st_ex_mode)) {
1317 0 : return false;
1318 : }
1319 :
1320 6299 : ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1321 6299 : if (ret == -1) {
1322 0 : return false;
1323 : }
1324 :
1325 6299 : return state.found_one;
1326 : }
1327 :
1328 : /*****************************************************************
1329 : Is this directory empty ?
1330 : *****************************************************************/
1331 :
1332 11248 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1333 : {
1334 11248 : NTSTATUS status = NT_STATUS_OK;
1335 11248 : const char *dname = NULL;
1336 11248 : char *talloced = NULL;
1337 11248 : struct connection_struct *conn = fsp->conn;
1338 11248 : struct smb_Dir *dir_hnd = NULL;
1339 :
1340 11248 : status = OpenDir(
1341 11248 : talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1342 11248 : if (!NT_STATUS_IS_OK(status)) {
1343 0 : return status;
1344 : }
1345 :
1346 33752 : while ((dname = ReadDirName(dir_hnd, &talloced))) {
1347 22648 : struct smb_filename *smb_dname_full = NULL;
1348 22648 : struct smb_filename *direntry_fname = NULL;
1349 22648 : char *fullname = NULL;
1350 148 : int ret;
1351 :
1352 22648 : if (ISDOT(dname) || (ISDOTDOT(dname))) {
1353 22496 : TALLOC_FREE(talloced);
1354 22504 : continue;
1355 : }
1356 152 : if (IS_VETO_PATH(conn, dname)) {
1357 4 : TALLOC_FREE(talloced);
1358 4 : continue;
1359 : }
1360 :
1361 148 : fullname = talloc_asprintf(talloc_tos(),
1362 : "%s/%s",
1363 148 : fsp->fsp_name->base_name,
1364 : dname);
1365 148 : if (fullname == NULL) {
1366 0 : status = NT_STATUS_NO_MEMORY;
1367 0 : break;
1368 : }
1369 :
1370 148 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1371 : fullname,
1372 : NULL,
1373 : NULL,
1374 142 : fsp->fsp_name->twrp,
1375 148 : fsp->fsp_name->flags);
1376 148 : if (smb_dname_full == NULL) {
1377 0 : TALLOC_FREE(talloced);
1378 0 : TALLOC_FREE(fullname);
1379 0 : status = NT_STATUS_NO_MEMORY;
1380 0 : break;
1381 : }
1382 :
1383 148 : ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1384 148 : if (ret != 0) {
1385 0 : status = map_nt_error_from_unix(errno);
1386 0 : TALLOC_FREE(talloced);
1387 0 : TALLOC_FREE(fullname);
1388 0 : TALLOC_FREE(smb_dname_full);
1389 0 : break;
1390 : }
1391 :
1392 148 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1393 : /* Could it be an msdfs link ? */
1394 8 : if (lp_host_msdfs() &&
1395 4 : lp_msdfs_root(SNUM(conn))) {
1396 0 : struct smb_filename *smb_dname;
1397 2 : smb_dname = synthetic_smb_fname(talloc_tos(),
1398 : dname,
1399 : NULL,
1400 2 : &smb_dname_full->st,
1401 2 : fsp->fsp_name->twrp,
1402 2 : fsp->fsp_name->flags);
1403 2 : if (smb_dname == NULL) {
1404 0 : TALLOC_FREE(talloced);
1405 0 : TALLOC_FREE(fullname);
1406 0 : TALLOC_FREE(smb_dname_full);
1407 0 : status = NT_STATUS_NO_MEMORY;
1408 0 : break;
1409 : }
1410 2 : if (is_msdfs_link(fsp, smb_dname)) {
1411 0 : TALLOC_FREE(talloced);
1412 0 : TALLOC_FREE(fullname);
1413 0 : TALLOC_FREE(smb_dname_full);
1414 0 : TALLOC_FREE(smb_dname);
1415 0 : DBG_DEBUG("got msdfs link name %s "
1416 : "- can't delete directory %s\n",
1417 : dname,
1418 : fsp_str_dbg(fsp));
1419 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1420 0 : break;
1421 : }
1422 2 : TALLOC_FREE(smb_dname);
1423 : }
1424 : /* Not a DFS link - could it be a dangling symlink ? */
1425 4 : ret = SMB_VFS_STAT(conn, smb_dname_full);
1426 4 : if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
1427 : /*
1428 : * Dangling symlink.
1429 : * Allow if "delete veto files = yes"
1430 : */
1431 4 : if (lp_delete_veto_files(SNUM(conn))) {
1432 2 : TALLOC_FREE(talloced);
1433 2 : TALLOC_FREE(fullname);
1434 2 : TALLOC_FREE(smb_dname_full);
1435 2 : continue;
1436 : }
1437 : }
1438 2 : DBG_DEBUG("got symlink name %s - "
1439 : "can't delete directory %s\n",
1440 : dname,
1441 : fsp_str_dbg(fsp));
1442 2 : TALLOC_FREE(talloced);
1443 2 : TALLOC_FREE(fullname);
1444 2 : TALLOC_FREE(smb_dname_full);
1445 2 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1446 2 : break;
1447 : }
1448 :
1449 : /* Not a symlink, get a pathref. */
1450 144 : status = synthetic_pathref(talloc_tos(),
1451 : fsp,
1452 : dname,
1453 : NULL,
1454 144 : &smb_dname_full->st,
1455 138 : fsp->fsp_name->twrp,
1456 144 : fsp->fsp_name->flags,
1457 : &direntry_fname);
1458 144 : if (!NT_STATUS_IS_OK(status)) {
1459 0 : status = map_nt_error_from_unix(errno);
1460 0 : TALLOC_FREE(talloced);
1461 0 : TALLOC_FREE(fullname);
1462 0 : TALLOC_FREE(smb_dname_full);
1463 0 : break;
1464 : }
1465 :
1466 144 : if (!is_visible_fsp(direntry_fname->fsp)) {
1467 : /*
1468 : * Hidden file.
1469 : * Allow if "delete veto files = yes"
1470 : */
1471 4 : if (lp_delete_veto_files(SNUM(conn))) {
1472 2 : TALLOC_FREE(talloced);
1473 2 : TALLOC_FREE(fullname);
1474 2 : TALLOC_FREE(smb_dname_full);
1475 2 : TALLOC_FREE(direntry_fname);
1476 2 : continue;
1477 : }
1478 : }
1479 :
1480 142 : TALLOC_FREE(talloced);
1481 142 : TALLOC_FREE(fullname);
1482 142 : TALLOC_FREE(smb_dname_full);
1483 142 : TALLOC_FREE(direntry_fname);
1484 :
1485 142 : DBG_DEBUG("got name %s - can't delete\n", dname);
1486 136 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1487 136 : break;
1488 : }
1489 11248 : TALLOC_FREE(talloced);
1490 11248 : TALLOC_FREE(dir_hnd);
1491 :
1492 11248 : if (!NT_STATUS_IS_OK(status)) {
1493 144 : return status;
1494 : }
1495 :
1496 21650 : if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1497 16665 : lp_strict_rename(SNUM(conn)) &&
1498 6119 : have_file_open_below(fsp->conn, fsp->fsp_name))
1499 : {
1500 0 : return NT_STATUS_ACCESS_DENIED;
1501 : }
1502 :
1503 11104 : return NT_STATUS_OK;
1504 : }
|