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 :
33 : /*
34 : This module implements directory related functions for Samba.
35 : */
36 :
37 : /* "Special" directory offsets. */
38 : #define END_OF_DIRECTORY_OFFSET ((long)-1)
39 : #define START_OF_DIRECTORY_OFFSET ((long)0)
40 : #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
41 :
42 : /* Make directory handle internals available. */
43 :
44 : struct smb_Dir {
45 : connection_struct *conn;
46 : DIR *dir;
47 : struct smb_filename *dir_smb_fname;
48 : unsigned int file_number;
49 : bool case_sensitive;
50 : files_struct *fsp; /* Back pointer to containing fsp, only
51 : set from OpenDir_fsp(). */
52 : };
53 :
54 : struct dptr_struct {
55 : struct dptr_struct *next, *prev;
56 : int dnum;
57 : struct connection_struct *conn;
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 31051 : bool init_dptrs(struct smbd_server_connection *sconn)
92 : {
93 31051 : if (sconn->searches.dptr_bmap) {
94 0 : return true;
95 : }
96 :
97 31051 : sconn->searches.dptr_bmap = bitmap_talloc(
98 : sconn, MAX_DIRECTORY_HANDLES);
99 :
100 31051 : if (sconn->searches.dptr_bmap == NULL) {
101 0 : return false;
102 : }
103 :
104 30209 : 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->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 18684 : 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 18684 : struct smbd_server_connection *sconn = conn->sconn;
206 18684 : struct dptr_struct *dptr = NULL;
207 18684 : struct smb_Dir *dir_hnd = NULL;
208 176 : NTSTATUS status;
209 :
210 18684 : DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
211 :
212 18684 : 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 18684 : if (!wcard) {
218 0 : return NT_STATUS_INVALID_PARAMETER;
219 : }
220 :
221 18684 : if (!(fsp->access_mask & SEC_DIR_LIST)) {
222 0 : DBG_INFO("dptr_create: directory %s "
223 : "not open for LIST access\n",
224 : fsp_str_dbg(fsp));
225 0 : return NT_STATUS_ACCESS_DENIED;
226 : }
227 18684 : status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
228 18684 : if (!NT_STATUS_IS_OK(status)) {
229 0 : return status;
230 : }
231 :
232 18684 : dptr = talloc_zero(NULL, struct dptr_struct);
233 18684 : if(!dptr) {
234 0 : DEBUG(0,("talloc fail in dptr_create.\n"));
235 0 : TALLOC_FREE(dir_hnd);
236 0 : return NT_STATUS_NO_MEMORY;
237 : }
238 :
239 18684 : dptr->conn = conn;
240 18684 : dptr->dir_hnd = dir_hnd;
241 18684 : dptr->wcard = talloc_strdup(dptr, wcard);
242 18684 : if (!dptr->wcard) {
243 0 : TALLOC_FREE(dptr);
244 0 : TALLOC_FREE(dir_hnd);
245 0 : return NT_STATUS_NO_MEMORY;
246 : }
247 18684 : if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
248 92 : dptr->has_wild = True;
249 : } else {
250 18592 : dptr->has_wild = ms_has_wild(dptr->wcard);
251 : }
252 :
253 18684 : dptr->attr = attr;
254 :
255 18684 : if (sconn->using_smb2) {
256 10029 : goto done;
257 : }
258 :
259 8655 : 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 8479 : dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
284 :
285 8479 : 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 8655 : bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
296 :
297 8655 : dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
298 :
299 8655 : DLIST_ADD(sconn->searches.dirptrs, dptr);
300 :
301 18684 : done:
302 18684 : DBG_INFO("creating new dirptr [%d] for path [%s]\n",
303 : dptr->dnum, fsp_str_dbg(fsp));
304 :
305 18684 : *dptr_ret = dptr;
306 :
307 18684 : return NT_STATUS_OK;
308 : }
309 :
310 :
311 : /****************************************************************************
312 : Wrapper functions to access the lower level directory handles.
313 : ****************************************************************************/
314 :
315 18684 : void dptr_CloseDir(files_struct *fsp)
316 : {
317 18684 : struct smbd_server_connection *sconn = NULL;
318 :
319 18684 : if (fsp->dptr == NULL) {
320 0 : return;
321 : }
322 18684 : sconn = fsp->dptr->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 18684 : DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
330 :
331 18684 : if (sconn != NULL && !sconn->using_smb2) {
332 8655 : 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 8655 : if (!bitmap_query(sconn->searches.dptr_bmap,
340 8655 : fsp->dptr->dnum - 1))
341 : {
342 0 : DBG_ERR("closing dnum = %d and bitmap not set !\n",
343 : fsp->dptr->dnum);
344 : }
345 :
346 8655 : bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
347 : }
348 :
349 18684 : TALLOC_FREE(fsp->dptr->dir_hnd);
350 18684 : 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 83440 : unsigned int dptr_FileNumber(struct dptr_struct *dptr)
362 : {
363 83440 : 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 8655 : int dptr_dnum(struct dptr_struct *dptr)
372 : {
373 8655 : 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 1301090 : bool dptr_case_sensitive(struct dptr_struct *dptr)
387 : {
388 1301090 : 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 1334041 : char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
396 : {
397 1334041 : struct stat_ex st = {
398 : .st_ex_nlink = 0,
399 : };
400 1334041 : struct smb_Dir *dir_hnd = dptr->dir_hnd;
401 1334041 : struct files_struct *dir_fsp = dir_hnd->fsp;
402 1334041 : struct smb_filename *dir_name = dir_fsp->fsp_name;
403 404 : struct smb_filename smb_fname_base;
404 1334041 : bool retry_scanning = false;
405 404 : int ret;
406 1334041 : int flags = 0;
407 :
408 1334041 : if (dptr->has_wild) {
409 1330032 : const char *name_temp = NULL;
410 1330032 : char *talloced = NULL;
411 1330032 : name_temp = ReadDirName(dir_hnd, &talloced);
412 1330032 : if (name_temp == NULL) {
413 26304 : return NULL;
414 : }
415 1303639 : if (talloced != NULL) {
416 430 : return talloc_move(ctx, &talloced);
417 : }
418 1303209 : return talloc_strdup(ctx, name_temp);
419 : }
420 :
421 4009 : 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 1992 : return NULL;
428 : }
429 2017 : dptr->did_stat = true;
430 :
431 : /* Create an smb_filename with stream_name == NULL. */
432 2017 : smb_fname_base = (struct smb_filename){
433 2017 : .base_name = dptr->wcard,
434 2017 : .flags = dir_name->flags,
435 2017 : .twrp = dir_name->twrp,
436 : };
437 :
438 2017 : if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
439 13 : flags |= AT_SYMLINK_NOFOLLOW;
440 : }
441 :
442 2017 : ret = SMB_VFS_FSTATAT(dptr->conn, dir_fsp, &smb_fname_base, &st, flags);
443 2017 : if (ret == 0) {
444 1701 : return talloc_strdup(ctx, dptr->wcard);
445 : }
446 :
447 : /*
448 : * If we get any other error than ENOENT or ENOTDIR
449 : * then the file exists, we just can't stat it.
450 : */
451 316 : if (errno != ENOENT && errno != ENOTDIR) {
452 0 : return talloc_strdup(ctx, dptr->wcard);
453 : }
454 :
455 : /*
456 : * A scan will find the long version of a mangled name as
457 : * wildcard.
458 : */
459 316 : retry_scanning |= mangle_is_mangled(dptr->wcard, dptr->conn->params);
460 :
461 : /*
462 : * Also retry scanning if the client requested case
463 : * insensitive semantics and the file system does not provide
464 : * it.
465 : */
466 632 : retry_scanning |=
467 632 : (!dir_hnd->case_sensitive &&
468 316 : (dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH));
469 :
470 316 : if (retry_scanning) {
471 316 : char *found_name = NULL;
472 0 : NTSTATUS status;
473 :
474 316 : status = get_real_filename_at(dir_fsp,
475 316 : dptr->wcard,
476 : ctx,
477 : &found_name);
478 316 : if (NT_STATUS_IS_OK(status)) {
479 47 : return found_name;
480 : }
481 : }
482 :
483 269 : return NULL;
484 : }
485 :
486 6 : struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
487 : {
488 6 : return dir_hnd->fsp;
489 : }
490 :
491 : /****************************************************************************
492 : Fetch the fsp associated with the dptr_num.
493 : ****************************************************************************/
494 :
495 2056 : files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
496 : int dptr_num)
497 : {
498 2056 : struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
499 2056 : if (dptr == NULL) {
500 8 : return NULL;
501 : }
502 2048 : DBG_NOTICE("fetching dirptr %d for path %s\n",
503 : dptr_num,
504 : dptr->dir_hnd->dir_smb_fname->base_name);
505 2048 : return dptr->dir_hnd->fsp;
506 : }
507 :
508 942856 : bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
509 : struct dptr_struct *dirptr,
510 : const char *mask,
511 : uint32_t dirtype,
512 : bool dont_descend,
513 : bool ask_sharemode,
514 : bool get_dosmode_in,
515 : bool (*match_fn)(TALLOC_CTX *ctx,
516 : void *private_data,
517 : const char *dname,
518 : const char *mask,
519 : char **_fname),
520 : void *private_data,
521 : char **_fname,
522 : struct smb_filename **_smb_fname,
523 : uint32_t *_mode)
524 : {
525 942856 : connection_struct *conn = dirptr->conn;
526 942856 : struct smb_Dir *dir_hnd = dirptr->dir_hnd;
527 942856 : struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
528 942856 : bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
529 942856 : const bool toplevel = ISDOT(dir_fname->base_name);
530 316 : NTSTATUS status;
531 :
532 942856 : *_smb_fname = NULL;
533 942856 : *_mode = 0;
534 :
535 942856 : if (dirptr->overflow.smb_fname != NULL) {
536 668 : *_fname = talloc_move(ctx, &dirptr->overflow.fname);
537 668 : *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
538 668 : *_mode = dirptr->overflow.mode;
539 668 : return true;
540 : }
541 :
542 942188 : if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
543 : /*
544 : * . and .. were returned first, we're done showing
545 : * the directory as empty.
546 : */
547 0 : return false;
548 : }
549 :
550 23719 : while (true) {
551 965503 : char *dname = NULL;
552 965503 : char *fname = NULL;
553 965503 : struct smb_filename *smb_fname = NULL;
554 965503 : uint32_t mode = 0;
555 965503 : bool get_dosmode = get_dosmode_in;
556 404 : bool toplevel_dotdot;
557 404 : bool visible;
558 404 : bool ok;
559 :
560 965503 : dname = dptr_ReadDirName(ctx, dirptr);
561 :
562 965503 : DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
563 : "dname [%s]\n",
564 : smb_fname_str_dbg(dir_fname),
565 : dirptr,
566 : dir_hnd->file_number,
567 : dname ? dname : "(finished)");
568 :
569 965503 : if (dname == NULL) {
570 942188 : return false;
571 : }
572 :
573 937893 : if (IS_VETO_PATH(conn, dname)) {
574 6 : TALLOC_FREE(dname);
575 23315 : continue;
576 : }
577 :
578 : /*
579 : * fname may get mangled, dname is never mangled.
580 : * Whenever we're accessing the filesystem we use
581 : * pathreal which is composed from dname.
582 : */
583 :
584 937887 : ok = match_fn(ctx, private_data, dname, mask, &fname);
585 937887 : if (!ok) {
586 6263 : TALLOC_FREE(dname);
587 6263 : continue;
588 : }
589 :
590 931624 : toplevel_dotdot = toplevel && ISDOTDOT(dname);
591 :
592 931939 : smb_fname = synthetic_smb_fname(talloc_tos(),
593 : toplevel_dotdot ? "." : dname,
594 : NULL,
595 : NULL,
596 : dir_fname->twrp,
597 : dir_fname->flags);
598 931624 : if (smb_fname == NULL) {
599 0 : TALLOC_FREE(dname);
600 0 : return false;
601 : }
602 :
603 : /*
604 : * UCF_POSIX_PATHNAMES to avoid the readdir fallback
605 : * if we get raced between readdir and unlink.
606 : */
607 931624 : status = openat_pathref_fsp_lcomp(dir_hnd->fsp,
608 : smb_fname,
609 : UCF_POSIX_PATHNAMES);
610 931624 : if (!NT_STATUS_IS_OK(status)) {
611 6 : DBG_DEBUG("Could not open %s: %s\n",
612 : dname,
613 : nt_errstr(status));
614 6 : TALLOC_FREE(smb_fname);
615 6 : TALLOC_FREE(fname);
616 6 : TALLOC_FREE(dname);
617 6 : continue;
618 : }
619 :
620 931618 : visible = is_visible_fsp(smb_fname->fsp);
621 931618 : if (!visible) {
622 32 : TALLOC_FREE(smb_fname);
623 32 : TALLOC_FREE(fname);
624 32 : TALLOC_FREE(dname);
625 32 : continue;
626 : }
627 :
628 931586 : if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
629 928844 : goto done;
630 : }
631 :
632 3114 : if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
633 372 : is_msdfs_link(dir_hnd->fsp, smb_fname))
634 : {
635 370 : DBG_INFO("Masquerading msdfs link %s as a directory\n",
636 : smb_fname->base_name);
637 :
638 370 : smb_fname->st.st_ex_mode = (smb_fname->st.st_ex_mode &
639 370 : ~S_IFMT) |
640 : S_IFDIR;
641 :
642 370 : mode = dos_mode_msdfs(conn, dname, &smb_fname->st);
643 370 : get_dosmode = false;
644 370 : ask_sharemode = false;
645 370 : goto done;
646 : }
647 :
648 2372 : if (posix) {
649 : /*
650 : * Posix always wants to see symlinks,
651 : * dangling or not. We've done the
652 : * openat_pathref_fsp() to fill in
653 : * smb_fname->fsp just in case it's not
654 : * dangling.
655 : */
656 52 : ask_sharemode = false;
657 52 : goto done;
658 : }
659 :
660 2320 : if (!lp_follow_symlinks(SNUM(conn))) {
661 : /*
662 : * Hide symlinks not followed
663 : */
664 0 : TALLOC_FREE(smb_fname);
665 0 : TALLOC_FREE(fname);
666 0 : TALLOC_FREE(dname);
667 0 : continue;
668 : }
669 :
670 : /*
671 : * We have to find out if it's a dangling
672 : * symlink. Use the fat logic behind
673 : * openat_pathref_fsp().
674 : */
675 :
676 : {
677 2320 : struct files_struct *fsp = smb_fname->fsp;
678 2320 : smb_fname_fsp_unlink(smb_fname);
679 2320 : fd_close(fsp);
680 2320 : file_free(NULL, fsp);
681 : }
682 :
683 2320 : status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
684 :
685 2320 : if (!NT_STATUS_IS_OK(status)) {
686 : /*
687 : * Dangling symlink. Hide.
688 : */
689 492 : TALLOC_FREE(smb_fname);
690 492 : TALLOC_FREE(fname);
691 492 : TALLOC_FREE(dname);
692 492 : continue;
693 : }
694 :
695 1828 : done:
696 931094 : if (get_dosmode) {
697 910586 : mode = fdos_mode(smb_fname->fsp);
698 910586 : smb_fname->st = smb_fname->fsp->fsp_name->st;
699 : }
700 :
701 931094 : if (!dir_check_ftype(mode, dirtype)) {
702 16516 : DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
703 : "0x%" PRIx32 "\n",
704 : fname,
705 : mode,
706 : dirtype);
707 16516 : TALLOC_FREE(smb_fname);
708 16516 : TALLOC_FREE(dname);
709 16516 : TALLOC_FREE(fname);
710 16516 : continue;
711 : }
712 :
713 914578 : if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
714 115 : struct timespec write_time_ts;
715 115 : struct file_id fileid;
716 :
717 716903 : fileid = vfs_file_id_from_sbuf(conn,
718 716903 : &smb_fname->st);
719 716903 : get_file_infos(fileid, 0, NULL, &write_time_ts);
720 716903 : if (!is_omit_timespec(&write_time_ts)) {
721 918 : update_stat_ex_mtime(&smb_fname->st,
722 : write_time_ts);
723 : }
724 : }
725 :
726 914578 : if (toplevel_dotdot) {
727 : /*
728 : * Ensure posix fileid and sids are hidden
729 : */
730 1489 : smb_fname->st.st_ex_ino = 0;
731 1489 : smb_fname->st.st_ex_dev = 0;
732 1489 : smb_fname->st.st_ex_uid = -1;
733 1489 : smb_fname->st.st_ex_gid = -1;
734 : }
735 :
736 914578 : DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
737 : mask,
738 : smb_fname_str_dbg(smb_fname),
739 : dname,
740 : fname);
741 :
742 914578 : TALLOC_FREE(dname);
743 :
744 914578 : *_smb_fname = talloc_move(ctx, &smb_fname);
745 914578 : *_fname = fname;
746 914578 : *_mode = mode;
747 :
748 914578 : return true;
749 : }
750 :
751 : return false;
752 : }
753 :
754 668 : void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
755 : char **_fname,
756 : struct smb_filename **_smb_fname,
757 : uint32_t mode)
758 : {
759 668 : SMB_ASSERT(dirptr->overflow.fname == NULL);
760 668 : SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
761 :
762 668 : dirptr->overflow.fname = talloc_move(dirptr, _fname);
763 668 : dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
764 668 : dirptr->overflow.mode = mode;
765 668 : }
766 :
767 893699 : void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
768 : char **_fname)
769 : {
770 893699 : TALLOC_FREE(dirptr->last_name_sent);
771 893699 : dirptr->last_name_sent = talloc_move(dirptr, _fname);
772 893699 : }
773 :
774 1424 : char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
775 : {
776 1424 : return dirptr->last_name_sent;
777 : }
778 :
779 : /*******************************************************************
780 : Check to see if a user can read an fsp . This is only approximate,
781 : it is used as part of the "hide unreadable" option. Don't
782 : use it for anything security sensitive.
783 : ********************************************************************/
784 :
785 118 : static bool user_can_read_fsp(struct files_struct *fsp)
786 : {
787 0 : NTSTATUS status;
788 118 : uint32_t rejected_share_access = 0;
789 118 : uint32_t rejected_mask = 0;
790 118 : struct security_descriptor *sd = NULL;
791 118 : uint32_t access_mask = FILE_READ_DATA|
792 : FILE_READ_EA|
793 : FILE_READ_ATTRIBUTES|
794 : SEC_STD_READ_CONTROL;
795 :
796 : /*
797 : * Never hide files from the root user.
798 : * We use (uid_t)0 here not sec_initial_uid()
799 : * as make test uses a single user context.
800 : */
801 :
802 118 : if (get_current_uid(fsp->conn) == (uid_t)0) {
803 0 : return true;
804 : }
805 :
806 : /*
807 : * We can't directly use smbd_check_access_rights_fsp()
808 : * here, as this implicitly grants FILE_READ_ATTRIBUTES
809 : * which the Windows access-based-enumeration code
810 : * explicitly checks for on the file security descriptor.
811 : * See bug:
812 : *
813 : * https://bugzilla.samba.org/show_bug.cgi?id=10252
814 : *
815 : * and the smb2.acl2.ACCESSBASED test for details.
816 : */
817 :
818 118 : rejected_share_access = access_mask & ~(fsp->conn->share_access);
819 118 : if (rejected_share_access) {
820 0 : DBG_DEBUG("rejected share access 0x%x "
821 : "on %s (0x%x)\n",
822 : (unsigned int)access_mask,
823 : fsp_str_dbg(fsp),
824 : (unsigned int)rejected_share_access);
825 0 : return false;
826 : }
827 :
828 118 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
829 : (SECINFO_OWNER |
830 : SECINFO_GROUP |
831 : SECINFO_DACL),
832 : talloc_tos(),
833 : &sd);
834 :
835 118 : if (!NT_STATUS_IS_OK(status)) {
836 0 : DBG_DEBUG("Could not get acl "
837 : "on %s: %s\n",
838 : fsp_str_dbg(fsp),
839 : nt_errstr(status));
840 0 : return false;
841 : }
842 :
843 118 : status = se_file_access_check(sd,
844 118 : get_current_nttok(fsp->conn),
845 : false,
846 : access_mask,
847 : &rejected_mask);
848 :
849 118 : TALLOC_FREE(sd);
850 :
851 118 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
852 14 : DBG_DEBUG("rejected bits 0x%x read access for %s\n",
853 : (unsigned int)rejected_mask,
854 : fsp_str_dbg(fsp));
855 14 : return false;
856 : }
857 104 : return true;
858 : }
859 :
860 : /*******************************************************************
861 : Check to see if a user can write to an fsp.
862 : Always return true for directories.
863 : This is only approximate,
864 : it is used as part of the "hide unwriteable" option. Don't
865 : use it for anything security sensitive.
866 : ********************************************************************/
867 :
868 110 : static bool user_can_write_fsp(struct files_struct *fsp)
869 : {
870 : /*
871 : * Never hide files from the root user.
872 : * We use (uid_t)0 here not sec_initial_uid()
873 : * as make test uses a single user context.
874 : */
875 :
876 110 : if (get_current_uid(fsp->conn) == (uid_t)0) {
877 0 : return true;
878 : }
879 :
880 110 : if (fsp->fsp_flags.is_directory) {
881 18 : return true;
882 : }
883 :
884 92 : return can_write_to_fsp(fsp);
885 : }
886 :
887 : /*******************************************************************
888 : Is a file a "special" type ?
889 : ********************************************************************/
890 :
891 0 : static bool file_is_special(connection_struct *conn,
892 : const struct smb_filename *smb_fname)
893 : {
894 : /*
895 : * Never hide files from the root user.
896 : * We use (uid_t)0 here not sec_initial_uid()
897 : * as make test uses a single user context.
898 : */
899 :
900 0 : if (get_current_uid(conn) == (uid_t)0) {
901 0 : return False;
902 : }
903 :
904 0 : SMB_ASSERT(VALID_STAT(smb_fname->st));
905 :
906 0 : if (S_ISREG(smb_fname->st.st_ex_mode) ||
907 0 : S_ISDIR(smb_fname->st.st_ex_mode) ||
908 0 : S_ISLNK(smb_fname->st.st_ex_mode))
909 0 : return False;
910 :
911 0 : return True;
912 : }
913 :
914 : /*******************************************************************
915 : Should the file be seen by the client?
916 : ********************************************************************/
917 :
918 931766 : bool is_visible_fsp(struct files_struct *fsp)
919 : {
920 931766 : bool hide_unreadable = false;
921 931766 : bool hide_unwriteable = false;
922 931766 : bool hide_special = false;
923 931766 : int hide_new_files_timeout = 0;
924 931766 : const char *last_component = NULL;
925 :
926 : /*
927 : * If the file does not exist, there's no point checking
928 : * the configuration options. We succeed, on the basis that the
929 : * checks *might* have passed if the file was present.
930 : */
931 931766 : if (fsp == NULL) {
932 0 : return true;
933 : }
934 :
935 931766 : hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
936 931766 : hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
937 931766 : hide_special = lp_hide_special_files(SNUM(fsp->conn));
938 931766 : hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
939 :
940 931766 : if (!hide_unreadable &&
941 931275 : !hide_unwriteable &&
942 931466 : !hide_special &&
943 321 : (hide_new_files_timeout == 0))
944 : {
945 930795 : return true;
946 : }
947 :
948 650 : fsp = metadata_fsp(fsp);
949 :
950 : /* Get the last component of the base name. */
951 650 : last_component = strrchr_m(fsp->fsp_name->base_name, '/');
952 650 : if (!last_component) {
953 578 : last_component = fsp->fsp_name->base_name;
954 : } else {
955 72 : last_component++; /* Go past '/' */
956 : }
957 :
958 650 : if (ISDOT(last_component) || ISDOTDOT(last_component)) {
959 100 : return true; /* . and .. are always visible. */
960 : }
961 :
962 550 : if (fsp_get_pathref_fd(fsp) == -1) {
963 : /*
964 : * Symlink in POSIX mode or MS-DFS.
965 : * We've checked veto files so the
966 : * only thing we can check is the
967 : * hide_new_files_timeout.
968 : */
969 7 : if ((hide_new_files_timeout != 0) &&
970 7 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
971 0 : double age = timespec_elapsed(
972 0 : &fsp->fsp_name->st.st_ex_mtime);
973 :
974 0 : if (age < (double)hide_new_files_timeout) {
975 0 : return false;
976 : }
977 : }
978 7 : return true;
979 : }
980 :
981 : /* Honour _hide unreadable_ option */
982 543 : if (hide_unreadable && !user_can_read_fsp(fsp)) {
983 14 : DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
984 14 : return false;
985 : }
986 :
987 : /* Honour _hide unwriteable_ option */
988 529 : if (hide_unwriteable && !user_can_write_fsp(fsp)) {
989 12 : DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
990 12 : return false;
991 : }
992 :
993 : /* Honour _hide_special_ option */
994 517 : if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
995 0 : DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
996 0 : return false;
997 : }
998 :
999 517 : if ((hide_new_files_timeout != 0) &&
1000 315 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1001 12 : double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1002 :
1003 12 : if (age < (double)hide_new_files_timeout) {
1004 10 : return false;
1005 : }
1006 : }
1007 :
1008 507 : return true;
1009 : }
1010 :
1011 304379 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1012 : {
1013 304379 : files_struct *fsp = dir_hnd->fsp;
1014 :
1015 304379 : SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1016 304379 : fsp_set_fd(fsp, -1);
1017 304379 : if (fsp->dptr != NULL) {
1018 18684 : SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1019 18684 : fsp->dptr->dir_hnd = NULL;
1020 : }
1021 304379 : dir_hnd->fsp = NULL;
1022 304379 : return 0;
1023 : }
1024 :
1025 : /*******************************************************************
1026 : Open a directory.
1027 : ********************************************************************/
1028 :
1029 285695 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1030 : {
1031 285695 : files_struct *fsp = dir_hnd->fsp;
1032 :
1033 285695 : smb_Dir_destructor(dir_hnd);
1034 285695 : file_free(NULL, fsp);
1035 285695 : return 0;
1036 : }
1037 :
1038 13167 : NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1039 : connection_struct *conn,
1040 : const struct smb_filename *smb_dname,
1041 : const char *mask,
1042 : uint32_t attr,
1043 : struct smb_Dir **_dir_hnd)
1044 : {
1045 13167 : struct files_struct *fsp = NULL;
1046 13167 : struct smb_Dir *dir_hnd = NULL;
1047 74 : NTSTATUS status;
1048 :
1049 13167 : status = open_internal_dirfsp(conn,
1050 : smb_dname,
1051 : O_RDONLY,
1052 : &fsp);
1053 13167 : if (!NT_STATUS_IS_OK(status)) {
1054 0 : return status;
1055 : }
1056 :
1057 13167 : status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1058 13167 : if (!NT_STATUS_IS_OK(status)) {
1059 0 : return status;
1060 : }
1061 :
1062 : /*
1063 : * This overwrites the destructor set by OpenDir_fsp() but
1064 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1065 : * destructor.
1066 : */
1067 13167 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1068 :
1069 13167 : *_dir_hnd = dir_hnd;
1070 13167 : return NT_STATUS_OK;
1071 : }
1072 :
1073 272529 : NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1074 : struct files_struct *dirfsp,
1075 : const char *mask,
1076 : uint32_t attr,
1077 : struct smb_Dir **_dir_hnd)
1078 : {
1079 272529 : struct files_struct *fsp = NULL;
1080 272529 : struct smb_Dir *dir_hnd = NULL;
1081 883 : NTSTATUS status;
1082 :
1083 272529 : status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1084 272529 : if (!NT_STATUS_IS_OK(status)) {
1085 1 : return status;
1086 : }
1087 :
1088 272528 : status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1089 272528 : if (!NT_STATUS_IS_OK(status)) {
1090 0 : return status;
1091 : }
1092 :
1093 : /*
1094 : * This overwrites the destructor set by OpenDir_fsp() but
1095 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1096 : * destructor.
1097 : */
1098 272528 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1099 :
1100 272528 : *_dir_hnd = dir_hnd;
1101 272528 : return NT_STATUS_OK;
1102 : }
1103 :
1104 : /*******************************************************************
1105 : Open a directory from an fsp.
1106 : ********************************************************************/
1107 :
1108 304379 : static NTSTATUS OpenDir_fsp(
1109 : TALLOC_CTX *mem_ctx,
1110 : connection_struct *conn,
1111 : files_struct *fsp,
1112 : const char *mask,
1113 : uint32_t attr,
1114 : struct smb_Dir **_dir_hnd)
1115 : {
1116 304379 : struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1117 1133 : NTSTATUS status;
1118 :
1119 304379 : if (!dir_hnd) {
1120 0 : return NT_STATUS_NO_MEMORY;
1121 : }
1122 :
1123 304379 : if (!fsp->fsp_flags.is_directory) {
1124 0 : status = NT_STATUS_INVALID_HANDLE;
1125 0 : goto fail;
1126 : }
1127 :
1128 304379 : if (fsp_get_io_fd(fsp) == -1) {
1129 0 : status = NT_STATUS_INVALID_HANDLE;
1130 0 : goto fail;
1131 : }
1132 :
1133 304379 : dir_hnd->conn = conn;
1134 :
1135 304379 : dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1136 304379 : if (!dir_hnd->dir_smb_fname) {
1137 0 : status = NT_STATUS_NO_MEMORY;
1138 0 : goto fail;
1139 : }
1140 :
1141 304379 : dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1142 304379 : if (dir_hnd->dir == NULL) {
1143 0 : status = map_nt_error_from_unix(errno);
1144 0 : goto fail;
1145 : }
1146 304379 : dir_hnd->fsp = fsp;
1147 304379 : if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1148 19 : dir_hnd->case_sensitive = true;
1149 : } else {
1150 304360 : dir_hnd->case_sensitive = conn->case_sensitive;
1151 : }
1152 :
1153 304379 : talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1154 :
1155 304379 : *_dir_hnd = dir_hnd;
1156 304379 : return NT_STATUS_OK;
1157 :
1158 0 : fail:
1159 0 : TALLOC_FREE(dir_hnd);
1160 0 : return status;
1161 : }
1162 :
1163 :
1164 : /*******************************************************************
1165 : Read from a directory.
1166 : Return directory entry, current offset, and optional stat information.
1167 : Don't check for veto or invisible files.
1168 : ********************************************************************/
1169 :
1170 160978997 : const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
1171 : {
1172 7211 : const char *n;
1173 160978997 : char *talloced = NULL;
1174 160978997 : connection_struct *conn = dir_hnd->conn;
1175 :
1176 160978997 : if (dir_hnd->file_number < 2) {
1177 610138 : if (dir_hnd->file_number == 0) {
1178 304026 : n = ".";
1179 : } else {
1180 305066 : n = "..";
1181 : }
1182 610138 : dir_hnd->file_number++;
1183 610138 : *ptalloced = NULL;
1184 610138 : return n;
1185 : }
1186 :
1187 321332406 : while ((n = vfs_readdirname(conn,
1188 160968666 : dir_hnd->fsp,
1189 160968666 : dir_hnd->dir,
1190 : &talloced))) {
1191 : /* Ignore . and .. - we've already returned them. */
1192 160661972 : if (ISDOT(n) || ISDOTDOT(n)) {
1193 599807 : TALLOC_FREE(talloced);
1194 599807 : continue;
1195 : }
1196 160062165 : *ptalloced = talloced;
1197 160062165 : dir_hnd->file_number++;
1198 160062165 : return n;
1199 : }
1200 306694 : *ptalloced = NULL;
1201 306694 : return NULL;
1202 : }
1203 :
1204 : /*******************************************************************
1205 : Rewind to the start.
1206 : ********************************************************************/
1207 :
1208 2732 : void RewindDir(struct smb_Dir *dir_hnd)
1209 : {
1210 2732 : SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1211 2732 : dir_hnd->file_number = 0;
1212 2732 : }
1213 :
1214 : struct files_below_forall_state {
1215 : char *dirpath;
1216 : ssize_t dirpath_len;
1217 : int (*fn)(struct file_id fid, const struct share_mode_data *data,
1218 : void *private_data);
1219 : void *private_data;
1220 : };
1221 :
1222 18759 : static int files_below_forall_fn(struct file_id fid,
1223 : const struct share_mode_data *data,
1224 : void *private_data)
1225 : {
1226 18759 : struct files_below_forall_state *state = private_data;
1227 0 : char tmpbuf[PATH_MAX];
1228 0 : char *fullpath, *to_free;
1229 0 : ssize_t len;
1230 :
1231 18759 : len = full_path_tos(data->servicepath, data->base_name,
1232 : tmpbuf, sizeof(tmpbuf),
1233 : &fullpath, &to_free);
1234 18759 : if (len == -1) {
1235 0 : return 0;
1236 : }
1237 18759 : if (state->dirpath_len >= len) {
1238 : /*
1239 : * Filter files above dirpath
1240 : */
1241 16453 : goto out;
1242 : }
1243 2306 : if (fullpath[state->dirpath_len] != '/') {
1244 : /*
1245 : * Filter file that don't have a path separator at the end of
1246 : * dirpath's length
1247 : */
1248 2252 : goto out;
1249 : }
1250 :
1251 54 : if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1252 : /*
1253 : * Not a parent
1254 : */
1255 42 : goto out;
1256 : }
1257 :
1258 12 : TALLOC_FREE(to_free);
1259 12 : return state->fn(fid, data, state->private_data);
1260 :
1261 18747 : out:
1262 18747 : TALLOC_FREE(to_free);
1263 18747 : return 0;
1264 : }
1265 :
1266 6299 : static int files_below_forall(connection_struct *conn,
1267 : const struct smb_filename *dir_name,
1268 : int (*fn)(struct file_id fid,
1269 : const struct share_mode_data *data,
1270 : void *private_data),
1271 : void *private_data)
1272 : {
1273 6299 : struct files_below_forall_state state = {
1274 : .fn = fn,
1275 : .private_data = private_data,
1276 : };
1277 0 : int ret;
1278 0 : char tmpbuf[PATH_MAX];
1279 0 : char *to_free;
1280 :
1281 12598 : state.dirpath_len = full_path_tos(conn->connectpath,
1282 6299 : dir_name->base_name,
1283 : tmpbuf, sizeof(tmpbuf),
1284 : &state.dirpath, &to_free);
1285 6299 : if (state.dirpath_len == -1) {
1286 0 : return -1;
1287 : }
1288 :
1289 6299 : ret = share_mode_forall(files_below_forall_fn, &state);
1290 6299 : TALLOC_FREE(to_free);
1291 6299 : return ret;
1292 : }
1293 :
1294 : struct have_file_open_below_state {
1295 : bool found_one;
1296 : };
1297 :
1298 12 : static int have_file_open_below_fn(struct file_id fid,
1299 : const struct share_mode_data *data,
1300 : void *private_data)
1301 : {
1302 12 : struct have_file_open_below_state *state = private_data;
1303 12 : state->found_one = true;
1304 12 : return 1;
1305 : }
1306 :
1307 6299 : bool have_file_open_below(connection_struct *conn,
1308 : const struct smb_filename *name)
1309 : {
1310 6299 : struct have_file_open_below_state state = {
1311 : .found_one = false,
1312 : };
1313 0 : int ret;
1314 :
1315 6299 : if (!VALID_STAT(name->st)) {
1316 0 : return false;
1317 : }
1318 6299 : if (!S_ISDIR(name->st.st_ex_mode)) {
1319 0 : return false;
1320 : }
1321 :
1322 6299 : ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1323 6299 : if (ret == -1) {
1324 0 : return false;
1325 : }
1326 :
1327 6299 : return state.found_one;
1328 : }
1329 :
1330 : /*****************************************************************
1331 : Is this directory empty ?
1332 : *****************************************************************/
1333 :
1334 11248 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1335 : {
1336 11248 : NTSTATUS status = NT_STATUS_OK;
1337 11248 : const char *dname = NULL;
1338 11248 : char *talloced = NULL;
1339 11248 : struct connection_struct *conn = fsp->conn;
1340 11248 : struct smb_Dir *dir_hnd = NULL;
1341 :
1342 11248 : status = OpenDir(
1343 11248 : talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1344 11248 : if (!NT_STATUS_IS_OK(status)) {
1345 0 : return status;
1346 : }
1347 :
1348 33752 : while ((dname = ReadDirName(dir_hnd, &talloced))) {
1349 22648 : struct smb_filename *smb_dname_full = NULL;
1350 22648 : struct smb_filename *direntry_fname = NULL;
1351 22648 : char *fullname = NULL;
1352 148 : int ret;
1353 :
1354 22648 : if (ISDOT(dname) || (ISDOTDOT(dname))) {
1355 22496 : TALLOC_FREE(talloced);
1356 22504 : continue;
1357 : }
1358 152 : if (IS_VETO_PATH(conn, dname)) {
1359 4 : TALLOC_FREE(talloced);
1360 4 : continue;
1361 : }
1362 :
1363 148 : fullname = talloc_asprintf(talloc_tos(),
1364 : "%s/%s",
1365 148 : fsp->fsp_name->base_name,
1366 : dname);
1367 148 : if (fullname == NULL) {
1368 0 : status = NT_STATUS_NO_MEMORY;
1369 0 : break;
1370 : }
1371 :
1372 148 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1373 : fullname,
1374 : NULL,
1375 : NULL,
1376 142 : fsp->fsp_name->twrp,
1377 148 : fsp->fsp_name->flags);
1378 148 : if (smb_dname_full == NULL) {
1379 0 : TALLOC_FREE(talloced);
1380 0 : TALLOC_FREE(fullname);
1381 0 : status = NT_STATUS_NO_MEMORY;
1382 0 : break;
1383 : }
1384 :
1385 148 : ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1386 148 : if (ret != 0) {
1387 0 : status = map_nt_error_from_unix(errno);
1388 0 : TALLOC_FREE(talloced);
1389 0 : TALLOC_FREE(fullname);
1390 0 : TALLOC_FREE(smb_dname_full);
1391 0 : break;
1392 : }
1393 :
1394 148 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1395 : /* Could it be an msdfs link ? */
1396 8 : if (lp_host_msdfs() &&
1397 4 : lp_msdfs_root(SNUM(conn))) {
1398 0 : struct smb_filename *smb_dname;
1399 2 : smb_dname = synthetic_smb_fname(talloc_tos(),
1400 : dname,
1401 : NULL,
1402 2 : &smb_dname_full->st,
1403 2 : fsp->fsp_name->twrp,
1404 2 : fsp->fsp_name->flags);
1405 2 : if (smb_dname == NULL) {
1406 0 : TALLOC_FREE(talloced);
1407 0 : TALLOC_FREE(fullname);
1408 0 : TALLOC_FREE(smb_dname_full);
1409 0 : status = NT_STATUS_NO_MEMORY;
1410 0 : break;
1411 : }
1412 2 : if (is_msdfs_link(fsp, smb_dname)) {
1413 0 : TALLOC_FREE(talloced);
1414 0 : TALLOC_FREE(fullname);
1415 0 : TALLOC_FREE(smb_dname_full);
1416 0 : TALLOC_FREE(smb_dname);
1417 0 : DBG_DEBUG("got msdfs link name %s "
1418 : "- can't delete directory %s\n",
1419 : dname,
1420 : fsp_str_dbg(fsp));
1421 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1422 0 : break;
1423 : }
1424 2 : TALLOC_FREE(smb_dname);
1425 : }
1426 : /* Not a DFS link - could it be a dangling symlink ? */
1427 4 : ret = SMB_VFS_STAT(conn, smb_dname_full);
1428 4 : if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
1429 : /*
1430 : * Dangling symlink.
1431 : * Allow if "delete veto files = yes"
1432 : */
1433 4 : if (lp_delete_veto_files(SNUM(conn))) {
1434 2 : TALLOC_FREE(talloced);
1435 2 : TALLOC_FREE(fullname);
1436 2 : TALLOC_FREE(smb_dname_full);
1437 2 : continue;
1438 : }
1439 : }
1440 2 : DBG_DEBUG("got symlink name %s - "
1441 : "can't delete directory %s\n",
1442 : dname,
1443 : fsp_str_dbg(fsp));
1444 2 : TALLOC_FREE(talloced);
1445 2 : TALLOC_FREE(fullname);
1446 2 : TALLOC_FREE(smb_dname_full);
1447 2 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1448 2 : break;
1449 : }
1450 :
1451 : /* Not a symlink, get a pathref. */
1452 144 : status = synthetic_pathref(talloc_tos(),
1453 : fsp,
1454 : dname,
1455 : NULL,
1456 144 : &smb_dname_full->st,
1457 138 : fsp->fsp_name->twrp,
1458 144 : fsp->fsp_name->flags,
1459 : &direntry_fname);
1460 144 : if (!NT_STATUS_IS_OK(status)) {
1461 0 : status = map_nt_error_from_unix(errno);
1462 0 : TALLOC_FREE(talloced);
1463 0 : TALLOC_FREE(fullname);
1464 0 : TALLOC_FREE(smb_dname_full);
1465 0 : break;
1466 : }
1467 :
1468 144 : if (!is_visible_fsp(direntry_fname->fsp)) {
1469 : /*
1470 : * Hidden file.
1471 : * Allow if "delete veto files = yes"
1472 : */
1473 4 : if (lp_delete_veto_files(SNUM(conn))) {
1474 2 : TALLOC_FREE(talloced);
1475 2 : TALLOC_FREE(fullname);
1476 2 : TALLOC_FREE(smb_dname_full);
1477 2 : TALLOC_FREE(direntry_fname);
1478 2 : continue;
1479 : }
1480 : }
1481 :
1482 142 : TALLOC_FREE(talloced);
1483 142 : TALLOC_FREE(fullname);
1484 142 : TALLOC_FREE(smb_dname_full);
1485 142 : TALLOC_FREE(direntry_fname);
1486 :
1487 142 : DBG_DEBUG("got name %s - can't delete\n", dname);
1488 136 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1489 136 : break;
1490 : }
1491 11248 : TALLOC_FREE(talloced);
1492 11248 : TALLOC_FREE(dir_hnd);
1493 :
1494 11248 : if (!NT_STATUS_IS_OK(status)) {
1495 144 : return status;
1496 : }
1497 :
1498 21650 : if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1499 16665 : lp_strict_rename(SNUM(conn)) &&
1500 6119 : have_file_open_below(fsp->conn, fsp->fsp_name))
1501 : {
1502 0 : return NT_STATUS_ACCESS_DENIED;
1503 : }
1504 :
1505 11104 : return NT_STATUS_OK;
1506 : }
|