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