Call check_parent_access() on readdir.
[mat/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         NTSTATUS status;
431
432         if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
433                 path = fsp->fsp_name->base_name;
434         }
435
436         DEBUG(5,("dptr_create dir=%s\n", path));
437
438         if (sconn == NULL) {
439                 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
440                 return NT_STATUS_INTERNAL_ERROR;
441         }
442
443         if (!wcard) {
444                 return NT_STATUS_INVALID_PARAMETER;
445         }
446
447         status = check_parent_access(conn,
448                                 path,
449                                 SEC_DIR_LIST,
450                                 NULL);
451         if (!NT_STATUS_IS_OK(status)) {
452                 DEBUG(5,("dptr_create: parent access check for path "
453                         "%s failed with %s\n",
454                         path,
455                         nt_errstr(status)));
456                 return status;
457         }
458
459         if (fsp) {
460                 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
461         } else {
462                 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
463         }
464
465         if (!dir_hnd) {
466                 return map_nt_error_from_unix(errno);
467         }
468
469         if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
470                 dptr_idleoldest(sconn);
471         }
472
473         dptr = SMB_MALLOC_P(struct dptr_struct);
474         if(!dptr) {
475                 DEBUG(0,("malloc fail in dptr_create.\n"));
476                 TALLOC_FREE(dir_hnd);
477                 return NT_STATUS_NO_MEMORY;
478         }
479
480         ZERO_STRUCTP(dptr);
481
482         if(old_handle) {
483
484                 /*
485                  * This is an old-style SMBsearch request. Ensure the
486                  * value we return will fit in the range 1-255.
487                  */
488
489                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
490
491                 if(dptr->dnum == -1 || dptr->dnum > 254) {
492
493                         /*
494                          * Try and close the oldest handle not marked for
495                          * expect close in the hope that the client has
496                          * finished with that one.
497                          */
498
499                         dptr_close_oldest(sconn, true);
500
501                         /* Now try again... */
502                         dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
503                         if(dptr->dnum == -1 || dptr->dnum > 254) {
504                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
505                                 SAFE_FREE(dptr);
506                                 TALLOC_FREE(dir_hnd);
507                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
508                         }
509                 }
510         } else {
511
512                 /*
513                  * This is a new-style trans2 request. Allocate from
514                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
515                  */
516
517                 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
518
519                 if(dptr->dnum == -1 || dptr->dnum < 255) {
520
521                         /*
522                          * Try and close the oldest handle close in the hope that
523                          * the client has finished with that one. This will only
524                          * happen in the case of the Win98 client bug where it leaks
525                          * directory handles.
526                          */
527
528                         dptr_close_oldest(sconn, false);
529
530                         /* Now try again... */
531                         dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
532
533                         if(dptr->dnum == -1 || dptr->dnum < 255) {
534                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
535                                 SAFE_FREE(dptr);
536                                 TALLOC_FREE(dir_hnd);
537                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
538                         }
539                 }
540         }
541
542         bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
543
544         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
545
546         string_set(&dptr->path,path);
547         dptr->conn = conn;
548         dptr->dir_hnd = dir_hnd;
549         dptr->spid = spid;
550         dptr->expect_close = expect_close;
551         dptr->wcard = SMB_STRDUP(wcard);
552         if (!dptr->wcard) {
553                 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
554                 SAFE_FREE(dptr);
555                 TALLOC_FREE(dir_hnd);
556                 return NT_STATUS_NO_MEMORY;
557         }
558         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
559                 dptr->has_wild = True;
560         } else {
561                 dptr->has_wild = wcard_has_wild;
562         }
563
564         dptr->attr = attr;
565
566         DLIST_ADD(sconn->searches.dirptrs, dptr);
567
568         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
569                 dptr->dnum,path,expect_close));  
570
571         *dptr_ret = dptr;
572
573         return NT_STATUS_OK;
574 }
575
576
577 /****************************************************************************
578  Wrapper functions to access the lower level directory handles.
579 ****************************************************************************/
580
581 void dptr_CloseDir(files_struct *fsp)
582 {
583         if (fsp->dptr) {
584 /*
585  * Ugly hack. We have defined fdopendir to return ENOSYS if dirfd also isn't
586  * present. I hate Solaris. JRA.
587  */
588 #ifdef HAVE_DIRFD
589                 if (fsp->fh->fd != -1 &&
590                                 fsp->dptr->dir_hnd &&
591                                 dirfd(fsp->dptr->dir_hnd->dir)) {
592                         /* The call below closes the underlying fd. */
593                         fsp->fh->fd = -1;
594                 }
595 #endif
596                 dptr_close_internal(fsp->dptr);
597                 fsp->dptr = NULL;
598         }
599 }
600
601 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
602 {
603         SeekDir(dptr->dir_hnd, offset);
604 }
605
606 long dptr_TellDir(struct dptr_struct *dptr)
607 {
608         return TellDir(dptr->dir_hnd);
609 }
610
611 bool dptr_has_wild(struct dptr_struct *dptr)
612 {
613         return dptr->has_wild;
614 }
615
616 int dptr_dnum(struct dptr_struct *dptr)
617 {
618         return dptr->dnum;
619 }
620
621 /****************************************************************************
622  Return the next visible file name, skipping veto'd and invisible files.
623 ****************************************************************************/
624
625 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
626                                            long *poffset, SMB_STRUCT_STAT *pst,
627                                            char **ptalloced)
628 {
629         /* Normal search for the next file. */
630         const char *name;
631         char *talloced = NULL;
632
633         while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
634                != NULL) {
635                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
636                         *ptalloced = talloced;
637                         return name;
638                 }
639                 TALLOC_FREE(talloced);
640         }
641         return NULL;
642 }
643
644 /****************************************************************************
645  Return the next visible file name, skipping veto'd and invisible files.
646 ****************************************************************************/
647
648 char *dptr_ReadDirName(TALLOC_CTX *ctx,
649                         struct dptr_struct *dptr,
650                         long *poffset,
651                         SMB_STRUCT_STAT *pst)
652 {
653         struct smb_filename smb_fname_base;
654         char *name = NULL;
655         const char *name_temp = NULL;
656         char *talloced = NULL;
657         char *pathreal = NULL;
658         char *found_name = NULL;
659         int ret;
660
661         SET_STAT_INVALID(*pst);
662
663         if (dptr->has_wild || dptr->did_stat) {
664                 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
665                                                     &talloced);
666                 if (name_temp == NULL) {
667                         return NULL;
668                 }
669                 if (talloced != NULL) {
670                         return talloc_move(ctx, &talloced);
671                 }
672                 return talloc_strdup(ctx, name_temp);
673         }
674
675         /* If poffset is -1 then we know we returned this name before and we
676          * have no wildcards. We're at the end of the directory. */
677         if (*poffset == END_OF_DIRECTORY_OFFSET) {
678                 return NULL;
679         }
680
681         /* We know the stored wcard contains no wildcard characters.
682          * See if we can match with a stat call. If we can't, then set
683          * did_stat to true to ensure we only do this once and keep
684          * searching. */
685
686         dptr->did_stat = true;
687
688         /* First check if it should be visible. */
689         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
690             pst, true))
691         {
692                 /* This only returns false if the file was found, but
693                    is explicitly not visible. Set us to end of
694                    directory, but return NULL as we know we can't ever
695                    find it. */
696                 goto ret;
697         }
698
699         if (VALID_STAT(*pst)) {
700                 name = talloc_strdup(ctx, dptr->wcard);
701                 goto ret;
702         }
703
704         pathreal = talloc_asprintf(ctx,
705                                 "%s/%s",
706                                 dptr->path,
707                                 dptr->wcard);
708         if (!pathreal)
709                 return NULL;
710
711         /* Create an smb_filename with stream_name == NULL. */
712         ZERO_STRUCT(smb_fname_base);
713         smb_fname_base.base_name = pathreal;
714
715         if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
716                 *pst = smb_fname_base.st;
717                 name = talloc_strdup(ctx, dptr->wcard);
718                 goto clean;
719         } else {
720                 /* If we get any other error than ENOENT or ENOTDIR
721                    then the file exists we just can't stat it. */
722                 if (errno != ENOENT && errno != ENOTDIR) {
723                         name = talloc_strdup(ctx, dptr->wcard);
724                         goto clean;
725                 }
726         }
727
728         /* Stat failed. We know this is authoratiative if we are
729          * providing case sensitive semantics or the underlying
730          * filesystem is case sensitive.
731          */
732         if (dptr->conn->case_sensitive ||
733             !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
734         {
735                 goto clean;
736         }
737
738         /*
739          * Try case-insensitive stat if the fs has the ability. This avoids
740          * scanning the whole directory.
741          */
742         ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
743                                         ctx, &found_name);
744         if (ret == 0) {
745                 name = found_name;
746                 goto clean;
747         } else if (errno == ENOENT) {
748                 /* The case-insensitive lookup was authoritative. */
749                 goto clean;
750         }
751
752         TALLOC_FREE(pathreal);
753
754         name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
755         if (name_temp == NULL) {
756                 return NULL;
757         }
758         if (talloced != NULL) {
759                 return talloc_move(ctx, &talloced);
760         }
761         return talloc_strdup(ctx, name_temp);
762
763 clean:
764         TALLOC_FREE(pathreal);
765 ret:
766         /* We need to set the underlying dir_hnd offset to -1
767          * also as this function is usually called with the
768          * output from TellDir. */
769         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
770         return name;
771 }
772
773 /****************************************************************************
774  Search for a file by name, skipping veto'ed and not visible files.
775 ****************************************************************************/
776
777 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
778 {
779         SET_STAT_INVALID(*pst);
780
781         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
782                 /* This is a singleton directory and we're already at the end. */
783                 *poffset = END_OF_DIRECTORY_OFFSET;
784                 return False;
785         }
786
787         return SearchDir(dptr->dir_hnd, name, poffset);
788 }
789
790 /****************************************************************************
791  Add the name we're returning into the underlying cache.
792 ****************************************************************************/
793
794 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
795 {
796         DirCacheAdd(dptr->dir_hnd, name, offset);
797 }
798
799 /****************************************************************************
800  Initialize variables & state data at the beginning of all search SMB requests.
801 ****************************************************************************/
802 void dptr_init_search_op(struct dptr_struct *dptr)
803 {
804         SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
805 }
806
807 /****************************************************************************
808  Fill the 5 byte server reserved dptr field.
809 ****************************************************************************/
810
811 bool dptr_fill(struct smbd_server_connection *sconn,
812                char *buf1,unsigned int key)
813 {
814         unsigned char *buf = (unsigned char *)buf1;
815         struct dptr_struct *dptr = dptr_get(sconn, key, false);
816         uint32 offset;
817         if (!dptr) {
818                 DEBUG(1,("filling null dirptr %d\n",key));
819                 return(False);
820         }
821         offset = (uint32)TellDir(dptr->dir_hnd);
822         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
823                 (long)dptr->dir_hnd,(int)offset));
824         buf[0] = key;
825         SIVAL(buf,1,offset);
826         return(True);
827 }
828
829 /****************************************************************************
830  Fetch the dir ptr and seek it given the 5 byte server field.
831 ****************************************************************************/
832
833 struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
834                                char *buf, int *num)
835 {
836         unsigned int key = *(unsigned char *)buf;
837         struct dptr_struct *dptr = dptr_get(sconn, key, false);
838         uint32 offset;
839         long seekoff;
840
841         if (!dptr) {
842                 DEBUG(3,("fetched null dirptr %d\n",key));
843                 return(NULL);
844         }
845         *num = key;
846         offset = IVAL(buf,1);
847         if (offset == (uint32)-1) {
848                 seekoff = END_OF_DIRECTORY_OFFSET;
849         } else {
850                 seekoff = (long)offset;
851         }
852         SeekDir(dptr->dir_hnd,seekoff);
853         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
854                 key, dptr->path, (int)seekoff));
855         return(dptr);
856 }
857
858 /****************************************************************************
859  Fetch the dir ptr.
860 ****************************************************************************/
861
862 struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
863                                        int dptr_num)
864 {
865         struct dptr_struct *dptr  = dptr_get(sconn, dptr_num, false);
866
867         if (!dptr) {
868                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
869                 return(NULL);
870         }
871         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
872         return(dptr);
873 }
874
875 /****************************************************************************
876  Check that a file matches a particular file type.
877 ****************************************************************************/
878
879 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
880 {
881         uint32 mask;
882
883         /* Check the "may have" search bits. */
884         if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
885                 return False;
886
887         /* Check the "must have" bits, which are the may have bits shifted eight */
888         /* If must have bit is set, the file/dir can not be returned in search unless the matching
889                 file attribute is set */
890         mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
891         if(mask) {
892                 if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask)   /* check if matching attribute present */
893                         return True;
894                 else
895                         return False;
896         }
897
898         return True;
899 }
900
901 static bool mangle_mask_match(connection_struct *conn,
902                 const char *filename,
903                 const char *mask)
904 {
905         char mname[13];
906
907         if (!name_to_8_3(filename,mname,False,conn->params)) {
908                 return False;
909         }
910         return mask_match_search(mname,mask,False);
911 }
912
913 bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
914                            struct dptr_struct *dirptr,
915                            const char *mask,
916                            uint32_t dirtype,
917                            bool dont_descend,
918                            bool ask_sharemode,
919                            bool (*match_fn)(TALLOC_CTX *ctx,
920                                             void *private_data,
921                                             const char *dname,
922                                             const char *mask,
923                                             char **_fname),
924                            bool (*mode_fn)(TALLOC_CTX *ctx,
925                                            void *private_data,
926                                            struct smb_filename *smb_fname,
927                                            uint32_t *_mode),
928                            void *private_data,
929                            char **_fname,
930                            struct smb_filename **_smb_fname,
931                            uint32_t *_mode,
932                            long *_prev_offset)
933 {
934         connection_struct *conn = dirptr->conn;
935         bool needslash;
936
937         *_smb_fname = NULL;
938         *_mode = 0;
939
940         needslash = ( dirptr->path[strlen(dirptr->path) -1] != '/');
941
942         while (true) {
943                 long cur_offset;
944                 long prev_offset;
945                 SMB_STRUCT_STAT sbuf;
946                 char *dname = NULL;
947                 bool isdots;
948                 char *fname = NULL;
949                 char *pathreal = NULL;
950                 struct smb_filename smb_fname;
951                 uint32_t mode = 0;
952                 bool ok;
953                 NTSTATUS status;
954
955                 cur_offset = dptr_TellDir(dirptr);
956                 prev_offset = cur_offset;
957                 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
958
959                 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
960                         (long)dirptr, cur_offset));
961
962                 if (dname == NULL) {
963                         return false;
964                 }
965
966                 isdots = (ISDOT(dname) || ISDOTDOT(dname));
967                 if (dont_descend && !isdots) {
968                         TALLOC_FREE(dname);
969                         continue;
970                 }
971
972                 /*
973                  * fname may get mangled, dname is never mangled.
974                  * Whenever we're accessing the filesystem we use
975                  * pathreal which is composed from dname.
976                  */
977
978                 ok = match_fn(ctx, private_data, dname, mask, &fname);
979                 if (!ok) {
980                         TALLOC_FREE(dname);
981                         continue;
982                 }
983
984                 pathreal = talloc_asprintf(ctx, "%s%s%s",
985                                            dirptr->path,
986                                            needslash?"/":"",
987                                            dname);
988                 if (!pathreal) {
989                         TALLOC_FREE(dname);
990                         TALLOC_FREE(fname);
991                         return false;
992                 }
993
994                 /* Create smb_fname with NULL stream_name. */
995                 ZERO_STRUCT(smb_fname);
996                 smb_fname.base_name = pathreal;
997                 smb_fname.st = sbuf;
998
999                 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1000                 if (!ok) {
1001                         TALLOC_FREE(dname);
1002                         TALLOC_FREE(fname);
1003                         TALLOC_FREE(pathreal);
1004                         continue;
1005                 }
1006
1007                 if (!dir_check_ftype(conn, mode, dirtype)) {
1008                         DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1009                                 fname, (unsigned int)mode, (unsigned int)dirtype));
1010                         TALLOC_FREE(dname);
1011                         TALLOC_FREE(fname);
1012                         TALLOC_FREE(pathreal);
1013                         continue;
1014                 }
1015
1016                 if (ask_sharemode) {
1017                         struct timespec write_time_ts;
1018                         struct file_id fileid;
1019
1020                         fileid = vfs_file_id_from_sbuf(conn,
1021                                                        &smb_fname.st);
1022                         get_file_infos(fileid, 0, NULL, &write_time_ts);
1023                         if (!null_timespec(write_time_ts)) {
1024                                 update_stat_ex_mtime(&smb_fname.st,
1025                                                      write_time_ts);
1026                         }
1027                 }
1028
1029                 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1030                         "fname=%s (%s)\n",
1031                         mask, smb_fname_str_dbg(&smb_fname),
1032                         dname, fname));
1033
1034                 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1035
1036                 TALLOC_FREE(dname);
1037
1038                 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1039                 TALLOC_FREE(pathreal);
1040                 if (!NT_STATUS_IS_OK(status)) {
1041                         return false;
1042                 }
1043                 *_fname = fname;
1044                 *_mode = mode;
1045                 *_prev_offset = prev_offset;
1046
1047                 return true;
1048         }
1049
1050         return false;
1051 }
1052
1053 /****************************************************************************
1054  Get an 8.3 directory entry.
1055 ****************************************************************************/
1056
1057 static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1058                                      void *private_data,
1059                                      const char *dname,
1060                                      const char *mask,
1061                                      char **_fname)
1062 {
1063         connection_struct *conn = (connection_struct *)private_data;
1064
1065         if ((strcmp(mask,"*.*") == 0) ||
1066             mask_match_search(dname, mask, false) ||
1067             mangle_mask_match(conn, dname, mask)) {
1068                 char mname[13];
1069                 const char *fname;
1070
1071                 if (!mangle_is_8_3(dname, false, conn->params)) {
1072                         bool ok = name_to_8_3(dname, mname, false,
1073                                               conn->params);
1074                         if (!ok) {
1075                                 return false;
1076                         }
1077                         fname = mname;
1078                 } else {
1079                         fname = dname;
1080                 }
1081
1082                 *_fname = talloc_strdup(ctx, fname);
1083                 if (*_fname == NULL) {
1084                         return false;
1085                 }
1086
1087                 return true;
1088         }
1089
1090         return false;
1091 }
1092
1093 static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1094                                     void *private_data,
1095                                     struct smb_filename *smb_fname,
1096                                     uint32_t *_mode)
1097 {
1098         connection_struct *conn = (connection_struct *)private_data;
1099
1100         if (!VALID_STAT(smb_fname->st)) {
1101                 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1102                         DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1103                                  "Couldn't stat [%s]. Error "
1104                                  "= %s\n",
1105                                  smb_fname_str_dbg(smb_fname),
1106                                  strerror(errno)));
1107                         return false;
1108                 }
1109         }
1110
1111         *_mode = dos_mode(conn, smb_fname);
1112         return true;
1113 }
1114
1115 bool get_dir_entry(TALLOC_CTX *ctx,
1116                 struct dptr_struct *dirptr,
1117                 const char *mask,
1118                 uint32_t dirtype,
1119                 char **_fname,
1120                 SMB_OFF_T *_size,
1121                 uint32_t *_mode,
1122                 struct timespec *_date,
1123                 bool check_descend,
1124                 bool ask_sharemode)
1125 {
1126         connection_struct *conn = dirptr->conn;
1127         char *fname = NULL;
1128         struct smb_filename *smb_fname = NULL;
1129         uint32_t mode = 0;
1130         long prev_offset;
1131         bool ok;
1132
1133         ok = smbd_dirptr_get_entry(ctx,
1134                                    dirptr,
1135                                    mask,
1136                                    dirtype,
1137                                    check_descend,
1138                                    ask_sharemode,
1139                                    smbd_dirptr_8_3_match_fn,
1140                                    smbd_dirptr_8_3_mode_fn,
1141                                    conn,
1142                                    &fname,
1143                                    &smb_fname,
1144                                    &mode,
1145                                    &prev_offset);
1146         if (!ok) {
1147                 return false;
1148         }
1149
1150         *_fname = talloc_move(ctx, &fname);
1151         *_size = smb_fname->st.st_ex_size;
1152         *_mode = mode;
1153         *_date = smb_fname->st.st_ex_mtime;
1154         TALLOC_FREE(smb_fname);
1155         return true;
1156 }
1157
1158 /*******************************************************************
1159  Check to see if a user can read a file. This is only approximate,
1160  it is used as part of the "hide unreadable" option. Don't
1161  use it for anything security sensitive.
1162 ********************************************************************/
1163
1164 static bool user_can_read_file(connection_struct *conn,
1165                                struct smb_filename *smb_fname)
1166 {
1167         /*
1168          * Never hide files from the root user.
1169          * We use (uid_t)0 here not sec_initial_uid()
1170          * as make test uses a single user context.
1171          */
1172
1173         if (get_current_uid(conn) == (uid_t)0) {
1174                 return True;
1175         }
1176
1177         return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1178 }
1179
1180 /*******************************************************************
1181  Check to see if a user can write a file (and only files, we do not
1182  check dirs on this one). This is only approximate,
1183  it is used as part of the "hide unwriteable" option. Don't
1184  use it for anything security sensitive.
1185 ********************************************************************/
1186
1187 static bool user_can_write_file(connection_struct *conn,
1188                                 const struct smb_filename *smb_fname)
1189 {
1190         /*
1191          * Never hide files from the root user.
1192          * We use (uid_t)0 here not sec_initial_uid()
1193          * as make test uses a single user context.
1194          */
1195
1196         if (get_current_uid(conn) == (uid_t)0) {
1197                 return True;
1198         }
1199
1200         SMB_ASSERT(VALID_STAT(smb_fname->st));
1201
1202         /* Pseudo-open the file */
1203
1204         if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1205                 return True;
1206         }
1207
1208         return can_write_to_file(conn, smb_fname);
1209 }
1210
1211 /*******************************************************************
1212   Is a file a "special" type ?
1213 ********************************************************************/
1214
1215 static bool file_is_special(connection_struct *conn,
1216                             const struct smb_filename *smb_fname)
1217 {
1218         /*
1219          * Never hide files from the root user.
1220          * We use (uid_t)0 here not sec_initial_uid()
1221          * as make test uses a single user context.
1222          */
1223
1224         if (get_current_uid(conn) == (uid_t)0) {
1225                 return False;
1226         }
1227
1228         SMB_ASSERT(VALID_STAT(smb_fname->st));
1229
1230         if (S_ISREG(smb_fname->st.st_ex_mode) ||
1231             S_ISDIR(smb_fname->st.st_ex_mode) ||
1232             S_ISLNK(smb_fname->st.st_ex_mode))
1233                 return False;
1234
1235         return True;
1236 }
1237
1238 /*******************************************************************
1239  Should the file be seen by the client?
1240  NOTE: A successful return is no guarantee of the file's existence.
1241 ********************************************************************/
1242
1243 bool is_visible_file(connection_struct *conn, const char *dir_path,
1244                      const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1245 {
1246         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1247         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1248         bool hide_special = lp_hide_special_files(SNUM(conn));
1249         char *entry = NULL;
1250         struct smb_filename *smb_fname_base = NULL;
1251         NTSTATUS status;
1252         bool ret = false;
1253
1254         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1255                 return True; /* . and .. are always visible. */
1256         }
1257
1258         /* If it's a vetoed file, pretend it doesn't even exist */
1259         if (use_veto && IS_VETO_PATH(conn, name)) {
1260                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1261                 return False;
1262         }
1263
1264         if (hide_unreadable || hide_unwriteable || hide_special) {
1265                 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1266                 if (!entry) {
1267                         ret = false;
1268                         goto out;
1269                 }
1270
1271                 /* Create an smb_filename with stream_name == NULL. */
1272                 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1273                                                     pst, &smb_fname_base);
1274                 if (!NT_STATUS_IS_OK(status)) {
1275                         ret = false;
1276                         goto out;
1277                 }
1278
1279                 /* If the file name does not exist, there's no point checking
1280                  * the configuration options. We succeed, on the basis that the
1281                  * checks *might* have passed if the file was present.
1282                  */
1283                 if (!VALID_STAT(*pst)) {
1284                         if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1285                                 ret = true;
1286                                 goto out;
1287                         } else {
1288                                 *pst = smb_fname_base->st;
1289                         }
1290                 }
1291
1292                 /* Honour _hide unreadable_ option */
1293                 if (hide_unreadable &&
1294                     !user_can_read_file(conn, smb_fname_base)) {
1295                         DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1296                                  entry ));
1297                         ret = false;
1298                         goto out;
1299                 }
1300                 /* Honour _hide unwriteable_ option */
1301                 if (hide_unwriteable && !user_can_write_file(conn,
1302                                                              smb_fname_base)) {
1303                         DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1304                                  entry ));
1305                         ret = false;
1306                         goto out;
1307                 }
1308                 /* Honour _hide_special_ option */
1309                 if (hide_special && file_is_special(conn, smb_fname_base)) {
1310                         DEBUG(10,("is_visible_file: file %s is special.\n",
1311                                  entry ));
1312                         ret = false;
1313                         goto out;
1314                 }
1315         }
1316
1317         ret = true;
1318  out:
1319         TALLOC_FREE(smb_fname_base);
1320         TALLOC_FREE(entry);
1321         return ret;
1322 }
1323
1324 static int smb_Dir_destructor(struct smb_Dir *dirp)
1325 {
1326         if (dirp->dir) {
1327 #ifdef HAVE_DIRFD
1328                 if (dirp->conn->sconn) {
1329                         files_struct *fsp = file_find_fd(dirp->conn->sconn,
1330                                                 dirfd(dirp->dir));
1331                         if (fsp) {
1332                                 /* The call below closes the underlying fd. */
1333                                 fsp->fh->fd = -1;
1334                         }
1335                 }
1336 #endif
1337                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1338         }
1339         if (dirp->conn->sconn) {
1340                 dirp->conn->sconn->searches.dirhandles_open--;
1341         }
1342         return 0;
1343 }
1344
1345 /*******************************************************************
1346  Open a directory.
1347 ********************************************************************/
1348
1349 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1350                         const char *name,
1351                         const char *mask,
1352                         uint32 attr)
1353 {
1354         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1355         struct smbd_server_connection *sconn = conn->sconn;
1356
1357         if (!dirp) {
1358                 return NULL;
1359         }
1360
1361         dirp->conn = conn;
1362         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1363
1364         dirp->dir_path = talloc_strdup(dirp, name);
1365         if (!dirp->dir_path) {
1366                 errno = ENOMEM;
1367                 goto fail;
1368         }
1369
1370         if (sconn) {
1371                 sconn->searches.dirhandles_open++;
1372         }
1373         talloc_set_destructor(dirp, smb_Dir_destructor);
1374
1375         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1376         if (!dirp->dir) {
1377                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1378                          strerror(errno) ));
1379                 goto fail;
1380         }
1381
1382         return dirp;
1383
1384   fail:
1385         TALLOC_FREE(dirp);
1386         return NULL;
1387 }
1388
1389 /*******************************************************************
1390  Open a directory from an fsp.
1391 ********************************************************************/
1392
1393 static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1394                         files_struct *fsp,
1395                         const char *mask,
1396                         uint32 attr)
1397 {
1398         struct smb_Dir *dirp = talloc_zero(mem_ctx, struct smb_Dir);
1399         struct smbd_server_connection *sconn = conn->sconn;
1400
1401         if (!dirp) {
1402                 return NULL;
1403         }
1404
1405         dirp->conn = conn;
1406         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1407
1408         dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1409         if (!dirp->dir_path) {
1410                 errno = ENOMEM;
1411                 goto fail;
1412         }
1413
1414         if (sconn) {
1415                 sconn->searches.dirhandles_open++;
1416         }
1417         talloc_set_destructor(dirp, smb_Dir_destructor);
1418
1419         if (fsp->is_directory && fsp->fh->fd != -1) {
1420                 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1421                 if (dirp->dir == NULL) {
1422                         DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1423                                 "NULL (%s)\n",
1424                                 dirp->dir_path,
1425                                 strerror(errno)));
1426                         if (errno != ENOSYS) {
1427                                 return NULL;
1428                         }
1429                 }
1430         }
1431
1432         if (dirp->dir == NULL) {
1433                 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1434                 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1435         }
1436
1437         if (!dirp->dir) {
1438                 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1439                          strerror(errno) ));
1440                 goto fail;
1441         }
1442
1443         return dirp;
1444
1445   fail:
1446         TALLOC_FREE(dirp);
1447         return NULL;
1448 }
1449
1450
1451 /*******************************************************************
1452  Read from a directory.
1453  Return directory entry, current offset, and optional stat information.
1454  Don't check for veto or invisible files.
1455 ********************************************************************/
1456
1457 const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1458                         SMB_STRUCT_STAT *sbuf, char **ptalloced)
1459 {
1460         const char *n;
1461         char *talloced = NULL;
1462         connection_struct *conn = dirp->conn;
1463
1464         /* Cheat to allow . and .. to be the first entries returned. */
1465         if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1466              (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1467         {
1468                 if (dirp->file_number == 0) {
1469                         n = ".";
1470                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1471                 } else {
1472                         n = "..";
1473                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1474                 }
1475                 dirp->file_number++;
1476                 *ptalloced = NULL;
1477                 return n;
1478         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1479                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1480                 return NULL;
1481         } else {
1482                 /* A real offset, seek to it. */
1483                 SeekDir(dirp, *poffset);
1484         }
1485
1486         while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1487                 /* Ignore . and .. - we've already returned them. */
1488                 if (*n == '.') {
1489                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1490                                 TALLOC_FREE(talloced);
1491                                 continue;
1492                         }
1493                 }
1494                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1495                 *ptalloced = talloced;
1496                 dirp->file_number++;
1497                 return n;
1498         }
1499         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1500         *ptalloced = NULL;
1501         return NULL;
1502 }
1503
1504 /*******************************************************************
1505  Rewind to the start.
1506 ********************************************************************/
1507
1508 void RewindDir(struct smb_Dir *dirp, long *poffset)
1509 {
1510         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1511         dirp->file_number = 0;
1512         dirp->offset = START_OF_DIRECTORY_OFFSET;
1513         *poffset = START_OF_DIRECTORY_OFFSET;
1514 }
1515
1516 /*******************************************************************
1517  Seek a dir.
1518 ********************************************************************/
1519
1520 void SeekDir(struct smb_Dir *dirp, long offset)
1521 {
1522         if (offset != dirp->offset) {
1523                 if (offset == START_OF_DIRECTORY_OFFSET) {
1524                         RewindDir(dirp, &offset);
1525                         /*
1526                          * Ok we should really set the file number here
1527                          * to 1 to enable ".." to be returned next. Trouble
1528                          * is I'm worried about callers using SeekDir(dirp,0)
1529                          * as equivalent to RewindDir(). So leave this alone
1530                          * for now.
1531                          */
1532                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1533                         RewindDir(dirp, &offset);
1534                         /*
1535                          * Set the file number to 2 - we want to get the first
1536                          * real file entry (the one we return after "..")
1537                          * on the next ReadDir.
1538                          */
1539                         dirp->file_number = 2;
1540                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1541                         ; /* Don't seek in this case. */
1542                 } else {
1543                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1544                 }
1545                 dirp->offset = offset;
1546         }
1547 }
1548
1549 /*******************************************************************
1550  Tell a dir position.
1551 ********************************************************************/
1552
1553 long TellDir(struct smb_Dir *dirp)
1554 {
1555         return(dirp->offset);
1556 }
1557
1558 /*******************************************************************
1559  Add an entry into the dcache.
1560 ********************************************************************/
1561
1562 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1563 {
1564         struct name_cache_entry *e;
1565
1566         if (dirp->name_cache_size == 0) {
1567                 return;
1568         }
1569
1570         if (dirp->name_cache == NULL) {
1571                 dirp->name_cache = talloc_zero_array(
1572                         dirp, struct name_cache_entry, dirp->name_cache_size);
1573
1574                 if (dirp->name_cache == NULL) {
1575                         return;
1576                 }
1577         }
1578
1579         dirp->name_cache_index = (dirp->name_cache_index+1) %
1580                                         dirp->name_cache_size;
1581         e = &dirp->name_cache[dirp->name_cache_index];
1582         TALLOC_FREE(e->name);
1583         e->name = talloc_strdup(dirp, name);
1584         e->offset = offset;
1585 }
1586
1587 /*******************************************************************
1588  Find an entry by name. Leave us at the offset after it.
1589  Don't check for veto or invisible files.
1590 ********************************************************************/
1591
1592 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1593 {
1594         int i;
1595         const char *entry = NULL;
1596         char *talloced = NULL;
1597         connection_struct *conn = dirp->conn;
1598
1599         /* Search back in the name cache. */
1600         if (dirp->name_cache_size && dirp->name_cache) {
1601                 for (i = dirp->name_cache_index; i >= 0; i--) {
1602                         struct name_cache_entry *e = &dirp->name_cache[i];
1603                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1604                                 *poffset = e->offset;
1605                                 SeekDir(dirp, e->offset);
1606                                 return True;
1607                         }
1608                 }
1609                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1610                         struct name_cache_entry *e = &dirp->name_cache[i];
1611                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1612                                 *poffset = e->offset;
1613                                 SeekDir(dirp, e->offset);
1614                                 return True;
1615                         }
1616                 }
1617         }
1618
1619         /* Not found in the name cache. Rewind directory and start from scratch. */
1620         SMB_VFS_REWINDDIR(conn, dirp->dir);
1621         dirp->file_number = 0;
1622         *poffset = START_OF_DIRECTORY_OFFSET;
1623         while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1624                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1625                         TALLOC_FREE(talloced);
1626                         return True;
1627                 }
1628                 TALLOC_FREE(talloced);
1629         }
1630         return False;
1631 }
1632
1633 /*****************************************************************
1634  Is this directory empty ?
1635 *****************************************************************/
1636
1637 NTSTATUS smbd_can_delete_directory(struct connection_struct *conn,
1638                                    const char *dirname)
1639 {
1640         NTSTATUS status = NT_STATUS_OK;
1641         long dirpos = 0;
1642         const char *dname = NULL;
1643         char *talloced = NULL;
1644         SMB_STRUCT_STAT st;
1645         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
1646                                         dirname, NULL, 0);
1647
1648         if (!dir_hnd) {
1649                 return map_nt_error_from_unix(errno);
1650         }
1651
1652         while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1653                 /* Quick check for "." and ".." */
1654                 if (dname[0] == '.') {
1655                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1656                                 TALLOC_FREE(talloced);
1657                                 continue;
1658                         }
1659                 }
1660
1661                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1662                         TALLOC_FREE(talloced);
1663                         continue;
1664                 }
1665
1666                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n",
1667                          dname ));
1668                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1669                 break;
1670         }
1671         TALLOC_FREE(talloced);
1672         TALLOC_FREE(dir_hnd);
1673
1674         return status;
1675 }