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