smbd: Make reopen_from_fsp() public
[samba4-gss.git] / source3 / smbd / filename.c
blobe6bc60ae217e0bfe690312126cb189844d154a18
1 /*
2 Unix SMB/CIFS implementation.
3 filename handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1999-2007
6 Copyright (C) Ying Chen 2000
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * New hash table stat cache code added by Ying Chen.
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "fake_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "libcli/smb/reparse.h"
33 #include "source3/smbd/dir.h"
35 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
37 uint32_t ucf_flags = 0;
39 if (req == NULL) {
40 return 0;
43 if (req->posix_pathnames) {
44 ucf_flags |= UCF_POSIX_PATHNAMES;
46 if (!conn_using_smb2(req->sconn)) {
47 ucf_flags |= UCF_LCOMP_LNK_OK;
50 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
51 ucf_flags |= UCF_DFS_PATHNAME;
53 if (req->flags2 & FLAGS2_REPARSE_PATH) {
54 ucf_flags |= UCF_GMT_PATHNAME;
57 return ucf_flags;
60 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
62 uint32_t ucf_flags = 0;
64 ucf_flags |= ucf_flags_from_smb_request(req);
66 switch (create_disposition) {
67 case FILE_OPEN:
68 case FILE_OVERWRITE:
69 break;
70 case FILE_SUPERSEDE:
71 case FILE_CREATE:
72 case FILE_OPEN_IF:
73 case FILE_OVERWRITE_IF:
74 ucf_flags |= UCF_PREP_CREATEFILE;
75 break;
78 return ucf_flags;
81 /****************************************************************************
82 Mangle the 2nd name and check if it is then equal to the first name.
83 ****************************************************************************/
85 static bool mangled_equal(const char *name1,
86 const char *name2,
87 const struct share_params *p)
89 char mname[13];
91 if (!name_to_8_3(name2, mname, False, p)) {
92 return False;
94 return strequal(name1, mname);
98 * Strip a valid @GMT-token from any incoming filename path,
99 * adding any NTTIME encoded in the pathname into the
100 * twrp field of the passed in smb_fname.
102 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
103 * at the *start* of a pathname component.
105 * If twrp is passed in then smb_fname->twrp is set to that
106 * value, and the @GMT-token part of the filename is removed
107 * and does not change the stored smb_fname->twrp.
111 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
112 uint32_t ucf_flags,
113 NTTIME twrp)
115 bool found;
117 if (twrp != 0) {
118 smb_fname->twrp = twrp;
121 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
122 return NT_STATUS_OK;
125 found = extract_snapshot_token(smb_fname->base_name, &twrp);
126 if (!found) {
127 return NT_STATUS_OK;
130 if (smb_fname->twrp == 0) {
131 smb_fname->twrp = twrp;
134 return NT_STATUS_OK;
137 static bool strnorm(char *s, int case_default)
139 if (case_default == CASE_UPPER)
140 return strupper_m(s);
141 else
142 return strlower_m(s);
146 * Utility function to normalize case on an incoming client filename
147 * if required on this connection struct.
148 * Performs an in-place case conversion guaranteed to stay the same size.
151 static NTSTATUS normalize_filename_case(connection_struct *conn,
152 char *filename,
153 uint32_t ucf_flags)
155 bool ok;
157 if (ucf_flags & UCF_POSIX_PATHNAMES) {
159 * POSIX never normalizes filename case.
161 return NT_STATUS_OK;
163 if (!conn->case_sensitive) {
164 return NT_STATUS_OK;
166 if (conn->case_preserve) {
167 return NT_STATUS_OK;
169 if (conn->short_case_preserve) {
170 return NT_STATUS_OK;
172 ok = strnorm(filename, lp_default_case(SNUM(conn)));
173 if (!ok) {
174 return NT_STATUS_INVALID_PARAMETER;
176 return NT_STATUS_OK;
179 /****************************************************************************
180 Check if two filenames are equal.
181 This needs to be careful about whether we are case sensitive.
182 ****************************************************************************/
184 static bool fname_equal(const char *name1, const char *name2,
185 bool case_sensitive)
187 /* Normal filename handling */
188 if (case_sensitive) {
189 return(strcmp(name1,name2) == 0);
192 return(strequal(name1,name2));
195 static bool sname_equal(const char *name1, const char *name2,
196 bool case_sensitive)
198 bool match;
199 const char *s1 = NULL;
200 const char *s2 = NULL;
201 size_t n1;
202 size_t n2;
203 const char *e1 = NULL;
204 const char *e2 = NULL;
205 char *c1 = NULL;
206 char *c2 = NULL;
208 match = fname_equal(name1, name2, case_sensitive);
209 if (match) {
210 return true;
213 if (name1[0] != ':') {
214 return false;
216 if (name2[0] != ':') {
217 return false;
219 s1 = &name1[1];
220 e1 = strchr(s1, ':');
221 if (e1 == NULL) {
222 n1 = strlen(s1);
223 } else {
224 n1 = PTR_DIFF(e1, s1);
226 s2 = &name2[1];
227 e2 = strchr(s2, ':');
228 if (e2 == NULL) {
229 n2 = strlen(s2);
230 } else {
231 n2 = PTR_DIFF(e2, s2);
234 /* Normal filename handling */
235 if (case_sensitive) {
236 return (strncmp(s1, s2, n1) == 0);
240 * We can't use strnequal() here
241 * as it takes the number of codepoints
242 * and not the number of bytes.
244 * So we make a copy before calling
245 * strequal().
247 * Note that we TALLOC_FREE() in reverse order
248 * in order to avoid memory fragmentation.
251 c1 = talloc_strndup(talloc_tos(), s1, n1);
252 c2 = talloc_strndup(talloc_tos(), s2, n2);
253 if (c1 == NULL || c2 == NULL) {
254 TALLOC_FREE(c2);
255 TALLOC_FREE(c1);
256 return (strncmp(s1, s2, n1) == 0);
259 match = strequal(c1, c2);
260 TALLOC_FREE(c2);
261 TALLOC_FREE(c1);
262 return match;
265 /****************************************************************************
266 Scan a directory to find a filename, matching without case sensitivity.
267 If the name looks like a mangled name then try via the mangling functions
268 ****************************************************************************/
270 NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
271 const char *name,
272 bool mangled,
273 TALLOC_CTX *mem_ctx,
274 char **found_name)
276 struct connection_struct *conn = dirfsp->conn;
277 struct smb_Dir *cur_dir = NULL;
278 const char *dname = NULL;
279 char *talloced = NULL;
280 char *unmangled_name = NULL;
281 NTSTATUS status;
283 /* If we have a case-sensitive filesystem, it doesn't do us any
284 * good to search for a name. If a case variation of the name was
285 * there, then the original stat(2) would have found it.
287 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
288 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
292 * The incoming name can be mangled, and if we de-mangle it
293 * here it will not compare correctly against the filename (name2)
294 * read from the directory and then mangled by the name_to_8_3()
295 * call. We need to mangle both names or neither.
296 * (JRA).
298 * Fix for bug found by Dina Fine. If in case sensitive mode then
299 * the mangle cache is no good (3 letter extension could be wrong
300 * case - so don't demangle in this case - leave as mangled and
301 * allow the mangling of the directory entry read (which is done
302 * case insensitively) to match instead. This will lead to more
303 * false positive matches but we fail completely without it. JRA.
306 if (mangled && !conn->case_sensitive) {
307 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
308 &unmangled_name,
309 conn->params);
310 if (!mangled) {
311 /* Name is now unmangled. */
312 name = unmangled_name;
316 /* open the directory */
317 status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
318 if (!NT_STATUS_IS_OK(status)) {
319 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
320 fsp_str_dbg(dirfsp),
321 nt_errstr(status));
322 TALLOC_FREE(unmangled_name);
323 return status;
326 /* now scan for matching names */
327 while ((dname = ReadDirName(cur_dir, &talloced))) {
329 /* Is it dot or dot dot. */
330 if (ISDOT(dname) || ISDOTDOT(dname)) {
331 TALLOC_FREE(talloced);
332 continue;
336 * At this point dname is the unmangled name.
337 * name is either mangled or not, depending on the state
338 * of the "mangled" variable. JRA.
342 * Check mangled name against mangled name, or unmangled name
343 * against unmangled name.
346 if ((mangled && mangled_equal(name,dname,conn->params)) ||
347 fname_equal(name, dname, conn->case_sensitive)) {
348 /* we've found the file, change it's name and return */
349 *found_name = talloc_strdup(mem_ctx, dname);
350 TALLOC_FREE(unmangled_name);
351 TALLOC_FREE(cur_dir);
352 if (!*found_name) {
353 TALLOC_FREE(talloced);
354 return NT_STATUS_NO_MEMORY;
356 TALLOC_FREE(talloced);
357 return NT_STATUS_OK;
359 TALLOC_FREE(talloced);
362 TALLOC_FREE(unmangled_name);
363 TALLOC_FREE(cur_dir);
364 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
367 /****************************************************************************
368 Wrapper around the vfs get_real_filename and the full directory scan
369 fallback.
370 ****************************************************************************/
372 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
373 const char *name,
374 TALLOC_CTX *mem_ctx,
375 char **found_name)
377 struct connection_struct *conn = dirfsp->conn;
378 NTSTATUS status;
379 bool mangled;
381 mangled = mangle_is_mangled(name, conn->params);
383 if (mangled) {
384 status = get_real_filename_full_scan_at(
385 dirfsp, name, mangled, mem_ctx, found_name);
386 return status;
389 /* Try the vfs first to take advantage of case-insensitive stat. */
390 status = SMB_VFS_GET_REAL_FILENAME_AT(
391 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
394 * If the case-insensitive stat was successful, or returned an error
395 * other than EOPNOTSUPP then there is no need to fall back on the
396 * full directory scan.
398 if (NT_STATUS_IS_OK(status) ||
399 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
400 return status;
403 status = get_real_filename_full_scan_at(
404 dirfsp, name, mangled, mem_ctx, found_name);
405 return status;
409 * Lightweight function to just get last component
410 * for rename / enumerate directory calls.
413 char *get_original_lcomp(TALLOC_CTX *ctx,
414 connection_struct *conn,
415 const char *filename_in,
416 uint32_t ucf_flags)
418 char *last_slash = NULL;
419 char *orig_lcomp;
420 NTSTATUS status;
422 last_slash = strrchr(filename_in, '/');
423 if (last_slash != NULL) {
424 orig_lcomp = talloc_strdup(ctx, last_slash+1);
425 } else {
426 orig_lcomp = talloc_strdup(ctx, filename_in);
428 if (orig_lcomp == NULL) {
429 return NULL;
431 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
432 if (!NT_STATUS_IS_OK(status)) {
433 TALLOC_FREE(orig_lcomp);
434 return NULL;
436 return orig_lcomp;
440 * Get the correct capitalized stream name hanging off
441 * base_fsp. Equivalent of get_real_filename(), but for streams.
443 static NTSTATUS get_real_stream_name(
444 TALLOC_CTX *mem_ctx,
445 struct files_struct *base_fsp,
446 const char *stream_name,
447 char **_found)
449 unsigned int i, num_streams = 0;
450 struct stream_struct *streams = NULL;
451 NTSTATUS status;
453 status = vfs_fstreaminfo(
454 base_fsp, talloc_tos(), &num_streams, &streams);
455 if (!NT_STATUS_IS_OK(status)) {
456 return status;
459 for (i=0; i<num_streams; i++) {
460 bool equal = sname_equal(stream_name, streams[i].name, false);
462 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
463 stream_name,
464 streams[i].name,
465 equal ? "" : "not ");
467 if (equal) {
468 *_found = talloc_move(mem_ctx, &streams[i].name);
469 TALLOC_FREE(streams);
470 return NT_STATUS_OK;
474 TALLOC_FREE(streams);
475 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
478 static bool filename_split_lcomp(
479 TALLOC_CTX *mem_ctx,
480 const char *name_in,
481 bool posix,
482 char **_dirname,
483 const char **_fname_rel,
484 const char **_streamname)
486 const char *lcomp = NULL;
487 const char *fname_rel = NULL;
488 const char *streamname = NULL;
489 char *dirname = NULL;
491 if (name_in[0] == '\0') {
492 fname_rel = ".";
493 dirname = talloc_strdup(mem_ctx, "");
494 if (dirname == NULL) {
495 return false;
497 goto done;
500 lcomp = strrchr_m(name_in, '/');
501 if (lcomp != NULL) {
502 fname_rel = lcomp+1;
503 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
504 if (dirname == NULL) {
505 return false;
507 goto find_stream;
511 * No slash, dir is empty
513 dirname = talloc_strdup(mem_ctx, "");
514 if (dirname == NULL) {
515 return false;
518 if (!posix && (name_in[0] == ':')) {
520 * Special case for stream on root directory
522 fname_rel = ".";
523 streamname = name_in;
524 goto done;
527 fname_rel = name_in;
529 find_stream:
530 if (!posix) {
531 streamname = strchr_m(fname_rel, ':');
533 if (streamname != NULL) {
534 fname_rel = talloc_strndup(
535 mem_ctx,
536 fname_rel,
537 streamname - fname_rel);
538 if (fname_rel == NULL) {
539 TALLOC_FREE(dirname);
540 return false;
545 done:
546 *_dirname = dirname;
547 *_fname_rel = fname_rel;
548 *_streamname = streamname;
549 return true;
553 * Create the correct capitalization of a file name to be created.
555 static NTSTATUS filename_convert_normalize_new(
556 TALLOC_CTX *mem_ctx,
557 struct connection_struct *conn,
558 char *name_in,
559 char **_normalized)
561 char *name = name_in;
563 *_normalized = NULL;
565 if (!conn->case_preserve ||
566 (mangle_is_8_3(name, false,
567 conn->params) &&
568 !conn->short_case_preserve)) {
570 char *normalized = talloc_strdup(mem_ctx, name);
571 if (normalized == NULL) {
572 return NT_STATUS_NO_MEMORY;
575 strnorm(normalized, lp_default_case(SNUM(conn)));
576 name = normalized;
579 if (mangle_is_mangled(name, conn->params)) {
580 bool found;
581 char *unmangled = NULL;
583 found = mangle_lookup_name_from_8_3(
584 mem_ctx, name, &unmangled, conn->params);
585 if (found) {
586 name = unmangled;
590 if (name != name_in) {
591 *_normalized = name;
594 return NT_STATUS_OK;
597 NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
598 const char *connectpath,
599 const char *dir,
600 const char *target,
601 size_t unparsed,
602 char **_relative)
604 char *abs_target = NULL;
605 char *abs_target_canon = NULL;
606 const char *relative = NULL;
607 bool in_share;
608 NTSTATUS status = NT_STATUS_NO_MEMORY;
610 DBG_DEBUG("connectpath [%s] target [%s] unparsed [%zu]\n",
611 connectpath, target, unparsed);
613 if (target[0] == '/') {
614 abs_target = talloc_strdup(mem_ctx, target);
615 } else if (dir == NULL) {
616 abs_target = talloc_asprintf(mem_ctx,
617 "%s/%s",
618 connectpath,
619 target);
620 } else if (dir[0] == '/') {
621 abs_target = talloc_asprintf(mem_ctx,
622 "%s/%s",
623 dir,
624 target);
625 } else {
626 abs_target = talloc_asprintf(mem_ctx,
627 "%s/%s/%s",
628 connectpath,
629 dir,
630 target);
632 if (abs_target == NULL) {
633 goto fail;
636 abs_target_canon = canonicalize_absolute_path(abs_target, abs_target);
637 if (abs_target_canon == NULL) {
638 goto fail;
641 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
643 in_share = subdir_of(
644 connectpath, strlen(connectpath), abs_target_canon, &relative);
645 if (!in_share) {
646 DBG_DEBUG("wide link to %s\n", abs_target_canon);
647 status = (unparsed != 0) ? NT_STATUS_OBJECT_PATH_NOT_FOUND
648 : NT_STATUS_OBJECT_NAME_NOT_FOUND;
649 goto fail;
652 *_relative = talloc_strdup(mem_ctx, relative);
653 if (*_relative == NULL) {
654 goto fail;
657 status = NT_STATUS_OK;
658 fail:
659 TALLOC_FREE(abs_target);
660 return status;
664 * Split up name_in as sent by the client into a directory pathref fsp
665 * and a relative smb_filename.
667 static NTSTATUS filename_convert_dirfsp_nosymlink(
668 TALLOC_CTX *mem_ctx,
669 connection_struct *conn,
670 const char *name_in,
671 uint32_t ucf_flags,
672 NTTIME twrp,
673 struct files_struct **_dirfsp,
674 struct smb_filename **_smb_fname,
675 struct reparse_data_buffer **_symlink_err)
677 struct smb_filename *smb_dirname = NULL;
678 struct smb_filename *smb_fname_rel = NULL;
679 struct smb_filename *smb_fname = NULL;
680 struct reparse_data_buffer *symlink_err = NULL;
681 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
682 char *dirname = NULL;
683 const char *fname_rel = NULL;
684 const char *streamname = NULL;
685 char *saved_streamname = NULL;
686 struct files_struct *base_fsp = NULL;
687 bool ok;
688 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
690 SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
692 if (is_fake_file_path(name_in)) {
693 const struct timespec omit = make_omit_timespec();
694 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
695 if (smb_fname == NULL) {
696 return NT_STATUS_NO_MEMORY;
698 smb_fname->st = (SMB_STRUCT_STAT){
699 .st_ex_nlink = 1,
700 .st_ex_mode = S_IFREG | 0644,
701 .st_ex_btime = omit,
702 .st_ex_atime = omit,
703 .st_ex_mtime = omit,
704 .st_ex_ctime = omit,
707 *_dirfsp = conn->cwd_fsp;
708 *_smb_fname = smb_fname;
709 return NT_STATUS_OK;
713 * Catch an invalid path of "." before we
714 * call filename_split_lcomp(). We need to
715 * do this as filename_split_lcomp() will
716 * use "." for the missing relative component
717 * when an empty name_in path is sent by
718 * the client.
720 if (ISDOT(name_in)) {
721 status = NT_STATUS_OBJECT_NAME_INVALID;
722 goto fail;
725 ok = filename_split_lcomp(
726 talloc_tos(),
727 name_in,
728 posix,
729 &dirname,
730 &fname_rel,
731 &streamname);
732 if (!ok) {
733 status = NT_STATUS_NO_MEMORY;
734 goto fail;
737 if ((streamname != NULL) &&
738 ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
739 status = NT_STATUS_OBJECT_NAME_INVALID;
740 goto fail;
743 if (!posix) {
744 bool name_has_wild = ms_has_wild(dirname);
745 name_has_wild |= ms_has_wild(fname_rel);
746 if (name_has_wild) {
747 status = NT_STATUS_OBJECT_NAME_INVALID;
748 goto fail;
752 if (dirname[0] == '\0') {
753 status = synthetic_pathref(
754 mem_ctx,
755 conn->cwd_fsp,
756 ".",
757 NULL,
758 NULL,
760 posix ? SMB_FILENAME_POSIX_PATH : 0,
761 &smb_dirname);
762 } else {
763 status = normalize_filename_case(conn, dirname, ucf_flags);
764 if (!NT_STATUS_IS_OK(status)) {
765 DBG_ERR("normalize_filename_case %s failed: %s\n",
766 dirname,
767 nt_errstr(status));
768 goto fail;
771 status = openat_pathref_fsp_nosymlink(mem_ctx,
772 conn,
773 conn->cwd_fsp,
774 dirname,
775 twrp,
776 posix,
777 &smb_dirname,
778 &symlink_err);
780 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
781 struct symlink_reparse_struct
782 *lnk = &symlink_err->parsed.lnk;
783 size_t unparsed = lnk->unparsed_path_length;
784 size_t name_in_len, dirname_len;
786 name_in_len = strlen(name_in);
787 dirname_len = strlen(dirname);
789 SMB_ASSERT(name_in_len >= dirname_len);
791 unparsed += (name_in_len - dirname_len);
793 if (unparsed > UINT16_MAX) {
794 status = NT_STATUS_BUFFER_OVERFLOW;
795 goto fail;
798 lnk->unparsed_path_length = unparsed;
799 *_symlink_err = symlink_err;
801 goto fail;
805 if (!NT_STATUS_IS_OK(status)) {
806 DBG_DEBUG("opening directory %s failed: %s\n",
807 dirname,
808 nt_errstr(status));
809 TALLOC_FREE(dirname);
811 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
813 * Except ACCESS_DENIED, everything else leads
814 * to PATH_NOT_FOUND.
816 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
819 goto fail;
822 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
823 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
824 goto fail;
826 smb_dirname->fsp->fsp_flags.is_directory = true;
829 * Only look at bad last component values
830 * once we know we have a valid directory. That
831 * way we won't confuse error messages from
832 * opening the directory path with error
833 * messages from a bad last component.
836 /* Relative filename can't be empty */
837 if (fname_rel[0] == '\0') {
838 status = NT_STATUS_OBJECT_NAME_INVALID;
839 goto fail;
842 /* Relative filename can't be ".." */
843 if (ISDOTDOT(fname_rel)) {
844 status = NT_STATUS_OBJECT_NAME_INVALID;
845 goto fail;
847 /* Relative name can only be dot if directory is empty. */
848 if (ISDOT(fname_rel) && dirname[0] != '\0') {
849 status = NT_STATUS_OBJECT_NAME_INVALID;
850 goto fail;
853 TALLOC_FREE(dirname);
855 smb_fname_rel = synthetic_smb_fname(
856 mem_ctx,
857 fname_rel,
858 streamname,
859 NULL,
860 twrp,
861 posix ? SMB_FILENAME_POSIX_PATH : 0);
862 if (smb_fname_rel == NULL) {
863 status = NT_STATUS_NO_MEMORY;
864 goto fail;
867 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
868 is_named_stream(smb_fname_rel)) {
870 * Find the base_fsp first without the stream.
872 saved_streamname = smb_fname_rel->stream_name;
873 smb_fname_rel->stream_name = NULL;
876 status = normalize_filename_case(
877 conn, smb_fname_rel->base_name, ucf_flags);
878 if (!NT_STATUS_IS_OK(status)) {
879 DBG_ERR("normalize_filename_case %s failed: %s\n",
880 smb_fname_rel->base_name,
881 nt_errstr(status));
882 goto fail;
885 status = openat_pathref_fsp_lcomp(smb_dirname->fsp,
886 smb_fname_rel,
887 ucf_flags);
889 if (NT_STATUS_IS_OK(status) && S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
892 * Upper layers might need the link target. Here we
893 * still have the relname around, get the symlink err.
895 status = read_symlink_reparse(mem_ctx,
896 smb_dirname->fsp,
897 smb_fname_rel,
898 &symlink_err);
899 if (!NT_STATUS_IS_OK(status)) {
900 DBG_DEBUG("Could not read symlink for %s: %s\n",
901 smb_fname_str_dbg(
902 smb_fname_rel->fsp->fsp_name),
903 nt_errstr(status));
904 goto fail;
908 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
909 !VALID_STAT(smb_fname_rel->st)) {
911 char *normalized = NULL;
914 * Creating a new file
917 status = filename_convert_normalize_new(
918 smb_fname_rel,
919 conn,
920 smb_fname_rel->base_name,
921 &normalized);
922 if (!NT_STATUS_IS_OK(status)) {
923 DBG_DEBUG("filename_convert_normalize_new failed: "
924 "%s\n",
925 nt_errstr(status));
926 goto fail;
928 if (normalized != NULL) {
929 smb_fname_rel->base_name = normalized;
932 smb_fname_rel->stream_name = saved_streamname;
934 smb_fname = full_path_from_dirfsp_atname(
935 mem_ctx, smb_dirname->fsp, smb_fname_rel);
936 if (smb_fname == NULL) {
937 status = NT_STATUS_NO_MEMORY;
938 goto fail;
940 goto done;
943 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
944 /* A vetoed file, pretend it's not there */
945 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
947 if (!NT_STATUS_IS_OK(status)) {
948 goto fail;
951 if (saved_streamname == NULL) {
952 /* smb_fname must be allocated off mem_ctx. */
953 smb_fname = cp_smb_filename(mem_ctx,
954 smb_fname_rel->fsp->fsp_name);
955 if (smb_fname == NULL) {
956 goto fail;
958 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
959 if (!NT_STATUS_IS_OK(status)) {
960 goto fail;
962 goto done;
965 base_fsp = smb_fname_rel->fsp;
966 smb_fname_fsp_unlink(smb_fname_rel);
967 SET_STAT_INVALID(smb_fname_rel->st);
969 smb_fname_rel->stream_name = saved_streamname;
971 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
973 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
974 !conn->case_sensitive) {
975 char *found = NULL;
977 status = get_real_stream_name(
978 smb_fname_rel,
979 base_fsp,
980 smb_fname_rel->stream_name,
981 &found);
983 if (NT_STATUS_IS_OK(status)) {
984 smb_fname_rel->stream_name = found;
985 found = NULL;
986 status = open_stream_pathref_fsp(
987 &base_fsp, smb_fname_rel);
991 if (NT_STATUS_IS_OK(status)) {
992 /* smb_fname must be allocated off mem_ctx. */
993 smb_fname = cp_smb_filename(mem_ctx,
994 smb_fname_rel->fsp->fsp_name);
995 if (smb_fname == NULL) {
996 goto fail;
998 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
999 if (!NT_STATUS_IS_OK(status)) {
1000 goto fail;
1002 goto done;
1005 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1007 * Creating a new stream
1009 * We should save the already-open base fsp for
1010 * create_file_unixpath() somehow.
1012 smb_fname = full_path_from_dirfsp_atname(
1013 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1014 if (smb_fname == NULL) {
1015 status = NT_STATUS_NO_MEMORY;
1016 goto fail;
1019 * When open_stream_pathref_fsp() returns
1020 * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1021 * has been set to NULL, so we must free base_fsp separately
1022 * to prevent fd-leaks when opening a stream that doesn't
1023 * exist.
1025 fd_close(base_fsp);
1026 file_free(NULL, base_fsp);
1027 base_fsp = NULL;
1028 goto done;
1031 if (!NT_STATUS_IS_OK(status)) {
1032 goto fail;
1035 done:
1036 *_dirfsp = smb_dirname->fsp;
1037 *_smb_fname = smb_fname;
1038 *_symlink_err = symlink_err;
1040 smb_fname_fsp_unlink(smb_fname_rel);
1041 TALLOC_FREE(smb_fname_rel);
1042 return NT_STATUS_OK;
1044 fail:
1046 * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1047 * has been set to NULL, so we must free base_fsp separately
1048 * to prevent fd-leaks when opening a stream that doesn't
1049 * exist.
1051 if (base_fsp != NULL) {
1052 fd_close(base_fsp);
1053 file_free(NULL, base_fsp);
1054 base_fsp = NULL;
1056 TALLOC_FREE(dirname);
1057 TALLOC_FREE(smb_dirname);
1058 TALLOC_FREE(smb_fname_rel);
1059 return status;
1062 NTSTATUS filename_convert_dirfsp(
1063 TALLOC_CTX *mem_ctx,
1064 connection_struct *conn,
1065 const char *name_in,
1066 uint32_t ucf_flags,
1067 NTTIME twrp,
1068 struct files_struct **_dirfsp,
1069 struct smb_filename **_smb_fname)
1071 struct reparse_data_buffer *symlink_err = NULL;
1072 struct symlink_reparse_struct *lnk = NULL;
1073 NTSTATUS status;
1074 char *target = NULL;
1075 char *safe_target = NULL;
1076 size_t symlink_redirects = 0;
1077 int ret;
1079 next:
1080 if (symlink_redirects > 40) {
1081 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1084 status = filename_convert_dirfsp_nosymlink(mem_ctx,
1085 conn,
1086 name_in,
1087 ucf_flags,
1088 twrp,
1089 _dirfsp,
1090 _smb_fname,
1091 &symlink_err);
1093 if (NT_STATUS_IS_OK(status) && S_ISLNK((*_smb_fname)->st.st_ex_mode)) {
1095 * lcomp is a symlink
1097 if (ucf_flags & UCF_LCOMP_LNK_OK) {
1098 TALLOC_FREE(symlink_err);
1099 return NT_STATUS_OK;
1101 close_file_free(NULL, _dirfsp, ERROR_CLOSE);
1102 status = NT_STATUS_STOPPED_ON_SYMLINK;
1105 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1106 return status;
1108 lnk = &symlink_err->parsed.lnk;
1111 * If we're on an MSDFS share, see if this is
1112 * an MSDFS link.
1114 if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1115 strnequal(lnk->substitute_name, "msdfs:", 6))
1117 TALLOC_FREE(*_smb_fname);
1118 TALLOC_FREE(symlink_err);
1119 return NT_STATUS_PATH_NOT_COVERED;
1122 if (!lp_follow_symlinks(SNUM(conn))) {
1123 status = (lnk->unparsed_path_length == 0)
1124 ? NT_STATUS_OBJECT_NAME_NOT_FOUND
1125 : NT_STATUS_OBJECT_PATH_NOT_FOUND;
1126 TALLOC_FREE(symlink_err);
1127 return status;
1131 * Right now, SMB2 and SMB1 always traverse symlinks
1132 * within the share. SMB1+POSIX traverses non-terminal
1133 * symlinks within the share.
1135 * When we add SMB2+POSIX we need to return
1136 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1137 * symlink target data read below if SMB2+POSIX has
1138 * UCF_POSIX_PATHNAMES set to cause the client to
1139 * resolve all symlinks locally.
1142 ret = symlink_target_path(mem_ctx,
1143 name_in,
1144 lnk->unparsed_path_length,
1145 lnk->substitute_name,
1146 lnk->substitute_name[0] != '/',
1147 '/',
1148 &target);
1149 if (ret != 0) {
1150 return map_nt_error_from_unix(ret);
1153 status = safe_symlink_target_path(mem_ctx,
1154 conn->connectpath,
1155 NULL,
1156 target,
1157 lnk->unparsed_path_length,
1158 &safe_target);
1159 TALLOC_FREE(symlink_err);
1160 if (!NT_STATUS_IS_OK(status)) {
1161 return status;
1163 name_in = safe_target;
1165 symlink_redirects += 1;
1167 goto next;
1170 char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
1171 const struct files_struct *dirfsp,
1172 const char *at_base_name)
1174 char *path = NULL;
1176 if (dirfsp == dirfsp->conn->cwd_fsp ||
1177 ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
1178 path = talloc_strdup(mem_ctx, at_base_name);
1179 } else {
1180 path = talloc_asprintf(mem_ctx,
1181 "%s/%s",
1182 dirfsp->fsp_name->base_name,
1183 at_base_name);
1186 return path;
1190 * Build the full path from a dirfsp and dirfsp relative name
1192 struct smb_filename *
1193 full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
1194 const struct files_struct *dirfsp,
1195 const struct smb_filename *atname)
1197 struct smb_filename *fname = NULL;
1198 char *path = NULL;
1200 path = full_path_from_dirfsp_at_basename(mem_ctx,
1201 dirfsp,
1202 atname->base_name);
1203 if (path == NULL) {
1204 return NULL;
1207 fname = synthetic_smb_fname(mem_ctx,
1208 path,
1209 atname->stream_name,
1210 &atname->st,
1211 atname->twrp,
1212 atname->flags);
1213 TALLOC_FREE(path);
1214 if (fname == NULL) {
1215 return NULL;
1218 return fname;