s3: dir - Introduce 32-bit wire versions of the 'special' values.
[nivanova/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         return (uint32_t)offset;
909 }
910
911 /****************************************************************************
912  Fill the 5 byte server reserved dptr field.
913 ****************************************************************************/
914
915 bool dptr_fill(struct smbd_server_connection *sconn,
916                char *buf1,unsigned int key)
917 {
918         unsigned char *buf = (unsigned char *)buf1;
919         struct dptr_struct *dptr = dptr_get(sconn, key, false);
920         uint32_t wire_offset;
921         if (!dptr) {
922                 DEBUG(1,("filling null dirptr %d\n",key));
923                 return(False);
924         }
925         wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
926         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
927                 (long)dptr->dir_hnd,(int)wire_offset));
928         buf[0] = key;
929         SIVAL(buf,1,wire_offset);
930         return(True);
931 }
932
933 /****************************************************************************
934  Fetch the dir ptr and seek it given the 5 byte server field.
935 ****************************************************************************/
936
937 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
938                                char *buf, int *num)
939 {
940         unsigned int key = *(unsigned char *)buf;
941         struct dptr_struct *dptr = dptr_get(sconn, key, false);
942         uint32_t wire_offset;
943         long seekoff;
944
945         if (!dptr) {
946                 DEBUG(3,("fetched null dirptr %d\n",key));
947                 return(NULL);
948         }
949         *num = key;
950         wire_offset = IVAL(buf,1);
951         if (wire_offset == (uint32_t)-1) {
952                 seekoff = END_OF_DIRECTORY_OFFSET;
953         } else {
954                 seekoff = (long)wire_offset;
955         }
956         SeekDir(dptr->dir_hnd,seekoff);
957         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
958                 key, dptr->path, (int)seekoff));
959         return(dptr);
960 }
961
962 /****************************************************************************
963  Fetch the dir ptr.
964 ****************************************************************************/
965
966 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
967                                        int dptr_num)
968 {
969         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num, false);
970
971         if (!dptr) {
972                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
973                 return(NULL);
974         }
975         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
976         return(dptr);
977 }
978
979 static bool mangle_mask_match(connection_struct *conn,
980                 const char *filename,
981                 const char *mask)
982 {
983         char mname[13];
984
985         if (!name_to_8_3(filename,mname,False,conn->params)) {
986                 return False;
987         }
988         return mask_match_search(mname,mask,False);
989 }
990
991 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
992                            struct dptr_struct *dirptr,
993                            const char *mask,
994                            uint32_t dirtype,
995                            bool dont_descend,
996                            bool ask_sharemode,
997                            bool (*match_fn)(TALLOC_CTX *ctx,
998                                             void *private_data,
999                                             const char *dname,
1000                                             const char *mask,
1001                                             char **_fname),
1002                            bool (*mode_fn)(TALLOC_CTX *ctx,
1003                                            void *private_data,
1004                                            struct smb_filename *smb_fname,
1005                                            uint32_t *_mode),
1006                            void *private_data,
1007                            char **_fname,
1008                            struct smb_filename **_smb_fname,
1009                            uint32_t *_mode,
1010                            long *_prev_offset)
1011 {
1012         connection_struct *conn = dirptr->conn;
1013         size_t slashlen;
1014         size_t pathlen;
1015
1016         *_smb_fname = NULL;
1017         *_mode = 0;
1018
1019         pathlen = strlen(dirptr->path);
1020         slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
1021
1022         while (true) {
1023                 long cur_offset;
1024                 long prev_offset;
1025                 SMB_STRUCT_STAT sbuf;
1026                 char *dname = NULL;
1027                 bool isdots;
1028                 char *fname = NULL;
1029                 char *pathreal = NULL;
1030                 struct smb_filename smb_fname;
1031                 uint32_t mode = 0;
1032                 bool ok;
1033
1034                 cur_offset = dptr_TellDir(dirptr);
1035                 prev_offset = cur_offset;
1036                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
1037
1038                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
1039                         (long)dirptr, cur_offset));
1040
1041                 if (dname == NULL) {
1042                         return false;
1043                 }
1044
1045                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
1046                 if (dont_descend && !isdots) {
1047                         TALLOC_FREE(dname);
1048                         continue;
1049                 }
1050
1051                 /*
1052                  * fname may get mangled, dname is never mangled.
1053                  * Whenever we're accessing the filesystem we use
1054                  * pathreal which is composed from dname.
1055                  */
1056
1057                 ok = match_fn(ctx, private_data, dname, mask, &fname);
1058                 if (!ok) {
1059                         TALLOC_FREE(dname);
1060                         continue;
1061                 }
1062
1063                 /*
1064                  * This used to be
1065                  * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
1066                  *                            needslash?"/":"", dname);
1067                  * but this was measurably slower than doing the memcpy.
1068                  */
1069
1070                 pathreal = talloc_array(
1071                         ctx, char,
1072                         pathlen + slashlen + talloc_get_size(dname));
1073                 if (!pathreal) {
1074                         TALLOC_FREE(dname);
1075                         TALLOC_FREE(fname);
1076                         return false;
1077                 }
1078
1079                 memcpy(pathreal, dirptr->path, pathlen);
1080                 pathreal[pathlen] = '/';
1081                 memcpy(pathreal + slashlen + pathlen, dname,
1082                        talloc_get_size(dname));
1083
1084                 /* Create smb_fname with NULL stream_name. */
1085                 ZERO_STRUCT(smb_fname);
1086                 smb_fname.base_name = pathreal;
1087                 smb_fname.st = sbuf;
1088
1089                 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1090                 if (!ok) {
1091                         TALLOC_FREE(dname);
1092                         TALLOC_FREE(fname);
1093                         TALLOC_FREE(pathreal);
1094                         continue;
1095                 }
1096
1097                 if (!dir_check_ftype(mode, dirtype)) {
1098                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1099                                 fname, (unsigned int)mode, (unsigned int)dirtype));
1100                         TALLOC_FREE(dname);
1101                         TALLOC_FREE(fname);
1102                         TALLOC_FREE(pathreal);
1103                         continue;
1104                 }
1105
1106                 if (ask_sharemode) {
1107                         struct timespec write_time_ts;
1108                         struct file_id fileid;
1109
1110                         fileid = vfs_file_id_from_sbuf(conn,
1111                                                        &smb_fname.st);
1112                         get_file_infos(fileid, 0, NULL, &write_time_ts);
1113                         if (!null_timespec(write_time_ts)) {
1114                                 update_stat_ex_mtime(&smb_fname.st,
1115                                                      write_time_ts);
1116                         }
1117                 }
1118
1119                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1120                         "fname=%s (%s)\n",
1121                         mask, smb_fname_str_dbg(&smb_fname),
1122                         dname, fname));
1123
1124                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1125
1126                 TALLOC_FREE(dname);
1127
1128                 *_smb_fname = cp_smb_filename(ctx, &smb_fname);
1129                 TALLOC_FREE(pathreal);
1130                 if (*_smb_fname == NULL) {
1131                         return false;
1132                 }
1133                 *_fname = fname;
1134                 *_mode = mode;
1135                 *_prev_offset = prev_offset;
1136
1137                 return true;
1138         }
1139
1140         return false;
1141 }
1142
1143 /****************************************************************************
1144  Get an 8.3 directory entry.
1145 ****************************************************************************/
1146
1147 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1148                                      void *private_data,
1149                                      const char *dname,
1150                                      const char *mask,
1151                                      char **_fname)
1152 {
1153         connection_struct *conn = (connection_struct *)private_data;
1154
1155         if ((strcmp(mask,"*.*") == 0) ||
1156             mask_match_search(dname, mask, false) ||
1157             mangle_mask_match(conn, dname, mask)) {
1158                 char mname[13];
1159                 const char *fname;
1160
1161                 if (!mangle_is_8_3(dname, false, conn->params)) {
1162                         bool ok = name_to_8_3(dname, mname, false,
1163                                               conn->params);
1164                         if (!ok) {
1165                                 return false;
1166                         }
1167                         fname = mname;
1168                 } else {
1169                         fname = dname;
1170                 }
1171
1172                 *_fname = talloc_strdup(ctx, fname);
1173                 if (*_fname == NULL) {
1174                         return false;
1175                 }
1176
1177                 return true;
1178         }
1179
1180         return false;
1181 }
1182
1183 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1184                                     void *private_data,
1185                                     struct smb_filename *smb_fname,
1186                                     uint32_t *_mode)
1187 {
1188         connection_struct *conn = (connection_struct *)private_data;
1189
1190         if (!VALID_STAT(smb_fname->st)) {
1191                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1192                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1193                                  "Couldn't stat [%s]. Error "
1194                                  "= %s\n",
1195                                  smb_fname_str_dbg(smb_fname),
1196                                  strerror(errno)));
1197                         return false;
1198                 }
1199         }
1200
1201         *_mode = dos_mode(conn, smb_fname);
1202         return true;
1203 }
1204
1205 bool get_dir_entry(TALLOC_CTX *ctx,
1206                 struct dptr_struct *dirptr,
1207                 const char *mask,
1208                 uint32_t dirtype,
1209                 char **_fname,
1210                 off_t *_size,
1211                 uint32_t *_mode,
1212                 struct timespec *_date,
1213                 bool check_descend,
1214                 bool ask_sharemode)
1215 {
1216         connection_struct *conn = dirptr->conn;
1217         char *fname = NULL;
1218         struct smb_filename *smb_fname = NULL;
1219         uint32_t mode = 0;
1220         long prev_offset;
1221         bool ok;
1222
1223         ok = smbd_dirptr_get_entry(ctx,
1224                                    dirptr,
1225                                    mask,
1226                                    dirtype,
1227                                    check_descend,
1228                                    ask_sharemode,
1229                                    smbd_dirptr_8_3_match_fn,
1230                                    smbd_dirptr_8_3_mode_fn,
1231                                    conn,
1232                                    &fname,
1233                                    &smb_fname,
1234                                    &mode,
1235                                    &prev_offset);
1236         if (!ok) {
1237                 return false;
1238         }
1239
1240         *_fname = talloc_move(ctx, &fname);
1241         *_size = smb_fname->st.st_ex_size;
1242         *_mode = mode;
1243         *_date = smb_fname->st.st_ex_mtime;
1244         TALLOC_FREE(smb_fname);
1245         return true;
1246 }
1247
1248 /*******************************************************************
1249  Check to see if a user can read a file. This is only approximate,
1250  it is used as part of the "hide unreadable" option. Don't
1251  use it for anything security sensitive.
1252 ********************************************************************/
1253
1254 static bool user_can_read_file(connection_struct *conn,
1255                                struct smb_filename *smb_fname)
1256 {
1257         /*
1258          * Never hide files from the root user.
1259          * We use (uid_t)0 here not sec_initial_uid()
1260          * as make test uses a single user context.
1261          */
1262
1263         if (get_current_uid(conn) == (uid_t)0) {
1264                 return True;
1265         }
1266
1267         return NT_STATUS_IS_OK(smbd_check_access_rights(conn,
1268                                 smb_fname,
1269                                 false,
1270                                 FILE_READ_DATA));
1271 }
1272
1273 /*******************************************************************
1274  Check to see if a user can write a file (and only files, we do not
1275  check dirs on this one). This is only approximate,
1276  it is used as part of the "hide unwriteable" option. Don't
1277  use it for anything security sensitive.
1278 ********************************************************************/
1279
1280 static bool user_can_write_file(connection_struct *conn,
1281                                 const struct smb_filename *smb_fname)
1282 {
1283         /*
1284          * Never hide files from the root user.
1285          * We use (uid_t)0 here not sec_initial_uid()
1286          * as make test uses a single user context.
1287          */
1288
1289         if (get_current_uid(conn) == (uid_t)0) {
1290                 return True;
1291         }
1292
1293         SMB_ASSERT(VALID_STAT(smb_fname->st));
1294
1295         /* Pseudo-open the file */
1296
1297         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1298                 return True;
1299         }
1300
1301         return can_write_to_file(conn, smb_fname);
1302 }
1303
1304 /*******************************************************************
1305   Is a file a "special" type ?
1306 ********************************************************************/
1307
1308 static bool file_is_special(connection_struct *conn,
1309                             const struct smb_filename *smb_fname)
1310 {
1311         /*
1312          * Never hide files from the root user.
1313          * We use (uid_t)0 here not sec_initial_uid()
1314          * as make test uses a single user context.
1315          */
1316
1317         if (get_current_uid(conn) == (uid_t)0) {
1318                 return False;
1319         }
1320
1321         SMB_ASSERT(VALID_STAT(smb_fname->st));
1322
1323         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1324             S_ISDIR(smb_fname->st.st_ex_mode) ||
1325             S_ISLNK(smb_fname->st.st_ex_mode))
1326                 return False;
1327
1328         return True;
1329 }
1330
1331 /*******************************************************************
1332  Should the file be seen by the client?
1333  NOTE: A successful return is no guarantee of the file's existence.
1334 ********************************************************************/
1335
1336 bool is_visible_file(connection_struct *conn, const char *dir_path,
1337                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1338 {
1339         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1340         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1341         bool hide_special = lp_hide_special_files(SNUM(conn));
1342         char *entry = NULL;
1343         struct smb_filename *smb_fname_base = NULL;
1344         bool ret = false;
1345
1346         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1347                 return True; /* . and .. are always visible. */
1348         }
1349
1350         /* If it's a vetoed file, pretend it doesn't even exist */
1351         if (use_veto && IS_VETO_PATH(conn, name)) {
1352                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1353                 return False;
1354         }
1355
1356         if (hide_unreadable || hide_unwriteable || hide_special) {
1357                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1358                 if (!entry) {
1359                         ret = false;
1360                         goto out;
1361                 }
1362
1363                 /* Create an smb_filename with stream_name == NULL. */
1364                 smb_fname_base = synthetic_smb_fname(talloc_tos(), entry, NULL,
1365                                                      pst);
1366                 if (smb_fname_base == NULL) {
1367                         ret = false;
1368                         goto out;
1369                 }
1370
1371                 /* If the file name does not exist, there's no point checking
1372                  * the configuration options. We succeed, on the basis that the
1373                  * checks *might* have passed if the file was present.
1374                  */
1375                 if (!VALID_STAT(*pst)) {
1376                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1377                                 ret = true;
1378                                 goto out;
1379                         } else {
1380                                 *pst = smb_fname_base->st;
1381                         }
1382                 }
1383
1384                 /* Honour _hide unreadable_ option */
1385                 if (hide_unreadable &&
1386                     !user_can_read_file(conn, smb_fname_base)) {
1387                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1388                                  entry ));
1389                         ret = false;
1390                         goto out;
1391                 }
1392                 /* Honour _hide unwriteable_ option */
1393                 if (hide_unwriteable && !user_can_write_file(conn,
1394                                                              smb_fname_base)) {
1395                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1396                                  entry ));
1397                         ret = false;
1398                         goto out;
1399                 }
1400                 /* Honour _hide_special_ option */
1401                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1402                         DEBUG(10,("is_visible_file: file %s is special.\n",
1403                                  entry ));
1404                         ret = false;
1405                         goto out;
1406                 }
1407         }
1408
1409         ret = true;
1410  out:
1411         TALLOC_FREE(smb_fname_base);
1412         TALLOC_FREE(entry);
1413         return ret;
1414 }
1415
1416 static int smb_Dir_destructor(struct smb_Dir *dirp)
1417 {
1418         if (dirp->dir != NULL) {
1419                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1420                 if (dirp->fsp != NULL) {
1421                         /*
1422                          * The SMB_VFS_CLOSEDIR above
1423                          * closes the underlying fd inside
1424                          * dirp->fsp.
1425                          */
1426                         dirp->fsp->fh->fd = -1;
1427                         if (dirp->fsp->dptr != NULL) {
1428                                 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1429                                 dirp->fsp->dptr->dir_hnd = NULL;
1430                         }
1431                         dirp->fsp = NULL;
1432                 }
1433         }
1434         if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1435                 dirp->conn->sconn->searches.dirhandles_open--;
1436         }
1437         return 0;
1438 }
1439
1440 /*******************************************************************
1441  Open a directory.
1442 ********************************************************************/
1443
1444 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1445                         const char *name,
1446                         const char *mask,
1447                         uint32 attr)
1448 {
1449         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1450         struct smbd_server_connection *sconn = conn->sconn;
1451
1452         if (!dirp) {
1453                 return NULL;
1454         }
1455
1456         dirp->conn = conn;
1457         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1458
1459         dirp->dir_path = talloc_strdup(dirp, name);
1460         if (!dirp->dir_path) {
1461                 errno = ENOMEM;
1462                 goto fail;
1463         }
1464
1465         if (sconn && !sconn->using_smb2) {
1466                 sconn->searches.dirhandles_open++;
1467         }
1468         talloc_set_destructor(dirp, smb_Dir_destructor);
1469
1470         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1471         if (!dirp->dir) {
1472                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1473                          strerror(errno) ));
1474                 goto fail;
1475         }
1476
1477         return dirp;
1478
1479   fail:
1480         TALLOC_FREE(dirp);
1481         return NULL;
1482 }
1483
1484 /*******************************************************************
1485  Open a directory from an fsp.
1486 ********************************************************************/
1487
1488 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1489                         files_struct *fsp,
1490                         const char *mask,
1491                         uint32 attr)
1492 {
1493         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1494         struct smbd_server_connection *sconn = conn->sconn;
1495
1496         if (!dirp) {
1497                 return NULL;
1498         }
1499
1500         dirp->conn = conn;
1501         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1502
1503         dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1504         if (!dirp->dir_path) {
1505                 errno = ENOMEM;
1506                 goto fail;
1507         }
1508
1509         if (sconn && !sconn->using_smb2) {
1510                 sconn->searches.dirhandles_open++;
1511         }
1512         talloc_set_destructor(dirp, smb_Dir_destructor);
1513
1514         if (fsp->is_directory && fsp->fh->fd != -1) {
1515                 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1516                 if (dirp->dir != NULL) {
1517                         dirp->fsp = fsp;
1518                 } else {
1519                         DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1520                                 "NULL (%s)\n",
1521                                 dirp->dir_path,
1522                                 strerror(errno)));
1523                         if (errno != ENOSYS) {
1524                                 return NULL;
1525                         }
1526                 }
1527         }
1528
1529         if (dirp->dir == NULL) {
1530                 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1531                 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1532         }
1533
1534         if (!dirp->dir) {
1535                 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1536                          strerror(errno) ));
1537                 goto fail;
1538         }
1539
1540         return dirp;
1541
1542   fail:
1543         TALLOC_FREE(dirp);
1544         return NULL;
1545 }
1546
1547
1548 /*******************************************************************
1549  Read from a directory.
1550  Return directory entry, current offset, and optional stat information.
1551  Don't check for veto or invisible files.
1552 ********************************************************************/
1553
1554 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1555                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1556 {
1557         const char *n;
1558         char *talloced = NULL;
1559         connection_struct *conn = dirp->conn;
1560
1561         /* Cheat to allow . and .. to be the first entries returned. */
1562         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1563              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1564         {
1565                 if (dirp->file_number == 0) {
1566                         n = ".";
1567                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1568                 } else {
1569                         n = "..";
1570                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1571                 }
1572                 dirp->file_number++;
1573                 *ptalloced = NULL;
1574                 return n;
1575         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1576                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1577                 return NULL;
1578         } else {
1579                 /* A real offset, seek to it. */
1580                 SeekDir(dirp, *poffset);
1581         }
1582
1583         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1584                 /* Ignore . and .. - we've already returned them. */
1585                 if (*n == '.') {
1586                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1587                                 TALLOC_FREE(talloced);
1588                                 continue;
1589                         }
1590                 }
1591                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1592                 *ptalloced = talloced;
1593                 dirp->file_number++;
1594                 return n;
1595         }
1596         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1597         *ptalloced = NULL;
1598         return NULL;
1599 }
1600
1601 /*******************************************************************
1602  Rewind to the start.
1603 ********************************************************************/
1604
1605 void RewindDir(struct smb_Dir *dirp, long *poffset)
1606 {
1607         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1608         dirp->file_number = 0;
1609         dirp->offset = START_OF_DIRECTORY_OFFSET;
1610         *poffset = START_OF_DIRECTORY_OFFSET;
1611 }
1612
1613 /*******************************************************************
1614  Seek a dir.
1615 ********************************************************************/
1616
1617 void SeekDir(struct smb_Dir *dirp, long offset)
1618 {
1619         if (offset != dirp->offset) {
1620                 if (offset == START_OF_DIRECTORY_OFFSET) {
1621                         RewindDir(dirp, &offset);
1622                         /*
1623                          * Ok we should really set the file number here
1624                          * to 1 to enable ".." to be returned next. Trouble
1625                          * is I'm worried about callers using SeekDir(dirp,0)
1626                          * as equivalent to RewindDir(). So leave this alone
1627                          * for now.
1628                          */
1629                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1630                         RewindDir(dirp, &offset);
1631                         /*
1632                          * Set the file number to 2 - we want to get the first
1633                          * real file entry (the one we return after "..")
1634                          * on the next ReadDir.
1635                          */
1636                         dirp->file_number = 2;
1637                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1638                         ; /* Don't seek in this case. */
1639                 } else {
1640                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1641                 }
1642                 dirp->offset = offset;
1643         }
1644 }
1645
1646 /*******************************************************************
1647  Tell a dir position.
1648 ********************************************************************/
1649
1650 long TellDir(struct smb_Dir *dirp)
1651 {
1652         return(dirp->offset);
1653 }
1654
1655 /*******************************************************************
1656  Add an entry into the dcache.
1657 ********************************************************************/
1658
1659 static void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1660 {
1661         struct name_cache_entry *e;
1662
1663         if (dirp->name_cache_size == 0) {
1664                 return;
1665         }
1666
1667         if (dirp->name_cache == NULL) {
1668                 dirp->name_cache = talloc_zero_array(
1669                         dirp, struct name_cache_entry, dirp->name_cache_size);
1670
1671                 if (dirp->name_cache == NULL) {
1672                         return;
1673                 }
1674         }
1675
1676         dirp->name_cache_index = (dirp->name_cache_index+1) %
1677                                         dirp->name_cache_size;
1678         e = &dirp->name_cache[dirp->name_cache_index];
1679         TALLOC_FREE(e->name);
1680         e->name = talloc_strdup(dirp, name);
1681         e->offset = offset;
1682 }
1683
1684 /*******************************************************************
1685  Find an entry by name. Leave us at the offset after it.
1686  Don't check for veto or invisible files.
1687 ********************************************************************/
1688
1689 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1690 {
1691         int i;
1692         const char *entry = NULL;
1693         char *talloced = NULL;
1694         connection_struct *conn = dirp->conn;
1695
1696         /* Search back in the name cache. */
1697         if (dirp->name_cache_size && dirp->name_cache) {
1698                 for (i = dirp->name_cache_index; i >= 0; i--) {
1699                         struct name_cache_entry *e = &dirp->name_cache[i];
1700                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1701                                 *poffset = e->offset;
1702                                 SeekDir(dirp, e->offset);
1703                                 return True;
1704                         }
1705                 }
1706                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1707                         struct name_cache_entry *e = &dirp->name_cache[i];
1708                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1709                                 *poffset = e->offset;
1710                                 SeekDir(dirp, e->offset);
1711                                 return True;
1712                         }
1713                 }
1714         }
1715
1716         /* Not found in the name cache. Rewind directory and start from scratch. */
1717         SMB_VFS_REWINDDIR(conn, dirp->dir);
1718         dirp->file_number = 0;
1719         *poffset = START_OF_DIRECTORY_OFFSET;
1720         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1721                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1722                         TALLOC_FREE(talloced);
1723                         return True;
1724                 }
1725                 TALLOC_FREE(talloced);
1726         }
1727         return False;
1728 }
1729
1730 /*****************************************************************
1731  Is this directory empty ?
1732 *****************************************************************/
1733
1734 NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1735 {
1736         NTSTATUS status = NT_STATUS_OK;
1737         long dirpos = 0;
1738         const char *dname = NULL;
1739         const char *dirname = fsp->fsp_name->base_name;
1740         char *talloced = NULL;
1741         SMB_STRUCT_STAT st;
1742         struct connection_struct *conn = fsp->conn;
1743         struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1744                                         conn,
1745                                         fsp,
1746                                         NULL,
1747                                         0);
1748
1749         if (!dir_hnd) {
1750                 return map_nt_error_from_unix(errno);
1751         }
1752
1753         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1754                 /* Quick check for "." and ".." */
1755                 if (dname[0] == '.') {
1756                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1757                                 TALLOC_FREE(talloced);
1758                                 continue;
1759                         }
1760                 }
1761
1762                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1763                         TALLOC_FREE(talloced);
1764                         continue;
1765                 }
1766
1767                 DEBUG(10,("got name %s - can't delete\n",
1768                          dname ));
1769                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1770                 break;
1771         }
1772         TALLOC_FREE(talloced);
1773         TALLOC_FREE(dir_hnd);
1774
1775         return status;
1776 }