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