Correct PPTP server firewall rules chain.
[tomato/davidwu.git] / release / src / router / samba / source / smbd / dir.c
blob379d0788fead6be83fa2b8c384f9ea50f70ded9a
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Directory handling routines
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
27 This module implements directory related functions for Samba.
30 typedef struct _dptr_struct {
31 struct _dptr_struct *next, *prev;
32 int dnum;
33 uint16 spid;
34 connection_struct *conn;
35 void *ptr;
36 BOOL expect_close;
37 char *wcard; /* Field only used for trans2_ searches */
38 uint16 attr; /* Field only used for trans2_ searches */
39 char *path;
40 } dptr_struct;
42 static struct bitmap *dptr_bmap;
43 static dptr_struct *dirptrs;
45 static int dptrs_open = 0;
47 #define INVALID_DPTR_KEY (-3)
49 /****************************************************************************
50 Initialise the dir bitmap.
51 ****************************************************************************/
53 void init_dptrs(void)
55 static BOOL dptrs_init=False;
57 if (dptrs_init)
58 return;
60 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
62 if (!dptr_bmap)
63 exit_server("out of memory in init_dptrs\n");
65 dptrs_init = True;
68 /****************************************************************************
69 Idle a dptr - the directory is closed but the control info is kept.
70 ****************************************************************************/
72 static void dptr_idle(dptr_struct *dptr)
74 if (dptr->ptr) {
75 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
76 dptrs_open--;
77 CloseDir(dptr->ptr);
78 dptr->ptr = NULL;
82 /****************************************************************************
83 Idle the oldest dptr.
84 ****************************************************************************/
86 static void dptr_idleoldest(void)
88 dptr_struct *dptr;
91 * Go to the end of the list.
93 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
96 if(!dptr) {
97 DEBUG(0,("No dptrs available to idle ?\n"));
98 return;
102 * Idle the oldest pointer.
105 for(; dptr; dptr = dptr->prev) {
106 if (dptr->ptr) {
107 dptr_idle(dptr);
108 return;
113 /****************************************************************************
114 Get the dptr_struct for a dir index.
115 ****************************************************************************/
117 static dptr_struct *dptr_get(int key, BOOL forclose)
119 dptr_struct *dptr;
121 for(dptr = dirptrs; dptr; dptr = dptr->next) {
122 if(dptr->dnum == key) {
123 if (!forclose && !dptr->ptr) {
124 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
125 dptr_idleoldest();
126 DEBUG(4,("Reopening dptr key %d\n",key));
127 if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
128 dptrs_open++;
130 DLIST_PROMOTE(dirptrs,dptr);
131 return dptr;
134 return(NULL);
137 /****************************************************************************
138 Get the dptr ptr for a dir index.
139 ****************************************************************************/
141 static void *dptr_ptr(int key)
143 dptr_struct *dptr = dptr_get(key, False);
145 if (dptr)
146 return(dptr->ptr);
147 return(NULL);
150 /****************************************************************************
151 Get the dir path for a dir index.
152 ****************************************************************************/
154 char *dptr_path(int key)
156 dptr_struct *dptr = dptr_get(key, False);
158 if (dptr)
159 return(dptr->path);
160 return(NULL);
163 /****************************************************************************
164 Get the dir wcard for a dir index (lanman2 specific).
165 ****************************************************************************/
167 char *dptr_wcard(int key)
169 dptr_struct *dptr = dptr_get(key, False);
171 if (dptr)
172 return(dptr->wcard);
173 return(NULL);
176 /****************************************************************************
177 Set the dir wcard for a dir index (lanman2 specific).
178 Returns 0 on ok, 1 on fail.
179 ****************************************************************************/
181 BOOL dptr_set_wcard(int key, char *wcard)
183 dptr_struct *dptr = dptr_get(key, False);
185 if (dptr) {
186 dptr->wcard = wcard;
187 return True;
189 return False;
192 /****************************************************************************
193 Set the dir attrib for a dir index (lanman2 specific).
194 Returns 0 on ok, 1 on fail.
195 ****************************************************************************/
197 BOOL dptr_set_attr(int key, uint16 attr)
199 dptr_struct *dptr = dptr_get(key, False);
201 if (dptr) {
202 dptr->attr = attr;
203 return True;
205 return False;
208 /****************************************************************************
209 Get the dir attrib for a dir index (lanman2 specific)
210 ****************************************************************************/
212 uint16 dptr_attr(int key)
214 dptr_struct *dptr = dptr_get(key, False);
216 if (dptr)
217 return(dptr->attr);
218 return(0);
221 /****************************************************************************
222 Close a dptr (internal func).
223 ****************************************************************************/
225 static void dptr_close_internal(dptr_struct *dptr)
227 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
229 DLIST_REMOVE(dirptrs, dptr);
232 * Free the dnum in the bitmap. Remember the dnum value is always
233 * biased by one with respect to the bitmap.
236 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
237 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
238 dptr->dnum ));
241 bitmap_clear(dptr_bmap, dptr->dnum - 1);
243 if (dptr->ptr) {
244 CloseDir(dptr->ptr);
245 dptrs_open--;
248 /* Lanman 2 specific code */
249 if (dptr->wcard)
250 free(dptr->wcard);
251 string_set(&dptr->path,"");
252 free((char *)dptr);
255 /****************************************************************************
256 Close a dptr given a key.
257 ****************************************************************************/
259 void dptr_close(int *key)
261 dptr_struct *dptr;
263 if(*key == INVALID_DPTR_KEY)
264 return;
266 /* OS/2 seems to use -1 to indicate "close all directories" */
267 if (*key == -1) {
268 dptr_struct *next;
269 for(dptr = dirptrs; dptr; dptr = next) {
270 next = dptr->next;
271 dptr_close_internal(dptr);
273 *key = INVALID_DPTR_KEY;
274 return;
277 dptr = dptr_get(*key, True);
279 if (!dptr) {
280 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
281 return;
284 dptr_close_internal(dptr);
286 *key = INVALID_DPTR_KEY;
289 /****************************************************************************
290 Close all dptrs for a cnum.
291 ****************************************************************************/
293 void dptr_closecnum(connection_struct *conn)
295 dptr_struct *dptr, *next;
296 for(dptr = dirptrs; dptr; dptr = next) {
297 next = dptr->next;
298 if (dptr->conn == conn)
299 dptr_close_internal(dptr);
303 /****************************************************************************
304 Idle all dptrs for a cnum.
305 ****************************************************************************/
307 void dptr_idlecnum(connection_struct *conn)
309 dptr_struct *dptr;
310 for(dptr = dirptrs; dptr; dptr = dptr->next) {
311 if (dptr->conn == conn && dptr->ptr)
312 dptr_idle(dptr);
316 /****************************************************************************
317 Close a dptr that matches a given path, only if it matches the spid also.
318 ****************************************************************************/
320 void dptr_closepath(char *path,uint16 spid)
322 dptr_struct *dptr, *next;
323 for(dptr = dirptrs; dptr; dptr = next) {
324 next = dptr->next;
325 if (spid == dptr->spid && strequal(dptr->path,path))
326 dptr_close_internal(dptr);
330 /****************************************************************************
331 Start a directory listing.
332 ****************************************************************************/
334 static BOOL start_dir(connection_struct *conn,char *directory)
336 DEBUG(5,("start_dir dir=%s\n",directory));
338 if (!check_name(directory,conn))
339 return(False);
341 if (! *directory)
342 directory = ".";
344 conn->dirptr = OpenDir(conn, directory, True);
345 if (conn->dirptr) {
346 dptrs_open++;
347 string_set(&conn->dirpath,directory);
348 return(True);
351 return(False);
354 /****************************************************************************
355 Try and close the oldest handle not marked for
356 expect close in the hope that the client has
357 finished with that one.
358 ****************************************************************************/
360 static void dptr_close_oldest(BOOL old)
362 dptr_struct *dptr;
365 * Go to the end of the list.
367 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
370 if(!dptr) {
371 DEBUG(0,("No old dptrs available to close oldest ?\n"));
372 return;
376 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
377 * does not have expect_close set. If 'old' is false, close
378 * one of the new dnum handles.
381 for(; dptr; dptr = dptr->prev) {
382 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
383 (!old && (dptr->dnum > 255))) {
384 dptr_close_internal(dptr);
385 return;
390 /****************************************************************************
391 Create a new dir ptr. If the flag old_handle is true then we must allocate
392 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
393 one byte long. If old_handle is false we allocate from the range
394 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
395 a directory handle is never zero. All the above is folklore taught to
396 me at Andrew's knee.... :-) :-). JRA.
397 ****************************************************************************/
399 int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,uint16 spid)
401 dptr_struct *dptr;
403 if (!start_dir(conn,path))
404 return(-2); /* Code to say use a unix error return code. */
406 if (dptrs_open >= MAX_OPEN_DIRECTORIES)
407 dptr_idleoldest();
409 dptr = (dptr_struct *)malloc(sizeof(dptr_struct));
410 if(!dptr) {
411 DEBUG(0,("malloc fail in dptr_create.\n"));
412 return -1;
415 ZERO_STRUCTP(dptr);
417 if(old_handle) {
420 * This is an old-style SMBsearch request. Ensure the
421 * value we return will fit in the range 1-255.
424 dptr->dnum = bitmap_find(dptr_bmap, 0);
426 if(dptr->dnum == -1 || dptr->dnum > 254) {
429 * Try and close the oldest handle not marked for
430 * expect close in the hope that the client has
431 * finished with that one.
434 dptr_close_oldest(True);
436 /* Now try again... */
437 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 free((char *)dptr);
442 return -1;
445 } else {
448 * This is a new-style trans2 request. Allocate from
449 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
452 dptr->dnum = bitmap_find(dptr_bmap, 255);
454 if(dptr->dnum == -1 || dptr->dnum < 255) {
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.
463 dptr_close_oldest(False);
465 /* Now try again... */
466 dptr->dnum = bitmap_find(dptr_bmap, 255);
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 free((char *)dptr);
471 return -1;
476 bitmap_set(dptr_bmap, dptr->dnum);
478 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
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 */
488 DLIST_ADD(dirptrs, dptr);
490 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
491 dptr->dnum,path,expect_close));
493 return(dptr->dnum);
496 /****************************************************************************
497 Fill the 5 byte server reserved dptr field.
498 ****************************************************************************/
500 BOOL dptr_fill(char *buf1,unsigned int key)
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);
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);
517 /****************************************************************************
518 Fetch the dir ptr and seek it given the 5 byte server field.
519 ****************************************************************************/
521 void *dptr_fetch(char *buf,int *num)
523 unsigned int key = *(unsigned char *)buf;
524 void *p = dptr_ptr(key);
525 uint32 offset;
526 if (!p) {
527 DEBUG(3,("fetched null dirptr %d\n",key));
528 return(NULL);
530 *num = key;
531 offset = IVAL(buf,1)&~DPTR_MASK;
532 SeekDir(p,offset);
533 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
534 key,dptr_path(key),offset));
535 return(p);
538 /****************************************************************************
539 Fetch the dir ptr.
540 ****************************************************************************/
542 void *dptr_fetch_lanman2(int dptr_num)
544 void *p = dptr_ptr(dptr_num);
546 if (!p) {
547 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
548 return(NULL);
550 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
551 return(p);
554 /****************************************************************************
555 Check a filetype for being valid.
556 ****************************************************************************/
558 BOOL dir_check_ftype(connection_struct *conn,int mode,SMB_STRUCT_STAT *st,int dirtype)
560 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
561 return False;
562 return True;
565 /****************************************************************************
566 Get an 8.3 directory entry.
567 ****************************************************************************/
569 BOOL get_dir_entry(connection_struct *conn,char *mask,int dirtype,char *fname,
570 SMB_OFF_T *size,int *mode,time_t *date,BOOL check_descend)
572 char *dname;
573 BOOL found = False;
574 SMB_STRUCT_STAT sbuf;
575 pstring path;
576 pstring pathreal;
577 BOOL isrootdir;
578 pstring filename;
579 BOOL needslash;
581 *path = *pathreal = *filename = 0;
583 isrootdir = (strequal(conn->dirpath,"./") ||
584 strequal(conn->dirpath,".") ||
585 strequal(conn->dirpath,"/"));
587 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
589 if (!conn->dirptr)
590 return(False);
592 while (!found)
594 BOOL filename_is_mask = False;
595 dname = ReadDirName(conn->dirptr);
597 DEBUG(6,("readdir on dirptr 0x%lx now at offset %d\n",
598 (long)conn->dirptr,TellDir(conn->dirptr)));
600 if (dname == NULL)
601 return(False);
603 pstrcpy(filename,dname);
605 if ((filename_is_mask = (strcmp(filename,mask) == 0)) ||
606 (name_map_mangle(filename,True,False,SNUM(conn)) &&
607 mask_match(filename,mask,False,False)))
609 if (isrootdir && (strequal(filename,"..") || strequal(filename,".")))
610 continue;
612 pstrcpy(fname,filename);
613 *path = 0;
614 pstrcpy(path,conn->dirpath);
615 if(needslash)
616 pstrcat(path,"/");
617 pstrcpy(pathreal,path);
618 pstrcat(path,fname);
619 pstrcat(pathreal,dname);
620 if (dos_stat(pathreal,&sbuf) != 0)
622 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
623 continue;
626 if (check_descend && !strequal(fname,".") && !strequal(fname,".."))
627 continue;
629 *mode = dos_mode(conn,pathreal,&sbuf);
631 if (!dir_check_ftype(conn,*mode,&sbuf,dirtype))
633 DEBUG(5,("[%s] attribs didn't match %x\n",filename,dirtype));
634 continue;
637 if (!filename_is_mask)
639 /* Now we can allow the mangled cache to be updated */
640 pstrcpy(filename,dname);
641 name_map_mangle(filename,True,True,SNUM(conn));
644 *size = sbuf.st_size;
645 *date = sbuf.st_mtime;
647 DEBUG(5,("get_dir_entry found %s fname=%s\n",pathreal,fname));
649 found = True;
653 return(found);
658 typedef struct
660 int pos;
661 int numentries;
662 int mallocsize;
663 char *data;
664 char *current;
665 } Dir;
668 /*******************************************************************
669 Open a directory.
670 ********************************************************************/
672 void *OpenDir(connection_struct *conn, char *name, BOOL use_veto)
674 Dir *dirp;
675 char *n;
676 DIR *p = dos_opendir(name);
677 int used=0;
679 if (!p) return(NULL);
680 dirp = (Dir *)malloc(sizeof(Dir));
681 if (!dirp) {
682 closedir(p);
683 return(NULL);
685 dirp->pos = dirp->numentries = dirp->mallocsize = 0;
686 dirp->data = dirp->current = NULL;
688 while ((n = dos_readdirname(p)))
690 int l = strlen(n)+1;
692 /* If it's a vetoed file, pretend it doesn't even exist */
693 if (use_veto && conn && IS_VETO_PATH(conn, n)) continue;
695 if (used + l > dirp->mallocsize) {
696 int s = MAX(used+l,used+2000);
697 char *r;
698 r = (char *)Realloc(dirp->data,s);
699 if (!r) {
700 DEBUG(0,("Out of memory in OpenDir\n"));
701 break;
703 dirp->data = r;
704 dirp->mallocsize = s;
705 dirp->current = dirp->data;
707 pstrcpy(dirp->data+used,n);
708 used += l;
709 dirp->numentries++;
712 closedir(p);
713 return((void *)dirp);
717 /*******************************************************************
718 Close a directory.
719 ********************************************************************/
721 void CloseDir(void *p)
723 Dir *dirp = (Dir *)p;
724 if (!dirp) return;
725 if (dirp->data) free(dirp->data);
726 free(dirp);
729 /*******************************************************************
730 Read from a directory.
731 ********************************************************************/
733 char *ReadDirName(void *p)
735 char *ret;
736 Dir *dirp = (Dir *)p;
738 if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL);
740 ret = dirp->current;
741 dirp->current = skip_string(dirp->current,1);
742 dirp->pos++;
744 return(ret);
748 /*******************************************************************
749 Seek a dir.
750 ********************************************************************/
752 BOOL SeekDir(void *p,int pos)
754 Dir *dirp = (Dir *)p;
756 if (!dirp) return(False);
758 if (pos < dirp->pos) {
759 dirp->current = dirp->data;
760 dirp->pos = 0;
763 while (dirp->pos < pos && ReadDirName(p)) ;
765 return(dirp->pos == pos);
768 /*******************************************************************
769 Tell a dir position.
770 ********************************************************************/
772 int TellDir(void *p)
774 Dir *dirp = (Dir *)p;
776 if (!dirp) return(-1);
778 return(dirp->pos);
782 /* -------------------------------------------------------------------------- **
783 * This section manages a global directory cache.
784 * (It should probably be split into a separate module. crh)
785 * -------------------------------------------------------------------------- **
788 typedef struct
790 ubi_dlNode node;
791 char *path;
792 char *name;
793 char *dname;
794 int snum;
795 } dir_cache_entry;
797 static ubi_dlNewList( dir_cache );
799 void DirCacheAdd( char *path, char *name, char *dname, int snum )
800 /* ------------------------------------------------------------------------ **
801 * Add an entry to the directory cache.
803 * Input: path -
804 * name -
805 * dname -
806 * snum -
808 * Output: None.
810 * ------------------------------------------------------------------------ **
813 int pathlen;
814 int namelen;
815 dir_cache_entry *entry;
817 /* Allocate the structure & string space in one go so that it can be freed
818 * in one call to free().
820 pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */
821 namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */
822 entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry )
823 + pathlen
824 + namelen
825 + strlen( dname ) +1 );
826 if( NULL == entry ) /* Not adding to the cache is not fatal, */
827 return; /* so just return as if nothing happened. */
829 /* Set pointers correctly and load values. */
830 entry->path = pstrcpy( (char *)&entry[1], path);
831 entry->name = pstrcpy( &(entry->path[pathlen]), name);
832 entry->dname = pstrcpy( &(entry->name[namelen]), dname);
833 entry->snum = snum;
835 /* Add the new entry to the linked list. */
836 (void)ubi_dlAddHead( dir_cache, entry );
837 DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) );
839 /* Free excess cache entries. */
840 while( DIRCACHESIZE < dir_cache->count )
841 free( ubi_dlRemTail( dir_cache ) );
843 } /* DirCacheAdd */
846 char *DirCacheCheck( char *path, char *name, int snum )
847 /* ------------------------------------------------------------------------ **
848 * Search for an entry to the directory cache.
850 * Input: path -
851 * name -
852 * snum -
854 * Output: The dname string of the located entry, or NULL if the entry was
855 * not found.
857 * Notes: This uses a linear search, which is is okay because of
858 * the small size of the cache. Use a splay tree or hash
859 * for large caches.
861 * ------------------------------------------------------------------------ **
864 dir_cache_entry *entry;
866 for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
867 NULL != entry;
868 entry = (dir_cache_entry *)ubi_dlNext( entry ) )
870 if( entry->snum == snum
871 && 0 == strcmp( name, entry->name )
872 && 0 == strcmp( path, entry->path ) )
874 DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname));
875 return( entry->dname );
879 return(NULL);
880 } /* DirCacheCheck */
882 void DirCacheFlush(int snum)
883 /* ------------------------------------------------------------------------ **
884 * Remove all cache entries which have an snum that matches the input.
886 * Input: snum -
888 * Output: None.
890 * ------------------------------------------------------------------------ **
893 dir_cache_entry *entry;
894 ubi_dlNodePtr next;
896 for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache );
897 NULL != entry; ) {
898 next = ubi_dlNext( entry );
899 if( entry->snum == snum )
900 free( ubi_dlRemThis( dir_cache, entry ) );
901 entry = (dir_cache_entry *)next;
903 } /* DirCacheFlush */
905 /* -------------------------------------------------------------------------- **
906 * End of the section that manages the global directory cache.
907 * -------------------------------------------------------------------------- **