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