file_access: remove unneeded stat buf parameter from can_access_file_acl().
[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
23 /*
24    This module implements directory related functions for Samba.
25 */
26
27 /* "Special" directory offsets. */
28 #define END_OF_DIRECTORY_OFFSET ((long)-1)
29 #define START_OF_DIRECTORY_OFFSET ((long)0)
30 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
31
32 /* Make directory handle internals available. */
33
34 struct name_cache_entry {
35         char *name;
36         long offset;
37 };
38
39 struct smb_Dir {
40         connection_struct *conn;
41         SMB_STRUCT_DIR *dir;
42         long offset;
43         char *dir_path;
44         size_t name_cache_size;
45         struct name_cache_entry *name_cache;
46         unsigned int name_cache_index;
47         unsigned int file_number;
48 };
49
50 struct dptr_struct {
51         struct dptr_struct *next, *prev;
52         int dnum;
53         uint16 spid;
54         struct connection_struct *conn;
55         struct smb_Dir *dir_hnd;
56         bool expect_close;
57         char *wcard;
58         uint32 attr;
59         char *path;
60         bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
61         bool did_stat; /* Optimisation for non-wcard searches. */
62 };
63
64 static struct bitmap *dptr_bmap;
65 static struct dptr_struct *dirptrs;
66 static int dirhandles_open = 0;
67
68 #define INVALID_DPTR_KEY (-3)
69
70 /****************************************************************************
71  Make a dir struct.
72 ****************************************************************************/
73
74 bool make_dir_struct(TALLOC_CTX *ctx,
75                         char *buf,
76                         const char *mask,
77                         const char *fname,
78                         SMB_OFF_T size,
79                         uint32 mode,
80                         time_t date,
81                         bool uc)
82 {
83         char *p;
84         char *mask2 = talloc_strdup(ctx, mask);
85
86         if (!mask2) {
87                 return False;
88         }
89
90         if ((mode & aDIR) != 0) {
91                 size = 0;
92         }
93
94         memset(buf+1,' ',11);
95         if ((p = strchr_m(mask2,'.')) != NULL) {
96                 *p = 0;
97                 push_ascii(buf+1,mask2,8, 0);
98                 push_ascii(buf+9,p+1,3, 0);
99                 *p = '.';
100         } else {
101                 push_ascii(buf+1,mask2,11, 0);
102         }
103
104         memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
105         SCVAL(buf,21,mode);
106         srv_put_dos_date(buf,22,date);
107         SSVAL(buf,26,size & 0xFFFF);
108         SSVAL(buf,28,(size >> 16)&0xFFFF);
109         /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
110            Strange, but verified on W2K3. Needed for OS/2. JRA. */
111         push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
112         DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
113         return True;
114 }
115
116 /****************************************************************************
117  Initialise the dir bitmap.
118 ****************************************************************************/
119
120 void init_dptrs(void)
121 {
122         static bool dptrs_init=False;
123
124         if (dptrs_init)
125                 return;
126
127         dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
128
129         if (!dptr_bmap)
130                 exit_server("out of memory in init_dptrs");
131
132         dptrs_init = True;
133 }
134
135 /****************************************************************************
136  Idle a dptr - the directory is closed but the control info is kept.
137 ****************************************************************************/
138
139 static void dptr_idle(struct dptr_struct *dptr)
140 {
141         if (dptr->dir_hnd) {
142                 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
143                 TALLOC_FREE(dptr->dir_hnd);
144         }
145 }
146
147 /****************************************************************************
148  Idle the oldest dptr.
149 ****************************************************************************/
150
151 static void dptr_idleoldest(void)
152 {
153         struct dptr_struct *dptr;
154
155         /*
156          * Go to the end of the list.
157          */
158         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
159                 ;
160
161         if(!dptr) {
162                 DEBUG(0,("No dptrs available to idle ?\n"));
163                 return;
164         }
165
166         /*
167          * Idle the oldest pointer.
168          */
169
170         for(; dptr; dptr = dptr->prev) {
171                 if (dptr->dir_hnd) {
172                         dptr_idle(dptr);
173                         return;
174                 }
175         }
176 }
177
178 /****************************************************************************
179  Get the struct dptr_struct for a dir index.
180 ****************************************************************************/
181
182 static struct dptr_struct *dptr_get(int key, bool forclose)
183 {
184         struct dptr_struct *dptr;
185
186         for(dptr = dirptrs; dptr; dptr = dptr->next) {
187                 if(dptr->dnum == key) {
188                         if (!forclose && !dptr->dir_hnd) {
189                                 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
190                                         dptr_idleoldest();
191                                 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
192                                 if (!(dptr->dir_hnd = OpenDir(
193                                               NULL, dptr->conn, dptr->path,
194                                               dptr->wcard, dptr->attr))) {
195                                         DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
196                                                 strerror(errno)));
197                                         return False;
198                                 }
199                         }
200                         DLIST_PROMOTE(dirptrs,dptr);
201                         return dptr;
202                 }
203         }
204         return(NULL);
205 }
206
207 /****************************************************************************
208  Get the dir path for a dir index.
209 ****************************************************************************/
210
211 char *dptr_path(int key)
212 {
213         struct dptr_struct *dptr = dptr_get(key, False);
214         if (dptr)
215                 return(dptr->path);
216         return(NULL);
217 }
218
219 /****************************************************************************
220  Get the dir wcard for a dir index.
221 ****************************************************************************/
222
223 char *dptr_wcard(int key)
224 {
225         struct dptr_struct *dptr = dptr_get(key, False);
226         if (dptr)
227                 return(dptr->wcard);
228         return(NULL);
229 }
230
231 /****************************************************************************
232  Get the dir attrib for a dir index.
233 ****************************************************************************/
234
235 uint16 dptr_attr(int key)
236 {
237         struct dptr_struct *dptr = dptr_get(key, False);
238         if (dptr)
239                 return(dptr->attr);
240         return(0);
241 }
242
243 /****************************************************************************
244  Close a dptr (internal func).
245 ****************************************************************************/
246
247 static void dptr_close_internal(struct dptr_struct *dptr)
248 {
249         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
250
251         DLIST_REMOVE(dirptrs, dptr);
252
253         /*
254          * Free the dnum in the bitmap. Remember the dnum value is always 
255          * biased by one with respect to the bitmap.
256          */
257
258         if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
259                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
260                         dptr->dnum ));
261         }
262
263         bitmap_clear(dptr_bmap, dptr->dnum - 1);
264
265         TALLOC_FREE(dptr->dir_hnd);
266
267         /* Lanman 2 specific code */
268         SAFE_FREE(dptr->wcard);
269         string_set(&dptr->path,"");
270         SAFE_FREE(dptr);
271 }
272
273 /****************************************************************************
274  Close a dptr given a key.
275 ****************************************************************************/
276
277 void dptr_close(int *key)
278 {
279         struct dptr_struct *dptr;
280
281         if(*key == INVALID_DPTR_KEY)
282                 return;
283
284         /* OS/2 seems to use -1 to indicate "close all directories" */
285         if (*key == -1) {
286                 struct dptr_struct *next;
287                 for(dptr = dirptrs; dptr; dptr = next) {
288                         next = dptr->next;
289                         dptr_close_internal(dptr);
290                 }
291                 *key = INVALID_DPTR_KEY;
292                 return;
293         }
294
295         dptr = dptr_get(*key, True);
296
297         if (!dptr) {
298                 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
299                 return;
300         }
301
302         dptr_close_internal(dptr);
303
304         *key = INVALID_DPTR_KEY;
305 }
306
307 /****************************************************************************
308  Close all dptrs for a cnum.
309 ****************************************************************************/
310
311 void dptr_closecnum(connection_struct *conn)
312 {
313         struct dptr_struct *dptr, *next;
314         for(dptr = dirptrs; dptr; dptr = next) {
315                 next = dptr->next;
316                 if (dptr->conn == conn)
317                         dptr_close_internal(dptr);
318         }
319 }
320
321 /****************************************************************************
322  Idle all dptrs for a cnum.
323 ****************************************************************************/
324
325 void dptr_idlecnum(connection_struct *conn)
326 {
327         struct dptr_struct *dptr;
328         for(dptr = dirptrs; dptr; dptr = dptr->next) {
329                 if (dptr->conn == conn && dptr->dir_hnd)
330                         dptr_idle(dptr);
331         }
332 }
333
334 /****************************************************************************
335  Close a dptr that matches a given path, only if it matches the spid also.
336 ****************************************************************************/
337
338 void dptr_closepath(char *path,uint16 spid)
339 {
340         struct dptr_struct *dptr, *next;
341         for(dptr = dirptrs; dptr; dptr = next) {
342                 next = dptr->next;
343                 if (spid == dptr->spid && strequal(dptr->path,path))
344                         dptr_close_internal(dptr);
345         }
346 }
347
348 /****************************************************************************
349  Try and close the oldest handle not marked for
350  expect close in the hope that the client has
351  finished with that one.
352 ****************************************************************************/
353
354 static void dptr_close_oldest(bool old)
355 {
356         struct dptr_struct *dptr;
357
358         /*
359          * Go to the end of the list.
360          */
361         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
362                 ;
363
364         if(!dptr) {
365                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
366                 return;
367         }
368
369         /*
370          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
371          * does not have expect_close set. If 'old' is false, close
372          * one of the new dnum handles.
373          */
374
375         for(; dptr; dptr = dptr->prev) {
376                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
377                         (!old && (dptr->dnum > 255))) {
378                                 dptr_close_internal(dptr);
379                                 return;
380                 }
381         }
382 }
383
384 /****************************************************************************
385  Create a new dir ptr. If the flag old_handle is true then we must allocate
386  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
387  one byte long. If old_handle is false we allocate from the range
388  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
389  a directory handle is never zero.
390  wcard must not be zero.
391 ****************************************************************************/
392
393 NTSTATUS dptr_create(connection_struct *conn, const char *path, bool old_handle, bool expect_close,uint16 spid,
394                 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
395 {
396         struct dptr_struct *dptr = NULL;
397         struct smb_Dir *dir_hnd;
398         NTSTATUS status;
399
400         DEBUG(5,("dptr_create dir=%s\n", path));
401
402         if (!wcard) {
403                 return NT_STATUS_INVALID_PARAMETER;
404         }
405
406         status = check_name(conn,path);
407         if (!NT_STATUS_IS_OK(status)) {
408                 return status;
409         }
410
411         dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
412         if (!dir_hnd) {
413                 return map_nt_error_from_unix(errno);
414         }
415
416         string_set(&conn->dirpath,path);
417
418         if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
419                 dptr_idleoldest();
420         }
421
422         dptr = SMB_MALLOC_P(struct dptr_struct);
423         if(!dptr) {
424                 DEBUG(0,("malloc fail in dptr_create.\n"));
425                 TALLOC_FREE(dir_hnd);
426                 return NT_STATUS_NO_MEMORY;
427         }
428
429         ZERO_STRUCTP(dptr);
430
431         if(old_handle) {
432
433                 /*
434                  * This is an old-style SMBsearch request. Ensure the
435                  * value we return will fit in the range 1-255.
436                  */
437
438                 dptr->dnum = bitmap_find(dptr_bmap, 0);
439
440                 if(dptr->dnum == -1 || dptr->dnum > 254) {
441
442                         /*
443                          * Try and close the oldest handle not marked for
444                          * expect close in the hope that the client has
445                          * finished with that one.
446                          */
447
448                         dptr_close_oldest(True);
449
450                         /* Now try again... */
451                         dptr->dnum = bitmap_find(dptr_bmap, 0);
452                         if(dptr->dnum == -1 || dptr->dnum > 254) {
453                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
454                                 SAFE_FREE(dptr);
455                                 TALLOC_FREE(dir_hnd);
456                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
457                         }
458                 }
459         } else {
460
461                 /*
462                  * This is a new-style trans2 request. Allocate from
463                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
464                  */
465
466                 dptr->dnum = bitmap_find(dptr_bmap, 255);
467
468                 if(dptr->dnum == -1 || dptr->dnum < 255) {
469
470                         /*
471                          * Try and close the oldest handle close in the hope that
472                          * the client has finished with that one. This will only
473                          * happen in the case of the Win98 client bug where it leaks
474                          * directory handles.
475                          */
476
477                         dptr_close_oldest(False);
478
479                         /* Now try again... */
480                         dptr->dnum = bitmap_find(dptr_bmap, 255);
481
482                         if(dptr->dnum == -1 || dptr->dnum < 255) {
483                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
484                                 SAFE_FREE(dptr);
485                                 TALLOC_FREE(dir_hnd);
486                                 return NT_STATUS_TOO_MANY_OPENED_FILES;
487                         }
488                 }
489         }
490
491         bitmap_set(dptr_bmap, dptr->dnum);
492
493         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
494
495         string_set(&dptr->path,path);
496         dptr->conn = conn;
497         dptr->dir_hnd = dir_hnd;
498         dptr->spid = spid;
499         dptr->expect_close = expect_close;
500         dptr->wcard = SMB_STRDUP(wcard);
501         if (!dptr->wcard) {
502                 bitmap_clear(dptr_bmap, dptr->dnum - 1);
503                 SAFE_FREE(dptr);
504                 TALLOC_FREE(dir_hnd);
505                 return NT_STATUS_NO_MEMORY;
506         }
507         if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
508                 dptr->has_wild = True;
509         } else {
510                 dptr->has_wild = wcard_has_wild;
511         }
512
513         dptr->attr = attr;
514
515         DLIST_ADD(dirptrs, dptr);
516
517         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
518                 dptr->dnum,path,expect_close));  
519
520         *dptr_ret = dptr;
521
522         return NT_STATUS_OK;
523 }
524
525
526 /****************************************************************************
527  Wrapper functions to access the lower level directory handles.
528 ****************************************************************************/
529
530 int dptr_CloseDir(struct dptr_struct *dptr)
531 {
532         DLIST_REMOVE(dirptrs, dptr);
533         TALLOC_FREE(dptr->dir_hnd);
534         return 0;
535 }
536
537 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
538 {
539         SeekDir(dptr->dir_hnd, offset);
540 }
541
542 long dptr_TellDir(struct dptr_struct *dptr)
543 {
544         return TellDir(dptr->dir_hnd);
545 }
546
547 bool dptr_has_wild(struct dptr_struct *dptr)
548 {
549         return dptr->has_wild;
550 }
551
552 int dptr_dnum(struct dptr_struct *dptr)
553 {
554         return dptr->dnum;
555 }
556
557 /****************************************************************************
558  Return the next visible file name, skipping veto'd and invisible files.
559 ****************************************************************************/
560
561 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
562 {
563         /* Normal search for the next file. */
564         const char *name;
565         while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
566                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
567                         return name;
568                 }
569         }
570         return NULL;
571 }
572
573 /****************************************************************************
574  Return the next visible file name, skipping veto'd and invisible files.
575 ****************************************************************************/
576
577 const char *dptr_ReadDirName(TALLOC_CTX *ctx,
578                         struct dptr_struct *dptr,
579                         long *poffset,
580                         SMB_STRUCT_STAT *pst)
581 {
582         SET_STAT_INVALID(*pst);
583
584         if (dptr->has_wild) {
585                 return dptr_normal_ReadDirName(dptr, poffset, pst);
586         }
587
588         /* If poffset is -1 then we know we returned this name before and we have
589            no wildcards. We're at the end of the directory. */
590         if (*poffset == END_OF_DIRECTORY_OFFSET) {
591                 return NULL;
592         }
593
594         if (!dptr->did_stat) {
595                 char *pathreal = NULL;
596
597                 /* We know the stored wcard contains no wildcard characters. See if we can match
598                    with a stat call. If we can't, then set did_stat to true to
599                    ensure we only do this once and keep searching. */
600
601                 dptr->did_stat = True;
602
603                 /* First check if it should be visible. */
604                 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
605                         /* This only returns False if the file was found, but
606                            is explicitly not visible. Set us to end of directory,
607                            but return NULL as we know we can't ever find it. */
608                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
609                         return NULL;
610                 }
611
612                 if (VALID_STAT(*pst)) {
613                         /* We need to set the underlying dir_hnd offset to -1 also as
614                            this function is usually called with the output from TellDir. */
615                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
616                         return dptr->wcard;
617                 }
618
619                 pathreal = talloc_asprintf(ctx,
620                                         "%s/%s",
621                                         dptr->path,
622                                         dptr->wcard);
623                 if (!pathreal) {
624                         return NULL;
625                 }
626
627                 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
628                         /* We need to set the underlying dir_hnd offset to -1 also as
629                            this function is usually called with the output from TellDir. */
630                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
631                         TALLOC_FREE(pathreal);
632                         return dptr->wcard;
633                 } else {
634                         /* If we get any other error than ENOENT or ENOTDIR
635                            then the file exists we just can't stat it. */
636                         if (errno != ENOENT && errno != ENOTDIR) {
637                                 /* We need to set the underlying dir_hdn offset to -1 also as
638                                    this function is usually called with the output from TellDir. */
639                                 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
640                                 TALLOC_FREE(pathreal);
641                                 return dptr->wcard;
642                         }
643                 }
644
645                 TALLOC_FREE(pathreal);
646
647                 /* Stat failed. We know this is authoratiative if we are
648                  * providing case sensitive semantics or the underlying
649                  * filesystem is case sensitive.
650                  */
651
652                 if (dptr->conn->case_sensitive ||
653                     !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
654                         /* We need to set the underlying dir_hnd offset to -1 also as
655                            this function is usually called with the output from TellDir. */
656                         dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
657                         return NULL;
658                 }
659         }
660         return dptr_normal_ReadDirName(dptr, poffset, pst);
661 }
662
663 /****************************************************************************
664  Search for a file by name, skipping veto'ed and not visible files.
665 ****************************************************************************/
666
667 bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
668 {
669         SET_STAT_INVALID(*pst);
670
671         if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
672                 /* This is a singleton directory and we're already at the end. */
673                 *poffset = END_OF_DIRECTORY_OFFSET;
674                 return False;
675         }
676
677         return SearchDir(dptr->dir_hnd, name, poffset);
678 }
679
680 /****************************************************************************
681  Add the name we're returning into the underlying cache.
682 ****************************************************************************/
683
684 void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
685 {
686         DirCacheAdd(dptr->dir_hnd, name, offset);
687 }
688
689 /****************************************************************************
690  Fill the 5 byte server reserved dptr field.
691 ****************************************************************************/
692
693 bool dptr_fill(char *buf1,unsigned int key)
694 {
695         unsigned char *buf = (unsigned char *)buf1;
696         struct dptr_struct *dptr = dptr_get(key, False);
697         uint32 offset;
698         if (!dptr) {
699                 DEBUG(1,("filling null dirptr %d\n",key));
700                 return(False);
701         }
702         offset = (uint32)TellDir(dptr->dir_hnd);
703         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
704                 (long)dptr->dir_hnd,(int)offset));
705         buf[0] = key;
706         SIVAL(buf,1,offset);
707         return(True);
708 }
709
710 /****************************************************************************
711  Fetch the dir ptr and seek it given the 5 byte server field.
712 ****************************************************************************/
713
714 struct dptr_struct *dptr_fetch(char *buf,int *num)
715 {
716         unsigned int key = *(unsigned char *)buf;
717         struct dptr_struct *dptr = dptr_get(key, False);
718         uint32 offset;
719         long seekoff;
720
721         if (!dptr) {
722                 DEBUG(3,("fetched null dirptr %d\n",key));
723                 return(NULL);
724         }
725         *num = key;
726         offset = IVAL(buf,1);
727         if (offset == (uint32)-1) {
728                 seekoff = END_OF_DIRECTORY_OFFSET;
729         } else {
730                 seekoff = (long)offset;
731         }
732         SeekDir(dptr->dir_hnd,seekoff);
733         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
734                 key,dptr_path(key),(int)seekoff));
735         return(dptr);
736 }
737
738 /****************************************************************************
739  Fetch the dir ptr.
740 ****************************************************************************/
741
742 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
743 {
744         struct dptr_struct *dptr  = dptr_get(dptr_num, False);
745
746         if (!dptr) {
747                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
748                 return(NULL);
749         }
750         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
751         return(dptr);
752 }
753
754 /****************************************************************************
755  Check that a file matches a particular file type.
756 ****************************************************************************/
757
758 bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
759 {
760         uint32 mask;
761
762         /* Check the "may have" search bits. */
763         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
764                 return False;
765
766         /* Check the "must have" bits, which are the may have bits shifted eight */
767         /* If must have bit is set, the file/dir can not be returned in search unless the matching
768                 file attribute is set */
769         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
770         if(mask) {
771                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
772                         return True;
773                 else
774                         return False;
775         }
776
777         return True;
778 }
779
780 static bool mangle_mask_match(connection_struct *conn,
781                 const char *filename,
782                 const char *mask)
783 {
784         char mname[13];
785
786         if (!name_to_8_3(filename,mname,False,conn->params)) {
787                 return False;
788         }
789         return mask_match_search(mname,mask,False);
790 }
791
792 /****************************************************************************
793  Get an 8.3 directory entry.
794 ****************************************************************************/
795
796 bool get_dir_entry(TALLOC_CTX *ctx,
797                 connection_struct *conn,
798                 const char *mask,
799                 uint32 dirtype,
800                 char **pp_fname_out,
801                 SMB_OFF_T *size,
802                 uint32 *mode,
803                 time_t *date,
804                 bool check_descend,
805                 bool ask_sharemode)
806 {
807         const char *dname = NULL;
808         bool found = False;
809         SMB_STRUCT_STAT sbuf;
810         char *pathreal = NULL;
811         const char *filename = NULL;
812         bool needslash;
813
814         *pp_fname_out = NULL;
815
816         needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
817
818         if (!conn->dirptr) {
819                 return(False);
820         }
821
822         while (!found) {
823                 long curoff = dptr_TellDir(conn->dirptr);
824                 dname = dptr_ReadDirName(ctx, conn->dirptr, &curoff, &sbuf);
825
826                 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
827                         (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
828
829                 if (dname == NULL) {
830                         return(False);
831                 }
832
833                 filename = dname;
834
835                 /* notice the special *.* handling. This appears to be the only difference
836                         between the wildcard handling in this routine and in the trans2 routines.
837                         see masktest for a demo
838                 */
839                 if ((strcmp(mask,"*.*") == 0) ||
840                     mask_match_search(filename,mask,False) ||
841                     mangle_mask_match(conn,filename,mask)) {
842                         char mname[13];
843
844                         if (!mangle_is_8_3(filename, False, conn->params)) {
845                                 if (!name_to_8_3(filename,mname,False,
846                                            conn->params)) {
847                                         continue;
848                                 }
849                                 filename = mname;
850                         }
851
852                         if (needslash) {
853                                 pathreal = talloc_asprintf(ctx,
854                                                 "%s/%s",
855                                                 conn->dirpath,
856                                                 dname);
857                         } else {
858                                 pathreal = talloc_asprintf(ctx,
859                                                 "%s%s",
860                                                 conn->dirpath,
861                                                 dname);
862                         }
863                         if (!pathreal) {
864                                 return False;
865                         }
866
867                         if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
868                                 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",
869                                         pathreal, strerror(errno) ));
870                                 TALLOC_FREE(pathreal);
871                                 continue;
872                         }
873
874                         *mode = dos_mode(conn,pathreal,&sbuf);
875
876                         if (!dir_check_ftype(conn,*mode,dirtype)) {
877                                 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype));
878                                 TALLOC_FREE(pathreal);
879                                 continue;
880                         }
881
882                         *size = sbuf.st_size;
883                         *date = sbuf.st_mtime;
884
885                         if (ask_sharemode) {
886                                 struct timespec write_time_ts;
887                                 struct file_id fileid;
888
889                                 fileid = vfs_file_id_from_sbuf(conn, &sbuf);
890                                 get_file_infos(fileid, NULL, &write_time_ts);
891                                 if (!null_timespec(write_time_ts)) {
892                                         *date = convert_timespec_to_time_t(write_time_ts);
893                                 }
894                         }
895
896                         DEBUG(3,("get_dir_entry mask=[%s] found %s "
897                                 "fname=%s (%s)\n",
898                                 mask,
899                                 pathreal,
900                                 dname,
901                                 filename));
902
903                         found = True;
904
905                         *pp_fname_out = talloc_strdup(ctx, filename);
906                         if (!*pp_fname_out) {
907                                 return False;
908                         }
909
910                         DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff);
911                         TALLOC_FREE(pathreal);
912                 }
913         }
914
915         return(found);
916 }
917
918 /*******************************************************************
919  Check to see if a user can read a file. This is only approximate,
920  it is used as part of the "hide unreadable" option. Don't
921  use it for anything security sensitive.
922 ********************************************************************/
923
924 static bool user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
925 {
926         /*
927          * If user is a member of the Admin group
928          * we never hide files from them.
929          */
930
931         if (conn->admin_user) {
932                 return True;
933         }
934
935         SMB_ASSERT(VALID_STAT(*pst));
936
937         return can_access_file_acl(conn, name, FILE_READ_DATA);
938 }
939
940 /*******************************************************************
941  Check to see if a user can write a file (and only files, we do not
942  check dirs on this one). This is only approximate,
943  it is used as part of the "hide unwriteable" option. Don't
944  use it for anything security sensitive.
945 ********************************************************************/
946
947 static bool user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
948 {
949         /*
950          * If user is a member of the Admin group
951          * we never hide files from them.
952          */
953
954         if (conn->admin_user) {
955                 return True;
956         }
957
958         SMB_ASSERT(VALID_STAT(*pst));
959
960         /* Pseudo-open the file */
961
962         if(S_ISDIR(pst->st_mode)) {
963                 return True;
964         }
965
966         return can_write_to_file(conn, name, pst);
967 }
968
969 /*******************************************************************
970   Is a file a "special" type ?
971 ********************************************************************/
972
973 static bool file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
974 {
975         /*
976          * If user is a member of the Admin group
977          * we never hide files from them.
978          */
979
980         if (conn->admin_user)
981                 return False;
982
983         SMB_ASSERT(VALID_STAT(*pst));
984
985         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
986                 return False;
987
988         return True;
989 }
990
991 /*******************************************************************
992  Should the file be seen by the client ? NOTE: A successful return
993  is no guarantee of the file's existence ... you also have to check
994  whether pst is valid.
995 ********************************************************************/
996
997 bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
998 {
999         bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1000         bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1001         bool hide_special = lp_hide_special_files(SNUM(conn));
1002
1003         SET_STAT_INVALID(*pst);
1004
1005         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1006                 return True; /* . and .. are always visible. */
1007         }
1008
1009         /* If it's a vetoed file, pretend it doesn't even exist */
1010         if (use_veto && IS_VETO_PATH(conn, name)) {
1011                 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1012                 return False;
1013         }
1014
1015         if (hide_unreadable || hide_unwriteable || hide_special) {
1016                 char *entry = NULL;
1017
1018                 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
1019                         return False;
1020                 }
1021
1022                 /* If it's a dfs symlink, ignore _hide xxxx_ options */
1023                 if (lp_host_msdfs() &&
1024                                 lp_msdfs_root(SNUM(conn)) &&
1025                                 is_msdfs_link(conn, entry, NULL)) {
1026                         SAFE_FREE(entry);
1027                         return True;
1028                 }
1029
1030                 /* If the file name does not exist, there's no point checking
1031                  * the configuration options. We succeed, on the basis that the
1032                  * checks *might* have passed if the file was present.
1033                  */
1034                 if (SMB_VFS_STAT(conn, entry, pst) != 0) {
1035                         SAFE_FREE(entry);
1036                         return True;
1037                 }
1038
1039                 /* Honour _hide unreadable_ option */
1040                 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
1041                         DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
1042                         SAFE_FREE(entry);
1043                         return False;
1044                 }
1045                 /* Honour _hide unwriteable_ option */
1046                 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
1047                         DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
1048                         SAFE_FREE(entry);
1049                         return False;
1050                 }
1051                 /* Honour _hide_special_ option */
1052                 if (hide_special && file_is_special(conn, entry, pst)) {
1053                         DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
1054                         SAFE_FREE(entry);
1055                         return False;
1056                 }
1057                 SAFE_FREE(entry);
1058         }
1059         return True;
1060 }
1061
1062 static int smb_Dir_destructor(struct smb_Dir *dirp)
1063 {
1064         if (dirp->dir) {
1065                 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1066         }
1067         dirhandles_open--;
1068         return 0;
1069 }
1070
1071 /*******************************************************************
1072  Open a directory.
1073 ********************************************************************/
1074
1075 struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1076                         const char *name, const char *mask, uint32 attr)
1077 {
1078         struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1079
1080         if (!dirp) {
1081                 return NULL;
1082         }
1083
1084         dirp->conn = conn;
1085         dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1086
1087         dirp->dir_path = talloc_strdup(dirp, name);
1088         if (!dirp->dir_path) {
1089                 goto fail;
1090         }
1091
1092         dirhandles_open++;
1093         talloc_set_destructor(dirp, smb_Dir_destructor);
1094
1095         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1096         if (!dirp->dir) {
1097                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1098                          strerror(errno) ));
1099                 goto fail;
1100         }
1101
1102         return dirp;
1103
1104   fail:
1105         TALLOC_FREE(dirp);
1106         return NULL;
1107 }
1108
1109 /*******************************************************************
1110  Read from a directory. Also return current offset.
1111  Don't check for veto or invisible files.
1112 ********************************************************************/
1113
1114 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1115 {
1116         const char *n;
1117         connection_struct *conn = dirp->conn;
1118
1119         /* Cheat to allow . and .. to be the first entries returned. */
1120         if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
1121                 if (dirp->file_number == 0) {
1122                         n = ".";
1123                         *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1124                 } else {
1125                         *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1126                         n = "..";
1127                 }
1128                 dirp->file_number++;
1129                 return n;
1130         } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1131                 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1132                 return NULL;
1133         } else {
1134                 /* A real offset, seek to it. */
1135                 SeekDir(dirp, *poffset);
1136         }
1137
1138         while ((n = vfs_readdirname(conn, dirp->dir))) {
1139                 /* Ignore . and .. - we've already returned them. */
1140                 if (*n == '.') {
1141                         if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1142                                 continue;
1143                         }
1144                 }
1145                 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1146                 dirp->file_number++;
1147                 return n;
1148         }
1149         *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1150         return NULL;
1151 }
1152
1153 /*******************************************************************
1154  Rewind to the start.
1155 ********************************************************************/
1156
1157 void RewindDir(struct smb_Dir *dirp, long *poffset)
1158 {
1159         SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1160         dirp->file_number = 0;
1161         dirp->offset = START_OF_DIRECTORY_OFFSET;
1162         *poffset = START_OF_DIRECTORY_OFFSET;
1163 }
1164
1165 /*******************************************************************
1166  Seek a dir.
1167 ********************************************************************/
1168
1169 void SeekDir(struct smb_Dir *dirp, long offset)
1170 {
1171         if (offset != dirp->offset) {
1172                 if (offset == START_OF_DIRECTORY_OFFSET) {
1173                         RewindDir(dirp, &offset);
1174                         /*
1175                          * Ok we should really set the file number here
1176                          * to 1 to enable ".." to be returned next. Trouble
1177                          * is I'm worried about callers using SeekDir(dirp,0)
1178                          * as equivalent to RewindDir(). So leave this alone
1179                          * for now.
1180                          */
1181                 } else if  (offset == DOT_DOT_DIRECTORY_OFFSET) {
1182                         RewindDir(dirp, &offset);
1183                         /*
1184                          * Set the file number to 2 - we want to get the first
1185                          * real file entry (the one we return after "..")
1186                          * on the next ReadDir.
1187                          */
1188                         dirp->file_number = 2;
1189                 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1190                         ; /* Don't seek in this case. */
1191                 } else {
1192                         SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1193                 }
1194                 dirp->offset = offset;
1195         }
1196 }
1197
1198 /*******************************************************************
1199  Tell a dir position.
1200 ********************************************************************/
1201
1202 long TellDir(struct smb_Dir *dirp)
1203 {
1204         return(dirp->offset);
1205 }
1206
1207 /*******************************************************************
1208  Add an entry into the dcache.
1209 ********************************************************************/
1210
1211 void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1212 {
1213         struct name_cache_entry *e;
1214
1215         if (dirp->name_cache_size == 0) {
1216                 return;
1217         }
1218
1219         if (dirp->name_cache == NULL) {
1220                 dirp->name_cache = TALLOC_ZERO_ARRAY(
1221                         dirp, struct name_cache_entry, dirp->name_cache_size);
1222
1223                 if (dirp->name_cache == NULL) {
1224                         return;
1225                 }
1226         }
1227
1228         dirp->name_cache_index = (dirp->name_cache_index+1) %
1229                                         dirp->name_cache_size;
1230         e = &dirp->name_cache[dirp->name_cache_index];
1231         TALLOC_FREE(e->name);
1232         e->name = talloc_strdup(dirp, name);
1233         e->offset = offset;
1234 }
1235
1236 /*******************************************************************
1237  Find an entry by name. Leave us at the offset after it.
1238  Don't check for veto or invisible files.
1239 ********************************************************************/
1240
1241 bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1242 {
1243         int i;
1244         const char *entry;
1245         connection_struct *conn = dirp->conn;
1246
1247         /* Search back in the name cache. */
1248         if (dirp->name_cache_size && dirp->name_cache) {
1249                 for (i = dirp->name_cache_index; i >= 0; i--) {
1250                         struct name_cache_entry *e = &dirp->name_cache[i];
1251                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1252                                 *poffset = e->offset;
1253                                 SeekDir(dirp, e->offset);
1254                                 return True;
1255                         }
1256                 }
1257                 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1258                         struct name_cache_entry *e = &dirp->name_cache[i];
1259                         if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1260                                 *poffset = e->offset;
1261                                 SeekDir(dirp, e->offset);
1262                                 return True;
1263                         }
1264                 }
1265         }
1266
1267         /* Not found in the name cache. Rewind directory and start from scratch. */
1268         SMB_VFS_REWINDDIR(conn, dirp->dir);
1269         dirp->file_number = 0;
1270         *poffset = START_OF_DIRECTORY_OFFSET;
1271         while ((entry = ReadDirName(dirp, poffset))) {
1272                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1273                         return True;
1274                 }
1275         }
1276         return False;
1277 }
1278
1279 /*****************************************************************
1280  Is this directory empty ?
1281 *****************************************************************/
1282
1283 NTSTATUS can_delete_directory(struct connection_struct *conn,
1284                                 const char *dirname)
1285 {
1286         NTSTATUS status = NT_STATUS_OK;
1287         long dirpos = 0;
1288         const char *dname;
1289         struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, dirname,
1290                                           NULL, 0);
1291
1292         if (!dir_hnd) {
1293                 return map_nt_error_from_unix(errno);
1294         }
1295
1296         while ((dname = ReadDirName(dir_hnd,&dirpos))) {
1297                 SMB_STRUCT_STAT st;
1298
1299                 /* Quick check for "." and ".." */
1300                 if (dname[0] == '.') {
1301                         if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1302                                 continue;
1303                         }
1304                 }
1305
1306                 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1307                         continue;
1308                 }
1309
1310                 DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
1311                 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1312                 break;
1313         }
1314         TALLOC_FREE(dir_hnd);
1315
1316         return status;
1317 }