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"
33 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
35 uint32_t ucf_flags = 0;
38 if (req->posix_pathnames) {
39 ucf_flags |= UCF_POSIX_PATHNAMES;
41 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
42 ucf_flags |= UCF_DFS_PATHNAME;
44 if (req->flags2 & FLAGS2_REPARSE_PATH) {
45 ucf_flags |= UCF_GMT_PATHNAME;
52 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
54 uint32_t ucf_flags = 0;
56 ucf_flags |= ucf_flags_from_smb_request(req);
58 switch (create_disposition) {
65 case FILE_OVERWRITE_IF:
66 ucf_flags |= UCF_PREP_CREATEFILE;
73 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
74 connection_struct *conn,
75 struct smb_filename *smb_fname);
77 /****************************************************************************
78 Mangle the 2nd name and check if it is then equal to the first name.
79 ****************************************************************************/
81 static bool mangled_equal(const char *name1,
83 const struct share_params *p)
87 if (!name_to_8_3(name2, mname, False, p)) {
90 return strequal(name1, mname);
93 /****************************************************************************
94 Cope with the differing wildcard and non-wildcard error cases.
95 ****************************************************************************/
97 static NTSTATUS determine_path_error(const char *name,
98 bool allow_wcard_last_component,
102 bool name_has_wild = false;
104 if (!allow_wcard_last_component) {
105 /* Error code within a pathname. */
106 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
109 /* We're terminating here so we
110 * can be a little slower and get
111 * the error code right. Windows
112 * treats the last part of the pathname
113 * separately I think, so if the last
114 * component is a wildcard then we treat
115 * this ./ as "end of component" */
117 p = strchr(name, '/');
119 if (!posix_pathnames) {
120 name_has_wild = ms_has_wild(name);
123 if (!p && (name_has_wild || ISDOT(name))) {
124 /* Error code at the end of a pathname. */
125 return NT_STATUS_OBJECT_NAME_INVALID;
127 /* Error code within a pathname. */
128 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
132 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
134 /* Ensure we catch all names with in "/."
135 this is disallowed under Windows and
136 in POSIX they've already been removed. */
137 const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
140 /* Error code within a pathname. */
141 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
142 } else if (p[2] == '\0') {
143 /* Error code at the end of a pathname. */
144 return NT_STATUS_OBJECT_NAME_INVALID;
150 /****************************************************************************
151 Optimization for common case where the missing part
152 is in the last component and the client already
153 sent the correct case.
154 Returns NT_STATUS_OK to mean continue the tree walk
155 (possibly with modified start pointer).
156 Any other NT_STATUS_XXX error means terminate the path
158 ****************************************************************************/
160 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
161 connection_struct *conn,
162 bool posix_pathnames,
163 const struct smb_filename *smb_fname,
167 struct smb_filename parent_fname = {0};
168 const char *last_component = NULL;
172 if (!parent_dirname(ctx, smb_fname->base_name,
173 &parent_fname.base_name,
175 return NT_STATUS_NO_MEMORY;
178 if (!posix_pathnames) {
179 if (ms_has_wild(parent_fname.base_name)) {
180 goto no_optimization_out;
185 * If there was no parent component in
186 * smb_fname->base_name then don't do this
189 if (smb_fname->base_name == last_component) {
190 goto no_optimization_out;
193 if (posix_pathnames) {
194 ret = SMB_VFS_LSTAT(conn, &parent_fname);
196 ret = SMB_VFS_STAT(conn, &parent_fname);
199 /* If the parent stat failed, just continue
200 with the normal tree walk. */
203 goto no_optimization_out;
206 status = check_for_dot_component(&parent_fname);
207 if (!NT_STATUS_IS_OK(status)) {
211 /* Parent exists - set "start" to be the
212 * last component to shorten the tree walk. */
215 * Safe to use discard_const_p
216 * here as last_component points
217 * into our smb_fname->base_name.
219 *pp_start = discard_const_p(char, last_component);
221 /* Update dirpath. */
222 TALLOC_FREE(*pp_dirpath);
223 *pp_dirpath = talloc_strdup(ctx, parent_fname.base_name);
225 return NT_STATUS_NO_MEMORY;
228 DEBUG(5,("check_parent_exists: name "
229 "= %s, dirpath = %s, "
231 smb_fname->base_name,
240 * We must still return an *pp_dirpath
241 * initialized to ".", and a *pp_start
242 * pointing at smb_fname->base_name.
245 TALLOC_FREE(parent_fname.base_name);
247 *pp_dirpath = talloc_strdup(ctx, ".");
248 if (*pp_dirpath == NULL) {
249 return NT_STATUS_NO_MEMORY;
252 * Safe to use discard_const_p
253 * here as by convention smb_fname->base_name
254 * is allocated off ctx.
256 *pp_start = discard_const_p(char, smb_fname->base_name);
261 * Re-order a known good @GMT-token path.
264 static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
269 size_t gmt_len = endp - startp;
270 char gmt_store[gmt_len + 1];
272 const char *last_component = NULL;
276 DBG_DEBUG("|%s| -> ", smb_fname->base_name);
278 /* Save off the @GMT-token. */
279 memcpy(gmt_store, startp, gmt_len);
280 gmt_store[gmt_len] = '\0';
283 /* Remove any trailing '/' */
289 * @GMT-token was at end of path.
290 * Remove any preceeding '/'
292 if (startp > smb_fname->base_name && startp[-1] == '/') {
297 /* Remove @GMT-token from the path. */
298 endlen = strlen(endp);
299 memmove(startp, endp, endlen + 1);
301 /* Split the remaining path into components. */
302 ret = parent_dirname(smb_fname,
303 smb_fname->base_name,
307 /* Must terminate debug with \n */
308 DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
309 return NT_STATUS_NO_MEMORY;
313 if (last_component[0] == '\0') {
314 newstr = talloc_strdup(smb_fname,
317 newstr = talloc_asprintf(smb_fname,
323 newstr = talloc_asprintf(smb_fname,
331 TALLOC_FREE(smb_fname->base_name);
332 smb_fname->base_name = newstr;
334 DBG_DEBUG("|%s|\n", newstr);
340 * Canonicalize any incoming pathname potentially containining
341 * a @GMT-token into a path that looks like:
343 * @GMT-YYYY-MM-DD-HH-MM-SS/path/name/components/last_component
345 * Leaves single path @GMT-token -component alone:
347 * @GMT-YYYY-MM-DD-HH-MM-SS -> @GMT-YYYY-MM-DD-HH-MM-SS
349 * Eventually when struct smb_filename is updated and the VFS
350 * ABI is changed this will remove the @GMT-YYYY-MM-DD-HH-MM-SS
351 * and store in the struct smb_filename as a struct timeval field
355 static NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname)
357 char *startp = strchr_m(smb_fname->base_name, '@');
361 if (startp == NULL) {
366 startp = strstr_m(startp, "@GMT-");
367 if (startp == NULL) {
372 if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
373 /* the GMT-token does not start a path-component */
377 endp = strptime(startp, GMT_FORMAT, &tm);
379 /* Not a valid timestring. */
383 if ( endp[0] == '\0') {
384 return rearrange_snapshot_path(smb_fname,
389 if (endp[0] != '/') {
391 * It is not a complete path component, i.e. the path
392 * component continues after the gmt-token.
397 return rearrange_snapshot_path(smb_fname,
402 /****************************************************************************
403 This routine is called to convert names from the dos namespace to unix
404 namespace. It needs to handle any case conversions, mangling, format changes,
407 We assume that we have already done a chdir() to the right "root" directory
410 The function will return an NTSTATUS error if some part of the name except for
411 the last part cannot be resolved, else NT_STATUS_OK.
413 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
414 didn't get any fatal errors that should immediately terminate the calling SMB
415 processing whilst resolving.
417 If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
418 of the pathname is set in smb_filename->original_lcomp.
420 If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected
421 and should be allowed in the last component of the path only.
423 If the orig_path was a stream, smb_filename->base_name will point to the base
424 filename, and smb_filename->stream_name will point to the stream name. If
425 orig_path was not a stream, then smb_filename->stream_name will be NULL.
427 On exit from unix_convert, the smb_filename->st stat struct will be populated
428 if the file exists and was found, if not this stat struct will be filled with
429 zeros (and this can be detected by checking for nlinks = 0, which can never be
431 ****************************************************************************/
433 NTSTATUS unix_convert(TALLOC_CTX *ctx,
434 connection_struct *conn,
435 const char *orig_path,
436 struct smb_filename **smb_fname_out,
439 struct smb_filename *smb_fname = NULL;
442 * This looks strange. But we need "start" initialized to "" here but
443 * it can't be a const char *, so 'char *start = "";' does not work.
446 char *start = &cnull;
449 char *dirpath = NULL;
451 bool component_was_mangled = False;
452 bool name_has_wildcard = False;
453 bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
454 bool allow_wcard_last_component =
455 (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
456 bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
457 bool snapshot_path = (ucf_flags & UCF_GMT_PATHNAME);
461 *smb_fname_out = NULL;
463 smb_fname = talloc_zero(ctx, struct smb_filename);
464 if (smb_fname == NULL) {
465 return NT_STATUS_NO_MEMORY;
469 /* we don't ever use the filenames on a printer share as a
470 filename - so don't convert them */
471 if (!(smb_fname->base_name = talloc_strdup(smb_fname,
473 status = NT_STATUS_NO_MEMORY;
479 smb_fname->flags = posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
481 DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
484 * Conversion to basic unix format is already done in
485 * check_path_syntax().
489 * Names must be relative to the root of the service - any leading /.
490 * and trailing /'s should have been trimmed by check_path_syntax().
494 SMB_ASSERT(*orig_path != '/');
498 * If we trimmed down to a single '\0' character
499 * then we should use the "." directory to avoid
500 * searching the cache, but not if we are in a
502 * As we know this is valid we can return true here.
506 if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) {
507 status = NT_STATUS_NO_MEMORY;
510 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
511 status = map_nt_error_from_unix(errno);
514 DEBUG(5, ("conversion finished \"\" -> %s\n",
515 smb_fname->base_name));
519 if (orig_path[0] == '.' && (orig_path[1] == '/' ||
520 orig_path[1] == '\0')) {
521 /* Start of pathname can't be "." only. */
522 if (orig_path[1] == '\0' || orig_path[2] == '\0') {
523 status = NT_STATUS_OBJECT_NAME_INVALID;
525 status =determine_path_error(&orig_path[2],
526 allow_wcard_last_component,
532 /* Start with the full orig_path as given by the caller. */
533 if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) {
534 DEBUG(0, ("talloc_strdup failed\n"));
535 status = NT_STATUS_NO_MEMORY;
539 /* Canonicalize any @GMT- paths. */
541 status = canonicalize_snapshot_path(smb_fname);
542 if (!NT_STATUS_IS_OK(status)) {
548 * Large directory fix normalization. If we're case sensitive, and
549 * the case preserving parameters are set to "no", normalize the case of
550 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
551 * This is in conflict with the current (3.0.20) man page, but is
552 * what people expect from the "large directory howto". I'll update
553 * the man page. Thanks to jht@samba.org for finding this. JRA.
556 if (conn->case_sensitive && !conn->case_preserve &&
557 !conn->short_case_preserve) {
558 if (!strnorm(smb_fname->base_name, lp_default_case(SNUM(conn)))) {
559 DEBUG(0, ("strnorm %s failed\n", smb_fname->base_name));
560 status = NT_STATUS_INVALID_PARAMETER;
566 * Ensure saved_last_component is valid even if file exists.
569 if(save_last_component) {
570 end = strrchr_m(smb_fname->base_name, '/');
572 smb_fname->original_lcomp = talloc_strdup(smb_fname,
575 smb_fname->original_lcomp =
576 talloc_strdup(smb_fname, smb_fname->base_name);
578 if (smb_fname->original_lcomp == NULL) {
579 status = NT_STATUS_NO_MEMORY;
585 * Strip off the stream, and add it back when we're done with the
588 if (!posix_pathnames) {
589 stream = strchr_m(smb_fname->base_name, ':');
591 if (stream != NULL) {
592 char *tmp = talloc_strdup(smb_fname, stream);
594 status = NT_STATUS_NO_MEMORY;
598 * Since this is actually pointing into
599 * smb_fname->base_name this truncates base_name.
604 if (smb_fname->base_name[0] == '\0') {
606 * orig_name was just a stream name.
607 * This is a stream on the root of
608 * the share. Replace base_name with
611 smb_fname->base_name =
612 talloc_strdup(smb_fname, ".");
613 if (smb_fname->base_name == NULL) {
614 status = NT_STATUS_NO_MEMORY;
617 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
618 status = map_nt_error_from_unix(errno);
621 /* dirpath must exist. */
622 dirpath = talloc_strdup(ctx,".");
623 if (dirpath == NULL) {
624 status = NT_STATUS_NO_MEMORY;
627 DEBUG(5, ("conversion finished %s -> %s\n",
629 smb_fname->base_name));
635 start = smb_fname->base_name;
638 * If we're providing case insensitive semantics or
639 * the underlying filesystem is case insensitive,
640 * then a case-normalized hit in the stat-cache is
641 * authoratitive. JRA.
643 * Note: We're only checking base_name. The stream_name will be
644 * added and verified in build_stream_path().
647 if((!conn->case_sensitive || !(conn->fs_capabilities &
648 FILE_CASE_SENSITIVE_SEARCH)) &&
649 stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start,
655 * Make sure "dirpath" is an allocated string, we use this for
656 * building the directories with talloc_asprintf and free it.
659 if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,".")))) {
660 DEBUG(0, ("talloc_strdup failed\n"));
661 status = NT_STATUS_NO_MEMORY;
666 * If we have a wildcard we must walk the path to
667 * find where the error is, even if case sensitive
671 if (!posix_pathnames) {
672 /* POSIX pathnames have no wildcards. */
673 name_has_wildcard = ms_has_wild(smb_fname->base_name);
674 if (name_has_wildcard && !allow_wcard_last_component) {
675 /* Wildcard not valid anywhere. */
676 status = NT_STATUS_OBJECT_NAME_INVALID;
681 DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
682 smb_fname->base_name, dirpath, start));
684 if (!name_has_wildcard) {
686 * stat the name - if it exists then we can add the stream back (if
687 * there was one) and be done!
690 if (posix_pathnames) {
691 ret = SMB_VFS_LSTAT(conn, smb_fname);
693 ret = SMB_VFS_STAT(conn, smb_fname);
697 status = check_for_dot_component(smb_fname);
698 if (!NT_STATUS_IS_OK(status)) {
701 /* Add the path (not including the stream) to the cache. */
702 stat_cache_add(orig_path, smb_fname->base_name,
703 conn->case_sensitive);
704 DEBUG(5,("conversion of base_name finished %s -> %s\n",
705 orig_path, smb_fname->base_name));
709 /* Stat failed - ensure we don't use it. */
710 SET_STAT_INVALID(smb_fname->st);
712 if (errno == ENOENT) {
713 /* Optimization when creating a new file - only
714 the last component doesn't exist.
715 NOTE : check_parent_exists() doesn't preserve errno.
717 int saved_errno = errno;
718 status = check_parent_exists(ctx,
725 if (!NT_STATUS_IS_OK(status)) {
731 * A special case - if we don't have any wildcards or mangling chars and are case
732 * sensitive or the underlying filesystem is case insensitive then searching
736 if ((conn->case_sensitive || !(conn->fs_capabilities &
737 FILE_CASE_SENSITIVE_SEARCH)) &&
738 !mangle_is_mangled(smb_fname->base_name, conn->params)) {
740 status = check_for_dot_component(smb_fname);
741 if (!NT_STATUS_IS_OK(status)) {
746 * The stat failed. Could be ok as it could be
750 if (errno == ENOTDIR || errno == ELOOP) {
751 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
753 } else if (errno == ENOENT) {
755 * Was it a missing last component ?
756 * or a missing intermediate component ?
758 struct smb_filename parent_fname;
759 const char *last_component = NULL;
761 ZERO_STRUCT(parent_fname);
762 if (!parent_dirname(ctx, smb_fname->base_name,
763 &parent_fname.base_name,
765 status = NT_STATUS_NO_MEMORY;
768 if (posix_pathnames) {
769 ret = SMB_VFS_LSTAT(conn, &parent_fname);
771 ret = SMB_VFS_STAT(conn, &parent_fname);
774 if (errno == ENOTDIR ||
777 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
783 * Missing last component is ok - new file.
784 * Also deal with permission denied elsewhere.
785 * Just drop out to done.
792 * We have a wildcard in the pathname.
794 * Optimization for common case where the wildcard
795 * is in the last component and the client already
796 * sent the correct case.
797 * NOTE : check_parent_exists() doesn't preserve errno.
799 int saved_errno = errno;
800 status = check_parent_exists(ctx,
807 if (!NT_STATUS_IS_OK(status)) {
813 * is_mangled() was changed to look at an entire pathname, not
814 * just a component. JRA.
817 if (mangle_is_mangled(start, conn->params)) {
818 component_was_mangled = True;
822 * Now we need to recursively match the name against the real
823 * directory structure.
827 * Match each part of the path name separately, trying the names
828 * as is first, then trying to scan the directory for matching names.
831 for (; start ; start = (end?end+1:(char *)NULL)) {
833 * Pinpoint the end of this section of the filename.
835 /* mb safe. '/' can't be in any encoded char. */
836 end = strchr(start, '/');
839 * Chop the name at this point.
845 if (save_last_component) {
846 TALLOC_FREE(smb_fname->original_lcomp);
847 smb_fname->original_lcomp = talloc_strdup(smb_fname,
848 end ? end + 1 : start);
849 if (!smb_fname->original_lcomp) {
850 DEBUG(0, ("talloc failed\n"));
851 status = NT_STATUS_NO_MEMORY;
856 /* The name cannot have a component of "." */
860 /* Error code at the end of a pathname. */
861 status = NT_STATUS_OBJECT_NAME_INVALID;
863 status = determine_path_error(end+1,
864 allow_wcard_last_component,
870 /* The name cannot have a wildcard if it's not
871 the last component. */
873 if (!posix_pathnames) {
874 name_has_wildcard = ms_has_wild(start);
877 /* Wildcards never valid within a pathname. */
878 if (name_has_wildcard && end) {
879 status = NT_STATUS_OBJECT_NAME_INVALID;
883 /* Skip the stat call if it's a wildcard end. */
884 if (name_has_wildcard) {
885 DEBUG(5,("Wildcard %s\n",start));
890 * Check if the name exists up to this point.
893 if (posix_pathnames) {
894 ret = SMB_VFS_LSTAT(conn, smb_fname);
896 ret = SMB_VFS_STAT(conn, smb_fname);
901 * It exists. it must either be a directory or this must
902 * be the last part of the path for it to be OK.
904 if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) {
906 * An intermediate part of the name isn't
909 DEBUG(5,("Not a dir %s\n",start));
912 * We need to return the fact that the
913 * intermediate name resolution failed. This
914 * is used to return an error of ERRbadpath
915 * rather than ERRbadfile. Some Windows
916 * applications depend on the difference between
919 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
924 char *found_name = NULL;
926 /* Stat failed - ensure we don't use it. */
927 SET_STAT_INVALID(smb_fname->st);
930 * Reset errno so we can detect
931 * directory open errors.
936 * Try to find this part of the path in the directory.
939 if (name_has_wildcard ||
940 (get_real_filename(conn, dirpath, start,
942 &found_name) == -1)) {
947 * An intermediate part of the name
950 DEBUG(5,("Intermediate not found %s\n",
955 * We need to return the fact that the
956 * intermediate name resolution failed.
957 * This is used to return an error of
958 * ERRbadpath rather than ERRbadfile.
959 * Some Windows applications depend on
960 * the difference between these two
965 * ENOENT, ENOTDIR and ELOOP all map
966 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
967 * in the filename walk.
970 if (errno == ENOENT ||
974 NT_STATUS_OBJECT_PATH_NOT_FOUND;
978 map_nt_error_from_unix(errno);
984 * ENOENT/EACCESS are the only valid errors
988 if (errno == EACCES) {
989 if ((ucf_flags & UCF_PREP_CREATEFILE) == 0) {
990 status = NT_STATUS_ACCESS_DENIED;
994 * This is the dropbox
995 * behaviour. A dropbox is a
996 * directory with only -wx
998 * get_real_filename fails
999 * with EACCESS, it needs to
1000 * list the directory. We
1001 * nevertheless want to allow
1002 * users creating a file.
1008 if ((errno != 0) && (errno != ENOENT)) {
1010 * ENOTDIR and ELOOP both map to
1011 * NT_STATUS_OBJECT_PATH_NOT_FOUND
1012 * in the filename walk.
1014 if (errno == ENOTDIR ||
1017 NT_STATUS_OBJECT_PATH_NOT_FOUND;
1020 map_nt_error_from_unix(errno);
1026 * Just the last part of the name doesn't exist.
1027 * We need to strupper() or strlower() it as
1028 * this conversion may be used for file creation
1029 * purposes. Fix inspired by
1030 * Thomas Neumann <t.neumann@iku-ag.de>.
1032 if (!conn->case_preserve ||
1033 (mangle_is_8_3(start, False,
1035 !conn->short_case_preserve)) {
1037 lp_default_case(SNUM(conn)))) {
1038 DEBUG(0, ("strnorm %s failed\n",
1040 status = NT_STATUS_INVALID_PARAMETER;
1046 * check on the mangled stack to see if we can
1047 * recover the base of the filename.
1050 if (mangle_is_mangled(start, conn->params)
1051 && mangle_lookup_name_from_8_3(ctx,
1057 start - smb_fname->base_name;
1059 if (!ISDOT(dirpath)) {
1060 tmp = talloc_asprintf(
1062 dirpath, unmangled);
1063 TALLOC_FREE(unmangled);
1069 DEBUG(0, ("talloc failed\n"));
1070 status = NT_STATUS_NO_MEMORY;
1073 TALLOC_FREE(smb_fname->base_name);
1074 smb_fname->base_name = tmp;
1076 smb_fname->base_name + start_ofs;
1077 end = start + strlen(start);
1080 DEBUG(5,("New file %s\n",start));
1086 * Restore the rest of the string. If the string was
1087 * mangled the size may have changed.
1092 start - smb_fname->base_name;
1094 if (!ISDOT(dirpath)) {
1095 tmp = talloc_asprintf(smb_fname,
1096 "%s/%s/%s", dirpath,
1100 tmp = talloc_asprintf(smb_fname,
1101 "%s/%s", found_name,
1105 DEBUG(0, ("talloc_asprintf failed\n"));
1106 status = NT_STATUS_NO_MEMORY;
1109 TALLOC_FREE(smb_fname->base_name);
1110 smb_fname->base_name = tmp;
1111 start = smb_fname->base_name + start_ofs;
1112 end = start + strlen(found_name);
1117 start - smb_fname->base_name;
1119 if (!ISDOT(dirpath)) {
1120 tmp = talloc_asprintf(smb_fname,
1124 tmp = talloc_strdup(smb_fname,
1128 DEBUG(0, ("talloc failed\n"));
1129 status = NT_STATUS_NO_MEMORY;
1132 TALLOC_FREE(smb_fname->base_name);
1133 smb_fname->base_name = tmp;
1134 start = smb_fname->base_name + start_ofs;
1137 * We just scanned for, and found the end of
1138 * the path. We must return a valid stat struct
1139 * if it exists. JRA.
1142 if (posix_pathnames) {
1143 ret = SMB_VFS_LSTAT(conn, smb_fname);
1145 ret = SMB_VFS_STAT(conn, smb_fname);
1149 SET_STAT_INVALID(smb_fname->st);
1153 TALLOC_FREE(found_name);
1157 * Add to the dirpath that we have resolved so far.
1160 if (!ISDOT(dirpath)) {
1161 char *tmp = talloc_asprintf(ctx,
1162 "%s/%s", dirpath, start);
1164 DEBUG(0, ("talloc_asprintf failed\n"));
1165 status = NT_STATUS_NO_MEMORY;
1168 TALLOC_FREE(dirpath);
1172 TALLOC_FREE(dirpath);
1173 if (!(dirpath = talloc_strdup(ctx,start))) {
1174 DEBUG(0, ("talloc_strdup failed\n"));
1175 status = NT_STATUS_NO_MEMORY;
1181 * Cache the dirpath thus far. Don't cache a name with mangled
1182 * or wildcard components as this can change the size.
1184 if(!component_was_mangled && !name_has_wildcard) {
1185 stat_cache_add(orig_path, dirpath,
1186 conn->case_sensitive);
1190 * Restore the / that we wiped out earlier.
1198 * Cache the full path. Don't cache a name with mangled or wildcard
1199 * components as this can change the size.
1202 if(!component_was_mangled && !name_has_wildcard) {
1203 stat_cache_add(orig_path, smb_fname->base_name,
1204 conn->case_sensitive);
1208 * The name has been resolved.
1211 DEBUG(5,("conversion finished %s -> %s\n", orig_path,
1212 smb_fname->base_name));
1215 /* Add back the stream if one was stripped off originally. */
1216 if (stream != NULL) {
1217 smb_fname->stream_name = stream;
1219 /* Check path now that the base_name has been converted. */
1220 status = build_stream_path(ctx, conn, smb_fname);
1221 if (!NT_STATUS_IS_OK(status)) {
1225 TALLOC_FREE(dirpath);
1226 *smb_fname_out = smb_fname;
1227 return NT_STATUS_OK;
1229 DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
1230 if (dirpath && !ISDOT(dirpath)) {
1231 smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s",
1234 smb_fname->base_name = talloc_strdup(smb_fname, start);
1236 if (!smb_fname->base_name) {
1237 DEBUG(0, ("talloc_asprintf failed\n"));
1238 status = NT_STATUS_NO_MEMORY;
1242 *smb_fname_out = smb_fname;
1243 TALLOC_FREE(dirpath);
1246 TALLOC_FREE(smb_fname);
1250 /****************************************************************************
1251 Ensure a path is not vetoed.
1252 ****************************************************************************/
1254 static NTSTATUS check_veto_path(connection_struct *conn,
1255 const struct smb_filename *smb_fname)
1257 const char *name = smb_fname->base_name;
1259 if (IS_VETO_PATH(conn, name)) {
1260 /* Is it not dot or dot dot. */
1261 if (!(ISDOT(name) || ISDOTDOT(name))) {
1262 DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1264 return map_nt_error_from_unix(ENOENT);
1267 return NT_STATUS_OK;
1270 /****************************************************************************
1271 Check a filename - possibly calling check_reduced_name.
1272 This is called by every routine before it allows an operation on a filename.
1273 It does any final confirmation necessary to ensure that the filename is
1274 a valid one for the user to access.
1275 ****************************************************************************/
1277 NTSTATUS check_name(connection_struct *conn,
1278 const struct smb_filename *smb_fname)
1280 NTSTATUS status = check_veto_path(conn, smb_fname);
1282 if (!NT_STATUS_IS_OK(status)) {
1286 if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1287 status = check_reduced_name(conn, NULL, smb_fname);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 DEBUG(5,("check_name: name %s failed with %s\n",
1290 smb_fname->base_name,
1291 nt_errstr(status)));
1296 return NT_STATUS_OK;
1299 /****************************************************************************
1300 Must be called as root. Creates the struct privilege_paths
1301 attached to the struct smb_request if this call is successful.
1302 ****************************************************************************/
1304 static NTSTATUS check_name_with_privilege(connection_struct *conn,
1305 struct smb_request *smbreq,
1306 const struct smb_filename *smb_fname)
1308 NTSTATUS status = check_veto_path(conn, smb_fname);
1310 if (!NT_STATUS_IS_OK(status)) {
1313 return check_reduced_name_with_privilege(conn,
1318 /****************************************************************************
1319 Check if two filenames are equal.
1320 This needs to be careful about whether we are case sensitive.
1321 ****************************************************************************/
1323 static bool fname_equal(const char *name1, const char *name2,
1324 bool case_sensitive)
1326 /* Normal filename handling */
1327 if (case_sensitive) {
1328 return(strcmp(name1,name2) == 0);
1331 return(strequal(name1,name2));
1334 /****************************************************************************
1335 Scan a directory to find a filename, matching without case sensitivity.
1336 If the name looks like a mangled name then try via the mangling functions
1337 ****************************************************************************/
1339 static int get_real_filename_full_scan(connection_struct *conn,
1340 const char *path, const char *name,
1342 TALLOC_CTX *mem_ctx, char **found_name)
1344 struct smb_Dir *cur_dir;
1345 const char *dname = NULL;
1346 char *talloced = NULL;
1347 char *unmangled_name = NULL;
1349 struct smb_filename *smb_fname = NULL;
1351 /* handle null paths */
1352 if ((path == NULL) || (*path == 0)) {
1356 /* If we have a case-sensitive filesystem, it doesn't do us any
1357 * good to search for a name. If a case variation of the name was
1358 * there, then the original stat(2) would have found it.
1360 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1366 * The incoming name can be mangled, and if we de-mangle it
1367 * here it will not compare correctly against the filename (name2)
1368 * read from the directory and then mangled by the name_to_8_3()
1369 * call. We need to mangle both names or neither.
1372 * Fix for bug found by Dina Fine. If in case sensitive mode then
1373 * the mangle cache is no good (3 letter extension could be wrong
1374 * case - so don't demangle in this case - leave as mangled and
1375 * allow the mangling of the directory entry read (which is done
1376 * case insensitively) to match instead. This will lead to more
1377 * false positive matches but we fail completely without it. JRA.
1380 if (mangled && !conn->case_sensitive) {
1381 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1385 /* Name is now unmangled. */
1386 name = unmangled_name;
1390 smb_fname = synthetic_smb_fname(talloc_tos(),
1395 if (smb_fname == NULL) {
1396 TALLOC_FREE(unmangled_name);
1400 /* open the directory */
1401 if (!(cur_dir = OpenDir(talloc_tos(), conn, smb_fname, NULL, 0))) {
1402 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1403 TALLOC_FREE(unmangled_name);
1404 TALLOC_FREE(smb_fname);
1408 TALLOC_FREE(smb_fname);
1410 /* now scan for matching names */
1412 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1414 /* Is it dot or dot dot. */
1415 if (ISDOT(dname) || ISDOTDOT(dname)) {
1416 TALLOC_FREE(talloced);
1421 * At this point dname is the unmangled name.
1422 * name is either mangled or not, depending on the state
1423 * of the "mangled" variable. JRA.
1427 * Check mangled name against mangled name, or unmangled name
1428 * against unmangled name.
1431 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1432 fname_equal(name, dname, conn->case_sensitive)) {
1433 /* we've found the file, change it's name and return */
1434 *found_name = talloc_strdup(mem_ctx, dname);
1435 TALLOC_FREE(unmangled_name);
1436 TALLOC_FREE(cur_dir);
1439 TALLOC_FREE(talloced);
1442 TALLOC_FREE(talloced);
1445 TALLOC_FREE(talloced);
1448 TALLOC_FREE(unmangled_name);
1449 TALLOC_FREE(cur_dir);
1454 /****************************************************************************
1455 Wrapper around the vfs get_real_filename and the full directory scan
1457 ****************************************************************************/
1459 int get_real_filename(connection_struct *conn, const char *path,
1460 const char *name, TALLOC_CTX *mem_ctx,
1466 /* handle null paths */
1467 if ((path == NULL) || (*path == 0)) {
1471 mangled = mangle_is_mangled(name, conn->params);
1474 return get_real_filename_full_scan(conn, path, name, mangled,
1475 mem_ctx, found_name);
1478 /* Try the vfs first to take advantage of case-insensitive stat. */
1479 ret = SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name);
1482 * If the case-insensitive stat was successful, or returned an error
1483 * other than EOPNOTSUPP then there is no need to fall back on the
1484 * full directory scan.
1486 if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1490 return get_real_filename_full_scan(conn, path, name, mangled, mem_ctx,
1494 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1495 connection_struct *conn,
1496 struct smb_filename *smb_fname)
1499 unsigned int i, num_streams = 0;
1500 struct stream_struct *streams = NULL;
1502 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1503 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1504 return NT_STATUS_OK;
1507 if (errno != ENOENT) {
1508 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1509 status = map_nt_error_from_unix(errno);
1513 /* Fall back to a case-insensitive scan of all streams on the file. */
1514 status = vfs_streaminfo(conn, NULL, smb_fname, mem_ctx,
1515 &num_streams, &streams);
1517 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1518 SET_STAT_INVALID(smb_fname->st);
1519 return NT_STATUS_OK;
1522 if (!NT_STATUS_IS_OK(status)) {
1523 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
1527 for (i=0; i<num_streams; i++) {
1528 DEBUG(10, ("comparing [%s] and [%s]: ",
1529 smb_fname->stream_name, streams[i].name));
1530 if (fname_equal(smb_fname->stream_name, streams[i].name,
1531 conn->case_sensitive)) {
1532 DEBUGADD(10, ("equal\n"));
1535 DEBUGADD(10, ("not equal\n"));
1538 /* Couldn't find the stream. */
1539 if (i == num_streams) {
1540 SET_STAT_INVALID(smb_fname->st);
1541 TALLOC_FREE(streams);
1542 return NT_STATUS_OK;
1545 DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1546 smb_fname->stream_name, streams[i].name));
1549 TALLOC_FREE(smb_fname->stream_name);
1550 smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1551 if (smb_fname->stream_name == NULL) {
1552 status = NT_STATUS_NO_MEMORY;
1556 SET_STAT_INVALID(smb_fname->st);
1558 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1559 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1561 status = NT_STATUS_OK;
1563 TALLOC_FREE(streams);
1568 * Go through all the steps to validate a filename.
1570 * @param ctx talloc_ctx to allocate memory with.
1571 * @param conn connection struct for vfs calls.
1572 * @param smbreq SMB request if we're using privileges.
1573 * @param name_in The unconverted name.
1574 * @param ucf_flags flags to pass through to unix_convert().
1575 * UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
1576 * p_cont_wcard != NULL and is true and
1577 * UCF_COND_ALLOW_WCARD_LCOMP.
1578 * @param p_cont_wcard If not NULL, will be set to true if the dfs path
1579 * resolution detects a wildcard.
1580 * @param pp_smb_fname The final converted name will be allocated if the
1581 * return is NT_STATUS_OK.
1583 * @return NT_STATUS_OK if all operations completed successfully, appropriate
1586 static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
1587 connection_struct *conn,
1588 struct smb_request *smbreq,
1589 const char *name_in,
1591 bool *ppath_contains_wcard,
1592 struct smb_filename **pp_smb_fname)
1596 *pp_smb_fname = NULL;
1598 if (ucf_flags & UCF_DFS_PATHNAME) {
1599 bool path_contains_wcard = false;
1601 status = resolve_dfspath_wcard(ctx, conn,
1604 !conn->sconn->using_smb2,
1606 &path_contains_wcard);
1607 if (!NT_STATUS_IS_OK(status)) {
1608 DEBUG(10,("filename_convert_internal: resolve_dfspath "
1609 "failed for name %s with %s\n",
1611 nt_errstr(status) ));
1615 if (ppath_contains_wcard != NULL && path_contains_wcard) {
1616 *ppath_contains_wcard = path_contains_wcard;
1618 ucf_flags &= ~UCF_DFS_PATHNAME;
1621 if (is_fake_file_path(name_in)) {
1625 *pp_smb_fname = synthetic_smb_fname_split(ctx,
1627 (ucf_flags & UCF_POSIX_PATHNAMES));
1628 if (*pp_smb_fname == NULL) {
1629 return NT_STATUS_NO_MEMORY;
1631 (*pp_smb_fname)->st = st;
1632 return NT_STATUS_OK;
1636 * If the caller conditionally allows wildcard lookups, only add the
1637 * always allow if the path actually does contain a wildcard.
1639 if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP &&
1640 ppath_contains_wcard != NULL && *ppath_contains_wcard) {
1641 ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
1644 status = unix_convert(ctx, conn, name_in, pp_smb_fname, ucf_flags);
1645 if (!NT_STATUS_IS_OK(status)) {
1646 DEBUG(10,("filename_convert_internal: unix_convert failed "
1647 "for name %s with %s\n",
1649 nt_errstr(status) ));
1653 if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) &&
1654 VALID_STAT((*pp_smb_fname)->st) &&
1655 S_ISLNK((*pp_smb_fname)->st.st_ex_mode)) {
1656 return check_veto_path(conn, (*pp_smb_fname));
1660 status = check_name(conn, (*pp_smb_fname));
1662 status = check_name_with_privilege(conn, smbreq,
1665 if (!NT_STATUS_IS_OK(status)) {
1666 DEBUG(3,("filename_convert_internal: check_name failed "
1667 "for name %s with %s\n",
1668 smb_fname_str_dbg(*pp_smb_fname),
1669 nt_errstr(status) ));
1670 TALLOC_FREE(*pp_smb_fname);
1678 * Go through all the steps to validate a filename.
1682 NTSTATUS filename_convert(TALLOC_CTX *ctx,
1683 connection_struct *conn,
1684 const char *name_in,
1686 bool *ppath_contains_wcard,
1687 struct smb_filename **pp_smb_fname)
1689 return filename_convert_internal(ctx,
1694 ppath_contains_wcard,
1699 * Go through all the steps to validate a filename.
1700 * root (privileged) version.
1703 NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
1704 connection_struct *conn,
1705 struct smb_request *smbreq,
1706 const char *name_in,
1708 bool *ppath_contains_wcard,
1709 struct smb_filename **pp_smb_fname)
1711 return filename_convert_internal(ctx,
1716 ppath_contains_wcard,