s3: smbd: remove redundant smb_dname arg from dptr_create()
[gd/samba-autobuild/.git] / source3 / smbd / dir.c
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 "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/bitmap.h"
27 #include "../lib/util/memcache.h"
28 #include "../librpc/gen_ndr/open_files.h"
29
30 /*
31    This module implements directory related functions for Samba.
32 */
33
34 /* "Special" directory offsets. */
35 #define END_OF_DIRECTORY_OFFSET ((long)-1)
36 #define START_OF_DIRECTORY_OFFSET ((long)0)
37 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
38
39 /* "Special" directory offsets in 32-bit wire format. */
40 #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
41 #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
42 #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
43
44 /* Make directory handle internals available. */
45
46 struct name_cache_entry {
47         char *name;
48         long offset;
49 };
50
51 struct smb_Dir {
52         connection_struct *conn;
53         DIR *dir;
54         long offset;
55         struct smb_filename *dir_smb_fname;
56         size_t name_cache_size;
57         struct name_cache_entry *name_cache;
58         unsigned int name_cache_index;
59         unsigned int file_number;
60         files_struct *fsp; /* Back pointer to containing fsp, only
61                               set from OpenDir_fsp(). */
62         bool fallback_opendir;
63 };
64
65 struct dptr_struct {
66         struct dptr_struct *next, *prev;
67         int dnum;
68         uint16_t spid;
69         struct connection_struct *conn;
70         struct smb_Dir *dir_hnd;
71         bool expect_close;
72         char *wcard;
73         uint32_t attr;
74         struct smb_filename *smb_dname;
75         bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
76         bool did_stat; /* Optimisation for non-wcard searches. */
77         bool priv;     /* Directory handle opened with privilege. */
78         uint32_t counter;
79         struct memcache *dptr_cache;
80 };
81
82 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
83                         files_struct *fsp,
84                         const char *mask,
85                         uint32_t attr);
86
87 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
88
89 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
90                                         connection_struct *conn,
91                                         const struct smb_filename *smb_dname,
92                                         const char *wcard,
93                                         uint32_t attr);
94 static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
95
96 #define INVALID_DPTR_KEY (-3)
97
98 /****************************************************************************
99  Initialise the dir bitmap.
100 ****************************************************************************/
101
102 bool init_dptrs(struct smbd_server_connection *sconn)
103 {
104         if (sconn->searches.dptr_bmap) {
105                 return true;
106         }
107
108         sconn->searches.dptr_bmap = bitmap_talloc(
109                 sconn, MAX_DIRECTORY_HANDLES);
110
111         if (sconn->searches.dptr_bmap == NULL) {
112                 return false;
113         }
114
115         return true;
116 }
117
118 /****************************************************************************
119  Get the struct dptr_struct for a dir index.
120 ****************************************************************************/
121
122 static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
123                                     int key)
124 {
125         struct dptr_struct *dptr;
126
127         for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
128                 if(dptr->dnum != key) {
129                         continue;
130                 }
131                 DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
132                 return dptr;
133         }
134         return(NULL);
135 }
136
137 /****************************************************************************
138  Get the dir path for a dir index.
139 ****************************************************************************/
140
141 const char *dptr_path(struct smbd_server_connection *sconn, int key)
142 {
143         struct dptr_struct *dptr = dptr_get(sconn, key);
144         if (dptr)
145                 return(dptr->smb_dname->base_name);
146         return(NULL);
147 }
148
149 /****************************************************************************
150  Get the dir wcard for a dir index.
151 ****************************************************************************/
152
153 const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
154 {
155         struct dptr_struct *dptr = dptr_get(sconn, key);
156         if (dptr)
157                 return(dptr->wcard);
158         return(NULL);
159 }
160
161 /****************************************************************************
162  Get the dir attrib for a dir index.
163 ****************************************************************************/
164
165 uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
166 {
167         struct dptr_struct *dptr = dptr_get(sconn, key);
168         if (dptr)
169                 return(dptr->attr);
170         return(0);
171 }
172
173 /****************************************************************************
174  Close a dptr (internal func).
175 ****************************************************************************/
176
177 static void dptr_close_internal(struct dptr_struct *dptr)
178 {
179         struct smbd_server_connection *sconn = dptr->conn->sconn;
180
181         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
182
183         if (sconn == NULL) {
184                 goto done;
185         }
186
187         if (sconn->using_smb2) {
188                 goto done;
189         }
190
191         DLIST_REMOVE(sconn->searches.dirptrs, dptr);
192
193         /*
194          * Free the dnum in the bitmap. Remember the dnum value is always 
195          * biased by one with respect to the bitmap.
196          */
197
198         if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
199                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
200                         dptr->dnum ));
201         }
202
203         bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
204
205 done:
206         TALLOC_FREE(dptr->dir_hnd);
207         TALLOC_FREE(dptr);
208 }
209
210 /****************************************************************************
211  Close all dptrs for a cnum.
212 ****************************************************************************/
213
214 void dptr_closecnum(connection_struct *conn)
215 {
216         struct dptr_struct *dptr, *next;
217         struct smbd_server_connection *sconn = conn->sconn;
218
219         if (sconn == NULL) {
220                 return;
221         }
222
223         for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
224                 next = dptr->next;
225                 if (dptr->conn == conn) {
226                         files_struct *fsp = dptr->dir_hnd->fsp;
227                         close_file(NULL, fsp, NORMAL_CLOSE);
228                         fsp = NULL;
229                 }
230         }
231 }
232
233 /****************************************************************************
234  Create a new dir ptr. If the flag old_handle is true then we must allocate
235  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
236  one byte long. If old_handle is false we allocate from the range
237  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
238  a directory handle is never zero.
239  wcard must not be zero.
240 ****************************************************************************/
241
242 NTSTATUS dptr_create(connection_struct *conn,
243                 struct smb_request *req,
244                 files_struct *fsp,
245                 bool old_handle,
246                 bool expect_close,
247                 uint16_t spid,
248                 const char *wcard,
249                 bool wcard_has_wild,
250                 uint32_t attr,
251                 struct dptr_struct **dptr_ret)
252 {
253         struct smbd_server_connection *sconn = conn->sconn;
254         struct dptr_struct *dptr = NULL;
255         struct smb_Dir *dir_hnd;
256
257         DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
258
259         if (sconn == NULL) {
260                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
261                 return NT_STATUS_INTERNAL_ERROR;
262         }
263
264         if (!wcard) {
265                 return NT_STATUS_INVALID_PARAMETER;
266         }
267
268         if (!(fsp->access_mask & SEC_DIR_LIST)) {
269                 DBG_INFO("dptr_create: directory %s "
270                         "not open for LIST access\n",
271                         fsp_str_dbg(fsp));
272                 return NT_STATUS_ACCESS_DENIED;
273         }
274         dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
275         if (!dir_hnd) {
276                 return map_nt_error_from_unix(errno);
277         }
278
279         dptr = talloc_zero(NULL, struct dptr_struct);
280         if(!dptr) {
281                 DEBUG(0,("talloc fail in dptr_create.\n"));
282                 TALLOC_FREE(dir_hnd);
283                 return NT_STATUS_NO_MEMORY;
284         }
285
286         dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
287         if (dptr->smb_dname == NULL) {
288                 TALLOC_FREE(dptr);
289                 TALLOC_FREE(dir_hnd);
290                 return NT_STATUS_NO_MEMORY;
291         }
292         dptr->conn = conn;
293         dptr->dir_hnd = dir_hnd;
294         dptr->spid = spid;
295         dptr->expect_close = expect_close;
296         dptr->wcard = talloc_strdup(dptr, wcard);
297         if (!dptr->wcard) {
298                 TALLOC_FREE(dptr);
299                 TALLOC_FREE(dir_hnd);
300                 return NT_STATUS_NO_MEMORY;
301         }
302         if ((req != NULL && req->posix_pathnames) ||
303                         (wcard[0] == '.' && wcard[1] == 0)) {
304                 dptr->has_wild = True;
305         } else {
306                 dptr->has_wild = wcard_has_wild;
307         }
308
309         dptr->attr = attr;
310
311         if (sconn->using_smb2) {
312                 goto done;
313         }
314
315         if(old_handle) {
316
317                 /*
318                  * This is an old-style SMBsearch request. Ensure the
319                  * value we return will fit in the range 1-255.
320                  */
321
322                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
323
324                 if(dptr->dnum == -1 || dptr->dnum > 254) {
325                         DBG_ERR("returned %d: Error - all old "
326                                 "dirptrs in use ?\n",
327                                 dptr->dnum);
328                         TALLOC_FREE(dptr);
329                         TALLOC_FREE(dir_hnd);
330                         return NT_STATUS_TOO_MANY_OPENED_FILES;
331                 }
332         } else {
333
334                 /*
335                  * This is a new-style trans2 request. Allocate from
336                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
337                  */
338
339                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
340
341                 if(dptr->dnum == -1 || dptr->dnum < 255) {
342                         DBG_ERR("returned %d: Error - all new "
343                                 "dirptrs in use ?\n",
344                                 dptr->dnum);
345                         TALLOC_FREE(dptr);
346                         TALLOC_FREE(dir_hnd);
347                         return NT_STATUS_TOO_MANY_OPENED_FILES;
348                 }
349         }
350
351         bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
352
353         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
354
355         DLIST_ADD(sconn->searches.dirptrs, dptr);
356
357 done:
358         DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
359                  dptr->dnum, fsp_str_dbg(fsp), expect_close);
360
361         *dptr_ret = dptr;
362
363         return NT_STATUS_OK;
364 }
365
366
367 /****************************************************************************
368  Wrapper functions to access the lower level directory handles.
369 ****************************************************************************/
370
371 void dptr_CloseDir(files_struct *fsp)
372 {
373         if (fsp->dptr) {
374                 /*
375                  * The destructor for the struct smb_Dir
376                  * (fsp->dptr->dir_hnd) now handles
377                  * all resource deallocation.
378                  */
379                 dptr_close_internal(fsp->dptr);
380                 fsp->dptr = NULL;
381         }
382 }
383
384 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
385 {
386         SeekDir(dptr->dir_hnd, offset);
387 }
388
389 long dptr_TellDir(struct dptr_struct *dptr)
390 {
391         return TellDir(dptr->dir_hnd);
392 }
393
394 bool dptr_has_wild(struct dptr_struct *dptr)
395 {
396         return dptr->has_wild;
397 }
398
399 int dptr_dnum(struct dptr_struct *dptr)
400 {
401         return dptr->dnum;
402 }
403
404 bool dptr_get_priv(struct dptr_struct *dptr)
405 {
406         return dptr->priv;
407 }
408
409 void dptr_set_priv(struct dptr_struct *dptr)
410 {
411         dptr->priv = true;
412 }
413
414 /****************************************************************************
415  Return the next visible file name, skipping veto'd and invisible files.
416 ****************************************************************************/
417
418 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
419                                            long *poffset, SMB_STRUCT_STAT *pst,
420                                            char **ptalloced)
421 {
422         /* Normal search for the next file. */
423         const char *name;
424         char *talloced = NULL;
425
426         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
427                != NULL) {
428                 if (is_visible_file(dptr->conn,
429                                 dptr->smb_dname->base_name,
430                                 name,
431                                 pst,
432                                 true)) {
433                         *ptalloced = talloced;
434                         return name;
435                 }
436                 TALLOC_FREE(talloced);
437         }
438         return NULL;
439 }
440
441 /****************************************************************************
442  Return the next visible file name, skipping veto'd and invisible files.
443 ****************************************************************************/
444
445 static char *dptr_ReadDirName(TALLOC_CTX *ctx,
446                               struct dptr_struct *dptr,
447                               long *poffset,
448                               SMB_STRUCT_STAT *pst)
449 {
450         struct smb_filename smb_fname_base;
451         char *name = NULL;
452         const char *name_temp = NULL;
453         char *talloced = NULL;
454         char *pathreal = NULL;
455         char *found_name = NULL;
456         int ret;
457
458         SET_STAT_INVALID(*pst);
459
460         if (dptr->has_wild || dptr->did_stat) {
461                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
462                                                     &talloced);
463                 if (name_temp == NULL) {
464                         return NULL;
465                 }
466                 if (talloced != NULL) {
467                         return talloc_move(ctx, &talloced);
468                 }
469                 return talloc_strdup(ctx, name_temp);
470         }
471
472         /* If poffset is -1 then we know we returned this name before and we
473          * have no wildcards. We're at the end of the directory. */
474         if (*poffset == END_OF_DIRECTORY_OFFSET) {
475                 return NULL;
476         }
477
478         /* We know the stored wcard contains no wildcard characters.
479          * See if we can match with a stat call. If we can't, then set
480          * did_stat to true to ensure we only do this once and keep
481          * searching. */
482
483         dptr->did_stat = true;
484
485         /* First check if it should be visible. */
486         if (!is_visible_file(dptr->conn,
487                         dptr->smb_dname->base_name,
488                         dptr->wcard,
489                         pst,
490                         true)) {
491                 /* This only returns false if the file was found, but
492                    is explicitly not visible. Set us to end of
493                    directory, but return NULL as we know we can't ever
494                    find it. */
495                 goto ret;
496         }
497
498         if (VALID_STAT(*pst)) {
499                 name = talloc_strdup(ctx, dptr->wcard);
500                 goto ret;
501         }
502
503         pathreal = talloc_asprintf(ctx,
504                                 "%s/%s",
505                                 dptr->smb_dname->base_name,
506                                 dptr->wcard);
507         if (!pathreal)
508                 return NULL;
509
510         /* Create an smb_filename with stream_name == NULL. */
511         smb_fname_base = (struct smb_filename) { .base_name = pathreal };
512
513         if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
514                 *pst = smb_fname_base.st;
515                 name = talloc_strdup(ctx, dptr->wcard);
516                 goto clean;
517         } else {
518                 /* If we get any other error than ENOENT or ENOTDIR
519                    then the file exists we just can't stat it. */
520                 if (errno != ENOENT && errno != ENOTDIR) {
521                         name = talloc_strdup(ctx, dptr->wcard);
522                         goto clean;
523                 }
524         }
525
526         /* Stat failed. We know this is authoratiative if we are
527          * providing case sensitive semantics or the underlying
528          * filesystem is case sensitive.
529          */
530         if (dptr->conn->case_sensitive ||
531             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
532         {
533                 goto clean;
534         }
535
536         /*
537          * Try case-insensitive stat if the fs has the ability. This avoids
538          * scanning the whole directory.
539          */
540         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn,
541                                         dptr->smb_dname->base_name,
542                                         dptr->wcard,
543                                         ctx,
544                                         &found_name);
545         if (ret == 0) {
546                 name = found_name;
547                 goto clean;
548         } else if (errno == ENOENT) {
549                 /* The case-insensitive lookup was authoritative. */
550                 goto clean;
551         }
552
553         TALLOC_FREE(pathreal);
554
555         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
556         if (name_temp == NULL) {
557                 return NULL;
558         }
559         if (talloced != NULL) {
560                 return talloc_move(ctx, &talloced);
561         }
562         return talloc_strdup(ctx, name_temp);
563
564 clean:
565         TALLOC_FREE(pathreal);
566 ret:
567         /* We need to set the underlying dir_hnd offset to -1
568          * also as this function is usually called with the
569          * output from TellDir. */
570         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
571         return name;
572 }
573
574 /****************************************************************************
575  Search for a file by name, skipping veto'ed and not visible files.
576 ****************************************************************************/
577
578 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
579 {
580         SET_STAT_INVALID(*pst);
581
582         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
583                 /* This is a singleton directory and we're already at the end. */
584                 *poffset = END_OF_DIRECTORY_OFFSET;
585                 return False;
586         }
587
588         return SearchDir(dptr->dir_hnd, name, poffset);
589 }
590
591 /****************************************************************************
592  Map a native directory offset to a 32-bit cookie.
593 ****************************************************************************/
594
595 static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
596 {
597         DATA_BLOB key;
598         DATA_BLOB val;
599
600         if (offset == END_OF_DIRECTORY_OFFSET) {
601                 return WIRE_END_OF_DIRECTORY_OFFSET;
602         } else if(offset == START_OF_DIRECTORY_OFFSET) {
603                 return WIRE_START_OF_DIRECTORY_OFFSET;
604         } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
605                 return WIRE_DOT_DOT_DIRECTORY_OFFSET;
606         }
607         if (sizeof(long) == 4) {
608                 /* 32-bit machine. We can cheat... */
609                 return (uint32_t)offset;
610         }
611         if (dptr->dptr_cache == NULL) {
612                 /* Lazy initialize cache. */
613                 dptr->dptr_cache = memcache_init(dptr, 0);
614                 if (dptr->dptr_cache == NULL) {
615                         return WIRE_END_OF_DIRECTORY_OFFSET;
616                 }
617         } else {
618                 /* Have we seen this offset before ? */
619                 key.data = (void *)&offset;
620                 key.length = sizeof(offset);
621                 if (memcache_lookup(dptr->dptr_cache,
622                                         SMB1_SEARCH_OFFSET_MAP,
623                                         key,
624                                         &val)) {
625                         uint32_t wire_offset;
626                         SMB_ASSERT(val.length == sizeof(wire_offset));
627                         memcpy(&wire_offset, val.data, sizeof(wire_offset));
628                         DEBUG(10,("found wire %u <-> offset %ld\n",
629                                 (unsigned int)wire_offset,
630                                 (long)offset));
631                         return wire_offset;
632                 }
633         }
634         /* Allocate a new wire cookie. */
635         do {
636                 dptr->counter++;
637         } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
638                  dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
639                  dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
640         /* Store it in the cache. */
641         key.data = (void *)&offset;
642         key.length = sizeof(offset);
643         val.data = (void *)&dptr->counter;
644         val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
645         memcache_add(dptr->dptr_cache,
646                         SMB1_SEARCH_OFFSET_MAP,
647                         key,
648                         val);
649         /* And the reverse mapping for lookup from
650            map_wire_to_dir_offset(). */
651         memcache_add(dptr->dptr_cache,
652                         SMB1_SEARCH_OFFSET_MAP,
653                         val,
654                         key);
655         DEBUG(10,("stored wire %u <-> offset %ld\n",
656                 (unsigned int)dptr->counter,
657                 (long)offset));
658         return dptr->counter;
659 }
660
661 /****************************************************************************
662  Fill the 5 byte server reserved dptr field.
663 ****************************************************************************/
664
665 bool dptr_fill(struct smbd_server_connection *sconn,
666                char *buf1,unsigned int key)
667 {
668         unsigned char *buf = (unsigned char *)buf1;
669         struct dptr_struct *dptr = dptr_get(sconn, key);
670         uint32_t wire_offset;
671         if (!dptr) {
672                 DEBUG(1,("filling null dirptr %d\n",key));
673                 return(False);
674         }
675         wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
676         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
677                 (long)dptr->dir_hnd,(int)wire_offset));
678         buf[0] = key;
679         SIVAL(buf,1,wire_offset);
680         return(True);
681 }
682
683 /****************************************************************************
684  Map a 32-bit wire cookie to a native directory offset.
685 ****************************************************************************/
686
687 static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
688 {
689         DATA_BLOB key;
690         DATA_BLOB val;
691
692         if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
693                 return END_OF_DIRECTORY_OFFSET;
694         } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
695                 return START_OF_DIRECTORY_OFFSET;
696         } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
697                 return DOT_DOT_DIRECTORY_OFFSET;
698         }
699         if (sizeof(long) == 4) {
700                 /* 32-bit machine. We can cheat... */
701                 return (long)wire_offset;
702         }
703         if (dptr->dptr_cache == NULL) {
704                 /* Logic error, cache should be initialized. */
705                 return END_OF_DIRECTORY_OFFSET;
706         }
707         key.data = (void *)&wire_offset;
708         key.length = sizeof(wire_offset);
709         if (memcache_lookup(dptr->dptr_cache,
710                                 SMB1_SEARCH_OFFSET_MAP,
711                                 key,
712                                 &val)) {
713                 /* Found mapping. */
714                 long offset;
715                 SMB_ASSERT(val.length == sizeof(offset));
716                 memcpy(&offset, val.data, sizeof(offset));
717                 DEBUG(10,("lookup wire %u <-> offset %ld\n",
718                         (unsigned int)wire_offset,
719                         (long)offset));
720                 return offset;
721         }
722         return END_OF_DIRECTORY_OFFSET;
723 }
724
725 /****************************************************************************
726  Return the associated fsp and seek the dir_hnd on it it given the 5 byte
727  server field.
728 ****************************************************************************/
729
730 files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
731                                char *buf, int *num)
732 {
733         unsigned int key = *(unsigned char *)buf;
734         struct dptr_struct *dptr = dptr_get(sconn, key);
735         uint32_t wire_offset;
736         long seekoff;
737
738         if (dptr == NULL) {
739                 DEBUG(3,("fetched null dirptr %d\n",key));
740                 return(NULL);
741         }
742         *num = key;
743         wire_offset = IVAL(buf,1);
744         seekoff = map_wire_to_dir_offset(dptr, wire_offset);
745         SeekDir(dptr->dir_hnd,seekoff);
746         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
747                 key, dptr->smb_dname->base_name, (int)seekoff));
748         return dptr->dir_hnd->fsp;
749 }
750
751 /****************************************************************************
752  Fetch the fsp associated with the dptr_num.
753 ****************************************************************************/
754
755 files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
756                                        int dptr_num)
757 {
758         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num);
759         if (dptr == NULL) {
760                 return NULL;
761         }
762         DBG_NOTICE("fetching dirptr %d for path %s\n",
763                 dptr_num,
764                 dptr->smb_dname->base_name);
765         return dptr->dir_hnd->fsp;
766 }
767
768 static bool mangle_mask_match(connection_struct *conn,
769                 const char *filename,
770                 const char *mask)
771 {
772         char mname[13];
773
774         if (!name_to_8_3(filename,mname,False,conn->params)) {
775                 return False;
776         }
777         return mask_match_search(mname,mask,False);
778 }
779
780 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
781                            struct dptr_struct *dirptr,
782                            const char *mask,
783                            uint32_t dirtype,
784                            bool dont_descend,
785                            bool ask_sharemode,
786                            bool get_dosmode,
787                            bool (*match_fn)(TALLOC_CTX *ctx,
788                                             void *private_data,
789                                             const char *dname,
790                                             const char *mask,
791                                             char **_fname),
792                            bool (*mode_fn)(TALLOC_CTX *ctx,
793                                            void *private_data,
794                                            struct smb_filename *smb_fname,
795                                            bool get_dosmode,
796                                            uint32_t *_mode),
797                            void *private_data,
798                            char **_fname,
799                            struct smb_filename **_smb_fname,
800                            uint32_t *_mode,
801                            long *_prev_offset)
802 {
803         connection_struct *conn = dirptr->conn;
804         size_t slashlen;
805         size_t pathlen;
806         const char *dpath = dirptr->smb_dname->base_name;
807         bool dirptr_path_is_dot = ISDOT(dpath);
808
809         *_smb_fname = NULL;
810         *_mode = 0;
811
812         pathlen = strlen(dpath);
813         slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
814
815         while (true) {
816                 long cur_offset;
817                 long prev_offset;
818                 SMB_STRUCT_STAT sbuf = { 0 };
819                 char *dname = NULL;
820                 bool isdots;
821                 char *fname = NULL;
822                 char *pathreal = NULL;
823                 struct smb_filename smb_fname;
824                 uint32_t mode = 0;
825                 bool ok;
826
827                 cur_offset = dptr_TellDir(dirptr);
828                 prev_offset = cur_offset;
829                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
830
831                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
832                         (long)dirptr, cur_offset));
833
834                 if (dname == NULL) {
835                         return false;
836                 }
837
838                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
839                 if (dont_descend && !isdots) {
840                         TALLOC_FREE(dname);
841                         continue;
842                 }
843
844                 /*
845                  * fname may get mangled, dname is never mangled.
846                  * Whenever we're accessing the filesystem we use
847                  * pathreal which is composed from dname.
848                  */
849
850                 ok = match_fn(ctx, private_data, dname, mask, &fname);
851                 if (!ok) {
852                         TALLOC_FREE(dname);
853                         continue;
854                 }
855
856                 /*
857                  * This used to be
858                  * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
859                  *                            needslash?"/":"", dname);
860                  * but this was measurably slower than doing the memcpy.
861                  */
862
863                 pathreal = talloc_array(
864                         ctx, char,
865                         pathlen + slashlen + talloc_get_size(dname));
866                 if (!pathreal) {
867                         TALLOC_FREE(dname);
868                         TALLOC_FREE(fname);
869                         return false;
870                 }
871
872                 /*
873                  * We don't want to pass ./xxx to modules below us so don't
874                  * add the path if it is just . by itself.
875                  */
876                 if (dirptr_path_is_dot) {
877                         memcpy(pathreal, dname, talloc_get_size(dname));
878                 } else {
879                         memcpy(pathreal, dpath, pathlen);
880                         pathreal[pathlen] = '/';
881                         memcpy(pathreal + slashlen + pathlen, dname,
882                                talloc_get_size(dname));
883                 }
884
885                 /* Create smb_fname with NULL stream_name. */
886                 smb_fname = (struct smb_filename) {
887                         .base_name = pathreal, .st = sbuf
888                 };
889
890                 ok = mode_fn(ctx, private_data, &smb_fname, get_dosmode, &mode);
891                 if (!ok) {
892                         TALLOC_FREE(dname);
893                         TALLOC_FREE(fname);
894                         TALLOC_FREE(pathreal);
895                         continue;
896                 }
897
898                 if (!dir_check_ftype(mode, dirtype)) {
899                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
900                                 fname, (unsigned int)mode, (unsigned int)dirtype));
901                         TALLOC_FREE(dname);
902                         TALLOC_FREE(fname);
903                         TALLOC_FREE(pathreal);
904                         continue;
905                 }
906
907                 if (ask_sharemode) {
908                         struct timespec write_time_ts;
909                         struct file_id fileid;
910
911                         fileid = vfs_file_id_from_sbuf(conn,
912                                                        &smb_fname.st);
913                         get_file_infos(fileid, 0, NULL, &write_time_ts);
914                         if (!null_timespec(write_time_ts)) {
915                                 update_stat_ex_mtime(&smb_fname.st,
916                                                      write_time_ts);
917                         }
918                 }
919
920                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
921                         "fname=%s (%s)\n",
922                         mask, smb_fname_str_dbg(&smb_fname),
923                         dname, fname));
924
925                 if (!conn->sconn->using_smb2) {
926                         /*
927                          * The dircache is only needed for SMB1 because SMB1
928                          * uses a name for the resume wheras SMB2 always
929                          * continues from the next position (unless it's told to
930                          * restart or close-and-reopen the listing).
931                          */
932                         DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
933                 }
934
935                 TALLOC_FREE(dname);
936
937                 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
938                 TALLOC_FREE(pathreal);
939                 if (*_smb_fname == NULL) {
940                         return false;
941                 }
942                 *_fname = fname;
943                 *_mode = mode;
944                 *_prev_offset = prev_offset;
945
946                 return true;
947         }
948
949         return false;
950 }
951
952 /****************************************************************************
953  Get an 8.3 directory entry.
954 ****************************************************************************/
955
956 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
957                                      void *private_data,
958                                      const char *dname,
959                                      const char *mask,
960                                      char **_fname)
961 {
962         connection_struct *conn = (connection_struct *)private_data;
963
964         if ((strcmp(mask,"*.*") == 0) ||
965             mask_match_search(dname, mask, false) ||
966             mangle_mask_match(conn, dname, mask)) {
967                 char mname[13];
968                 const char *fname;
969                 /*
970                  * Ensure we can push the original name as UCS2. If
971                  * not, then just don't return this name.
972                  */
973                 NTSTATUS status;
974                 size_t ret_len = 0;
975                 size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
976                 uint8_t *tmp = talloc_array(talloc_tos(),
977                                         uint8_t,
978                                         len);
979
980                 status = srvstr_push(NULL,
981                         FLAGS2_UNICODE_STRINGS,
982                         tmp,
983                         dname,
984                         len,
985                         STR_TERMINATE,
986                         &ret_len);
987
988                 TALLOC_FREE(tmp);
989
990                 if (!NT_STATUS_IS_OK(status)) {
991                         return false;
992                 }
993
994                 if (!mangle_is_8_3(dname, false, conn->params)) {
995                         bool ok = name_to_8_3(dname, mname, false,
996                                               conn->params);
997                         if (!ok) {
998                                 return false;
999                         }
1000                         fname = mname;
1001                 } else {
1002                         fname = dname;
1003                 }
1004
1005                 *_fname = talloc_strdup(ctx, fname);
1006                 if (*_fname == NULL) {
1007                         return false;
1008                 }
1009
1010                 return true;
1011         }
1012
1013         return false;
1014 }
1015
1016 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1017                                     void *private_data,
1018                                     struct smb_filename *smb_fname,
1019                                     bool get_dosmode,
1020                                     uint32_t *_mode)
1021 {
1022         connection_struct *conn = (connection_struct *)private_data;
1023
1024         if (!VALID_STAT(smb_fname->st)) {
1025                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1026                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1027                                  "Couldn't stat [%s]. Error "
1028                                  "= %s\n",
1029                                  smb_fname_str_dbg(smb_fname),
1030                                  strerror(errno)));
1031                         return false;
1032                 }
1033         }
1034
1035         *_mode = dos_mode(conn, smb_fname);
1036         return true;
1037 }
1038
1039 bool get_dir_entry(TALLOC_CTX *ctx,
1040                 struct dptr_struct *dirptr,
1041                 const char *mask,
1042                 uint32_t dirtype,
1043                 char **_fname,
1044                 off_t *_size,
1045                 uint32_t *_mode,
1046                 struct timespec *_date,
1047                 bool check_descend,
1048                 bool ask_sharemode)
1049 {
1050         connection_struct *conn = dirptr->conn;
1051         char *fname = NULL;
1052         struct smb_filename *smb_fname = NULL;
1053         uint32_t mode = 0;
1054         long prev_offset;
1055         bool ok;
1056
1057         ok = smbd_dirptr_get_entry(ctx,
1058                                    dirptr,
1059                                    mask,
1060                                    dirtype,
1061                                    check_descend,
1062                                    ask_sharemode,
1063                                    true,
1064                                    smbd_dirptr_8_3_match_fn,
1065                                    smbd_dirptr_8_3_mode_fn,
1066                                    conn,
1067                                    &fname,
1068                                    &smb_fname,
1069                                    &mode,
1070                                    &prev_offset);
1071         if (!ok) {
1072                 return false;
1073         }
1074
1075         *_fname = talloc_move(ctx, &fname);
1076         *_size = smb_fname->st.st_ex_size;
1077         *_mode = mode;
1078         *_date = smb_fname->st.st_ex_mtime;
1079         TALLOC_FREE(smb_fname);
1080         return true;
1081 }
1082
1083 /*******************************************************************
1084  Check to see if a user can read a file. This is only approximate,
1085  it is used as part of the "hide unreadable" option. Don't
1086  use it for anything security sensitive.
1087 ********************************************************************/
1088
1089 static bool user_can_read_file(connection_struct *conn,
1090                                struct smb_filename *smb_fname)
1091 {
1092         NTSTATUS status;
1093         uint32_t rejected_share_access = 0;
1094         uint32_t rejected_mask = 0;
1095         struct security_descriptor *sd = NULL;
1096         uint32_t access_mask = FILE_READ_DATA|
1097                                 FILE_READ_EA|
1098                                 FILE_READ_ATTRIBUTES|
1099                                 SEC_STD_READ_CONTROL;
1100
1101         /*
1102          * Never hide files from the root user.
1103          * We use (uid_t)0 here not sec_initial_uid()
1104          * as make test uses a single user context.
1105          */
1106
1107         if (get_current_uid(conn) == (uid_t)0) {
1108                 return True;
1109         }
1110
1111         /*
1112          * We can't directly use smbd_check_access_rights()
1113          * here, as this implicitly grants FILE_READ_ATTRIBUTES
1114          * which the Windows access-based-enumeration code
1115          * explicitly checks for on the file security descriptor.
1116          * See bug:
1117          *
1118          * https://bugzilla.samba.org/show_bug.cgi?id=10252
1119          *
1120          * and the smb2.acl2.ACCESSBASED test for details.
1121          */
1122
1123         rejected_share_access = access_mask & ~(conn->share_access);
1124         if (rejected_share_access) {
1125                 DEBUG(10, ("rejected share access 0x%x "
1126                         "on %s (0x%x)\n",
1127                         (unsigned int)access_mask,
1128                         smb_fname_str_dbg(smb_fname),
1129                         (unsigned int)rejected_share_access ));
1130                 return false;
1131         }
1132
1133         status = SMB_VFS_GET_NT_ACL(conn,
1134                         smb_fname,
1135                         (SECINFO_OWNER |
1136                          SECINFO_GROUP |
1137                          SECINFO_DACL),
1138                         talloc_tos(),
1139                         &sd);
1140
1141         if (!NT_STATUS_IS_OK(status)) {
1142                 DEBUG(10, ("Could not get acl "
1143                         "on %s: %s\n",
1144                         smb_fname_str_dbg(smb_fname),
1145                         nt_errstr(status)));
1146                 return false;
1147         }
1148
1149         status = se_file_access_check(sd,
1150                                 get_current_nttok(conn),
1151                                 false,
1152                                 access_mask,
1153                                 &rejected_mask);
1154
1155         TALLOC_FREE(sd);
1156
1157         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1158                 DEBUG(10,("rejected bits 0x%x read access for %s\n",
1159                         (unsigned int)rejected_mask,
1160                         smb_fname_str_dbg(smb_fname) ));
1161                 return false;
1162         }
1163         return true;
1164 }
1165
1166 /*******************************************************************
1167  Check to see if a user can write a file (and only files, we do not
1168  check dirs on this one). This is only approximate,
1169  it is used as part of the "hide unwriteable" option. Don't
1170  use it for anything security sensitive.
1171 ********************************************************************/
1172
1173 static bool user_can_write_file(connection_struct *conn,
1174                                 const struct smb_filename *smb_fname)
1175 {
1176         /*
1177          * Never hide files from the root user.
1178          * We use (uid_t)0 here not sec_initial_uid()
1179          * as make test uses a single user context.
1180          */
1181
1182         if (get_current_uid(conn) == (uid_t)0) {
1183                 return True;
1184         }
1185
1186         SMB_ASSERT(VALID_STAT(smb_fname->st));
1187
1188         /* Pseudo-open the file */
1189
1190         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1191                 return True;
1192         }
1193
1194         return can_write_to_file(conn, smb_fname);
1195 }
1196
1197 /*******************************************************************
1198   Is a file a "special" type ?
1199 ********************************************************************/
1200
1201 static bool file_is_special(connection_struct *conn,
1202                             const struct smb_filename *smb_fname)
1203 {
1204         /*
1205          * Never hide files from the root user.
1206          * We use (uid_t)0 here not sec_initial_uid()
1207          * as make test uses a single user context.
1208          */
1209
1210         if (get_current_uid(conn) == (uid_t)0) {
1211                 return False;
1212         }
1213
1214         SMB_ASSERT(VALID_STAT(smb_fname->st));
1215
1216         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1217             S_ISDIR(smb_fname->st.st_ex_mode) ||
1218             S_ISLNK(smb_fname->st.st_ex_mode))
1219                 return False;
1220
1221         return True;
1222 }
1223
1224 /*******************************************************************
1225  Should the file be seen by the client?
1226  NOTE: A successful return is no guarantee of the file's existence.
1227 ********************************************************************/
1228
1229 bool is_visible_file(connection_struct *conn, const char *dir_path,
1230                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1231 {
1232         bool hide_unreadable = lp_hide_unreadable(SNUM(conn));
1233         bool hide_unwriteable = lp_hide_unwriteable_files(SNUM(conn));
1234         bool hide_special = lp_hide_special_files(SNUM(conn));
1235         int hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(conn));
1236         char *entry = NULL;
1237         struct smb_filename *smb_fname_base = NULL;
1238         bool ret = false;
1239
1240         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1241                 return True; /* . and .. are always visible. */
1242         }
1243
1244         /* If it's a vetoed file, pretend it doesn't even exist */
1245         if (use_veto && IS_VETO_PATH(conn, name)) {
1246                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1247                 return False;
1248         }
1249
1250         if (hide_unreadable ||
1251             hide_unwriteable ||
1252             hide_special ||
1253             (hide_new_files_timeout != 0))
1254         {
1255                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1256                 if (!entry) {
1257                         ret = false;
1258                         goto out;
1259                 }
1260
1261                 /* Create an smb_filename with stream_name == NULL. */
1262                 smb_fname_base = synthetic_smb_fname(talloc_tos(),
1263                                                 entry,
1264                                                 NULL,
1265                                                 pst,
1266                                                 0);
1267                 if (smb_fname_base == NULL) {
1268                         ret = false;
1269                         goto out;
1270                 }
1271
1272                 /* If the file name does not exist, there's no point checking
1273                  * the configuration options. We succeed, on the basis that the
1274                  * checks *might* have passed if the file was present.
1275                  */
1276                 if (!VALID_STAT(*pst)) {
1277                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1278                                 ret = true;
1279                                 goto out;
1280                         }
1281                         *pst = smb_fname_base->st;
1282                 }
1283
1284                 /* Honour _hide unreadable_ option */
1285                 if (hide_unreadable &&
1286                     !user_can_read_file(conn, smb_fname_base)) {
1287                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1288                                  entry ));
1289                         ret = false;
1290                         goto out;
1291                 }
1292                 /* Honour _hide unwriteable_ option */
1293                 if (hide_unwriteable && !user_can_write_file(conn,
1294                                                              smb_fname_base)) {
1295                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1296                                  entry ));
1297                         ret = false;
1298                         goto out;
1299                 }
1300                 /* Honour _hide_special_ option */
1301                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1302                         DEBUG(10,("is_visible_file: file %s is special.\n",
1303                                  entry ));
1304                         ret = false;
1305                         goto out;
1306                 }
1307
1308                 if (hide_new_files_timeout != 0) {
1309
1310                         double age = timespec_elapsed(
1311                                 &smb_fname_base->st.st_ex_mtime);
1312
1313                         if (age < (double)hide_new_files_timeout) {
1314                                 ret = false;
1315                                 goto out;
1316                         }
1317                 }
1318         }
1319
1320         ret = true;
1321  out:
1322         TALLOC_FREE(smb_fname_base);
1323         TALLOC_FREE(entry);
1324         return ret;
1325 }
1326
1327 static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1328 {
1329         files_struct *fsp = dir_hnd->fsp;
1330
1331         SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1332         /*
1333          * The SMB_VFS_CLOSEDIR above
1334          * closes the underlying fd inside
1335          * dirp->fsp, unless fallback_opendir
1336          * was set in which case the fd
1337          * in dir_hnd->fsp->fh->fd isn't
1338          * the one being closed. Close
1339          * it separately.
1340          */
1341         if (dir_hnd->fallback_opendir) {
1342                 SMB_VFS_CLOSE(fsp);
1343         }
1344         fsp->fh->fd = -1;
1345         SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1346         fsp->dptr->dir_hnd = NULL;
1347         dir_hnd->fsp = NULL;
1348         return 0;
1349 }
1350
1351 /*******************************************************************
1352  Open a directory.
1353 ********************************************************************/
1354
1355 static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1356                         connection_struct *conn,
1357                         const struct smb_filename *smb_dname,
1358                         const char *mask,
1359                         uint32_t attr)
1360 {
1361         struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1362
1363         if (!dir_hnd) {
1364                 return NULL;
1365         }
1366
1367         dir_hnd->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1368
1369         if (!dir_hnd->dir) {
1370                 DEBUG(5,("OpenDir: Can't open %s. %s\n",
1371                         smb_dname->base_name,
1372                         strerror(errno) ));
1373                 goto fail;
1374         }
1375
1376         dir_hnd->conn = conn;
1377
1378         if (!conn->sconn->using_smb2) {
1379                 /*
1380                  * The dircache is only needed for SMB1 because SMB1 uses a name
1381                  * for the resume wheras SMB2 always continues from the next
1382                  * position (unless it's told to restart or close-and-reopen the
1383                  * listing).
1384                  */
1385                 dir_hnd->name_cache_size =
1386                         lp_directory_name_cache_size(SNUM(conn));
1387         }
1388
1389         return dir_hnd;
1390
1391   fail:
1392         TALLOC_FREE(dir_hnd);
1393         return NULL;
1394 }
1395
1396 /**
1397  * @brief Open a directory handle by pathname, ensuring it's under the share path.
1398  *
1399  * First stores the $cwd, then changes directory to the passed in pathname
1400  * uses check_name() to ensure this is under the connection struct share path,
1401  * then operates on a pathname of "." to ensure we're in the same place.
1402  *
1403  * The returned struct smb_Dir * should have a talloc destrctor added to
1404  * ensure that when the struct is freed the internal POSIX DIR * pointer
1405  * is closed.
1406  *
1407  * @code
1408  *
1409  * static int sample_smb_Dir_destructor(struct smb_Dir *dirp)
1410  * {
1411  *     SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1412  * }
1413  * ..
1414  *     struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1415  *                              conn,
1416  *                              smb_dname,
1417  *                              mask,
1418  *                              attr);
1419  *      if (dir_hnd == NULL) {
1420  *              return NULL;
1421  *      }
1422  *      talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1423  * ..
1424  * @endcode
1425  */
1426
1427 static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1428                                         connection_struct *conn,
1429                                         const struct smb_filename *smb_dname,
1430                                         const char *wcard,
1431                                         uint32_t attr)
1432 {
1433         struct smb_Dir *dir_hnd = NULL;
1434         struct smb_filename *smb_fname_cwd = NULL;
1435         struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn);
1436         NTSTATUS status;
1437
1438         if (saved_dir_fname == NULL) {
1439                 return NULL;
1440         }
1441
1442         if (vfs_ChDir(conn, smb_dname) == -1) {
1443                 goto out;
1444         }
1445
1446         smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1447                                         ".",
1448                                         NULL,
1449                                         NULL,
1450                                         smb_dname->flags);
1451         if (smb_fname_cwd == NULL) {
1452                 goto out;
1453         }
1454
1455         /*
1456          * Now the directory is pinned, use
1457          * REALPATH to ensure we can access it.
1458          */
1459         status = check_name(conn, smb_fname_cwd);
1460         if (!NT_STATUS_IS_OK(status)) {
1461                 goto out;
1462         }
1463
1464         dir_hnd = OpenDir_internal(ctx,
1465                                 conn,
1466                                 smb_fname_cwd,
1467                                 wcard,
1468                                 attr);
1469
1470         if (dir_hnd == NULL) {
1471                 goto out;
1472         }
1473
1474         /*
1475          * OpenDir_internal only gets "." as the dir name.
1476          * Store the real dir name here.
1477          */
1478
1479         dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1480         if (!dir_hnd->dir_smb_fname) {
1481                 TALLOC_FREE(dir_hnd);
1482                 SMB_VFS_CLOSEDIR(conn, dir_hnd->dir);
1483                 errno = ENOMEM;
1484         }
1485
1486   out:
1487
1488         vfs_ChDir(conn, saved_dir_fname);
1489         TALLOC_FREE(saved_dir_fname);
1490         return dir_hnd;
1491 }
1492
1493 /*
1494  * Simple destructor for OpenDir() use. Don't need to
1495  * care about fsp back pointer as we know we have never
1496  * set it in the OpenDir() code path.
1497  */
1498
1499 static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1500 {
1501         SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1502         return 0;
1503 }
1504
1505 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1506                         const struct smb_filename *smb_dname,
1507                         const char *mask,
1508                         uint32_t attr)
1509 {
1510         struct smb_Dir *dir_hnd = open_dir_safely(mem_ctx,
1511                                 conn,
1512                                 smb_dname,
1513                                 mask,
1514                                 attr);
1515         if (dir_hnd == NULL) {
1516                 return NULL;
1517         }
1518         talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1519         return dir_hnd;
1520 }
1521
1522 /*******************************************************************
1523  Open a directory from an fsp.
1524 ********************************************************************/
1525
1526 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1527                         files_struct *fsp,
1528                         const char *mask,
1529                         uint32_t attr)
1530 {
1531         struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1532
1533         if (!dir_hnd) {
1534                 goto fail;
1535         }
1536
1537         if (!fsp->is_directory) {
1538                 errno = EBADF;
1539                 goto fail;
1540         }
1541
1542         if (fsp->fh->fd == -1) {
1543                 errno = EBADF;
1544                 goto fail;
1545         }
1546
1547         dir_hnd->conn = conn;
1548
1549         if (!conn->sconn->using_smb2) {
1550                 /*
1551                  * The dircache is only needed for SMB1 because SMB1 uses a name
1552                  * for the resume wheras SMB2 always continues from the next
1553                  * position (unless it's told to restart or close-and-reopen the
1554                  * listing).
1555                  */
1556                 dir_hnd->name_cache_size =
1557                         lp_directory_name_cache_size(SNUM(conn));
1558         }
1559
1560         dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1561         if (!dir_hnd->dir_smb_fname) {
1562                 errno = ENOMEM;
1563                 goto fail;
1564         }
1565
1566         dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1567         if (dir_hnd->dir != NULL) {
1568                 dir_hnd->fsp = fsp;
1569         } else {
1570                 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1571                         "NULL (%s)\n",
1572                         dir_hnd->dir_smb_fname->base_name,
1573                         strerror(errno)));
1574                 if (errno != ENOSYS) {
1575                         goto fail;
1576                 }
1577         }
1578
1579         if (dir_hnd->dir == NULL) {
1580                 /* FDOPENDIR is not supported. Use OPENDIR instead. */
1581                 TALLOC_FREE(dir_hnd);
1582                 dir_hnd = open_dir_safely(mem_ctx,
1583                                         conn,
1584                                         fsp->fsp_name,
1585                                         mask,
1586                                         attr);
1587                 if (dir_hnd == NULL) {
1588                         errno = ENOMEM;
1589                         goto fail;
1590                 }
1591                 /*
1592                  * Remember if we used the fallback.
1593                  * We need to change the destructor
1594                  * to also close the fsp file descriptor
1595                  * in this case as it isn't the same
1596                  * one the directory handle uses.
1597                  */
1598                 dir_hnd->fsp = fsp;
1599                 dir_hnd->fallback_opendir = true;
1600         }
1601
1602         talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1603
1604         return dir_hnd;
1605
1606   fail:
1607         TALLOC_FREE(dir_hnd);
1608         return NULL;
1609 }
1610
1611
1612 /*******************************************************************
1613  Read from a directory.
1614  Return directory entry, current offset, and optional stat information.
1615  Don't check for veto or invisible files.
1616 ********************************************************************/
1617
1618 const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1619                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1620 {
1621         const char *n;
1622         char *talloced = NULL;
1623         connection_struct *conn = dir_hnd->conn;
1624
1625         /* Cheat to allow . and .. to be the first entries returned. */
1626         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1627              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dir_hnd->file_number < 2))
1628         {
1629                 if (dir_hnd->file_number == 0) {
1630                         n = ".";
1631                         *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1632                 } else {
1633                         n = "..";
1634                         *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1635                 }
1636                 dir_hnd->file_number++;
1637                 *ptalloced = NULL;
1638                 return n;
1639         }
1640
1641         if (*poffset == END_OF_DIRECTORY_OFFSET) {
1642                 *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1643                 return NULL;
1644         }
1645
1646         /* A real offset, seek to it. */
1647         SeekDir(dir_hnd, *poffset);
1648
1649         while ((n = vfs_readdirname(conn, dir_hnd->dir, sbuf, &talloced))) {
1650                 /* Ignore . and .. - we've already returned them. */
1651                 if (*n == '.') {
1652                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1653                                 TALLOC_FREE(talloced);
1654                                 continue;
1655                         }
1656                 }
1657                 *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1658                 *ptalloced = talloced;
1659                 dir_hnd->file_number++;
1660                 return n;
1661         }
1662         *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1663         *ptalloced = NULL;
1664         return NULL;
1665 }
1666
1667 /*******************************************************************
1668  Rewind to the start.
1669 ********************************************************************/
1670
1671 void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1672 {
1673         SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1674         dir_hnd->file_number = 0;
1675         dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1676         *poffset = START_OF_DIRECTORY_OFFSET;
1677 }
1678
1679 /*******************************************************************
1680  Seek a dir.
1681 ********************************************************************/
1682
1683 void SeekDir(struct smb_Dir *dirp, long offset)
1684 {
1685         if (offset != dirp->offset) {
1686                 if (offset == START_OF_DIRECTORY_OFFSET) {
1687                         RewindDir(dirp, &offset);
1688                         /*
1689                          * Ok we should really set the file number here
1690                          * to 1 to enable ".." to be returned next. Trouble
1691                          * is I'm worried about callers using SeekDir(dirp,0)
1692                          * as equivalent to RewindDir(). So leave this alone
1693                          * for now.
1694                          */
1695                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1696                         RewindDir(dirp, &offset);
1697                         /*
1698                          * Set the file number to 2 - we want to get the first
1699                          * real file entry (the one we return after "..")
1700                          * on the next ReadDir.
1701                          */
1702                         dirp->file_number = 2;
1703                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1704                         ; /* Don't seek in this case. */
1705                 } else {
1706                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1707                 }
1708                 dirp->offset = offset;
1709         }
1710 }
1711
1712 /*******************************************************************
1713  Tell a dir position.
1714 ********************************************************************/
1715
1716 long TellDir(struct smb_Dir *dir_hnd)
1717 {
1718         return(dir_hnd->offset);
1719 }
1720
1721 /*******************************************************************
1722  Add an entry into the dcache.
1723 ********************************************************************/
1724
1725 static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1726 {
1727         struct name_cache_entry *e;
1728
1729         if (dir_hnd->name_cache_size == 0) {
1730                 return;
1731         }
1732
1733         if (dir_hnd->name_cache == NULL) {
1734                 dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1735                                                 struct name_cache_entry,
1736                                                 dir_hnd->name_cache_size);
1737
1738                 if (dir_hnd->name_cache == NULL) {
1739                         return;
1740                 }
1741         }
1742
1743         dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1744                                         dir_hnd->name_cache_size;
1745         e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1746         TALLOC_FREE(e->name);
1747         e->name = talloc_strdup(dir_hnd, name);
1748         e->offset = offset;
1749 }
1750
1751 /*******************************************************************
1752  Find an entry by name. Leave us at the offset after it.
1753  Don't check for veto or invisible files.
1754 ********************************************************************/
1755
1756 bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1757 {
1758         int i;
1759         const char *entry = NULL;
1760         char *talloced = NULL;
1761         connection_struct *conn = dir_hnd->conn;
1762
1763         /* Search back in the name cache. */
1764         if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1765                 for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1766                         struct name_cache_entry *e = &dir_hnd->name_cache[i];
1767                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1768                                 *poffset = e->offset;
1769                                 SeekDir(dir_hnd, e->offset);
1770                                 return True;
1771                         }
1772                 }
1773                 for (i = dir_hnd->name_cache_size - 1;
1774                                 i > dir_hnd->name_cache_index; i--) {
1775                         struct name_cache_entry *e = &dir_hnd->name_cache[i];
1776                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1777                                 *poffset = e->offset;
1778                                 SeekDir(dir_hnd, e->offset);
1779                                 return True;
1780                         }
1781                 }
1782         }
1783
1784         /* Not found in the name cache. Rewind directory and start from scratch. */
1785         SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1786         dir_hnd->file_number = 0;
1787         *poffset = START_OF_DIRECTORY_OFFSET;
1788         while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1789                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1790                         TALLOC_FREE(talloced);
1791                         return True;
1792                 }
1793                 TALLOC_FREE(talloced);
1794         }
1795         return False;
1796 }
1797
1798 struct files_below_forall_state {
1799         char *dirpath;
1800         size_t dirpath_len;
1801         int (*fn)(struct file_id fid, const struct share_mode_data *data,
1802                   void *private_data);
1803         void *private_data;
1804 };
1805
1806 static int files_below_forall_fn(struct file_id fid,
1807                                  const struct share_mode_data *data,
1808                                  void *private_data)
1809 {
1810         struct files_below_forall_state *state = private_data;
1811         char tmpbuf[PATH_MAX];
1812         char *fullpath, *to_free;
1813         size_t len;
1814
1815         len = full_path_tos(data->servicepath, data->base_name,
1816                             tmpbuf, sizeof(tmpbuf),
1817                             &fullpath, &to_free);
1818         if (len == -1) {
1819                 return 0;
1820         }
1821         if (state->dirpath_len >= len) {
1822                 /*
1823                  * Filter files above dirpath
1824                  */
1825                 goto out;
1826         }
1827         if (fullpath[state->dirpath_len] != '/') {
1828                 /*
1829                  * Filter file that don't have a path separator at the end of
1830                  * dirpath's length
1831                  */
1832                 goto out;
1833         }
1834
1835         if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1836                 /*
1837                  * Not a parent
1838                  */
1839                 goto out;
1840         }
1841
1842         TALLOC_FREE(to_free);
1843         return state->fn(fid, data, state->private_data);
1844
1845 out:
1846         TALLOC_FREE(to_free);
1847         return 0;
1848 }
1849
1850 static int files_below_forall(connection_struct *conn,
1851                               const struct smb_filename *dir_name,
1852                               int (*fn)(struct file_id fid,
1853                                         const struct share_mode_data *data,
1854                                         void *private_data),
1855                               void *private_data)
1856 {
1857         struct files_below_forall_state state = {
1858                         .fn = fn,
1859                         .private_data = private_data,
1860         };
1861         int ret;
1862         char tmpbuf[PATH_MAX];
1863         char *to_free;
1864
1865         state.dirpath_len = full_path_tos(conn->connectpath,
1866                                           dir_name->base_name,
1867                                           tmpbuf, sizeof(tmpbuf),
1868                                           &state.dirpath, &to_free);
1869         if (state.dirpath_len == -1) {
1870                 return -1;
1871         }
1872
1873         ret = share_mode_forall(files_below_forall_fn, &state);
1874         TALLOC_FREE(to_free);
1875         return ret;
1876 }
1877
1878 struct have_file_open_below_state {
1879         bool found_one;
1880 };
1881
1882 static int have_file_open_below_fn(struct file_id fid,
1883                                    const struct share_mode_data *data,
1884                                    void *private_data)
1885 {
1886         struct have_file_open_below_state *state = private_data;
1887         state->found_one = true;
1888         return 1;
1889 }
1890
1891 bool have_file_open_below(connection_struct *conn,
1892                                  const struct smb_filename *name)
1893 {
1894         struct have_file_open_below_state state = {
1895                 .found_one = false,
1896         };
1897         int ret;
1898
1899         if (!VALID_STAT(name->st)) {
1900                 return false;
1901         }
1902         if (!S_ISDIR(name->st.st_ex_mode)) {
1903                 return false;
1904         }
1905
1906         ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1907         if (ret == -1) {
1908                 return false;
1909         }
1910
1911         return state.found_one;
1912 }
1913
1914 /*****************************************************************
1915  Is this directory empty ?
1916 *****************************************************************/
1917
1918 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1919 {
1920         NTSTATUS status = NT_STATUS_OK;
1921         long dirpos = 0;
1922         const char *dname = NULL;
1923         const char *dirname = fsp->fsp_name->base_name;
1924         char *talloced = NULL;
1925         SMB_STRUCT_STAT st;
1926         struct connection_struct *conn = fsp->conn;
1927         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(),
1928                                         conn,
1929                                         fsp->fsp_name,
1930                                         NULL,
1931                                         0);
1932
1933         if (!dir_hnd) {
1934                 return map_nt_error_from_unix(errno);
1935         }
1936
1937         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1938                 /* Quick check for "." and ".." */
1939                 if (dname[0] == '.') {
1940                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1941                                 TALLOC_FREE(talloced);
1942                                 continue;
1943                         }
1944                 }
1945
1946                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1947                         TALLOC_FREE(talloced);
1948                         continue;
1949                 }
1950
1951                 DEBUG(10,("got name %s - can't delete\n",
1952                          dname ));
1953                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1954                 break;
1955         }
1956         TALLOC_FREE(talloced);
1957         TALLOC_FREE(dir_hnd);
1958
1959         if (!NT_STATUS_IS_OK(status)) {
1960                 return status;
1961         }
1962
1963         if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
1964             lp_strict_rename(SNUM(conn)) &&
1965             have_file_open_below(fsp->conn, fsp->fsp_name))
1966         {
1967                 return NT_STATUS_ACCESS_DENIED;
1968         }
1969
1970         return NT_STATUS_OK;
1971 }