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 30667 : bool init_dptrs(struct smbd_server_connection *sconn)
92 : {
93 30667 : if (sconn->searches.dptr_bmap) {
94 0 : return true;
95 : }
96 :
97 30667 : sconn->searches.dptr_bmap = bitmap_talloc(
98 : sconn, MAX_DIRECTORY_HANDLES);
99 :
100 30667 : if (sconn->searches.dptr_bmap == NULL) {
101 0 : return false;
102 : }
103 :
104 29825 : 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 18534 : 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 18534 : struct smbd_server_connection *sconn = conn->sconn;
206 18534 : struct dptr_struct *dptr = NULL;
207 18534 : struct smb_Dir *dir_hnd = NULL;
208 176 : NTSTATUS status;
209 :
210 18534 : DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
211 :
212 18534 : 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 18534 : if (!wcard) {
218 0 : return NT_STATUS_INVALID_PARAMETER;
219 : }
220 :
221 18534 : 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 18534 : status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
228 18534 : if (!NT_STATUS_IS_OK(status)) {
229 0 : return status;
230 : }
231 :
232 18534 : dptr = talloc_zero(NULL, struct dptr_struct);
233 18534 : 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 18534 : dptr->conn = conn;
240 18534 : dptr->dir_hnd = dir_hnd;
241 18534 : dptr->wcard = talloc_strdup(dptr, wcard);
242 18534 : if (!dptr->wcard) {
243 0 : TALLOC_FREE(dptr);
244 0 : TALLOC_FREE(dir_hnd);
245 0 : return NT_STATUS_NO_MEMORY;
246 : }
247 18534 : if ((req != NULL && req->posix_pathnames) || ISDOT(wcard)) {
248 92 : dptr->has_wild = True;
249 : } else {
250 18442 : dptr->has_wild = ms_has_wild(dptr->wcard);
251 : }
252 :
253 18534 : dptr->attr = attr;
254 :
255 18534 : if (sconn->using_smb2) {
256 9855 : 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 18534 : done:
302 18534 : DBG_INFO("creating new dirptr [%d] for path [%s]\n",
303 : dptr->dnum, fsp_str_dbg(fsp));
304 :
305 18534 : *dptr_ret = dptr;
306 :
307 18534 : return NT_STATUS_OK;
308 : }
309 :
310 :
311 : /****************************************************************************
312 : Wrapper functions to access the lower level directory handles.
313 : ****************************************************************************/
314 :
315 18534 : void dptr_CloseDir(files_struct *fsp)
316 : {
317 18534 : struct smbd_server_connection *sconn = NULL;
318 :
319 18534 : if (fsp->dptr == NULL) {
320 0 : return;
321 : }
322 18534 : 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 18534 : DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
330 :
331 18534 : if (sconn != NULL && !sconn->using_smb2) {
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 18534 : TALLOC_FREE(fsp->dptr->dir_hnd);
350 18534 : TALLOC_FREE(fsp->dptr);
351 : }
352 :
353 3108 : void dptr_RewindDir(struct dptr_struct *dptr)
354 : {
355 3108 : RewindDir(dptr->dir_hnd);
356 3108 : dptr->did_stat = false;
357 3108 : TALLOC_FREE(dptr->overflow.fname);
358 3108 : TALLOC_FREE(dptr->overflow.smb_fname);
359 3108 : }
360 :
361 83436 : unsigned int dptr_FileNumber(struct dptr_struct *dptr)
362 : {
363 83436 : 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 1447489 : bool dptr_case_sensitive(struct dptr_struct *dptr)
387 : {
388 1447489 : 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 1480611 : char *dptr_ReadDirName(TALLOC_CTX *ctx, struct dptr_struct *dptr)
396 : {
397 1480611 : struct stat_ex st = {
398 : .st_ex_nlink = 0,
399 : };
400 1480611 : struct smb_Dir *dir_hnd = dptr->dir_hnd;
401 1480611 : struct files_struct *dir_fsp = dir_hnd->fsp;
402 1480611 : struct smb_filename *dir_name = dir_fsp->fsp_name;
403 404 : struct smb_filename smb_fname_base;
404 1480611 : bool retry_scanning = false;
405 404 : int ret;
406 1480611 : int flags = 0;
407 :
408 1480611 : if (dptr->has_wild) {
409 1476654 : const char *name_temp = NULL;
410 1476654 : char *talloced = NULL;
411 1476654 : name_temp = ReadDirName(dir_hnd, &talloced);
412 1476654 : if (name_temp == NULL) {
413 26022 : return NULL;
414 : }
415 1450543 : if (talloced != NULL) {
416 430 : return talloc_move(ctx, &talloced);
417 : }
418 1450113 : return talloc_strdup(ctx, name_temp);
419 : }
420 :
421 3957 : 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 1958 : return NULL;
428 : }
429 1999 : dptr->did_stat = true;
430 :
431 : /* Create an smb_filename with stream_name == NULL. */
432 1999 : smb_fname_base = (struct smb_filename){
433 1999 : .base_name = dptr->wcard,
434 1999 : .flags = dir_name->flags,
435 1999 : .twrp = dir_name->twrp,
436 : };
437 :
438 1999 : if (dir_name->flags & SMB_FILENAME_POSIX_PATH) {
439 13 : flags |= AT_SYMLINK_NOFOLLOW;
440 : }
441 :
442 1999 : ret = SMB_VFS_FSTATAT(dptr->conn, dir_fsp, &smb_fname_base, &st, flags);
443 1999 : if (ret == 0) {
444 1685 : 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 314 : 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 314 : 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 628 : retry_scanning |=
467 628 : (!dir_hnd->case_sensitive &&
468 314 : (dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH));
469 :
470 314 : if (retry_scanning) {
471 314 : char *found_name = NULL;
472 0 : NTSTATUS status;
473 :
474 314 : status = get_real_filename_at(dir_fsp,
475 314 : dptr->wcard,
476 : ctx,
477 : &found_name);
478 314 : if (NT_STATUS_IS_OK(status)) {
479 47 : return found_name;
480 : }
481 : }
482 :
483 267 : 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 941718 : 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 : bool (*mode_fn)(TALLOC_CTX *ctx,
521 : void *private_data,
522 : struct files_struct *dirfsp,
523 : struct smb_filename *smb_fname,
524 : bool get_dosmode,
525 : uint32_t *_mode),
526 : void *private_data,
527 : char **_fname,
528 : struct smb_filename **_smb_fname,
529 : uint32_t *_mode)
530 : {
531 941718 : connection_struct *conn = dirptr->conn;
532 941718 : struct smb_Dir *dir_hnd = dirptr->dir_hnd;
533 941718 : struct smb_filename *dir_fname = dir_hnd->dir_smb_fname;
534 941718 : bool posix = (dir_fname->flags & SMB_FILENAME_POSIX_PATH);
535 941718 : const char *dpath = dir_fname->base_name;
536 316 : NTSTATUS status;
537 :
538 941718 : *_smb_fname = NULL;
539 941718 : *_mode = 0;
540 :
541 941718 : if (dirptr->overflow.smb_fname != NULL) {
542 668 : *_fname = talloc_move(ctx, &dirptr->overflow.fname);
543 668 : *_smb_fname = talloc_move(ctx, &dirptr->overflow.smb_fname);
544 668 : *_mode = dirptr->overflow.mode;
545 668 : return true;
546 : }
547 :
548 941050 : if (dont_descend && (dptr_FileNumber(dirptr) >= 2)) {
549 : /*
550 : * . and .. were returned first, we're done showing
551 : * the directory as empty.
552 : */
553 0 : return false;
554 : }
555 :
556 23909 : while (true) {
557 964555 : char *dname = NULL;
558 964555 : char *fname = NULL;
559 964555 : struct smb_filename *smb_fname = NULL;
560 964555 : struct open_symlink_err *symlink_err = NULL;
561 964555 : uint32_t mode = 0;
562 964555 : bool get_dosmode = get_dosmode_in;
563 404 : bool ok;
564 :
565 964555 : dname = dptr_ReadDirName(ctx, dirptr);
566 :
567 964555 : DBG_DEBUG("dir [%s] dirptr [%p] offset [%u] => "
568 : "dname [%s]\n",
569 : smb_fname_str_dbg(dir_fname),
570 : dirptr,
571 : dir_hnd->file_number,
572 : dname ? dname : "(finished)");
573 :
574 964555 : if (dname == NULL) {
575 941050 : return false;
576 : }
577 :
578 937269 : if (IS_VETO_PATH(conn, dname)) {
579 6 : TALLOC_FREE(dname);
580 23505 : continue;
581 : }
582 :
583 : /*
584 : * fname may get mangled, dname is never mangled.
585 : * Whenever we're accessing the filesystem we use
586 : * pathreal which is composed from dname.
587 : */
588 :
589 937263 : ok = match_fn(ctx, private_data, dname, mask, &fname);
590 937263 : if (!ok) {
591 6241 : TALLOC_FREE(dname);
592 6241 : continue;
593 : }
594 :
595 931022 : if (ISDOT(dname) || ISDOTDOT(dname)) {
596 :
597 34956 : const char *dotname = dname;
598 :
599 34956 : if (ISDOTDOT(dname) && ISDOT(dpath)) {
600 : /*
601 : * Handle ".." in toplevel like "." to not
602 : * leak info from outside the share.
603 : */
604 1515 : dotname = ".";
605 : }
606 :
607 34956 : smb_fname = synthetic_smb_fname(talloc_tos(),
608 : dotname,
609 : NULL,
610 : NULL,
611 : dir_fname->twrp,
612 : dir_fname->flags);
613 34956 : if (smb_fname == NULL) {
614 0 : TALLOC_FREE(dname);
615 0 : return false;
616 : }
617 :
618 34956 : status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
619 34956 : if (!NT_STATUS_IS_OK(status)) {
620 4 : DBG_INFO("Could not open \"..\": %s\n",
621 : nt_errstr(status));
622 4 : TALLOC_FREE(smb_fname);
623 4 : TALLOC_FREE(dname);
624 4 : continue;
625 : }
626 :
627 34952 : mode = fdos_mode(smb_fname->fsp);
628 :
629 : /*
630 : * Don't leak INO/DEV/User SID/Group SID about
631 : * the containing directory of the share.
632 : */
633 34952 : if (ISDOT(dpath) && ISDOTDOT(dname)) {
634 : /*
635 : * Ensure posix fileid and sids are hidden
636 : */
637 1515 : smb_fname->st.st_ex_ino = 0;
638 1515 : smb_fname->st.st_ex_dev = 0;
639 1515 : smb_fname->st.st_ex_uid = -1;
640 1515 : smb_fname->st.st_ex_gid = -1;
641 : }
642 :
643 34952 : goto done;
644 : }
645 :
646 896066 : status = openat_pathref_fsp_nosymlink(talloc_tos(),
647 : conn,
648 896066 : dir_hnd->fsp,
649 : dname,
650 : dir_fname->twrp,
651 : posix,
652 : &smb_fname,
653 : &symlink_err);
654 :
655 896066 : if (NT_STATUS_IS_OK(status)) {
656 893130 : bool visible = is_visible_fsp(smb_fname->fsp);
657 893130 : if (!visible) {
658 32 : TALLOC_FREE(smb_fname);
659 32 : TALLOC_FREE(dname);
660 32 : TALLOC_FREE(fname);
661 32 : continue;
662 : }
663 2936 : } else if (NT_STATUS_EQUAL(status,
664 : NT_STATUS_STOPPED_ON_SYMLINK)) {
665 2742 : struct symlink_reparse_struct *reparse =
666 2742 : symlink_err->reparse;
667 2742 : const char *target = reparse->substitute_name;
668 0 : bool is_msdfs_link;
669 :
670 2742 : is_msdfs_link = lp_host_msdfs();
671 2742 : is_msdfs_link &= lp_msdfs_root(SNUM(conn));
672 2742 : is_msdfs_link &= (strncmp(target, "msdfs:", 6) == 0);
673 :
674 2742 : if (is_msdfs_link) {
675 370 : char *path = NULL;
676 :
677 370 : path = full_path_from_dirfsp_at_basename(
678 : talloc_tos(),
679 370 : dir_hnd->fsp,
680 : dname);
681 370 : if (path == NULL) {
682 0 : return false;
683 : }
684 :
685 370 : smb_fname =
686 370 : synthetic_smb_fname(talloc_tos(),
687 : path,
688 : NULL,
689 370 : &symlink_err->st,
690 : dir_fname->twrp,
691 : dir_fname->flags);
692 370 : TALLOC_FREE(path);
693 370 : if (smb_fname == NULL) {
694 0 : return false;
695 : }
696 :
697 370 : DBG_INFO("Masquerading msdfs link %s as a"
698 : "directory\n",
699 : smb_fname->base_name);
700 :
701 370 : smb_fname->st.st_ex_mode =
702 370 : (smb_fname->st.st_ex_mode & ~S_IFMT) |
703 : S_IFDIR;
704 :
705 740 : mode = dos_mode_msdfs(conn,
706 : dname,
707 370 : &smb_fname->st);
708 370 : get_dosmode = false;
709 370 : ask_sharemode = false;
710 422 : goto done;
711 : }
712 :
713 2372 : smb_fname = synthetic_smb_fname(talloc_tos(),
714 : dname,
715 : NULL,
716 2372 : &symlink_err->st,
717 : dir_fname->twrp,
718 : dir_fname->flags);
719 2372 : if (smb_fname == NULL) {
720 0 : return false;
721 : }
722 :
723 2372 : status = openat_pathref_fsp(dir_hnd->fsp, smb_fname);
724 :
725 2372 : if (posix) {
726 : /*
727 : * Posix always wants to see symlinks,
728 : * dangling or not. We've done the
729 : * openat_pathref_fsp() to fill in
730 : * smb_fname->fsp just in case it's
731 : * not dangling.
732 : */
733 52 : mode = FILE_ATTRIBUTE_NORMAL;
734 52 : get_dosmode = false;
735 52 : ask_sharemode = false;
736 52 : goto done;
737 : }
738 :
739 2320 : if (!NT_STATUS_IS_OK(status)) {
740 : /*
741 : * Dangling symlink. Hide.
742 : */
743 492 : TALLOC_FREE(smb_fname);
744 492 : TALLOC_FREE(fname);
745 492 : TALLOC_FREE(dname);
746 686 : continue;
747 : }
748 : } else {
749 194 : DBG_NOTICE("Could not open %s: %s\n",
750 : dname,
751 : nt_errstr(status));
752 194 : TALLOC_FREE(dname);
753 194 : TALLOC_FREE(fname);
754 194 : TALLOC_FREE(smb_fname);
755 194 : continue;
756 : }
757 :
758 895063 : ok = mode_fn(ctx,
759 : private_data,
760 894926 : dir_hnd->fsp,
761 : smb_fname,
762 : get_dosmode,
763 : &mode);
764 894926 : if (!ok) {
765 0 : TALLOC_FREE(smb_fname);
766 0 : TALLOC_FREE(dname);
767 0 : TALLOC_FREE(fname);
768 0 : continue;
769 : }
770 :
771 894926 : done:
772 :
773 930300 : if (!dir_check_ftype(mode, dirtype)) {
774 16536 : DBG_INFO("[%s] attribs 0x%" PRIx32 " didn't match "
775 : "0x%" PRIx32 "\n",
776 : fname,
777 : mode,
778 : dirtype);
779 16536 : TALLOC_FREE(smb_fname);
780 16536 : TALLOC_FREE(dname);
781 16536 : TALLOC_FREE(fname);
782 16536 : continue;
783 : }
784 :
785 913764 : if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
786 115 : struct timespec write_time_ts;
787 115 : struct file_id fileid;
788 :
789 716776 : fileid = vfs_file_id_from_sbuf(conn,
790 716776 : &smb_fname->st);
791 716776 : get_file_infos(fileid, 0, NULL, &write_time_ts);
792 716776 : if (!is_omit_timespec(&write_time_ts)) {
793 918 : update_stat_ex_mtime(&smb_fname->st,
794 : write_time_ts);
795 : }
796 : }
797 :
798 913764 : DBG_NOTICE("mask=[%s] found %s fname=%s (%s)\n",
799 : mask,
800 : smb_fname_str_dbg(smb_fname),
801 : dname,
802 : fname);
803 :
804 913764 : TALLOC_FREE(dname);
805 :
806 913764 : *_smb_fname = talloc_move(ctx, &smb_fname);
807 913764 : if (*_smb_fname == NULL) {
808 0 : return false;
809 : }
810 913764 : *_fname = fname;
811 913764 : *_mode = mode;
812 :
813 913764 : return true;
814 : }
815 :
816 : return false;
817 : }
818 :
819 668 : void smbd_dirptr_push_overflow(struct dptr_struct *dirptr,
820 : char **_fname,
821 : struct smb_filename **_smb_fname,
822 : uint32_t mode)
823 : {
824 668 : SMB_ASSERT(dirptr->overflow.fname == NULL);
825 668 : SMB_ASSERT(dirptr->overflow.smb_fname == NULL);
826 :
827 668 : dirptr->overflow.fname = talloc_move(dirptr, _fname);
828 668 : dirptr->overflow.smb_fname = talloc_move(dirptr, _smb_fname);
829 668 : dirptr->overflow.mode = mode;
830 668 : }
831 :
832 892886 : void smbd_dirptr_set_last_name_sent(struct dptr_struct *dirptr,
833 : char **_fname)
834 : {
835 892886 : TALLOC_FREE(dirptr->last_name_sent);
836 892886 : dirptr->last_name_sent = talloc_move(dirptr, _fname);
837 892886 : }
838 :
839 1424 : char *smbd_dirptr_get_last_name_sent(struct dptr_struct *dirptr)
840 : {
841 1424 : return dirptr->last_name_sent;
842 : }
843 :
844 : /*******************************************************************
845 : Check to see if a user can read an fsp . This is only approximate,
846 : it is used as part of the "hide unreadable" option. Don't
847 : use it for anything security sensitive.
848 : ********************************************************************/
849 :
850 118 : static bool user_can_read_fsp(struct files_struct *fsp)
851 : {
852 0 : NTSTATUS status;
853 118 : uint32_t rejected_share_access = 0;
854 118 : uint32_t rejected_mask = 0;
855 118 : struct security_descriptor *sd = NULL;
856 118 : uint32_t access_mask = FILE_READ_DATA|
857 : FILE_READ_EA|
858 : FILE_READ_ATTRIBUTES|
859 : SEC_STD_READ_CONTROL;
860 :
861 : /*
862 : * Never hide files from the root user.
863 : * We use (uid_t)0 here not sec_initial_uid()
864 : * as make test uses a single user context.
865 : */
866 :
867 118 : if (get_current_uid(fsp->conn) == (uid_t)0) {
868 0 : return true;
869 : }
870 :
871 : /*
872 : * We can't directly use smbd_check_access_rights_fsp()
873 : * here, as this implicitly grants FILE_READ_ATTRIBUTES
874 : * which the Windows access-based-enumeration code
875 : * explicitly checks for on the file security descriptor.
876 : * See bug:
877 : *
878 : * https://bugzilla.samba.org/show_bug.cgi?id=10252
879 : *
880 : * and the smb2.acl2.ACCESSBASED test for details.
881 : */
882 :
883 118 : rejected_share_access = access_mask & ~(fsp->conn->share_access);
884 118 : if (rejected_share_access) {
885 0 : DBG_DEBUG("rejected share access 0x%x "
886 : "on %s (0x%x)\n",
887 : (unsigned int)access_mask,
888 : fsp_str_dbg(fsp),
889 : (unsigned int)rejected_share_access);
890 0 : return false;
891 : }
892 :
893 118 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
894 : (SECINFO_OWNER |
895 : SECINFO_GROUP |
896 : SECINFO_DACL),
897 : talloc_tos(),
898 : &sd);
899 :
900 118 : if (!NT_STATUS_IS_OK(status)) {
901 0 : DBG_DEBUG("Could not get acl "
902 : "on %s: %s\n",
903 : fsp_str_dbg(fsp),
904 : nt_errstr(status));
905 0 : return false;
906 : }
907 :
908 118 : status = se_file_access_check(sd,
909 118 : get_current_nttok(fsp->conn),
910 : false,
911 : access_mask,
912 : &rejected_mask);
913 :
914 118 : TALLOC_FREE(sd);
915 :
916 118 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
917 14 : DBG_DEBUG("rejected bits 0x%x read access for %s\n",
918 : (unsigned int)rejected_mask,
919 : fsp_str_dbg(fsp));
920 14 : return false;
921 : }
922 104 : return true;
923 : }
924 :
925 : /*******************************************************************
926 : Check to see if a user can write to an fsp.
927 : Always return true for directories.
928 : This is only approximate,
929 : it is used as part of the "hide unwriteable" option. Don't
930 : use it for anything security sensitive.
931 : ********************************************************************/
932 :
933 110 : static bool user_can_write_fsp(struct files_struct *fsp)
934 : {
935 : /*
936 : * Never hide files from the root user.
937 : * We use (uid_t)0 here not sec_initial_uid()
938 : * as make test uses a single user context.
939 : */
940 :
941 110 : if (get_current_uid(fsp->conn) == (uid_t)0) {
942 0 : return true;
943 : }
944 :
945 110 : if (fsp->fsp_flags.is_directory) {
946 18 : return true;
947 : }
948 :
949 92 : return can_write_to_fsp(fsp);
950 : }
951 :
952 : /*******************************************************************
953 : Is a file a "special" type ?
954 : ********************************************************************/
955 :
956 0 : static bool file_is_special(connection_struct *conn,
957 : const struct smb_filename *smb_fname)
958 : {
959 : /*
960 : * Never hide files from the root user.
961 : * We use (uid_t)0 here not sec_initial_uid()
962 : * as make test uses a single user context.
963 : */
964 :
965 0 : if (get_current_uid(conn) == (uid_t)0) {
966 0 : return False;
967 : }
968 :
969 0 : SMB_ASSERT(VALID_STAT(smb_fname->st));
970 :
971 0 : if (S_ISREG(smb_fname->st.st_ex_mode) ||
972 0 : S_ISDIR(smb_fname->st.st_ex_mode) ||
973 0 : S_ISLNK(smb_fname->st.st_ex_mode))
974 0 : return False;
975 :
976 0 : return True;
977 : }
978 :
979 : /*******************************************************************
980 : Should the file be seen by the client?
981 : ********************************************************************/
982 :
983 893282 : bool is_visible_fsp(struct files_struct *fsp)
984 : {
985 893282 : bool hide_unreadable = false;
986 893282 : bool hide_unwriteable = false;
987 893282 : bool hide_special = false;
988 893282 : int hide_new_files_timeout = 0;
989 893282 : const char *last_component = NULL;
990 :
991 : /*
992 : * If the file does not exist, there's no point checking
993 : * the configuration options. We succeed, on the basis that the
994 : * checks *might* have passed if the file was present.
995 : */
996 893282 : if (fsp == NULL) {
997 0 : return true;
998 : }
999 :
1000 893282 : hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
1001 893282 : hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
1002 893282 : hide_special = lp_hide_special_files(SNUM(fsp->conn));
1003 893282 : hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
1004 :
1005 893282 : if (!hide_unreadable &&
1006 893021 : !hide_unwriteable &&
1007 893054 : !hide_special &&
1008 143 : (hide_new_files_timeout == 0))
1009 : {
1010 892596 : return true;
1011 : }
1012 :
1013 543 : fsp = metadata_fsp(fsp);
1014 :
1015 : /* Get the last component of the base name. */
1016 543 : last_component = strrchr_m(fsp->fsp_name->base_name, '/');
1017 543 : if (!last_component) {
1018 519 : last_component = fsp->fsp_name->base_name;
1019 : } else {
1020 24 : last_component++; /* Go past '/' */
1021 : }
1022 :
1023 543 : if (ISDOT(last_component) || ISDOTDOT(last_component)) {
1024 0 : return true; /* . and .. are always visible. */
1025 : }
1026 :
1027 543 : if (fsp_get_pathref_fd(fsp) == -1) {
1028 : /*
1029 : * Symlink in POSIX mode or MS-DFS.
1030 : * We've checked veto files so the
1031 : * only thing we can check is the
1032 : * hide_new_files_timeout.
1033 : */
1034 0 : if ((hide_new_files_timeout != 0) &&
1035 0 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1036 0 : double age = timespec_elapsed(
1037 0 : &fsp->fsp_name->st.st_ex_mtime);
1038 :
1039 0 : if (age < (double)hide_new_files_timeout) {
1040 0 : return false;
1041 : }
1042 : }
1043 0 : return true;
1044 : }
1045 :
1046 : /* Honour _hide unreadable_ option */
1047 543 : if (hide_unreadable && !user_can_read_fsp(fsp)) {
1048 14 : DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
1049 14 : return false;
1050 : }
1051 :
1052 : /* Honour _hide unwriteable_ option */
1053 529 : if (hide_unwriteable && !user_can_write_fsp(fsp)) {
1054 12 : DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
1055 12 : return false;
1056 : }
1057 :
1058 : /* Honour _hide_special_ option */
1059 517 : if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
1060 0 : DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
1061 0 : return false;
1062 : }
1063 :
1064 517 : if ((hide_new_files_timeout != 0) &&
1065 315 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1066 12 : double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1067 :
1068 12 : if (age < (double)hide_new_files_timeout) {
1069 10 : return false;
1070 : }
1071 : }
1072 :
1073 507 : return true;
1074 : }
1075 :
1076 304038 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1077 : {
1078 304038 : files_struct *fsp = dir_hnd->fsp;
1079 :
1080 304038 : SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1081 304038 : fsp_set_fd(fsp, -1);
1082 304038 : if (fsp->dptr != NULL) {
1083 18534 : SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1084 18534 : fsp->dptr->dir_hnd = NULL;
1085 : }
1086 304038 : dir_hnd->fsp = NULL;
1087 304038 : return 0;
1088 : }
1089 :
1090 : /*******************************************************************
1091 : Open a directory.
1092 : ********************************************************************/
1093 :
1094 285504 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1095 : {
1096 285504 : files_struct *fsp = dir_hnd->fsp;
1097 :
1098 285504 : smb_Dir_destructor(dir_hnd);
1099 285504 : file_free(NULL, fsp);
1100 285504 : return 0;
1101 : }
1102 :
1103 13119 : NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1104 : connection_struct *conn,
1105 : const struct smb_filename *smb_dname,
1106 : const char *mask,
1107 : uint32_t attr,
1108 : struct smb_Dir **_dir_hnd)
1109 : {
1110 13119 : struct files_struct *fsp = NULL;
1111 13119 : struct smb_Dir *dir_hnd = NULL;
1112 74 : NTSTATUS status;
1113 :
1114 13119 : status = open_internal_dirfsp(conn,
1115 : smb_dname,
1116 : O_RDONLY,
1117 : &fsp);
1118 13119 : if (!NT_STATUS_IS_OK(status)) {
1119 0 : return status;
1120 : }
1121 :
1122 13119 : status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1123 13119 : if (!NT_STATUS_IS_OK(status)) {
1124 0 : return status;
1125 : }
1126 :
1127 : /*
1128 : * This overwrites the destructor set by OpenDir_fsp() but
1129 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1130 : * destructor.
1131 : */
1132 13119 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1133 :
1134 13119 : *_dir_hnd = dir_hnd;
1135 13119 : return NT_STATUS_OK;
1136 : }
1137 :
1138 272386 : NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1139 : struct files_struct *dirfsp,
1140 : const char *mask,
1141 : uint32_t attr,
1142 : struct smb_Dir **_dir_hnd)
1143 : {
1144 272386 : struct files_struct *fsp = NULL;
1145 272386 : struct smb_Dir *dir_hnd = NULL;
1146 883 : NTSTATUS status;
1147 :
1148 272386 : status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1149 272386 : if (!NT_STATUS_IS_OK(status)) {
1150 1 : return status;
1151 : }
1152 :
1153 272385 : status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1154 272385 : if (!NT_STATUS_IS_OK(status)) {
1155 0 : return status;
1156 : }
1157 :
1158 : /*
1159 : * This overwrites the destructor set by OpenDir_fsp() but
1160 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1161 : * destructor.
1162 : */
1163 272385 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1164 :
1165 272385 : *_dir_hnd = dir_hnd;
1166 272385 : return NT_STATUS_OK;
1167 : }
1168 :
1169 : /*******************************************************************
1170 : Open a directory from an fsp.
1171 : ********************************************************************/
1172 :
1173 304038 : static NTSTATUS OpenDir_fsp(
1174 : TALLOC_CTX *mem_ctx,
1175 : connection_struct *conn,
1176 : files_struct *fsp,
1177 : const char *mask,
1178 : uint32_t attr,
1179 : struct smb_Dir **_dir_hnd)
1180 : {
1181 304038 : struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1182 1133 : NTSTATUS status;
1183 :
1184 304038 : if (!dir_hnd) {
1185 0 : return NT_STATUS_NO_MEMORY;
1186 : }
1187 :
1188 304038 : if (!fsp->fsp_flags.is_directory) {
1189 0 : status = NT_STATUS_INVALID_HANDLE;
1190 0 : goto fail;
1191 : }
1192 :
1193 304038 : if (fsp_get_io_fd(fsp) == -1) {
1194 0 : status = NT_STATUS_INVALID_HANDLE;
1195 0 : goto fail;
1196 : }
1197 :
1198 304038 : dir_hnd->conn = conn;
1199 :
1200 304038 : dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1201 304038 : if (!dir_hnd->dir_smb_fname) {
1202 0 : status = NT_STATUS_NO_MEMORY;
1203 0 : goto fail;
1204 : }
1205 :
1206 304038 : dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1207 304038 : if (dir_hnd->dir == NULL) {
1208 0 : status = map_nt_error_from_unix(errno);
1209 0 : goto fail;
1210 : }
1211 304038 : dir_hnd->fsp = fsp;
1212 304038 : if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1213 19 : dir_hnd->case_sensitive = true;
1214 : } else {
1215 304019 : dir_hnd->case_sensitive = conn->case_sensitive;
1216 : }
1217 :
1218 304038 : talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1219 :
1220 304038 : *_dir_hnd = dir_hnd;
1221 304038 : return NT_STATUS_OK;
1222 :
1223 0 : fail:
1224 0 : TALLOC_FREE(dir_hnd);
1225 0 : return status;
1226 : }
1227 :
1228 :
1229 : /*******************************************************************
1230 : Read from a directory.
1231 : Return directory entry, current offset, and optional stat information.
1232 : Don't check for veto or invisible files.
1233 : ********************************************************************/
1234 :
1235 161125140 : const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
1236 : {
1237 7211 : const char *n;
1238 161125140 : char *talloced = NULL;
1239 161125140 : connection_struct *conn = dir_hnd->conn;
1240 :
1241 161125140 : if (dir_hnd->file_number < 2) {
1242 610252 : if (dir_hnd->file_number == 0) {
1243 304083 : n = ".";
1244 : } else {
1245 305123 : n = "..";
1246 : }
1247 610252 : dir_hnd->file_number++;
1248 610252 : *ptalloced = NULL;
1249 610252 : return n;
1250 : }
1251 :
1252 321624577 : while ((n = vfs_readdirname(conn,
1253 161114808 : dir_hnd->fsp,
1254 161114808 : dir_hnd->dir,
1255 : &talloced))) {
1256 : /* Ignore . and .. - we've already returned them. */
1257 160808579 : if (ISDOT(n) || ISDOTDOT(n)) {
1258 599920 : TALLOC_FREE(talloced);
1259 599920 : continue;
1260 : }
1261 160208659 : *ptalloced = talloced;
1262 160208659 : dir_hnd->file_number++;
1263 160208659 : return n;
1264 : }
1265 306229 : *ptalloced = NULL;
1266 306229 : return NULL;
1267 : }
1268 :
1269 : /*******************************************************************
1270 : Rewind to the start.
1271 : ********************************************************************/
1272 :
1273 3112 : void RewindDir(struct smb_Dir *dir_hnd)
1274 : {
1275 3112 : SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1276 3112 : dir_hnd->file_number = 0;
1277 3112 : }
1278 :
1279 : struct files_below_forall_state {
1280 : char *dirpath;
1281 : ssize_t dirpath_len;
1282 : int (*fn)(struct file_id fid, const struct share_mode_data *data,
1283 : void *private_data);
1284 : void *private_data;
1285 : };
1286 :
1287 18713 : static int files_below_forall_fn(struct file_id fid,
1288 : const struct share_mode_data *data,
1289 : void *private_data)
1290 : {
1291 18713 : struct files_below_forall_state *state = private_data;
1292 0 : char tmpbuf[PATH_MAX];
1293 0 : char *fullpath, *to_free;
1294 0 : ssize_t len;
1295 :
1296 18713 : len = full_path_tos(data->servicepath, data->base_name,
1297 : tmpbuf, sizeof(tmpbuf),
1298 : &fullpath, &to_free);
1299 18713 : if (len == -1) {
1300 0 : return 0;
1301 : }
1302 18713 : if (state->dirpath_len >= len) {
1303 : /*
1304 : * Filter files above dirpath
1305 : */
1306 16407 : goto out;
1307 : }
1308 2306 : if (fullpath[state->dirpath_len] != '/') {
1309 : /*
1310 : * Filter file that don't have a path separator at the end of
1311 : * dirpath's length
1312 : */
1313 2252 : goto out;
1314 : }
1315 :
1316 54 : if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1317 : /*
1318 : * Not a parent
1319 : */
1320 42 : goto out;
1321 : }
1322 :
1323 12 : TALLOC_FREE(to_free);
1324 12 : return state->fn(fid, data, state->private_data);
1325 :
1326 18701 : out:
1327 18701 : TALLOC_FREE(to_free);
1328 18701 : return 0;
1329 : }
1330 :
1331 6241 : static int files_below_forall(connection_struct *conn,
1332 : const struct smb_filename *dir_name,
1333 : int (*fn)(struct file_id fid,
1334 : const struct share_mode_data *data,
1335 : void *private_data),
1336 : void *private_data)
1337 : {
1338 6241 : struct files_below_forall_state state = {
1339 : .fn = fn,
1340 : .private_data = private_data,
1341 : };
1342 0 : int ret;
1343 0 : char tmpbuf[PATH_MAX];
1344 0 : char *to_free;
1345 :
1346 12482 : state.dirpath_len = full_path_tos(conn->connectpath,
1347 6241 : dir_name->base_name,
1348 : tmpbuf, sizeof(tmpbuf),
1349 : &state.dirpath, &to_free);
1350 6241 : if (state.dirpath_len == -1) {
1351 0 : return -1;
1352 : }
1353 :
1354 6241 : ret = share_mode_forall(files_below_forall_fn, &state);
1355 6241 : TALLOC_FREE(to_free);
1356 6241 : return ret;
1357 : }
1358 :
1359 : struct have_file_open_below_state {
1360 : bool found_one;
1361 : };
1362 :
1363 12 : static int have_file_open_below_fn(struct file_id fid,
1364 : const struct share_mode_data *data,
1365 : void *private_data)
1366 : {
1367 12 : struct have_file_open_below_state *state = private_data;
1368 12 : state->found_one = true;
1369 12 : return 1;
1370 : }
1371 :
1372 6241 : bool have_file_open_below(connection_struct *conn,
1373 : const struct smb_filename *name)
1374 : {
1375 6241 : struct have_file_open_below_state state = {
1376 : .found_one = false,
1377 : };
1378 0 : int ret;
1379 :
1380 6241 : if (!VALID_STAT(name->st)) {
1381 0 : return false;
1382 : }
1383 6241 : if (!S_ISDIR(name->st.st_ex_mode)) {
1384 0 : return false;
1385 : }
1386 :
1387 6241 : ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1388 6241 : if (ret == -1) {
1389 0 : return false;
1390 : }
1391 :
1392 6241 : return state.found_one;
1393 : }
1394 :
1395 : /*****************************************************************
1396 : Is this directory empty ?
1397 : *****************************************************************/
1398 :
1399 11200 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1400 : {
1401 11200 : NTSTATUS status = NT_STATUS_OK;
1402 11200 : const char *dname = NULL;
1403 11200 : char *talloced = NULL;
1404 11200 : struct connection_struct *conn = fsp->conn;
1405 11200 : struct smb_Dir *dir_hnd = NULL;
1406 :
1407 11200 : status = OpenDir(
1408 11200 : talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1409 11200 : if (!NT_STATUS_IS_OK(status)) {
1410 0 : return status;
1411 : }
1412 :
1413 33608 : while ((dname = ReadDirName(dir_hnd, &talloced))) {
1414 22556 : struct smb_filename *smb_dname_full = NULL;
1415 22556 : struct smb_filename *direntry_fname = NULL;
1416 22556 : char *fullname = NULL;
1417 148 : int ret;
1418 :
1419 22556 : if (ISDOT(dname) || (ISDOTDOT(dname))) {
1420 22400 : TALLOC_FREE(talloced);
1421 22408 : continue;
1422 : }
1423 156 : if (IS_VETO_PATH(conn, dname)) {
1424 4 : TALLOC_FREE(talloced);
1425 4 : continue;
1426 : }
1427 :
1428 152 : fullname = talloc_asprintf(talloc_tos(),
1429 : "%s/%s",
1430 152 : fsp->fsp_name->base_name,
1431 : dname);
1432 152 : if (fullname == NULL) {
1433 0 : status = NT_STATUS_NO_MEMORY;
1434 0 : break;
1435 : }
1436 :
1437 152 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1438 : fullname,
1439 : NULL,
1440 : NULL,
1441 146 : fsp->fsp_name->twrp,
1442 152 : fsp->fsp_name->flags);
1443 152 : if (smb_dname_full == NULL) {
1444 0 : TALLOC_FREE(talloced);
1445 0 : TALLOC_FREE(fullname);
1446 0 : status = NT_STATUS_NO_MEMORY;
1447 0 : break;
1448 : }
1449 :
1450 152 : ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1451 152 : if (ret != 0) {
1452 0 : status = map_nt_error_from_unix(errno);
1453 0 : TALLOC_FREE(talloced);
1454 0 : TALLOC_FREE(fullname);
1455 0 : TALLOC_FREE(smb_dname_full);
1456 0 : break;
1457 : }
1458 :
1459 152 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1460 : /* Could it be an msdfs link ? */
1461 8 : if (lp_host_msdfs() &&
1462 4 : lp_msdfs_root(SNUM(conn))) {
1463 0 : struct smb_filename *smb_dname;
1464 2 : smb_dname = synthetic_smb_fname(talloc_tos(),
1465 : dname,
1466 : NULL,
1467 2 : &smb_dname_full->st,
1468 2 : fsp->fsp_name->twrp,
1469 2 : fsp->fsp_name->flags);
1470 2 : if (smb_dname == NULL) {
1471 0 : TALLOC_FREE(talloced);
1472 0 : TALLOC_FREE(fullname);
1473 0 : TALLOC_FREE(smb_dname_full);
1474 0 : status = NT_STATUS_NO_MEMORY;
1475 0 : break;
1476 : }
1477 2 : if (is_msdfs_link(fsp, smb_dname)) {
1478 0 : TALLOC_FREE(talloced);
1479 0 : TALLOC_FREE(fullname);
1480 0 : TALLOC_FREE(smb_dname_full);
1481 0 : TALLOC_FREE(smb_dname);
1482 0 : DBG_DEBUG("got msdfs link name %s "
1483 : "- can't delete directory %s\n",
1484 : dname,
1485 : fsp_str_dbg(fsp));
1486 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1487 0 : break;
1488 : }
1489 2 : TALLOC_FREE(smb_dname);
1490 : }
1491 : /* Not a DFS link - could it be a dangling symlink ? */
1492 4 : ret = SMB_VFS_STAT(conn, smb_dname_full);
1493 4 : if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
1494 : /*
1495 : * Dangling symlink.
1496 : * Allow if "delete veto files = yes"
1497 : */
1498 4 : if (lp_delete_veto_files(SNUM(conn))) {
1499 2 : TALLOC_FREE(talloced);
1500 2 : TALLOC_FREE(fullname);
1501 2 : TALLOC_FREE(smb_dname_full);
1502 2 : continue;
1503 : }
1504 : }
1505 2 : DBG_DEBUG("got symlink name %s - "
1506 : "can't delete directory %s\n",
1507 : dname,
1508 : fsp_str_dbg(fsp));
1509 2 : TALLOC_FREE(talloced);
1510 2 : TALLOC_FREE(fullname);
1511 2 : TALLOC_FREE(smb_dname_full);
1512 2 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1513 2 : break;
1514 : }
1515 :
1516 : /* Not a symlink, get a pathref. */
1517 148 : status = synthetic_pathref(talloc_tos(),
1518 : fsp,
1519 : dname,
1520 : NULL,
1521 148 : &smb_dname_full->st,
1522 142 : fsp->fsp_name->twrp,
1523 148 : fsp->fsp_name->flags,
1524 : &direntry_fname);
1525 148 : if (!NT_STATUS_IS_OK(status)) {
1526 0 : status = map_nt_error_from_unix(errno);
1527 0 : TALLOC_FREE(talloced);
1528 0 : TALLOC_FREE(fullname);
1529 0 : TALLOC_FREE(smb_dname_full);
1530 0 : break;
1531 : }
1532 :
1533 148 : if (!is_visible_fsp(direntry_fname->fsp)) {
1534 : /*
1535 : * Hidden file.
1536 : * Allow if "delete veto files = yes"
1537 : */
1538 4 : if (lp_delete_veto_files(SNUM(conn))) {
1539 2 : TALLOC_FREE(talloced);
1540 2 : TALLOC_FREE(fullname);
1541 2 : TALLOC_FREE(smb_dname_full);
1542 2 : TALLOC_FREE(direntry_fname);
1543 2 : continue;
1544 : }
1545 : }
1546 :
1547 146 : TALLOC_FREE(talloced);
1548 146 : TALLOC_FREE(fullname);
1549 146 : TALLOC_FREE(smb_dname_full);
1550 146 : TALLOC_FREE(direntry_fname);
1551 :
1552 146 : DBG_DEBUG("got name %s - can't delete\n", dname);
1553 140 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1554 140 : break;
1555 : }
1556 11200 : TALLOC_FREE(talloced);
1557 11200 : TALLOC_FREE(dir_hnd);
1558 :
1559 11200 : if (!NT_STATUS_IS_OK(status)) {
1560 148 : return status;
1561 : }
1562 :
1563 21546 : if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1564 16555 : lp_strict_rename(SNUM(conn)) &&
1565 6061 : have_file_open_below(fsp->conn, fsp->fsp_name))
1566 : {
1567 0 : return NT_STATUS_ACCESS_DENIED;
1568 : }
1569 :
1570 11052 : return NT_STATUS_OK;
1571 : }
|