Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Files[] structure handling
4 : Copyright (C) Andrew Tridgell 1998
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "smbd/smbd.h"
22 : #include "smbd/globals.h"
23 : #include "smbd/smbXsrv_open.h"
24 : #include "libcli/security/security.h"
25 : #include "util_tdb.h"
26 : #include "lib/util/bitmap.h"
27 : #include "lib/util/strv.h"
28 :
29 : #define FILE_HANDLE_OFFSET 0x1000
30 :
31 : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
32 : struct smb_filename **_smb_fname);
33 :
34 : /**
35 : * create new fsp to be used for file_new or a durable handle reconnect
36 : */
37 146984 : NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
38 : files_struct **result)
39 : {
40 146984 : NTSTATUS status = NT_STATUS_NO_MEMORY;
41 146984 : files_struct *fsp = NULL;
42 146984 : struct smbd_server_connection *sconn = conn->sconn;
43 :
44 146984 : fsp = talloc_zero(mem_ctx, struct files_struct);
45 146984 : if (fsp == NULL) {
46 0 : goto fail;
47 : }
48 :
49 : /*
50 : * This can't be a child of fsp because the file_handle can be ref'd
51 : * when doing a dos/fcb open, which will then share the file_handle
52 : * across multiple fsps.
53 : */
54 146984 : fsp->fh = fd_handle_create(mem_ctx);
55 146984 : if (fsp->fh == NULL) {
56 0 : goto fail;
57 : }
58 :
59 146984 : fsp->fsp_flags.use_ofd_locks = !lp_smbd_force_process_locks(SNUM(conn));
60 : #ifndef HAVE_OFD_LOCKS
61 : fsp->fsp_flags.use_ofd_locks = false;
62 : #endif
63 :
64 146984 : fh_set_refcount(fsp->fh, 1);
65 146984 : fsp_set_fd(fsp, -1);
66 :
67 146984 : fsp->fnum = FNUM_FIELD_INVALID;
68 146984 : fsp->conn = conn;
69 146984 : fsp->close_write_time = make_omit_timespec();
70 :
71 146984 : DLIST_ADD(sconn->files, fsp);
72 146984 : sconn->num_files += 1;
73 :
74 146984 : conn->num_files_open++;
75 :
76 146984 : DBG_INFO("allocated files structure (%u used)\n",
77 : (unsigned int)sconn->num_files);
78 :
79 146984 : *result = fsp;
80 146984 : return NT_STATUS_OK;
81 :
82 0 : fail:
83 0 : if (fsp != NULL) {
84 0 : TALLOC_FREE(fsp->fh);
85 : }
86 0 : TALLOC_FREE(fsp);
87 :
88 0 : return status;
89 : }
90 :
91 123433 : void fsp_set_gen_id(files_struct *fsp)
92 : {
93 : static uint64_t gen_id = 1;
94 :
95 : /*
96 : * A billion of 64-bit increments per second gives us
97 : * more than 500 years of runtime without wrap.
98 : */
99 123433 : gen_id++;
100 123433 : fh_set_gen_id(fsp->fh, gen_id);
101 123433 : }
102 :
103 : /****************************************************************************
104 : Find first available file slot.
105 : ****************************************************************************/
106 :
107 21880 : NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
108 : {
109 21880 : struct smbXsrv_open *op = NULL;
110 : NTTIME now;
111 : NTSTATUS status;
112 :
113 21880 : if (req == NULL) {
114 4306 : DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
115 4306 : return NT_STATUS_OK;
116 : }
117 :
118 17574 : now = timeval_to_nttime(&fsp->open_time);
119 :
120 17574 : status = smbXsrv_open_create(req->xconn,
121 17574 : fsp->conn->session_info,
122 : now,
123 : &op);
124 17574 : if (!NT_STATUS_IS_OK(status)) {
125 0 : return status;
126 : }
127 17574 : fsp->op = op;
128 17574 : op->compat = fsp;
129 17574 : fsp->fnum = op->local_id;
130 :
131 17574 : fsp->mid = req->mid;
132 17574 : req->chain_fsp = fsp;
133 :
134 17574 : DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
135 : fsp_str_dbg(fsp), fsp->mid);
136 :
137 17574 : return NT_STATUS_OK;
138 : }
139 :
140 9471 : NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
141 : files_struct **result)
142 : {
143 9471 : struct smbd_server_connection *sconn = conn->sconn;
144 : files_struct *fsp;
145 : NTSTATUS status;
146 :
147 9471 : status = fsp_new(conn, conn, &fsp);
148 9471 : if (!NT_STATUS_IS_OK(status)) {
149 0 : return status;
150 : }
151 :
152 9471 : GetTimeOfDay(&fsp->open_time);
153 :
154 9471 : status = fsp_bind_smb(fsp, req);
155 9471 : if (!NT_STATUS_IS_OK(status)) {
156 0 : file_free(NULL, fsp);
157 0 : return status;
158 : }
159 :
160 9471 : fsp_set_gen_id(fsp);
161 :
162 : /*
163 : * Create an smb_filename with "" for the base_name. There are very
164 : * few NULL checks, so make sure it's initialized with something. to
165 : * be safe until an audit can be done.
166 : */
167 9471 : fsp->fsp_name = synthetic_smb_fname(fsp,
168 : "",
169 : NULL,
170 : NULL,
171 : 0,
172 : 0);
173 9471 : if (fsp->fsp_name == NULL) {
174 0 : file_free(NULL, fsp);
175 0 : return NT_STATUS_NO_MEMORY;
176 : }
177 :
178 9471 : DBG_INFO("new file %s\n", fsp_fnum_dbg(fsp));
179 :
180 : /* A new fsp invalidates the positive and
181 : negative fsp_fi_cache as the new fsp is pushed
182 : at the start of the list and we search from
183 : a cache hit to the *end* of the list. */
184 :
185 9471 : ZERO_STRUCT(sconn->fsp_fi_cache);
186 :
187 9471 : *result = fsp;
188 9471 : return NT_STATUS_OK;
189 : }
190 :
191 4226 : NTSTATUS create_internal_fsp(connection_struct *conn,
192 : const struct smb_filename *smb_fname,
193 : struct files_struct **_fsp)
194 : {
195 4226 : struct files_struct *fsp = NULL;
196 : NTSTATUS status;
197 :
198 4226 : status = file_new(NULL, conn, &fsp);
199 4226 : if (!NT_STATUS_IS_OK(status)) {
200 0 : return status;
201 : }
202 :
203 4226 : status = fsp_set_smb_fname(fsp, smb_fname);
204 4226 : if (!NT_STATUS_IS_OK(status)) {
205 0 : file_free(NULL, fsp);
206 0 : return status;
207 : }
208 :
209 4226 : *_fsp = fsp;
210 4226 : return NT_STATUS_OK;
211 : }
212 :
213 : /*
214 : * Create an internal fsp for an *existing* directory.
215 : *
216 : * This should only be used by callers in the VFS that need to control the
217 : * opening of the directory. Otherwise use open_internal_dirfsp_at().
218 : */
219 4226 : NTSTATUS create_internal_dirfsp(connection_struct *conn,
220 : const struct smb_filename *smb_dname,
221 : struct files_struct **_fsp)
222 : {
223 4226 : struct files_struct *fsp = NULL;
224 : NTSTATUS status;
225 :
226 4226 : status = create_internal_fsp(conn, smb_dname, &fsp);
227 4226 : if (!NT_STATUS_IS_OK(status)) {
228 0 : return status;
229 : }
230 :
231 4226 : fsp->access_mask = FILE_LIST_DIRECTORY;
232 4226 : fsp->fsp_flags.is_directory = true;
233 4226 : fsp->fsp_flags.is_dirfsp = true;
234 :
235 4226 : *_fsp = fsp;
236 4226 : return NT_STATUS_OK;
237 : }
238 :
239 : /*
240 : * Open an internal fsp for an *existing* directory.
241 : */
242 846 : NTSTATUS open_internal_dirfsp(connection_struct *conn,
243 : const struct smb_filename *smb_dname,
244 : int _open_flags,
245 : struct files_struct **_fsp)
246 : {
247 846 : struct vfs_open_how how = { .flags = _open_flags, };
248 846 : struct files_struct *fsp = NULL;
249 : NTSTATUS status;
250 :
251 846 : status = create_internal_dirfsp(conn, smb_dname, &fsp);
252 846 : if (!NT_STATUS_IS_OK(status)) {
253 0 : return status;
254 : }
255 :
256 : #ifdef O_DIRECTORY
257 846 : how.flags |= O_DIRECTORY;
258 : #endif
259 846 : status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
260 846 : if (!NT_STATUS_IS_OK(status)) {
261 0 : DBG_INFO("Could not open fd for %s (%s)\n",
262 : smb_fname_str_dbg(smb_dname),
263 : nt_errstr(status));
264 0 : file_free(NULL, fsp);
265 0 : return status;
266 : }
267 :
268 846 : status = vfs_stat_fsp(fsp);
269 846 : if (!NT_STATUS_IS_OK(status)) {
270 0 : file_free(NULL, fsp);
271 0 : return status;
272 : }
273 :
274 846 : if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
275 0 : DBG_ERR("%s is not a directory!\n",
276 : smb_fname_str_dbg(smb_dname));
277 0 : file_free(NULL, fsp);
278 0 : return NT_STATUS_NOT_A_DIRECTORY;
279 : }
280 :
281 846 : fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
282 :
283 846 : *_fsp = fsp;
284 846 : return NT_STATUS_OK;
285 : }
286 :
287 : /*
288 : * Convert a pathref dirfsp into a real fsp. No need to do any cwd
289 : * tricks, we just open ".".
290 : */
291 3380 : NTSTATUS openat_internal_dir_from_pathref(
292 : struct files_struct *dirfsp,
293 : int _open_flags,
294 : struct files_struct **_fsp)
295 : {
296 3380 : struct connection_struct *conn = dirfsp->conn;
297 3380 : struct smb_filename *smb_dname = dirfsp->fsp_name;
298 3380 : struct files_struct *fsp = NULL;
299 3380 : char dot[] = ".";
300 3380 : struct smb_filename smb_dot = {
301 : .base_name = dot,
302 3380 : .flags = smb_dname->flags,
303 3380 : .twrp = smb_dname->twrp,
304 : };
305 3380 : struct vfs_open_how how = { .flags = _open_flags, };
306 : NTSTATUS status;
307 :
308 3380 : status = create_internal_dirfsp(conn, smb_dname, &fsp);
309 3380 : if (!NT_STATUS_IS_OK(status)) {
310 0 : return status;
311 : }
312 :
313 : /*
314 : * Pointless for opening ".", but you never know...
315 : */
316 3380 : how.flags |= O_NOFOLLOW;
317 :
318 3380 : status = fd_openat(dirfsp, &smb_dot, fsp, &how);
319 3380 : if (!NT_STATUS_IS_OK(status)) {
320 0 : DBG_INFO("fd_openat(\"%s\", \".\") failed: %s\n",
321 : fsp_str_dbg(dirfsp),
322 : nt_errstr(status));
323 0 : file_free(NULL, fsp);
324 0 : return status;
325 : }
326 :
327 3380 : fsp->fsp_name->st = smb_dname->st;
328 3380 : fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
329 3380 : *_fsp = fsp;
330 3380 : return NT_STATUS_OK;
331 : }
332 :
333 : /*
334 : * The "link" in the name doesn't imply link in the filesystem
335 : * sense. It's a object that "links" together an fsp and an smb_fname
336 : * and the link allocated as talloc child of an fsp.
337 : *
338 : * The link is created for fsps that openat_pathref_fsp() returns in
339 : * smb_fname->fsp. When this fsp is freed by file_free() by some caller
340 : * somewhere, the destructor fsp_smb_fname_link_destructor() on the link object
341 : * will use the link to reset the reference in smb_fname->fsp that is about to
342 : * go away.
343 : *
344 : * This prevents smb_fname_internal_fsp_destructor() from seeing dangling fsp
345 : * pointers.
346 : */
347 :
348 : struct fsp_smb_fname_link {
349 : struct fsp_smb_fname_link **smb_fname_link;
350 : struct files_struct **smb_fname_fsp;
351 : };
352 :
353 129983 : static int fsp_smb_fname_link_destructor(struct fsp_smb_fname_link *link)
354 : {
355 129983 : if (link->smb_fname_link == NULL) {
356 0 : return 0;
357 : }
358 :
359 129983 : *link->smb_fname_link = NULL;
360 129983 : *link->smb_fname_fsp = NULL;
361 129983 : return 0;
362 : }
363 :
364 233742 : static NTSTATUS fsp_smb_fname_link(struct files_struct *fsp,
365 : struct fsp_smb_fname_link **smb_fname_link,
366 : struct files_struct **smb_fname_fsp)
367 : {
368 233742 : struct fsp_smb_fname_link *link = NULL;
369 :
370 233742 : SMB_ASSERT(*smb_fname_link == NULL);
371 233742 : SMB_ASSERT(*smb_fname_fsp == NULL);
372 :
373 233742 : link = talloc_zero(fsp, struct fsp_smb_fname_link);
374 233742 : if (link == NULL) {
375 0 : return NT_STATUS_NO_MEMORY;
376 : }
377 :
378 233742 : link->smb_fname_link = smb_fname_link;
379 233742 : link->smb_fname_fsp = smb_fname_fsp;
380 233742 : *smb_fname_link = link;
381 233742 : *smb_fname_fsp = fsp;
382 :
383 233742 : talloc_set_destructor(link, fsp_smb_fname_link_destructor);
384 233742 : return NT_STATUS_OK;
385 : }
386 :
387 : /*
388 : * Free a link, carefully avoiding to trigger the link destructor
389 : */
390 128241 : static void destroy_fsp_smb_fname_link(struct fsp_smb_fname_link **_link)
391 : {
392 128241 : struct fsp_smb_fname_link *link = *_link;
393 :
394 128241 : if (link == NULL) {
395 24482 : return;
396 : }
397 103759 : talloc_set_destructor(link, NULL);
398 103759 : TALLOC_FREE(link);
399 103759 : *_link = NULL;
400 : }
401 :
402 : /*
403 : * Talloc destructor set on an smb_fname set by openat_pathref_fsp() used to
404 : * close the embedded smb_fname->fsp.
405 : */
406 66092 : static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
407 : {
408 66092 : struct files_struct *fsp = smb_fname->fsp;
409 66092 : struct files_struct *base_fsp = NULL;
410 : NTSTATUS status;
411 66092 : int saved_errno = errno;
412 :
413 66092 : destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
414 :
415 66092 : if (fsp == NULL) {
416 0 : errno = saved_errno;
417 0 : return 0;
418 : }
419 :
420 66092 : if (fsp_is_alternate_stream(fsp)) {
421 16 : base_fsp = fsp->base_fsp;
422 : }
423 :
424 66092 : status = fd_close(fsp);
425 66092 : if (!NT_STATUS_IS_OK(status)) {
426 0 : DBG_ERR("Closing fd for fsp [%s] failed: %s. "
427 : "Please check your filesystem!!!\n",
428 : fsp_str_dbg(fsp), nt_errstr(status));
429 : }
430 66092 : file_free(NULL, fsp);
431 66092 : smb_fname->fsp = NULL;
432 :
433 66092 : if (base_fsp != NULL) {
434 16 : base_fsp->stream_fsp = NULL;
435 16 : status = fd_close(base_fsp);
436 16 : if (!NT_STATUS_IS_OK(status)) {
437 0 : DBG_ERR("Closing fd for base_fsp [%s] failed: %s. "
438 : "Please check your filesystem!!!\n",
439 : fsp_str_dbg(base_fsp), nt_errstr(status));
440 : }
441 16 : file_free(NULL, base_fsp);
442 : }
443 :
444 66092 : errno = saved_errno;
445 66092 : return 0;
446 : }
447 :
448 113962 : static NTSTATUS openat_pathref_fullname(
449 : struct connection_struct *conn,
450 : const struct files_struct *dirfsp,
451 : struct files_struct *basefsp,
452 : struct smb_filename **full_fname,
453 : struct smb_filename *smb_fname,
454 : const struct vfs_open_how *how)
455 : {
456 113962 : struct files_struct *fsp = NULL;
457 113962 : bool have_dirfsp = (dirfsp != NULL);
458 113962 : bool have_basefsp = (basefsp != NULL);
459 : NTSTATUS status;
460 :
461 113962 : DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
462 :
463 113962 : SMB_ASSERT(smb_fname->fsp == NULL);
464 113962 : SMB_ASSERT(have_dirfsp != have_basefsp);
465 :
466 113962 : status = fsp_new(conn, conn, &fsp);
467 113962 : if (!NT_STATUS_IS_OK(status)) {
468 0 : return status;
469 : }
470 :
471 113962 : GetTimeOfDay(&fsp->open_time);
472 113962 : fsp_set_gen_id(fsp);
473 113962 : ZERO_STRUCT(conn->sconn->fsp_fi_cache);
474 :
475 113962 : fsp->fsp_flags.is_pathref = true;
476 :
477 113962 : status = fsp_attach_smb_fname(fsp, full_fname);
478 113962 : if (!NT_STATUS_IS_OK(status)) {
479 0 : goto fail;
480 : }
481 113962 : fsp_set_base_fsp(fsp, basefsp);
482 :
483 113962 : status = fd_openat(dirfsp, smb_fname, fsp, how);
484 113962 : if (!NT_STATUS_IS_OK(status)) {
485 :
486 41939 : smb_fname->st = fsp->fsp_name->st;
487 :
488 41939 : if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
489 41935 : NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
490 41923 : NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
491 : {
492 : /*
493 : * streams_xattr return NT_STATUS_NOT_FOUND for
494 : * opens of not yet existing streams.
495 : *
496 : * ELOOP maps to NT_STATUS_OBJECT_PATH_NOT_FOUND
497 : * and this will result from a open request from
498 : * a POSIX client on a symlink.
499 : *
500 : * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple
501 : * ENOENT case.
502 : *
503 : * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying
504 : * to open a symlink, our callers are not interested in
505 : * this.
506 : */
507 20 : status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
508 : }
509 41939 : goto fail;
510 : }
511 :
512 : /*
513 : * fd_openat() has done an FSTAT on the handle
514 : * so update the smb_fname stat info with "truth".
515 : * from the handle.
516 : */
517 72023 : smb_fname->st = fsp->fsp_name->st;
518 :
519 72023 : fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
520 :
521 72023 : fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
522 :
523 72023 : status = fsp_smb_fname_link(fsp,
524 : &smb_fname->fsp_link,
525 : &smb_fname->fsp);
526 72023 : if (!NT_STATUS_IS_OK(status)) {
527 0 : goto fail;
528 : }
529 :
530 72023 : DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
531 :
532 72023 : talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
533 72023 : return NT_STATUS_OK;
534 :
535 41939 : fail:
536 41939 : DBG_DEBUG("Opening pathref for [%s] failed: %s\n",
537 : smb_fname_str_dbg(smb_fname),
538 : nt_errstr(status));
539 :
540 41939 : fsp_set_base_fsp(fsp, NULL);
541 41939 : fd_close(fsp);
542 41939 : file_free(NULL, fsp);
543 41939 : return status;
544 : }
545 :
546 : /*
547 : * Open an internal O_PATH based fsp for smb_fname. If O_PATH is not
548 : * available, open O_RDONLY as root. Both is done in fd_open() ->
549 : * non_widelink_open(), triggered by setting fsp->fsp_flags.is_pathref to
550 : * true.
551 : */
552 113890 : NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
553 : struct smb_filename *smb_fname)
554 : {
555 113890 : connection_struct *conn = dirfsp->conn;
556 113890 : struct smb_filename *full_fname = NULL;
557 113890 : struct smb_filename *base_fname = NULL;
558 113890 : struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
559 : NTSTATUS status;
560 :
561 113890 : DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
562 :
563 113890 : if (smb_fname->fsp != NULL) {
564 : /* We already have one for this name. */
565 0 : DBG_DEBUG("smb_fname [%s] already has a pathref fsp.\n",
566 : smb_fname_str_dbg(smb_fname));
567 0 : return NT_STATUS_OK;
568 : }
569 :
570 113890 : if (is_named_stream(smb_fname) &&
571 32 : ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
572 0 : DBG_DEBUG("stream open [%s] on non-stream share\n",
573 : smb_fname_str_dbg(smb_fname));
574 0 : return NT_STATUS_OBJECT_NAME_INVALID;
575 : }
576 :
577 113890 : if (!is_named_stream(smb_fname)) {
578 : /*
579 : * openat_pathref_fullname() will make "full_fname" a
580 : * talloc child of the smb_fname->fsp. Don't use
581 : * talloc_tos() to allocate it to avoid making the
582 : * talloc stackframe pool long-lived.
583 : */
584 113858 : full_fname = full_path_from_dirfsp_atname(
585 : conn,
586 : dirfsp,
587 : smb_fname);
588 113858 : if (full_fname == NULL) {
589 0 : status = NT_STATUS_NO_MEMORY;
590 0 : goto fail;
591 : }
592 113858 : status = openat_pathref_fullname(
593 : conn, dirfsp, NULL, &full_fname, smb_fname, &how);
594 113858 : TALLOC_FREE(full_fname);
595 113858 : return status;
596 : }
597 :
598 : /*
599 : * stream open
600 : */
601 32 : base_fname = cp_smb_filename_nostream(conn, smb_fname);
602 32 : if (base_fname == NULL) {
603 0 : return NT_STATUS_NO_MEMORY;
604 : }
605 :
606 32 : full_fname = full_path_from_dirfsp_atname(
607 : conn, /* no talloc_tos(), see comment above */
608 : dirfsp,
609 : base_fname);
610 32 : if (full_fname == NULL) {
611 0 : status = NT_STATUS_NO_MEMORY;
612 0 : goto fail;
613 : }
614 :
615 32 : status = openat_pathref_fullname(
616 : conn, dirfsp, NULL, &full_fname, base_fname, &how);
617 32 : TALLOC_FREE(full_fname);
618 32 : if (!NT_STATUS_IS_OK(status)) {
619 0 : DBG_DEBUG("openat_pathref_fullname() failed: %s\n",
620 : nt_errstr(status));
621 0 : goto fail;
622 : }
623 :
624 32 : status = open_stream_pathref_fsp(&base_fname->fsp, smb_fname);
625 32 : if (!NT_STATUS_IS_OK(status)) {
626 0 : DBG_DEBUG("open_stream_pathref_fsp failed: %s\n",
627 : nt_errstr(status));
628 0 : goto fail;
629 : }
630 :
631 32 : smb_fname_fsp_unlink(base_fname);
632 32 : fail:
633 32 : TALLOC_FREE(base_fname);
634 32 : return status;
635 : }
636 :
637 : /*
638 : * Open a stream given an already opened base_fsp. Avoid
639 : * non_widelink_open: This is only valid for the case where we have a
640 : * valid non-cwd_fsp dirfsp that we can pass to SMB_VFS_OPENAT()
641 : */
642 72 : NTSTATUS open_stream_pathref_fsp(
643 : struct files_struct **_base_fsp,
644 : struct smb_filename *smb_fname)
645 : {
646 72 : struct files_struct *base_fsp = *_base_fsp;
647 72 : connection_struct *conn = base_fsp->conn;
648 72 : struct smb_filename *base_fname = base_fsp->fsp_name;
649 72 : struct smb_filename *full_fname = NULL;
650 72 : struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
651 : NTSTATUS status;
652 :
653 72 : SMB_ASSERT(smb_fname->fsp == NULL);
654 72 : SMB_ASSERT(is_named_stream(smb_fname));
655 :
656 144 : full_fname = synthetic_smb_fname(
657 : conn, /* no talloc_tos(), this will be long-lived */
658 72 : base_fname->base_name,
659 72 : smb_fname->stream_name,
660 72 : &smb_fname->st,
661 : smb_fname->twrp,
662 : smb_fname->flags);
663 72 : if (full_fname == NULL) {
664 0 : return NT_STATUS_NO_MEMORY;
665 : }
666 :
667 72 : status = openat_pathref_fullname(
668 : conn, NULL, base_fsp, &full_fname, smb_fname, &how);
669 72 : TALLOC_FREE(full_fname);
670 72 : return status;
671 : }
672 :
673 19495 : static char *path_to_strv(TALLOC_CTX *mem_ctx, const char *path)
674 : {
675 19495 : char *result = talloc_strdup(mem_ctx, path);
676 :
677 19495 : if (result == NULL) {
678 0 : return NULL;
679 : }
680 19495 : string_replace(result, '/', '\0');
681 19495 : return result;
682 : }
683 :
684 14786 : NTSTATUS readlink_talloc(
685 : TALLOC_CTX *mem_ctx,
686 : struct files_struct *dirfsp,
687 : struct smb_filename *smb_relname,
688 : char **_substitute)
689 : {
690 14786 : struct smb_filename null_fname = {
691 : .base_name = discard_const_p(char, ""),
692 : };
693 : char buf[PATH_MAX];
694 : ssize_t ret;
695 : char *substitute;
696 : NTSTATUS status;
697 :
698 14786 : if (smb_relname == NULL) {
699 : /*
700 : * We have a Linux O_PATH handle in dirfsp and want to
701 : * read its value, essentially a freadlink
702 : */
703 1892 : smb_relname = &null_fname;
704 : }
705 :
706 14786 : ret = SMB_VFS_READLINKAT(
707 : dirfsp->conn, dirfsp, smb_relname, buf, sizeof(buf));
708 14786 : if (ret < 0) {
709 0 : status = map_nt_error_from_unix(errno);
710 0 : DBG_DEBUG("SMB_VFS_READLINKAT() failed: %s\n",
711 : strerror(errno));
712 0 : return status;
713 : }
714 :
715 14786 : if ((size_t)ret == sizeof(buf)) {
716 : /*
717 : * Do we need symlink targets longer than PATH_MAX?
718 : */
719 0 : DBG_DEBUG("Got full %zu bytes from readlink, too long\n",
720 : sizeof(buf));
721 0 : return NT_STATUS_BUFFER_OVERFLOW;
722 : }
723 :
724 14786 : substitute = talloc_strndup(mem_ctx, buf, ret);
725 14786 : if (substitute == NULL) {
726 0 : DBG_DEBUG("talloc_strndup() failed\n");
727 0 : return NT_STATUS_NO_MEMORY;
728 : }
729 :
730 14786 : *_substitute = substitute;
731 14786 : return NT_STATUS_OK;
732 : }
733 :
734 19495 : NTSTATUS openat_pathref_dirfsp_nosymlink(
735 : TALLOC_CTX *mem_ctx,
736 : struct connection_struct *conn,
737 : const char *path_in,
738 : NTTIME twrp,
739 : bool posix,
740 : struct smb_filename **_smb_fname,
741 : size_t *unparsed,
742 : char **substitute)
743 : {
744 19495 : struct files_struct *dirfsp = conn->cwd_fsp;
745 38990 : struct smb_filename full_fname = {
746 : .base_name = NULL,
747 : .twrp = twrp,
748 19495 : .flags = posix ? SMB_FILENAME_POSIX_PATH : 0,
749 : };
750 19495 : struct smb_filename rel_fname = {
751 : .base_name = NULL,
752 : .twrp = twrp,
753 19495 : .flags = full_fname.flags,
754 : };
755 19495 : struct smb_filename *result = NULL;
756 19495 : struct files_struct *fsp = NULL;
757 19495 : char *path = NULL, *next = NULL;
758 : bool case_sensitive;
759 : int fd;
760 : NTSTATUS status;
761 19495 : struct vfs_open_how how = {
762 : .flags = O_NOFOLLOW|O_DIRECTORY,
763 : .mode = 0,
764 : };
765 :
766 19495 : DBG_DEBUG("path_in=%s\n", path_in);
767 :
768 19495 : status = fsp_new(conn, conn, &fsp);
769 19495 : if (!NT_STATUS_IS_OK(status)) {
770 0 : DBG_DEBUG("fsp_new() failed: %s\n", nt_errstr(status));
771 0 : goto fail;
772 : }
773 19495 : fsp->fsp_name = &full_fname;
774 :
775 : #ifdef O_PATH
776 : /*
777 : * Add O_PATH manually, doing this by setting
778 : * fsp->fsp_flags.is_pathref will make us become_root() in the
779 : * non-O_PATH case, which would cause a security problem.
780 : */
781 19495 : how.flags |= O_PATH;
782 : #else
783 : #ifdef O_SEARCH
784 : /*
785 : * O_SEARCH just checks for the "x" bit. We are traversing
786 : * directories, so we don't need the implicit O_RDONLY ("r"
787 : * permissions) but only the "x"-permissions requested by
788 : * O_SEARCH. We need either O_PATH or O_SEARCH to correctly
789 : * function, without either we will incorrectly require also
790 : * the "r" bit when traversing the directory hierarchy.
791 : */
792 : how.flags |= O_SEARCH;
793 : #endif
794 : #endif
795 :
796 19495 : full_fname.base_name = talloc_strdup(talloc_tos(), "");
797 19495 : if (full_fname.base_name == NULL) {
798 0 : DBG_DEBUG("talloc_strdup() failed\n");
799 0 : goto nomem;
800 : }
801 :
802 : /*
803 : * First split the path into individual components.
804 : */
805 19495 : path = path_to_strv(talloc_tos(), path_in);
806 19495 : if (path == NULL) {
807 0 : DBG_DEBUG("path_to_strv() failed\n");
808 0 : goto nomem;
809 : }
810 :
811 : /*
812 : * First we loop over all components
813 : * in order to verify, there's no '.' or '..'
814 : */
815 19495 : rel_fname.base_name = path;
816 223310 : while (rel_fname.base_name != NULL) {
817 :
818 203815 : next = strv_next(path, rel_fname.base_name);
819 :
820 : /*
821 : * Path sanitizing further up has cleaned or rejected
822 : * empty path components. Assert this here.
823 : */
824 203815 : SMB_ASSERT(rel_fname.base_name[0] != '\0');
825 :
826 203815 : if (ISDOT(rel_fname.base_name) ||
827 203815 : ISDOTDOT(rel_fname.base_name)) {
828 0 : DBG_DEBUG("%s contains a dot\n", path_in);
829 0 : status = NT_STATUS_OBJECT_NAME_INVALID;
830 0 : goto fail;
831 : }
832 :
833 : /* Check veto files. */
834 203815 : if (IS_VETO_PATH(conn, rel_fname.base_name)) {
835 0 : DBG_DEBUG("%s contains veto files path component %s\n",
836 : path_in, rel_fname.base_name);
837 0 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
838 0 : goto fail;
839 : }
840 :
841 203815 : rel_fname.base_name = next;
842 : }
843 :
844 19495 : if (conn->open_how_resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
845 :
846 : /*
847 : * Try a direct openat2 with RESOLVE_NO_SYMLINKS to
848 : * avoid the openat/close loop further down.
849 : */
850 :
851 19438 : rel_fname.base_name = discard_const_p(char, path_in);
852 19438 : how.resolve = VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
853 :
854 19438 : fd = SMB_VFS_OPENAT(conn, dirfsp, &rel_fname, fsp, &how);
855 19438 : if (fd >= 0) {
856 5936 : fsp_set_fd(fsp, fd);
857 5936 : TALLOC_FREE(full_fname.base_name);
858 5936 : full_fname = rel_fname;
859 5936 : goto done;
860 : }
861 :
862 13502 : status = map_nt_error_from_unix(errno);
863 13502 : DBG_DEBUG("SMB_VFS_OPENAT(%s, %s, RESOLVE_NO_SYMLINKS) "
864 : "returned %d %s => %s\n",
865 : smb_fname_str_dbg(dirfsp->fsp_name), path_in,
866 : errno, strerror(errno), nt_errstr(status));
867 13502 : SMB_ASSERT(fd == -1);
868 13502 : switch (errno) {
869 0 : case ENOSYS:
870 : /*
871 : * We got ENOSYS, so fallback to the old code
872 : * if the kernel doesn't support openat2() yet.
873 : */
874 0 : break;
875 :
876 12894 : case ELOOP:
877 : case ENOTDIR:
878 : /*
879 : * For ELOOP we also fallback in order to
880 : * return the correct information with
881 : * NT_STATUS_STOPPED_ON_SYMLINK.
882 : *
883 : * O_NOFOLLOW|O_DIRECTORY results in
884 : * ENOTDIR instead of ELOOP for the final
885 : * component.
886 : */
887 12894 : break;
888 :
889 608 : case ENOENT:
890 : /*
891 : * If we got ENOENT, the filesystem could
892 : * be case sensitive. For now we only do
893 : * the get_real_filename_at() dance in
894 : * the fallback loop below.
895 : */
896 608 : break;
897 :
898 0 : default:
899 0 : goto fail;
900 : }
901 :
902 : /*
903 : * Just fallback to the openat loop
904 : */
905 13502 : how.resolve = 0;
906 : }
907 :
908 : /*
909 : * Now we loop over all components
910 : * opening each one and using it
911 : * as dirfd for the next one.
912 : *
913 : * It means we can detect symlinks
914 : * within the path.
915 : */
916 13559 : rel_fname.base_name = path;
917 20021 : next:
918 20021 : next = strv_next(path, rel_fname.base_name);
919 :
920 20021 : fd = SMB_VFS_OPENAT(
921 : conn,
922 : dirfsp,
923 : &rel_fname,
924 : fsp,
925 : &how);
926 :
927 20021 : case_sensitive = (posix || conn->case_sensitive);
928 :
929 20021 : if ((fd == -1) && (errno == ENOENT) && !case_sensitive) {
930 642 : const char *orig_base_name = rel_fname.base_name;
931 :
932 642 : status = get_real_filename_at(
933 : dirfsp,
934 642 : rel_fname.base_name,
935 : talloc_tos(),
936 : &rel_fname.base_name);
937 :
938 642 : if (!NT_STATUS_IS_OK(status)) {
939 51 : DBG_DEBUG("get_real_filename_at failed: %s\n",
940 : nt_errstr(status));
941 51 : goto fail;
942 : }
943 :
944 : /* Name might have been demangled - check veto files. */
945 591 : if (IS_VETO_PATH(conn, rel_fname.base_name)) {
946 0 : DBG_DEBUG("%s contains veto files path component "
947 : "%s => %s\n",
948 : path_in,
949 : orig_base_name,
950 : rel_fname.base_name);
951 0 : status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
952 0 : goto fail;
953 : }
954 :
955 591 : fd = SMB_VFS_OPENAT(
956 : conn,
957 : dirfsp,
958 : &rel_fname,
959 : fsp,
960 : &how);
961 : }
962 :
963 : /*
964 : * O_NOFOLLOW|O_DIRECTORY results in
965 : * ENOTDIR instead of ELOOP.
966 : *
967 : * But we should be prepared to handle ELOOP too.
968 : */
969 19970 : if ((fd == -1) && (errno == ENOTDIR || errno == ELOOP)) {
970 12894 : NTSTATUS orig_status = map_nt_error_from_unix(errno);
971 :
972 12894 : status = readlink_talloc(
973 : mem_ctx, dirfsp, &rel_fname, substitute);
974 :
975 12894 : if (NT_STATUS_IS_OK(status)) {
976 : /*
977 : * readlink_talloc() found a symlink
978 : */
979 12894 : status = NT_STATUS_STOPPED_ON_SYMLINK;
980 :
981 12894 : if (unparsed != NULL) {
982 12894 : if (next == NULL) {
983 1098 : *unparsed = 0;
984 : } else {
985 11796 : size_t parsed = next - path;
986 11796 : size_t len = talloc_get_size(path);
987 11796 : *unparsed = len - parsed;
988 : }
989 : }
990 : /*
991 : * If we're on an MSDFS share, see if this is
992 : * an MSDFS link.
993 : */
994 25788 : if (lp_host_msdfs() &&
995 22344 : lp_msdfs_root(SNUM(conn)) &&
996 9450 : (substitute != NULL) &&
997 18900 : strnequal(*substitute, "msdfs:", 6) &&
998 9450 : is_msdfs_link(dirfsp, &rel_fname))
999 : {
1000 9450 : status = NT_STATUS_PATH_NOT_COVERED;
1001 : }
1002 : } else {
1003 :
1004 0 : DBG_DEBUG("readlink_talloc failed: %s\n",
1005 : nt_errstr(status));
1006 : /*
1007 : * Restore the error status from SMB_VFS_OPENAT()
1008 : */
1009 0 : status = orig_status;
1010 : }
1011 12894 : goto fail;
1012 : }
1013 :
1014 7076 : if (fd == -1) {
1015 0 : status = map_nt_error_from_unix(errno);
1016 0 : DBG_DEBUG("SMB_VFS_OPENAT() failed: %s\n",
1017 : strerror(errno));
1018 0 : goto fail;
1019 : }
1020 7076 : fsp_set_fd(fsp, fd);
1021 :
1022 7076 : fsp->fsp_flags.is_directory = true; /* See O_DIRECTORY above */
1023 :
1024 7076 : full_fname.base_name = talloc_asprintf_append_buffer(
1025 : full_fname.base_name,
1026 : "%s%s",
1027 7076 : full_fname.base_name[0] == '\0' ? "" : "/",
1028 : rel_fname.base_name);
1029 :
1030 7076 : if (full_fname.base_name == NULL) {
1031 0 : DBG_DEBUG("talloc_asprintf_append_buffer() failed\n");
1032 0 : goto nomem;
1033 : }
1034 :
1035 7076 : if (next != NULL) {
1036 6462 : struct files_struct *tmp = NULL;
1037 :
1038 6462 : if (dirfsp != conn->cwd_fsp) {
1039 2406 : fd_close(dirfsp);
1040 : }
1041 :
1042 6462 : tmp = dirfsp;
1043 6462 : dirfsp = fsp;
1044 :
1045 6462 : if (tmp == conn->cwd_fsp) {
1046 4056 : status = fsp_new(conn, conn, &fsp);
1047 4056 : if (!NT_STATUS_IS_OK(status)) {
1048 0 : DBG_DEBUG("fsp_new() failed: %s\n",
1049 : nt_errstr(status));
1050 0 : goto fail;
1051 : }
1052 4056 : fsp->fsp_name = &full_fname;
1053 : } else {
1054 2406 : fsp = tmp;
1055 : }
1056 :
1057 6462 : rel_fname.base_name = next;
1058 :
1059 6462 : goto next;
1060 : }
1061 :
1062 614 : if (dirfsp != conn->cwd_fsp) {
1063 561 : SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
1064 561 : fd_close(dirfsp);
1065 561 : dirfsp->fsp_name = NULL;
1066 561 : file_free(NULL, dirfsp);
1067 561 : dirfsp = NULL;
1068 : }
1069 :
1070 53 : done:
1071 6550 : fsp->fsp_flags.is_pathref = true;
1072 6550 : fsp->fsp_name = NULL;
1073 :
1074 6550 : status = fsp_set_smb_fname(fsp, &full_fname);
1075 6550 : if (!NT_STATUS_IS_OK(status)) {
1076 0 : DBG_DEBUG("fsp_set_smb_fname() failed: %s\n",
1077 : nt_errstr(status));
1078 0 : goto fail;
1079 : }
1080 :
1081 6550 : status = vfs_stat_fsp(fsp);
1082 6550 : if (!NT_STATUS_IS_OK(status)) {
1083 0 : DBG_DEBUG("vfs_stat_fsp(%s) failed: %s\n",
1084 : fsp_str_dbg(fsp),
1085 : nt_errstr(status));
1086 0 : goto fail;
1087 : }
1088 : /*
1089 : * We must correctly set fsp->file_id as code inside
1090 : * open.c will use this to check if delete_on_close
1091 : * has been set on the dirfsp.
1092 : */
1093 6550 : fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
1094 :
1095 6550 : result = cp_smb_filename(mem_ctx, fsp->fsp_name);
1096 6550 : if (result == NULL) {
1097 0 : DBG_DEBUG("cp_smb_filename() failed\n");
1098 0 : goto nomem;
1099 : }
1100 :
1101 6550 : status = fsp_smb_fname_link(fsp,
1102 : &result->fsp_link,
1103 : &result->fsp);
1104 6550 : if (!NT_STATUS_IS_OK(status)) {
1105 0 : goto fail;
1106 : }
1107 6550 : talloc_set_destructor(result, smb_fname_fsp_destructor);
1108 :
1109 6550 : *_smb_fname = result;
1110 :
1111 6550 : DBG_DEBUG("returning %s\n", smb_fname_str_dbg(result));
1112 :
1113 6550 : return NT_STATUS_OK;
1114 :
1115 0 : nomem:
1116 0 : status = NT_STATUS_NO_MEMORY;
1117 12945 : fail:
1118 12945 : if (fsp != NULL) {
1119 12945 : if (fsp_get_pathref_fd(fsp) != -1) {
1120 0 : fd_close(fsp);
1121 : }
1122 12945 : file_free(NULL, fsp);
1123 12945 : fsp = NULL;
1124 : }
1125 :
1126 12945 : if ((dirfsp != NULL) && (dirfsp != conn->cwd_fsp)) {
1127 3495 : SMB_ASSERT(fsp_get_pathref_fd(dirfsp) != -1);
1128 3495 : fd_close(dirfsp);
1129 3495 : dirfsp->fsp_name = NULL;
1130 3495 : file_free(NULL, dirfsp);
1131 3495 : dirfsp = NULL;
1132 : }
1133 :
1134 12945 : TALLOC_FREE(path);
1135 12945 : return status;
1136 : }
1137 :
1138 60755 : void smb_fname_fsp_unlink(struct smb_filename *smb_fname)
1139 : {
1140 60755 : talloc_set_destructor(smb_fname, NULL);
1141 60755 : smb_fname->fsp = NULL;
1142 60755 : destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
1143 60755 : }
1144 :
1145 : /*
1146 : * Move any existing embedded fsp refs from the src name to the
1147 : * destination. It's safe to call this on src smb_fname's that have no embedded
1148 : * pathref fsp.
1149 : */
1150 23820 : NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
1151 : struct smb_filename *smb_fname_src)
1152 : {
1153 : NTSTATUS status;
1154 :
1155 : /*
1156 : * The target should always not be linked yet!
1157 : */
1158 23820 : SMB_ASSERT(smb_fname_dst->fsp == NULL);
1159 23820 : SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
1160 :
1161 23820 : if (smb_fname_src->fsp == NULL) {
1162 80 : return NT_STATUS_OK;
1163 : }
1164 :
1165 23740 : status = fsp_smb_fname_link(smb_fname_src->fsp,
1166 : &smb_fname_dst->fsp_link,
1167 : &smb_fname_dst->fsp);
1168 23740 : if (!NT_STATUS_IS_OK(status)) {
1169 0 : return status;
1170 : }
1171 :
1172 23740 : talloc_set_destructor(smb_fname_dst, smb_fname_fsp_destructor);
1173 :
1174 23740 : smb_fname_fsp_unlink(smb_fname_src);
1175 :
1176 23740 : return NT_STATUS_OK;
1177 : }
1178 :
1179 1394 : static int fsp_ref_no_close_destructor(struct smb_filename *smb_fname)
1180 : {
1181 1394 : destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
1182 1394 : return 0;
1183 : }
1184 :
1185 1791 : NTSTATUS reference_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
1186 : const struct smb_filename *smb_fname_src)
1187 : {
1188 : NTSTATUS status;
1189 :
1190 : /*
1191 : * The target should always not be linked yet!
1192 : */
1193 1791 : SMB_ASSERT(smb_fname_dst->fsp == NULL);
1194 1791 : SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
1195 :
1196 1791 : if (smb_fname_src->fsp == NULL) {
1197 397 : return NT_STATUS_OK;
1198 : }
1199 :
1200 1394 : status = fsp_smb_fname_link(smb_fname_src->fsp,
1201 : &smb_fname_dst->fsp_link,
1202 : &smb_fname_dst->fsp);
1203 1394 : if (!NT_STATUS_IS_OK(status)) {
1204 0 : return status;
1205 : }
1206 :
1207 1394 : talloc_set_destructor(smb_fname_dst, fsp_ref_no_close_destructor);
1208 :
1209 1394 : return NT_STATUS_OK;
1210 : }
1211 :
1212 : /**
1213 : * Create an smb_fname and open smb_fname->fsp pathref
1214 : **/
1215 10635 : NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
1216 : struct files_struct *dirfsp,
1217 : const char *base_name,
1218 : const char *stream_name,
1219 : const SMB_STRUCT_STAT *psbuf,
1220 : NTTIME twrp,
1221 : uint32_t flags,
1222 : struct smb_filename **_smb_fname)
1223 : {
1224 10635 : struct smb_filename *smb_fname = NULL;
1225 : NTSTATUS status;
1226 :
1227 10635 : smb_fname = synthetic_smb_fname(mem_ctx,
1228 : base_name,
1229 : stream_name,
1230 : psbuf,
1231 : twrp,
1232 : flags);
1233 10635 : if (smb_fname == NULL) {
1234 0 : return NT_STATUS_NO_MEMORY;
1235 : }
1236 :
1237 10635 : status = openat_pathref_fsp(dirfsp, smb_fname);
1238 10635 : if (!NT_STATUS_IS_OK(status)) {
1239 315 : DBG_NOTICE("opening [%s] failed\n",
1240 : smb_fname_str_dbg(smb_fname));
1241 315 : TALLOC_FREE(smb_fname);
1242 315 : return status;
1243 : }
1244 :
1245 10320 : *_smb_fname = smb_fname;
1246 10320 : return NT_STATUS_OK;
1247 : }
1248 :
1249 : /**
1250 : * Turn a path into a parent pathref and atname
1251 : *
1252 : * This returns the parent pathref in _parent and the name relative to it. If
1253 : * smb_fname was a pathref (ie smb_fname->fsp != NULL), then _atname will be a
1254 : * pathref as well, ie _atname->fsp will point at the same fsp as
1255 : * smb_fname->fsp.
1256 : **/
1257 1775 : NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
1258 : struct files_struct *dirfsp,
1259 : const struct smb_filename *smb_fname,
1260 : struct smb_filename **_parent,
1261 : struct smb_filename **_atname)
1262 : {
1263 1775 : struct smb_filename *parent = NULL;
1264 1775 : struct smb_filename *atname = NULL;
1265 : NTSTATUS status;
1266 :
1267 1775 : status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
1268 : mem_ctx,
1269 : smb_fname,
1270 : &parent,
1271 : &atname);
1272 1775 : if (!NT_STATUS_IS_OK(status)) {
1273 0 : return status;
1274 : }
1275 :
1276 : /*
1277 : * We know that the parent name must
1278 : * exist, and the name has been canonicalized
1279 : * even if this was a POSIX pathname.
1280 : * Ensure that we follow symlinks for
1281 : * the parent. See the torture test
1282 : * POSIX-SYMLINK-PARENT for details.
1283 : */
1284 1775 : parent->flags &= ~SMB_FILENAME_POSIX_PATH;
1285 :
1286 1775 : status = openat_pathref_fsp(dirfsp, parent);
1287 1775 : if (!NT_STATUS_IS_OK(status)) {
1288 0 : TALLOC_FREE(parent);
1289 0 : return status;
1290 : }
1291 :
1292 1775 : status = reference_smb_fname_fsp_link(atname, smb_fname);
1293 1775 : if (!NT_STATUS_IS_OK(status)) {
1294 0 : TALLOC_FREE(parent);
1295 0 : return status;
1296 : }
1297 :
1298 1775 : *_parent = parent;
1299 1775 : *_atname = atname;
1300 1775 : return NT_STATUS_OK;
1301 : }
1302 :
1303 277 : static bool close_file_in_loop(struct files_struct *fsp,
1304 : enum file_close_type close_type)
1305 : {
1306 277 : if (fsp_is_alternate_stream(fsp)) {
1307 : /*
1308 : * This is a stream, it can't be a base
1309 : */
1310 0 : SMB_ASSERT(fsp->stream_fsp == NULL);
1311 0 : SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
1312 :
1313 : /*
1314 : * Remove the base<->stream link so that
1315 : * close_file_free() does not close fsp->base_fsp as
1316 : * well. This would destroy walking the linked list of
1317 : * fsps.
1318 : */
1319 0 : fsp->base_fsp->stream_fsp = NULL;
1320 0 : fsp->base_fsp = NULL;
1321 :
1322 0 : close_file_free(NULL, &fsp, close_type);
1323 0 : return NULL;
1324 : }
1325 :
1326 277 : if (fsp->stream_fsp != NULL) {
1327 : /*
1328 : * This is the base of a stream.
1329 : */
1330 0 : SMB_ASSERT(fsp->stream_fsp->base_fsp == fsp);
1331 :
1332 : /*
1333 : * Remove the base<->stream link. This will make fsp
1334 : * look like a normal fsp for the next round.
1335 : */
1336 0 : fsp->stream_fsp->base_fsp = NULL;
1337 0 : fsp->stream_fsp = NULL;
1338 :
1339 : /*
1340 : * Have us called back a second time. In the second
1341 : * round, "fsp" now looks like a normal fsp.
1342 : */
1343 0 : return false;
1344 : }
1345 :
1346 277 : close_file_free(NULL, &fsp, close_type);
1347 277 : return true;
1348 : }
1349 :
1350 : /****************************************************************************
1351 : Close all open files for a connection.
1352 : ****************************************************************************/
1353 :
1354 : struct file_close_conn_state {
1355 : struct connection_struct *conn;
1356 : enum file_close_type close_type;
1357 : bool fsp_left_behind;
1358 : };
1359 :
1360 2 : static struct files_struct *file_close_conn_fn(
1361 : struct files_struct *fsp,
1362 : void *private_data)
1363 : {
1364 2 : struct file_close_conn_state *state = private_data;
1365 : bool did_close;
1366 :
1367 2 : if (fsp->conn != state->conn) {
1368 2 : return NULL;
1369 : }
1370 :
1371 0 : if (fsp->op != NULL && fsp->op->global->durable) {
1372 : /*
1373 : * A tree disconnect closes a durable handle
1374 : */
1375 0 : fsp->op->global->durable = false;
1376 : }
1377 :
1378 0 : did_close = close_file_in_loop(fsp, state->close_type);
1379 0 : if (!did_close) {
1380 0 : state->fsp_left_behind = true;
1381 : }
1382 :
1383 0 : return NULL;
1384 : }
1385 :
1386 5615 : void file_close_conn(connection_struct *conn, enum file_close_type close_type)
1387 : {
1388 5615 : struct file_close_conn_state state = { .conn = conn,
1389 : .close_type = close_type };
1390 :
1391 5615 : files_forall(conn->sconn, file_close_conn_fn, &state);
1392 :
1393 5615 : if (state.fsp_left_behind) {
1394 0 : state.fsp_left_behind = false;
1395 0 : files_forall(conn->sconn, file_close_conn_fn, &state);
1396 0 : SMB_ASSERT(!state.fsp_left_behind);
1397 : }
1398 5615 : }
1399 :
1400 : /****************************************************************************
1401 : Initialise file structures.
1402 : ****************************************************************************/
1403 :
1404 : static int files_max_open_fds;
1405 :
1406 5251 : bool file_init_global(void)
1407 : {
1408 5251 : int request_max = lp_max_open_files();
1409 : int real_lim;
1410 : int real_max;
1411 :
1412 5251 : if (files_max_open_fds != 0) {
1413 5251 : return true;
1414 : }
1415 :
1416 : /*
1417 : * Set the max_open files to be the requested
1418 : * max plus a fudgefactor to allow for the extra
1419 : * fd's we need such as log files etc...
1420 : */
1421 0 : real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
1422 :
1423 0 : real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
1424 :
1425 0 : if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
1426 0 : real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
1427 : }
1428 :
1429 0 : if (real_max != request_max) {
1430 0 : DEBUG(1, ("file_init_global: Information only: requested %d "
1431 : "open files, %d are available.\n",
1432 : request_max, real_max));
1433 : }
1434 :
1435 0 : SMB_ASSERT(real_max > 100);
1436 :
1437 0 : files_max_open_fds = real_max;
1438 0 : return true;
1439 : }
1440 :
1441 5251 : bool file_init(struct smbd_server_connection *sconn)
1442 : {
1443 : bool ok;
1444 :
1445 5251 : ok = file_init_global();
1446 5251 : if (!ok) {
1447 0 : return false;
1448 : }
1449 :
1450 5251 : sconn->real_max_open_files = files_max_open_fds;
1451 :
1452 5251 : return true;
1453 : }
1454 :
1455 : /****************************************************************************
1456 : Close files open by a specified vuid.
1457 : ****************************************************************************/
1458 :
1459 : struct file_close_user_state {
1460 : uint64_t vuid;
1461 : bool fsp_left_behind;
1462 : };
1463 :
1464 279 : static struct files_struct *file_close_user_fn(
1465 : struct files_struct *fsp,
1466 : void *private_data)
1467 : {
1468 279 : struct file_close_user_state *state = private_data;
1469 : bool did_close;
1470 :
1471 279 : if (fsp->vuid != state->vuid) {
1472 2 : return NULL;
1473 : }
1474 :
1475 277 : did_close = close_file_in_loop(fsp, SHUTDOWN_CLOSE);
1476 277 : if (!did_close) {
1477 0 : state->fsp_left_behind = true;
1478 : }
1479 :
1480 277 : return NULL;
1481 : }
1482 :
1483 4952 : void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
1484 : {
1485 4952 : struct file_close_user_state state = { .vuid = vuid };
1486 :
1487 4952 : files_forall(sconn, file_close_user_fn, &state);
1488 :
1489 4952 : if (state.fsp_left_behind) {
1490 0 : state.fsp_left_behind = false;
1491 0 : files_forall(sconn, file_close_user_fn, &state);
1492 0 : SMB_ASSERT(!state.fsp_left_behind);
1493 : }
1494 4952 : }
1495 :
1496 : /*
1497 : * Walk the files table until "fn" returns non-NULL
1498 : */
1499 :
1500 11986 : struct files_struct *files_forall(
1501 : struct smbd_server_connection *sconn,
1502 : struct files_struct *(*fn)(struct files_struct *fsp,
1503 : void *private_data),
1504 : void *private_data)
1505 : {
1506 : struct files_struct *fsp, *next;
1507 :
1508 13175 : for (fsp = sconn->files; fsp; fsp = next) {
1509 : struct files_struct *ret;
1510 1241 : next = fsp->next;
1511 1241 : ret = fn(fsp, private_data);
1512 1241 : if (ret != NULL) {
1513 52 : return ret;
1514 : }
1515 : }
1516 11934 : return NULL;
1517 : }
1518 :
1519 : /****************************************************************************
1520 : Find a fsp given a file descriptor.
1521 : ****************************************************************************/
1522 :
1523 0 : files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
1524 : {
1525 0 : int count=0;
1526 : files_struct *fsp;
1527 :
1528 0 : for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
1529 0 : if (fsp_get_pathref_fd(fsp) == fd) {
1530 0 : if (count > 10) {
1531 0 : DLIST_PROMOTE(sconn->files, fsp);
1532 : }
1533 0 : return fsp;
1534 : }
1535 : }
1536 :
1537 0 : return NULL;
1538 : }
1539 :
1540 : /****************************************************************************
1541 : Find a fsp given a device, inode and file_id.
1542 : ****************************************************************************/
1543 :
1544 20 : files_struct *file_find_dif(struct smbd_server_connection *sconn,
1545 : struct file_id id, unsigned long gen_id)
1546 : {
1547 20 : int count=0;
1548 : files_struct *fsp;
1549 :
1550 20 : if (gen_id == 0) {
1551 0 : return NULL;
1552 : }
1553 :
1554 66 : for (fsp = sconn->files; fsp; fsp = fsp->next,count++) {
1555 : /*
1556 : * We can have a fsp->fh->fd == -1 here as it could be a stat
1557 : * open.
1558 : */
1559 66 : if (!file_id_equal(&fsp->file_id, &id)) {
1560 26 : continue;
1561 : }
1562 40 : if (!fsp->fsp_flags.is_fsa) {
1563 20 : continue;
1564 : }
1565 20 : if (fh_get_gen_id(fsp->fh) != gen_id) {
1566 0 : continue;
1567 : }
1568 20 : if (count > 10) {
1569 0 : DLIST_PROMOTE(sconn->files, fsp);
1570 : }
1571 20 : return fsp;
1572 : }
1573 :
1574 0 : return NULL;
1575 : }
1576 :
1577 : /****************************************************************************
1578 : Find the first fsp given a device and inode.
1579 : We use a singleton cache here to speed up searching from getfilepathinfo
1580 : calls.
1581 : ****************************************************************************/
1582 :
1583 41 : files_struct *file_find_di_first(struct smbd_server_connection *sconn,
1584 : struct file_id id,
1585 : bool need_fsa)
1586 : {
1587 : files_struct *fsp;
1588 :
1589 41 : if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
1590 : /* Positive or negative cache hit. */
1591 0 : return sconn->fsp_fi_cache.fsp;
1592 : }
1593 :
1594 41 : sconn->fsp_fi_cache.id = id;
1595 :
1596 128 : for (fsp=sconn->files;fsp;fsp=fsp->next) {
1597 107 : if (need_fsa && !fsp->fsp_flags.is_fsa) {
1598 22 : continue;
1599 : }
1600 85 : if (file_id_equal(&fsp->file_id, &id)) {
1601 : /* Setup positive cache. */
1602 20 : sconn->fsp_fi_cache.fsp = fsp;
1603 20 : return fsp;
1604 : }
1605 : }
1606 :
1607 : /* Setup negative cache. */
1608 21 : sconn->fsp_fi_cache.fsp = NULL;
1609 21 : return NULL;
1610 : }
1611 :
1612 : /****************************************************************************
1613 : Find the next fsp having the same device and inode.
1614 : ****************************************************************************/
1615 :
1616 20 : files_struct *file_find_di_next(files_struct *start_fsp,
1617 : bool need_fsa)
1618 : {
1619 : files_struct *fsp;
1620 :
1621 20 : for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
1622 0 : if (need_fsa && !fsp->fsp_flags.is_fsa) {
1623 0 : continue;
1624 : }
1625 0 : if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
1626 0 : return fsp;
1627 : }
1628 : }
1629 :
1630 20 : return NULL;
1631 : }
1632 :
1633 0 : struct files_struct *file_find_one_fsp_from_lease_key(
1634 : struct smbd_server_connection *sconn,
1635 : const struct smb2_lease_key *lease_key)
1636 : {
1637 : struct files_struct *fsp;
1638 :
1639 0 : for (fsp = sconn->files; fsp; fsp=fsp->next) {
1640 0 : if ((fsp->lease != NULL) &&
1641 0 : (fsp->lease->lease.lease_key.data[0] ==
1642 0 : lease_key->data[0]) &&
1643 0 : (fsp->lease->lease.lease_key.data[1] ==
1644 0 : lease_key->data[1])) {
1645 0 : return fsp;
1646 : }
1647 : }
1648 0 : return NULL;
1649 : }
1650 :
1651 : /****************************************************************************
1652 : Find any fsp open with a pathname below that of an already open path.
1653 : ****************************************************************************/
1654 :
1655 0 : bool file_find_subpath(files_struct *dir_fsp)
1656 : {
1657 : files_struct *fsp;
1658 : size_t dlen;
1659 0 : char *d_fullname = NULL;
1660 :
1661 0 : d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
1662 0 : dir_fsp->conn->connectpath,
1663 0 : dir_fsp->fsp_name->base_name);
1664 :
1665 0 : if (!d_fullname) {
1666 0 : return false;
1667 : }
1668 :
1669 0 : dlen = strlen(d_fullname);
1670 :
1671 0 : for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
1672 : char *d1_fullname;
1673 :
1674 0 : if (fsp == dir_fsp) {
1675 0 : continue;
1676 : }
1677 :
1678 0 : d1_fullname = talloc_asprintf(talloc_tos(),
1679 : "%s/%s",
1680 0 : fsp->conn->connectpath,
1681 0 : fsp->fsp_name->base_name);
1682 :
1683 : /*
1684 : * If the open file has a path that is a longer
1685 : * component, then it's a subpath.
1686 : */
1687 0 : if (strnequal(d_fullname, d1_fullname, dlen) &&
1688 0 : (d1_fullname[dlen] == '/')) {
1689 0 : TALLOC_FREE(d1_fullname);
1690 0 : TALLOC_FREE(d_fullname);
1691 0 : return true;
1692 : }
1693 0 : TALLOC_FREE(d1_fullname);
1694 : }
1695 :
1696 0 : TALLOC_FREE(d_fullname);
1697 0 : return false;
1698 : }
1699 :
1700 : /****************************************************************************
1701 : Free up a fsp.
1702 : ****************************************************************************/
1703 :
1704 146984 : static void fsp_free(files_struct *fsp)
1705 : {
1706 146984 : struct smbd_server_connection *sconn = fsp->conn->sconn;
1707 :
1708 146984 : if (fsp == sconn->fsp_fi_cache.fsp) {
1709 4 : ZERO_STRUCT(sconn->fsp_fi_cache);
1710 : }
1711 :
1712 146984 : DLIST_REMOVE(sconn->files, fsp);
1713 146984 : SMB_ASSERT(sconn->num_files > 0);
1714 146984 : sconn->num_files--;
1715 :
1716 146984 : TALLOC_FREE(fsp->fake_file_handle);
1717 :
1718 146984 : if (fh_get_refcount(fsp->fh) == 1) {
1719 146984 : TALLOC_FREE(fsp->fh);
1720 : } else {
1721 0 : size_t new_refcount = fh_get_refcount(fsp->fh) - 1;
1722 0 : fh_set_refcount(fsp->fh, new_refcount);
1723 : }
1724 :
1725 146984 : if (fsp->lease != NULL) {
1726 0 : if (fsp->lease->ref_count == 1) {
1727 0 : TALLOC_FREE(fsp->lease);
1728 : } else {
1729 0 : fsp->lease->ref_count--;
1730 : }
1731 : }
1732 :
1733 146984 : fsp->conn->num_files_open--;
1734 :
1735 146984 : if (fsp->fsp_name != NULL &&
1736 142928 : fsp->fsp_name->fsp_link != NULL)
1737 : {
1738 : /*
1739 : * Free fsp_link of fsp->fsp_name. To do this in the correct
1740 : * talloc destructor order we have to do it here. The
1741 : * talloc_free() of the link should set the fsp pointer to NULL.
1742 : */
1743 129983 : TALLOC_FREE(fsp->fsp_name->fsp_link);
1744 129983 : SMB_ASSERT(fsp->fsp_name->fsp == NULL);
1745 : }
1746 :
1747 : /* this is paranoia, just in case someone tries to reuse the
1748 : information */
1749 146984 : ZERO_STRUCTP(fsp);
1750 :
1751 : /* fsp->fsp_name is a talloc child and is free'd automatically. */
1752 146984 : TALLOC_FREE(fsp);
1753 146984 : }
1754 :
1755 : /*
1756 : * Rundown of all smb-related sub-structures of an fsp
1757 : */
1758 164633 : void fsp_unbind_smb(struct smb_request *req, files_struct *fsp)
1759 : {
1760 164633 : if (fsp == fsp->conn->cwd_fsp) {
1761 0 : return;
1762 : }
1763 :
1764 164633 : if (fsp->notify) {
1765 30 : size_t len = fsp_fullbasepath(fsp, NULL, 0);
1766 30 : char fullpath[len+1];
1767 :
1768 30 : fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
1769 :
1770 : /*
1771 : * Avoid /. at the end of the path name. notify can't
1772 : * deal with it.
1773 : */
1774 30 : if (len > 1 && fullpath[len-1] == '.' &&
1775 24 : fullpath[len-2] == '/') {
1776 24 : fullpath[len-2] = '\0';
1777 : }
1778 :
1779 30 : notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
1780 30 : TALLOC_FREE(fsp->notify);
1781 : }
1782 :
1783 : /* Ensure this event will never fire. */
1784 164633 : TALLOC_FREE(fsp->update_write_time_event);
1785 :
1786 164633 : if (fsp->op != NULL) {
1787 17574 : fsp->op->compat = NULL;
1788 : }
1789 164633 : TALLOC_FREE(fsp->op);
1790 :
1791 164633 : if ((req != NULL) && (fsp == req->chain_fsp)) {
1792 17297 : req->chain_fsp = NULL;
1793 : }
1794 :
1795 : /*
1796 : * Clear all possible chained fsp
1797 : * pointers in the SMB2 request queue.
1798 : */
1799 164633 : remove_smb2_chained_fsp(fsp);
1800 : }
1801 :
1802 146984 : void file_free(struct smb_request *req, files_struct *fsp)
1803 : {
1804 146984 : struct smbd_server_connection *sconn = fsp->conn->sconn;
1805 146984 : uint64_t fnum = fsp->fnum;
1806 :
1807 146984 : fsp_unbind_smb(req, fsp);
1808 :
1809 : /* Drop all remaining extensions. */
1810 146984 : vfs_remove_all_fsp_extensions(fsp);
1811 :
1812 146984 : fsp_free(fsp);
1813 :
1814 146984 : DBG_INFO("freed files structure %"PRIu64" (%zu used)\n",
1815 : fnum,
1816 : sconn->num_files);
1817 146984 : }
1818 :
1819 : /****************************************************************************
1820 : Get an fsp from a packet given a 16 bit fnum.
1821 : ****************************************************************************/
1822 :
1823 0 : files_struct *file_fsp(struct smb_request *req, uint16_t fid)
1824 : {
1825 : struct smbXsrv_open *op;
1826 : NTSTATUS status;
1827 0 : NTTIME now = 0;
1828 : files_struct *fsp;
1829 :
1830 0 : if (req == NULL) {
1831 : /*
1832 : * We should never get here. req==NULL could in theory
1833 : * only happen from internal opens with a non-zero
1834 : * root_dir_fid. Internal opens just don't do that, at
1835 : * least they are not supposed to do so. And if they
1836 : * start to do so, they better fake up a smb_request
1837 : * from which we get the right smbd_server_conn. While
1838 : * this should never happen, let's return NULL here.
1839 : */
1840 0 : return NULL;
1841 : }
1842 :
1843 0 : if (req->chain_fsp != NULL) {
1844 0 : if (req->chain_fsp->fsp_flags.closing) {
1845 0 : return NULL;
1846 : }
1847 0 : return req->chain_fsp;
1848 : }
1849 :
1850 0 : if (req->xconn == NULL) {
1851 0 : return NULL;
1852 : }
1853 :
1854 0 : now = timeval_to_nttime(&req->request_time);
1855 :
1856 0 : status = smb1srv_open_lookup(req->xconn,
1857 : fid, now, &op);
1858 0 : if (!NT_STATUS_IS_OK(status)) {
1859 0 : return NULL;
1860 : }
1861 :
1862 0 : fsp = op->compat;
1863 0 : if (fsp == NULL) {
1864 0 : return NULL;
1865 : }
1866 :
1867 0 : if (fsp->fsp_flags.closing) {
1868 0 : return NULL;
1869 : }
1870 :
1871 0 : req->chain_fsp = fsp;
1872 0 : fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTES_INVALID;
1873 0 : return fsp;
1874 : }
1875 :
1876 115386 : struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
1877 : uint64_t persistent_id,
1878 : uint64_t volatile_id)
1879 : {
1880 : struct smbXsrv_open *op;
1881 : NTSTATUS status;
1882 115386 : NTTIME now = 0;
1883 : struct files_struct *fsp;
1884 :
1885 115386 : now = timeval_to_nttime(&smb2req->request_time);
1886 :
1887 115386 : status = smb2srv_open_lookup(smb2req->xconn,
1888 : persistent_id, volatile_id,
1889 : now, &op);
1890 115386 : if (!NT_STATUS_IS_OK(status)) {
1891 1671 : return NULL;
1892 : }
1893 :
1894 113715 : fsp = op->compat;
1895 113715 : if (fsp == NULL) {
1896 0 : return NULL;
1897 : }
1898 :
1899 113715 : if (smb2req->tcon == NULL) {
1900 0 : return NULL;
1901 : }
1902 :
1903 113715 : if (smb2req->tcon->compat != fsp->conn) {
1904 0 : return NULL;
1905 : }
1906 :
1907 113715 : if (smb2req->session == NULL) {
1908 0 : return NULL;
1909 : }
1910 :
1911 113715 : if (smb2req->session->global->session_wire_id != fsp->vuid) {
1912 0 : return NULL;
1913 : }
1914 :
1915 113715 : if (fsp->fsp_flags.closing) {
1916 0 : return NULL;
1917 : }
1918 :
1919 113715 : fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTES_INVALID;
1920 :
1921 113715 : return fsp;
1922 : }
1923 :
1924 229097 : struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
1925 : uint64_t persistent_id,
1926 : uint64_t volatile_id)
1927 : {
1928 : struct files_struct *fsp;
1929 :
1930 229097 : if (smb2req->compat_chain_fsp != NULL) {
1931 113711 : if (smb2req->compat_chain_fsp->fsp_flags.closing) {
1932 0 : return NULL;
1933 : }
1934 113711 : smb2req->compat_chain_fsp->fsp_name->st.cached_dos_attributes =
1935 : FILE_ATTRIBUTES_INVALID;
1936 113711 : return smb2req->compat_chain_fsp;
1937 : }
1938 :
1939 115386 : fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
1940 115386 : if (fsp == NULL) {
1941 1671 : return NULL;
1942 : }
1943 :
1944 113715 : smb2req->compat_chain_fsp = fsp;
1945 113715 : return fsp;
1946 : }
1947 :
1948 : /****************************************************************************
1949 : Duplicate the file handle part for a DOS or FCB open.
1950 : ****************************************************************************/
1951 :
1952 0 : NTSTATUS dup_file_fsp(
1953 : files_struct *from,
1954 : uint32_t access_mask,
1955 : files_struct *to)
1956 : {
1957 : size_t new_refcount;
1958 :
1959 : /* this can never happen for print files */
1960 0 : SMB_ASSERT(from->print_file == NULL);
1961 :
1962 0 : TALLOC_FREE(to->fh);
1963 :
1964 0 : to->fh = from->fh;
1965 0 : new_refcount = fh_get_refcount(to->fh) + 1;
1966 0 : fh_set_refcount(to->fh, new_refcount);
1967 :
1968 0 : to->file_id = from->file_id;
1969 0 : to->initial_allocation_size = from->initial_allocation_size;
1970 0 : to->file_pid = from->file_pid;
1971 0 : to->vuid = from->vuid;
1972 0 : to->open_time = from->open_time;
1973 0 : to->access_mask = access_mask;
1974 0 : to->oplock_type = from->oplock_type;
1975 0 : to->fsp_flags.can_lock = from->fsp_flags.can_lock;
1976 0 : to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
1977 0 : to->fsp_flags.can_write =
1978 0 : CAN_WRITE(from->conn) &&
1979 0 : ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
1980 0 : if (from->fsp_name->twrp != 0) {
1981 0 : to->fsp_flags.can_write = false;
1982 : }
1983 0 : to->fsp_flags.modified = from->fsp_flags.modified;
1984 0 : to->fsp_flags.is_directory = from->fsp_flags.is_directory;
1985 0 : to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
1986 0 : to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
1987 0 : to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
1988 0 : to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
1989 0 : to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
1990 :
1991 0 : return fsp_set_smb_fname(to, from->fsp_name);
1992 : }
1993 :
1994 : /**
1995 : * Return a jenkins hash of a pathname on a connection.
1996 : */
1997 :
1998 130072 : NTSTATUS file_name_hash(connection_struct *conn,
1999 : const char *name, uint32_t *p_name_hash)
2000 : {
2001 : char tmpbuf[PATH_MAX];
2002 : char *fullpath, *to_free;
2003 : ssize_t len;
2004 : TDB_DATA key;
2005 :
2006 : /* Set the hash of the full pathname. */
2007 :
2008 130072 : if (name[0] == '/') {
2009 34736 : strlcpy(tmpbuf, name, sizeof(tmpbuf));
2010 34736 : fullpath = tmpbuf;
2011 34736 : len = strlen(fullpath);
2012 34736 : to_free = NULL;
2013 : } else {
2014 95336 : len = full_path_tos(conn->connectpath,
2015 : name,
2016 : tmpbuf,
2017 : sizeof(tmpbuf),
2018 : &fullpath,
2019 : &to_free);
2020 : }
2021 130072 : if (len == -1) {
2022 0 : return NT_STATUS_NO_MEMORY;
2023 : }
2024 130072 : key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
2025 130072 : *p_name_hash = tdb_jenkins_hash(&key);
2026 :
2027 130072 : DEBUG(10,("file_name_hash: %s hash 0x%x\n",
2028 : fullpath,
2029 : (unsigned int)*p_name_hash ));
2030 :
2031 130072 : TALLOC_FREE(to_free);
2032 130072 : return NT_STATUS_OK;
2033 : }
2034 :
2035 130035 : static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
2036 : struct smb_filename **_smb_fname)
2037 : {
2038 130035 : struct smb_filename *smb_fname_new = talloc_move(fsp, _smb_fname);
2039 130035 : const char *name_str = NULL;
2040 130035 : uint32_t name_hash = 0;
2041 : NTSTATUS status;
2042 :
2043 130035 : name_str = smb_fname_str_dbg(smb_fname_new);
2044 130035 : if (name_str == NULL) {
2045 0 : return NT_STATUS_NO_MEMORY;
2046 : }
2047 :
2048 130035 : status = file_name_hash(fsp->conn,
2049 : name_str,
2050 : &name_hash);
2051 130035 : if (!NT_STATUS_IS_OK(status)) {
2052 0 : return status;
2053 : }
2054 :
2055 130035 : status = fsp_smb_fname_link(fsp,
2056 : &smb_fname_new->fsp_link,
2057 : &smb_fname_new->fsp);
2058 130035 : if (!NT_STATUS_IS_OK(status)) {
2059 0 : return status;
2060 : }
2061 :
2062 130035 : fsp->name_hash = name_hash;
2063 130035 : fsp->fsp_name = smb_fname_new;
2064 130035 : fsp->fsp_name->st.cached_dos_attributes = FILE_ATTRIBUTES_INVALID;
2065 130035 : *_smb_fname = NULL;
2066 130035 : return NT_STATUS_OK;
2067 : }
2068 :
2069 : /**
2070 : * The only way that the fsp->fsp_name field should ever be set.
2071 : */
2072 16073 : NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
2073 : const struct smb_filename *smb_fname_in)
2074 : {
2075 16073 : struct smb_filename *smb_fname_old = fsp->fsp_name;
2076 16073 : struct smb_filename *smb_fname_new = NULL;
2077 : NTSTATUS status;
2078 :
2079 16073 : smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
2080 16073 : if (smb_fname_new == NULL) {
2081 0 : return NT_STATUS_NO_MEMORY;
2082 : }
2083 :
2084 16073 : status = fsp_attach_smb_fname(fsp, &smb_fname_new);
2085 16073 : if (!NT_STATUS_IS_OK(status)) {
2086 0 : TALLOC_FREE(smb_fname_new);
2087 0 : return status;
2088 : }
2089 :
2090 16073 : if (smb_fname_old != NULL) {
2091 9523 : smb_fname_fsp_unlink(smb_fname_old);
2092 9523 : TALLOC_FREE(smb_fname_old);
2093 : }
2094 :
2095 16073 : return NT_STATUS_OK;
2096 : }
2097 :
2098 120 : size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
2099 : {
2100 120 : int len = 0;
2101 120 : char tmp_buf[1] = {'\0'};
2102 :
2103 : /*
2104 : * Don't pass NULL buffer to snprintf (to satisfy static checker)
2105 : * Some callers will call this function with NULL for buf and
2106 : * 0 for buflen in order to get length of fullbasepath (without
2107 : * needing to allocate or write to buf)
2108 : */
2109 120 : if (buf == NULL) {
2110 60 : buf = tmp_buf;
2111 60 : SMB_ASSERT(buflen==0);
2112 : }
2113 :
2114 120 : len = snprintf(buf, buflen, "%s/%s", fsp->conn->connectpath,
2115 120 : fsp->fsp_name->base_name);
2116 120 : SMB_ASSERT(len>0);
2117 :
2118 120 : return len;
2119 : }
2120 :
2121 156011 : void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
2122 : {
2123 156011 : SMB_ASSERT(fsp->stream_fsp == NULL);
2124 156011 : if (base_fsp != NULL) {
2125 136 : SMB_ASSERT(base_fsp->base_fsp == NULL);
2126 136 : SMB_ASSERT(base_fsp->stream_fsp == NULL);
2127 : }
2128 :
2129 156011 : if (fsp->base_fsp != NULL) {
2130 56 : SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
2131 56 : fsp->base_fsp->stream_fsp = NULL;
2132 : }
2133 :
2134 156011 : fsp->base_fsp = base_fsp;
2135 156011 : if (fsp->base_fsp != NULL) {
2136 136 : fsp->base_fsp->stream_fsp = fsp;
2137 : }
2138 156011 : }
2139 :
2140 472041 : bool fsp_is_alternate_stream(const struct files_struct *fsp)
2141 : {
2142 472041 : return (fsp->base_fsp != NULL);
2143 : }
2144 :
2145 61745 : struct files_struct *metadata_fsp(struct files_struct *fsp)
2146 : {
2147 61745 : if (fsp_is_alternate_stream(fsp)) {
2148 246 : return fsp->base_fsp;
2149 : }
2150 61499 : return fsp;
2151 : }
2152 :
2153 7108 : static bool fsp_generic_ask_sharemode(struct files_struct *fsp)
2154 : {
2155 7108 : if (fsp == NULL) {
2156 0 : return false;
2157 : }
2158 :
2159 7108 : if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
2160 : /* Always use filesystem for UNIX mtime query. */
2161 0 : return false;
2162 : }
2163 :
2164 7108 : return true;
2165 : }
2166 :
2167 4292 : bool fsp_search_ask_sharemode(struct files_struct *fsp)
2168 : {
2169 4292 : if (!fsp_generic_ask_sharemode(fsp)) {
2170 0 : return false;
2171 : }
2172 :
2173 4292 : return lp_smbd_search_ask_sharemode(SNUM(fsp->conn));
2174 : }
2175 :
2176 2816 : bool fsp_getinfo_ask_sharemode(struct files_struct *fsp)
2177 : {
2178 2816 : if (!fsp_generic_ask_sharemode(fsp)) {
2179 0 : return false;
2180 : }
2181 :
2182 2816 : return lp_smbd_getinfo_ask_sharemode(SNUM(fsp->conn));
2183 : }
|