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