r9456: Attempt to fix bug #3010 by handling END_OF_DIRECTORY_OFFSET
[Samba.git] / source / smbd / dir.c
blobf722bedecbb196b2a9ca1900ba7d374ef6a952c7
1 /*
2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
24 This module implements directory related functions for Samba.
27 extern struct current_user current_user;
29 /* "Special" directory offsets. */
30 #define END_OF_DIRECTORY_OFFSET ((long)-1)
31 #define START_OF_DIRECTORY_OFFSET ((long)0)
32 #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
34 /* Make directory handle internals available. */
36 #define NAME_CACHE_SIZE 100
38 struct name_cache_entry {
39 char *name;
40 long offset;
43 struct smb_Dir {
44 connection_struct *conn;
45 DIR *dir;
46 long offset;
47 char *dir_path;
48 struct name_cache_entry *name_cache;
49 unsigned int name_cache_index;
50 unsigned int file_number;
53 struct dptr_struct {
54 struct dptr_struct *next, *prev;
55 int dnum;
56 uint16 spid;
57 struct connection_struct *conn;
58 struct smb_Dir *dir_hnd;
59 BOOL expect_close;
60 char *wcard;
61 uint32 attr;
62 char *path;
63 BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
66 static struct bitmap *dptr_bmap;
67 static struct dptr_struct *dirptrs;
68 static int dirhandles_open = 0;
70 #define INVALID_DPTR_KEY (-3)
72 /****************************************************************************
73 Make a dir struct.
74 ****************************************************************************/
76 void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
78 char *p;
79 pstring mask2;
81 pstrcpy(mask2,mask);
83 if ((mode & aDIR) != 0)
84 size = 0;
86 memset(buf+1,' ',11);
87 if ((p = strchr_m(mask2,'.')) != NULL) {
88 *p = 0;
89 push_ascii(buf+1,mask2,8, 0);
90 push_ascii(buf+9,p+1,3, 0);
91 *p = '.';
92 } else
93 push_ascii(buf+1,mask2,11, 0);
95 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
96 SCVAL(buf,21,mode);
97 put_dos_date(buf,22,date);
98 SSVAL(buf,26,size & 0xFFFF);
99 SSVAL(buf,28,(size >> 16)&0xFFFF);
100 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
101 Strange, but verified on W2K3. Needed for OS/2. JRA. */
102 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
103 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
106 /****************************************************************************
107 Initialise the dir bitmap.
108 ****************************************************************************/
110 void init_dptrs(void)
112 static BOOL dptrs_init=False;
114 if (dptrs_init)
115 return;
117 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
119 if (!dptr_bmap)
120 exit_server("out of memory in init_dptrs");
122 dptrs_init = True;
125 /****************************************************************************
126 Idle a dptr - the directory is closed but the control info is kept.
127 ****************************************************************************/
129 static void dptr_idle(struct dptr_struct *dptr)
131 if (dptr->dir_hnd) {
132 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
133 CloseDir(dptr->dir_hnd);
134 dptr->dir_hnd = NULL;
138 /****************************************************************************
139 Idle the oldest dptr.
140 ****************************************************************************/
142 static void dptr_idleoldest(void)
144 struct dptr_struct *dptr;
147 * Go to the end of the list.
149 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
152 if(!dptr) {
153 DEBUG(0,("No dptrs available to idle ?\n"));
154 return;
158 * Idle the oldest pointer.
161 for(; dptr; dptr = dptr->prev) {
162 if (dptr->dir_hnd) {
163 dptr_idle(dptr);
164 return;
169 /****************************************************************************
170 Get the struct dptr_struct for a dir index.
171 ****************************************************************************/
173 static struct dptr_struct *dptr_get(int key, BOOL forclose)
175 struct dptr_struct *dptr;
177 for(dptr = dirptrs; dptr; dptr = dptr->next) {
178 if(dptr->dnum == key) {
179 if (!forclose && !dptr->dir_hnd) {
180 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
181 dptr_idleoldest();
182 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
183 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
184 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
185 strerror(errno)));
186 return False;
189 DLIST_PROMOTE(dirptrs,dptr);
190 return dptr;
193 return(NULL);
196 /****************************************************************************
197 Get the dir path for a dir index.
198 ****************************************************************************/
200 char *dptr_path(int key)
202 struct dptr_struct *dptr = dptr_get(key, False);
203 if (dptr)
204 return(dptr->path);
205 return(NULL);
208 /****************************************************************************
209 Get the dir wcard for a dir index.
210 ****************************************************************************/
212 char *dptr_wcard(int key)
214 struct dptr_struct *dptr = dptr_get(key, False);
215 if (dptr)
216 return(dptr->wcard);
217 return(NULL);
220 /****************************************************************************
221 Get the dir attrib for a dir index.
222 ****************************************************************************/
224 uint16 dptr_attr(int key)
226 struct dptr_struct *dptr = dptr_get(key, False);
227 if (dptr)
228 return(dptr->attr);
229 return(0);
232 /****************************************************************************
233 Close a dptr (internal func).
234 ****************************************************************************/
236 static void dptr_close_internal(struct dptr_struct *dptr)
238 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
240 DLIST_REMOVE(dirptrs, dptr);
243 * Free the dnum in the bitmap. Remember the dnum value is always
244 * biased by one with respect to the bitmap.
247 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
248 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
249 dptr->dnum ));
252 bitmap_clear(dptr_bmap, dptr->dnum - 1);
254 if (dptr->dir_hnd) {
255 CloseDir(dptr->dir_hnd);
258 /* Lanman 2 specific code */
259 SAFE_FREE(dptr->wcard);
260 string_set(&dptr->path,"");
261 SAFE_FREE(dptr);
264 /****************************************************************************
265 Close a dptr given a key.
266 ****************************************************************************/
268 void dptr_close(int *key)
270 struct dptr_struct *dptr;
272 if(*key == INVALID_DPTR_KEY)
273 return;
275 /* OS/2 seems to use -1 to indicate "close all directories" */
276 if (*key == -1) {
277 struct dptr_struct *next;
278 for(dptr = dirptrs; dptr; dptr = next) {
279 next = dptr->next;
280 dptr_close_internal(dptr);
282 *key = INVALID_DPTR_KEY;
283 return;
286 dptr = dptr_get(*key, True);
288 if (!dptr) {
289 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
290 return;
293 dptr_close_internal(dptr);
295 *key = INVALID_DPTR_KEY;
298 /****************************************************************************
299 Close all dptrs for a cnum.
300 ****************************************************************************/
302 void dptr_closecnum(connection_struct *conn)
304 struct dptr_struct *dptr, *next;
305 for(dptr = dirptrs; dptr; dptr = next) {
306 next = dptr->next;
307 if (dptr->conn == conn)
308 dptr_close_internal(dptr);
312 /****************************************************************************
313 Idle all dptrs for a cnum.
314 ****************************************************************************/
316 void dptr_idlecnum(connection_struct *conn)
318 struct dptr_struct *dptr;
319 for(dptr = dirptrs; dptr; dptr = dptr->next) {
320 if (dptr->conn == conn && dptr->dir_hnd)
321 dptr_idle(dptr);
325 /****************************************************************************
326 Close a dptr that matches a given path, only if it matches the spid also.
327 ****************************************************************************/
329 void dptr_closepath(char *path,uint16 spid)
331 struct dptr_struct *dptr, *next;
332 for(dptr = dirptrs; dptr; dptr = next) {
333 next = dptr->next;
334 if (spid == dptr->spid && strequal(dptr->path,path))
335 dptr_close_internal(dptr);
339 /****************************************************************************
340 Try and close the oldest handle not marked for
341 expect close in the hope that the client has
342 finished with that one.
343 ****************************************************************************/
345 static void dptr_close_oldest(BOOL old)
347 struct dptr_struct *dptr;
350 * Go to the end of the list.
352 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
355 if(!dptr) {
356 DEBUG(0,("No old dptrs available to close oldest ?\n"));
357 return;
361 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
362 * does not have expect_close set. If 'old' is false, close
363 * one of the new dnum handles.
366 for(; dptr; dptr = dptr->prev) {
367 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
368 (!old && (dptr->dnum > 255))) {
369 dptr_close_internal(dptr);
370 return;
375 /****************************************************************************
376 Create a new dir ptr. If the flag old_handle is true then we must allocate
377 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
378 one byte long. If old_handle is false we allocate from the range
379 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
380 a directory handle is never zero.
381 wcard must not be zero.
382 ****************************************************************************/
384 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
385 const char *wcard, uint32 attr)
387 struct dptr_struct *dptr = NULL;
388 struct smb_Dir *dir_hnd;
389 const char *dir2;
391 DEBUG(5,("dptr_create dir=%s\n", path));
393 if (!wcard) {
394 return -1;
397 if (!check_name(path,conn))
398 return(-2); /* Code to say use a unix error return code. */
400 /* use a const pointer from here on */
401 dir2 = path;
402 if (!*dir2)
403 dir2 = ".";
405 dir_hnd = OpenDir(conn, dir2, wcard, attr);
406 if (!dir_hnd) {
407 return (-2);
410 string_set(&conn->dirpath,dir2);
412 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
413 dptr_idleoldest();
415 dptr = SMB_MALLOC_P(struct dptr_struct);
416 if(!dptr) {
417 DEBUG(0,("malloc fail in dptr_create.\n"));
418 CloseDir(dir_hnd);
419 return -1;
422 ZERO_STRUCTP(dptr);
424 if(old_handle) {
427 * This is an old-style SMBsearch request. Ensure the
428 * value we return will fit in the range 1-255.
431 dptr->dnum = bitmap_find(dptr_bmap, 0);
433 if(dptr->dnum == -1 || dptr->dnum > 254) {
436 * Try and close the oldest handle not marked for
437 * expect close in the hope that the client has
438 * finished with that one.
441 dptr_close_oldest(True);
443 /* Now try again... */
444 dptr->dnum = bitmap_find(dptr_bmap, 0);
445 if(dptr->dnum == -1 || dptr->dnum > 254) {
446 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
447 SAFE_FREE(dptr);
448 CloseDir(dir_hnd);
449 return -1;
452 } else {
455 * This is a new-style trans2 request. Allocate from
456 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
459 dptr->dnum = bitmap_find(dptr_bmap, 255);
461 if(dptr->dnum == -1 || dptr->dnum < 255) {
464 * Try and close the oldest handle close in the hope that
465 * the client has finished with that one. This will only
466 * happen in the case of the Win98 client bug where it leaks
467 * directory handles.
470 dptr_close_oldest(False);
472 /* Now try again... */
473 dptr->dnum = bitmap_find(dptr_bmap, 255);
475 if(dptr->dnum == -1 || dptr->dnum < 255) {
476 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
477 SAFE_FREE(dptr);
478 CloseDir(dir_hnd);
479 return -1;
484 bitmap_set(dptr_bmap, dptr->dnum);
486 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
488 string_set(&dptr->path,dir2);
489 dptr->conn = conn;
490 dptr->dir_hnd = dir_hnd;
491 dptr->spid = spid;
492 dptr->expect_close = expect_close;
493 dptr->wcard = SMB_STRDUP(wcard);
494 if (!dptr->wcard) {
495 bitmap_clear(dptr_bmap, dptr->dnum - 1);
496 SAFE_FREE(dptr);
497 CloseDir(dir_hnd);
498 return -1;
500 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
501 dptr->has_wild = True;
502 } else {
503 dptr->has_wild = ms_has_wild(wcard);
506 dptr->attr = attr;
508 DLIST_ADD(dirptrs, dptr);
510 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
511 dptr->dnum,path,expect_close));
513 conn->dirptr = dptr;
515 return(dptr->dnum);
519 /****************************************************************************
520 Wrapper functions to access the lower level directory handles.
521 ****************************************************************************/
523 int dptr_CloseDir(struct dptr_struct *dptr)
525 return CloseDir(dptr->dir_hnd);
528 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
530 SeekDir(dptr->dir_hnd, offset);
533 long dptr_TellDir(struct dptr_struct *dptr)
535 return TellDir(dptr->dir_hnd);
538 /****************************************************************************
539 Return the next visible file name, skipping veto'd and invisible files.
540 ****************************************************************************/
542 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
544 /* Normal search for the next file. */
545 const char *name;
546 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
547 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
548 return name;
551 return NULL;
554 /****************************************************************************
555 Return the next visible file name, skipping veto'd and invisible files.
556 ****************************************************************************/
558 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
560 pstring pathreal;
562 SET_STAT_INVALID(*pst);
564 if (dptr->has_wild) {
565 return dptr_normal_ReadDirName(dptr, poffset, pst);
568 /* If poffset is -1 then we know we returned this name before and we have
569 no wildcards. We're at the end of the directory. */
570 if (*poffset == END_OF_DIRECTORY_OFFSET) {
571 return NULL;
574 /* We know the stored wcard contains no wildcard characters. See if we can match
575 with a stat call. If we can't, then set has_wild to true to
576 prevent us from doing this on every call. */
578 /* First check if it should be visible. */
579 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
580 dptr->has_wild = True;
581 return dptr_normal_ReadDirName(dptr, poffset, pst);
584 if (VALID_STAT(*pst)) {
585 /* We need to set the underlying dir_hdn offset to -1 also as
586 this function is usually called with the output from TellDir. */
587 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
588 return dptr->wcard;
591 pstrcpy(pathreal,dptr->path);
592 pstrcat(pathreal,"/");
593 pstrcat(pathreal,dptr->wcard);
595 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
596 /* We need to set the underlying dir_hdn offset to -1 also as
597 this function is usually called with the output from TellDir. */
598 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
599 return dptr->wcard;
600 } else {
601 /* If we get any other error than ENOENT or ENOTDIR
602 then the file exists we just can't stat it. */
603 if (errno != ENOENT && errno != ENOTDIR) {
604 /* We need to set the underlying dir_hdn offset to -1 also as
605 this function is usually called with the output from TellDir. */
606 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
607 return dptr->wcard;
611 /* In case sensitive mode we don't search - we know if it doesn't exist
612 with a stat we will fail. */
614 if (dptr->conn->case_sensitive) {
615 /* We need to set the underlying dir_hdn offset to -1 also as
616 this function is usually called with the output from TellDir. */
617 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
618 return NULL;
619 } else {
620 dptr->has_wild = True;
621 return dptr_normal_ReadDirName(dptr, poffset, pst);
625 /****************************************************************************
626 Search for a file by name, skipping veto'ed and not visible files.
627 ****************************************************************************/
629 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
631 SET_STAT_INVALID(*pst);
633 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
634 /* This is a singleton directory and we're already at the end. */
635 *poffset = END_OF_DIRECTORY_OFFSET;
636 return False;
639 if (SearchDir(dptr->dir_hnd, name, poffset)) {
640 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
641 return True;
644 return False;
647 /****************************************************************************
648 Fill the 5 byte server reserved dptr field.
649 ****************************************************************************/
651 BOOL dptr_fill(char *buf1,unsigned int key)
653 unsigned char *buf = (unsigned char *)buf1;
654 struct dptr_struct *dptr = dptr_get(key, False);
655 uint32 offset;
656 if (!dptr) {
657 DEBUG(1,("filling null dirptr %d\n",key));
658 return(False);
660 offset = (uint32)TellDir(dptr->dir_hnd);
661 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
662 (long)dptr->dir_hnd,(int)offset));
663 buf[0] = key;
664 SIVAL(buf,1,offset);
665 return(True);
668 /****************************************************************************
669 Fetch the dir ptr and seek it given the 5 byte server field.
670 ****************************************************************************/
672 struct dptr_struct *dptr_fetch(char *buf,int *num)
674 unsigned int key = *(unsigned char *)buf;
675 struct dptr_struct *dptr = dptr_get(key, False);
676 uint32 offset;
677 long seekoff;
679 if (!dptr) {
680 DEBUG(3,("fetched null dirptr %d\n",key));
681 return(NULL);
683 *num = key;
684 offset = IVAL(buf,1);
685 if (offset == (uint32)-1) {
686 seekoff = END_OF_DIRECTORY_OFFSET;
687 } else {
688 seekoff = (long)offset;
690 SeekDir(dptr->dir_hnd,seekoff);
691 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
692 key,dptr_path(key),(int)seekoff));
693 return(dptr);
696 /****************************************************************************
697 Fetch the dir ptr.
698 ****************************************************************************/
700 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
702 struct dptr_struct *dptr = dptr_get(dptr_num, False);
704 if (!dptr) {
705 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
706 return(NULL);
708 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
709 return(dptr);
712 /****************************************************************************
713 Check a filetype for being valid.
714 ****************************************************************************/
716 BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
718 uint32 mask;
720 /* Check the "may have" search bits. */
721 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
722 return False;
724 /* Check the "must have" bits, which are the may have bits shifted eight */
725 /* If must have bit is set, the file/dir can not be returned in search unless the matching
726 file attribute is set */
727 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
728 if(mask) {
729 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
730 return True;
731 else
732 return False;
735 return True;
738 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
740 mangle_map(filename,True,False,SNUM(conn));
741 return mask_match_search(filename,mask,False);
744 /****************************************************************************
745 Get an 8.3 directory entry.
746 ****************************************************************************/
748 BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
749 SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
751 const char *dname;
752 BOOL found = False;
753 SMB_STRUCT_STAT sbuf;
754 pstring path;
755 pstring pathreal;
756 pstring filename;
757 BOOL needslash;
759 *path = *pathreal = *filename = 0;
761 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
763 if (!conn->dirptr)
764 return(False);
766 while (!found) {
767 long curoff = dptr_TellDir(conn->dirptr);
768 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
770 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
771 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
773 if (dname == NULL)
774 return(False);
776 pstrcpy(filename,dname);
778 /* notice the special *.* handling. This appears to be the only difference
779 between the wildcard handling in this routine and in the trans2 routines.
780 see masktest for a demo
782 if ((strcmp(mask,"*.*") == 0) ||
783 mask_match_search(filename,mask,False) ||
784 mangle_mask_match(conn,filename,mask)) {
786 if (!mangle_is_8_3(filename, False, SNUM(conn)))
787 mangle_map(filename,True,False,SNUM(conn));
789 pstrcpy(fname,filename);
790 *path = 0;
791 pstrcpy(path,conn->dirpath);
792 if(needslash)
793 pstrcat(path,"/");
794 pstrcpy(pathreal,path);
795 pstrcat(path,fname);
796 pstrcat(pathreal,dname);
797 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
798 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
799 continue;
802 *mode = dos_mode(conn,pathreal,&sbuf);
804 if (!dir_check_ftype(conn,*mode,dirtype)) {
805 DEBUG(5,("[%s] attribs didn't match %x\n",filename,(unsigned int)dirtype));
806 continue;
809 *size = sbuf.st_size;
810 *date = sbuf.st_mtime;
812 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
814 found = True;
818 return(found);
821 /*******************************************************************
822 Check to see if a user can read a file. This is only approximate,
823 it is used as part of the "hide unreadable" option. Don't
824 use it for anything security sensitive.
825 ********************************************************************/
827 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
829 SEC_DESC *psd = NULL;
830 size_t sd_size;
831 files_struct *fsp;
832 NTSTATUS status;
833 uint32 access_granted;
836 * If user is a member of the Admin group
837 * we never hide files from them.
840 if (conn->admin_user) {
841 return True;
844 /* If we can't stat it does not show it */
845 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
846 return False;
849 /* Pseudo-open the file (note - no fd's created). */
851 if(S_ISDIR(pst->st_mode)) {
852 fsp = open_directory(conn, name, pst,
853 READ_CONTROL_ACCESS,
854 FILE_SHARE_READ|FILE_SHARE_WRITE,
855 FILE_OPEN,
856 0, /* no create options. */
857 NULL);
858 } else {
859 fsp = open_file_stat(conn, name, pst);
862 if (!fsp) {
863 return False;
866 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
867 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
868 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
869 close_file(fsp, True);
871 /* No access if SD get failed. */
872 if (!sd_size) {
873 return False;
876 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
877 &access_granted, &status);
880 /*******************************************************************
881 Check to see if a user can write a file (and only files, we do not
882 check dirs on this one). This is only approximate,
883 it is used as part of the "hide unwriteable" option. Don't
884 use it for anything security sensitive.
885 ********************************************************************/
887 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
889 SEC_DESC *psd = NULL;
890 size_t sd_size;
891 files_struct *fsp;
892 int info;
893 NTSTATUS status;
894 uint32 access_granted;
897 * If user is a member of the Admin group
898 * we never hide files from them.
901 if (conn->admin_user) {
902 return True;
905 /* If we can't stat it does not show it */
906 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
907 return False;
910 /* Pseudo-open the file */
912 if(S_ISDIR(pst->st_mode)) {
913 return True;
914 } else {
915 fsp = open_file_ntcreate(conn, name, pst,
916 FILE_WRITE_ATTRIBUTES,
917 FILE_SHARE_READ|FILE_SHARE_WRITE,
918 FILE_OPEN,
920 FILE_ATTRIBUTE_NORMAL,
921 INTERNAL_OPEN_ONLY,
922 &info);
925 if (!fsp) {
926 return False;
929 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
930 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
931 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
932 close_file(fsp, False);
934 /* No access if SD get failed. */
935 if (!sd_size)
936 return False;
938 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
939 &access_granted, &status);
942 /*******************************************************************
943 Is a file a "special" type ?
944 ********************************************************************/
946 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
949 * If user is a member of the Admin group
950 * we never hide files from them.
953 if (conn->admin_user)
954 return False;
956 /* If we can't stat it does not show it */
957 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
958 return True;
960 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
961 return False;
963 return True;
966 /*******************************************************************
967 Should the file be seen by the client ?
968 ********************************************************************/
970 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
972 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
973 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
974 BOOL hide_special = lp_hide_special_files(SNUM(conn));
976 SET_STAT_INVALID(*pst);
978 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
979 return True; /* . and .. are always visible. */
982 /* If it's a vetoed file, pretend it doesn't even exist */
983 if (use_veto && IS_VETO_PATH(conn, name)) {
984 return False;
987 if (hide_unreadable || hide_unwriteable || hide_special) {
988 char *entry = NULL;
990 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
991 return False;
993 /* Honour _hide unreadable_ option */
994 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
995 SAFE_FREE(entry);
996 return False;
998 /* Honour _hide unwriteable_ option */
999 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
1000 SAFE_FREE(entry);
1001 return False;
1003 /* Honour _hide_special_ option */
1004 if (hide_special && file_is_special(conn, entry, pst)) {
1005 SAFE_FREE(entry);
1006 return False;
1008 SAFE_FREE(entry);
1010 return True;
1013 /*******************************************************************
1014 Open a directory.
1015 ********************************************************************/
1017 struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
1019 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1020 if (!dirp) {
1021 return NULL;
1023 ZERO_STRUCTP(dirp);
1025 dirp->conn = conn;
1027 dirp->dir_path = SMB_STRDUP(name);
1028 if (!dirp->dir_path) {
1029 goto fail;
1031 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1032 if (!dirp->dir) {
1033 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1034 goto fail;
1037 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1038 if (!dirp->name_cache) {
1039 goto fail;
1042 dirhandles_open++;
1043 return dirp;
1045 fail:
1047 if (dirp) {
1048 if (dirp->dir) {
1049 SMB_VFS_CLOSEDIR(conn,dirp->dir);
1051 SAFE_FREE(dirp->dir_path);
1052 SAFE_FREE(dirp->name_cache);
1053 SAFE_FREE(dirp);
1055 return NULL;
1059 /*******************************************************************
1060 Close a directory.
1061 ********************************************************************/
1063 int CloseDir(struct smb_Dir *dirp)
1065 int i, ret = 0;
1067 if (dirp->dir) {
1068 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1070 SAFE_FREE(dirp->dir_path);
1071 if (dirp->name_cache) {
1072 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1073 SAFE_FREE(dirp->name_cache[i].name);
1076 SAFE_FREE(dirp->name_cache);
1077 SAFE_FREE(dirp);
1078 dirhandles_open--;
1079 return ret;
1082 /*******************************************************************
1083 Read from a directory. Also return current offset.
1084 Don't check for veto or invisible files.
1085 ********************************************************************/
1087 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1089 const char *n;
1090 connection_struct *conn = dirp->conn;
1092 /* Cheat to allow . and .. to be the first entries returned. */
1093 if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
1094 if (dirp->file_number == 0) {
1095 n = ".";
1096 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1097 } else {
1098 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1099 n = "..";
1101 dirp->file_number++;
1102 return n;
1103 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1104 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1105 return NULL;
1106 } else {
1107 /* A real offset, seek to it. */
1108 SeekDir(dirp, *poffset);
1111 while ((n = vfs_readdirname(conn, dirp->dir))) {
1112 struct name_cache_entry *e;
1113 /* Ignore . and .. - we've already returned them. */
1114 if (*n == '.') {
1115 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1116 continue;
1119 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1120 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1121 e = &dirp->name_cache[dirp->name_cache_index];
1122 SAFE_FREE(e->name);
1123 e->name = SMB_STRDUP(n);
1124 *poffset = e->offset= dirp->offset;
1125 dirp->file_number++;
1126 return e->name;
1128 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1129 return NULL;
1132 /*******************************************************************
1133 Rewind to the start.
1134 ********************************************************************/
1136 void RewindDir(struct smb_Dir *dirp, long *poffset)
1138 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1139 dirp->file_number = 0;
1140 dirp->offset = START_OF_DIRECTORY_OFFSET;
1141 *poffset = START_OF_DIRECTORY_OFFSET;
1144 /*******************************************************************
1145 Seek a dir.
1146 ********************************************************************/
1148 void SeekDir(struct smb_Dir *dirp, long offset)
1150 if (offset != dirp->offset) {
1151 if (offset == START_OF_DIRECTORY_OFFSET || offset == DOT_DOT_DIRECTORY_OFFSET) {
1152 RewindDir(dirp, &offset);
1153 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1154 ; /* Don't seek in this case. */
1155 } else {
1156 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1158 dirp->offset = offset;
1162 /*******************************************************************
1163 Tell a dir position.
1164 ********************************************************************/
1166 long TellDir(struct smb_Dir *dirp)
1168 return(dirp->offset);
1171 /*******************************************************************
1172 Find an entry by name. Leave us at the offset after it.
1173 Don't check for veto or invisible files.
1174 ********************************************************************/
1176 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1178 int i;
1179 const char *entry;
1180 connection_struct *conn = dirp->conn;
1182 /* Search back in the name cache. */
1183 for (i = dirp->name_cache_index; i >= 0; i--) {
1184 struct name_cache_entry *e = &dirp->name_cache[i];
1185 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1186 *poffset = e->offset;
1187 SeekDir(dirp, e->offset);
1188 return True;
1191 for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1192 struct name_cache_entry *e = &dirp->name_cache[i];
1193 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1194 *poffset = e->offset;
1195 SeekDir(dirp, e->offset);
1196 return True;
1200 /* Not found in the name cache. Rewind directory and start from scratch. */
1201 SMB_VFS_REWINDDIR(conn, dirp->dir);
1202 dirp->file_number = 0;
1203 *poffset = START_OF_DIRECTORY_OFFSET;
1204 while ((entry = ReadDirName(dirp, poffset))) {
1205 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1206 return True;
1209 return False;