source: trunk/server/source3/smbd/dir.c

Last change on this file was 920, checked in by Silvan Scherrer, 9 years ago

Samba Server: apply latest security patches to trunk

File size: 43.8 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Directory handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
6
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 3 of the License, or
10 (at your option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "system/filesys.h"
23#include "smbd/smbd.h"
24#include "smbd/globals.h"
25#include "libcli/security/security.h"
26#include "lib/util/bitmap.h"
27
28/*
29 This module implements directory related functions for Samba.
30*/
31
32/* "Special" directory offsets. */
33#define END_OF_DIRECTORY_OFFSET ((long)-1)
34#define START_OF_DIRECTORY_OFFSET ((long)0)
35#define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
36
37/* Make directory handle internals available. */
38
39struct name_cache_entry {
40 char *name;
41 long offset;
42};
43
44struct smb_Dir {
45 connection_struct *conn;
46 SMB_STRUCT_DIR *dir;
47 long offset;
48 char *dir_path;
49 size_t name_cache_size;
50 struct name_cache_entry *name_cache;
51 unsigned int name_cache_index;
52 unsigned int file_number;
53 files_struct *fsp; /* Back pointer to containing fsp, only
54 set from OpenDir_fsp(). */
55};
56
57struct dptr_struct {
58 struct dptr_struct *next, *prev;
59 int dnum;
60 uint16 spid;
61 struct connection_struct *conn;
62 struct smb_Dir *dir_hnd;
63 bool expect_close;
64 char *wcard;
65 uint32 attr;
66 char *path;
67 bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
68 bool did_stat; /* Optimisation for non-wcard searches. */
69};
70
71static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
72 files_struct *fsp,
73 const char *mask,
74 uint32 attr);
75
76#define INVALID_DPTR_KEY (-3)
77
78/****************************************************************************
79 Make a dir struct.
80****************************************************************************/
81
82bool make_dir_struct(TALLOC_CTX *ctx,
83 char *buf,
84 const char *mask,
85 const char *fname,
86 SMB_OFF_T size,
87 uint32 mode,
88 time_t date,
89 bool uc)
90{
91 char *p;
92 char *mask2 = talloc_strdup(ctx, mask);
93
94 if (!mask2) {
95 return False;
96 }
97
98 if ((mode & FILE_ATTRIBUTE_DIRECTORY) != 0) {
99 size = 0;
100 }
101
102 memset(buf+1,' ',11);
103 if ((p = strchr_m(mask2,'.')) != NULL) {
104 *p = 0;
105 push_ascii(buf+1,mask2,8, 0);
106 push_ascii(buf+9,p+1,3, 0);
107 *p = '.';
108 } else {
109 push_ascii(buf+1,mask2,11, 0);
110 }
111
112 memset(buf+21,'\0',DIR_STRUCT_SIZE-21);
113 SCVAL(buf,21,mode);
114 srv_put_dos_date(buf,22,date);
115 SSVAL(buf,26,size & 0xFFFF);
116 SSVAL(buf,28,(size >> 16)&0xFFFF);
117 /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
118 Strange, but verified on W2K3. Needed for OS/2. JRA. */
119 push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0);
120 DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname));
121 return True;
122}
123
124/****************************************************************************
125 Initialise the dir bitmap.
126****************************************************************************/
127
128bool init_dptrs(struct smbd_server_connection *sconn)
129{
130 if (sconn->searches.dptr_bmap) {
131 return true;
132 }
133
134 sconn->searches.dptr_bmap = bitmap_talloc(
135 sconn, MAX_DIRECTORY_HANDLES);
136
137 if (sconn->searches.dptr_bmap == NULL) {
138 return false;
139 }
140
141 return true;
142}
143
144/****************************************************************************
145 Idle a dptr - the directory is closed but the control info is kept.
146****************************************************************************/
147
148static void dptr_idle(struct dptr_struct *dptr)
149{
150 if (dptr->dir_hnd) {
151 DEBUG(4,("Idling dptr dnum %d\n",dptr->dnum));
152 TALLOC_FREE(dptr->dir_hnd);
153 }
154}
155
156/****************************************************************************
157 Idle the oldest dptr.
158****************************************************************************/
159
160static void dptr_idleoldest(struct smbd_server_connection *sconn)
161{
162 struct dptr_struct *dptr;
163
164 /*
165 * Go to the end of the list.
166 */
167 dptr = DLIST_TAIL(sconn->searches.dirptrs);
168
169 if(!dptr) {
170 DEBUG(0,("No dptrs available to idle ?\n"));
171 return;
172 }
173
174 /*
175 * Idle the oldest pointer.
176 */
177
178 for(; dptr; dptr = DLIST_PREV(dptr)) {
179 if (dptr->dir_hnd) {
180 dptr_idle(dptr);
181 return;
182 }
183 }
184}
185
186/****************************************************************************
187 Get the struct dptr_struct for a dir index.
188****************************************************************************/
189
190static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
191 int key, bool forclose)
192{
193 struct dptr_struct *dptr;
194
195 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
196 if(dptr->dnum == key) {
197 if (!forclose && !dptr->dir_hnd) {
198 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES)
199 dptr_idleoldest(sconn);
200 DEBUG(4,("dptr_get: Reopening dptr key %d\n",key));
201 if (!(dptr->dir_hnd = OpenDir(
202 NULL, dptr->conn, dptr->path,
203 dptr->wcard, dptr->attr))) {
204 DEBUG(4,("dptr_get: Failed to open %s (%s)\n",dptr->path,
205 strerror(errno)));
206 return False;
207 }
208 }
209 DLIST_PROMOTE(sconn->searches.dirptrs,dptr);
210 return dptr;
211 }
212 }
213 return(NULL);
214}
215
216/****************************************************************************
217 Get the dir path for a dir index.
218****************************************************************************/
219
220char *dptr_path(struct smbd_server_connection *sconn, int key)
221{
222 struct dptr_struct *dptr = dptr_get(sconn, key, false);
223 if (dptr)
224 return(dptr->path);
225 return(NULL);
226}
227
228/****************************************************************************
229 Get the dir wcard for a dir index.
230****************************************************************************/
231
232char *dptr_wcard(struct smbd_server_connection *sconn, int key)
233{
234 struct dptr_struct *dptr = dptr_get(sconn, key, false);
235 if (dptr)
236 return(dptr->wcard);
237 return(NULL);
238}
239
240/****************************************************************************
241 Get the dir attrib for a dir index.
242****************************************************************************/
243
244uint16 dptr_attr(struct smbd_server_connection *sconn, int key)
245{
246 struct dptr_struct *dptr = dptr_get(sconn, key, false);
247 if (dptr)
248 return(dptr->attr);
249 return(0);
250}
251
252/****************************************************************************
253 Close a dptr (internal func).
254****************************************************************************/
255
256static void dptr_close_internal(struct dptr_struct *dptr)
257{
258 struct smbd_server_connection *sconn = dptr->conn->sconn;
259
260 DEBUG(4,("closing dptr key %d\n",dptr->dnum));
261
262 if (sconn == NULL) {
263 goto done;
264 }
265
266 if (sconn->using_smb2) {
267 goto done;
268 }
269
270 DLIST_REMOVE(sconn->searches.dirptrs, dptr);
271
272 /*
273 * Free the dnum in the bitmap. Remember the dnum value is always
274 * biased by one with respect to the bitmap.
275 */
276
277 if (!bitmap_query(sconn->searches.dptr_bmap, dptr->dnum - 1)) {
278 DEBUG(0,("dptr_close_internal : Error - closing dnum = %d and bitmap not set !\n",
279 dptr->dnum ));
280 }
281
282 bitmap_clear(sconn->searches.dptr_bmap, dptr->dnum - 1);
283
284done:
285 TALLOC_FREE(dptr->dir_hnd);
286
287 /* Lanman 2 specific code */
288 SAFE_FREE(dptr->wcard);
289 SAFE_FREE(dptr->path);
290 SAFE_FREE(dptr);
291}
292
293/****************************************************************************
294 Close a dptr given a key.
295****************************************************************************/
296
297void dptr_close(struct smbd_server_connection *sconn, int *key)
298{
299 struct dptr_struct *dptr;
300
301 if(*key == INVALID_DPTR_KEY)
302 return;
303
304 /* OS/2 seems to use -1 to indicate "close all directories" */
305 if (*key == -1) {
306 struct dptr_struct *next;
307 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
308 next = dptr->next;
309 dptr_close_internal(dptr);
310 }
311 *key = INVALID_DPTR_KEY;
312 return;
313 }
314
315 dptr = dptr_get(sconn, *key, true);
316
317 if (!dptr) {
318 DEBUG(0,("Invalid key %d given to dptr_close\n", *key));
319 return;
320 }
321
322 dptr_close_internal(dptr);
323
324 *key = INVALID_DPTR_KEY;
325}
326
327/****************************************************************************
328 Close all dptrs for a cnum.
329****************************************************************************/
330
331void dptr_closecnum(connection_struct *conn)
332{
333 struct dptr_struct *dptr, *next;
334 struct smbd_server_connection *sconn = conn->sconn;
335
336 if (sconn == NULL) {
337 return;
338 }
339
340 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
341 next = dptr->next;
342 if (dptr->conn == conn) {
343 dptr_close_internal(dptr);
344 }
345 }
346}
347
348/****************************************************************************
349 Idle all dptrs for a cnum.
350****************************************************************************/
351
352void dptr_idlecnum(connection_struct *conn)
353{
354 struct dptr_struct *dptr;
355 struct smbd_server_connection *sconn = conn->sconn;
356
357 if (sconn == NULL) {
358 return;
359 }
360
361 for(dptr = sconn->searches.dirptrs; dptr; dptr = dptr->next) {
362 if (dptr->conn == conn && dptr->dir_hnd) {
363 dptr_idle(dptr);
364 }
365 }
366}
367
368/****************************************************************************
369 Close a dptr that matches a given path, only if it matches the spid also.
370****************************************************************************/
371
372void dptr_closepath(struct smbd_server_connection *sconn,
373 char *path,uint16 spid)
374{
375 struct dptr_struct *dptr, *next;
376 for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
377 next = dptr->next;
378 if (spid == dptr->spid && strequal(dptr->path,path))
379 dptr_close_internal(dptr);
380 }
381}
382
383/****************************************************************************
384 Try and close the oldest handle not marked for
385 expect close in the hope that the client has
386 finished with that one.
387****************************************************************************/
388
389static void dptr_close_oldest(struct smbd_server_connection *sconn,
390 bool old)
391{
392 struct dptr_struct *dptr;
393
394 /*
395 * Go to the end of the list.
396 */
397 for(dptr = sconn->searches.dirptrs; dptr && dptr->next; dptr = dptr->next)
398 ;
399
400 if(!dptr) {
401 DEBUG(0,("No old dptrs available to close oldest ?\n"));
402 return;
403 }
404
405 /*
406 * If 'old' is true, close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
407 * does not have expect_close set. If 'old' is false, close
408 * one of the new dnum handles.
409 */
410
411 for(; dptr; dptr = DLIST_PREV(dptr)) {
412 if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
413 (!old && (dptr->dnum > 255))) {
414 dptr_close_internal(dptr);
415 return;
416 }
417 }
418}
419
420/****************************************************************************
421 Create a new dir ptr. If the flag old_handle is true then we must allocate
422 from the bitmap range 0 - 255 as old SMBsearch directory handles are only
423 one byte long. If old_handle is false we allocate from the range
424 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
425 a directory handle is never zero.
426 wcard must not be zero.
427****************************************************************************/
428
429NTSTATUS dptr_create(connection_struct *conn, files_struct *fsp,
430 const char *path, bool old_handle, bool expect_close,uint16 spid,
431 const char *wcard, bool wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
432{
433 struct smbd_server_connection *sconn = conn->sconn;
434 struct dptr_struct *dptr = NULL;
435 struct smb_Dir *dir_hnd;
436 NTSTATUS status;
437
438 if (fsp && fsp->is_directory && fsp->fh->fd != -1) {
439 path = fsp->fsp_name->base_name;
440 }
441
442 DEBUG(5,("dptr_create dir=%s\n", path));
443
444 if (sconn == NULL) {
445 DEBUG(0,("dptr_create: called with fake connection_struct\n"));
446 return NT_STATUS_INTERNAL_ERROR;
447 }
448
449 if (!wcard) {
450 return NT_STATUS_INVALID_PARAMETER;
451 }
452
453 if (fsp) {
454 dir_hnd = OpenDir_fsp(NULL, conn, fsp, wcard, attr);
455 } else {
456 status = check_name(conn,path);
457 if (!NT_STATUS_IS_OK(status)) {
458 return status;
459 }
460 dir_hnd = OpenDir(NULL, conn, path, wcard, attr);
461 }
462
463 if (!dir_hnd) {
464 return map_nt_error_from_unix(errno);
465 }
466
467 if (sconn->searches.dirhandles_open >= MAX_OPEN_DIRECTORIES) {
468 dptr_idleoldest(sconn);
469 }
470
471 dptr = SMB_MALLOC_P(struct dptr_struct);
472 if(!dptr) {
473 DEBUG(0,("malloc fail in dptr_create.\n"));
474 TALLOC_FREE(dir_hnd);
475 return NT_STATUS_NO_MEMORY;
476 }
477
478 ZERO_STRUCTP(dptr);
479
480 dptr->path = SMB_STRDUP(path);
481 if (!dptr->path) {
482 SAFE_FREE(dptr);
483 TALLOC_FREE(dir_hnd);
484 return NT_STATUS_NO_MEMORY;
485 }
486 dptr->conn = conn;
487 dptr->dir_hnd = dir_hnd;
488 dptr->spid = spid;
489 dptr->expect_close = expect_close;
490 dptr->wcard = SMB_STRDUP(wcard);
491 if (!dptr->wcard) {
492 SAFE_FREE(dptr->path);
493 SAFE_FREE(dptr);
494 TALLOC_FREE(dir_hnd);
495 return NT_STATUS_NO_MEMORY;
496 }
497 if (lp_posix_pathnames() || (wcard[0] == '.' && wcard[1] == 0)) {
498 dptr->has_wild = True;
499 } else {
500 dptr->has_wild = wcard_has_wild;
501 }
502
503 dptr->attr = attr;
504
505 if (sconn->using_smb2) {
506 goto done;
507 }
508
509 if(old_handle) {
510
511 /*
512 * This is an old-style SMBsearch request. Ensure the
513 * value we return will fit in the range 1-255.
514 */
515
516 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
517
518 if(dptr->dnum == -1 || dptr->dnum > 254) {
519
520 /*
521 * Try and close the oldest handle not marked for
522 * expect close in the hope that the client has
523 * finished with that one.
524 */
525
526 dptr_close_oldest(sconn, true);
527
528 /* Now try again... */
529 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
530 if(dptr->dnum == -1 || dptr->dnum > 254) {
531 DEBUG(0,("dptr_create: returned %d: Error - all old dirptrs in use ?\n", dptr->dnum));
532 SAFE_FREE(dptr->path);
533 SAFE_FREE(dptr->wcard);
534 SAFE_FREE(dptr);
535 TALLOC_FREE(dir_hnd);
536 return NT_STATUS_TOO_MANY_OPENED_FILES;
537 }
538 }
539 } else {
540
541 /*
542 * This is a new-style trans2 request. Allocate from
543 * a range that will return 256 - MAX_DIRECTORY_HANDLES.
544 */
545
546 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
547
548 if(dptr->dnum == -1 || dptr->dnum < 255) {
549
550 /*
551 * Try and close the oldest handle close in the hope that
552 * the client has finished with that one. This will only
553 * happen in the case of the Win98 client bug where it leaks
554 * directory handles.
555 */
556
557 dptr_close_oldest(sconn, false);
558
559 /* Now try again... */
560 dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
561
562 if(dptr->dnum == -1 || dptr->dnum < 255) {
563 DEBUG(0,("dptr_create: returned %d: Error - all new dirptrs in use ?\n", dptr->dnum));
564 SAFE_FREE(dptr->path);
565 SAFE_FREE(dptr->wcard);
566 SAFE_FREE(dptr);
567 TALLOC_FREE(dir_hnd);
568 return NT_STATUS_TOO_MANY_OPENED_FILES;
569 }
570 }
571 }
572
573 bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
574
575 dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
576
577 DLIST_ADD(sconn->searches.dirptrs, dptr);
578
579done:
580 DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
581 dptr->dnum,path,expect_close));
582
583 *dptr_ret = dptr;
584
585 return NT_STATUS_OK;
586}
587
588
589/****************************************************************************
590 Wrapper functions to access the lower level directory handles.
591****************************************************************************/
592
593void dptr_CloseDir(files_struct *fsp)
594{
595 if (fsp->dptr) {
596 /*
597 * The destructor for the struct smb_Dir
598 * (fsp->dptr->dir_hnd) now handles
599 * all resource deallocation.
600 */
601 dptr_close_internal(fsp->dptr);
602 fsp->dptr = NULL;
603 }
604}
605
606void dptr_SeekDir(struct dptr_struct *dptr, long offset)
607{
608 SeekDir(dptr->dir_hnd, offset);
609}
610
611long dptr_TellDir(struct dptr_struct *dptr)
612{
613 return TellDir(dptr->dir_hnd);
614}
615
616bool dptr_has_wild(struct dptr_struct *dptr)
617{
618 return dptr->has_wild;
619}
620
621int dptr_dnum(struct dptr_struct *dptr)
622{
623 return dptr->dnum;
624}
625
626/****************************************************************************
627 Return the next visible file name, skipping veto'd and invisible files.
628****************************************************************************/
629
630static const char *dptr_normal_ReadDirName(struct dptr_struct *dptr,
631 long *poffset, SMB_STRUCT_STAT *pst,
632 char **ptalloced)
633{
634 /* Normal search for the next file. */
635 const char *name;
636 char *talloced = NULL;
637
638 while ((name = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced))
639 != NULL) {
640 if (is_visible_file(dptr->conn, dptr->path, name, pst, True)) {
641 *ptalloced = talloced;
642 return name;
643 }
644 TALLOC_FREE(talloced);
645 }
646 return NULL;
647}
648
649/****************************************************************************
650 Return the next visible file name, skipping veto'd and invisible files.
651****************************************************************************/
652
653char *dptr_ReadDirName(TALLOC_CTX *ctx,
654 struct dptr_struct *dptr,
655 long *poffset,
656 SMB_STRUCT_STAT *pst)
657{
658 struct smb_filename smb_fname_base;
659 char *name = NULL;
660 const char *name_temp = NULL;
661 char *talloced = NULL;
662 char *pathreal = NULL;
663 char *found_name = NULL;
664 int ret;
665
666 SET_STAT_INVALID(*pst);
667
668 if (dptr->has_wild || dptr->did_stat) {
669 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst,
670 &talloced);
671 if (name_temp == NULL) {
672 return NULL;
673 }
674 if (talloced != NULL) {
675 return talloc_move(ctx, &talloced);
676 }
677 return talloc_strdup(ctx, name_temp);
678 }
679
680 /* If poffset is -1 then we know we returned this name before and we
681 * have no wildcards. We're at the end of the directory. */
682 if (*poffset == END_OF_DIRECTORY_OFFSET) {
683 return NULL;
684 }
685
686 /* We know the stored wcard contains no wildcard characters.
687 * See if we can match with a stat call. If we can't, then set
688 * did_stat to true to ensure we only do this once and keep
689 * searching. */
690
691 dptr->did_stat = true;
692
693 /* First check if it should be visible. */
694 if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard,
695 pst, true))
696 {
697 /* This only returns false if the file was found, but
698 is explicitly not visible. Set us to end of
699 directory, but return NULL as we know we can't ever
700 find it. */
701 goto ret;
702 }
703
704 if (VALID_STAT(*pst)) {
705 name = talloc_strdup(ctx, dptr->wcard);
706 goto ret;
707 }
708
709 pathreal = talloc_asprintf(ctx,
710 "%s/%s",
711 dptr->path,
712 dptr->wcard);
713 if (!pathreal)
714 return NULL;
715
716 /* Create an smb_filename with stream_name == NULL. */
717 ZERO_STRUCT(smb_fname_base);
718 smb_fname_base.base_name = pathreal;
719
720 if (SMB_VFS_STAT(dptr->conn, &smb_fname_base) == 0) {
721 *pst = smb_fname_base.st;
722 name = talloc_strdup(ctx, dptr->wcard);
723 goto clean;
724 } else {
725 /* If we get any other error than ENOENT or ENOTDIR
726 then the file exists we just can't stat it. */
727 if (errno != ENOENT && errno != ENOTDIR) {
728 name = talloc_strdup(ctx, dptr->wcard);
729 goto clean;
730 }
731 }
732
733 /* Stat failed. We know this is authoratiative if we are
734 * providing case sensitive semantics or the underlying
735 * filesystem is case sensitive.
736 */
737 if (dptr->conn->case_sensitive ||
738 !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
739 {
740 goto clean;
741 }
742
743 /*
744 * Try case-insensitive stat if the fs has the ability. This avoids
745 * scanning the whole directory.
746 */
747 ret = SMB_VFS_GET_REAL_FILENAME(dptr->conn, dptr->path, dptr->wcard,
748 ctx, &found_name);
749 if (ret == 0) {
750 name = found_name;
751 goto clean;
752 } else if (errno == ENOENT) {
753 /* The case-insensitive lookup was authoritative. */
754 goto clean;
755 }
756
757 TALLOC_FREE(pathreal);
758
759 name_temp = dptr_normal_ReadDirName(dptr, poffset, pst, &talloced);
760 if (name_temp == NULL) {
761 return NULL;
762 }
763 if (talloced != NULL) {
764 return talloc_move(ctx, &talloced);
765 }
766 return talloc_strdup(ctx, name_temp);
767
768clean:
769 TALLOC_FREE(pathreal);
770ret:
771 /* We need to set the underlying dir_hnd offset to -1
772 * also as this function is usually called with the
773 * output from TellDir. */
774 dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
775 return name;
776}
777
778/****************************************************************************
779 Search for a file by name, skipping veto'ed and not visible files.
780****************************************************************************/
781
782bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
783{
784 SET_STAT_INVALID(*pst);
785
786 if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
787 /* This is a singleton directory and we're already at the end. */
788 *poffset = END_OF_DIRECTORY_OFFSET;
789 return False;
790 }
791
792 return SearchDir(dptr->dir_hnd, name, poffset);
793}
794
795/****************************************************************************
796 Add the name we're returning into the underlying cache.
797****************************************************************************/
798
799void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset)
800{
801 DirCacheAdd(dptr->dir_hnd, name, offset);
802}
803
804/****************************************************************************
805 Initialize variables & state data at the beginning of all search SMB requests.
806****************************************************************************/
807void dptr_init_search_op(struct dptr_struct *dptr)
808{
809 SMB_VFS_INIT_SEARCH_OP(dptr->conn, dptr->dir_hnd->dir);
810}
811
812/****************************************************************************
813 Fill the 5 byte server reserved dptr field.
814****************************************************************************/
815
816bool dptr_fill(struct smbd_server_connection *sconn,
817 char *buf1,unsigned int key)
818{
819 unsigned char *buf = (unsigned char *)buf1;
820 struct dptr_struct *dptr = dptr_get(sconn, key, false);
821 uint32 offset;
822 if (!dptr) {
823 DEBUG(1,("filling null dirptr %d\n",key));
824 return(False);
825 }
826 offset = (uint32)TellDir(dptr->dir_hnd);
827 DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
828 (long)dptr->dir_hnd,(int)offset));
829 buf[0] = key;
830 SIVAL(buf,1,offset);
831 return(True);
832}
833
834/****************************************************************************
835 Fetch the dir ptr and seek it given the 5 byte server field.
836****************************************************************************/
837
838struct dptr_struct *dptr_fetch(struct smbd_server_connection *sconn,
839 char *buf, int *num)
840{
841 unsigned int key = *(unsigned char *)buf;
842 struct dptr_struct *dptr = dptr_get(sconn, key, false);
843 uint32 offset;
844 long seekoff;
845
846 if (!dptr) {
847 DEBUG(3,("fetched null dirptr %d\n",key));
848 return(NULL);
849 }
850 *num = key;
851 offset = IVAL(buf,1);
852 if (offset == (uint32)-1) {
853 seekoff = END_OF_DIRECTORY_OFFSET;
854 } else {
855 seekoff = (long)offset;
856 }
857 SeekDir(dptr->dir_hnd,seekoff);
858 DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
859 key, dptr->path, (int)seekoff));
860 return(dptr);
861}
862
863/****************************************************************************
864 Fetch the dir ptr.
865****************************************************************************/
866
867struct dptr_struct *dptr_fetch_lanman2(struct smbd_server_connection *sconn,
868 int dptr_num)
869{
870 struct dptr_struct *dptr = dptr_get(sconn, dptr_num, false);
871
872 if (!dptr) {
873 DEBUG(3,("fetched null dirptr %d\n",dptr_num));
874 return(NULL);
875 }
876 DEBUG(3,("fetching dirptr %d for path %s\n",dptr_num,dptr->path));
877 return(dptr);
878}
879
880/****************************************************************************
881 Check that a file matches a particular file type.
882****************************************************************************/
883
884bool dir_check_ftype(connection_struct *conn, uint32 mode, uint32 dirtype)
885{
886 uint32 mask;
887
888 /* Check the "may have" search bits. */
889 if (((mode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) != 0)
890 return False;
891
892 /* Check the "must have" bits, which are the may have bits shifted eight */
893 /* If must have bit is set, the file/dir can not be returned in search unless the matching
894 file attribute is set */
895 mask = ((dirtype >> 8) & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)); /* & 0x37 */
896 if(mask) {
897 if((mask & (mode & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))) == mask) /* check if matching attribute present */
898 return True;
899 else
900 return False;
901 }
902
903 return True;
904}
905
906static bool mangle_mask_match(connection_struct *conn,
907 const char *filename,
908 const char *mask)
909{
910 char mname[13];
911
912 if (!name_to_8_3(filename,mname,False,conn->params)) {
913 return False;
914 }
915 return mask_match_search(mname,mask,False);
916}
917
918bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
919 struct dptr_struct *dirptr,
920 const char *mask,
921 uint32_t dirtype,
922 bool dont_descend,
923 bool ask_sharemode,
924 bool (*match_fn)(TALLOC_CTX *ctx,
925 void *private_data,
926 const char *dname,
927 const char *mask,
928 char **_fname),
929 bool (*mode_fn)(TALLOC_CTX *ctx,
930 void *private_data,
931 struct smb_filename *smb_fname,
932 uint32_t *_mode),
933 void *private_data,
934 char **_fname,
935 struct smb_filename **_smb_fname,
936 uint32_t *_mode,
937 long *_prev_offset)
938{
939 connection_struct *conn = dirptr->conn;
940 size_t slashlen;
941 size_t pathlen;
942
943 *_smb_fname = NULL;
944 *_mode = 0;
945
946 pathlen = strlen(dirptr->path);
947 slashlen = ( dirptr->path[pathlen-1] != '/') ? 1 : 0;
948
949 while (true) {
950 long cur_offset;
951 long prev_offset;
952 SMB_STRUCT_STAT sbuf;
953 char *dname = NULL;
954 bool isdots;
955 char *fname = NULL;
956 char *pathreal = NULL;
957 struct smb_filename smb_fname;
958 uint32_t mode = 0;
959 bool ok;
960 NTSTATUS status;
961
962 cur_offset = dptr_TellDir(dirptr);
963 prev_offset = cur_offset;
964 dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
965
966 DEBUG(6,("smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld\n",
967 (long)dirptr, cur_offset));
968
969 if (dname == NULL) {
970 return false;
971 }
972
973 isdots = (ISDOT(dname) || ISDOTDOT(dname));
974 if (dont_descend && !isdots) {
975 TALLOC_FREE(dname);
976 continue;
977 }
978
979 /*
980 * fname may get mangled, dname is never mangled.
981 * Whenever we're accessing the filesystem we use
982 * pathreal which is composed from dname.
983 */
984
985 ok = match_fn(ctx, private_data, dname, mask, &fname);
986 if (!ok) {
987 TALLOC_FREE(dname);
988 continue;
989 }
990
991 /*
992 * This used to be
993 * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
994 * needslash?"/":"", dname);
995 * but this was measurably slower than doing the memcpy.
996 */
997
998 pathreal = talloc_array(
999 ctx, char,
1000 pathlen + slashlen + talloc_get_size(dname));
1001 if (!pathreal) {
1002 TALLOC_FREE(dname);
1003 TALLOC_FREE(fname);
1004 return false;
1005 }
1006
1007 memcpy(pathreal, dirptr->path, pathlen);
1008 pathreal[pathlen] = '/';
1009 memcpy(pathreal + slashlen + pathlen, dname,
1010 talloc_get_size(dname));
1011
1012 /* Create smb_fname with NULL stream_name. */
1013 ZERO_STRUCT(smb_fname);
1014 smb_fname.base_name = pathreal;
1015 smb_fname.st = sbuf;
1016
1017 ok = mode_fn(ctx, private_data, &smb_fname, &mode);
1018 if (!ok) {
1019 TALLOC_FREE(dname);
1020 TALLOC_FREE(fname);
1021 TALLOC_FREE(pathreal);
1022 continue;
1023 }
1024
1025 if (!dir_check_ftype(conn, mode, dirtype)) {
1026 DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1027 fname, (unsigned int)mode, (unsigned int)dirtype));
1028 TALLOC_FREE(dname);
1029 TALLOC_FREE(fname);
1030 TALLOC_FREE(pathreal);
1031 continue;
1032 }
1033
1034 if (ask_sharemode) {
1035 struct timespec write_time_ts;
1036 struct file_id fileid;
1037
1038 fileid = vfs_file_id_from_sbuf(conn,
1039 &smb_fname.st);
1040 get_file_infos(fileid, 0, NULL, &write_time_ts);
1041 if (!null_timespec(write_time_ts)) {
1042 update_stat_ex_mtime(&smb_fname.st,
1043 write_time_ts);
1044 }
1045 }
1046
1047 DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1048 "fname=%s (%s)\n",
1049 mask, smb_fname_str_dbg(&smb_fname),
1050 dname, fname));
1051
1052 DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1053
1054 TALLOC_FREE(dname);
1055
1056 status = copy_smb_filename(ctx, &smb_fname, _smb_fname);
1057 TALLOC_FREE(pathreal);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 return false;
1060 }
1061 *_fname = fname;
1062 *_mode = mode;
1063 *_prev_offset = prev_offset;
1064
1065 return true;
1066 }
1067
1068 return false;
1069}
1070
1071/****************************************************************************
1072 Get an 8.3 directory entry.
1073****************************************************************************/
1074
1075static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1076 void *private_data,
1077 const char *dname,
1078 const char *mask,
1079 char **_fname)
1080{
1081 connection_struct *conn = (connection_struct *)private_data;
1082
1083 if ((strcmp(mask,"*.*") == 0) ||
1084 mask_match_search(dname, mask, false) ||
1085 mangle_mask_match(conn, dname, mask)) {
1086 char mname[13];
1087 const char *fname;
1088
1089 if (!mangle_is_8_3(dname, false, conn->params)) {
1090 bool ok = name_to_8_3(dname, mname, false,
1091 conn->params);
1092 if (!ok) {
1093 return false;
1094 }
1095 fname = mname;
1096 } else {
1097 fname = dname;
1098 }
1099
1100 *_fname = talloc_strdup(ctx, fname);
1101 if (*_fname == NULL) {
1102 return false;
1103 }
1104
1105 return true;
1106 }
1107
1108 return false;
1109}
1110
1111static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1112 void *private_data,
1113 struct smb_filename *smb_fname,
1114 uint32_t *_mode)
1115{
1116 connection_struct *conn = (connection_struct *)private_data;
1117
1118 if (!VALID_STAT(smb_fname->st)) {
1119 if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1120 DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1121 "Couldn't stat [%s]. Error "
1122 "= %s\n",
1123 smb_fname_str_dbg(smb_fname),
1124 strerror(errno)));
1125 return false;
1126 }
1127 }
1128
1129 *_mode = dos_mode(conn, smb_fname);
1130 return true;
1131}
1132
1133bool get_dir_entry(TALLOC_CTX *ctx,
1134 struct dptr_struct *dirptr,
1135 const char *mask,
1136 uint32_t dirtype,
1137 char **_fname,
1138 SMB_OFF_T *_size,
1139 uint32_t *_mode,
1140 struct timespec *_date,
1141 bool check_descend,
1142 bool ask_sharemode)
1143{
1144 connection_struct *conn = dirptr->conn;
1145 char *fname = NULL;
1146 struct smb_filename *smb_fname = NULL;
1147 uint32_t mode = 0;
1148 long prev_offset;
1149 bool ok;
1150
1151 ok = smbd_dirptr_get_entry(ctx,
1152 dirptr,
1153 mask,
1154 dirtype,
1155 check_descend,
1156 ask_sharemode,
1157 smbd_dirptr_8_3_match_fn,
1158 smbd_dirptr_8_3_mode_fn,
1159 conn,
1160 &fname,
1161 &smb_fname,
1162 &mode,
1163 &prev_offset);
1164 if (!ok) {
1165 return false;
1166 }
1167
1168 *_fname = talloc_move(ctx, &fname);
1169 *_size = smb_fname->st.st_ex_size;
1170 *_mode = mode;
1171 *_date = smb_fname->st.st_ex_mtime;
1172 TALLOC_FREE(smb_fname);
1173 return true;
1174}
1175
1176/*******************************************************************
1177 Check to see if a user can read a file. This is only approximate,
1178 it is used as part of the "hide unreadable" option. Don't
1179 use it for anything security sensitive.
1180********************************************************************/
1181
1182static bool user_can_read_file(connection_struct *conn,
1183 struct smb_filename *smb_fname)
1184{
1185 /*
1186 * Never hide files from the root user.
1187 * We use (uid_t)0 here not sec_initial_uid()
1188 * as make test uses a single user context.
1189 */
1190
1191 if (get_current_uid(conn) == (uid_t)0) {
1192 return True;
1193 }
1194
1195 return can_access_file_acl(conn, smb_fname, FILE_READ_DATA);
1196}
1197
1198/*******************************************************************
1199 Check to see if a user can write a file (and only files, we do not
1200 check dirs on this one). This is only approximate,
1201 it is used as part of the "hide unwriteable" option. Don't
1202 use it for anything security sensitive.
1203********************************************************************/
1204
1205static bool user_can_write_file(connection_struct *conn,
1206 const struct smb_filename *smb_fname)
1207{
1208 /*
1209 * Never hide files from the root user.
1210 * We use (uid_t)0 here not sec_initial_uid()
1211 * as make test uses a single user context.
1212 */
1213
1214 if (get_current_uid(conn) == (uid_t)0) {
1215 return True;
1216 }
1217
1218 SMB_ASSERT(VALID_STAT(smb_fname->st));
1219
1220 /* Pseudo-open the file */
1221
1222 if(S_ISDIR(smb_fname->st.st_ex_mode)) {
1223 return True;
1224 }
1225
1226 return can_write_to_file(conn, smb_fname);
1227}
1228
1229/*******************************************************************
1230 Is a file a "special" type ?
1231********************************************************************/
1232
1233static bool file_is_special(connection_struct *conn,
1234 const struct smb_filename *smb_fname)
1235{
1236 /*
1237 * Never hide files from the root user.
1238 * We use (uid_t)0 here not sec_initial_uid()
1239 * as make test uses a single user context.
1240 */
1241
1242 if (get_current_uid(conn) == (uid_t)0) {
1243 return False;
1244 }
1245
1246 SMB_ASSERT(VALID_STAT(smb_fname->st));
1247
1248 if (S_ISREG(smb_fname->st.st_ex_mode) ||
1249 S_ISDIR(smb_fname->st.st_ex_mode) ||
1250 S_ISLNK(smb_fname->st.st_ex_mode))
1251 return False;
1252
1253 return True;
1254}
1255
1256/*******************************************************************
1257 Should the file be seen by the client?
1258 NOTE: A successful return is no guarantee of the file's existence.
1259********************************************************************/
1260
1261bool is_visible_file(connection_struct *conn, const char *dir_path,
1262 const char *name, SMB_STRUCT_STAT *pst, bool use_veto)
1263{
1264 bool hide_unreadable = lp_hideunreadable(SNUM(conn));
1265 bool hide_unwriteable = lp_hideunwriteable_files(SNUM(conn));
1266 bool hide_special = lp_hide_special_files(SNUM(conn));
1267 char *entry = NULL;
1268 struct smb_filename *smb_fname_base = NULL;
1269 NTSTATUS status;
1270 bool ret = false;
1271
1272 if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) {
1273 return True; /* . and .. are always visible. */
1274 }
1275
1276 /* If it's a vetoed file, pretend it doesn't even exist */
1277 if (use_veto && IS_VETO_PATH(conn, name)) {
1278 DEBUG(10,("is_visible_file: file %s is vetoed.\n", name ));
1279 return False;
1280 }
1281
1282 if (hide_unreadable || hide_unwriteable || hide_special) {
1283 entry = talloc_asprintf(talloc_tos(), "%s/%s", dir_path, name);
1284 if (!entry) {
1285 ret = false;
1286 goto out;
1287 }
1288
1289 /* Create an smb_filename with stream_name == NULL. */
1290 status = create_synthetic_smb_fname(talloc_tos(), entry, NULL,
1291 pst, &smb_fname_base);
1292 if (!NT_STATUS_IS_OK(status)) {
1293 ret = false;
1294 goto out;
1295 }
1296
1297 /* If the file name does not exist, there's no point checking
1298 * the configuration options. We succeed, on the basis that the
1299 * checks *might* have passed if the file was present.
1300 */
1301 if (!VALID_STAT(*pst)) {
1302 if (SMB_VFS_STAT(conn, smb_fname_base) != 0) {
1303 ret = true;
1304 goto out;
1305 } else {
1306 *pst = smb_fname_base->st;
1307 }
1308 }
1309
1310 /* Honour _hide unreadable_ option */
1311 if (hide_unreadable &&
1312 !user_can_read_file(conn, smb_fname_base)) {
1313 DEBUG(10,("is_visible_file: file %s is unreadable.\n",
1314 entry ));
1315 ret = false;
1316 goto out;
1317 }
1318 /* Honour _hide unwriteable_ option */
1319 if (hide_unwriteable && !user_can_write_file(conn,
1320 smb_fname_base)) {
1321 DEBUG(10,("is_visible_file: file %s is unwritable.\n",
1322 entry ));
1323 ret = false;
1324 goto out;
1325 }
1326 /* Honour _hide_special_ option */
1327 if (hide_special && file_is_special(conn, smb_fname_base)) {
1328 DEBUG(10,("is_visible_file: file %s is special.\n",
1329 entry ));
1330 ret = false;
1331 goto out;
1332 }
1333 }
1334
1335 ret = true;
1336 out:
1337 TALLOC_FREE(smb_fname_base);
1338 TALLOC_FREE(entry);
1339 return ret;
1340}
1341
1342static int smb_Dir_destructor(struct smb_Dir *dirp)
1343{
1344 if (dirp->dir != NULL) {
1345 SMB_VFS_CLOSEDIR(dirp->conn,dirp->dir);
1346 if (dirp->fsp != NULL) {
1347 /*
1348 * The SMB_VFS_CLOSEDIR above
1349 * closes the underlying fd inside
1350 * dirp->fsp.
1351 */
1352 dirp->fsp->fh->fd = -1;
1353 if (dirp->fsp->dptr != NULL) {
1354 SMB_ASSERT(dirp->fsp->dptr->dir_hnd == dirp);
1355 dirp->fsp->dptr->dir_hnd = NULL;
1356 }
1357 dirp->fsp = NULL;
1358 }
1359 }
1360 if (dirp->conn->sconn && !dirp->conn->sconn->using_smb2) {
1361 dirp->conn->sconn->searches.dirhandles_open--;
1362 }
1363 return 0;
1364}
1365
1366/*******************************************************************
1367 Open a directory.
1368********************************************************************/
1369
1370struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1371 const char *name,
1372 const char *mask,
1373 uint32 attr)
1374{
1375 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1376 struct smbd_server_connection *sconn = conn->sconn;
1377
1378 if (!dirp) {
1379 return NULL;
1380 }
1381
1382 dirp->conn = conn;
1383 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1384
1385 dirp->dir_path = talloc_strdup(dirp, name);
1386 if (!dirp->dir_path) {
1387 errno = ENOMEM;
1388 goto fail;
1389 }
1390
1391 if (sconn && !sconn->using_smb2) {
1392 sconn->searches.dirhandles_open++;
1393 }
1394 talloc_set_destructor(dirp, smb_Dir_destructor);
1395
1396 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1397 if (!dirp->dir) {
1398 DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1399 strerror(errno) ));
1400 goto fail;
1401 }
1402
1403 return dirp;
1404
1405 fail:
1406 TALLOC_FREE(dirp);
1407 return NULL;
1408}
1409
1410/*******************************************************************
1411 Open a directory from an fsp.
1412********************************************************************/
1413
1414static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn,
1415 files_struct *fsp,
1416 const char *mask,
1417 uint32 attr)
1418{
1419 struct smb_Dir *dirp = TALLOC_ZERO_P(mem_ctx, struct smb_Dir);
1420 struct smbd_server_connection *sconn = conn->sconn;
1421
1422 if (!dirp) {
1423 return NULL;
1424 }
1425
1426 dirp->conn = conn;
1427 dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1428
1429 dirp->dir_path = talloc_strdup(dirp, fsp->fsp_name->base_name);
1430 if (!dirp->dir_path) {
1431 errno = ENOMEM;
1432 goto fail;
1433 }
1434
1435 if (sconn && !sconn->using_smb2) {
1436 sconn->searches.dirhandles_open++;
1437 }
1438 talloc_set_destructor(dirp, smb_Dir_destructor);
1439
1440 if (fsp->is_directory && fsp->fh->fd != -1) {
1441 dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1442 if (dirp->dir != NULL) {
1443 dirp->fsp = fsp;
1444 } else {
1445 DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1446 "NULL (%s)\n",
1447 dirp->dir_path,
1448 strerror(errno)));
1449 if (errno != ENOSYS) {
1450 return NULL;
1451 }
1452 }
1453 }
1454
1455 if (dirp->dir == NULL) {
1456 /* FDOPENDIR didn't work. Use OPENDIR instead. */
1457 dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1458 }
1459
1460 if (!dirp->dir) {
1461 DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1462 strerror(errno) ));
1463 goto fail;
1464 }
1465
1466 return dirp;
1467
1468 fail:
1469 TALLOC_FREE(dirp);
1470 return NULL;
1471}
1472
1473
1474/*******************************************************************
1475 Read from a directory.
1476 Return directory entry, current offset, and optional stat information.
1477 Don't check for veto or invisible files.
1478********************************************************************/
1479
1480const char *ReadDirName(struct smb_Dir *dirp, long *poffset,
1481 SMB_STRUCT_STAT *sbuf, char **ptalloced)
1482{
1483 const char *n;
1484 char *talloced = NULL;
1485 connection_struct *conn = dirp->conn;
1486
1487 /* Cheat to allow . and .. to be the first entries returned. */
1488 if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1489 (*poffset == DOT_DOT_DIRECTORY_OFFSET)) && (dirp->file_number < 2))
1490 {
1491 if (dirp->file_number == 0) {
1492 n = ".";
1493 *poffset = dirp->offset = START_OF_DIRECTORY_OFFSET;
1494 } else {
1495 n = "..";
1496 *poffset = dirp->offset = DOT_DOT_DIRECTORY_OFFSET;
1497 }
1498 dirp->file_number++;
1499 *ptalloced = NULL;
1500 return n;
1501 } else if (*poffset == END_OF_DIRECTORY_OFFSET) {
1502 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1503 return NULL;
1504 } else {
1505 /* A real offset, seek to it. */
1506 SeekDir(dirp, *poffset);
1507 }
1508
1509 while ((n = vfs_readdirname(conn, dirp->dir, sbuf, &talloced))) {
1510 /* Ignore . and .. - we've already returned them. */
1511 if (*n == '.') {
1512 if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) {
1513 TALLOC_FREE(talloced);
1514 continue;
1515 }
1516 }
1517 *poffset = dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir);
1518 *ptalloced = talloced;
1519 dirp->file_number++;
1520 return n;
1521 }
1522 *poffset = dirp->offset = END_OF_DIRECTORY_OFFSET;
1523 *ptalloced = NULL;
1524 return NULL;
1525}
1526
1527/*******************************************************************
1528 Rewind to the start.
1529********************************************************************/
1530
1531void RewindDir(struct smb_Dir *dirp, long *poffset)
1532{
1533 SMB_VFS_REWINDDIR(dirp->conn, dirp->dir);
1534 dirp->file_number = 0;
1535 dirp->offset = START_OF_DIRECTORY_OFFSET;
1536 *poffset = START_OF_DIRECTORY_OFFSET;
1537}
1538
1539/*******************************************************************
1540 Seek a dir.
1541********************************************************************/
1542
1543void SeekDir(struct smb_Dir *dirp, long offset)
1544{
1545 if (offset != dirp->offset) {
1546 if (offset == START_OF_DIRECTORY_OFFSET) {
1547 RewindDir(dirp, &offset);
1548 /*
1549 * Ok we should really set the file number here
1550 * to 1 to enable ".." to be returned next. Trouble
1551 * is I'm worried about callers using SeekDir(dirp,0)
1552 * as equivalent to RewindDir(). So leave this alone
1553 * for now.
1554 */
1555 } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1556 RewindDir(dirp, &offset);
1557 /*
1558 * Set the file number to 2 - we want to get the first
1559 * real file entry (the one we return after "..")
1560 * on the next ReadDir.
1561 */
1562 dirp->file_number = 2;
1563 } else if (offset == END_OF_DIRECTORY_OFFSET) {
1564 ; /* Don't seek in this case. */
1565 } else {
1566 SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1567 }
1568 dirp->offset = offset;
1569 }
1570}
1571
1572/*******************************************************************
1573 Tell a dir position.
1574********************************************************************/
1575
1576long TellDir(struct smb_Dir *dirp)
1577{
1578 return(dirp->offset);
1579}
1580
1581/*******************************************************************
1582 Add an entry into the dcache.
1583********************************************************************/
1584
1585void DirCacheAdd(struct smb_Dir *dirp, const char *name, long offset)
1586{
1587 struct name_cache_entry *e;
1588
1589 if (dirp->name_cache_size == 0) {
1590 return;
1591 }
1592
1593 if (dirp->name_cache == NULL) {
1594 dirp->name_cache = TALLOC_ZERO_ARRAY(
1595 dirp, struct name_cache_entry, dirp->name_cache_size);
1596
1597 if (dirp->name_cache == NULL) {
1598 return;
1599 }
1600 }
1601
1602 dirp->name_cache_index = (dirp->name_cache_index+1) %
1603 dirp->name_cache_size;
1604 e = &dirp->name_cache[dirp->name_cache_index];
1605 TALLOC_FREE(e->name);
1606 e->name = talloc_strdup(dirp, name);
1607 e->offset = offset;
1608}
1609
1610/*******************************************************************
1611 Find an entry by name. Leave us at the offset after it.
1612 Don't check for veto or invisible files.
1613********************************************************************/
1614
1615bool SearchDir(struct smb_Dir *dirp, const char *name, long *poffset)
1616{
1617 int i;
1618 const char *entry = NULL;
1619 char *talloced = NULL;
1620 connection_struct *conn = dirp->conn;
1621
1622 /* Search back in the name cache. */
1623 if (dirp->name_cache_size && dirp->name_cache) {
1624 for (i = dirp->name_cache_index; i >= 0; i--) {
1625 struct name_cache_entry *e = &dirp->name_cache[i];
1626 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1627 *poffset = e->offset;
1628 SeekDir(dirp, e->offset);
1629 return True;
1630 }
1631 }
1632 for (i = dirp->name_cache_size - 1; i > dirp->name_cache_index; i--) {
1633 struct name_cache_entry *e = &dirp->name_cache[i];
1634 if (e->name && (conn->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1635 *poffset = e->offset;
1636 SeekDir(dirp, e->offset);
1637 return True;
1638 }
1639 }
1640 }
1641
1642 /* Not found in the name cache. Rewind directory and start from scratch. */
1643 SMB_VFS_REWINDDIR(conn, dirp->dir);
1644 dirp->file_number = 0;
1645 *poffset = START_OF_DIRECTORY_OFFSET;
1646 while ((entry = ReadDirName(dirp, poffset, NULL, &talloced))) {
1647 if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1648 TALLOC_FREE(talloced);
1649 return True;
1650 }
1651 TALLOC_FREE(talloced);
1652 }
1653 return False;
1654}
1655
1656/*****************************************************************
1657 Is this directory empty ?
1658*****************************************************************/
1659
1660NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1661{
1662 NTSTATUS status = NT_STATUS_OK;
1663 long dirpos = 0;
1664 const char *dname = NULL;
1665 char *talloced = NULL;
1666 SMB_STRUCT_STAT st;
1667 struct connection_struct *conn = fsp->conn;
1668 struct smb_Dir *dir_hnd = OpenDir_fsp(talloc_tos(),
1669 conn,
1670 fsp,
1671 NULL,
1672 0);
1673
1674 if (!dir_hnd) {
1675 return map_nt_error_from_unix(errno);
1676 }
1677
1678 while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced))) {
1679 /* Quick check for "." and ".." */
1680 if (dname[0] == '.') {
1681 if (!dname[1] || (dname[1] == '.' && !dname[2])) {
1682 TALLOC_FREE(talloced);
1683 continue;
1684 }
1685 }
1686
1687 if (!is_visible_file(conn, fsp->fsp_name->base_name, dname, &st, True)) {
1688 TALLOC_FREE(talloced);
1689 continue;
1690 }
1691
1692 DEBUG(10,("can_delete_directory_fsp: got name %s - can't delete\n",
1693 dname ));
1694 status = NT_STATUS_DIRECTORY_NOT_EMPTY;
1695 break;
1696 }
1697 TALLOC_FREE(talloced);
1698 TALLOC_FREE(dir_hnd);
1699
1700 return status;
1701}
Note: See TracBrowser for help on using the repository browser.