Line data Source code
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 "locking/share_mode_lock.h"
24 : #include "smbd/smbd.h"
25 : #include "smbd/globals.h"
26 : #include "libcli/security/security.h"
27 : #include "lib/util/bitmap.h"
28 : #include "../lib/util/memcache.h"
29 : #include "../librpc/gen_ndr/open_files.h"
30 : #include "lib/util/string_wrappers.h"
31 :
32 : /*
33 : This module implements directory related functions for Samba.
34 : */
35 :
36 : /* "Special" directory offsets. */
37 : #define END_OF_DIRECTORY_OFFSET ((long)-1)
38 : #define START_OF_DIRECTORY_OFFSET ((long)0)
39 : #define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
40 :
41 : /* "Special" directory offsets in 32-bit wire format. */
42 : #define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
43 : #define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
44 : #define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
45 :
46 : /* Make directory handle internals available. */
47 :
48 : struct name_cache_entry {
49 : char *name;
50 : long offset;
51 : };
52 :
53 : struct smb_Dir {
54 : connection_struct *conn;
55 : DIR *dir;
56 : long offset;
57 : struct smb_filename *dir_smb_fname;
58 : size_t name_cache_size;
59 : struct name_cache_entry *name_cache;
60 : unsigned int name_cache_index;
61 : unsigned int file_number;
62 : bool case_sensitive;
63 : files_struct *fsp; /* Back pointer to containing fsp, only
64 : set from OpenDir_fsp(). */
65 : };
66 :
67 : struct dptr_struct {
68 : struct dptr_struct *next, *prev;
69 : int dnum;
70 : uint16_t spid;
71 : struct connection_struct *conn;
72 : struct smb_Dir *dir_hnd;
73 : bool expect_close;
74 : char *wcard;
75 : uint32_t attr;
76 : struct smb_filename *smb_dname;
77 : bool has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
78 : bool did_stat; /* Optimisation for non-wcard searches. */
79 : bool priv; /* Directory handle opened with privilege. */
80 : uint32_t counter;
81 : struct memcache *dptr_cache;
82 : };
83 :
84 : static NTSTATUS OpenDir_fsp(
85 : TALLOC_CTX *mem_ctx,
86 : connection_struct *conn,
87 : files_struct *fsp,
88 : const char *mask,
89 : uint32_t attr,
90 : struct smb_Dir **_dir_hnd);
91 :
92 : static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset);
93 :
94 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd);
95 :
96 : static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset);
97 :
98 : #define INVALID_DPTR_KEY (-3)
99 :
100 : /****************************************************************************
101 : Initialise the dir bitmap.
102 : ****************************************************************************/
103 :
104 5251 : bool init_dptrs(struct smbd_server_connection *sconn)
105 : {
106 5251 : if (sconn->searches.dptr_bmap) {
107 0 : return true;
108 : }
109 :
110 5251 : sconn->searches.dptr_bmap = bitmap_talloc(
111 : sconn, MAX_DIRECTORY_HANDLES);
112 :
113 5251 : if (sconn->searches.dptr_bmap == NULL) {
114 0 : return false;
115 : }
116 :
117 5251 : return true;
118 : }
119 :
120 : /****************************************************************************
121 : Get the struct dptr_struct for a dir index.
122 : ****************************************************************************/
123 :
124 0 : static struct dptr_struct *dptr_get(struct smbd_server_connection *sconn,
125 : int key)
126 : {
127 : struct dptr_struct *dptr;
128 :
129 0 : for (dptr = sconn->searches.dirptrs; dptr != NULL; dptr = dptr->next) {
130 0 : if(dptr->dnum != key) {
131 0 : continue;
132 : }
133 0 : DLIST_PROMOTE(sconn->searches.dirptrs, dptr);
134 0 : return dptr;
135 : }
136 0 : return(NULL);
137 : }
138 :
139 : /****************************************************************************
140 : Get the dir path for a dir index.
141 : ****************************************************************************/
142 :
143 0 : const char *dptr_path(struct smbd_server_connection *sconn, int key)
144 : {
145 0 : struct dptr_struct *dptr = dptr_get(sconn, key);
146 0 : if (dptr)
147 0 : return(dptr->smb_dname->base_name);
148 0 : return(NULL);
149 : }
150 :
151 : /****************************************************************************
152 : Get the dir wcard for a dir index.
153 : ****************************************************************************/
154 :
155 0 : const char *dptr_wcard(struct smbd_server_connection *sconn, int key)
156 : {
157 0 : struct dptr_struct *dptr = dptr_get(sconn, key);
158 0 : if (dptr)
159 0 : return(dptr->wcard);
160 0 : return(NULL);
161 : }
162 :
163 : /****************************************************************************
164 : Get the dir attrib for a dir index.
165 : ****************************************************************************/
166 :
167 0 : uint16_t dptr_attr(struct smbd_server_connection *sconn, int key)
168 : {
169 0 : struct dptr_struct *dptr = dptr_get(sconn, key);
170 0 : if (dptr)
171 0 : return(dptr->attr);
172 0 : return(0);
173 : }
174 :
175 : /****************************************************************************
176 : Close all dptrs for a cnum.
177 : ****************************************************************************/
178 :
179 0 : void dptr_closecnum(connection_struct *conn)
180 : {
181 : struct dptr_struct *dptr, *next;
182 0 : struct smbd_server_connection *sconn = conn->sconn;
183 :
184 0 : if (sconn == NULL) {
185 0 : return;
186 : }
187 :
188 0 : for(dptr = sconn->searches.dirptrs; dptr; dptr = next) {
189 0 : next = dptr->next;
190 0 : if (dptr->conn == conn) {
191 : /*
192 : * Need to make a copy, "dptr" will be gone
193 : * after close_file_free() returns
194 : */
195 0 : struct files_struct *fsp = dptr->dir_hnd->fsp;
196 0 : close_file_free(NULL, &fsp, NORMAL_CLOSE);
197 : }
198 : }
199 : }
200 :
201 : /****************************************************************************
202 : Create a new dir ptr. If the flag old_handle is true then we must allocate
203 : from the bitmap range 0 - 255 as old SMBsearch directory handles are only
204 : one byte long. If old_handle is false we allocate from the range
205 : 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
206 : a directory handle is never zero.
207 : wcard must not be zero.
208 : ****************************************************************************/
209 :
210 2171 : NTSTATUS dptr_create(connection_struct *conn,
211 : struct smb_request *req,
212 : files_struct *fsp,
213 : bool old_handle,
214 : bool expect_close,
215 : uint16_t spid,
216 : const char *wcard,
217 : uint32_t attr,
218 : struct dptr_struct **dptr_ret)
219 : {
220 2171 : struct smbd_server_connection *sconn = conn->sconn;
221 2171 : struct dptr_struct *dptr = NULL;
222 2171 : struct smb_Dir *dir_hnd = NULL;
223 : NTSTATUS status;
224 :
225 2171 : DBG_INFO("dir=%s\n", fsp_str_dbg(fsp));
226 :
227 2171 : if (sconn == NULL) {
228 0 : DEBUG(0,("dptr_create: called with fake connection_struct\n"));
229 0 : return NT_STATUS_INTERNAL_ERROR;
230 : }
231 :
232 2171 : if (!wcard) {
233 0 : return NT_STATUS_INVALID_PARAMETER;
234 : }
235 :
236 2171 : status = check_any_access_fsp(fsp, SEC_DIR_LIST);
237 2171 : if (!NT_STATUS_IS_OK(status)) {
238 0 : DBG_INFO("dptr_create: directory %s "
239 : "not open for LIST access\n",
240 : fsp_str_dbg(fsp));
241 0 : return status;
242 : }
243 2171 : status = OpenDir_fsp(NULL, conn, fsp, wcard, attr, &dir_hnd);
244 2171 : if (!NT_STATUS_IS_OK(status)) {
245 0 : return status;
246 : }
247 :
248 2171 : dptr = talloc_zero(NULL, struct dptr_struct);
249 2171 : if(!dptr) {
250 0 : DEBUG(0,("talloc fail in dptr_create.\n"));
251 0 : TALLOC_FREE(dir_hnd);
252 0 : return NT_STATUS_NO_MEMORY;
253 : }
254 :
255 2171 : dptr->smb_dname = cp_smb_filename(dptr, fsp->fsp_name);
256 2171 : if (dptr->smb_dname == NULL) {
257 0 : TALLOC_FREE(dptr);
258 0 : TALLOC_FREE(dir_hnd);
259 0 : return NT_STATUS_NO_MEMORY;
260 : }
261 2171 : dptr->conn = conn;
262 2171 : dptr->dir_hnd = dir_hnd;
263 2171 : dptr->spid = spid;
264 2171 : dptr->expect_close = expect_close;
265 2171 : dptr->wcard = talloc_strdup(dptr, wcard);
266 2171 : if (!dptr->wcard) {
267 0 : TALLOC_FREE(dptr);
268 0 : TALLOC_FREE(dir_hnd);
269 0 : return NT_STATUS_NO_MEMORY;
270 : }
271 2171 : if ((req != NULL && req->posix_pathnames) ||
272 2171 : (wcard[0] == '.' && wcard[1] == 0)) {
273 0 : dptr->has_wild = True;
274 : } else {
275 2171 : dptr->has_wild = ms_has_wild(dptr->wcard);
276 : }
277 :
278 2171 : dptr->attr = attr;
279 :
280 2171 : if (sconn->using_smb2) {
281 2171 : goto done;
282 : }
283 :
284 0 : if(old_handle) {
285 :
286 : /*
287 : * This is an old-style SMBsearch request. Ensure the
288 : * value we return will fit in the range 1-255.
289 : */
290 :
291 0 : dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 0);
292 :
293 0 : if(dptr->dnum == -1 || dptr->dnum > 254) {
294 0 : DBG_ERR("returned %d: Error - all old "
295 : "dirptrs in use ?\n",
296 : dptr->dnum);
297 0 : TALLOC_FREE(dptr);
298 0 : TALLOC_FREE(dir_hnd);
299 0 : return NT_STATUS_TOO_MANY_OPENED_FILES;
300 : }
301 : } else {
302 :
303 : /*
304 : * This is a new-style trans2 request. Allocate from
305 : * a range that will return 256 - MAX_DIRECTORY_HANDLES.
306 : */
307 :
308 0 : dptr->dnum = bitmap_find(sconn->searches.dptr_bmap, 255);
309 :
310 0 : if(dptr->dnum == -1 || dptr->dnum < 255) {
311 0 : DBG_ERR("returned %d: Error - all new "
312 : "dirptrs in use ?\n",
313 : dptr->dnum);
314 0 : TALLOC_FREE(dptr);
315 0 : TALLOC_FREE(dir_hnd);
316 0 : return NT_STATUS_TOO_MANY_OPENED_FILES;
317 : }
318 : }
319 :
320 0 : bitmap_set(sconn->searches.dptr_bmap, dptr->dnum);
321 :
322 0 : dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
323 :
324 0 : DLIST_ADD(sconn->searches.dirptrs, dptr);
325 :
326 2171 : done:
327 2171 : DBG_INFO("creating new dirptr [%d] for path [%s], expect_close = %d\n",
328 : dptr->dnum, fsp_str_dbg(fsp), expect_close);
329 :
330 2171 : *dptr_ret = dptr;
331 :
332 2171 : return NT_STATUS_OK;
333 : }
334 :
335 :
336 : /****************************************************************************
337 : Wrapper functions to access the lower level directory handles.
338 : ****************************************************************************/
339 :
340 2171 : void dptr_CloseDir(files_struct *fsp)
341 : {
342 2171 : struct smbd_server_connection *sconn = NULL;
343 :
344 2171 : if (fsp->dptr == NULL) {
345 0 : return;
346 : }
347 2171 : sconn = fsp->dptr->conn->sconn;
348 :
349 : /*
350 : * The destructor for the struct smb_Dir (fsp->dptr->dir_hnd)
351 : * now handles all resource deallocation.
352 : */
353 :
354 2171 : DBG_INFO("closing dptr key %d\n", fsp->dptr->dnum);
355 :
356 2171 : if (sconn != NULL && !sconn->using_smb2) {
357 0 : DLIST_REMOVE(sconn->searches.dirptrs, fsp->dptr);
358 :
359 : /*
360 : * Free the dnum in the bitmap. Remember the dnum value is
361 : * always biased by one with respect to the bitmap.
362 : */
363 :
364 0 : if (!bitmap_query(sconn->searches.dptr_bmap,
365 0 : fsp->dptr->dnum - 1))
366 : {
367 0 : DBG_ERR("closing dnum = %d and bitmap not set !\n",
368 : fsp->dptr->dnum);
369 : }
370 :
371 0 : bitmap_clear(sconn->searches.dptr_bmap, fsp->dptr->dnum - 1);
372 : }
373 :
374 2171 : TALLOC_FREE(fsp->dptr->dir_hnd);
375 2171 : TALLOC_FREE(fsp->dptr);
376 : }
377 :
378 0 : void dptr_SeekDir(struct dptr_struct *dptr, long offset)
379 : {
380 0 : SeekDir(dptr->dir_hnd, offset);
381 0 : }
382 :
383 15947 : long dptr_TellDir(struct dptr_struct *dptr)
384 : {
385 15947 : return TellDir(dptr->dir_hnd);
386 : }
387 :
388 14920 : bool dptr_has_wild(struct dptr_struct *dptr)
389 : {
390 14920 : return dptr->has_wild;
391 : }
392 :
393 0 : int dptr_dnum(struct dptr_struct *dptr)
394 : {
395 0 : return dptr->dnum;
396 : }
397 :
398 0 : bool dptr_get_priv(struct dptr_struct *dptr)
399 : {
400 0 : return dptr->priv;
401 : }
402 :
403 0 : void dptr_set_priv(struct dptr_struct *dptr)
404 : {
405 0 : dptr->priv = true;
406 0 : }
407 :
408 14920 : bool dptr_case_sensitive(struct dptr_struct *dptr)
409 : {
410 14920 : return dptr->dir_hnd->case_sensitive;
411 : }
412 :
413 : /****************************************************************************
414 : Return the next visible file name, skipping veto'd and invisible files.
415 : ****************************************************************************/
416 :
417 15947 : static char *dptr_ReadDirName(TALLOC_CTX *ctx,
418 : struct dptr_struct *dptr,
419 : long *poffset,
420 : SMB_STRUCT_STAT *pst)
421 : {
422 : struct smb_filename smb_fname_base;
423 15947 : char *name = NULL;
424 15947 : const char *name_temp = NULL;
425 15947 : char *talloced = NULL;
426 15947 : char *pathreal = NULL;
427 15947 : char *found_name = NULL;
428 : NTSTATUS status;
429 :
430 15947 : SET_STAT_INVALID(*pst);
431 :
432 15947 : if (dptr->has_wild || dptr->did_stat) {
433 15805 : name_temp = ReadDirName(dptr->dir_hnd, poffset, pst,
434 : &talloced);
435 15805 : if (name_temp == NULL) {
436 4299 : return NULL;
437 : }
438 11506 : if (talloced != NULL) {
439 0 : return talloc_move(ctx, &talloced);
440 : }
441 11506 : return talloc_strdup(ctx, name_temp);
442 : }
443 :
444 : /* If poffset is -1 then we know we returned this name before and we
445 : * have no wildcards. We're at the end of the directory. */
446 142 : if (*poffset == END_OF_DIRECTORY_OFFSET) {
447 0 : return NULL;
448 : }
449 :
450 : /* We know the stored wcard contains no wildcard characters.
451 : * See if we can match with a stat call. If we can't, then set
452 : * did_stat to true to ensure we only do this once and keep
453 : * searching. */
454 :
455 142 : dptr->did_stat = true;
456 :
457 142 : if (VALID_STAT(*pst)) {
458 0 : name = talloc_strdup(ctx, dptr->wcard);
459 0 : goto ret;
460 : }
461 :
462 142 : pathreal = talloc_asprintf(ctx,
463 : "%s/%s",
464 142 : dptr->smb_dname->base_name,
465 : dptr->wcard);
466 142 : if (!pathreal)
467 0 : return NULL;
468 :
469 : /* Create an smb_filename with stream_name == NULL. */
470 142 : smb_fname_base = (struct smb_filename) {
471 : .base_name = pathreal,
472 142 : .flags = dptr->dir_hnd->fsp->fsp_name->flags,
473 142 : .twrp = dptr->smb_dname->twrp,
474 : };
475 :
476 142 : if (vfs_stat(dptr->conn, &smb_fname_base) == 0) {
477 113 : *pst = smb_fname_base.st;
478 113 : name = talloc_strdup(ctx, dptr->wcard);
479 113 : goto clean;
480 : } else {
481 : /* If we get any other error than ENOENT or ENOTDIR
482 : then the file exists we just can't stat it. */
483 29 : if (errno != ENOENT && errno != ENOTDIR) {
484 0 : name = talloc_strdup(ctx, dptr->wcard);
485 0 : goto clean;
486 : }
487 : }
488 :
489 : /* Stat failed. We know this is authoritative if we are
490 : * providing case sensitive semantics or the underlying
491 : * filesystem is case sensitive.
492 : */
493 29 : if (dptr->dir_hnd->case_sensitive ||
494 29 : !(dptr->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
495 : {
496 0 : goto clean;
497 : }
498 :
499 : /*
500 : * Try case-insensitive stat if the fs has the ability. This avoids
501 : * scanning the whole directory.
502 : */
503 29 : status = SMB_VFS_GET_REAL_FILENAME_AT(dptr->conn,
504 : dptr->dir_hnd->fsp,
505 : dptr->wcard,
506 : ctx,
507 : &found_name);
508 29 : if (NT_STATUS_IS_OK(status)) {
509 0 : name = found_name;
510 0 : goto clean;
511 : }
512 29 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
513 : /* The case-insensitive lookup was authoritative. */
514 0 : goto clean;
515 : }
516 :
517 29 : TALLOC_FREE(pathreal);
518 :
519 29 : name_temp = ReadDirName(dptr->dir_hnd, poffset, pst, &talloced);
520 29 : if (name_temp == NULL) {
521 0 : return NULL;
522 : }
523 29 : if (talloced != NULL) {
524 0 : return talloc_move(ctx, &talloced);
525 : }
526 29 : return talloc_strdup(ctx, name_temp);
527 :
528 113 : clean:
529 113 : TALLOC_FREE(pathreal);
530 0 : ret:
531 : /* We need to set the underlying dir_hnd offset to -1
532 : * also as this function is usually called with the
533 : * output from TellDir. */
534 113 : dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
535 113 : return name;
536 : }
537 :
538 : /****************************************************************************
539 : Search for a file by name.
540 : ****************************************************************************/
541 :
542 0 : bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst)
543 : {
544 0 : SET_STAT_INVALID(*pst);
545 :
546 0 : if (!dptr->has_wild && (dptr->dir_hnd->offset == END_OF_DIRECTORY_OFFSET)) {
547 : /* This is a singleton directory and we're already at the end. */
548 0 : *poffset = END_OF_DIRECTORY_OFFSET;
549 0 : return False;
550 : }
551 :
552 0 : return SearchDir(dptr->dir_hnd, name, poffset);
553 : }
554 :
555 : /****************************************************************************
556 : Map a native directory offset to a 32-bit cookie.
557 : ****************************************************************************/
558 :
559 0 : static uint32_t map_dir_offset_to_wire(struct dptr_struct *dptr, long offset)
560 : {
561 : DATA_BLOB key;
562 : DATA_BLOB val;
563 :
564 0 : if (offset == END_OF_DIRECTORY_OFFSET) {
565 0 : return WIRE_END_OF_DIRECTORY_OFFSET;
566 : }
567 0 : if (offset == START_OF_DIRECTORY_OFFSET) {
568 0 : return WIRE_START_OF_DIRECTORY_OFFSET;
569 : }
570 0 : if (offset == DOT_DOT_DIRECTORY_OFFSET) {
571 0 : return WIRE_DOT_DOT_DIRECTORY_OFFSET;
572 : }
573 : if (sizeof(long) == 4) {
574 : /* 32-bit machine. We can cheat... */
575 : return (uint32_t)offset;
576 : }
577 0 : if (dptr->dptr_cache == NULL) {
578 : /* Lazy initialize cache. */
579 0 : dptr->dptr_cache = memcache_init(dptr, 0);
580 0 : if (dptr->dptr_cache == NULL) {
581 0 : return WIRE_END_OF_DIRECTORY_OFFSET;
582 : }
583 : } else {
584 : /* Have we seen this offset before ? */
585 0 : key.data = (void *)&offset;
586 0 : key.length = sizeof(offset);
587 0 : if (memcache_lookup(dptr->dptr_cache,
588 : SMB1_SEARCH_OFFSET_MAP,
589 : key,
590 : &val)) {
591 : uint32_t wire_offset;
592 0 : SMB_ASSERT(val.length == sizeof(wire_offset));
593 0 : memcpy(&wire_offset, val.data, sizeof(wire_offset));
594 0 : DEBUG(10,("found wire %u <-> offset %ld\n",
595 : (unsigned int)wire_offset,
596 : (long)offset));
597 0 : return wire_offset;
598 : }
599 : }
600 : /* Allocate a new wire cookie. */
601 : do {
602 0 : dptr->counter++;
603 0 : } while (dptr->counter == WIRE_START_OF_DIRECTORY_OFFSET ||
604 0 : dptr->counter == WIRE_END_OF_DIRECTORY_OFFSET ||
605 0 : dptr->counter == WIRE_DOT_DOT_DIRECTORY_OFFSET);
606 : /* Store it in the cache. */
607 0 : key.data = (void *)&offset;
608 0 : key.length = sizeof(offset);
609 0 : val.data = (void *)&dptr->counter;
610 0 : val.length = sizeof(dptr->counter); /* MUST BE uint32_t ! */
611 0 : memcache_add(dptr->dptr_cache,
612 : SMB1_SEARCH_OFFSET_MAP,
613 : key,
614 : val);
615 : /* And the reverse mapping for lookup from
616 : map_wire_to_dir_offset(). */
617 0 : memcache_add(dptr->dptr_cache,
618 : SMB1_SEARCH_OFFSET_MAP,
619 : val,
620 : key);
621 0 : DEBUG(10,("stored wire %u <-> offset %ld\n",
622 : (unsigned int)dptr->counter,
623 : (long)offset));
624 0 : return dptr->counter;
625 : }
626 :
627 : /****************************************************************************
628 : Fill the 5 byte server reserved dptr field.
629 : ****************************************************************************/
630 :
631 0 : bool dptr_fill(struct smbd_server_connection *sconn,
632 : char *buf1,unsigned int key)
633 : {
634 0 : unsigned char *buf = (unsigned char *)buf1;
635 0 : struct dptr_struct *dptr = dptr_get(sconn, key);
636 : uint32_t wire_offset;
637 0 : if (!dptr) {
638 0 : DEBUG(1,("filling null dirptr %d\n",key));
639 0 : return(False);
640 : }
641 0 : wire_offset = map_dir_offset_to_wire(dptr,TellDir(dptr->dir_hnd));
642 0 : DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key,
643 : (long)dptr->dir_hnd,(int)wire_offset));
644 0 : buf[0] = key;
645 0 : SIVAL(buf,1,wire_offset);
646 0 : return(True);
647 : }
648 :
649 : /****************************************************************************
650 : Map a 32-bit wire cookie to a native directory offset.
651 : ****************************************************************************/
652 :
653 0 : static long map_wire_to_dir_offset(struct dptr_struct *dptr, uint32_t wire_offset)
654 : {
655 : DATA_BLOB key;
656 : DATA_BLOB val;
657 :
658 0 : if (wire_offset == WIRE_END_OF_DIRECTORY_OFFSET) {
659 0 : return END_OF_DIRECTORY_OFFSET;
660 0 : } else if(wire_offset == WIRE_START_OF_DIRECTORY_OFFSET) {
661 0 : return START_OF_DIRECTORY_OFFSET;
662 0 : } else if (wire_offset == WIRE_DOT_DOT_DIRECTORY_OFFSET) {
663 0 : return DOT_DOT_DIRECTORY_OFFSET;
664 : }
665 : if (sizeof(long) == 4) {
666 : /* 32-bit machine. We can cheat... */
667 : return (long)wire_offset;
668 : }
669 0 : if (dptr->dptr_cache == NULL) {
670 : /* Logic error, cache should be initialized. */
671 0 : return END_OF_DIRECTORY_OFFSET;
672 : }
673 0 : key.data = (void *)&wire_offset;
674 0 : key.length = sizeof(wire_offset);
675 0 : if (memcache_lookup(dptr->dptr_cache,
676 : SMB1_SEARCH_OFFSET_MAP,
677 : key,
678 : &val)) {
679 : /* Found mapping. */
680 : long offset;
681 0 : SMB_ASSERT(val.length == sizeof(offset));
682 0 : memcpy(&offset, val.data, sizeof(offset));
683 0 : DEBUG(10,("lookup wire %u <-> offset %ld\n",
684 : (unsigned int)wire_offset,
685 : (long)offset));
686 0 : return offset;
687 : }
688 0 : return END_OF_DIRECTORY_OFFSET;
689 : }
690 :
691 : /****************************************************************************
692 : Return the associated fsp and seek the dir_hnd on it it given the 5 byte
693 : server field.
694 : ****************************************************************************/
695 :
696 0 : files_struct *dptr_fetch_fsp(struct smbd_server_connection *sconn,
697 : char *buf, int *num)
698 : {
699 0 : unsigned int key = *(unsigned char *)buf;
700 0 : struct dptr_struct *dptr = dptr_get(sconn, key);
701 : uint32_t wire_offset;
702 : long seekoff;
703 :
704 0 : if (dptr == NULL) {
705 0 : DEBUG(3,("fetched null dirptr %d\n",key));
706 0 : return(NULL);
707 : }
708 0 : *num = key;
709 0 : wire_offset = IVAL(buf,1);
710 0 : seekoff = map_wire_to_dir_offset(dptr, wire_offset);
711 0 : SeekDir(dptr->dir_hnd,seekoff);
712 0 : DEBUG(3,("fetching dirptr %d for path %s at offset %d\n",
713 : key, dptr->smb_dname->base_name, (int)seekoff));
714 0 : return dptr->dir_hnd->fsp;
715 : }
716 :
717 0 : struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd)
718 : {
719 0 : return dir_hnd->fsp;
720 : }
721 :
722 : /****************************************************************************
723 : Fetch the fsp associated with the dptr_num.
724 : ****************************************************************************/
725 :
726 0 : files_struct *dptr_fetch_lanman2_fsp(struct smbd_server_connection *sconn,
727 : int dptr_num)
728 : {
729 0 : struct dptr_struct *dptr = dptr_get(sconn, dptr_num);
730 0 : if (dptr == NULL) {
731 0 : return NULL;
732 : }
733 0 : DBG_NOTICE("fetching dirptr %d for path %s\n",
734 : dptr_num,
735 : dptr->smb_dname->base_name);
736 0 : return dptr->dir_hnd->fsp;
737 : }
738 :
739 0 : static bool mangle_mask_match(connection_struct *conn,
740 : const char *filename,
741 : const char *mask)
742 : {
743 : char mname[13];
744 :
745 0 : if (!name_to_8_3(filename,mname,False,conn->params)) {
746 0 : return False;
747 : }
748 0 : return mask_match_search(mname,mask,False);
749 : }
750 :
751 14920 : bool smbd_dirptr_get_entry(TALLOC_CTX *ctx,
752 : struct dptr_struct *dirptr,
753 : const char *mask,
754 : uint32_t dirtype,
755 : bool dont_descend,
756 : bool ask_sharemode,
757 : bool get_dosmode_in,
758 : bool (*match_fn)(TALLOC_CTX *ctx,
759 : void *private_data,
760 : const char *dname,
761 : const char *mask,
762 : char **_fname),
763 : bool (*mode_fn)(TALLOC_CTX *ctx,
764 : void *private_data,
765 : struct files_struct *dirfsp,
766 : struct smb_filename *atname,
767 : struct smb_filename *smb_fname,
768 : bool get_dosmode,
769 : uint32_t *_mode),
770 : void *private_data,
771 : char **_fname,
772 : struct smb_filename **_smb_fname,
773 : uint32_t *_mode,
774 : long *_prev_offset)
775 : {
776 14920 : connection_struct *conn = dirptr->conn;
777 : size_t slashlen;
778 : size_t pathlen;
779 14920 : const char *dpath = dirptr->smb_dname->base_name;
780 14920 : bool dirptr_path_is_dot = ISDOT(dpath);
781 : NTSTATUS status;
782 : int ret;
783 :
784 14920 : *_smb_fname = NULL;
785 14920 : *_mode = 0;
786 :
787 14920 : pathlen = strlen(dpath);
788 14920 : slashlen = ( dpath[pathlen-1] != '/') ? 1 : 0;
789 :
790 1027 : while (true) {
791 : long cur_offset;
792 : long prev_offset;
793 15947 : SMB_STRUCT_STAT sbuf = { 0 };
794 15947 : char *dname = NULL;
795 : bool isdots;
796 15947 : char *fname = NULL;
797 15947 : char *pathreal = NULL;
798 15947 : struct smb_filename *atname = NULL;
799 15947 : struct smb_filename *smb_fname = NULL;
800 15947 : uint32_t mode = 0;
801 15947 : bool check_dfs_symlink = false;
802 15947 : bool get_dosmode = get_dosmode_in;
803 : bool ok;
804 :
805 15947 : cur_offset = dptr_TellDir(dirptr);
806 15947 : prev_offset = cur_offset;
807 15947 : dname = dptr_ReadDirName(ctx, dirptr, &cur_offset, &sbuf);
808 :
809 15947 : DBG_DEBUG("dir [%s] dirptr [0x%lx] offset [%ld] => dname [%s]\n",
810 : smb_fname_str_dbg(dirptr->smb_dname), (long)dirptr,
811 : cur_offset, dname ? dname : "(finished)");
812 :
813 15947 : if (dname == NULL) {
814 14920 : return false;
815 : }
816 :
817 11648 : isdots = (ISDOT(dname) || ISDOTDOT(dname));
818 11648 : if (dont_descend && !isdots) {
819 0 : TALLOC_FREE(dname);
820 1027 : continue;
821 : }
822 :
823 11648 : if (IS_VETO_PATH(conn, dname)) {
824 0 : TALLOC_FREE(dname);
825 0 : continue;
826 : }
827 :
828 : /*
829 : * fname may get mangled, dname is never mangled.
830 : * Whenever we're accessing the filesystem we use
831 : * pathreal which is composed from dname.
832 : */
833 :
834 11648 : ok = match_fn(ctx, private_data, dname, mask, &fname);
835 11648 : if (!ok) {
836 1003 : TALLOC_FREE(dname);
837 1003 : continue;
838 : }
839 :
840 : /*
841 : * This used to be
842 : * pathreal = talloc_asprintf(ctx, "%s%s%s", dirptr->path,
843 : * needslash?"/":"", dname);
844 : * but this was measurably slower than doing the memcpy.
845 : */
846 :
847 10645 : pathreal = talloc_array(
848 : ctx, char,
849 : pathlen + slashlen + talloc_get_size(dname));
850 10645 : if (!pathreal) {
851 0 : TALLOC_FREE(dname);
852 0 : TALLOC_FREE(fname);
853 0 : return false;
854 : }
855 :
856 : /*
857 : * We don't want to pass ./xxx to modules below us so don't
858 : * add the path if it is just . by itself.
859 : */
860 10645 : if (dirptr_path_is_dot) {
861 5350 : memcpy(pathreal, dname, talloc_get_size(dname));
862 : } else {
863 5295 : memcpy(pathreal, dpath, pathlen);
864 5295 : pathreal[pathlen] = '/';
865 5295 : memcpy(pathreal + slashlen + pathlen, dname,
866 : talloc_get_size(dname));
867 : }
868 :
869 : /* Create smb_fname with NULL stream_name. */
870 10645 : smb_fname = synthetic_smb_fname(talloc_tos(),
871 : pathreal,
872 : NULL,
873 : &sbuf,
874 10645 : dirptr->smb_dname->twrp,
875 10645 : dirptr->smb_dname->flags);
876 10645 : TALLOC_FREE(pathreal);
877 10645 : if (smb_fname == NULL) {
878 0 : TALLOC_FREE(dname);
879 0 : TALLOC_FREE(fname);
880 0 : return false;
881 : }
882 :
883 10645 : if (!VALID_STAT(smb_fname->st)) {
884 : /*
885 : * If stat() fails with ENOENT it might be a
886 : * msdfs-symlink in Windows context, this is checked
887 : * below, for now we just want to fill stat info as good
888 : * as we can.
889 : */
890 4464 : ret = vfs_stat(conn, smb_fname);
891 4464 : if (ret != 0 && errno != ENOENT) {
892 0 : TALLOC_FREE(smb_fname);
893 0 : TALLOC_FREE(dname);
894 0 : TALLOC_FREE(fname);
895 0 : continue;
896 : }
897 : }
898 :
899 : /* Create smb_fname with NULL stream_name. */
900 10645 : atname = synthetic_smb_fname(talloc_tos(),
901 : dname,
902 : NULL,
903 10645 : &smb_fname->st,
904 10645 : dirptr->smb_dname->twrp,
905 10645 : dirptr->smb_dname->flags);
906 10645 : if (atname == NULL) {
907 0 : TALLOC_FREE(dname);
908 0 : TALLOC_FREE(fname);
909 0 : TALLOC_FREE(smb_fname);
910 0 : return false;
911 : }
912 :
913 : /*
914 : * openat_pathref_fsp() will return
915 : * NT_STATUS_OBJECT_NAME_NOT_FOUND in non-POSIX context when
916 : * hitting a dangling symlink. It may be a DFS symlink, this is
917 : * checked below by the mode_fn() call, so we have to allow this
918 : * here.
919 : *
920 : * NT_STATUS_STOPPED_ON_SYMLINK is returned in POSIX context
921 : * when hitting a symlink and ensures we always return directory
922 : * entries that are symlinks in POSIX context.
923 : */
924 10645 : status = openat_pathref_fsp(dirptr->dir_hnd->fsp, atname);
925 10645 : if (!NT_STATUS_IS_OK(status) &&
926 80 : !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
927 : {
928 0 : TALLOC_FREE(atname);
929 0 : TALLOC_FREE(dname);
930 0 : TALLOC_FREE(fname);
931 0 : TALLOC_FREE(smb_fname);
932 0 : continue;
933 : }
934 :
935 10645 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
936 80 : if (!(atname->flags & SMB_FILENAME_POSIX_PATH)) {
937 80 : check_dfs_symlink = true;
938 : }
939 : /*
940 : * Check if it's a symlink. We only want to return this
941 : * if it's a DFS symlink or in POSIX mode. Disable
942 : * getting dosmode in the mode_fn() and prime the mode
943 : * as FILE_ATTRIBUTE_NORMAL.
944 : */
945 80 : mode = FILE_ATTRIBUTE_NORMAL;
946 80 : get_dosmode = false;
947 : }
948 :
949 10645 : status = move_smb_fname_fsp_link(smb_fname, atname);
950 10645 : if (!NT_STATUS_IS_OK(status)) {
951 0 : DBG_WARNING("Failed to move pathref for [%s]: %s\n",
952 : smb_fname_str_dbg(smb_fname),
953 : nt_errstr(status));
954 0 : TALLOC_FREE(atname);
955 0 : TALLOC_FREE(smb_fname);
956 0 : TALLOC_FREE(dname);
957 0 : TALLOC_FREE(fname);
958 0 : continue;
959 : }
960 :
961 10645 : if (!is_visible_fsp(smb_fname->fsp)) {
962 0 : TALLOC_FREE(atname);
963 0 : TALLOC_FREE(smb_fname);
964 0 : TALLOC_FREE(dname);
965 0 : TALLOC_FREE(fname);
966 0 : continue;
967 : }
968 :
969 : /*
970 : * Don't leak metadata about the containing
971 : * directory of the share.
972 : */
973 10645 : if (dirptr_path_is_dot && ISDOTDOT(dname)) {
974 : /*
975 : * Making a copy here, then freeing
976 : * the original will close the smb_fname->fsp.
977 : */
978 : struct smb_filename *tmp_smb_fname =
979 422 : cp_smb_filename(ctx, smb_fname);
980 :
981 422 : if (tmp_smb_fname == NULL) {
982 0 : TALLOC_FREE(atname);
983 0 : TALLOC_FREE(smb_fname);
984 0 : TALLOC_FREE(dname);
985 0 : TALLOC_FREE(fname);
986 0 : return false;
987 : }
988 422 : TALLOC_FREE(smb_fname);
989 422 : smb_fname = tmp_smb_fname;
990 422 : mode = FILE_ATTRIBUTE_DIRECTORY;
991 422 : get_dosmode = false;
992 :
993 : /* Ensure posix fileid and sids are hidden
994 : */
995 422 : smb_fname->st.st_ex_ino = 0;
996 422 : smb_fname->st.st_ex_dev = 0;
997 422 : smb_fname->st.st_ex_uid = -1;
998 422 : smb_fname->st.st_ex_gid = -1;
999 : }
1000 :
1001 10645 : ok = mode_fn(ctx,
1002 : private_data,
1003 10645 : dirptr->dir_hnd->fsp,
1004 : atname,
1005 : smb_fname,
1006 : get_dosmode,
1007 : &mode);
1008 10645 : if (!ok) {
1009 20 : TALLOC_FREE(atname);
1010 20 : TALLOC_FREE(smb_fname);
1011 20 : TALLOC_FREE(dname);
1012 20 : TALLOC_FREE(fname);
1013 20 : continue;
1014 : }
1015 :
1016 10625 : TALLOC_FREE(atname);
1017 :
1018 : /*
1019 : * The only valid cases where we return the directory entry if
1020 : * it's a symlink are:
1021 : *
1022 : * 1. POSIX context, always return it, or
1023 : *
1024 : * 2. a DFS symlink where the mode_fn() call above has verified
1025 : * this and set mode to FILE_ATTRIBUTE_REPARSE_POINT.
1026 : */
1027 10625 : if (check_dfs_symlink &&
1028 60 : !(mode & FILE_ATTRIBUTE_REPARSE_POINT))
1029 : {
1030 4 : TALLOC_FREE(smb_fname);
1031 4 : TALLOC_FREE(dname);
1032 4 : TALLOC_FREE(fname);
1033 4 : continue;
1034 : }
1035 :
1036 10621 : if (!dir_check_ftype(mode, dirtype)) {
1037 0 : DEBUG(5,("[%s] attribs 0x%x didn't match 0x%x\n",
1038 : fname, (unsigned int)mode, (unsigned int)dirtype));
1039 0 : TALLOC_FREE(smb_fname);
1040 0 : TALLOC_FREE(dname);
1041 0 : TALLOC_FREE(fname);
1042 0 : continue;
1043 : }
1044 :
1045 10621 : if (ask_sharemode && !S_ISDIR(smb_fname->st.st_ex_mode)) {
1046 : struct timespec write_time_ts;
1047 : struct file_id fileid;
1048 :
1049 916 : fileid = vfs_file_id_from_sbuf(conn,
1050 916 : &smb_fname->st);
1051 916 : get_file_infos(fileid, 0, NULL, &write_time_ts);
1052 916 : if (!is_omit_timespec(&write_time_ts)) {
1053 0 : update_stat_ex_mtime(&smb_fname->st,
1054 : write_time_ts);
1055 : }
1056 : }
1057 :
1058 10621 : DEBUG(3,("smbd_dirptr_get_entry mask=[%s] found %s "
1059 : "fname=%s (%s)\n",
1060 : mask, smb_fname_str_dbg(smb_fname),
1061 : dname, fname));
1062 :
1063 10621 : if (!conn->sconn->using_smb2) {
1064 : /*
1065 : * The dircache is only needed for SMB1 because SMB1
1066 : * uses a name for the resume wheras SMB2 always
1067 : * continues from the next position (unless it's told to
1068 : * restart or close-and-reopen the listing).
1069 : */
1070 0 : DirCacheAdd(dirptr->dir_hnd, dname, cur_offset);
1071 : }
1072 :
1073 10621 : TALLOC_FREE(dname);
1074 :
1075 10621 : *_smb_fname = talloc_move(ctx, &smb_fname);
1076 10621 : if (*_smb_fname == NULL) {
1077 0 : return false;
1078 : }
1079 10621 : *_fname = fname;
1080 10621 : *_mode = mode;
1081 10621 : *_prev_offset = prev_offset;
1082 :
1083 10621 : return true;
1084 : }
1085 :
1086 : return false;
1087 : }
1088 :
1089 : /****************************************************************************
1090 : Get an 8.3 directory entry.
1091 : ****************************************************************************/
1092 :
1093 0 : static bool smbd_dirptr_8_3_match_fn(TALLOC_CTX *ctx,
1094 : void *private_data,
1095 : const char *dname,
1096 : const char *mask,
1097 : char **_fname)
1098 : {
1099 0 : connection_struct *conn = (connection_struct *)private_data;
1100 :
1101 0 : if ((strcmp(mask,"*.*") == 0) ||
1102 0 : mask_match_search(dname, mask, false) ||
1103 0 : mangle_mask_match(conn, dname, mask)) {
1104 : char mname[13];
1105 : const char *fname;
1106 : /*
1107 : * Ensure we can push the original name as UCS2. If
1108 : * not, then just don't return this name.
1109 : */
1110 : NTSTATUS status;
1111 0 : size_t ret_len = 0;
1112 0 : size_t len = (strlen(dname) + 2) * 4; /* Allow enough space. */
1113 0 : uint8_t *tmp = talloc_array(talloc_tos(),
1114 : uint8_t,
1115 : len);
1116 :
1117 0 : status = srvstr_push(NULL,
1118 : FLAGS2_UNICODE_STRINGS,
1119 : tmp,
1120 : dname,
1121 : len,
1122 : STR_TERMINATE,
1123 : &ret_len);
1124 :
1125 0 : TALLOC_FREE(tmp);
1126 :
1127 0 : if (!NT_STATUS_IS_OK(status)) {
1128 0 : return false;
1129 : }
1130 :
1131 0 : if (!mangle_is_8_3(dname, false, conn->params)) {
1132 0 : bool ok = name_to_8_3(dname, mname, false,
1133 0 : conn->params);
1134 0 : if (!ok) {
1135 0 : return false;
1136 : }
1137 0 : fname = mname;
1138 : } else {
1139 0 : fname = dname;
1140 : }
1141 :
1142 0 : *_fname = talloc_strdup(ctx, fname);
1143 0 : if (*_fname == NULL) {
1144 0 : return false;
1145 : }
1146 :
1147 0 : return true;
1148 : }
1149 :
1150 0 : return false;
1151 : }
1152 :
1153 0 : static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
1154 : void *private_data,
1155 : struct files_struct *dirfsp,
1156 : struct smb_filename *atname,
1157 : struct smb_filename *smb_fname,
1158 : bool get_dosmode,
1159 : uint32_t *_mode)
1160 : {
1161 0 : connection_struct *conn = (connection_struct *)private_data;
1162 :
1163 0 : if (!VALID_STAT(smb_fname->st)) {
1164 0 : if ((SMB_VFS_STAT(conn, smb_fname)) != 0) {
1165 0 : DEBUG(5,("smbd_dirptr_8_3_mode_fn: "
1166 : "Couldn't stat [%s]. Error "
1167 : "= %s\n",
1168 : smb_fname_str_dbg(smb_fname),
1169 : strerror(errno)));
1170 0 : return false;
1171 : }
1172 : }
1173 :
1174 0 : if (get_dosmode) {
1175 0 : *_mode = fdos_mode(smb_fname->fsp);
1176 0 : smb_fname->st = smb_fname->fsp->fsp_name->st;
1177 : }
1178 0 : return true;
1179 : }
1180 :
1181 0 : bool get_dir_entry(TALLOC_CTX *ctx,
1182 : struct dptr_struct *dirptr,
1183 : const char *mask,
1184 : uint32_t dirtype,
1185 : char **_fname,
1186 : off_t *_size,
1187 : uint32_t *_mode,
1188 : struct timespec *_date,
1189 : bool check_descend,
1190 : bool ask_sharemode)
1191 : {
1192 0 : connection_struct *conn = dirptr->conn;
1193 0 : char *fname = NULL;
1194 0 : struct smb_filename *smb_fname = NULL;
1195 0 : uint32_t mode = 0;
1196 : long prev_offset;
1197 : bool ok;
1198 :
1199 0 : ok = smbd_dirptr_get_entry(ctx,
1200 : dirptr,
1201 : mask,
1202 : dirtype,
1203 : check_descend,
1204 : ask_sharemode,
1205 : true,
1206 : smbd_dirptr_8_3_match_fn,
1207 : smbd_dirptr_8_3_mode_fn,
1208 : conn,
1209 : &fname,
1210 : &smb_fname,
1211 : &mode,
1212 : &prev_offset);
1213 0 : if (!ok) {
1214 0 : return false;
1215 : }
1216 :
1217 0 : *_fname = talloc_move(ctx, &fname);
1218 0 : *_size = smb_fname->st.st_ex_size;
1219 0 : *_mode = mode;
1220 0 : *_date = smb_fname->st.st_ex_mtime;
1221 0 : TALLOC_FREE(smb_fname);
1222 0 : return true;
1223 : }
1224 :
1225 : /*******************************************************************
1226 : Check to see if a user can read an fsp . This is only approximate,
1227 : it is used as part of the "hide unreadable" option. Don't
1228 : use it for anything security sensitive.
1229 : ********************************************************************/
1230 :
1231 0 : static bool user_can_read_fsp(struct files_struct *fsp)
1232 : {
1233 : NTSTATUS status;
1234 0 : uint32_t rejected_share_access = 0;
1235 0 : uint32_t rejected_mask = 0;
1236 0 : struct security_descriptor *sd = NULL;
1237 0 : uint32_t access_mask = FILE_READ_DATA|
1238 : FILE_READ_EA|
1239 : FILE_READ_ATTRIBUTES|
1240 : SEC_STD_READ_CONTROL;
1241 :
1242 : /*
1243 : * Never hide files from the root user.
1244 : * We use (uid_t)0 here not sec_initial_uid()
1245 : * as make test uses a single user context.
1246 : */
1247 :
1248 0 : if (get_current_uid(fsp->conn) == (uid_t)0) {
1249 0 : return true;
1250 : }
1251 :
1252 : /*
1253 : * We can't directly use smbd_check_access_rights_fsp()
1254 : * here, as this implicitly grants FILE_READ_ATTRIBUTES
1255 : * which the Windows access-based-enumeration code
1256 : * explicitly checks for on the file security descriptor.
1257 : * See bug:
1258 : *
1259 : * https://bugzilla.samba.org/show_bug.cgi?id=10252
1260 : *
1261 : * and the smb2.acl2.ACCESSBASED test for details.
1262 : */
1263 :
1264 0 : rejected_share_access = access_mask & ~(fsp->conn->share_access);
1265 0 : if (rejected_share_access) {
1266 0 : DBG_DEBUG("rejected share access 0x%x "
1267 : "on %s (0x%x)\n",
1268 : (unsigned int)access_mask,
1269 : fsp_str_dbg(fsp),
1270 : (unsigned int)rejected_share_access);
1271 0 : return false;
1272 : }
1273 :
1274 0 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(fsp),
1275 : (SECINFO_OWNER |
1276 : SECINFO_GROUP |
1277 : SECINFO_DACL),
1278 : talloc_tos(),
1279 : &sd);
1280 :
1281 0 : if (!NT_STATUS_IS_OK(status)) {
1282 0 : DBG_DEBUG("Could not get acl "
1283 : "on %s: %s\n",
1284 : fsp_str_dbg(fsp),
1285 : nt_errstr(status));
1286 0 : return false;
1287 : }
1288 :
1289 0 : status = se_file_access_check(sd,
1290 0 : get_current_nttok(fsp->conn),
1291 : false,
1292 : access_mask,
1293 : &rejected_mask);
1294 :
1295 0 : TALLOC_FREE(sd);
1296 :
1297 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1298 0 : DBG_DEBUG("rejected bits 0x%x read access for %s\n",
1299 : (unsigned int)rejected_mask,
1300 : fsp_str_dbg(fsp));
1301 0 : return false;
1302 : }
1303 0 : return true;
1304 : }
1305 :
1306 : /*******************************************************************
1307 : Check to see if a user can write to an fsp.
1308 : Always return true for directories.
1309 : This is only approximate,
1310 : it is used as part of the "hide unwriteable" option. Don't
1311 : use it for anything security sensitive.
1312 : ********************************************************************/
1313 :
1314 0 : static bool user_can_write_fsp(struct files_struct *fsp)
1315 : {
1316 : /*
1317 : * Never hide files from the root user.
1318 : * We use (uid_t)0 here not sec_initial_uid()
1319 : * as make test uses a single user context.
1320 : */
1321 :
1322 0 : if (get_current_uid(fsp->conn) == (uid_t)0) {
1323 0 : return true;
1324 : }
1325 :
1326 0 : if (fsp->fsp_flags.is_directory) {
1327 0 : return true;
1328 : }
1329 :
1330 0 : return can_write_to_fsp(fsp);
1331 : }
1332 :
1333 : /*******************************************************************
1334 : Is a file a "special" type ?
1335 : ********************************************************************/
1336 :
1337 0 : static bool file_is_special(connection_struct *conn,
1338 : const struct smb_filename *smb_fname)
1339 : {
1340 : /*
1341 : * Never hide files from the root user.
1342 : * We use (uid_t)0 here not sec_initial_uid()
1343 : * as make test uses a single user context.
1344 : */
1345 :
1346 0 : if (get_current_uid(conn) == (uid_t)0) {
1347 0 : return False;
1348 : }
1349 :
1350 0 : SMB_ASSERT(VALID_STAT(smb_fname->st));
1351 :
1352 0 : if (S_ISREG(smb_fname->st.st_ex_mode) ||
1353 0 : S_ISDIR(smb_fname->st.st_ex_mode) ||
1354 0 : S_ISLNK(smb_fname->st.st_ex_mode))
1355 0 : return False;
1356 :
1357 0 : return True;
1358 : }
1359 :
1360 : /*******************************************************************
1361 : Should the file be seen by the client?
1362 : ********************************************************************/
1363 :
1364 10651 : bool is_visible_fsp(struct files_struct *fsp)
1365 : {
1366 10651 : bool hide_unreadable = false;
1367 10651 : bool hide_unwriteable = false;
1368 10651 : bool hide_special = false;
1369 10651 : int hide_new_files_timeout = 0;
1370 10651 : const char *last_component = NULL;
1371 :
1372 : /*
1373 : * If the file does not exist, there's no point checking
1374 : * the configuration options. We succeed, on the basis that the
1375 : * checks *might* have passed if the file was present.
1376 : */
1377 10651 : if (fsp == NULL) {
1378 80 : return true;
1379 : }
1380 :
1381 10571 : hide_unreadable = lp_hide_unreadable(SNUM(fsp->conn));
1382 10571 : hide_unwriteable = lp_hide_unwriteable_files(SNUM(fsp->conn));
1383 10571 : hide_special = lp_hide_special_files(SNUM(fsp->conn));
1384 10571 : hide_new_files_timeout = lp_hide_new_files_timeout(SNUM(fsp->conn));
1385 :
1386 10571 : if (!hide_unreadable &&
1387 10571 : !hide_unwriteable &&
1388 10571 : !hide_special &&
1389 : (hide_new_files_timeout == 0))
1390 : {
1391 10571 : return true;
1392 : }
1393 :
1394 0 : fsp = metadata_fsp(fsp);
1395 :
1396 : /* Get the last component of the base name. */
1397 0 : last_component = strrchr_m(fsp->fsp_name->base_name, '/');
1398 0 : if (!last_component) {
1399 0 : last_component = fsp->fsp_name->base_name;
1400 : } else {
1401 0 : last_component++; /* Go past '/' */
1402 : }
1403 :
1404 0 : if (ISDOT(last_component) || ISDOTDOT(last_component)) {
1405 0 : return true; /* . and .. are always visible. */
1406 : }
1407 :
1408 0 : if (fsp_get_pathref_fd(fsp) == -1) {
1409 : /*
1410 : * Symlink in POSIX mode or MS-DFS.
1411 : * We've checked veto files so the
1412 : * only thing we can check is the
1413 : * hide_new_files_timeout.
1414 : */
1415 0 : if ((hide_new_files_timeout != 0) &&
1416 0 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1417 0 : double age = timespec_elapsed(
1418 0 : &fsp->fsp_name->st.st_ex_mtime);
1419 :
1420 0 : if (age < (double)hide_new_files_timeout) {
1421 0 : return false;
1422 : }
1423 : }
1424 0 : return true;
1425 : }
1426 :
1427 : /* Honour _hide unreadable_ option */
1428 0 : if (hide_unreadable && !user_can_read_fsp(fsp)) {
1429 0 : DBG_DEBUG("file %s is unreadable.\n", fsp_str_dbg(fsp));
1430 0 : return false;
1431 : }
1432 :
1433 : /* Honour _hide unwriteable_ option */
1434 0 : if (hide_unwriteable && !user_can_write_fsp(fsp)) {
1435 0 : DBG_DEBUG("file %s is unwritable.\n", fsp_str_dbg(fsp));
1436 0 : return false;
1437 : }
1438 :
1439 : /* Honour _hide_special_ option */
1440 0 : if (hide_special && file_is_special(fsp->conn, fsp->fsp_name)) {
1441 0 : DBG_DEBUG("file %s is special.\n", fsp_str_dbg(fsp));
1442 0 : return false;
1443 : }
1444 :
1445 0 : if ((hide_new_files_timeout != 0) &&
1446 0 : !S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
1447 0 : double age = timespec_elapsed(&fsp->fsp_name->st.st_ex_mtime);
1448 :
1449 0 : if (age < (double)hide_new_files_timeout) {
1450 0 : return false;
1451 : }
1452 : }
1453 :
1454 0 : return true;
1455 : }
1456 :
1457 6397 : static int smb_Dir_destructor(struct smb_Dir *dir_hnd)
1458 : {
1459 6397 : files_struct *fsp = dir_hnd->fsp;
1460 :
1461 6397 : SMB_VFS_CLOSEDIR(dir_hnd->conn, dir_hnd->dir);
1462 6397 : fsp_set_fd(fsp, -1);
1463 6397 : if (fsp->dptr != NULL) {
1464 2171 : SMB_ASSERT(fsp->dptr->dir_hnd == dir_hnd);
1465 2171 : fsp->dptr->dir_hnd = NULL;
1466 : }
1467 6397 : dir_hnd->fsp = NULL;
1468 6397 : return 0;
1469 : }
1470 :
1471 : /*******************************************************************
1472 : Open a directory.
1473 : ********************************************************************/
1474 :
1475 4226 : static int smb_Dir_OpenDir_destructor(struct smb_Dir *dir_hnd)
1476 : {
1477 4226 : files_struct *fsp = dir_hnd->fsp;
1478 :
1479 4226 : smb_Dir_destructor(dir_hnd);
1480 4226 : file_free(NULL, fsp);
1481 4226 : return 0;
1482 : }
1483 :
1484 846 : NTSTATUS OpenDir(TALLOC_CTX *mem_ctx,
1485 : connection_struct *conn,
1486 : const struct smb_filename *smb_dname,
1487 : const char *mask,
1488 : uint32_t attr,
1489 : struct smb_Dir **_dir_hnd)
1490 : {
1491 846 : struct files_struct *fsp = NULL;
1492 846 : struct smb_Dir *dir_hnd = NULL;
1493 : NTSTATUS status;
1494 :
1495 846 : status = open_internal_dirfsp(conn,
1496 : smb_dname,
1497 : O_RDONLY,
1498 : &fsp);
1499 846 : if (!NT_STATUS_IS_OK(status)) {
1500 0 : return status;
1501 : }
1502 :
1503 846 : status = OpenDir_fsp(mem_ctx, conn, fsp, mask, attr, &dir_hnd);
1504 846 : if (!NT_STATUS_IS_OK(status)) {
1505 0 : return status;
1506 : }
1507 :
1508 : /*
1509 : * This overwrites the destructor set by OpenDir_fsp() but
1510 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1511 : * destructor.
1512 : */
1513 846 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1514 :
1515 846 : *_dir_hnd = dir_hnd;
1516 846 : return NT_STATUS_OK;
1517 : }
1518 :
1519 3380 : NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
1520 : struct files_struct *dirfsp,
1521 : const char *mask,
1522 : uint32_t attr,
1523 : struct smb_Dir **_dir_hnd)
1524 : {
1525 3380 : struct files_struct *fsp = NULL;
1526 3380 : struct smb_Dir *dir_hnd = NULL;
1527 : NTSTATUS status;
1528 :
1529 3380 : status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
1530 3380 : if (!NT_STATUS_IS_OK(status)) {
1531 0 : return status;
1532 : }
1533 :
1534 3380 : status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
1535 3380 : if (!NT_STATUS_IS_OK(status)) {
1536 0 : return status;
1537 : }
1538 :
1539 : /*
1540 : * This overwrites the destructor set by OpenDir_fsp() but
1541 : * smb_Dir_OpenDir_destructor() calls the OpenDir_fsp()
1542 : * destructor.
1543 : */
1544 3380 : talloc_set_destructor(dir_hnd, smb_Dir_OpenDir_destructor);
1545 :
1546 3380 : *_dir_hnd = dir_hnd;
1547 3380 : return NT_STATUS_OK;
1548 : }
1549 :
1550 : /*******************************************************************
1551 : Open a directory from an fsp.
1552 : ********************************************************************/
1553 :
1554 6397 : static NTSTATUS OpenDir_fsp(
1555 : TALLOC_CTX *mem_ctx,
1556 : connection_struct *conn,
1557 : files_struct *fsp,
1558 : const char *mask,
1559 : uint32_t attr,
1560 : struct smb_Dir **_dir_hnd)
1561 : {
1562 6397 : struct smb_Dir *dir_hnd = talloc_zero(mem_ctx, struct smb_Dir);
1563 : NTSTATUS status;
1564 :
1565 6397 : if (!dir_hnd) {
1566 0 : return NT_STATUS_NO_MEMORY;
1567 : }
1568 :
1569 6397 : if (!fsp->fsp_flags.is_directory) {
1570 0 : status = NT_STATUS_INVALID_HANDLE;
1571 0 : goto fail;
1572 : }
1573 :
1574 6397 : if (fsp_get_io_fd(fsp) == -1) {
1575 0 : status = NT_STATUS_INVALID_HANDLE;
1576 0 : goto fail;
1577 : }
1578 :
1579 6397 : dir_hnd->conn = conn;
1580 :
1581 6397 : if (!conn->sconn->using_smb2) {
1582 : /*
1583 : * The dircache is only needed for SMB1 because SMB1 uses a name
1584 : * for the resume wheras SMB2 always continues from the next
1585 : * position (unless it's told to restart or close-and-reopen the
1586 : * listing).
1587 : */
1588 836 : dir_hnd->name_cache_size =
1589 836 : lp_directory_name_cache_size(SNUM(conn));
1590 : }
1591 :
1592 6397 : dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, fsp->fsp_name);
1593 6397 : if (!dir_hnd->dir_smb_fname) {
1594 0 : status = NT_STATUS_NO_MEMORY;
1595 0 : goto fail;
1596 : }
1597 :
1598 6397 : dir_hnd->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1599 6397 : if (dir_hnd->dir == NULL) {
1600 0 : status = map_nt_error_from_unix(errno);
1601 0 : goto fail;
1602 : }
1603 6397 : dir_hnd->fsp = fsp;
1604 6397 : if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
1605 0 : dir_hnd->case_sensitive = true;
1606 : } else {
1607 6397 : dir_hnd->case_sensitive = conn->case_sensitive;
1608 : }
1609 :
1610 6397 : talloc_set_destructor(dir_hnd, smb_Dir_destructor);
1611 :
1612 6397 : *_dir_hnd = dir_hnd;
1613 6397 : return NT_STATUS_OK;
1614 :
1615 0 : fail:
1616 0 : TALLOC_FREE(dir_hnd);
1617 0 : return status;
1618 : }
1619 :
1620 :
1621 : /*******************************************************************
1622 : Read from a directory.
1623 : Return directory entry, current offset, and optional stat information.
1624 : Don't check for veto or invisible files.
1625 : ********************************************************************/
1626 :
1627 39101 : const char *ReadDirName(struct smb_Dir *dir_hnd, long *poffset,
1628 : SMB_STRUCT_STAT *sbuf, char **ptalloced)
1629 : {
1630 : const char *n;
1631 39101 : char *talloced = NULL;
1632 39101 : connection_struct *conn = dir_hnd->conn;
1633 :
1634 : /* Cheat to allow . and .. to be the first entries returned. */
1635 39101 : if (((*poffset == START_OF_DIRECTORY_OFFSET) ||
1636 26533 : (*poffset == DOT_DOT_DIRECTORY_OFFSET)) &&
1637 18852 : (dir_hnd->file_number < 2))
1638 : {
1639 12568 : if (dir_hnd->file_number == 0) {
1640 6284 : n = ".";
1641 6284 : *poffset = dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1642 : } else {
1643 6284 : n = "..";
1644 6284 : *poffset = dir_hnd->offset = DOT_DOT_DIRECTORY_OFFSET;
1645 : }
1646 12568 : dir_hnd->file_number++;
1647 12568 : *ptalloced = NULL;
1648 12568 : return n;
1649 : }
1650 :
1651 26533 : if (*poffset == END_OF_DIRECTORY_OFFSET) {
1652 2241 : *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1653 2241 : return NULL;
1654 : }
1655 :
1656 : /* A real offset, seek to it. */
1657 24292 : SeekDir(dir_hnd, *poffset);
1658 :
1659 33866 : while ((n = vfs_readdirname(conn, dir_hnd->fsp, dir_hnd->dir, sbuf, &talloced))) {
1660 : /* Ignore . and .. - we've already returned them. */
1661 29091 : if (ISDOT(n) || ISDOTDOT(n)) {
1662 9574 : TALLOC_FREE(talloced);
1663 9574 : continue;
1664 : }
1665 19517 : *poffset = dir_hnd->offset = SMB_VFS_TELLDIR(conn, dir_hnd->dir);
1666 19517 : *ptalloced = talloced;
1667 19517 : dir_hnd->file_number++;
1668 19517 : return n;
1669 : }
1670 4775 : *poffset = dir_hnd->offset = END_OF_DIRECTORY_OFFSET;
1671 4775 : *ptalloced = NULL;
1672 4775 : return NULL;
1673 : }
1674 :
1675 : /*******************************************************************
1676 : Rewind to the start.
1677 : ********************************************************************/
1678 :
1679 0 : void RewindDir(struct smb_Dir *dir_hnd, long *poffset)
1680 : {
1681 0 : SMB_VFS_REWINDDIR(dir_hnd->conn, dir_hnd->dir);
1682 0 : dir_hnd->file_number = 0;
1683 0 : dir_hnd->offset = START_OF_DIRECTORY_OFFSET;
1684 0 : *poffset = START_OF_DIRECTORY_OFFSET;
1685 0 : }
1686 :
1687 : /*******************************************************************
1688 : Seek a dir.
1689 : ********************************************************************/
1690 :
1691 24292 : void SeekDir(struct smb_Dir *dirp, long offset)
1692 : {
1693 24292 : if (offset != dirp->offset) {
1694 0 : if (offset == START_OF_DIRECTORY_OFFSET) {
1695 0 : RewindDir(dirp, &offset);
1696 : /*
1697 : * Ok we should really set the file number here
1698 : * to 1 to enable ".." to be returned next. Trouble
1699 : * is I'm worried about callers using SeekDir(dirp,0)
1700 : * as equivalent to RewindDir(). So leave this alone
1701 : * for now.
1702 : */
1703 0 : } else if (offset == DOT_DOT_DIRECTORY_OFFSET) {
1704 0 : RewindDir(dirp, &offset);
1705 : /*
1706 : * Set the file number to 2 - we want to get the first
1707 : * real file entry (the one we return after "..")
1708 : * on the next ReadDir.
1709 : */
1710 0 : dirp->file_number = 2;
1711 0 : } else if (offset == END_OF_DIRECTORY_OFFSET) {
1712 : ; /* Don't seek in this case. */
1713 : } else {
1714 0 : SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset);
1715 : }
1716 0 : dirp->offset = offset;
1717 : }
1718 24292 : }
1719 :
1720 : /*******************************************************************
1721 : Tell a dir position.
1722 : ********************************************************************/
1723 :
1724 15947 : long TellDir(struct smb_Dir *dir_hnd)
1725 : {
1726 15947 : return(dir_hnd->offset);
1727 : }
1728 :
1729 : /*******************************************************************
1730 : Add an entry into the dcache.
1731 : ********************************************************************/
1732 :
1733 0 : static void DirCacheAdd(struct smb_Dir *dir_hnd, const char *name, long offset)
1734 : {
1735 : struct name_cache_entry *e;
1736 :
1737 0 : if (dir_hnd->name_cache_size == 0) {
1738 0 : return;
1739 : }
1740 :
1741 0 : if (dir_hnd->name_cache == NULL) {
1742 0 : dir_hnd->name_cache = talloc_zero_array(dir_hnd,
1743 : struct name_cache_entry,
1744 : dir_hnd->name_cache_size);
1745 :
1746 0 : if (dir_hnd->name_cache == NULL) {
1747 0 : return;
1748 : }
1749 : }
1750 :
1751 0 : dir_hnd->name_cache_index = (dir_hnd->name_cache_index+1) %
1752 0 : dir_hnd->name_cache_size;
1753 0 : e = &dir_hnd->name_cache[dir_hnd->name_cache_index];
1754 0 : TALLOC_FREE(e->name);
1755 0 : e->name = talloc_strdup(dir_hnd, name);
1756 0 : e->offset = offset;
1757 : }
1758 :
1759 : /*******************************************************************
1760 : Find an entry by name. Leave us at the offset after it.
1761 : Don't check for veto or invisible files.
1762 : ********************************************************************/
1763 :
1764 0 : static bool SearchDir(struct smb_Dir *dir_hnd, const char *name, long *poffset)
1765 : {
1766 : int i;
1767 0 : const char *entry = NULL;
1768 0 : char *talloced = NULL;
1769 0 : connection_struct *conn = dir_hnd->conn;
1770 :
1771 : /* Search back in the name cache. */
1772 0 : if (dir_hnd->name_cache_size && dir_hnd->name_cache) {
1773 0 : for (i = dir_hnd->name_cache_index; i >= 0; i--) {
1774 0 : struct name_cache_entry *e = &dir_hnd->name_cache[i];
1775 0 : if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1776 0 : *poffset = e->offset;
1777 0 : SeekDir(dir_hnd, e->offset);
1778 0 : return True;
1779 : }
1780 : }
1781 0 : for (i = dir_hnd->name_cache_size - 1;
1782 0 : i > dir_hnd->name_cache_index; i--) {
1783 0 : struct name_cache_entry *e = &dir_hnd->name_cache[i];
1784 0 : if (e->name && (dir_hnd->case_sensitive ? (strcmp(e->name, name) == 0) : strequal(e->name, name))) {
1785 0 : *poffset = e->offset;
1786 0 : SeekDir(dir_hnd, e->offset);
1787 0 : return True;
1788 : }
1789 : }
1790 : }
1791 :
1792 : /* Not found in the name cache. Rewind directory and start from scratch. */
1793 0 : SMB_VFS_REWINDDIR(conn, dir_hnd->dir);
1794 0 : dir_hnd->file_number = 0;
1795 0 : *poffset = START_OF_DIRECTORY_OFFSET;
1796 0 : while ((entry = ReadDirName(dir_hnd, poffset, NULL, &talloced))) {
1797 0 : if (dir_hnd->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) {
1798 0 : TALLOC_FREE(talloced);
1799 0 : return True;
1800 : }
1801 0 : TALLOC_FREE(talloced);
1802 : }
1803 0 : return False;
1804 : }
1805 :
1806 : struct files_below_forall_state {
1807 : char *dirpath;
1808 : ssize_t dirpath_len;
1809 : int (*fn)(struct file_id fid, const struct share_mode_data *data,
1810 : void *private_data);
1811 : void *private_data;
1812 : };
1813 :
1814 132 : static int files_below_forall_fn(struct file_id fid,
1815 : const struct share_mode_data *data,
1816 : void *private_data)
1817 : {
1818 132 : struct files_below_forall_state *state = private_data;
1819 : char tmpbuf[PATH_MAX];
1820 : char *fullpath, *to_free;
1821 : ssize_t len;
1822 :
1823 132 : len = full_path_tos(data->servicepath, data->base_name,
1824 : tmpbuf, sizeof(tmpbuf),
1825 : &fullpath, &to_free);
1826 132 : if (len == -1) {
1827 0 : return 0;
1828 : }
1829 132 : if (state->dirpath_len >= len) {
1830 : /*
1831 : * Filter files above dirpath
1832 : */
1833 128 : goto out;
1834 : }
1835 4 : if (fullpath[state->dirpath_len] != '/') {
1836 : /*
1837 : * Filter file that don't have a path separator at the end of
1838 : * dirpath's length
1839 : */
1840 4 : goto out;
1841 : }
1842 :
1843 0 : if (memcmp(state->dirpath, fullpath, state->dirpath_len) != 0) {
1844 : /*
1845 : * Not a parent
1846 : */
1847 0 : goto out;
1848 : }
1849 :
1850 0 : TALLOC_FREE(to_free);
1851 0 : return state->fn(fid, data, state->private_data);
1852 :
1853 132 : out:
1854 132 : TALLOC_FREE(to_free);
1855 132 : return 0;
1856 : }
1857 :
1858 104 : static int files_below_forall(connection_struct *conn,
1859 : const struct smb_filename *dir_name,
1860 : int (*fn)(struct file_id fid,
1861 : const struct share_mode_data *data,
1862 : void *private_data),
1863 : void *private_data)
1864 : {
1865 104 : struct files_below_forall_state state = {
1866 : .fn = fn,
1867 : .private_data = private_data,
1868 : };
1869 : int ret;
1870 : char tmpbuf[PATH_MAX];
1871 : char *to_free;
1872 :
1873 208 : state.dirpath_len = full_path_tos(conn->connectpath,
1874 104 : dir_name->base_name,
1875 : tmpbuf, sizeof(tmpbuf),
1876 : &state.dirpath, &to_free);
1877 104 : if (state.dirpath_len == -1) {
1878 0 : return -1;
1879 : }
1880 :
1881 104 : ret = share_mode_forall(files_below_forall_fn, &state);
1882 104 : TALLOC_FREE(to_free);
1883 104 : return ret;
1884 : }
1885 :
1886 : struct have_file_open_below_state {
1887 : bool found_one;
1888 : };
1889 :
1890 0 : static int have_file_open_below_fn(struct file_id fid,
1891 : const struct share_mode_data *data,
1892 : void *private_data)
1893 : {
1894 0 : struct have_file_open_below_state *state = private_data;
1895 0 : state->found_one = true;
1896 0 : return 1;
1897 : }
1898 :
1899 104 : bool have_file_open_below(connection_struct *conn,
1900 : const struct smb_filename *name)
1901 : {
1902 104 : struct have_file_open_below_state state = {
1903 : .found_one = false,
1904 : };
1905 : int ret;
1906 :
1907 104 : if (!VALID_STAT(name->st)) {
1908 0 : return false;
1909 : }
1910 104 : if (!S_ISDIR(name->st.st_ex_mode)) {
1911 0 : return false;
1912 : }
1913 :
1914 104 : ret = files_below_forall(conn, name, have_file_open_below_fn, &state);
1915 104 : if (ret == -1) {
1916 0 : return false;
1917 : }
1918 :
1919 104 : return state.found_one;
1920 : }
1921 :
1922 : /*****************************************************************
1923 : Is this directory empty ?
1924 : *****************************************************************/
1925 :
1926 814 : NTSTATUS can_delete_directory_fsp(files_struct *fsp)
1927 : {
1928 814 : NTSTATUS status = NT_STATUS_OK;
1929 814 : long dirpos = 0;
1930 814 : const char *dname = NULL;
1931 814 : char *talloced = NULL;
1932 814 : struct connection_struct *conn = fsp->conn;
1933 814 : struct smb_Dir *dir_hnd = NULL;
1934 :
1935 814 : status = OpenDir(
1936 814 : talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
1937 814 : if (!NT_STATUS_IS_OK(status)) {
1938 0 : return status;
1939 : }
1940 :
1941 2442 : while ((dname = ReadDirName(dir_hnd, &dirpos, NULL, &talloced))) {
1942 1634 : struct smb_filename *smb_dname_full = NULL;
1943 1634 : struct smb_filename *direntry_fname = NULL;
1944 1634 : char *fullname = NULL;
1945 : int ret;
1946 :
1947 1634 : if (ISDOT(dname) || (ISDOTDOT(dname))) {
1948 1628 : TALLOC_FREE(talloced);
1949 1628 : continue;
1950 : }
1951 6 : if (IS_VETO_PATH(conn, dname)) {
1952 0 : TALLOC_FREE(talloced);
1953 0 : continue;
1954 : }
1955 :
1956 6 : fullname = talloc_asprintf(talloc_tos(),
1957 : "%s/%s",
1958 6 : fsp->fsp_name->base_name,
1959 : dname);
1960 6 : if (fullname == NULL) {
1961 0 : status = NT_STATUS_NO_MEMORY;
1962 0 : break;
1963 : }
1964 :
1965 6 : smb_dname_full = synthetic_smb_fname(talloc_tos(),
1966 : fullname,
1967 : NULL,
1968 : NULL,
1969 6 : fsp->fsp_name->twrp,
1970 6 : fsp->fsp_name->flags);
1971 6 : if (smb_dname_full == NULL) {
1972 0 : TALLOC_FREE(talloced);
1973 0 : TALLOC_FREE(fullname);
1974 0 : status = NT_STATUS_NO_MEMORY;
1975 0 : break;
1976 : }
1977 :
1978 6 : ret = SMB_VFS_LSTAT(conn, smb_dname_full);
1979 6 : if (ret != 0) {
1980 0 : status = map_nt_error_from_unix(errno);
1981 0 : TALLOC_FREE(talloced);
1982 0 : TALLOC_FREE(fullname);
1983 0 : TALLOC_FREE(smb_dname_full);
1984 0 : break;
1985 : }
1986 :
1987 6 : if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
1988 : /* Could it be an msdfs link ? */
1989 0 : if (lp_host_msdfs() &&
1990 0 : lp_msdfs_root(SNUM(conn))) {
1991 : struct smb_filename *smb_dname;
1992 0 : smb_dname = synthetic_smb_fname(talloc_tos(),
1993 : dname,
1994 : NULL,
1995 0 : &smb_dname_full->st,
1996 0 : fsp->fsp_name->twrp,
1997 0 : fsp->fsp_name->flags);
1998 0 : if (smb_dname == NULL) {
1999 0 : TALLOC_FREE(talloced);
2000 0 : TALLOC_FREE(fullname);
2001 0 : TALLOC_FREE(smb_dname_full);
2002 0 : status = NT_STATUS_NO_MEMORY;
2003 0 : break;
2004 : }
2005 0 : if (is_msdfs_link(fsp, smb_dname)) {
2006 0 : TALLOC_FREE(talloced);
2007 0 : TALLOC_FREE(fullname);
2008 0 : TALLOC_FREE(smb_dname_full);
2009 0 : TALLOC_FREE(smb_dname);
2010 0 : DBG_DEBUG("got msdfs link name %s "
2011 : "- can't delete directory %s\n",
2012 : dname,
2013 : fsp_str_dbg(fsp));
2014 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2015 0 : break;
2016 : }
2017 0 : TALLOC_FREE(smb_dname);
2018 : }
2019 : /* Not a DFS link - could it be a dangling symlink ? */
2020 0 : ret = SMB_VFS_STAT(conn, smb_dname_full);
2021 0 : if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
2022 : /*
2023 : * Dangling symlink.
2024 : * Allow if "delete veto files = yes"
2025 : */
2026 0 : if (lp_delete_veto_files(SNUM(conn))) {
2027 0 : TALLOC_FREE(talloced);
2028 0 : TALLOC_FREE(fullname);
2029 0 : TALLOC_FREE(smb_dname_full);
2030 0 : continue;
2031 : }
2032 : }
2033 0 : DBG_DEBUG("got symlink name %s - "
2034 : "can't delete directory %s\n",
2035 : dname,
2036 : fsp_str_dbg(fsp));
2037 0 : TALLOC_FREE(talloced);
2038 0 : TALLOC_FREE(fullname);
2039 0 : TALLOC_FREE(smb_dname_full);
2040 0 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2041 0 : break;
2042 : }
2043 :
2044 : /* Not a symlink, get a pathref. */
2045 6 : status = synthetic_pathref(talloc_tos(),
2046 : fsp,
2047 : dname,
2048 : NULL,
2049 6 : &smb_dname_full->st,
2050 6 : fsp->fsp_name->twrp,
2051 6 : fsp->fsp_name->flags,
2052 : &direntry_fname);
2053 6 : if (!NT_STATUS_IS_OK(status)) {
2054 0 : status = map_nt_error_from_unix(errno);
2055 0 : TALLOC_FREE(talloced);
2056 0 : TALLOC_FREE(fullname);
2057 0 : TALLOC_FREE(smb_dname_full);
2058 0 : break;
2059 : }
2060 :
2061 6 : if (!is_visible_fsp(direntry_fname->fsp)) {
2062 : /*
2063 : * Hidden file.
2064 : * Allow if "delete veto files = yes"
2065 : */
2066 0 : if (lp_delete_veto_files(SNUM(conn))) {
2067 0 : TALLOC_FREE(talloced);
2068 0 : TALLOC_FREE(fullname);
2069 0 : TALLOC_FREE(smb_dname_full);
2070 0 : TALLOC_FREE(direntry_fname);
2071 0 : continue;
2072 : }
2073 : }
2074 :
2075 6 : TALLOC_FREE(talloced);
2076 6 : TALLOC_FREE(fullname);
2077 6 : TALLOC_FREE(smb_dname_full);
2078 6 : TALLOC_FREE(direntry_fname);
2079 :
2080 6 : DBG_DEBUG("got name %s - can't delete\n", dname);
2081 6 : status = NT_STATUS_DIRECTORY_NOT_EMPTY;
2082 6 : break;
2083 : }
2084 814 : TALLOC_FREE(talloced);
2085 814 : TALLOC_FREE(dir_hnd);
2086 :
2087 814 : if (!NT_STATUS_IS_OK(status)) {
2088 6 : return status;
2089 : }
2090 :
2091 1616 : if (!(fsp->posix_flags & FSP_POSIX_FLAGS_RENAME) &&
2092 908 : lp_strict_rename(SNUM(conn)) &&
2093 100 : have_file_open_below(fsp->conn, fsp->fsp_name))
2094 : {
2095 0 : return NT_STATUS_ACCESS_DENIED;
2096 : }
2097 :
2098 808 : return NT_STATUS_OK;
2099 : }
|