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;
39 if (req
->posix_pathnames
) {
40 ucf_flags
|= UCF_POSIX_PATHNAMES
;
42 if (req
->flags2
& FLAGS2_DFS_PATHNAMES
) {
43 ucf_flags
|= UCF_DFS_PATHNAME
;
45 if (req
->flags2
& FLAGS2_REPARSE_PATH
) {
46 ucf_flags
|= UCF_GMT_PATHNAME
;
53 uint32_t filename_create_ucf_flags(struct smb_request
*req
, uint32_t create_disposition
)
55 uint32_t ucf_flags
= 0;
57 ucf_flags
|= ucf_flags_from_smb_request(req
);
59 switch (create_disposition
) {
66 case FILE_OVERWRITE_IF
:
67 ucf_flags
|= UCF_PREP_CREATEFILE
;
74 /****************************************************************************
75 Mangle the 2nd name and check if it is then equal to the first name.
76 ****************************************************************************/
78 static bool mangled_equal(const char *name1
,
80 const struct share_params
*p
)
84 if (!name_to_8_3(name2
, mname
, False
, p
)) {
87 return strequal(name1
, mname
);
90 static bool find_snapshot_token(
93 const char **_next_component
,
96 const char *start
= NULL
;
97 const char *end
= NULL
;
101 start
= strstr_m(filename
, "@GMT-");
107 if ((start
> filename
) && (start
[-1] != '/')) {
108 /* the GMT-token does not start a path-component */
112 end
= strptime(start
, GMT_FORMAT
, &tm
);
114 /* Not a valid timestring. */
118 if ((end
[0] != '\0') && (end
[0] != '/')) {
120 * It is not a complete path component, i.e. the path
121 * component continues after the gmt-token.
128 unix_to_nt_time(twrp
, t
);
130 DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
131 nt_time_string(talloc_tos(), *twrp
));
138 *_next_component
= end
;
143 bool extract_snapshot_token(char *fname
, NTTIME
*twrp
)
145 const char *start
= NULL
;
146 const char *next
= NULL
;
150 found
= find_snapshot_token(fname
, &start
, &next
, twrp
);
155 remaining
= strlen(next
);
156 memmove(discard_const_p(char, start
), next
, remaining
+1);
162 * Strip a valid @GMT-token from any incoming filename path,
163 * adding any NTTIME encoded in the pathname into the
164 * twrp field of the passed in smb_fname.
166 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
167 * at the *start* of a pathname component.
169 * If twrp is passed in then smb_fname->twrp is set to that
170 * value, and the @GMT-token part of the filename is removed
171 * and does not change the stored smb_fname->twrp.
175 NTSTATUS
canonicalize_snapshot_path(struct smb_filename
*smb_fname
,
182 smb_fname
->twrp
= twrp
;
185 if (!(ucf_flags
& UCF_GMT_PATHNAME
)) {
189 found
= extract_snapshot_token(smb_fname
->base_name
, &twrp
);
194 if (smb_fname
->twrp
== 0) {
195 smb_fname
->twrp
= twrp
;
201 static bool strnorm(char *s
, int case_default
)
203 if (case_default
== CASE_UPPER
)
204 return strupper_m(s
);
206 return strlower_m(s
);
210 * Utility function to normalize case on an incoming client filename
211 * if required on this connection struct.
212 * Performs an in-place case conversion guaranteed to stay the same size.
215 static NTSTATUS
normalize_filename_case(connection_struct
*conn
,
221 if (ucf_flags
& UCF_POSIX_PATHNAMES
) {
223 * POSIX never normalizes filename case.
227 if (!conn
->case_sensitive
) {
230 if (conn
->case_preserve
) {
233 if (conn
->short_case_preserve
) {
236 ok
= strnorm(filename
, lp_default_case(SNUM(conn
)));
238 return NT_STATUS_INVALID_PARAMETER
;
243 /****************************************************************************
244 Check if two filenames are equal.
245 This needs to be careful about whether we are case sensitive.
246 ****************************************************************************/
248 static bool fname_equal(const char *name1
, const char *name2
,
251 /* Normal filename handling */
252 if (case_sensitive
) {
253 return(strcmp(name1
,name2
) == 0);
256 return(strequal(name1
,name2
));
259 static bool sname_equal(const char *name1
, const char *name2
,
263 const char *s1
= NULL
;
264 const char *s2
= NULL
;
267 const char *e1
= NULL
;
268 const char *e2
= NULL
;
272 match
= fname_equal(name1
, name2
, case_sensitive
);
277 if (name1
[0] != ':') {
280 if (name2
[0] != ':') {
284 e1
= strchr(s1
, ':');
288 n1
= PTR_DIFF(e1
, s1
);
291 e2
= strchr(s2
, ':');
295 n2
= PTR_DIFF(e2
, s2
);
298 /* Normal filename handling */
299 if (case_sensitive
) {
300 return (strncmp(s1
, s2
, n1
) == 0);
304 * We can't use strnequal() here
305 * as it takes the number of codepoints
306 * and not the number of bytes.
308 * So we make a copy before calling
311 * Note that we TALLOC_FREE() in reverse order
312 * in order to avoid memory fragmentation.
315 c1
= talloc_strndup(talloc_tos(), s1
, n1
);
316 c2
= talloc_strndup(talloc_tos(), s2
, n2
);
317 if (c1
== NULL
|| c2
== NULL
) {
320 return (strncmp(s1
, s2
, n1
) == 0);
323 match
= strequal(c1
, c2
);
329 /****************************************************************************
330 Scan a directory to find a filename, matching without case sensitivity.
331 If the name looks like a mangled name then try via the mangling functions
332 ****************************************************************************/
334 NTSTATUS
get_real_filename_full_scan_at(struct files_struct
*dirfsp
,
340 struct connection_struct
*conn
= dirfsp
->conn
;
341 struct smb_Dir
*cur_dir
= NULL
;
342 const char *dname
= NULL
;
343 char *talloced
= NULL
;
344 char *unmangled_name
= NULL
;
348 /* If we have a case-sensitive filesystem, it doesn't do us any
349 * good to search for a name. If a case variation of the name was
350 * there, then the original stat(2) would have found it.
352 if (!mangled
&& !(conn
->fs_capabilities
& FILE_CASE_SENSITIVE_SEARCH
)) {
353 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
357 * The incoming name can be mangled, and if we de-mangle it
358 * here it will not compare correctly against the filename (name2)
359 * read from the directory and then mangled by the name_to_8_3()
360 * call. We need to mangle both names or neither.
363 * Fix for bug found by Dina Fine. If in case sensitive mode then
364 * the mangle cache is no good (3 letter extension could be wrong
365 * case - so don't demangle in this case - leave as mangled and
366 * allow the mangling of the directory entry read (which is done
367 * case insensitively) to match instead. This will lead to more
368 * false positive matches but we fail completely without it. JRA.
371 if (mangled
&& !conn
->case_sensitive
) {
372 mangled
= !mangle_lookup_name_from_8_3(talloc_tos(), name
,
376 /* Name is now unmangled. */
377 name
= unmangled_name
;
381 /* open the directory */
382 status
= OpenDir_from_pathref(talloc_tos(), dirfsp
, NULL
, 0, &cur_dir
);
383 if (!NT_STATUS_IS_OK(status
)) {
384 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
387 TALLOC_FREE(unmangled_name
);
391 /* now scan for matching names */
393 while ((dname
= ReadDirName(cur_dir
, &curpos
, NULL
, &talloced
))) {
395 /* Is it dot or dot dot. */
396 if (ISDOT(dname
) || ISDOTDOT(dname
)) {
397 TALLOC_FREE(talloced
);
402 * At this point dname is the unmangled name.
403 * name is either mangled or not, depending on the state
404 * of the "mangled" variable. JRA.
408 * Check mangled name against mangled name, or unmangled name
409 * against unmangled name.
412 if ((mangled
&& mangled_equal(name
,dname
,conn
->params
)) ||
413 fname_equal(name
, dname
, conn
->case_sensitive
)) {
414 /* we've found the file, change it's name and return */
415 *found_name
= talloc_strdup(mem_ctx
, dname
);
416 TALLOC_FREE(unmangled_name
);
417 TALLOC_FREE(cur_dir
);
419 TALLOC_FREE(talloced
);
420 return NT_STATUS_NO_MEMORY
;
422 TALLOC_FREE(talloced
);
425 TALLOC_FREE(talloced
);
428 TALLOC_FREE(unmangled_name
);
429 TALLOC_FREE(cur_dir
);
430 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
433 /****************************************************************************
434 Wrapper around the vfs get_real_filename and the full directory scan
436 ****************************************************************************/
438 NTSTATUS
get_real_filename_at(struct files_struct
*dirfsp
,
443 struct connection_struct
*conn
= dirfsp
->conn
;
447 mangled
= mangle_is_mangled(name
, conn
->params
);
450 status
= get_real_filename_full_scan_at(
451 dirfsp
, name
, mangled
, mem_ctx
, found_name
);
455 /* Try the vfs first to take advantage of case-insensitive stat. */
456 status
= SMB_VFS_GET_REAL_FILENAME_AT(
457 dirfsp
->conn
, dirfsp
, name
, mem_ctx
, found_name
);
460 * If the case-insensitive stat was successful, or returned an error
461 * other than EOPNOTSUPP then there is no need to fall back on the
462 * full directory scan.
464 if (NT_STATUS_IS_OK(status
) ||
465 !NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
469 status
= get_real_filename_full_scan_at(
470 dirfsp
, name
, mangled
, mem_ctx
, found_name
);
475 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
476 * the stat cache for the last component to be looked up. Cache
477 * contents is the correctly capitalized translation of the parameter
478 * "name" as it exists on disk. This is indexed by inode of the dirfsp
479 * and name, and contrary to stat_cahce_lookup() it does not
480 * vfs_stat() the last component. This will be taken care of by an
481 * attempt to do a openat_pathref_fsp().
483 static bool get_real_filename_cache_key(
485 struct files_struct
*dirfsp
,
489 struct file_id fid
= vfs_file_id_from_sbuf(
490 dirfsp
->conn
, &dirfsp
->fsp_name
->st
);
493 size_t namelen
, keylen
;
495 upper
= talloc_strdup_upper(mem_ctx
, name
);
499 namelen
= talloc_get_size(upper
);
501 keylen
= namelen
+ sizeof(fid
);
502 if (keylen
< sizeof(fid
)) {
507 key
= talloc_size(mem_ctx
, keylen
);
513 memcpy(key
, &fid
, sizeof(fid
));
514 memcpy(key
+ sizeof(fid
), upper
, namelen
);
517 *_key
= (DATA_BLOB
) { .data
= key
, .length
= keylen
, };
522 * Lightweight function to just get last component
523 * for rename / enumerate directory calls.
526 char *get_original_lcomp(TALLOC_CTX
*ctx
,
527 connection_struct
*conn
,
528 const char *filename_in
,
531 char *last_slash
= NULL
;
535 last_slash
= strrchr(filename_in
, '/');
536 if (last_slash
!= NULL
) {
537 orig_lcomp
= talloc_strdup(ctx
, last_slash
+1);
539 orig_lcomp
= talloc_strdup(ctx
, filename_in
);
541 if (orig_lcomp
== NULL
) {
544 status
= normalize_filename_case(conn
, orig_lcomp
, ucf_flags
);
545 if (!NT_STATUS_IS_OK(status
)) {
546 TALLOC_FREE(orig_lcomp
);
553 * Deal with the SMB1 semantics of sending a pathname with a
554 * wildcard as the terminal component for a SMB1search or
558 NTSTATUS
filename_convert_smb1_search_path(TALLOC_CTX
*ctx
,
559 connection_struct
*conn
,
562 struct files_struct
**_dirfsp
,
563 struct smb_filename
**_smb_fname_out
,
569 struct smb_filename
*smb_fname
= NULL
;
572 *_smb_fname_out
= NULL
;
576 DBG_DEBUG("name_in: %s\n", name_in
);
578 if (ucf_flags
& UCF_GMT_PATHNAME
) {
579 extract_snapshot_token(name_in
, &twrp
);
580 ucf_flags
&= ~UCF_GMT_PATHNAME
;
583 if (ucf_flags
& UCF_DFS_PATHNAME
) {
585 * We've been given a raw DFS pathname.
587 char *pathname
= NULL
;
588 DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in
);
589 status
= dfs_filename_convert(ctx
,
594 if (!NT_STATUS_IS_OK(status
)) {
595 DBG_DEBUG("dfs_filename_convert "
596 "failed for name %s with %s\n",
601 ucf_flags
&= ~UCF_DFS_PATHNAME
;
603 DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in
);
606 /* Get the original lcomp. */
607 mask
= get_original_lcomp(ctx
,
612 return NT_STATUS_NO_MEMORY
;
615 if (mask
[0] == '\0') {
616 /* Windows and OS/2 systems treat search on the root as * */
618 mask
= talloc_strdup(ctx
, "*");
620 return NT_STATUS_NO_MEMORY
;
624 DBG_DEBUG("mask = %s\n", mask
);
627 * Remove the terminal component so
628 * filename_convert_dirfsp never sees the mask.
630 p
= strrchr_m(name_in
,'/');
632 /* filename_convert_dirfsp handles a '\0' name. */
638 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
641 /* Convert the parent directory path. */
642 status
= filename_convert_dirfsp(ctx
,
650 if (!NT_STATUS_IS_OK(status
)) {
651 DBG_DEBUG("filename_convert error for %s: %s\n",
656 *_smb_fname_out
= talloc_move(ctx
, &smb_fname
);
657 *_mask_out
= talloc_move(ctx
, &mask
);
663 * Get the correct capitalized stream name hanging off
664 * base_fsp. Equivalent of get_real_filename(), but for streams.
666 static NTSTATUS
get_real_stream_name(
668 struct files_struct
*base_fsp
,
669 const char *stream_name
,
672 unsigned int i
, num_streams
= 0;
673 struct stream_struct
*streams
= NULL
;
676 status
= vfs_fstreaminfo(
677 base_fsp
, talloc_tos(), &num_streams
, &streams
);
678 if (!NT_STATUS_IS_OK(status
)) {
682 for (i
=0; i
<num_streams
; i
++) {
683 bool equal
= sname_equal(stream_name
, streams
[i
].name
, false);
685 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
688 equal
? "" : "not ");
691 *_found
= talloc_move(mem_ctx
, &streams
[i
].name
);
692 TALLOC_FREE(streams
);
697 TALLOC_FREE(streams
);
698 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
701 static bool filename_split_lcomp(
706 const char **_fname_rel
,
707 const char **_streamname
)
709 const char *lcomp
= NULL
;
710 const char *fname_rel
= NULL
;
711 const char *streamname
= NULL
;
712 char *dirname
= NULL
;
714 if (name_in
[0] == '\0') {
716 dirname
= talloc_strdup(mem_ctx
, "");
717 if (dirname
== NULL
) {
723 lcomp
= strrchr_m(name_in
, '/');
726 dirname
= talloc_strndup(mem_ctx
, name_in
, lcomp
- name_in
);
727 if (dirname
== NULL
) {
734 * No slash, dir is emtpy
736 dirname
= talloc_strdup(mem_ctx
, "");
737 if (dirname
== NULL
) {
741 if (!posix
&& (name_in
[0] == ':')) {
743 * Special case for stream on root directory
746 streamname
= name_in
;
754 streamname
= strchr_m(fname_rel
, ':');
756 if (streamname
!= NULL
) {
757 fname_rel
= talloc_strndup(
760 streamname
- fname_rel
);
761 if (fname_rel
== NULL
) {
762 TALLOC_FREE(dirname
);
770 *_fname_rel
= fname_rel
;
771 *_streamname
= streamname
;
776 * Create the correct capitalization of a file name to be created.
778 static NTSTATUS
filename_convert_normalize_new(
780 struct connection_struct
*conn
,
784 char *name
= name_in
;
788 if (!conn
->case_preserve
||
789 (mangle_is_8_3(name
, false,
791 !conn
->short_case_preserve
)) {
793 char *normalized
= talloc_strdup(mem_ctx
, name
);
794 if (normalized
== NULL
) {
795 return NT_STATUS_NO_MEMORY
;
798 strnorm(normalized
, lp_default_case(SNUM(conn
)));
802 if (mangle_is_mangled(name
, conn
->params
)) {
804 char *unmangled
= NULL
;
806 found
= mangle_lookup_name_from_8_3(
807 mem_ctx
, name
, &unmangled
, conn
->params
);
813 if (name
!= name_in
) {
821 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
822 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
823 * the first attempt based on the filename sent by the client gives
826 static NTSTATUS
openat_pathref_fsp_case_insensitive(
827 struct files_struct
*dirfsp
,
828 struct smb_filename
*smb_fname_rel
,
831 const bool posix
= (ucf_flags
& UCF_POSIX_PATHNAMES
);
832 DATA_BLOB cache_key
= { .data
= NULL
, };
833 char *found_name
= NULL
;
837 SET_STAT_INVALID(smb_fname_rel
->st
);
839 /* Check veto files - only looks at last component. */
840 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
841 DBG_DEBUG("veto files rejecting last component %s\n",
842 smb_fname_str_dbg(smb_fname_rel
));
843 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
846 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
848 if (NT_STATUS_IS_OK(status
)) {
852 if (VALID_STAT(smb_fname_rel
->st
)) {
854 * We got an error although the object existed. Might
855 * be a symlink we don't want.
860 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
862 * Only retry on ENOENT
867 if (posix
|| dirfsp
->conn
->case_sensitive
) {
869 * Only return case insensitive if required
874 if (lp_stat_cache()) {
875 char *base_name
= smb_fname_rel
->base_name
;
876 DATA_BLOB value
= { .data
= NULL
};
878 ok
= get_real_filename_cache_key(
879 talloc_tos(), dirfsp
, base_name
, &cache_key
);
882 * probably ENOMEM, just bail
887 DO_PROFILE_INC(statcache_lookups
);
889 ok
= memcache_lookup(
890 NULL
, GETREALFILENAME_CACHE
, cache_key
, &value
);
892 DO_PROFILE_INC(statcache_misses
);
895 DO_PROFILE_INC(statcache_hits
);
897 TALLOC_FREE(smb_fname_rel
->base_name
);
898 smb_fname_rel
->base_name
= talloc_memdup(
899 smb_fname_rel
, value
.data
, value
.length
);
900 if (smb_fname_rel
->base_name
== NULL
) {
901 TALLOC_FREE(cache_key
.data
);
902 return NT_STATUS_NO_MEMORY
;
905 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
906 DBG_DEBUG("veto files rejecting last component %s\n",
907 smb_fname_str_dbg(smb_fname_rel
));
908 TALLOC_FREE(cache_key
.data
);
909 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
912 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
913 if (NT_STATUS_IS_OK(status
)) {
914 TALLOC_FREE(cache_key
.data
);
918 memcache_delete(NULL
, GETREALFILENAME_CACHE
, cache_key
);
922 status
= get_real_filename_at(
923 dirfsp
, smb_fname_rel
->base_name
, smb_fname_rel
, &found_name
);
924 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
925 (ucf_flags
& UCF_PREP_CREATEFILE
)) {
929 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
932 if (NT_STATUS_IS_OK(status
)) {
933 TALLOC_FREE(smb_fname_rel
->base_name
);
934 smb_fname_rel
->base_name
= found_name
;
936 if (IS_VETO_PATH(dirfsp
->conn
, smb_fname_rel
->base_name
)) {
937 DBG_DEBUG("veto files rejecting last component %s\n",
938 smb_fname_str_dbg(smb_fname_rel
));
939 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
942 status
= openat_pathref_fsp(dirfsp
, smb_fname_rel
);
945 if (NT_STATUS_IS_OK(status
) && (cache_key
.data
!= NULL
)) {
947 .data
= (uint8_t *)smb_fname_rel
->base_name
,
948 .length
= strlen(smb_fname_rel
->base_name
) + 1,
951 memcache_add(NULL
, GETREALFILENAME_CACHE
, cache_key
, value
);
954 TALLOC_FREE(cache_key
.data
);
960 * Split up name_in as sent by the client into a directory pathref fsp
961 * and a relative smb_filename.
963 static const char *previous_slash(const char *name_in
, const char *slash
)
965 const char *prev
= name_in
;
968 const char *next
= strchr_m(prev
, '/');
970 SMB_ASSERT(next
!= NULL
); /* we have at least one slash */
979 if (prev
== name_in
) {
980 /* no previous slash */
987 static char *symlink_target_path(
990 const char *substitute
,
993 size_t name_in_len
= strlen(name_in
);
994 const char *p_unparsed
= NULL
;
995 const char *parent
= NULL
;
998 SMB_ASSERT(unparsed
<= name_in_len
);
1000 p_unparsed
= name_in
+ (name_in_len
- unparsed
);
1002 if (substitute
[0] == '/') {
1003 ret
= talloc_asprintf(mem_ctx
, "%s%s", substitute
, p_unparsed
);
1007 if (unparsed
== 0) {
1008 parent
= strrchr_m(name_in
, '/');
1010 parent
= previous_slash(name_in
, p_unparsed
);
1013 if (parent
== NULL
) {
1014 /* no previous slash */
1018 ret
= talloc_asprintf(
1021 (int)(parent
- name_in
),
1029 * Split up name_in as sent by the client into a directory pathref fsp
1030 * and a relative smb_filename.
1032 static NTSTATUS
filename_convert_dirfsp_nosymlink(
1033 TALLOC_CTX
*mem_ctx
,
1034 connection_struct
*conn
,
1035 const char *name_in
,
1038 struct files_struct
**_dirfsp
,
1039 struct smb_filename
**_smb_fname
,
1043 struct smb_filename
*smb_dirname
= NULL
;
1044 struct smb_filename
*smb_fname_rel
= NULL
;
1045 struct smb_filename
*smb_fname
= NULL
;
1046 const bool posix
= (ucf_flags
& UCF_POSIX_PATHNAMES
);
1047 char *dirname
= NULL
;
1048 const char *fname_rel
= NULL
;
1049 const char *streamname
= NULL
;
1050 char *saved_streamname
= NULL
;
1051 struct files_struct
*base_fsp
= NULL
;
1053 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1055 if (ucf_flags
& UCF_DFS_PATHNAME
) {
1057 * We've been given a raw DFS pathname.
1059 char *pathname
= NULL
;
1060 DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in
);
1061 status
= dfs_filename_convert(mem_ctx
,
1066 if (!NT_STATUS_IS_OK(status
)) {
1067 DBG_DEBUG("dfs_filename_convert "
1068 "failed for name %s with %s\n",
1073 ucf_flags
&= ~UCF_DFS_PATHNAME
;
1075 DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in
);
1078 if (is_fake_file_path(name_in
)) {
1079 smb_fname
= synthetic_smb_fname_split(mem_ctx
, name_in
, posix
);
1080 if (smb_fname
== NULL
) {
1081 return NT_STATUS_NO_MEMORY
;
1083 smb_fname
->st
= (SMB_STRUCT_STAT
) { .st_ex_nlink
= 1 };
1084 smb_fname
->st
.st_ex_btime
=
1085 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1086 smb_fname
->st
.st_ex_atime
=
1087 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1088 smb_fname
->st
.st_ex_mtime
=
1089 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1090 smb_fname
->st
.st_ex_ctime
=
1091 (struct timespec
){0, SAMBA_UTIME_OMIT
};
1093 *_dirfsp
= conn
->cwd_fsp
;
1094 *_smb_fname
= smb_fname
;
1095 return NT_STATUS_OK
;
1099 * Catch an invalid path of "." before we
1100 * call filename_split_lcomp(). We need to
1101 * do this as filename_split_lcomp() will
1102 * use "." for the missing relative component
1103 * when an empty name_in path is sent by
1106 if (ISDOT(name_in
)) {
1107 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1111 ok
= filename_split_lcomp(
1119 status
= NT_STATUS_NO_MEMORY
;
1123 if ((streamname
!= NULL
) &&
1124 ((conn
->fs_capabilities
& FILE_NAMED_STREAMS
) == 0)) {
1125 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1130 bool name_has_wild
= ms_has_wild(dirname
);
1131 name_has_wild
|= ms_has_wild(fname_rel
);
1132 if (name_has_wild
) {
1133 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1138 if (dirname
[0] == '\0') {
1139 status
= synthetic_pathref(
1146 posix
? SMB_FILENAME_POSIX_PATH
: 0,
1149 char *substitute
= NULL
;
1150 size_t unparsed
= 0;
1152 status
= openat_pathref_dirfsp_nosymlink(
1161 if (NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1163 size_t name_in_len
= strlen(name_in
);
1164 size_t dirname_len
= strlen(dirname
);
1166 SMB_ASSERT(name_in_len
>= dirname_len
);
1168 *_substitute
= substitute
;
1169 *_unparsed
= unparsed
+ (name_in_len
- dirname_len
);
1175 if (!NT_STATUS_IS_OK(status
)) {
1176 DBG_DEBUG("opening directory %s failed: %s\n",
1179 TALLOC_FREE(dirname
);
1181 if (NT_STATUS_EQUAL(status
, NT_STATUS_PATH_NOT_COVERED
)) {
1182 /* MS-DFS error must propagate back out. */
1186 if (!NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
1188 * Except ACCESS_DENIED, everything else leads
1189 * to PATH_NOT_FOUND.
1191 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1197 if (!VALID_STAT_OF_DIR(smb_dirname
->st
)) {
1198 status
= NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1203 * Only look at bad last component values
1204 * once we know we have a valid directory. That
1205 * way we won't confuse error messages from
1206 * opening the directory path with error
1207 * messages from a bad last component.
1210 /* Relative filename can't be empty */
1211 if (fname_rel
[0] == '\0') {
1212 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1216 /* Relative filename can't be ".." */
1217 if (ISDOTDOT(fname_rel
)) {
1218 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1221 /* Relative name can only be dot if directory is empty. */
1222 if (ISDOT(fname_rel
) && dirname
[0] != '\0') {
1223 status
= NT_STATUS_OBJECT_NAME_INVALID
;
1227 TALLOC_FREE(dirname
);
1229 smb_fname_rel
= synthetic_smb_fname(
1235 posix
? SMB_FILENAME_POSIX_PATH
: 0);
1236 if (smb_fname_rel
== NULL
) {
1237 status
= NT_STATUS_NO_MEMORY
;
1241 if ((conn
->fs_capabilities
& FILE_NAMED_STREAMS
) &&
1242 is_named_stream(smb_fname_rel
)) {
1244 * Find the base_fsp first without the stream.
1246 saved_streamname
= smb_fname_rel
->stream_name
;
1247 smb_fname_rel
->stream_name
= NULL
;
1250 status
= normalize_filename_case(
1251 conn
, smb_fname_rel
->base_name
, ucf_flags
);
1252 if (!NT_STATUS_IS_OK(status
)) {
1253 DBG_ERR("normalize_filename_case %s failed: %s\n",
1254 smb_fname_rel
->base_name
,
1259 status
= openat_pathref_fsp_case_insensitive(
1260 smb_dirname
->fsp
, smb_fname_rel
, ucf_flags
);
1262 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1264 char *normalized
= NULL
;
1266 if (VALID_STAT(smb_fname_rel
->st
)) {
1268 * If we're on an MSDFS share, see if this is
1271 if (lp_host_msdfs() &&
1272 lp_msdfs_root(SNUM(conn
)) &&
1273 S_ISLNK(smb_fname_rel
->st
.st_ex_mode
) &&
1274 is_msdfs_link(smb_dirname
->fsp
, smb_fname_rel
))
1276 status
= NT_STATUS_PATH_NOT_COVERED
;
1280 #if defined(WITH_SMB1SERVER)
1282 * In SMB1 posix mode, if this is a symlink,
1283 * allow access to the name with a NULL smb_fname->fsp.
1285 if (!conn
->sconn
->using_smb2
&&
1287 S_ISLNK(smb_fname_rel
->st
.st_ex_mode
)) {
1288 SMB_ASSERT(smb_fname_rel
->fsp
== NULL
);
1289 SMB_ASSERT(streamname
== NULL
);
1291 smb_fname
= full_path_from_dirfsp_atname(
1295 if (smb_fname
== NULL
) {
1296 status
= NT_STATUS_NO_MEMORY
;
1303 * NT_STATUS_OBJECT_NAME_NOT_FOUND is
1304 * misleading: The object exists but might be
1305 * a symlink pointing outside the share.
1311 * Creating a new file
1314 status
= filename_convert_normalize_new(
1317 smb_fname_rel
->base_name
,
1319 if (!NT_STATUS_IS_OK(status
)) {
1320 DBG_DEBUG("filename_convert_normalize_new failed: "
1325 if (normalized
!= NULL
) {
1326 smb_fname_rel
->base_name
= normalized
;
1329 smb_fname_rel
->stream_name
= saved_streamname
;
1331 smb_fname
= full_path_from_dirfsp_atname(
1332 mem_ctx
, smb_dirname
->fsp
, smb_fname_rel
);
1333 if (smb_fname
== NULL
) {
1334 status
= NT_STATUS_NO_MEMORY
;
1340 if (!NT_STATUS_IS_OK(status
)) {
1344 if (saved_streamname
== NULL
) {
1345 /* smb_fname must be allocated off mem_ctx. */
1346 smb_fname
= cp_smb_filename(mem_ctx
,
1347 smb_fname_rel
->fsp
->fsp_name
);
1348 if (smb_fname
== NULL
) {
1351 status
= move_smb_fname_fsp_link(smb_fname
, smb_fname_rel
);
1352 if (!NT_STATUS_IS_OK(status
)) {
1358 base_fsp
= smb_fname_rel
->fsp
;
1359 smb_fname_fsp_unlink(smb_fname_rel
);
1360 SET_STAT_INVALID(smb_fname_rel
->st
);
1362 smb_fname_rel
->stream_name
= saved_streamname
;
1364 status
= open_stream_pathref_fsp(&base_fsp
, smb_fname_rel
);
1366 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
) &&
1367 !conn
->case_sensitive
) {
1370 status
= get_real_stream_name(
1373 smb_fname_rel
->stream_name
,
1376 if (NT_STATUS_IS_OK(status
)) {
1377 smb_fname_rel
->stream_name
= found
;
1379 status
= open_stream_pathref_fsp(
1380 &base_fsp
, smb_fname_rel
);
1384 if (NT_STATUS_IS_OK(status
)) {
1385 /* smb_fname must be allocated off mem_ctx. */
1386 smb_fname
= cp_smb_filename(mem_ctx
,
1387 smb_fname_rel
->fsp
->fsp_name
);
1388 if (smb_fname
== NULL
) {
1391 status
= move_smb_fname_fsp_link(smb_fname
, smb_fname_rel
);
1392 if (!NT_STATUS_IS_OK(status
)) {
1398 if (NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1400 * Creating a new stream
1402 * We should save the already-open base fsp for
1403 * create_file_unixpath() somehow.
1405 smb_fname
= full_path_from_dirfsp_atname(
1406 mem_ctx
, smb_dirname
->fsp
, smb_fname_rel
);
1407 if (smb_fname
== NULL
) {
1408 status
= NT_STATUS_NO_MEMORY
;
1414 if (!NT_STATUS_IS_OK(status
)) {
1419 *_dirfsp
= smb_dirname
->fsp
;
1420 *_smb_fname
= smb_fname
;
1422 smb_fname_fsp_unlink(smb_fname_rel
);
1423 TALLOC_FREE(smb_fname_rel
);
1424 return NT_STATUS_OK
;
1427 TALLOC_FREE(dirname
);
1428 TALLOC_FREE(smb_dirname
);
1429 TALLOC_FREE(smb_fname_rel
);
1433 NTSTATUS
filename_convert_dirfsp(
1434 TALLOC_CTX
*mem_ctx
,
1435 connection_struct
*conn
,
1436 const char *name_in
,
1439 struct files_struct
**_dirfsp
,
1440 struct smb_filename
**_smb_fname
)
1442 char *substitute
= NULL
;
1443 size_t unparsed
= 0;
1445 char *target
= NULL
;
1446 char *abs_target
= NULL
;
1447 char *abs_target_canon
= NULL
;
1448 size_t symlink_redirects
= 0;
1452 if (symlink_redirects
> 40) {
1453 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1456 status
= filename_convert_dirfsp_nosymlink(
1467 if (!NT_STATUS_EQUAL(status
, NT_STATUS_STOPPED_ON_SYMLINK
)) {
1471 if (!lp_follow_symlinks(SNUM(conn
))) {
1472 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1476 * Right now, SMB2 and SMB1 always traverse symlinks
1477 * within the share. SMB1+POSIX traverses non-terminal
1478 * symlinks within the share.
1480 * When we add SMB2+POSIX we need to return
1481 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1482 * symlink target data read below if SMB2+POSIX has
1483 * UCF_POSIX_PATHNAMES set to cause the client to
1484 * resolve all symlinks locally.
1487 target
= symlink_target_path(mem_ctx
, name_in
, substitute
, unparsed
);
1488 if (target
== NULL
) {
1489 return NT_STATUS_NO_MEMORY
;
1492 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
1498 if (target
[0] == '/') {
1499 abs_target
= target
;
1501 abs_target
= talloc_asprintf(
1502 mem_ctx
, "%s/%s", conn
->connectpath
, target
);
1503 if (abs_target
== NULL
) {
1504 return NT_STATUS_NO_MEMORY
;
1508 abs_target_canon
= canonicalize_absolute_path(mem_ctx
, abs_target
);
1509 if (abs_target_canon
== NULL
) {
1510 return NT_STATUS_NO_MEMORY
;
1513 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon
);
1518 strlen(conn
->connectpath
)) == 0;
1520 DBG_DEBUG("wide link to %s\n", abs_target_canon
);
1521 return NT_STATUS_OBJECT_PATH_NOT_FOUND
;
1524 name_in
= talloc_strdup(
1525 mem_ctx
, abs_target_canon
+ strlen(conn
->connectpath
) + 1);
1527 symlink_redirects
+= 1;
1533 * Build the full path from a dirfsp and dirfsp relative name
1535 struct smb_filename
*full_path_from_dirfsp_atname(
1536 TALLOC_CTX
*mem_ctx
,
1537 const struct files_struct
*dirfsp
,
1538 const struct smb_filename
*atname
)
1540 struct smb_filename
*fname
= NULL
;
1543 if (dirfsp
== dirfsp
->conn
->cwd_fsp
||
1544 ISDOT(dirfsp
->fsp_name
->base_name
) ||
1545 atname
->base_name
[0] == '/')
1547 path
= talloc_strdup(mem_ctx
, atname
->base_name
);
1549 path
= talloc_asprintf(mem_ctx
, "%s/%s",
1550 dirfsp
->fsp_name
->base_name
,
1557 fname
= synthetic_smb_fname(mem_ctx
,
1559 atname
->stream_name
,
1564 if (fname
== NULL
) {