import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / 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 = (dptr_struct *)malloc(sizeof(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, 0, &access_mode, &smb_action);
767
768         if (!fsp)
769                 return False;
770
771         /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
772         sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
773                         (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
774         close_file(fsp, False);
775
776         /* No access if SD get failed. */
777         if (!sd_size)
778                 return False;
779
780         return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
781                                  &access_granted, &status);
782 }
783
784 /*******************************************************************
785   Is a file a "special" type ?
786 ********************************************************************/
787
788 static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
789 {
790         /*
791          * If user is a member of the Admin group
792          * we never hide files from them.
793          */
794
795         if (conn->admin_user)
796                 return False;
797
798         /* If we can't stat it does not show it */
799         if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
800                 return True;
801
802         if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
803                 return False;
804
805         return True;
806 }
807
808 /*******************************************************************
809  Open a directory.
810 ********************************************************************/
811
812 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
813 {
814         Dir *dirp;
815         const char *n;
816         DIR *p = SMB_VFS_OPENDIR(conn,name);
817         int used=0;
818
819         if (!p)
820                 return(NULL);
821         dirp = (Dir *)malloc(sizeof(Dir));
822         if (!dirp) {
823                 DEBUG(0,("Out of memory in OpenDir\n"));
824                 SMB_VFS_CLOSEDIR(conn,p);
825                 return(NULL);
826         }
827         dirp->pos = dirp->numentries = dirp->mallocsize = 0;
828         dirp->data = dirp->current = NULL;
829
830         while (True) {
831                 int l;
832                 BOOL normal_entry = True;
833                 SMB_STRUCT_STAT st;
834                 char *entry = NULL;
835
836                 if (used == 0) {
837                         n = ".";
838                         normal_entry = False;
839                 } else if (used == 2) {
840                         n = "..";
841                         normal_entry = False;
842                 } else {
843                         n = vfs_readdirname(conn, p);
844                         if (n == NULL)
845                                 break;
846                         if ((strcmp(".",n) == 0) ||(strcmp("..",n) == 0))
847                                 continue;
848                         normal_entry = True;
849                 }
850
851                 ZERO_STRUCT(st);
852                 l = strlen(n)+1;
853
854                 /* If it's a vetoed file, pretend it doesn't even exist */
855                 if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
856                         continue;
857
858                 /* Honour _hide unreadable_ option */
859                 if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
860                         int ret=0;
861       
862                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
863                                 ret = user_can_read_file(conn, entry, &st);
864                         }
865                         if (!ret) {
866                                 SAFE_FREE(entry);
867                                 continue;
868                         }
869                 }
870
871                 /* Honour _hide unwriteable_ option */
872                 if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
873                         int ret=0;
874       
875                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
876                                 ret = user_can_write_file(conn, entry, &st);
877                         }
878                         if (!ret) {
879                                 SAFE_FREE(entry);
880                                 continue;
881                         }
882                 }
883
884                 /* Honour _hide_special_ option */
885                 if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
886                         int ret=0;
887       
888                         if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
889                                 ret = file_is_special(conn, entry, &st);
890                         }
891                         if (ret) {
892                                 SAFE_FREE(entry);
893                                 continue;
894                         }
895                 }
896
897                 SAFE_FREE(entry);
898
899                 if (used + l > dirp->mallocsize) {
900                         int s = MAX(used+l,used+2000);
901                         char *r;
902                         r = (char *)Realloc(dirp->data,s);
903                         if (!r) {
904                                 DEBUG(0,("Out of memory in OpenDir\n"));
905                                         break;
906                         }
907                         dirp->data = r;
908                         dirp->mallocsize = s;
909                         dirp->current = dirp->data;
910                 }
911
912                 safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize);
913                 used += l;
914                 dirp->numentries++;
915         }
916
917         SMB_VFS_CLOSEDIR(conn,p);
918         return((void *)dirp);
919 }
920
921
922 /*******************************************************************
923  Close a directory.
924 ********************************************************************/
925
926 void CloseDir(void *p)
927 {
928         if (!p)
929                 return;    
930         SAFE_FREE(((Dir *)p)->data);
931         SAFE_FREE(p);
932 }
933
934 /*******************************************************************
935  Read from a directory.
936 ********************************************************************/
937
938 const char *ReadDirName(void *p)
939 {
940         char *ret;
941         Dir *dirp = (Dir *)p;
942
943         if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
944                 return(NULL);
945
946         ret = dirp->current;
947         dirp->current = skip_string(dirp->current,1);
948         dirp->pos++;
949
950         return(ret);
951 }
952
953 /*******************************************************************
954  Seek a dir.
955 ********************************************************************/
956
957 BOOL SeekDir(void *p,int pos)
958 {
959         Dir *dirp = (Dir *)p;
960
961         if (!dirp)
962                 return(False);
963
964         if (pos < dirp->pos) {
965                 dirp->current = dirp->data;
966                 dirp->pos = 0;
967         }
968
969         while (dirp->pos < pos && ReadDirName(p))
970                 ;
971
972         return (dirp->pos == pos);
973 }
974
975 /*******************************************************************
976  Tell a dir position.
977 ********************************************************************/
978
979 int TellDir(void *p)
980 {
981         Dir *dirp = (Dir *)p;
982
983         if (!dirp)
984                 return(-1);
985   
986         return(dirp->pos);
987 }
988
989 /*******************************************************************************
990  This section manages a global directory cache.
991  (It should probably be split into a separate module.  crh)
992 ********************************************************************************/
993
994 typedef struct {
995         ubi_dlNode node;
996         char *path;
997         char *name;
998         char *dname;
999         int snum;
1000 } dir_cache_entry;
1001
1002 static ubi_dlNewList( dir_cache );
1003
1004 /*****************************************************************************
1005  Add an entry to the directory cache.
1006  Input:  path  -
1007          name  -
1008          dname -
1009          snum  -
1010  Output: None.
1011 *****************************************************************************/
1012
1013 void DirCacheAdd( const char *path, const char *name, const char *dname, int snum )
1014 {
1015         int pathlen;
1016         int namelen;
1017         dir_cache_entry  *entry;
1018
1019         /*
1020          * Allocate the structure & string space in one go so that it can be freed
1021          * in one call to free().
1022          */
1023         pathlen = strlen(path) + 1;  /* Bytes required to store path (with nul). */
1024         namelen = strlen(name) + 1;  /* Bytes required to store name (with nul). */
1025         entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
1026                                         + pathlen
1027                                         + namelen
1028                                         + strlen( dname ) +1 );
1029         if( NULL == entry )   /* Not adding to the cache is not fatal,  */
1030                 return;             /* so just return as if nothing happened. */
1031
1032         /* Set pointers correctly and load values. */
1033         entry->path  = memcpy( (char *)&entry[1], path, strlen(path)+1 );
1034         entry->name  = memcpy( &(entry->path[pathlen]), name, strlen(name)+1 );
1035         entry->dname = memcpy( &(entry->name[namelen]), dname, strlen(dname)+1 );
1036         entry->snum  = snum;
1037
1038         /* Add the new entry to the linked list. */
1039         (void)ubi_dlAddHead( dir_cache, entry );
1040         DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
1041
1042         /* Free excess cache entries. */
1043         while( DIRCACHESIZE < dir_cache->count )
1044                 safe_free( ubi_dlRemTail( dir_cache ) );
1045 }
1046
1047 /*****************************************************************************
1048  Search for an entry to the directory cache.
1049  Input:  path  -
1050          name  -
1051          snum  -
1052  Output: The dname string of the located entry, or NULL if the entry was
1053          not found.
1054
1055  Notes:  This uses a linear search, which is is okay because of
1056          the small size of the cache.  Use a splay tree or hash
1057          for large caches.
1058 *****************************************************************************/
1059
1060 char *DirCacheCheck( const char *path, const char *name, int snum )
1061 {
1062         dir_cache_entry *entry;
1063
1064         for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
1065                         NULL != entry;
1066                         entry = (dir_cache_entry *)ubi_dlNext( entry ) ) {
1067                 if( entry->snum == snum
1068                                 && entry->name && 0 == strcmp( name, entry->name )
1069                                 && entry->path && 0 == strcmp( path, entry->path ) ) {
1070                         DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
1071                         return( entry->dname );
1072                 }
1073         }
1074
1075         return(NULL);
1076 }
1077
1078 /*****************************************************************************
1079  Remove all cache entries which have an snum that matches the input.
1080  Input:  snum  -
1081  Output: None.
1082 *****************************************************************************/
1083
1084 void DirCacheFlush(int snum)
1085 {
1086         dir_cache_entry *entry;
1087         ubi_dlNodePtr    next;
1088
1089         for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); 
1090             NULL != entry; )  {
1091                 next = ubi_dlNext( entry );
1092                 if( entry->snum == snum )
1093                         safe_free( ubi_dlRemThis( dir_cache, entry ) );
1094                 entry = (dir_cache_entry *)next;
1095         }
1096 }