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
31struct name_cache_entry {
32	char *name;
33	long offset;
34};
35
36struct 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
45struct 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
58static struct bitmap *dptr_bmap;
59static struct dptr_struct *dirptrs;
60static int dirhandles_open = 0;
61
62#define INVALID_DPTR_KEY (-3)
63
64/****************************************************************************
65 Initialise the dir bitmap.
66****************************************************************************/
67
68void 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
87static 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
100static 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
131static 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
158char *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
170char *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
182uint16 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
195BOOL 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
218static 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
250void 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
284void 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
298void 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
311void 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
327static 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
365int 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
488int dptr_CloseDir(struct dptr_struct *dptr)
489{
490	return CloseDir(dptr->dir_hnd);
491}
492
493void dptr_SeekDir(struct dptr_struct *dptr, long offset)
494{
495	SeekDir(dptr->dir_hnd, offset);
496}
497
498long 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
507static 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
523const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
524{
525	pstring pathreal;
526
527	ZERO_STRUCTP(pst);
528
529	if (dptr->has_wild) {
530		return dptr_normal_ReadDirName(dptr, poffset, pst);
531	}
532
533	/* If poffset is -1 then we know we returned this name before and we have
534	   no wildcards. We're at the end of the directory. */
535	if (*poffset == -1) {
536		return NULL;
537	}
538
539	/* We know the stored wcard contains no wildcard characters. See if we can match
540	   with a stat call. If we can't, then set has_wild to true to
541	   prevent us from doing this on every call. */
542
543	/* First check if it should be visible. */
544	if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
545		dptr->has_wild = True;
546		return dptr_normal_ReadDirName(dptr, poffset, pst);
547	}
548
549	if (VALID_STAT(*pst)) {
550		/* We need to set the underlying dir_hdn offset to -1 also as
551		   this function is usually called with the output from TellDir. */
552		dptr->dir_hnd->offset = *poffset = -1;
553		return dptr->wcard;
554	}
555
556	pstrcpy(pathreal,dptr->path);
557	pstrcat(pathreal,"/");
558	pstrcat(pathreal,dptr->wcard);
559
560	if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
561		/* We need to set the underlying dir_hdn offset to -1 also as
562		   this function is usually called with the output from TellDir. */
563		dptr->dir_hnd->offset = *poffset = -1;
564		return dptr->wcard;
565	} else {
566		/* If we get any other error than ENOENT or ENOTDIR
567		   then the file exists we just can't stat it. */
568		if (errno != ENOENT && errno != ENOTDIR) {
569			/* We need to set the underlying dir_hdn offset to -1 also as
570			   this function is usually called with the output from TellDir. */
571			dptr->dir_hnd->offset = *poffset = -1;
572			return dptr->wcard;
573		}
574	}
575
576	dptr->has_wild = True;
577
578	/* In case sensitive mode we don't search - we know if it doesn't exist
579	   with a stat we will fail. */
580
581	if (dptr->conn->case_sensitive) {
582		/* We need to set the underlying dir_hdn offset to -1 also as
583		   this function is usually called with the output from TellDir. */
584		dptr->dir_hnd->offset = *poffset = -1;
585		return NULL;
586	} else {
587		return dptr_normal_ReadDirName(dptr, poffset, pst);
588	}
589}
590
591/****************************************************************************
592 Search for a file by name, skipping veto'ed and not visible files.
593****************************************************************************/
594
595BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
596{
597	ZERO_STRUCTP(pst);
598
599	if (!dptr->has_wild && (dptr->dir_hnd->offset == -1)) {
600		/* This is a singleton directory and we're already at the end. */
601		*poffset = -1;
602		return False;
603	}
604
605	while (SearchDir(dptr->dir_hnd, name, poffset) == True) {
606		if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
607			return True;
608		}
609	}
610	return False;
611}
612
613/****************************************************************************
614 Fill the 5 byte server reserved dptr field.
615****************************************************************************/
616
617BOOL dptr_fill(char *buf1,unsigned int key)
618{
619	unsigned char *buf = (unsigned char *)buf1;
620	struct dptr_struct *dptr = dptr_get(key, False);
621	uint32 offset;
622	if (!dptr) {
623		DEBUG(1,("filling null dirptr %d\n",key));
624		return(False);
625	}
626	offset = TellDir(dptr->dir_hnd);
627	DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
628		(long)dptr->dir_hnd,(int)offset));
629	buf[0] = key;
630	SIVAL(buf,1,offset | DPTR_MASK);
631	return(True);
632}
633
634/****************************************************************************
635 Fetch the dir ptr and seek it given the 5 byte server field.
636****************************************************************************/
637
638struct dptr_struct *dptr_fetch(char *buf,int *num)
639{
640	unsigned int key = *(unsigned char *)buf;
641	struct dptr_struct *dptr = dptr_get(key, False);
642	uint32 offset;
643
644	if (!dptr) {
645		DEBUG(3,("fetched null dirptr %d\n",key));
646		return(NULL);
647	}
648	*num = key;
649	offset = IVAL(buf,1)&~DPTR_MASK;
650	SeekDir(dptr->dir_hnd,(long)offset);
651	DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
652		key,dptr_path(key),offset));
653	return(dptr);
654}
655
656/****************************************************************************
657 Fetch the dir ptr.
658****************************************************************************/
659
660struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
661{
662	struct dptr_struct *dptr  = dptr_get(dptr_num, False);
663
664	if (!dptr) {
665		DEBUG(3,("fetched null dirptr %d\n",dptr_num));
666		return(NULL);
667	}
668	DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
669	return(dptr);
670}
671
672/****************************************************************************
673 Check a filetype for being valid.
674****************************************************************************/
675
676BOOL dir_check_ftype(connection_struct *conn,int mode,int dirtype)
677{
678	int mask;
679
680	/* Check the "may have" search bits. */
681	if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
682		return False;
683
684	/* Check the "must have" bits, which are the may have bits shifted eight */
685	/* If must have bit is set, the file/dir can not be returned in search unless the matching
686		file attribute is set */
687	mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
688	if(mask) {
689		if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask)   /* check if matching attribute present */
690			return True;
691		else
692			return False;
693	}
694
695	return True;
696}
697
698static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
699{
700	mangle_map(filename,True,False,SNUM(conn));
701	return mask_match(filename,mask,False);
702}
703
704/****************************************************************************
705 Get an 8.3 directory entry.
706****************************************************************************/
707
708BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype, pstring fname,
709                   SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
710{
711	const char *dname;
712	BOOL found = False;
713	SMB_STRUCT_STAT sbuf;
714	pstring path;
715	pstring pathreal;
716	BOOL isrootdir;
717	pstring filename;
718	BOOL needslash;
719
720	*path = *pathreal = *filename = 0;
721
722	isrootdir = (strequal(conn->dirpath,"./") ||
723			strequal(conn->dirpath,".") ||
724			strequal(conn->dirpath,"/"));
725
726	needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
727
728	if (!conn->dirptr)
729		return(False);
730
731	while (!found) {
732		long curoff = dptr_TellDir(conn->dirptr);
733		dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
734
735		DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
736			(long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
737
738		if (dname == NULL)
739			return(False);
740
741		pstrcpy(filename,dname);
742
743		/* notice the special *.* handling. This appears to be the only difference
744			between the wildcard handling in this routine and in the trans2 routines.
745			see masktest for a demo
746		*/
747		if ((strcmp(mask,"*.*") == 0) ||
748		    mask_match(filename,mask,False) ||
749		    mangle_mask_match(conn,filename,mask)) {
750			if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
751				continue;
752
753			if (!mangle_is_8_3(filename, False))
754				mangle_map(filename,True,False,SNUM(conn));
755
756			pstrcpy(fname,filename);
757			*path = 0;
758			pstrcpy(path,conn->dirpath);
759			if(needslash)
760				pstrcat(path,"/");
761			pstrcpy(pathreal,path);
762			pstrcat(path,fname);
763			pstrcat(pathreal,dname);
764			if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
765				DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
766				continue;
767			}
768
769			*mode = dos_mode(conn,pathreal,&sbuf);
770
771			if (!dir_check_ftype(conn,*mode,dirtype)) {
772				DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
773				continue;
774			}
775
776			*size = sbuf.st_size;
777			*date = sbuf.st_mtime;
778
779			DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
780
781			found = True;
782		}
783	}
784
785	return(found);
786}
787
788/*******************************************************************
789 Check to see if a user can read a file. This is only approximate,
790 it is used as part of the "hide unreadable" option. Don't
791 use it for anything security sensitive.
792********************************************************************/
793
794static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
795{
796	extern struct current_user current_user;
797	SEC_DESC *psd = NULL;
798	size_t sd_size;
799	files_struct *fsp;
800	int smb_action;
801	NTSTATUS status;
802	uint32 access_granted;
803
804	/*
805	 * If user is a member of the Admin group
806	 * we never hide files from them.
807	 */
808
809	if (conn->admin_user)
810		return True;
811
812	/* If we can't stat it does not show it */
813	if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
814		return False;
815
816	/* Pseudo-open the file (note - no fd's created). */
817
818	if(S_ISDIR(pst->st_mode))
819		 fsp = open_directory(conn, name, pst, 0, SET_DENY_MODE(DENY_NONE), (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
820			&smb_action);
821	else
822		fsp = open_file_stat(conn, name, pst);
823
824	if (!fsp)
825		return False;
826
827	/* Get NT ACL -allocated in main loop talloc context. No free needed here. */
828	sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
829			(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
830	close_file(fsp, True);
831
832	/* No access if SD get failed. */
833	if (!sd_size)
834		return False;
835
836	return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
837                                 &access_granted, &status);
838}
839
840/*******************************************************************
841 Check to see if a user can write a file (and only files, we do not
842 check dirs on this one). This is only approximate,
843 it is used as part of the "hide unwriteable" option. Don't
844 use it for anything security sensitive.
845********************************************************************/
846
847static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
848{
849	extern struct current_user current_user;
850	SEC_DESC *psd = NULL;
851	size_t sd_size;
852	files_struct *fsp;
853	int smb_action;
854	int access_mode;
855	NTSTATUS status;
856	uint32 access_granted;
857
858	/*
859	 * If user is a member of the Admin group
860	 * we never hide files from them.
861	 */
862
863	if (conn->admin_user)
864		return True;
865
866	/* If we can't stat it does not show it */
867	if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
868		return False;
869
870	/* Pseudo-open the file (note - no fd's created). */
871
872	if(S_ISDIR(pst->st_mode))
873		return True;
874	else
875		fsp = open_file_shared1(conn, name, pst, FILE_WRITE_ATTRIBUTES, SET_DENY_MODE(DENY_NONE),
876			(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), FILE_ATTRIBUTE_NORMAL, INTERNAL_OPEN_ONLY,
877			&access_mode, &smb_action);
878
879	if (!fsp)
880		return False;
881
882	/* Get NT ACL -allocated in main loop talloc context. No free needed here. */
883	sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fd,
884			(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
885	close_file(fsp, False);
886
887	/* No access if SD get failed. */
888	if (!sd_size)
889		return False;
890
891	return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
892                                 &access_granted, &status);
893}
894
895/*******************************************************************
896  Is a file a "special" type ?
897********************************************************************/
898
899static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
900{
901	/*
902	 * If user is a member of the Admin group
903	 * we never hide files from them.
904	 */
905
906	if (conn->admin_user)
907		return False;
908
909	/* If we can't stat it does not show it */
910	if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
911		return True;
912
913	if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
914		return False;
915
916	return True;
917}
918
919/*******************************************************************
920 Should the file be seen by the client ?
921********************************************************************/
922
923BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
924{
925	BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
926	BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
927	BOOL hide_special = lp_hide_special_files(SNUM(conn));
928
929	ZERO_STRUCTP(pst);
930
931	if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
932		return True; /* . and .. are always visible. */
933	}
934
935	/* Foxconn added start pling 01/30/2012 */
936	/* Only allow "admin" user to see admin paths */
937	if (1) {
938		pstring full_path;
939		getcwd(full_path, sizeof(full_path));
940		pstrcat(full_path, "/");
941		if (strcmp(dir_path, "./")) {
942			pstrcat(full_path, dir_path);
943			pstrcat(full_path, "/");
944		}
945		pstrcat(full_path, name);
946
947		/* "full_path" is in format "/tmp/mnt/usbx/partx/xxx",
948		 * skip the leading /tmp/mnt/ */
949		if (IS_ADMIN_PATH(conn, &full_path[9])) {
950			if (strcmp(conn->user, "admin") == 0)
951				return True;
952			else
953				return False;
954		}
955	}
956	/* Foxconn added end pling 01/30/2012 */
957
958	/* If it's a vetoed file, pretend it doesn't even exist */
959	if (use_veto && IS_VETO_PATH(conn, name)) {
960		return False;
961	}
962
963	if (hide_unreadable || hide_unwriteable || hide_special) {
964		char *entry = NULL;
965
966		if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
967			return False;
968		}
969		/* Honour _hide unreadable_ option */
970		if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
971  		        SAFE_FREE(entry);
972		        return False;
973		}
974		/* Honour _hide unwriteable_ option */
975		if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
976			SAFE_FREE(entry);
977			return False;
978		}
979		/* Honour _hide_special_ option */
980		if (hide_special && !file_is_special(conn, entry, pst)) {
981			SAFE_FREE(entry);
982			return False;
983		}
984		SAFE_FREE(entry);
985	}
986	return True;
987}
988
989/*******************************************************************
990 Open a directory.
991********************************************************************/
992
993struct smb_Dir *OpenDir(connection_struct *conn, const char *name)
994{
995	struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
996	if (!dirp) {
997		return NULL;
998	}
999	ZERO_STRUCTP(dirp);
1000
1001	dirp->conn = conn;
1002
1003	dirp->dir_path = SMB_STRDUP(name);
1004	if (!dirp->dir_path) {
1005		goto fail;
1006	}
1007	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path);
1008	if (!dirp->dir) {
1009		DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1010		goto fail;
1011	}
1012
1013	dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry, NAME_CACHE_SIZE);
1014	if (!dirp->name_cache) {
1015		goto fail;
1016	}
1017
1018	dirhandles_open++;
1019	return dirp;
1020
1021  fail:
1022
1023	if (dirp) {
1024		if (dirp->dir) {
1025			SMB_VFS_CLOSEDIR(conn,dirp->dir);
1026		}
1027		SAFE_FREE(dirp->dir_path);
1028		SAFE_FREE(dirp->name_cache);
1029		SAFE_FREE(dirp);
1030	}
1031	return NULL;
1032}
1033
1034
1035/*******************************************************************
1036 Close a directory.
1037********************************************************************/
1038
1039int CloseDir(struct smb_Dir *dirp)
1040{
1041	int i, ret = 0;
1042
1043	if (dirp->dir) {
1044		ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1045	}
1046	SAFE_FREE(dirp->dir_path);
1047	if (dirp->name_cache) {
1048		for (i = 0; i < NAME_CACHE_SIZE; i++) {
1049			SAFE_FREE(dirp->name_cache[i].name);
1050		}
1051	}
1052	SAFE_FREE(dirp->name_cache);
1053	SAFE_FREE(dirp);
1054	dirhandles_open--;
1055	return ret;
1056}
1057
1058/*******************************************************************
1059 Read from a directory. Also return current offset.
1060 Don't check for veto or invisible files.
1061********************************************************************/
1062
1063const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1064{
1065	const char *n;
1066	connection_struct *conn = dirp->conn;
1067
1068	SeekDir(dirp, *poffset);
1069	while ((n = vfs_readdirname(conn, dirp->dir))) {
1070		struct name_cache_entry *e;
1071		dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1072		if (dirp->offset == -1) {
1073			return NULL;
1074		}
1075		dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE;
1076
1077		e = &dirp->name_cache[dirp->name_cache_index];
1078		SAFE_FREE(e->name);
1079		e->name = SMB_STRDUP(n);
1080		*poffset = e->offset= dirp->offset;
1081		return e->name;
1082	}
1083	dirp->offset = -1;
1084	return NULL;
1085}
1086
1087/*******************************************************************
1088 Seek a dir.
1089********************************************************************/
1090
1091void SeekDir(struct smb_Dir *dirp, long offset)
1092{
1093	if (offset != dirp->offset) {
1094		SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1095		dirp->offset = offset;
1096	}
1097}
1098
1099/*******************************************************************
1100 Tell a dir position.
1101********************************************************************/
1102
1103long TellDir(struct smb_Dir *dirp)
1104{
1105	return(dirp->offset);
1106}
1107
1108/*******************************************************************
1109 Find an entry by name. Leave us at the offset after it.
1110 Don't check for veto or invisible files.
1111********************************************************************/
1112
1113BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1114{
1115	int i;
1116	const char *entry;
1117	connection_struct *conn = dirp->conn;
1118
1119	/* Search back in the name cache. */
1120	for (i = dirp->name_cache_index; i >= 0; i--) {
1121		struct name_cache_entry *e = &dirp->name_cache[i];
1122		if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1123			*poffset = e->offset;
1124			SeekDir(dirp, e->offset);
1125			return True;
1126		}
1127	}
1128	for (i = NAME_CACHE_SIZE-1; i > dirp->name_cache_index; i--) {
1129		struct name_cache_entry *e = &dirp->name_cache[i];
1130		if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1131			*poffset = e->offset;
1132			SeekDir(dirp, e->offset);
1133			return True;
1134		}
1135	}
1136
1137	/* Not found in the name cache. Rewind directory and start from scratch. */
1138	SMB_VFS_REWINDDIR(conn, dirp->dir);
1139	*poffset = 0;
1140	while ((entry = ReadDirName(dirp, poffset))) {
1141		if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1142			return True;
1143		}
1144	}
1145	return False;
1146}
1147