source: branches/samba-3.0/source/smbd/dir.c@ 223

Last change on this file since 223 was 71, checked in by Paul Smedley, 18 years ago

Update source to 3.0.26a

File size: 37.2 KB
Line 
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
27extern struct current_user current_user;
28
29/* "Special" directory offsets. */
30#define END_OF_DIRECTORY_OFFSET ((long)-1)
31#define START_OF_DIRECTORY_OFFSET ((long)0)
32#define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
33
34/* Make directory handle internals available. */
35
36struct name_cache_entry {
37 char *name;
38 long offset;
39};
40
41struct smb_Dir {
42 connection_struct *conn;
43 SMB_STRUCT_DIR *dir;
44 long offset;
45 char *dir_path;
46 size_t name_cache_size;
47 struct name_cache_entry *name_cache;
48 unsigned int name_cache_index;
49 unsigned int file_number;
50};
51
52struct dptr_struct {
53 struct dptr_struct *next, *prev;
54 int dnum;
55 uint16 spid;
56 struct connection_struct *conn;
57 struct smb_Dir *dir_hnd;
58 BOOL expect_close;
59 char *wcard;
60 uint32 attr;
61 char *path;
62 BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
63 BOOL did_stat; /* Optimisation for non-wcard searches. */
64};
65
66static struct bitmap *dptr_bmap;
67static struct dptr_struct *dirptrs;
68static int dirhandles_open = 0;
69
70#define INVALID_DPTR_KEY (-3)
71
72/****************************************************************************
73 Make a dir struct.
74****************************************************************************/
75
76void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,uint32 mode,time_t date, BOOL uc)
77{
78 char *p;
79 pstring mask2;
80
81 pstrcpy(mask2,mask);
82
83 if ((mode & aDIR) != 0)
84 size = 0;
85
86 memset(buf+1,' ',11);
87 if ((p = strchr_m(mask2,'.')) != NULL) {
88 *p = 0;
89 push_ascii(buf+1,mask2,8, 0);
90 push_ascii(buf+9,p+1,3, 0);
91 *p = '.';
92 } else
93 push_ascii(buf+1,mask2,11, 0);
94
95 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
96 SCVAL(buf,21,mode);
97 srv_put_dos_date(buf,22,date);
98 SSVAL(buf,26,size & 0xFFFF);
99 SSVAL(buf,28,(size >> 16)&0xFFFF);
100 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
101 Strange, but verified on W2K3. Needed for OS/2. JRA. */
102 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
103 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
104}
105
106/****************************************************************************
107 Initialise the dir bitmap.
108****************************************************************************/
109
110void init_dptrs(void)
111{
112 static BOOL dptrs_init=False;
113
114 if (dptrs_init)
115 return;
116
117 dptr_bmap = bitmap_allocate(MAX_DIRECTORY_HANDLES);
118
119 if (!dptr_bmap)
120 exit_server("out of memory in init_dptrs");
121
122 dptrs_init = True;
123}
124
125/****************************************************************************
126 Idle a dptr - the directory is closed but the control info is kept.
127****************************************************************************/
128
129static void dptr_idle(struct dptr_struct *dptr)
130{
131 if (dptr->dir_hnd) {
132 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
133 CloseDir(dptr->dir_hnd);
134 dptr->dir_hnd = NULL;
135 }
136}
137
138/****************************************************************************
139 Idle the oldest dptr.
140****************************************************************************/
141
142static void dptr_idleoldest(void)
143{
144 struct dptr_struct *dptr;
145
146 /*
147 * Go to the end of the list.
148 */
149 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
150 ;
151
152 if(!dptr) {
153 DEBUG(0,("No dptrs available to idle ?\n"));
154 return;
155 }
156
157 /*
158 * Idle the oldest pointer.
159 */
160
161 for(; dptr; dptr = dptr->prev) {
162 if (dptr->dir_hnd) {
163 dptr_idle(dptr);
164 return;
165 }
166 }
167}
168
169/****************************************************************************
170 Get the struct dptr_struct for a dir index.
171****************************************************************************/
172
173static struct dptr_struct *dptr_get(int key, BOOL forclose)
174{
175 struct dptr_struct *dptr;
176
177 for(dptr = dirptrs; dptr; dptr = dptr->next) {
178 if(dptr->dnum == key) {
179 if (!forclose && !dptr->dir_hnd) {
180 if (dirhandles_open >= MAX_OPEN_DIRECTORIES)
181 dptr_idleoldest();
182 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
183 if (!(dptr->dir_hnd = OpenDir(dptr->conn, dptr->path, dptr->wcard, dptr->attr))) {
184 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
185 strerror(errno)));
186 return False;
187 }
188 }
189 DLIST_PROMOTE(dirptrs,dptr);
190 return dptr;
191 }
192 }
193 return(NULL);
194}
195
196/****************************************************************************
197 Get the dir path for a dir index.
198****************************************************************************/
199
200char *dptr_path(int key)
201{
202 struct dptr_struct *dptr = dptr_get(key, False);
203 if (dptr)
204 return(dptr->path);
205 return(NULL);
206}
207
208/****************************************************************************
209 Get the dir wcard for a dir index.
210****************************************************************************/
211
212char *dptr_wcard(int key)
213{
214 struct dptr_struct *dptr = dptr_get(key, False);
215 if (dptr)
216 return(dptr->wcard);
217 return(NULL);
218}
219
220/****************************************************************************
221 Get the dir attrib for a dir index.
222****************************************************************************/
223
224uint16 dptr_attr(int key)
225{
226 struct dptr_struct *dptr = dptr_get(key, False);
227 if (dptr)
228 return(dptr->attr);
229 return(0);
230}
231
232/****************************************************************************
233 Close a dptr (internal func).
234****************************************************************************/
235
236static void dptr_close_internal(struct dptr_struct *dptr)
237{
238 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
239
240 DLIST_REMOVE(dirptrs, dptr);
241
242 /*
243 * Free the dnum in the bitmap. Remember the dnum value is always
244 * biased by one with respect to the bitmap.
245 */
246
247 if(bitmap_query( dptr_bmap, dptr->dnum - 1) != True) {
248 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
249 dptr->dnum ));
250 }
251
252 bitmap_clear(dptr_bmap, dptr->dnum - 1);
253
254 if (dptr->dir_hnd) {
255 CloseDir(dptr->dir_hnd);
256 }
257
258 /* Lanman 2 specific code */
259 SAFE_FREE(dptr->wcard);
260 string_set(&dptr->path,"");
261 SAFE_FREE(dptr);
262}
263
264/****************************************************************************
265 Close a dptr given a key.
266****************************************************************************/
267
268void dptr_close(int *key)
269{
270 struct dptr_struct *dptr;
271
272 if(*key == INVALID_DPTR_KEY)
273 return;
274
275 /* OS/2 seems to use -1 to indicate "close all directories" */
276 if (*key == -1) {
277 struct dptr_struct *next;
278 for(dptr = dirptrs; dptr; dptr = next) {
279 next = dptr->next;
280 dptr_close_internal(dptr);
281 }
282 *key = INVALID_DPTR_KEY;
283 return;
284 }
285
286 dptr = dptr_get(*key, True);
287
288 if (!dptr) {
289 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
290 return;
291 }
292
293 dptr_close_internal(dptr);
294
295 *key = INVALID_DPTR_KEY;
296}
297
298/****************************************************************************
299 Close all dptrs for a cnum.
300****************************************************************************/
301
302void dptr_closecnum(connection_struct *conn)
303{
304 struct dptr_struct *dptr, *next;
305 for(dptr = dirptrs; dptr; dptr = next) {
306 next = dptr->next;
307 if (dptr->conn == conn)
308 dptr_close_internal(dptr);
309 }
310}
311
312/****************************************************************************
313 Idle all dptrs for a cnum.
314****************************************************************************/
315
316void dptr_idlecnum(connection_struct *conn)
317{
318 struct dptr_struct *dptr;
319 for(dptr = dirptrs; dptr; dptr = dptr->next) {
320 if (dptr->conn == conn && dptr->dir_hnd)
321 dptr_idle(dptr);
322 }
323}
324
325/****************************************************************************
326 Close a dptr that matches a given path, only if it matches the spid also.
327****************************************************************************/
328
329void dptr_closepath(char *path,uint16 spid)
330{
331 struct dptr_struct *dptr, *next;
332 for(dptr = dirptrs; dptr; dptr = next) {
333 next = dptr->next;
334 if (spid == dptr->spid && strequal(dptr->path,path))
335 dptr_close_internal(dptr);
336 }
337}
338
339/****************************************************************************
340 Try and close the oldest handle not marked for
341 expect close in the hope that the client has
342 finished with that one.
343****************************************************************************/
344
345static void dptr_close_oldest(BOOL old)
346{
347 struct dptr_struct *dptr;
348
349 /*
350 * Go to the end of the list.
351 */
352 for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
353 ;
354
355 if(!dptr) {
356 DEBUG(0,("No old dptrs available to close oldest ?\n"));
357 return;
358 }
359
360 /*
361 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
362 * does not have expect_close set. If 'old' is false, close
363 * one of the new dnum handles.
364 */
365
366 for(; dptr; dptr = dptr->prev) {
367 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
368 (!old && (dptr->dnum > 255))) {
369 dptr_close_internal(dptr);
370 return;
371 }
372 }
373}
374
375/****************************************************************************
376 Create a new dir ptr. If the flag old_handle is true then we must allocate
377 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
378 one byte long. If old_handle is false we allocate from the range
379 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
380 a directory handle is never zero.
381 wcard must not be zero.
382****************************************************************************/
383
384NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
385 const char *wcard, BOOL wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
386{
387 struct dptr_struct *dptr = NULL;
388 struct smb_Dir *dir_hnd;
389 const char *dir2;
390 NTSTATUS status;
391
392 DEBUG(5,("dptr_create dir=%s\n", path));
393
394 if (!wcard) {
395 return NT_STATUS_INVALID_PARAMETER;
396 }
397
398 status = check_name(conn,path);
399 if (!NT_STATUS_IS_OK(status)) {
400 return status;
401 }
402
403 /* use a const pointer from here on */
404 dir2 = path;
405 if (!*dir2)
406 dir2 = ".";
407
408 dir_hnd = OpenDir(conn, dir2, wcard, attr);
409 if (!dir_hnd) {
410 return map_nt_error_from_unix(errno);
411 }
412
413 string_set(&conn->dirpath,dir2);
414
415 if (dirhandles_open >= MAX_OPEN_DIRECTORIES) {
416 dptr_idleoldest();
417 }
418
419 dptr = SMB_MALLOC_P(struct dptr_struct);
420 if(!dptr) {
421 DEBUG(0,("malloc fail in dptr_create.\n"));
422 CloseDir(dir_hnd);
423 return NT_STATUS_NO_MEMORY;
424 }
425
426 ZERO_STRUCTP(dptr);
427
428 if(old_handle) {
429
430 /*
431 * This is an old-style SMBsearch request. Ensure the
432 * value we return will fit in the range 1-255.
433 */
434
435 dptr->dnum = bitmap_find(dptr_bmap, 0);
436
437 if(dptr->dnum == -1 || dptr->dnum > 254) {
438
439 /*
440 * Try and close the oldest handle not marked for
441 * expect close in the hope that the client has
442 * finished with that one.
443 */
444
445 dptr_close_oldest(True);
446
447 /* Now try again... */
448 dptr->dnum = bitmap_find(dptr_bmap, 0);
449 if(dptr->dnum == -1 || dptr->dnum > 254) {
450 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
451 SAFE_FREE(dptr);
452 CloseDir(dir_hnd);
453 return NT_STATUS_TOO_MANY_OPENED_FILES;
454 }
455 }
456 } else {
457
458 /*
459 * This is a new-style trans2 request. Allocate from
460 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
461 */
462
463 dptr->dnum = bitmap_find(dptr_bmap, 255);
464
465 if(dptr->dnum == -1 || dptr->dnum < 255) {
466
467 /*
468 * Try and close the oldest handle close in the hope that
469 * the client has finished with that one. This will only
470 * happen in the case of the Win98 client bug where it leaks
471 * directory handles.
472 */
473
474 dptr_close_oldest(False);
475
476 /* Now try again... */
477 dptr->dnum = bitmap_find(dptr_bmap, 255);
478
479 if(dptr->dnum == -1 || dptr->dnum < 255) {
480 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
481 SAFE_FREE(dptr);
482 CloseDir(dir_hnd);
483 return NT_STATUS_TOO_MANY_OPENED_FILES;
484 }
485 }
486 }
487
488 bitmap_set(dptr_bmap, dptr->dnum);
489
490 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
491
492 string_set(&dptr->path,dir2);
493 dptr->conn = conn;
494 dptr->dir_hnd = dir_hnd;
495 dptr->spid = spid;
496 dptr->expect_close = expect_close;
497 dptr->wcard = SMB_STRDUP(wcard);
498 if (!dptr->wcard) {
499 bitmap_clear(dptr_bmap, dptr->dnum - 1);
500 SAFE_FREE(dptr);
501 CloseDir(dir_hnd);
502 return NT_STATUS_NO_MEMORY;
503 }
504 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
505 dptr->has_wild = True;
506 } else {
507 dptr->has_wild = wcard_has_wild;
508 }
509
510 dptr->attr = attr;
511
512 DLIST_ADD(dirptrs, dptr);
513
514 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
515 dptr->dnum,path,expect_close));
516
517 *dptr_ret = dptr;
518
519 return NT_STATUS_OK;
520}
521
522
523/****************************************************************************
524 Wrapper functions to access the lower level directory handles.
525****************************************************************************/
526
527int dptr_CloseDir(struct dptr_struct *dptr)
528{
529 DLIST_REMOVE(dirptrs, dptr);
530 return CloseDir(dptr->dir_hnd);
531}
532
533void dptr_SeekDir(struct dptr_struct *dptr, long offset)
534{
535 SeekDir(dptr->dir_hnd, offset);
536}
537
538long dptr_TellDir(struct dptr_struct *dptr)
539{
540 return TellDir(dptr->dir_hnd);
541}
542
543BOOL dptr_has_wild(struct dptr_struct *dptr)
544{
545 return dptr->has_wild;
546}
547
548int dptr_dnum(struct dptr_struct *dptr)
549{
550 return dptr->dnum;
551}
552
553/****************************************************************************
554 Return the next visible file name, skipping veto'd and invisible files.
555****************************************************************************/
556
557static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
558{
559 /* Normal search for the next file. */
560 const char *name;
561 while ((name = ReadDirName(dptr->dir_hnd, poffset)) != NULL) {
562 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
563 return name;
564 }
565 }
566 return NULL;
567}
568
569/****************************************************************************
570 Return the next visible file name, skipping veto'd and invisible files.
571****************************************************************************/
572
573const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
574{
575 SET_STAT_INVALID(*pst);
576
577 if (dptr->has_wild) {
578 return dptr_normal_ReadDirName(dptr, poffset, pst);
579 }
580
581 /* If poffset is -1 then we know we returned this name before and we have
582 no wildcards. We're at the end of the directory. */
583 if (*poffset == END_OF_DIRECTORY_OFFSET) {
584 return NULL;
585 }
586
587 if (!dptr->did_stat) {
588 pstring pathreal;
589
590 /* We know the stored wcard contains no wildcard characters. See if we can match
591 with a stat call. If we can't, then set did_stat to true to
592 ensure we only do this once and keep searching. */
593
594 dptr->did_stat = True;
595
596 /* First check if it should be visible. */
597 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
598 /* This only returns False if the file was found, but
599 is explicitly not visible. Set us to end of directory,
600 but return NULL as we know we can't ever find it. */
601 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
602 return NULL;
603 }
604
605 if (VALID_STAT(*pst)) {
606 /* We need to set the underlying dir_hnd offset to -1 also as
607 this function is usually called with the output from TellDir. */
608 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
609 return dptr->wcard;
610 }
611
612 pstrcpy(pathreal,dptr->path);
613 pstrcat(pathreal,"/");
614 pstrcat(pathreal,dptr->wcard);
615
616 if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
617 /* We need to set the underlying dir_hnd offset to -1 also as
618 this function is usually called with the output from TellDir. */
619 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
620 return dptr->wcard;
621 } else {
622 /* If we get any other error than ENOENT or ENOTDIR
623 then the file exists we just can't stat it. */
624 if (errno != ENOENT && errno != ENOTDIR) {
625 /* We need to set the underlying dir_hdn offset to -1 also as
626 this function is usually called with the output from TellDir. */
627 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
628 return dptr->wcard;
629 }
630 }
631
632 /* In case sensitive mode we don't search - we know if it doesn't exist
633 with a stat we will fail. */
634
635 if (dptr->conn->case_sensitive) {
636 /* We need to set the underlying dir_hnd offset to -1 also as
637 this function is usually called with the output from TellDir. */
638 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
639 return NULL;
640 }
641 }
642 return dptr_normal_ReadDirName(dptr, poffset, pst);
643}
644
645/****************************************************************************
646 Search for a file by name, skipping veto'ed and not visible files.
647****************************************************************************/
648
649BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
650{
651 SET_STAT_INVALID(*pst);
652
653 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
654 /* This is a singleton directory and we're already at the end. */
655 *poffset = END_OF_DIRECTORY_OFFSET;
656 return False;
657 }
658
659 return SearchDir(dptr->dir_hnd, name, poffset);
660}
661
662/****************************************************************************
663 Add the name we're returning into the underlying cache.
664****************************************************************************/
665
666void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
667{
668 DirCacheAdd(dptr->dir_hnd, name, offset);
669}
670
671/****************************************************************************
672 Fill the 5 byte server reserved dptr field.
673****************************************************************************/
674
675BOOL dptr_fill(char *buf1,unsigned int key)
676{
677 unsigned char *buf = (unsigned char *)buf1;
678 struct dptr_struct *dptr = dptr_get(key, False);
679 uint32 offset;
680 if (!dptr) {
681 DEBUG(1,("filling null dirptr %d\n",key));
682 return(False);
683 }
684 offset = (uint32)TellDir(dptr->dir_hnd);
685 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
686 (long)dptr->dir_hnd,(int)offset));
687 buf[0] = key;
688 SIVAL(buf,1,offset);
689 return(True);
690}
691
692/****************************************************************************
693 Fetch the dir ptr and seek it given the 5 byte server field.
694****************************************************************************/
695
696struct dptr_struct *dptr_fetch(char *buf,int *num)
697{
698 unsigned int key = *(unsigned char *)buf;
699 struct dptr_struct *dptr = dptr_get(key, False);
700 uint32 offset;
701 long seekoff;
702
703 if (!dptr) {
704 DEBUG(3,("fetched null dirptr %d\n",key));
705 return(NULL);
706 }
707 *num = key;
708 offset = IVAL(buf,1);
709 if (offset == (uint32)-1) {
710 seekoff = END_OF_DIRECTORY_OFFSET;
711 } else {
712 seekoff = (long)offset;
713 }
714 SeekDir(dptr->dir_hnd,seekoff);
715 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
716 key,dptr_path(key),(int)seekoff));
717 return(dptr);
718}
719
720/****************************************************************************
721 Fetch the dir ptr.
722****************************************************************************/
723
724struct dptr_struct *dptr_fetch_lanman2(int dptr_num)
725{
726 struct dptr_struct *dptr = dptr_get(dptr_num, False);
727
728 if (!dptr) {
729 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
730 return(NULL);
731 }
732 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr_path(dptr_num)));
733 return(dptr);
734}
735
736/****************************************************************************
737 Check that a file matches a particular file type.
738****************************************************************************/
739
740BOOL dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
741{
742 uint32 mask;
743
744 /* Check the "may have" search bits. */
745 if (((mode & ~dirtype) & (aHIDDEN | aSYSTEM | aDIR)) != 0)
746 return False;
747
748 /* Check the "must have" bits, which are the may have bits shifted eight */
749 /* If must have bit is set, the file/dir can not be returned in search unless the matching
750 file attribute is set */
751 mask = ((dirtype >> 8) & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM)); /* & 0x37 */
752 if(mask) {
753 if((mask & (mode & (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM))) == mask) /* check if matching attribute present */
754 return True;
755 else
756 return False;
757 }
758
759 return True;
760}
761
762static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask)
763{
764 mangle_map(filename,True,False,conn->params);
765 return mask_match_search(filename,mask,False);
766}
767
768/****************************************************************************
769 Get an 8.3 directory entry.
770****************************************************************************/
771
772BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fname,
773 SMB_OFF_T *size,uint32 *mode,time_t *date,BOOL check_descend)
774{
775 const char *dname;
776 BOOL found = False;
777 SMB_STRUCT_STAT sbuf;
778 pstring path;
779 pstring pathreal;
780 pstring filename;
781 BOOL needslash;
782
783 *path = *pathreal = *filename = 0;
784
785 needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
786
787 if (!conn->dirptr)
788 return(False);
789
790 while (!found) {
791 long curoff = dptr_TellDir(conn->dirptr);
792 dname = dptr_ReadDirName(conn->dirptr, &curoff, &sbuf);
793
794 DEBUG(6,("readdir on dirptr 0x%lx now at offset %ld\n",
795 (long)conn->dirptr,TellDir(conn->dirptr->dir_hnd)));
796
797 if (dname == NULL)
798 return(False);
799
800 pstrcpy(filename,dname);
801
802 /* notice the special *.* handling. This appears to be the only difference
803 between the wildcard handling in this routine and in the trans2 routines.
804 see masktest for a demo
805 */
806 if ((strcmp(mask,"*.*") == 0) ||
807 mask_match_search(filename,mask,False) ||
808 mangle_mask_match(conn,filename,mask)) {
809
810 if (!mangle_is_8_3(filename, False, conn->params))
811 mangle_map(filename,True,False,
812 conn->params);
813
814 pstrcpy(fname,filename);
815 *path = 0;
816 pstrcpy(path,conn->dirpath);
817 if(needslash)
818 pstrcat(path,"/");
819 pstrcpy(pathreal,path);
820 pstrcat(path,fname);
821 pstrcat(pathreal,dname);
822 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn, pathreal, &sbuf)) != 0) {
823 DEBUG(5,("Couldn't stat 1 [%s]. Error = %s\n",path, strerror(errno) ));
824 continue;
825 }
826
827 *mode = dos_mode(conn,pathreal,&sbuf);
828
829 if (!dir_check_ftype(conn,*mode,dirtype)) {
830 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",filename,(unsigned int)*mode,(unsigned int)dirtype));
831 continue;
832 }
833
834 *size = sbuf.st_size;
835 *date = sbuf.st_mtime;
836
837 DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname));
838
839 found = True;
840
841 DirCacheAdd(conn->dirptr->dir_hnd, dname, curoff);
842 }
843 }
844
845 return(found);
846}
847
848/*******************************************************************
849 Check to see if a user can read a file. This is only approximate,
850 it is used as part of the "hide unreadable" option. Don't
851 use it for anything security sensitive.
852********************************************************************/
853
854static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
855{
856 SEC_DESC *psd = NULL;
857 size_t sd_size;
858 files_struct *fsp;
859 NTSTATUS status;
860 uint32 access_granted;
861
862 /*
863 * If user is a member of the Admin group
864 * we never hide files from them.
865 */
866
867 if (conn->admin_user) {
868 return True;
869 }
870
871 /* If we can't stat it does not show it */
872 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
873 DEBUG(10,("user_can_read_file: SMB_VFS_STAT failed for file %s with error %s\n",
874 name, strerror(errno) ));
875 return False;
876 }
877
878 /* Pseudo-open the file (note - no fd's created). */
879
880 if(S_ISDIR(pst->st_mode)) {
881 status = open_directory(conn, name, pst,
882 READ_CONTROL_ACCESS,
883 FILE_SHARE_READ|FILE_SHARE_WRITE,
884 FILE_OPEN,
885 0, /* no create options. */
886 FILE_ATTRIBUTE_DIRECTORY,
887 NULL, &fsp);
888 } else {
889 status = open_file_stat(conn, name, pst, &fsp);
890 }
891
892 if (!NT_STATUS_IS_OK(status)) {
893 return False;
894 }
895
896 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
897 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
898 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
899 close_file(fsp, NORMAL_CLOSE);
900
901 /* No access if SD get failed. */
902 if (!sd_size) {
903 return False;
904 }
905
906 return se_access_check(psd, current_user.nt_user_token, FILE_READ_DATA,
907 &access_granted, &status);
908}
909
910/*******************************************************************
911 Check to see if a user can write a file (and only files, we do not
912 check dirs on this one). This is only approximate,
913 it is used as part of the "hide unwriteable" option. Don't
914 use it for anything security sensitive.
915********************************************************************/
916
917static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
918{
919 SEC_DESC *psd = NULL;
920 size_t sd_size;
921 files_struct *fsp;
922 int info;
923 NTSTATUS status;
924 uint32 access_granted;
925
926 /*
927 * If user is a member of the Admin group
928 * we never hide files from them.
929 */
930
931 if (conn->admin_user) {
932 return True;
933 }
934
935 /* If we can't stat it does not show it */
936 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0)) {
937 return False;
938 }
939
940 /* Pseudo-open the file */
941
942 if(S_ISDIR(pst->st_mode)) {
943 return True;
944 } else {
945 status = open_file_ntcreate(conn, name, pst,
946 FILE_WRITE_ATTRIBUTES,
947 FILE_SHARE_READ|FILE_SHARE_WRITE,
948 FILE_OPEN,
949 0,
950 FILE_ATTRIBUTE_NORMAL,
951 INTERNAL_OPEN_ONLY,
952 &info, &fsp);
953 }
954
955 if (!NT_STATUS_IS_OK(status)) {
956 return False;
957 }
958
959 /* Get NT ACL -allocated in main loop talloc context. No free needed here. */
960 sd_size = SMB_VFS_FGET_NT_ACL(fsp, fsp->fh->fd,
961 (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION), &psd);
962 close_file(fsp, NORMAL_CLOSE);
963
964 /* No access if SD get failed. */
965 if (!sd_size)
966 return False;
967
968 return se_access_check(psd, current_user.nt_user_token, FILE_WRITE_DATA,
969 &access_granted, &status);
970}
971
972/*******************************************************************
973 Is a file a "special" type ?
974********************************************************************/
975
976static BOOL file_is_special(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst)
977{
978 /*
979 * If user is a member of the Admin group
980 * we never hide files from them.
981 */
982
983 if (conn->admin_user)
984 return False;
985
986 /* If we can't stat it does not show it */
987 if (!VALID_STAT(*pst) && (SMB_VFS_STAT(conn, name, pst) != 0))
988 return True;
989
990 if (S_ISREG(pst->st_mode) || S_ISDIR(pst->st_mode) || S_ISLNK(pst->st_mode))
991 return False;
992
993 return True;
994}
995
996/*******************************************************************
997 Should the file be seen by the client ?
998********************************************************************/
999
1000BOOL is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, BOOL use_veto)
1001{
1002 BOOL hide_unreadable = lp_hideunreadable(SNUM(conn));
1003 BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1004 BOOL hide_special = lp_hide_special_files(SNUM(conn));
1005
1006 SET_STAT_INVALID(*pst);
1007
1008 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1009 return True; /* . and .. are always visible. */
1010 }
1011
1012 /* If it's a vetoed file, pretend it doesn't even exist */
1013 if (use_veto && IS_VETO_PATH(conn, name)) {
1014 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1015 return False;
1016 }
1017
1018 if (hide_unreadable || hide_unwriteable || hide_special) {
1019 pstring link_target;
1020 char *entry = NULL;
1021
1022 if (asprintf(&entry, "%s/%s", dir_path, name) == -1) {
1023 return False;
1024 }
1025
1026 /* If it's a dfs symlink, ignore _hide xxxx_ options */
1027 if (lp_host_msdfs() &&
1028 lp_msdfs_root(SNUM(conn)) &&
1029 is_msdfs_link(conn, entry, link_target, NULL)) {
1030 SAFE_FREE(entry);
1031 return True;
1032 }
1033
1034 /* Honour _hide unreadable_ option */
1035 if (hide_unreadable && !user_can_read_file(conn, entry, pst)) {
1036 DEBUG(10,("is_visible_file: file %s is unreadable.\n", entry ));
1037 SAFE_FREE(entry);
1038 return False;
1039 }
1040 /* Honour _hide unwriteable_ option */
1041 if (hide_unwriteable && !user_can_write_file(conn, entry, pst)) {
1042 DEBUG(10,("is_visible_file: file %s is unwritable.\n", entry ));
1043 SAFE_FREE(entry);
1044 return False;
1045 }
1046 /* Honour _hide_special_ option */
1047 if (hide_special && file_is_special(conn, entry, pst)) {
1048 DEBUG(10,("is_visible_file: file %s is special.\n", entry ));
1049 SAFE_FREE(entry);
1050 return False;
1051 }
1052 SAFE_FREE(entry);
1053 }
1054 return True;
1055}
1056
1057/*******************************************************************
1058 Open a directory.
1059********************************************************************/
1060
1061struct smb_Dir *OpenDir(connection_struct *conn, const char *name, const char *mask, uint32 attr)
1062{
1063 struct smb_Dir *dirp = SMB_MALLOC_P(struct smb_Dir);
1064
1065 if (!dirp) {
1066 return NULL;
1067 }
1068 ZERO_STRUCTP(dirp);
1069
1070 dirp->conn = conn;
1071 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1072
1073 dirp->dir_path = SMB_STRDUP(name);
1074 if (!dirp->dir_path) {
1075 goto fail;
1076 }
1077 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1078 if (!dirp->dir) {
1079 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path, strerror(errno) ));
1080 goto fail;
1081 }
1082
1083 if (dirp->name_cache_size) {
1084 dirp->name_cache = SMB_CALLOC_ARRAY(struct name_cache_entry,
1085 dirp->name_cache_size);
1086 if (!dirp->name_cache) {
1087 goto fail;
1088 }
1089 } else {
1090 dirp->name_cache = NULL;
1091 }
1092
1093 dirhandles_open++;
1094 return dirp;
1095
1096 fail:
1097
1098 if (dirp) {
1099 if (dirp->dir) {
1100 SMB_VFS_CLOSEDIR(conn,dirp->dir);
1101 }
1102 SAFE_FREE(dirp->dir_path);
1103 SAFE_FREE(dirp->name_cache);
1104 SAFE_FREE(dirp);
1105 }
1106 return NULL;
1107}
1108
1109
1110/*******************************************************************
1111 Close a directory.
1112********************************************************************/
1113
1114int CloseDir(struct smb_Dir *dirp)
1115{
1116 int i, ret = 0;
1117
1118 if (dirp->dir) {
1119 ret = SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1120 }
1121 SAFE_FREE(dirp->dir_path);
1122 if (dirp->name_cache) {
1123 for (i = 0; i < dirp->name_cache_size; i++) {
1124 SAFE_FREE(dirp->name_cache[i].name);
1125 }
1126 }
1127 SAFE_FREE(dirp->name_cache);
1128 SAFE_FREE(dirp);
1129 dirhandles_open--;
1130 return ret;
1131}
1132
1133/*******************************************************************
1134 Read from a directory. Also return current offset.
1135 Don't check for veto or invisible files.
1136********************************************************************/
1137
1138const char *ReadDirName(struct smb_Dir *dirp, long *poffset)
1139{
1140 const char *n;
1141 connection_struct *conn = dirp->conn;
1142
1143 /* Cheat to allow . and .. to be the first entries returned. */
1144 if (((*poffset == START_OF_DIRECTORY_OFFSET) || (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2)) {
1145 if (dirp->file_number == 0) {
1146 n = ".";
1147 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1148 } else {
1149 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1150 n = "..";
1151 }
1152 dirp->file_number++;
1153 return n;
1154 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1155 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1156 return NULL;
1157 } else {
1158 /* A real offset, seek to it. */
1159 SeekDir(dirp, *poffset);
1160 }
1161
1162 while ((n = vfs_readdirname(conn, dirp->dir))) {
1163 /* Ignore . and .. - we've already returned them. */
1164 if (*n == '.') {
1165 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1166 continue;
1167 }
1168 }
1169 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1170 dirp->file_number++;
1171 return n;
1172 }
1173 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1174 return NULL;
1175}
1176
1177/*******************************************************************
1178 Rewind to the start.
1179********************************************************************/
1180
1181void RewindDir(struct smb_Dir *dirp, long *poffset)
1182{
1183 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1184 dirp->file_number = 0;
1185 dirp->offset = START_OF_DIRECTORY_OFFSET;
1186 *poffset = START_OF_DIRECTORY_OFFSET;
1187}
1188
1189/*******************************************************************
1190 Seek a dir.
1191********************************************************************/
1192
1193void SeekDir(struct smb_Dir *dirp, long offset)
1194{
1195 if (offset != dirp->offset) {
1196 if (offset == START_OF_DIRECTORY_OFFSET) {
1197 RewindDir(dirp, &offset);
1198 /*
1199 * Ok we should really set the file number here
1200 * to 1 to enable ".." to be returned next. Trouble
1201 * is I'm worried about callers using SeekDir(dirp,0)
1202 * as equivalent to RewindDir(). So leave this alone
1203 * for now.
1204 */
1205 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1206 RewindDir(dirp, &offset);
1207 /*
1208 * Set the file number to 2 - we want to get the first
1209 * real file entry (the one we return after "..")
1210 * on the next ReadDir.
1211 */
1212 dirp->file_number = 2;
1213 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1214 ; /* Don't seek in this case. */
1215 } else {
1216 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1217 }
1218 dirp->offset = offset;
1219 }
1220}
1221
1222/*******************************************************************
1223 Tell a dir position.
1224********************************************************************/
1225
1226long TellDir(struct smb_Dir *dirp)
1227{
1228 return(dirp->offset);
1229}
1230
1231/*******************************************************************
1232 Add an entry into the dcache.
1233********************************************************************/
1234
1235void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1236{
1237 struct name_cache_entry *e;
1238
1239 if (!dirp->name_cache_size || !dirp->name_cache) {
1240 return;
1241 }
1242
1243 dirp->name_cache_index = (dirp->name_cache_index+1) %
1244 dirp->name_cache_size;
1245 e = &dirp->name_cache[dirp->name_cache_index];
1246 SAFE_FREE(e->name);
1247 e->name = SMB_STRDUP(name);
1248 e->offset = offset;
1249}
1250
1251/*******************************************************************
1252 Find an entry by name. Leave us at the offset after it.
1253 Don't check for veto or invisible files.
1254********************************************************************/
1255
1256BOOL SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1257{
1258 int i;
1259 const char *entry;
1260 connection_struct *conn = dirp->conn;
1261
1262 /* Search back in the name cache. */
1263 if (dirp->name_cache_size && dirp->name_cache) {
1264 for (i = dirp->name_cache_index; i >= 0; i--) {
1265 struct name_cache_entry *e = &dirp->name_cache[i];
1266 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1267 *poffset = e->offset;
1268 SeekDir(dirp, e->offset);
1269 return True;
1270 }
1271 }
1272 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1273 struct name_cache_entry *e = &dirp->name_cache[i];
1274 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1275 *poffset = e->offset;
1276 SeekDir(dirp, e->offset);
1277 return True;
1278 }
1279 }
1280 }
1281
1282 /* Not found in the name cache. Rewind directory and start from scratch. */
1283 SMB_VFS_REWINDDIR(conn, dirp->dir);
1284 dirp->file_number = 0;
1285 *poffset = START_OF_DIRECTORY_OFFSET;
1286 while ((entry = ReadDirName(dirp, poffset))) {
1287 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1288 return True;
1289 }
1290 }
1291 return False;
1292}
1293
1294/*****************************************************************
1295 Is this directory empty ?
1296*****************************************************************/
1297
1298NTSTATUS can_delete_directory(struct connection_struct *conn,
1299 const char *dirname)
1300{
1301 NTSTATUS status = NT_STATUS_OK;
1302 long dirpos = 0;
1303 const char *dname;
1304 struct smb_Dir *dir_hnd = OpenDir(conn, dirname, NULL, 0);
1305
1306 if (!dir_hnd) {
1307 return map_nt_error_from_unix(errno);
1308 }
1309
1310 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
1311 SMB_STRUCT_STAT st;
1312
1313 /* Quick check for "." and ".." */
1314 if (dname[0] == '.') {
1315 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1316 continue;
1317 }
1318 }
1319
1320 if (!is_visible_file(conn, dirname, dname, &st, True)) {
1321 continue;
1322 }
1323
1324 DEBUG(10,("can_delete_directory: got name %s - can't delete\n", dname ));
1325 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1326 break;
1327 }
1328 CloseDir(dir_hnd);
1329
1330 return status;
1331}
Note: See TracBrowser for help on using the repository browser.