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.
28 #include "system/filesys.h"
29 #include "fake_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "lib/util/memcache.h"
34 uint32_t ucf_flags_from_smb_request(struct smb_request
*req
)
36 uint32_t ucf_flags
= 0;
42 if (req
->posix_pathnames
) {
43 ucf_flags
|= UCF_POSIX_PATHNAMES
;
45 if (!req
->sconn
->using_smb2
) {
46 ucf_flags
|= UCF_LCOMP_LNK_OK
;
49 if (req
->flags2
& FLAGS2_DFS_PATHNAMES
) {
50 ucf_flags
|= UCF_DFS_PATHNAME
;
52 if (req
->flags2
& FLAGS2_REPARSE_PATH
) {
53 ucf_flags
|= UCF_GMT_PATHNAME
;
59 uint32_t filename_create_ucf_flags(struct smb_request
*req
, uint32_t create_disposition
)
61 uint32_t ucf_flags
= 0;
63 ucf_flags
|= ucf_flags_from_smb_request(req
);
65 switch (create_disposition
) {
72 case FILE_OVERWRITE_IF
:
73 ucf_flags
|= UCF_PREP_CREATEFILE
;
80 /****************************************************************************
81 Mangle the 2nd name and check if it is then equal to the first name.
82 ****************************************************************************/
84 static bool mangled_equal(const char *name1
,
86 const struct share_params
*p
)
90 if (!name_to_8_3(name2
, mname
, False
, p
)) {
93 return strequal(name1
, mname
);
97 * Strip a valid @GMT-token from any incoming filename path,
98 * adding any NTTIME encoded in the pathname into the
99 * twrp field of the passed in smb_fname.
101 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
102 * at the *start* of a pathname component.
104 * If twrp is passed in then smb_fname->twrp is set to that
105 * value, and the @GMT-token part of the filename is removed
106 * and does not change the stored smb_fname->twrp.
110 NTSTATUS
canonicalize_snapshot_path(struct smb_filename
*smb_fname
,
117 smb_fname
->twrp
= twrp
;
120 if (!(ucf_flags
& UCF_GMT_PATHNAME
)) {
124 found
= extract_snapshot_token(smb_fname
->base_name
, &twrp
);
129 if (smb_fname
->twrp
== 0) {
130 smb_fname
->twrp
= twrp
;
136 static bool strnorm(char *s
, int case_default
)
138 if (case_default
== CASE_UPPER
)
139 return strupper_m(s
);
141 return strlower_m(s
);
145 * Utility function to normalize case on an incoming client filename
146 * if required on this connection struct.
147 * Performs an in-place case conversion guaranteed to stay the same size.
150 static NTSTATUS
normalize_filename_case(connection_struct
*conn
,
156 if (ucf_flags
& UCF_POSIX_PATHNAMES
) {
158 * POSIX never normalizes filename case.
162 if (!conn
->case_sensitive
) {
165 if (conn
->case_preserve
) {
168 if (conn
->short_case_preserve
) {
171 ok
= strnorm(filename
, lp_default_case(SNUM(conn
)));
173 return NT_STATUS_INVALID_PARAMETER
;
178 /****************************************************************************
179 Check if two filenames are equal.
180 This needs to be careful about whether we are case sensitive.
181 ****************************************************************************/
183 static bool fname_equal(const char *name1
, const char *name2
,
186 /* Normal filename handling */
187 if (case_sensitive
) {
188 return(strcmp(name1
,name2
) == 0);
191 return(strequal(name1
,name2
));
194 static bool sname_equal(const char *name1
, const char *name2
,
198 const char *s1
= NULL
;
199 const char *s2
= NULL
;
202 const char *e1
= NULL
;
203 const char *e2
= NULL
;
207 match
= fname_equal(name1
, name2
, case_sensitive
);
212 if (name1
[0] != ':') {
215 if (name2
[0] != ':') {
219 e1
= strchr(s1
, ':');
223 n1
= PTR_DIFF(e1
, s1
);
226 e2
= strchr(s2
, ':');
230 n2
= PTR_DIFF(e2
, s2
);
233 /* Normal filename handling */
234 if (case_sensitive
) {
235 return (strncmp(s1
, s2
, n1
) == 0);
239 * We can't use strnequal() here
240 * as it takes the number of codepoints
241 * and not the number of bytes.
243 * So we make a copy before calling
246 * Note that we TALLOC_FREE() in reverse order
247 * in order to avoid memory fragmentation.
250 c1
= talloc_strndup(talloc_tos(), s1
, n1
);
251 c2
= talloc_strndup(talloc_tos(), s2
, n2
);
252 if (c1
== NULL
|| c2
== NULL
) {
255 return (strncmp(s1
, s2
, n1
) == 0);
258 match
= strequal(c1
, c2
);
264 /****************************************************************************
265 Scan a directory to find a filename, matching without case sensitivity.
266 If the name looks like a mangled name then try via the mangling functions
267 ****************************************************************************/
269 NTSTATUS
get_real_filename_full_scan_at(struct files_struct
*dirfsp
,
275 struct connection_struct
*conn
= dirfsp
->conn
;
276 struct smb_Dir
*cur_dir
= NULL
;
277 const char *dname
= NULL
;
278 char *talloced
= NULL
;
279 char *unmangled_name
= NULL
;
282 /* If we have a case-sensitive filesystem, it doesn't do us any
283 * good to search for a name. If a case variation of the name was
284 * there, then the original stat(2) would have found it.
286 if (!mangled
&& !(conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
)) {
287 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
291 * The incoming name can be mangled, and if we de-mangle it
292 * here it will not compare correctly against the filename (name2)
293 * read from the directory and then mangled by the name_to_8_3()
294 * call. We need to mangle both names or neither.
297 * Fix for bug found by Dina Fine. If in case sensitive mode then
298 * the mangle cache is no good (3 letter extension could be wrong
299 * case - so don't demangle in this case - leave as mangled and
300 * allow the mangling of the directory entry read (which is done
301 * case insensitively) to match instead. This will lead to more
302 * false positive matches but we fail completely without it. JRA.
305 if (mangled
&& !conn
->case_sensitive
) {
306 mangled
= !mangle_lookup_name_from_8_3(talloc_tos(), name
,
310 /* Name is now unmangled. */
311 name
= unmangled_name
;
315 /* open the directory */
316 status
= OpenDir_from_pathref(talloc_tos(), dirfsp
, NULL
, 0, &cur_dir
);
317 if (!NT_STATUS_IS_OK(status
)) {
318 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
321 TALLOC_FREE(unmangled_name
);
325 /* now scan for matching names */
326 while ((dname
= ReadDirName(cur_dir
, &talloced
))) {
328 /* Is it dot or dot dot. */
329 if (ISDOT(dname
) || ISDOTDOT(dname
)) {
330 TALLOC_FREE(talloced
);
335 * At this point dname is the unmangled name.
336 * name is either mangled or not, depending on the state
337 * of the "mangled" variable. JRA.
341 * Check mangled name against mangled name, or unmangled name
342 * against unmangled name.
345 if ((mangled
&& mangled_equal(name
,dname
,conn
->params
)) ||
346 fname_equal(name
, dname
, conn
->case_sensitive
)) {
347 /* we've found the file, change it's name and return */
348 *found_name
= talloc_strdup(mem_ctx
, dname
);
349 TALLOC_FREE(unmangled_name
);
350 TALLOC_FREE(cur_dir
);
352 TALLOC_FREE(talloced
);
353 return NT_STATUS_NO_MEMORY
;
355 TALLOC_FREE(talloced
);
358 TALLOC_FREE(talloced
);
361 TALLOC_FREE(unmangled_name
);
362 TALLOC_FREE(cur_dir
);
363 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
366 /****************************************************************************
367 Wrapper around the vfs get_real_filename and the full directory scan
369 ****************************************************************************/
371 NTSTATUS
get_real_filename_at(struct files_struct
*dirfsp
,
376 struct connection_struct
*conn
= dirfsp
->conn
;
380 mangled
= mangle_is_mangled(name
, conn
->params
);
383 status
= get_real_filename_full_scan_at(
384 dirfsp
, name
, mangled
, mem_ctx
, found_name
);
388 /* Try the vfs first to take advantage of case-insensitive stat. */
389 status
= SMB_VFS_GET_REAL_FILENAME_AT(
390 dirfsp
->conn
, dirfsp
, name
, mem_ctx
, found_name
);
393 * If the case-insensitive stat was successful, or returned an error
394 * other than EOPNOTSUPP then there is no need to fall back on the
395 * full directory scan.
397 if (NT_STATUS_IS_OK(status
) ||
398 !NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
402 status
= get_real_filename_full_scan_at(
403 dirfsp
, name
, mangled
, mem_ctx
, found_name
);
408 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
409 * the stat cache for the last component to be looked up. Cache
410 * contents is the correctly capitalized translation of the parameter
411 * "name" as it exists on disk. This is indexed by inode of the dirfsp
412 * and name, and contrary to stat_cahce_lookup() it does not
413 * vfs_stat() the last component. This will be taken care of by an
414 * attempt to do a openat_pathref_fsp().
416 static bool get_real_filename_cache_key(
418 struct files_struct
*dirfsp
,
422 struct file_id fid
= vfs_file_id_from_sbuf(
423 dirfsp
->conn
, &dirfsp
->fsp_name
->st
);
426 size_t namelen
, keylen
;
428 upper
= talloc_strdup_upper(mem_ctx
, name
);
432 namelen
= talloc_get_size(upper
);
434 keylen
= namelen
+ sizeof(fid
);
435 if (keylen
< sizeof(fid
)) {
440 key
= talloc_size(mem_ctx
, keylen
);
446 memcpy(key
, &fid
, sizeof(fid
));
447 memcpy(key
+ sizeof(fid
), upper
, namelen
);
450 *_key
= (DATA_BLOB
) { .data
= key
, .length
= keylen
, };
455 * Lightweight function to just get last component
456 * for rename / enumerate directory calls.
459 char *get_original_lcomp(TALLOC_CTX
*ctx
,
460 connection_struct
*conn
,
461 const char *filename_in
,
464 char *last_slash
= NULL
;
468 last_slash
= strrchr(filename_in
, '/');
469 if (last_slash
!= NULL
) {
470 orig_lcomp
= talloc_strdup(ctx
, last_slash
+1);
472 orig_lcomp
= talloc_strdup(ctx
, filename_in
);
474 if (orig_lcomp
== NULL
) {
477 status
= normalize_filename_case(conn
, orig_lcomp
, ucf_flags
);
478 if (!NT_STATUS_IS_OK(status
)) {
479 TALLOC_FREE(orig_lcomp
);
486 * Deal with the SMB1 semantics of sending a pathname with a
487 * wildcard as the terminal component for a SMB1search or
491 NTSTATUS
filename_convert_smb1_search_path(TALLOC_CTX
*ctx
,
492 connection_struct
*conn
,
495 struct files_struct
**_dirfsp
,
496 struct smb_filename
**_smb_fname_out
,
502 struct smb_filename
*smb_fname
= NULL
;
505 *_smb_fname_out
= NULL
;
509 DBG_DEBUG("name_in: %s\n", name_in
);
511 if (ucf_flags
& UCF_GMT_PATHNAME
) {
512 extract_snapshot_token(name_in
, &twrp
);
513 ucf_flags
&= ~UCF_GMT_PATHNAME
;
516 /* Get the original lcomp. */
517 mask
= get_original_lcomp(ctx
,
522 return NT_STATUS_NO_MEMORY
;
525 if (mask
[0] == '\0') {
526 /* Windows and OS/2 systems treat search on the root as * */
528 mask
= talloc_strdup(ctx
, "*");
530 return NT_STATUS_NO_MEMORY
;
534 DBG_DEBUG("mask = %s\n", mask
);
537 * Remove the terminal component so
538 * filename_convert_dirfsp never sees the mask.
540 p
= strrchr_m(name_in
,'/');
542 /* filename_convert_dirfsp handles a '\0' name. */
548 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
551 /* Convert the parent directory path. */
552 status
= filename_convert_dirfsp(ctx
,
560 if (!NT_STATUS_IS_OK(status
)) {
561 DBG_DEBUG("filename_convert error for %s: %s\n",
566 *_smb_fname_out
= talloc_move(ctx
, &smb_fname
);
567 *_mask_out
= talloc_move(ctx
, &mask
);
573 * Get the correct capitalized stream name hanging off
574 * base_fsp. Equivalent of get_real_filename(), but for streams.
576 static NTSTATUS
get_real_stream_name(
578 struct files_struct
*base_fsp
,
579 const char *stream_name
,
582 unsigned int i
, num_streams
= 0;
583 struct stream_struct
*streams
= NULL
;
586 status
= vfs_fstreaminfo(
587 base_fsp
, talloc_tos(), &num_streams
, &streams
);
588 if (!NT_STATUS_IS_OK(status
)) {
592 for (i
=0; i
<num_streams
; i
++) {
593 bool equal
= sname_equal(stream_name
, streams
[i
].name
, false);
595 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
598 equal
? "" : "not ");
601 *_found
= talloc_move(mem_ctx
, &streams
[i
].name
);
602 TALLOC_FREE(streams
);
607 TALLOC_FREE(streams
);
608 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
611 static bool filename_split_lcomp(
616 const char **_fname_rel
,
617 const char **_streamname
)
619 const char *lcomp
= NULL
;
620 const char *fname_rel
= NULL
;
621 const char *streamname
= NULL
;
622 char *dirname
= NULL
;
624 if (name_in
[0] == '\0') {
626 dirname
= talloc_strdup(mem_ctx
, "");
627 if (dirname
== NULL
) {
633 lcomp
= strrchr_m(name_in
, '/');
636 dirname
= talloc_strndup(mem_ctx
, name_in
, lcomp
- name_in
);
637 if (dirname
== NULL
) {
644 * No slash, dir is emtpy
646 dirname
= talloc_strdup(mem_ctx
, "");
647 if (dirname
== NULL
) {
651 if (!posix
&& (name_in
[0] == ':')) {
653 * Special case for stream on root directory
656 streamname
= name_in
;
664 streamname
= strchr_m(fname_rel
, ':');
666 if (streamname
!= NULL
) {
667 fname_rel
= talloc_strndup(
670 streamname
- fname_rel
);
671 if (fname_rel
== NULL
) {
672 TALLOC_FREE(dirname
);
680 *_fname_rel
= fname_rel
;
681 *_streamname
= streamname
;
686 * Create the correct capitalization of a file name to be created.
688 static NTSTATUS
filename_convert_normalize_new(
690 struct connection_struct
*conn
,
694 char *name
= name_in
;
698 if (!conn
->case_preserve
||
699 (mangle_is_8_3(name
, false,
701 !conn
->short_case_preserve
)) {
703 char *normalized
= talloc_strdup(mem_ctx
, name
);
704 if (normalized
== NULL
) {
705 return NT_STATUS_NO_MEMORY
;
708 strnorm(normalized
, lp_default_case(SNUM(conn
)));
712 if (mangle_is_mangled(name
, conn
->params
)) {
714 char *unmangled
= NULL
;
716 found
= mangle_lookup_name_from_8_3(
717 mem_ctx
, name
, &unmangled
, conn
->params
);
723 if (name
!= name_in
) {
731 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
732 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
733 * the first attempt based on the filename sent by the client gives
736 static NTSTATUS
openat_pathref_fsp_case_insensitive(
737 struct files_struct
*dirfsp
,
738 struct smb_filename
*smb_fname_rel
,
741 const bool posix
= (ucf_flags
& UCF_POSIX_PATHNAMES
);
742 DATA_BLOB cache_key
= { .data
= NULL
, };
743 char *found_name
= NULL
;
747 SET_STAT_INVALID(smb_fname_rel
->st
);
749 /* Check veto files - only looks at last component. */
750 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
751 DBG_DEBUG("veto files rejecting last component %s\n",
752 smb_fname_str_dbg(smb_fname_rel
));
753 return NT_STATUS_NETWORK_OPEN_RESTRICTION
;
756 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
758 if (NT_STATUS_IS_OK(status
)) {
762 if (VALID_STAT(smb_fname_rel
->st
)) {
764 * We got an error although the object existed. Might
765 * be a symlink we don't want.
770 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
772 * Only retry on ENOENT
777 if (posix
|| dirfsp
->conn
->case_sensitive
) {
779 * Only return case insensitive if required
784 if (lp_stat_cache()) {
785 char *base_name
= smb_fname_rel
->base_name
;
786 DATA_BLOB value
= { .data
= NULL
};
788 ok
= get_real_filename_cache_key(
789 talloc_tos(), dirfsp
, base_name
, &cache_key
);
792 * probably ENOMEM, just bail
797 DO_PROFILE_INC(statcache_lookups
);
799 ok
= memcache_lookup(
800 NULL
, GETREALFILENAME_CACHE
, cache_key
, &value
);
802 DO_PROFILE_INC(statcache_misses
);
805 DO_PROFILE_INC(statcache_hits
);
807 TALLOC_FREE(smb_fname_rel
->base_name
);
808 smb_fname_rel
->base_name
= talloc_memdup(
809 smb_fname_rel
, value
.data
, value
.length
);
810 if (smb_fname_rel
->base_name
== NULL
) {
811 TALLOC_FREE(cache_key
.data
);
812 return NT_STATUS_NO_MEMORY
;
815 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
816 DBG_DEBUG("veto files rejecting last component %s\n",
817 smb_fname_str_dbg(smb_fname_rel
));
818 TALLOC_FREE(cache_key
.data
);
819 return NT_STATUS_NETWORK_OPEN_RESTRICTION
;
822 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
823 if (NT_STATUS_IS_OK(status
)) {
824 TALLOC_FREE(cache_key
.data
);
828 memcache_delete(NULL
, GETREALFILENAME_CACHE
, cache_key
);
832 status
= get_real_filename_at(
833 dirfsp
, smb_fname_rel
->base_name
, smb_fname_rel
, &found_name
);
834 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
835 (ucf_flags
& UCF_PREP_CREATEFILE
)) {
839 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
842 if (NT_STATUS_IS_OK(status
)) {
843 TALLOC_FREE(smb_fname_rel
->base_name
);
844 smb_fname_rel
->base_name
= found_name
;
846 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
847 DBG_DEBUG("veto files rejecting last component %s\n",
848 smb_fname_str_dbg(smb_fname_rel
));
849 return NT_STATUS_NETWORK_OPEN_RESTRICTION
;
852 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
855 if (NT_STATUS_IS_OK(status
) && (cache_key
.data
!= NULL
)) {
857 .data
= (uint8_t *)smb_fname_rel
->base_name
,
858 .length
= strlen(smb_fname_rel
->base_name
) + 1,
861 memcache_add(NULL
, GETREALFILENAME_CACHE
, cache_key
, value
);
864 TALLOC_FREE(cache_key
.data
);
869 static const char *previous_slash(const char *name_in
, const char *slash
)
871 const char *prev
= name_in
;
874 const char *next
= strchr_m(prev
, '/');
876 SMB_ASSERT(next
!= NULL
); /* we have at least one slash */
885 if (prev
== name_in
) {
886 /* no previous slash */
893 static char *symlink_target_path(
896 const char *substitute
,
899 size_t name_in_len
= strlen(name_in
);
900 const char *p_unparsed
= NULL
;
901 const char *parent
= NULL
;
904 SMB_ASSERT(unparsed
<= name_in_len
);
906 p_unparsed
= name_in
+ (name_in_len
- unparsed
);
908 if (substitute
[0] == '/') {
909 ret
= talloc_asprintf(mem_ctx
, "%s%s", substitute
, p_unparsed
);
914 parent
= strrchr_m(name_in
, '/');
916 parent
= previous_slash(name_in
, p_unparsed
);
919 if (parent
== NULL
) {
920 /* no previous slash */
924 ret
= talloc_asprintf(
927 (int)(parent
- name_in
),
934 static NTSTATUS
safe_symlink_target_path(
936 const char *connectpath
,
938 const char *substitute
,
943 char *abs_target
= NULL
;
944 char *abs_target_canon
= NULL
;
945 const char *relative
= NULL
;
946 char *name_out
= NULL
;
947 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
950 target
= symlink_target_path(mem_ctx
, name_in
, substitute
, unparsed
);
951 if (target
== NULL
) {
955 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
961 if (target
[0] == '/') {
964 abs_target
= talloc_asprintf(
965 target
, "%s/%s", connectpath
, target
);
966 if (abs_target
== NULL
) {
971 abs_target_canon
= canonicalize_absolute_path(target
, abs_target
);
972 if (abs_target_canon
== NULL
) {
976 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon
);
978 in_share
= subdir_of(
979 connectpath
, strlen(connectpath
), abs_target_canon
, &relative
);
981 DBG_DEBUG("wide link to %s\n", abs_target_canon
);
982 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
986 name_out
= talloc_strdup(mem_ctx
, relative
);
987 if (name_out
== NULL
) {
991 status
= NT_STATUS_OK
;
992 *_name_out
= name_out
;
999 * Split up name_in as sent by the client into a directory pathref fsp
1000 * and a relative smb_filename.
1002 static NTSTATUS
filename_convert_dirfsp_nosymlink(
1003 TALLOC_CTX
*mem_ctx
,
1004 connection_struct
*conn
,
1005 const char *name_in
,
1008 struct files_struct
**_dirfsp
,
1009 struct smb_filename
**_smb_fname
,
1013 struct smb_filename
*smb_dirname
= NULL
;
1014 struct smb_filename
*smb_fname_rel
= NULL
;
1015 struct smb_filename
*smb_fname
= NULL
;
1016 const bool posix
= (ucf_flags
& UCF_POSIX_PATHNAMES
);
1017 char *dirname
= NULL
;
1018 const char *fname_rel
= NULL
;
1019 const char *streamname
= NULL
;
1020 char *saved_streamname
= NULL
;
1021 struct files_struct
*base_fsp
= NULL
;
1023 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1025 SMB_ASSERT(!(ucf_flags
& UCF_DFS_PATHNAME
));
1027 if (is_fake_file_path(name_in
)) {
1028 smb_fname
= synthetic_smb_fname_split(mem_ctx
, name_in
, posix
);
1029 if (smb_fname
== NULL
) {
1030 return NT_STATUS_NO_MEMORY
;
1032 smb_fname
->st
= (SMB_STRUCT_STAT
) { .st_ex_nlink
= 1 };
1033 smb_fname
->st
.st_ex_btime
=
1034 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1035 smb_fname
->st
.st_ex_atime
=
1036 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1037 smb_fname
->st
.st_ex_mtime
=
1038 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1039 smb_fname
->st
.st_ex_ctime
=
1040 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1042 *_dirfsp
= conn
->cwd_fsp
;
1043 *_smb_fname
= smb_fname
;
1044 return NT_STATUS_OK
;
1048 * Catch an invalid path of "." before we
1049 * call filename_split_lcomp(). We need to
1050 * do this as filename_split_lcomp() will
1051 * use "." for the missing relative component
1052 * when an empty name_in path is sent by
1055 if (ISDOT(name_in
)) {
1056 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1060 ok
= filename_split_lcomp(
1068 status
= NT_STATUS_NO_MEMORY
;
1072 if ((streamname
!= NULL
) &&
1073 ((conn
->fs_capabilities
& FILE_NAMED_STREAMS
) == 0)) {
1074 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1079 bool name_has_wild
= ms_has_wild(dirname
);
1080 name_has_wild
|= ms_has_wild(fname_rel
);
1081 if (name_has_wild
) {
1082 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1087 if (dirname
[0] == '\0') {
1088 status
= synthetic_pathref(
1095 posix
? SMB_FILENAME_POSIX_PATH
: 0,
1098 char *substitute
= NULL
;
1099 size_t unparsed
= 0;
1101 status
= normalize_filename_case(conn
, dirname
, ucf_flags
);
1102 if (!NT_STATUS_IS_OK(status
)) {
1103 DBG_ERR("normalize_filename_case %s failed: %s\n",
1109 status
= openat_pathref_dirfsp_nosymlink(
1119 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1121 size_t name_in_len
= strlen(name_in
);
1122 size_t dirname_len
= strlen(dirname
);
1124 SMB_ASSERT(name_in_len
>= dirname_len
);
1126 *_substitute
= substitute
;
1127 *_unparsed
= unparsed
+ (name_in_len
- dirname_len
);
1133 if (!NT_STATUS_IS_OK(status
)) {
1134 DBG_DEBUG("opening directory %s failed: %s\n",
1137 TALLOC_FREE(dirname
);
1139 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1140 /* MS-DFS error must propagate back out. */
1144 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1146 * Except ACCESS_DENIED, everything else leads
1147 * to PATH_NOT_FOUND.
1149 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1155 if (!VALID_STAT_OF_DIR(smb_dirname
->st
)) {
1156 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1161 * Only look at bad last component values
1162 * once we know we have a valid directory. That
1163 * way we won't confuse error messages from
1164 * opening the directory path with error
1165 * messages from a bad last component.
1168 /* Relative filename can't be empty */
1169 if (fname_rel
[0] == '\0') {
1170 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1174 /* Relative filename can't be ".." */
1175 if (ISDOTDOT(fname_rel
)) {
1176 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1179 /* Relative name can only be dot if directory is empty. */
1180 if (ISDOT(fname_rel
) && dirname
[0] != '\0') {
1181 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1185 TALLOC_FREE(dirname
);
1187 smb_fname_rel
= synthetic_smb_fname(
1193 posix
? SMB_FILENAME_POSIX_PATH
: 0);
1194 if (smb_fname_rel
== NULL
) {
1195 status
= NT_STATUS_NO_MEMORY
;
1199 if ((conn
->fs_capabilities
& FILE_NAMED_STREAMS
) &&
1200 is_named_stream(smb_fname_rel
)) {
1202 * Find the base_fsp first without the stream.
1204 saved_streamname
= smb_fname_rel
->stream_name
;
1205 smb_fname_rel
->stream_name
= NULL
;
1208 status
= normalize_filename_case(
1209 conn
, smb_fname_rel
->base_name
, ucf_flags
);
1210 if (!NT_STATUS_IS_OK(status
)) {
1211 DBG_ERR("normalize_filename_case %s failed: %s\n",
1212 smb_fname_rel
->base_name
,
1217 status
= openat_pathref_fsp_case_insensitive(
1218 smb_dirname
->fsp
, smb_fname_rel
, ucf_flags
);
1220 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) &&
1221 VALID_STAT(smb_fname_rel
->st
) &&
1222 S_ISLNK(smb_fname_rel
->st
.st_ex_mode
)) {
1225 * If we're on an MSDFS share, see if this is
1228 if (lp_host_msdfs() &&
1229 lp_msdfs_root(SNUM(conn
)) &&
1230 is_msdfs_link(smb_dirname
->fsp
, smb_fname_rel
))
1232 status
= NT_STATUS_PATH_NOT_COVERED
;
1236 #if defined(WITH_SMB1SERVER)
1238 * In SMB1 posix mode, if this is a symlink,
1239 * allow access to the name with a NULL smb_fname->fsp.
1241 if (ucf_flags
& UCF_LCOMP_LNK_OK
) {
1242 SMB_ASSERT(smb_fname_rel
->fsp
== NULL
);
1243 SMB_ASSERT(streamname
== NULL
);
1245 smb_fname
= full_path_from_dirfsp_atname(
1249 if (smb_fname
== NULL
) {
1250 status
= NT_STATUS_NO_MEMORY
;
1258 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) &&
1259 !VALID_STAT(smb_fname_rel
->st
)) {
1261 char *normalized
= NULL
;
1264 * Creating a new file
1267 status
= filename_convert_normalize_new(
1270 smb_fname_rel
->base_name
,
1272 if (!NT_STATUS_IS_OK(status
)) {
1273 DBG_DEBUG("filename_convert_normalize_new failed: "
1278 if (normalized
!= NULL
) {
1279 smb_fname_rel
->base_name
= normalized
;
1282 smb_fname_rel
->stream_name
= saved_streamname
;
1284 smb_fname
= full_path_from_dirfsp_atname(
1285 mem_ctx
, smb_dirname
->fsp
, smb_fname_rel
);
1286 if (smb_fname
== NULL
) {
1287 status
= NT_STATUS_NO_MEMORY
;
1293 if (NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_OPEN_RESTRICTION
)) {
1294 /* A vetoed file, pretend it's not there */
1295 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1297 if (!NT_STATUS_IS_OK(status
)) {
1301 if (saved_streamname
== NULL
) {
1302 /* smb_fname must be allocated off mem_ctx. */
1303 smb_fname
= cp_smb_filename(mem_ctx
,
1304 smb_fname_rel
->fsp
->fsp_name
);
1305 if (smb_fname
== NULL
) {
1308 status
= move_smb_fname_fsp_link(smb_fname
, smb_fname_rel
);
1309 if (!NT_STATUS_IS_OK(status
)) {
1315 base_fsp
= smb_fname_rel
->fsp
;
1316 smb_fname_fsp_unlink(smb_fname_rel
);
1317 SET_STAT_INVALID(smb_fname_rel
->st
);
1319 smb_fname_rel
->stream_name
= saved_streamname
;
1321 status
= open_stream_pathref_fsp(&base_fsp
, smb_fname_rel
);
1323 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) &&
1324 !conn
->case_sensitive
) {
1327 status
= get_real_stream_name(
1330 smb_fname_rel
->stream_name
,
1333 if (NT_STATUS_IS_OK(status
)) {
1334 smb_fname_rel
->stream_name
= found
;
1336 status
= open_stream_pathref_fsp(
1337 &base_fsp
, smb_fname_rel
);
1341 if (NT_STATUS_IS_OK(status
)) {
1342 /* smb_fname must be allocated off mem_ctx. */
1343 smb_fname
= cp_smb_filename(mem_ctx
,
1344 smb_fname_rel
->fsp
->fsp_name
);
1345 if (smb_fname
== NULL
) {
1348 status
= move_smb_fname_fsp_link(smb_fname
, smb_fname_rel
);
1349 if (!NT_STATUS_IS_OK(status
)) {
1355 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1357 * Creating a new stream
1359 * We should save the already-open base fsp for
1360 * create_file_unixpath() somehow.
1362 smb_fname
= full_path_from_dirfsp_atname(
1363 mem_ctx
, smb_dirname
->fsp
, smb_fname_rel
);
1364 if (smb_fname
== NULL
) {
1365 status
= NT_STATUS_NO_MEMORY
;
1369 * When open_stream_pathref_fsp() returns
1370 * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1371 * has been set to NULL, so we must free base_fsp separately
1372 * to prevent fd-leaks when opening a stream that doesn't
1376 file_free(NULL
, base_fsp
);
1381 if (!NT_STATUS_IS_OK(status
)) {
1386 *_dirfsp
= smb_dirname
->fsp
;
1387 *_smb_fname
= smb_fname
;
1389 smb_fname_fsp_unlink(smb_fname_rel
);
1390 TALLOC_FREE(smb_fname_rel
);
1391 return NT_STATUS_OK
;
1395 * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1396 * has been set to NULL, so we must free base_fsp separately
1397 * to prevent fd-leaks when opening a stream that doesn't
1400 if (base_fsp
!= NULL
) {
1402 file_free(NULL
, base_fsp
);
1405 TALLOC_FREE(dirname
);
1406 TALLOC_FREE(smb_dirname
);
1407 TALLOC_FREE(smb_fname_rel
);
1411 NTSTATUS
filename_convert_dirfsp(
1412 TALLOC_CTX
*mem_ctx
,
1413 connection_struct
*conn
,
1414 const char *name_in
,
1417 struct files_struct
**_dirfsp
,
1418 struct smb_filename
**_smb_fname
)
1420 char *substitute
= NULL
;
1421 size_t unparsed
= 0;
1423 char *target
= NULL
;
1424 size_t symlink_redirects
= 0;
1427 if (symlink_redirects
> 40) {
1428 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1431 status
= filename_convert_dirfsp_nosymlink(
1442 if (!NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1446 if (!lp_follow_symlinks(SNUM(conn
))) {
1447 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1451 * Right now, SMB2 and SMB1 always traverse symlinks
1452 * within the share. SMB1+POSIX traverses non-terminal
1453 * symlinks within the share.
1455 * When we add SMB2+POSIX we need to return
1456 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1457 * symlink target data read below if SMB2+POSIX has
1458 * UCF_POSIX_PATHNAMES set to cause the client to
1459 * resolve all symlinks locally.
1462 status
= safe_symlink_target_path(
1469 if (!NT_STATUS_IS_OK(status
)) {
1474 symlink_redirects
+= 1;
1480 * Build the full path from a dirfsp and dirfsp relative name
1482 struct smb_filename
*full_path_from_dirfsp_atname(
1483 TALLOC_CTX
*mem_ctx
,
1484 const struct files_struct
*dirfsp
,
1485 const struct smb_filename
*atname
)
1487 struct smb_filename
*fname
= NULL
;
1490 if (dirfsp
== dirfsp
->conn
->cwd_fsp
||
1491 ISDOT(dirfsp
->fsp_name
->base_name
) ||
1492 atname
->base_name
[0] == '/')
1494 path
= talloc_strdup(mem_ctx
, atname
->base_name
);
1496 path
= talloc_asprintf(mem_ctx
, "%s/%s",
1497 dirfsp
->fsp_name
->base_name
,
1504 fname
= synthetic_smb_fname(mem_ctx
,
1506 atname
->stream_name
,
1511 if (fname
== NULL
) {