r5508: Typo - ZERO_STRUCT -> ZERO_STRUCTP.
[metze/samba/wip.git] / source3 / smbd / dir.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Directory handling routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22
23 /*
24    This module implements directory related functions for Samba.
25 */
26
27 /* Make directory handle internals available. */
28
29 #define NAME_CACHE_SIZE 100
30
31 struct name_cache_entry {
32         char *name;
33         long offset;
34 };
35
36 struct smb_Dir {
37         connection_struct *conn;
38         DIR *dir;
39         long offset;
40         char *dir_path;
41         struct name_cache_entry *name_cache;
42         unsigned int name_cache_index;
43 };
44
45 struct dptr_struct {
46         struct dptr_struct *next, *prev;
47         int dnum;
48         uint16 spid;
49         struct connection_struct *conn;
50         struct smb_Dir *dir_hnd;
51         BOOL expect_close;
52         char *wcard;
53         uint16 attr;
54         char *path;
55         BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
56 };
57
58 static struct bitmap *dptr_bmap;
59 static struct dptr_struct *dirptrs;
60 static int dirhandles_open = 0;
61
62 #define INVALID_DPTR_KEY (-3)
63
64 /****************************************************************************
65  Initialise the dir bitmap.
66 ****************************************************************************/
67
68 void init_dptrs(void)
69 {
70         static BOOL dptrs_init=False;
71
72         if (dptrs_init)
73                 return;
74
75         dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
76
77         if (!dptr_bmap)
78                 exit_server("out of memory in init_dptrs");
79
80         dptrs_init = True;
81 }
82
83 /****************************************************************************
84  Idle a dptr - the directory is closed but the control info is kept.
85 ****************************************************************************/
86
87 static void dptr_idle(struct dptr_struct *dptr)
88 {
89         if (dptr->dir_hnd) {
90                 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
91                 CloseDir(dptr->dir_hnd);
92                 dptr->dir_hnd = NULL;
93         }
94 }
95
96 /****************************************************************************
97  Idle the oldest dptr.
98 ****************************************************************************/
99
100 static void dptr_idleoldest(void)
101 {
102         struct dptr_struct *dptr;
103
104         /*
105          * Go to the end of the list.
106          */
107         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
108                 ;
109
110         if(!dptr) {
111                 DEBUG(0,("No dptrs available to idle ?\n"));
112                 return;
113         }
114
115         /*
116          * Idle the oldest pointer.
117          */
118
119         for(; dptr; dptr = dptr->prev) {
120                 if (dptr->dir_hnd) {
121                         dptr_idle(dptr);
122                         return;
123                 }
124         }
125 }
126
127 /****************************************************************************
128  Get the struct dptr_struct for a dir index.
129 ****************************************************************************/
130
131 static struct dptr_struct *dptr_get(int key, BOOL forclose)
132 {
133         struct dptr_struct *dptr;
134
135         for(dptr = dirptrs; dptr; dptr = dptr->next) {
136                 if(dptr->dnum == key) {
137                         if (!forclose && !dptr->dir_hnd) {
138                                 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
139                                         dptr_idleoldest();
140                                 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
141                                 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path))) {
142                                         DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
143                                                 strerror(errno)));
144                                         return False;
145                                 }
146                         }
147                         DLIST_PROMOTE(dirptrs,dptr);
148                         return dptr;
149                 }
150         }
151         return(NULL);
152 }
153
154 /****************************************************************************
155  Get the dir path for a dir index.
156 ****************************************************************************/
157
158 char *dptr_path(int key)
159 {
160         struct dptr_struct *dptr = dptr_get(key, False);
161         if (dptr)
162                 return(dptr->path);
163         return(NULL);
164 }
165
166 /****************************************************************************
167  Get the dir wcard for a dir index.
168 ****************************************************************************/
169
170 char *dptr_wcard(int key)
171 {
172         struct dptr_struct *dptr = dptr_get(key, False);
173         if (dptr)
174                 return(dptr->wcard);
175         return(NULL);
176 }
177
178 /****************************************************************************
179  Get the dir attrib for a dir index.
180 ****************************************************************************/
181
182 uint16 dptr_attr(int key)
183 {
184         struct dptr_struct *dptr = dptr_get(key, False);
185         if (dptr)
186                 return(dptr->attr);
187         return(0);
188 }
189
190 /****************************************************************************
191  Set the dir wcard for a dir index.
192  Returns 0 on ok, 1 on fail.
193 ****************************************************************************/
194
195 BOOL dptr_set_wcard_and_attributes(int key, const char *wcard, uint16 attr)
196 {
197         struct dptr_struct *dptr = dptr_get(key, False);
198
199         if (dptr) {
200                 dptr->attr = attr;
201                 dptr->wcard = SMB_STRDUP(wcard);
202                 if (!dptr->wcard)
203                         return False;
204                 if (wcard[0] == '.' && wcard[1] == 0) {
205                         dptr->has_wild = True;
206                 } else {
207                         dptr->has_wild = ms_has_wild(wcard);
208                 }
209                 return True;
210         }
211         return False;
212 }
213
214 /****************************************************************************
215  Close a dptr (internal func).
216 ****************************************************************************/
217
218 static void dptr_close_internal(struct dptr_struct *dptr)
219 {
220         DEBUG(4,("closing dptr key %d\n",dptr->dnum));
221
222         DLIST_REMOVE(dirptrs, dptr);
223
224         /* 
225          * Free the dnum in the bitmap. Remember the dnum value is always 
226          * biased by one with respect to the bitmap.
227          */
228
229         if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
230                 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
231                         dptr->dnum ));
232         }
233
234         bitmap_clear(dptr_bmap, dptr->dnum - 1);
235
236         if (dptr->dir_hnd) {
237                 CloseDir(dptr->dir_hnd);
238         }
239
240         /* Lanman 2 specific code */
241         SAFE_FREE(dptr->wcard);
242         string_set(&dptr->path,"");
243         SAFE_FREE(dptr);
244 }
245
246 /****************************************************************************
247  Close a dptr given a key.
248 ****************************************************************************/
249
250 void dptr_close(int *key)
251 {
252         struct dptr_struct *dptr;
253
254         if(*key == INVALID_DPTR_KEY)
255                 return;
256
257         /* OS/2 seems to use -1 to indicate "close all directories" */
258         if (*key == -1) {
259                 struct dptr_struct *next;
260                 for(dptr = dirptrs; dptr; dptr = next) {
261                         next = dptr->next;
262                         dptr_close_internal(dptr);
263                 }
264                 *key = INVALID_DPTR_KEY;
265                 return;
266         }
267
268         dptr = dptr_get(*key, True);
269
270         if (!dptr) {
271                 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
272                 return;
273         }
274
275         dptr_close_internal(dptr);
276
277         *key = INVALID_DPTR_KEY;
278 }
279
280 /****************************************************************************
281  Close all dptrs for a cnum.
282 ****************************************************************************/
283
284 void dptr_closecnum(connection_struct *conn)
285 {
286         struct dptr_struct *dptr, *next;
287         for(dptr = dirptrs; dptr; dptr = next) {
288                 next = dptr->next;
289                 if (dptr->conn == conn)
290                         dptr_close_internal(dptr);
291         }
292 }
293
294 /****************************************************************************
295  Idle all dptrs for a cnum.
296 ****************************************************************************/
297
298 void dptr_idlecnum(connection_struct *conn)
299 {
300         struct dptr_struct *dptr;
301         for(dptr = dirptrs; dptr; dptr = dptr->next) {
302                 if (dptr->conn == conn && dptr->dir_hnd)
303                         dptr_idle(dptr);
304         }
305 }
306
307 /****************************************************************************
308  Close a dptr that matches a given path, only if it matches the spid also.
309 ****************************************************************************/
310
311 void dptr_closepath(char *path,uint16 spid)
312 {
313         struct dptr_struct *dptr, *next;
314         for(dptr = dirptrs; dptr; dptr = next) {
315                 next = dptr->next;
316                 if (spid == dptr->spid && strequal(dptr->path,path))
317                         dptr_close_internal(dptr);
318         }
319 }
320
321 /****************************************************************************
322  Try and close the oldest handle not marked for
323  expect close in the hope that the client has
324  finished with that one.
325 ****************************************************************************/
326
327 static void dptr_close_oldest(BOOL old)
328 {
329         struct dptr_struct *dptr;
330
331         /*
332          * Go to the end of the list.
333          */
334         for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
335                 ;
336
337         if(!dptr) {
338                 DEBUG(0,("No old dptrs available to close oldest ?\n"));
339                 return;
340         }
341
342         /*
343          * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
344          * does not have expect_close set. If 'old' is false, close
345          * one of the new dnum handles.
346          */
347
348         for(; dptr; dptr = dptr->prev) {
349                 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
350                         (!old && (dptr->dnum > 255))) {
351                                 dptr_close_internal(dptr);
352                                 return;
353                 }
354         }
355 }
356
357 /****************************************************************************
358  Create a new dir ptr. If the flag old_handle is true then we must allocate
359  from the bitmap range 0 - 255 as old SMBsearch directory handles are only
360  one byte long. If old_handle is false we allocate from the range
361  256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
362  a directory handle is never zero.
363 ****************************************************************************/
364
365 int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
366 {
367         struct dptr_struct *dptr = NULL;
368         struct smb_Dir *dir_hnd;
369         const char *dir2;
370
371         DEBUG(5,("dptr_create dir=%s\n", path));
372
373         if (!check_name(path,conn))
374                 return(-2); /* Code to say use a unix error return code. */
375
376         /* use a const pointer from here on */
377         dir2 = path;
378         if (!*dir2)
379                 dir2 = ".";
380
381         dir_hnd = OpenDir(conn, dir2);
382         if (!dir_hnd) {
383                 return (-2);
384         }
385
386         string_set(&conn->dirpath,dir2);
387
388         if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
389                 dptr_idleoldest();
390
391         dptr = SMB_MALLOC_P(struct dptr_struct);
392         if(!dptr) {
393                 DEBUG(0,("malloc fail in dptr_create.\n"));
394                 CloseDir(dir_hnd);
395                 return -1;
396         }
397
398         ZERO_STRUCTP(dptr);
399
400         if(old_handle) {
401
402                 /*
403                  * This is an old-style SMBsearch request. Ensure the
404                  * value we return will fit in the range 1-255.
405                  */
406
407                 dptr->dnum = bitmap_find(dptr_bmap, 0);
408
409                 if(dptr->dnum == -1 || dptr->dnum > 254) {
410
411                         /*
412                          * Try and close the oldest handle not marked for
413                          * expect close in the hope that the client has
414                          * finished with that one.
415                          */
416
417                         dptr_close_oldest(True);
418
419                         /* Now try again... */
420                         dptr->dnum = bitmap_find(dptr_bmap, 0);
421                         if(dptr->dnum == -1 || dptr->dnum > 254) {
422                                 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
423                                 SAFE_FREE(dptr);
424                                 CloseDir(dir_hnd);
425                                 return -1;
426                         }
427                 }
428         } else {
429
430                 /*
431                  * This is a new-style trans2 request. Allocate from
432                  * a range that will return 256 - MAX_DIRECTORY_HANDLES.
433                  */
434
435                 dptr->dnum = bitmap_find(dptr_bmap, 255);
436
437                 if(dptr->dnum == -1 || dptr->dnum < 255) {
438
439                         /*
440                          * Try and close the oldest handle close in the hope that
441                          * the client has finished with that one. This will only
442                          * happen in the case of the Win98 client bug where it leaks
443                          * directory handles.
444                          */
445
446                         dptr_close_oldest(False);
447
448                         /* Now try again... */
449                         dptr->dnum = bitmap_find(dptr_bmap, 255);
450
451                         if(dptr->dnum == -1 || dptr->dnum < 255) {
452                                 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
453                                 SAFE_FREE(dptr);
454                                 CloseDir(dir_hnd);
455                                 return -1;
456                         }
457                 }
458         }
459
460         bitmap_set(dptr_bmap, dptr->dnum);
461
462         dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
463
464         string_set(&dptr->path,dir2);
465         dptr->conn = conn;
466         dptr->dir_hnd = dir_hnd;
467         dptr->spid = spid;
468         dptr->expect_close = expect_close;
469         dptr->wcard = NULL; /* Only used in lanman2 searches */
470         dptr->attr = 0; /* Only used in lanman2 searches */
471         dptr->has_wild = True; /* Only used in lanman2 searches */
472
473         DLIST_ADD(dirptrs, dptr);
474
475         DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
476                 dptr->dnum,path,expect_close));  
477
478         conn->dirptr = dptr;
479
480         return(dptr->dnum);
481 }
482
483
484 /****************************************************************************
485  Wrapper functions to access the lower level directory handles.
486 ****************************************************************************/
487
488 int dptr_CloseDir(struct dptr_struct *dptr)
489 {
490         return CloseDir(dptr->dir_hnd);
491 }
492
493 void dptr_SeekDir(struct dptr_struct *dptr, long offset)
494 {
495         SeekDir(dptr->dir_hnd, offset);
496 }
497
498 long dptr_TellDir(struct dptr_struct *dptr)
499 {
500         return TellDir(dptr->dir_hnd);
501 }
502
503 /****************************************************************************
504  Return the next visible file name, skipping veto'd and invisible files.
505 ****************************************************************************/
506
507 static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
508 {
509         /* Normal search for the next file. */
510         const char *name;
511         while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
512                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
513                         return name;
514                 }
515         }
516         return NULL;
517 }
518
519 /****************************************************************************
520  Return the next visible file name, skipping veto'd and invisible files.
521 ****************************************************************************/
522
523 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
524 {
525         pstring pathreal;
526
527         ZERO_STRUCTP(pst);
528         if (dptr->has_wild) {
529                 return dptr_normal_ReadDirName(dptr, poffset, pst);
530         }
531
532         /* We know the stored wcard contains no wildcard characters. See if we can match
533            with a stat call. If we can't, then set has_wild to true to
534            prevent us from doing this on every call. */
535
536         /* First check if it should be visible. */
537         if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
538                 dptr->has_wild = True;
539                 return dptr_normal_ReadDirName(dptr, poffset, pst);
540         }
541
542         if (VALID_STAT(*pst)) {
543                 return dptr->wcard;
544         }
545
546         pstrcpy(pathreal,dptr->path);
547         pstrcat(pathreal,"/");
548         pstrcat(pathreal,dptr->wcard);
549
550         if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
551                 return dptr->wcard;
552         } else {
553                 /* If we get any other error than ENOENT or ENOTDIR
554                    then the file exists we just can't stat it. */
555                 if (errno != ENOENT && errno != ENOTDIR) {
556                         return dptr->wcard;
557                 }
558         }
559
560         dptr->has_wild = True;
561
562         /* In case sensitive mode we don't search - we know if it doesn't exist 
563            with a stat we will fail. */
564
565         if (dptr->conn->case_sensitive) {
566                 return NULL;
567         } else {
568                 return dptr_normal_ReadDirName(dptr, poffset, pst);
569         }
570 }
571
572 /****************************************************************************
573  Search for a file by name, skipping veto'ed and not visible files.
574 ****************************************************************************/
575
576 BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
577 {
578         BOOL ret;
579
580         ZERO_STRUCTP(pst);
581         while ((ret = SearchDir(dptr->dir_hnd, name, poffset)) == True) {
582                 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
583                         return True;
584                 }
585         }
586         return False;
587 }
588
589 /****************************************************************************
590  Fill the 5 byte server reserved dptr field.
591 ****************************************************************************/
592
593 BOOL dptr_fill(char *buf1,unsigned int key)
594 {
595         unsigned char *buf = (unsigned char *)buf1;
596         struct dptr_struct *dptr = dptr_get(key, False);
597         uint32 offset;
598         if (!dptr) {
599                 DEBUG(1,("filling null dirptr %d\n",key));
600                 return(False);
601         }
602         offset = TellDir(dptr->dir_hnd);
603         DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
604                 (long)dptr->dir_hnd,(int)offset));
605         buf[0] = key;
606         SIVAL(buf,1,offset | DPTR_MASK);
607         return(True);
608 }
609
610 /****************************************************************************
611  Fetch the dir ptr and seek it given the 5 byte server field.
612 ****************************************************************************/
613
614 struct dptr_struct *dptr_fetch(char *buf,int *num)
615 {
616         unsigned int key = *(unsigned char *)buf;
617         struct dptr_struct *dptr = dptr_get(key, False);
618         uint32 offset;
619
620         if (!dptr) {
621                 DEBUG(3,("fetched null dirptr %d\n",key));
622                 return(NULL);
623         }
624         *num = key;
625         offset = IVAL(buf,1)&~DPTR_MASK;
626         SeekDir(dptr->dir_hnd,(long)offset);
627         DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
628                 key,dptr_path(key),offset));
629         return(dptr);
630 }
631
632 /****************************************************************************
633  Fetch the dir ptr.
634 ****************************************************************************/
635
636 struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
637 {
638         struct dptr_struct *dptr  = dptr_get(dptr_num, False);
639
640         if (!dptr) {
641                 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
642                 return(NULL);
643         }
644         DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
645         return(dptr);
646 }
647
648 /****************************************************************************
649  Check a filetype for being valid.
650 ****************************************************************************/
651
652 BOOL dir_check_ftype(connection_struct *conn,int mode,int dirtype)
653 {
654         int mask;
655
656         /* Check the "may have" search bits. */
657         if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
658                 return False;
659
660         /* Check the "must have" bits, which are the may have bits shifted eight */
661         /* If must have bit is set, the file/dir can not be returned in search unless the matching
662                 file attribute is set */
663         mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
664         if(mask) {
665                 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
666                         return True;
667                 else
668                         return False;
669         }
670
671         return True;
672 }
673
674 static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
675 {
676         mangle_map(filename,True,False,SNUM(conn));
677         return mask_match(filename,mask,False);
678 }
679
680 /****************************************************************************
681  Get an 8.3 directory entry.
682 ****************************************************************************/
683
684 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname,
685                    SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
686 {
687         const char *dname;
688         BOOL found = False;
689         SMB_STRUCT_STAT sbuf;
690         pstring path;
691         pstring pathreal;
692         BOOL isrootdir;
693         pstring filename;
694         BOOL needslash;
695
696         *path = *pathreal = *filename = 0;
697
698         isrootdir = (strequal(conn->dirpath,"./") ||
699                         strequal(conn->dirpath,".") ||
700                         strequal(conn->dirpath,"/"));
701   
702         needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
703
704         if (!conn->dirptr)
705                 return(False);
706
707         while (!found) {
708                 long curoff = dptr_TellDir(conn->dirptr);
709                 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
710
711                 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
712                         (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
713       
714                 if (dname == NULL) 
715                         return(False);
716       
717                 pstrcpy(filename,dname);      
718
719                 /* notice the special *.* handling. This appears to be the only difference
720                         between the wildcard handling in this routine and in the trans2 routines.
721                         see masktest for a demo
722                 */
723                 if ((strcmp(mask,"*.*") == 0) ||
724                     mask_match(filename,mask,False) ||
725                     mangle_mask_match(conn,filename,mask)) {
726                         if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
727                                 continue;
728
729                         if (!mangle_is_8_3(filename, False))
730                                 mangle_map(filename,True,False,SNUM(conn));
731
732                         pstrcpy(fname,filename);
733                         *path = 0;
734                         pstrcpy(path,conn->dirpath);
735                         if(needslash)
736                                 pstrcat(path,"/");
737                         pstrcpy(pathreal,path);
738                         pstrcat(path,fname);
739                         pstrcat(pathreal,dname);
740                         if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
741                                 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
742                                 continue;
743                         }
744           
745                         *mode = dos_mode(conn,pathreal,&sbuf);
746
747                         if (!dir_check_ftype(conn,*mode,dirtype)) {
748                                 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
749                                 continue;
750                         }
751
752                         *size = sbuf.st_size;
753                         *date = sbuf.st_mtime;
754
755                         DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
756
757                         found = True;
758                 }
759         }
760
761         return(found);
762 }
763
764 /*******************************************************************
765  Check to see if a user can read a file. This is only approximate,
766  it is used as part of the "hide unreadable" option. Don't
767  use it for anything security sensitive.
768 ********************************************************************/
769
770 static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
771 {
772         extern struct current_user current_user;
773         SEC_DESC *psd = NULL;
774         size_t sd_size;
775         files_struct *fsp;
776         int smb_action;
777         NTSTATUS status;
778         uint32 access_granted;
779
780         /*
781          * If user is a member of the Admin group
782          * we never hide files from them.
783          */
784
785         if (conn->admin_user)
786                 return True;
787
788         /* If we can't stat it does not show it */
789         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
790                 return False;
791
792         /* Pseudo-open the file (note - no fd's created). */
793
794         if(S_ISDIR(pst->st_mode))       
795                  fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
796                         &smb_action);
797         else
798                 fsp = open_file_stat(conn, name, pst);
799
800         if (!fsp)
801                 return False;
802
803         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
804         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
805                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
806         close_file(fsp, True);
807
808         /* No access if SD get failed. */
809         if (!sd_size)
810                 return False;
811
812         return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
813                                  &access_granted, &status);
814 }
815
816 /*******************************************************************
817  Check to see if a user can write a file (and only files, we do not
818  check dirs on this one). This is only approximate,
819  it is used as part of the "hide unwriteable" option. Don't
820  use it for anything security sensitive.
821 ********************************************************************/
822
823 static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
824 {
825         extern struct current_user current_user;
826         SEC_DESC *psd = NULL;
827         size_t sd_size;
828         files_struct *fsp;
829         int smb_action;
830         int access_mode;
831         NTSTATUS status;
832         uint32 access_granted;
833
834         /*
835          * If user is a member of the Admin group
836          * we never hide files from them.
837          */
838
839         if (conn->admin_user)
840                 return True;
841
842         /* If we can't stat it does not show it */
843         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
844                 return False;
845
846         /* Pseudo-open the file (note - no fd's created). */
847
848         if(S_ISDIR(pst->st_mode))       
849                 return True;
850         else
851                 fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
852                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
853                         &access_mode, &smb_action);
854
855         if (!fsp)
856                 return False;
857
858         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
859         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
860                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
861         close_file(fsp, False);
862
863         /* No access if SD get failed. */
864         if (!sd_size)
865                 return False;
866
867         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
868                                  &access_granted, &status);
869 }
870
871 /*******************************************************************
872   Is a file a "special" type ?
873 ********************************************************************/
874
875 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
876 {
877         /*
878          * If user is a member of the Admin group
879          * we never hide files from them.
880          */
881
882         if (conn->admin_user)
883                 return False;
884
885         /* If we can't stat it does not show it */
886         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
887                 return True;
888
889         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
890                 return False;
891
892         return True;
893 }
894
895 /*******************************************************************
896  Should the file be seen by the client ?
897 ********************************************************************/
898
899 BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
900 {
901         BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
902         BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
903         BOOL hide_special = lp_hide_special_files(SNUM(conn));
904
905         ZERO_STRUCTP(pst);
906
907         if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
908                 return True; /* . and .. are always visible. */
909         }
910
911         /* If it's a vetoed file, pretend it doesn't even exist */
912         if (use_veto && IS_VETO_PATH(conn, name)) {
913                 return False;
914         }
915
916         if (hide_unreadable || hide_unwriteable || hide_special) {
917                 char *entry = NULL;
918
919                 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
920                         return False;
921                 }
922                 /* Honour _hide unreadable_ option */
923                 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
924                         SAFE_FREE(entry);
925                         return False;
926                 }
927                 /* Honour _hide unwriteable_ option */
928                 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
929                         SAFE_FREE(entry);
930                         return False;
931                 }
932                 /* Honour _hide_special_ option */
933                 if (hide_special && !file_is_special(conn, entry, pst)) {
934                         SAFE_FREE(entry);
935                         return False;
936                 }
937                 SAFE_FREE(entry);
938         }
939         return True;
940 }
941
942 /*******************************************************************
943  Open a directory.
944 ********************************************************************/
945
946 struct smb_Dir *OpenDir(connection_struct *conn, const char *name)
947 {
948         struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
949         if (!dirp) {
950                 return NULL;
951         }
952         ZERO_STRUCTP(dirp);
953
954         dirp->conn = conn;
955
956         dirp->dir_path = SMB_STRDUP(name);
957         if (!dirp->dir_path) {
958                 goto fail;
959         }
960         dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
961         if (!dirp->dir) {
962                 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
963                 goto fail;
964         }
965
966         dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
967         if (!dirp->name_cache) {
968                 goto fail;
969         }
970
971         dirhandles_open++;
972         return dirp;
973
974   fail:
975
976         if (dirp) {
977                 if (dirp->dir) {
978                         SMB_VFS_CLOSEDIR(conn,dirp->dir);
979                 }
980                 SAFE_FREE(dirp->dir_path);
981                 SAFE_FREE(dirp->name_cache);
982                 SAFE_FREE(dirp);
983         }
984         return NULL;
985 }
986
987
988 /*******************************************************************
989  Close a directory.
990 ********************************************************************/
991
992 int CloseDir(struct smb_Dir *dirp)
993 {
994         int i, ret = 0;
995
996         if (dirp->dir) {
997                 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
998         }
999         SAFE_FREE(dirp->dir_path);
1000         if (dirp->name_cache) {
1001                 for (i = 0; i < NAME_CACHE_SIZE; i++) {
1002                         SAFE_FREE(dirp->name_cache[i].name);
1003                 }
1004         }
1005         SAFE_FREE(dirp->name_cache);
1006         SAFE_FREE(dirp);
1007         dirhandles_open--;
1008         return ret;
1009 }
1010
1011 /*******************************************************************
1012  Read from a directory. Also return current offset.
1013  Don't check for veto or invisible files.
1014 ********************************************************************/
1015
1016 const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1017 {
1018         const char *n;
1019         connection_struct *conn = dirp->conn;
1020
1021         SeekDir(dirp, *poffset);
1022         while ((n = vfs_readdirname(conn, dirp->dir))) {
1023                 struct name_cache_entry *e;
1024                 dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1025                 if (dirp->offset == -1) {
1026                         return NULL;
1027                 }
1028                 dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1029
1030                 e = &dirp->name_cache[dirp->name_cache_index];
1031                 SAFE_FREE(e->name);
1032                 e->name = SMB_STRDUP(n);
1033                 *poffset = e->offset= dirp->offset;
1034                 return e->name;
1035         }
1036         return NULL;
1037 }
1038
1039 /*******************************************************************
1040  Seek a dir.
1041 ********************************************************************/
1042
1043 void SeekDir(struct smb_Dir *dirp, long offset)
1044 {
1045         if (offset != dirp->offset) {
1046                 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1047                 dirp->offset = offset;
1048         }
1049 }
1050
1051 /*******************************************************************
1052  Tell a dir position.
1053 ********************************************************************/
1054
1055 long TellDir(struct smb_Dir *dirp)
1056 {
1057         return(dirp->offset);
1058 }
1059
1060 /*******************************************************************
1061  Find an entry by name. Leave us at the offset after it.
1062  Don't check for veto or invisible files.
1063 ********************************************************************/
1064
1065 BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1066 {
1067         int i;
1068         const char *entry;
1069         connection_struct *conn = dirp->conn;
1070
1071         /* Search back in the name cache. */
1072         for (i = dirp->name_cache_index; i >= 0; i--) {
1073                 struct name_cache_entry *e = &dirp->name_cache[i];
1074                 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1075                         *poffset = e->offset;
1076                         SeekDir(dirp, e->offset);
1077                         return True;
1078                 }
1079         }
1080         for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1081                 struct name_cache_entry *e = &dirp->name_cache[i];
1082                 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1083                         *poffset = e->offset;
1084                         SeekDir(dirp, e->offset);
1085                         return True;
1086                 }
1087         }
1088
1089         /* Not found in the name cache. Rewind directory and start from scratch. */
1090         SMB_VFS_REWINDDIR(conn, dirp->dir);
1091         *poffset = 0;
1092         while ((entry = ReadDirName(dirp, poffset))) {
1093                 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1094                         return True;
1095                 }
1096         }
1097         return False;
1098 }