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