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