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