Coverage Report

Created: 2026-01-16 06:47

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