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