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