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