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