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;
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.
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,
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",
322 TALLOC_FREE(unmangled_name);
326 /* now scan for matching names */
328 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
330 /* Is it dot or dot dot. */
331 if (ISDOT(dname) || ISDOTDOT(dname)) {
332 TALLOC_FREE(talloced);
337 * At this point dname is the unmangled name.
338 * name is either mangled or not, depending on the state
339 * of the "mangled" variable. JRA.
343 * Check mangled name against mangled name, or unmangled name
344 * against unmangled name.
347 if ((mangled && mangled_equal(name,dname,conn->params)) ||
348 fname_equal(name, dname, conn->case_sensitive)) {
349 /* we've found the file, change it's name and return */
350 *found_name = talloc_strdup(mem_ctx, dname);
351 TALLOC_FREE(unmangled_name);
352 TALLOC_FREE(cur_dir);
354 TALLOC_FREE(talloced);
355 return NT_STATUS_NO_MEMORY;
357 TALLOC_FREE(talloced);
360 TALLOC_FREE(talloced);
363 TALLOC_FREE(unmangled_name);
364 TALLOC_FREE(cur_dir);
365 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
368 /****************************************************************************
369 Wrapper around the vfs get_real_filename and the full directory scan
371 ****************************************************************************/
373 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
378 struct connection_struct *conn = dirfsp->conn;
382 mangled = mangle_is_mangled(name, conn->params);
385 status = get_real_filename_full_scan_at(
386 dirfsp, name, mangled, mem_ctx, found_name);
390 /* Try the vfs first to take advantage of case-insensitive stat. */
391 status = SMB_VFS_GET_REAL_FILENAME_AT(
392 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
395 * If the case-insensitive stat was successful, or returned an error
396 * other than EOPNOTSUPP then there is no need to fall back on the
397 * full directory scan.
399 if (NT_STATUS_IS_OK(status) ||
400 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
404 status = get_real_filename_full_scan_at(
405 dirfsp, name, mangled, mem_ctx, found_name);
410 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
411 * the stat cache for the last component to be looked up. Cache
412 * contents is the correctly capitalized translation of the parameter
413 * "name" as it exists on disk. This is indexed by inode of the dirfsp
414 * and name, and contrary to stat_cahce_lookup() it does not
415 * vfs_stat() the last component. This will be taken care of by an
416 * attempt to do a openat_pathref_fsp().
418 static bool get_real_filename_cache_key(
420 struct files_struct *dirfsp,
424 struct file_id fid = vfs_file_id_from_sbuf(
425 dirfsp->conn, &dirfsp->fsp_name->st);
428 size_t namelen, keylen;
430 upper = talloc_strdup_upper(mem_ctx, name);
434 namelen = talloc_get_size(upper);
436 keylen = namelen + sizeof(fid);
437 if (keylen < sizeof(fid)) {
442 key = talloc_size(mem_ctx, keylen);
448 memcpy(key, &fid, sizeof(fid));
449 memcpy(key + sizeof(fid), upper, namelen);
452 *_key = (DATA_BLOB) { .data = key, .length = keylen, };
457 * Lightweight function to just get last component
458 * for rename / enumerate directory calls.
461 char *get_original_lcomp(TALLOC_CTX *ctx,
462 connection_struct *conn,
463 const char *filename_in,
466 char *last_slash = NULL;
470 last_slash = strrchr(filename_in, '/');
471 if (last_slash != NULL) {
472 orig_lcomp = talloc_strdup(ctx, last_slash+1);
474 orig_lcomp = talloc_strdup(ctx, filename_in);
476 if (orig_lcomp == NULL) {
479 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
480 if (!NT_STATUS_IS_OK(status)) {
481 TALLOC_FREE(orig_lcomp);
488 * Deal with the SMB1 semantics of sending a pathname with a
489 * wildcard as the terminal component for a SMB1search or
493 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
494 connection_struct *conn,
497 struct files_struct **_dirfsp,
498 struct smb_filename **_smb_fname_out,
504 struct smb_filename *smb_fname = NULL;
507 *_smb_fname_out = NULL;
511 DBG_DEBUG("name_in: %s\n", name_in);
513 if (ucf_flags & UCF_GMT_PATHNAME) {
514 extract_snapshot_token(name_in, &twrp);
515 ucf_flags &= ~UCF_GMT_PATHNAME;
518 /* Get the original lcomp. */
519 mask = get_original_lcomp(ctx,
524 return NT_STATUS_NO_MEMORY;
527 if (mask[0] == '\0') {
528 /* Windows and OS/2 systems treat search on the root as * */
530 mask = talloc_strdup(ctx, "*");
532 return NT_STATUS_NO_MEMORY;
536 DBG_DEBUG("mask = %s\n", mask);
539 * Remove the terminal component so
540 * filename_convert_dirfsp never sees the mask.
542 p = strrchr_m(name_in,'/');
544 /* filename_convert_dirfsp handles a '\0' name. */
550 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
553 /* Convert the parent directory path. */
554 status = filename_convert_dirfsp(ctx,
562 if (!NT_STATUS_IS_OK(status)) {
563 DBG_DEBUG("filename_convert error for %s: %s\n",
568 *_smb_fname_out = talloc_move(ctx, &smb_fname);
569 *_mask_out = talloc_move(ctx, &mask);
575 * Get the correct capitalized stream name hanging off
576 * base_fsp. Equivalent of get_real_filename(), but for streams.
578 static NTSTATUS get_real_stream_name(
580 struct files_struct *base_fsp,
581 const char *stream_name,
584 unsigned int i, num_streams = 0;
585 struct stream_struct *streams = NULL;
588 status = vfs_fstreaminfo(
589 base_fsp, talloc_tos(), &num_streams, &streams);
590 if (!NT_STATUS_IS_OK(status)) {
594 for (i=0; i<num_streams; i++) {
595 bool equal = sname_equal(stream_name, streams[i].name, false);
597 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
600 equal ? "" : "not ");
603 *_found = talloc_move(mem_ctx, &streams[i].name);
604 TALLOC_FREE(streams);
609 TALLOC_FREE(streams);
610 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
613 static bool filename_split_lcomp(
618 const char **_fname_rel,
619 const char **_streamname)
621 const char *lcomp = NULL;
622 const char *fname_rel = NULL;
623 const char *streamname = NULL;
624 char *dirname = NULL;
626 if (name_in[0] == '\0') {
628 dirname = talloc_strdup(mem_ctx, "");
629 if (dirname == NULL) {
635 lcomp = strrchr_m(name_in, '/');
638 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
639 if (dirname == NULL) {
646 * No slash, dir is emtpy
648 dirname = talloc_strdup(mem_ctx, "");
649 if (dirname == NULL) {
653 if (!posix && (name_in[0] == ':')) {
655 * Special case for stream on root directory
658 streamname = name_in;
666 streamname = strchr_m(fname_rel, ':');
668 if (streamname != NULL) {
669 fname_rel = talloc_strndup(
672 streamname - fname_rel);
673 if (fname_rel == NULL) {
674 TALLOC_FREE(dirname);
682 *_fname_rel = fname_rel;
683 *_streamname = streamname;
688 * Create the correct capitalization of a file name to be created.
690 static NTSTATUS filename_convert_normalize_new(
692 struct connection_struct *conn,
696 char *name = name_in;
700 if (!conn->case_preserve ||
701 (mangle_is_8_3(name, false,
703 !conn->short_case_preserve)) {
705 char *normalized = talloc_strdup(mem_ctx, name);
706 if (normalized == NULL) {
707 return NT_STATUS_NO_MEMORY;
710 strnorm(normalized, lp_default_case(SNUM(conn)));
714 if (mangle_is_mangled(name, conn->params)) {
716 char *unmangled = NULL;
718 found = mangle_lookup_name_from_8_3(
719 mem_ctx, name, &unmangled, conn->params);
725 if (name != name_in) {
733 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
734 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
735 * the first attempt based on the filename sent by the client gives
738 static NTSTATUS openat_pathref_fsp_case_insensitive(
739 struct files_struct *dirfsp,
740 struct smb_filename *smb_fname_rel,
743 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
744 DATA_BLOB cache_key = { .data = NULL, };
745 char *found_name = NULL;
749 SET_STAT_INVALID(smb_fname_rel->st);
751 /* Check veto files - only looks at last component. */
752 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
753 DBG_DEBUG("veto files rejecting last component %s\n",
754 smb_fname_str_dbg(smb_fname_rel));
755 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
758 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
760 if (NT_STATUS_IS_OK(status)) {
764 if (VALID_STAT(smb_fname_rel->st)) {
766 * We got an error although the object existed. Might
767 * be a symlink we don't want.
772 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
774 * Only retry on ENOENT
779 if (posix || dirfsp->conn->case_sensitive) {
781 * Only return case insensitive if required
786 if (lp_stat_cache()) {
787 char *base_name = smb_fname_rel->base_name;
788 char *original_relname = NULL;
789 DATA_BLOB value = { .data = NULL };
791 ok = get_real_filename_cache_key(
792 talloc_tos(), dirfsp, base_name, &cache_key);
795 * probably ENOMEM, just bail
800 DO_PROFILE_INC(statcache_lookups);
802 ok = memcache_lookup(
803 NULL, GETREALFILENAME_CACHE, cache_key, &value);
805 DO_PROFILE_INC(statcache_misses);
808 DO_PROFILE_INC(statcache_hits);
811 * For the "new filename" case we need to preserve the
812 * capitalization the client sent us, see
813 * https://bugzilla.samba.org/show_bug.cgi?id=15481
815 original_relname = smb_fname_rel->base_name;
817 smb_fname_rel->base_name = talloc_memdup(
818 smb_fname_rel, value.data, value.length);
819 if (smb_fname_rel->base_name == NULL) {
820 TALLOC_FREE(cache_key.data);
821 return NT_STATUS_NO_MEMORY;
824 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
825 DBG_DEBUG("veto files rejecting last component %s\n",
826 smb_fname_str_dbg(smb_fname_rel));
827 TALLOC_FREE(cache_key.data);
828 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
831 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
832 if (NT_STATUS_IS_OK(status)) {
833 TALLOC_FREE(cache_key.data);
834 TALLOC_FREE(original_relname);
838 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
839 TALLOC_FREE(smb_fname_rel->base_name);
840 smb_fname_rel->base_name = original_relname;
844 status = get_real_filename_at(
845 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
846 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
847 (ucf_flags & UCF_PREP_CREATEFILE)) {
851 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
854 if (NT_STATUS_IS_OK(status)) {
855 TALLOC_FREE(smb_fname_rel->base_name);
856 smb_fname_rel->base_name = found_name;
858 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
859 DBG_DEBUG("veto files rejecting last component %s\n",
860 smb_fname_str_dbg(smb_fname_rel));
861 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
864 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
867 if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
869 .data = (uint8_t *)smb_fname_rel->base_name,
870 .length = strlen(smb_fname_rel->base_name) + 1,
873 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
876 TALLOC_FREE(cache_key.data);
881 static const char *previous_slash(const char *name_in, const char *slash)
883 const char *prev = name_in;
886 const char *next = strchr_m(prev, '/');
888 SMB_ASSERT(next != NULL); /* we have at least one slash */
897 if (prev == name_in) {
898 /* no previous slash */
905 static char *symlink_target_path(
908 const char *substitute,
911 size_t name_in_len = strlen(name_in);
912 const char *p_unparsed = NULL;
913 const char *parent = NULL;
916 SMB_ASSERT(unparsed <= name_in_len);
918 p_unparsed = name_in + (name_in_len - unparsed);
920 if (substitute[0] == '/') {
921 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
926 parent = strrchr_m(name_in, '/');
928 parent = previous_slash(name_in, p_unparsed);
931 if (parent == NULL) {
932 /* no previous slash */
936 ret = talloc_asprintf(
939 (int)(parent - name_in),
946 static NTSTATUS safe_symlink_target_path(
948 const char *connectpath,
950 const char *substitute,
955 char *abs_target = NULL;
956 char *abs_target_canon = NULL;
957 const char *relative = NULL;
958 char *name_out = NULL;
959 NTSTATUS status = NT_STATUS_NO_MEMORY;
962 target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
963 if (target == NULL) {
967 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
973 if (target[0] == '/') {
976 abs_target = talloc_asprintf(
977 target, "%s/%s", connectpath, target);
978 if (abs_target == NULL) {
983 abs_target_canon = canonicalize_absolute_path(target, abs_target);
984 if (abs_target_canon == NULL) {
988 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
990 in_share = subdir_of(
991 connectpath, strlen(connectpath), abs_target_canon, &relative);
993 DBG_DEBUG("wide link to %s\n", abs_target_canon);
994 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
998 name_out = talloc_strdup(mem_ctx, relative);
999 if (name_out == NULL) {
1003 status = NT_STATUS_OK;
1004 *_name_out = name_out;
1006 TALLOC_FREE(target);
1011 * Split up name_in as sent by the client into a directory pathref fsp
1012 * and a relative smb_filename.
1014 static NTSTATUS filename_convert_dirfsp_nosymlink(
1015 TALLOC_CTX *mem_ctx,
1016 connection_struct *conn,
1017 const char *name_in,
1020 struct files_struct **_dirfsp,
1021 struct smb_filename **_smb_fname,
1025 struct smb_filename *smb_dirname = NULL;
1026 struct smb_filename *smb_fname_rel = NULL;
1027 struct smb_filename *smb_fname = NULL;
1028 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
1029 char *dirname = NULL;
1030 const char *fname_rel = NULL;
1031 const char *streamname = NULL;
1032 char *saved_streamname = NULL;
1033 struct files_struct *base_fsp = NULL;
1035 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1037 if (ucf_flags & UCF_DFS_PATHNAME) {
1039 * We've been given a raw DFS pathname.
1041 char *pathname = NULL;
1042 DBG_DEBUG("Before dfs_filename_convert name_in: %s\n",
1044 status = dfs_filename_convert(mem_ctx,
1049 if (!NT_STATUS_IS_OK(status)) {
1050 DBG_DEBUG("dfs_filename_convert "
1051 "failed for name %s with %s\n",
1056 ucf_flags &= ~UCF_DFS_PATHNAME;
1058 DBG_DEBUG("After dfs_filename_convert name_in: %s\n",
1062 if (is_fake_file_path(name_in)) {
1063 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
1064 if (smb_fname == NULL) {
1065 return NT_STATUS_NO_MEMORY;
1067 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1068 smb_fname->st.st_ex_btime =
1069 (struct timespec){0, SAMBA_UTIME_OMIT};
1070 smb_fname->st.st_ex_atime =
1071 (struct timespec){0, SAMBA_UTIME_OMIT};
1072 smb_fname->st.st_ex_mtime =
1073 (struct timespec){0, SAMBA_UTIME_OMIT};
1074 smb_fname->st.st_ex_ctime =
1075 (struct timespec){0, SAMBA_UTIME_OMIT};
1077 *_dirfsp = conn->cwd_fsp;
1078 *_smb_fname = smb_fname;
1079 return NT_STATUS_OK;
1083 * Catch an invalid path of "." before we
1084 * call filename_split_lcomp(). We need to
1085 * do this as filename_split_lcomp() will
1086 * use "." for the missing relative component
1087 * when an empty name_in path is sent by
1090 if (ISDOT(name_in)) {
1091 status = NT_STATUS_OBJECT_NAME_INVALID;
1095 ok = filename_split_lcomp(
1103 status = NT_STATUS_NO_MEMORY;
1107 if ((streamname != NULL) &&
1108 ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
1109 status = NT_STATUS_OBJECT_NAME_INVALID;
1114 bool name_has_wild = ms_has_wild(dirname);
1115 name_has_wild |= ms_has_wild(fname_rel);
1116 if (name_has_wild) {
1117 status = NT_STATUS_OBJECT_NAME_INVALID;
1122 if (dirname[0] == '\0') {
1123 status = synthetic_pathref(
1130 posix ? SMB_FILENAME_POSIX_PATH : 0,
1133 char *substitute = NULL;
1134 size_t unparsed = 0;
1136 status = normalize_filename_case(conn, dirname, ucf_flags);
1137 if (!NT_STATUS_IS_OK(status)) {
1138 DBG_ERR("normalize_filename_case %s failed: %s\n",
1144 status = openat_pathref_dirfsp_nosymlink(
1154 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1156 size_t name_in_len = strlen(name_in);
1157 size_t dirname_len = strlen(dirname);
1159 SMB_ASSERT(name_in_len >= dirname_len);
1161 *_substitute = substitute;
1162 *_unparsed = unparsed + (name_in_len - dirname_len);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 DBG_DEBUG("opening directory %s failed: %s\n",
1172 TALLOC_FREE(dirname);
1174 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1175 /* MS-DFS error must propagate back out. */
1179 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1181 * Except ACCESS_DENIED, everything else leads
1182 * to PATH_NOT_FOUND.
1184 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1190 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
1191 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1196 * Only look at bad last component values
1197 * once we know we have a valid directory. That
1198 * way we won't confuse error messages from
1199 * opening the directory path with error
1200 * messages from a bad last component.
1203 /* Relative filename can't be empty */
1204 if (fname_rel[0] == '\0') {
1205 status = NT_STATUS_OBJECT_NAME_INVALID;
1209 /* Relative filename can't be ".." */
1210 if (ISDOTDOT(fname_rel)) {
1211 status = NT_STATUS_OBJECT_NAME_INVALID;
1214 /* Relative name can only be dot if directory is empty. */
1215 if (ISDOT(fname_rel) && dirname[0] != '\0') {
1216 status = NT_STATUS_OBJECT_NAME_INVALID;
1220 TALLOC_FREE(dirname);
1222 smb_fname_rel = synthetic_smb_fname(
1228 posix ? SMB_FILENAME_POSIX_PATH : 0);
1229 if (smb_fname_rel == NULL) {
1230 status = NT_STATUS_NO_MEMORY;
1234 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
1235 is_named_stream(smb_fname_rel)) {
1237 * Find the base_fsp first without the stream.
1239 saved_streamname = smb_fname_rel->stream_name;
1240 smb_fname_rel->stream_name = NULL;
1243 status = normalize_filename_case(
1244 conn, smb_fname_rel->base_name, ucf_flags);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 DBG_ERR("normalize_filename_case %s failed: %s\n",
1247 smb_fname_rel->base_name,
1252 status = openat_pathref_fsp_case_insensitive(
1253 smb_dirname->fsp, smb_fname_rel, ucf_flags);
1255 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1256 VALID_STAT(smb_fname_rel->st) &&
1257 S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
1260 * If we're on an MSDFS share, see if this is
1263 if (lp_host_msdfs() &&
1264 lp_msdfs_root(SNUM(conn)) &&
1265 is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
1267 status = NT_STATUS_PATH_NOT_COVERED;
1271 #if defined(WITH_SMB1SERVER)
1273 * In SMB1 posix mode, if this is a symlink,
1274 * allow access to the name with a NULL smb_fname->fsp.
1276 if (ucf_flags & UCF_LCOMP_LNK_OK) {
1277 SMB_ASSERT(smb_fname_rel->fsp == NULL);
1278 SMB_ASSERT(streamname == NULL);
1280 smb_fname = full_path_from_dirfsp_atname(
1284 if (smb_fname == NULL) {
1285 status = NT_STATUS_NO_MEMORY;
1293 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1294 !VALID_STAT(smb_fname_rel->st)) {
1296 char *normalized = NULL;
1299 * Creating a new file
1302 status = filename_convert_normalize_new(
1305 smb_fname_rel->base_name,
1307 if (!NT_STATUS_IS_OK(status)) {
1308 DBG_DEBUG("filename_convert_normalize_new failed: "
1313 if (normalized != NULL) {
1314 smb_fname_rel->base_name = normalized;
1317 smb_fname_rel->stream_name = saved_streamname;
1319 smb_fname = full_path_from_dirfsp_atname(
1320 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1321 if (smb_fname == NULL) {
1322 status = NT_STATUS_NO_MEMORY;
1328 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
1329 /* A vetoed file, pretend it's not there */
1330 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1332 if (!NT_STATUS_IS_OK(status)) {
1336 if (saved_streamname == NULL) {
1337 /* smb_fname must be allocated off mem_ctx. */
1338 smb_fname = cp_smb_filename(mem_ctx,
1339 smb_fname_rel->fsp->fsp_name);
1340 if (smb_fname == NULL) {
1343 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1344 if (!NT_STATUS_IS_OK(status)) {
1350 base_fsp = smb_fname_rel->fsp;
1351 smb_fname_fsp_unlink(smb_fname_rel);
1352 SET_STAT_INVALID(smb_fname_rel->st);
1354 smb_fname_rel->stream_name = saved_streamname;
1356 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1358 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1359 !conn->case_sensitive) {
1362 status = get_real_stream_name(
1365 smb_fname_rel->stream_name,
1368 if (NT_STATUS_IS_OK(status)) {
1369 smb_fname_rel->stream_name = found;
1371 status = open_stream_pathref_fsp(
1372 &base_fsp, smb_fname_rel);
1376 if (NT_STATUS_IS_OK(status)) {
1377 /* smb_fname must be allocated off mem_ctx. */
1378 smb_fname = cp_smb_filename(mem_ctx,
1379 smb_fname_rel->fsp->fsp_name);
1380 if (smb_fname == NULL) {
1383 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1384 if (!NT_STATUS_IS_OK(status)) {
1390 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1392 * Creating a new stream
1394 * We should save the already-open base fsp for
1395 * create_file_unixpath() somehow.
1397 smb_fname = full_path_from_dirfsp_atname(
1398 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1399 if (smb_fname == NULL) {
1400 status = NT_STATUS_NO_MEMORY;
1404 * When open_stream_pathref_fsp() returns
1405 * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1406 * has been set to NULL, so we must free base_fsp separately
1407 * to prevent fd-leaks when opening a stream that doesn't
1411 file_free(NULL, base_fsp);
1416 if (!NT_STATUS_IS_OK(status)) {
1421 *_dirfsp = smb_dirname->fsp;
1422 *_smb_fname = smb_fname;
1424 smb_fname_fsp_unlink(smb_fname_rel);
1425 TALLOC_FREE(smb_fname_rel);
1426 return NT_STATUS_OK;
1430 * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1431 * has been set to NULL, so we must free base_fsp separately
1432 * to prevent fd-leaks when opening a stream that doesn't
1435 if (base_fsp != NULL) {
1437 file_free(NULL, base_fsp);
1440 TALLOC_FREE(dirname);
1441 TALLOC_FREE(smb_dirname);
1442 TALLOC_FREE(smb_fname_rel);
1446 NTSTATUS filename_convert_dirfsp(
1447 TALLOC_CTX *mem_ctx,
1448 connection_struct *conn,
1449 const char *name_in,
1452 struct files_struct **_dirfsp,
1453 struct smb_filename **_smb_fname)
1455 char *substitute = NULL;
1456 size_t unparsed = 0;
1458 char *target = NULL;
1459 size_t symlink_redirects = 0;
1462 if (symlink_redirects > 40) {
1463 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1466 status = filename_convert_dirfsp_nosymlink(
1477 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1481 if (!lp_follow_symlinks(SNUM(conn))) {
1482 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1486 * Right now, SMB2 and SMB1 always traverse symlinks
1487 * within the share. SMB1+POSIX traverses non-terminal
1488 * symlinks within the share.
1490 * When we add SMB2+POSIX we need to return
1491 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1492 * symlink target data read below if SMB2+POSIX has
1493 * UCF_POSIX_PATHNAMES set to cause the client to
1494 * resolve all symlinks locally.
1497 status = safe_symlink_target_path(
1504 if (!NT_STATUS_IS_OK(status)) {
1509 symlink_redirects += 1;
1515 * Build the full path from a dirfsp and dirfsp relative name
1517 struct smb_filename *full_path_from_dirfsp_atname(
1518 TALLOC_CTX *mem_ctx,
1519 const struct files_struct *dirfsp,
1520 const struct smb_filename *atname)
1522 struct smb_filename *fname = NULL;
1525 if (dirfsp == dirfsp->conn->cwd_fsp ||
1526 ISDOT(dirfsp->fsp_name->base_name) ||
1527 atname->base_name[0] == '/')
1529 path = talloc_strdup(mem_ctx, atname->base_name);
1531 path = talloc_asprintf(mem_ctx, "%s/%s",
1532 dirfsp->fsp_name->base_name,
1539 fname = synthetic_smb_fname(mem_ctx,
1541 atname->stream_name,
1546 if (fname == NULL) {