s3: smbd: Change filename_convert_smb1_search_path() to use extract_snapshot_token().
[Samba.git] / source3 / smbd / filename.c
blob6b6f70e1100f36dddf9438148935edd1e2d25a19
1 /*
2 Unix SMB/CIFS implementation.
3 filename handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1999-2007
6 Copyright (C) Ying Chen 2000
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * New hash table stat cache code added by Ying Chen.
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "fake_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "lib/util/memcache.h"
34 static NTSTATUS get_real_filename(connection_struct *conn,
35 struct smb_filename *path,
36 const char *name,
37 TALLOC_CTX *mem_ctx,
38 char **found_name);
40 static NTSTATUS check_name(connection_struct *conn,
41 const struct smb_filename *smb_fname);
43 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
45 uint32_t ucf_flags = 0;
47 if (req != NULL) {
48 if (req->posix_pathnames) {
49 ucf_flags |= UCF_POSIX_PATHNAMES;
51 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
52 ucf_flags |= UCF_DFS_PATHNAME;
54 if (req->flags2 & FLAGS2_REPARSE_PATH) {
55 ucf_flags |= UCF_GMT_PATHNAME;
59 return ucf_flags;
62 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
64 uint32_t ucf_flags = 0;
66 ucf_flags |= ucf_flags_from_smb_request(req);
68 switch (create_disposition) {
69 case FILE_OPEN:
70 case FILE_OVERWRITE:
71 break;
72 case FILE_SUPERSEDE:
73 case FILE_CREATE:
74 case FILE_OPEN_IF:
75 case FILE_OVERWRITE_IF:
76 ucf_flags |= UCF_PREP_CREATEFILE;
77 break;
80 return ucf_flags;
83 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
84 connection_struct *conn,
85 struct smb_filename *smb_fname);
87 /****************************************************************************
88 Mangle the 2nd name and check if it is then equal to the first name.
89 ****************************************************************************/
91 static bool mangled_equal(const char *name1,
92 const char *name2,
93 const struct share_params *p)
95 char mname[13];
97 if (!name_to_8_3(name2, mname, False, p)) {
98 return False;
100 return strequal(name1, mname);
103 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
105 /* Ensure we catch all names with in "/."
106 this is disallowed under Windows and
107 in POSIX they've already been removed. */
108 const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
109 if (p) {
110 if (p[2] == '/') {
111 /* Error code within a pathname. */
112 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
113 } else if (p[2] == '\0') {
114 /* Error code at the end of a pathname. */
115 return NT_STATUS_OBJECT_NAME_INVALID;
118 return NT_STATUS_OK;
121 /****************************************************************************
122 Optimization for common case where the missing part
123 is in the last component and the client already
124 sent the correct case.
125 Returns NT_STATUS_OK to mean continue the tree walk
126 (possibly with modified start pointer).
127 Any other NT_STATUS_XXX error means terminate the path
128 lookup here.
129 ****************************************************************************/
131 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
132 connection_struct *conn,
133 bool posix_pathnames,
134 const struct smb_filename *smb_fname,
135 char **pp_dirpath,
136 char **pp_start,
137 int *p_parent_stat_errno)
139 char *parent_name = NULL;
140 struct smb_filename *parent_fname = NULL;
141 const char *last_component = NULL;
142 NTSTATUS status;
143 int ret;
145 if (!parent_dirname(ctx, smb_fname->base_name,
146 &parent_name,
147 &last_component)) {
148 return NT_STATUS_NO_MEMORY;
151 if (!posix_pathnames) {
152 if (ms_has_wild(parent_name)) {
153 goto no_optimization_out;
158 * If there was no parent component in
159 * smb_fname->base_name then don't do this
160 * optimization.
162 if (smb_fname->base_name == last_component) {
163 goto no_optimization_out;
166 parent_fname = synthetic_smb_fname(ctx,
167 parent_name,
168 NULL,
169 NULL,
170 smb_fname->twrp,
171 smb_fname->flags);
172 if (parent_fname == NULL) {
173 return NT_STATUS_NO_MEMORY;
176 ret = vfs_stat(conn, parent_fname);
178 /* If the parent stat failed, just continue
179 with the normal tree walk. */
181 if (ret == -1) {
183 * Optimization. Preserving the
184 * errno from the STAT/LSTAT here
185 * will allow us to save a duplicate
186 * STAT/LSTAT system call of the parent
187 * pathname in a hot code path in the caller.
189 if (p_parent_stat_errno != NULL) {
190 *p_parent_stat_errno = errno;
192 goto no_optimization_out;
195 status = check_for_dot_component(parent_fname);
196 if (!NT_STATUS_IS_OK(status)) {
197 return status;
200 /* Parent exists - set "start" to be the
201 * last component to shorten the tree walk. */
204 * Safe to use discard_const_p
205 * here as last_component points
206 * into our smb_fname->base_name.
208 *pp_start = discard_const_p(char, last_component);
210 /* Update dirpath. */
211 TALLOC_FREE(*pp_dirpath);
212 *pp_dirpath = talloc_strdup(ctx, parent_fname->base_name);
213 if (!*pp_dirpath) {
214 return NT_STATUS_NO_MEMORY;
217 DEBUG(5,("check_parent_exists: name "
218 "= %s, dirpath = %s, "
219 "start = %s\n",
220 smb_fname->base_name,
221 *pp_dirpath,
222 *pp_start));
224 return NT_STATUS_OK;
226 no_optimization_out:
229 * We must still return an *pp_dirpath
230 * initialized to ".", and a *pp_start
231 * pointing at smb_fname->base_name.
234 TALLOC_FREE(parent_name);
235 TALLOC_FREE(parent_fname);
237 *pp_dirpath = talloc_strdup(ctx, ".");
238 if (*pp_dirpath == NULL) {
239 return NT_STATUS_NO_MEMORY;
242 * Safe to use discard_const_p
243 * here as by convention smb_fname->base_name
244 * is allocated off ctx.
246 *pp_start = discard_const_p(char, smb_fname->base_name);
247 return NT_STATUS_OK;
250 static bool find_snapshot_token(
251 const char *filename,
252 const char **_start,
253 const char **_next_component,
254 NTTIME *twrp)
256 const char *start = NULL;
257 const char *end = NULL;
258 struct tm tm;
259 time_t t;
261 start = strstr_m(filename, "@GMT-");
263 if (start == NULL) {
264 return false;
267 if ((start > filename) && (start[-1] != '/')) {
268 /* the GMT-token does not start a path-component */
269 return false;
272 end = strptime(start, GMT_FORMAT, &tm);
273 if (end == NULL) {
274 /* Not a valid timestring. */
275 return false;
278 if ((end[0] != '\0') && (end[0] != '/')) {
280 * It is not a complete path component, i.e. the path
281 * component continues after the gmt-token.
283 return false;
286 tm.tm_isdst = -1;
287 t = timegm(&tm);
288 unix_to_nt_time(twrp, t);
290 DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
291 nt_time_string(talloc_tos(), *twrp));
293 *_start = start;
295 if (end[0] == '/') {
296 end += 1;
298 *_next_component = end;
300 return true;
303 bool extract_snapshot_token(char *fname, uint32_t ucf_flags, NTTIME *twrp)
305 const char *start = NULL;
306 const char *next = NULL;
307 size_t remaining;
308 bool found;
309 bool posix_path = (ucf_flags & UCF_POSIX_PATHNAMES);
310 bool msdfs_path = (ucf_flags & UCF_DFS_PATHNAME);
312 if (msdfs_path && !posix_path) {
314 * A raw (non-POSIX) MSDFS path looks like \server\share\path.
315 * find_snapshot_token only looks for '/' separators.
316 * Convert the separator characters in place.
318 string_replace(fname, '\\', '/');
320 found = find_snapshot_token(fname, &start, &next, twrp);
321 if (msdfs_path && !posix_path) {
322 /* Put the original separators back. */
323 string_replace(fname, '/', '\\');
325 if (!found) {
326 return false;
329 remaining = strlen(next);
330 memmove(discard_const_p(char, start), next, remaining+1);
332 return true;
336 * Strip a valid @GMT-token from any incoming filename path,
337 * adding any NTTIME encoded in the pathname into the
338 * twrp field of the passed in smb_fname.
340 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
341 * at the *start* of a pathname component.
343 * If twrp is passed in then smb_fname->twrp is set to that
344 * value, and the @GMT-token part of the filename is removed
345 * and does not change the stored smb_fname->twrp.
349 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
350 uint32_t ucf_flags,
351 NTTIME twrp)
353 bool found;
355 if (twrp != 0) {
356 smb_fname->twrp = twrp;
359 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
360 return NT_STATUS_OK;
363 found = extract_snapshot_token(smb_fname->base_name, ucf_flags, &twrp);
364 if (!found) {
365 return NT_STATUS_OK;
368 if (smb_fname->twrp == 0) {
369 smb_fname->twrp = twrp;
372 return NT_STATUS_OK;
375 static bool strnorm(char *s, int case_default)
377 if (case_default == CASE_UPPER)
378 return strupper_m(s);
379 else
380 return strlower_m(s);
384 * Utility function to normalize case on an incoming client filename
385 * if required on this connection struct.
386 * Performs an in-place case conversion guaranteed to stay the same size.
389 static NTSTATUS normalize_filename_case(connection_struct *conn,
390 char *filename,
391 uint32_t ucf_flags)
393 bool ok;
395 if (ucf_flags & UCF_POSIX_PATHNAMES) {
397 * POSIX never normalizes filename case.
399 return NT_STATUS_OK;
401 if (!conn->case_sensitive) {
402 return NT_STATUS_OK;
404 if (conn->case_preserve) {
405 return NT_STATUS_OK;
407 if (conn->short_case_preserve) {
408 return NT_STATUS_OK;
410 ok = strnorm(filename, lp_default_case(SNUM(conn)));
411 if (!ok) {
412 return NT_STATUS_INVALID_PARAMETER;
414 return NT_STATUS_OK;
417 /****************************************************************************
418 This routine is called to convert names from the dos namespace to unix
419 namespace. It needs to handle any case conversions, mangling, format changes,
420 streams etc.
422 We assume that we have already done a chdir() to the right "root" directory
423 for this service.
425 Conversion to basic unix format is already done in check_path_syntax().
427 Names must be relative to the root of the service - any leading /. and
428 trailing /'s should have been trimmed by check_path_syntax().
430 The function will return an NTSTATUS error if some part of the name except for
431 the last part cannot be resolved, else NT_STATUS_OK.
433 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
434 didn't get any fatal errors that should immediately terminate the calling SMB
435 processing whilst resolving.
437 If the orig_path was a stream, smb_filename->base_name will point to the base
438 filename, and smb_filename->stream_name will point to the stream name. If
439 orig_path was not a stream, then smb_filename->stream_name will be NULL.
441 On exit from unix_convert, the smb_filename->st stat struct will be populated
442 if the file exists and was found, if not this stat struct will be filled with
443 zeros (and this can be detected by checking for nlinks = 0, which can never be
444 true for any file).
445 ****************************************************************************/
447 struct uc_state {
448 TALLOC_CTX *mem_ctx;
449 struct connection_struct *conn;
450 struct smb_filename *smb_fname;
451 const char *orig_path;
452 uint32_t ucf_flags;
453 char *name;
454 char *end;
455 char *dirpath;
456 char *stream;
457 bool component_was_mangled;
458 bool posix_pathnames;
459 bool done;
460 bool case_sensitive;
461 bool case_preserve;
462 bool short_case_preserve;
465 static NTSTATUS unix_convert_step_search_fail(
466 struct uc_state *state, NTSTATUS status)
468 char *unmangled;
470 if (state->end) {
472 * An intermediate part of the name
473 * can't be found.
475 DBG_DEBUG("Intermediate [%s] missing\n",
476 state->name);
477 *state->end = '/';
480 * We need to return the fact that the
481 * intermediate name resolution failed.
482 * This is used to return an error of
483 * ERRbadpath rather than ERRbadfile.
484 * Some Windows applications depend on
485 * the difference between these two
486 * errors.
490 * ENOENT, ENOTDIR and ELOOP all map
491 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
492 * in the filename walk.
494 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
495 NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
496 NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
497 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
499 return status;
503 * ENOENT/EACCESS are the only valid errors
504 * here.
507 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
508 if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
510 * Could be a symlink pointing to
511 * a directory outside the share
512 * to which we don't have access.
513 * If so, we need to know that here
514 * so we can return the correct error code.
515 * check_name() is never called if we
516 * error out of filename_convert().
518 int ret;
519 struct smb_filename dname = (struct smb_filename) {
520 .base_name = state->dirpath,
521 .twrp = state->smb_fname->twrp,
524 /* handle null paths */
525 if ((dname.base_name == NULL) ||
526 (dname.base_name[0] == '\0')) {
527 return NT_STATUS_ACCESS_DENIED;
529 ret = SMB_VFS_LSTAT(state->conn, &dname);
530 if (ret != 0) {
531 return NT_STATUS_ACCESS_DENIED;
533 if (!S_ISLNK(dname.st.st_ex_mode)) {
534 return NT_STATUS_ACCESS_DENIED;
536 status = check_name(state->conn, &dname);
537 if (!NT_STATUS_IS_OK(status)) {
538 /* We know this is an intermediate path. */
539 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
541 return NT_STATUS_ACCESS_DENIED;
542 } else {
544 * This is the dropbox
545 * behaviour. A dropbox is a
546 * directory with only -wx
547 * permissions, so
548 * get_real_filename fails
549 * with EACCESS, it needs to
550 * list the directory. We
551 * nevertheless want to allow
552 * users creating a file.
554 status = NT_STATUS_OK;
558 if (!NT_STATUS_IS_OK(status) &&
559 !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
561 * ENOTDIR and ELOOP both map to
562 * NT_STATUS_OBJECT_PATH_NOT_FOUND
563 * in the filename walk.
565 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY) ||
566 NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
567 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
569 return status;
573 * POSIX pathnames must never call into mangling.
575 if (state->posix_pathnames) {
576 goto done;
580 * Just the last part of the name doesn't exist.
581 * We need to strupper() or strlower() it as
582 * this conversion may be used for file creation
583 * purposes. Fix inspired by
584 * Thomas Neumann <t.neumann@iku-ag.de>.
586 if (!state->case_preserve ||
587 (mangle_is_8_3(state->name, false,
588 state->conn->params) &&
589 !state->short_case_preserve)) {
590 if (!strnorm(state->name,
591 lp_default_case(SNUM(state->conn)))) {
592 DBG_DEBUG("strnorm %s failed\n",
593 state->name);
594 return NT_STATUS_INVALID_PARAMETER;
599 * check on the mangled stack to see if we can
600 * recover the base of the filename.
603 if (mangle_is_mangled(state->name, state->conn->params)
604 && mangle_lookup_name_from_8_3(state->mem_ctx,
605 state->name,
606 &unmangled,
607 state->conn->params)) {
608 char *tmp;
609 size_t name_ofs =
610 state->name - state->smb_fname->base_name;
612 if (!ISDOT(state->dirpath)) {
613 tmp = talloc_asprintf(
614 state->smb_fname, "%s/%s",
615 state->dirpath, unmangled);
616 TALLOC_FREE(unmangled);
618 else {
619 tmp = unmangled;
621 if (tmp == NULL) {
622 DBG_ERR("talloc failed\n");
623 return NT_STATUS_NO_MEMORY;
625 TALLOC_FREE(state->smb_fname->base_name);
626 state->smb_fname->base_name = tmp;
627 state->name =
628 state->smb_fname->base_name + name_ofs;
629 state->end = state->name + strlen(state->name);
632 done:
634 DBG_DEBUG("New file [%s]\n", state->name);
635 state->done = true;
636 return NT_STATUS_OK;
639 static NTSTATUS unix_convert_step_stat(struct uc_state *state)
641 struct smb_filename dname;
642 char dot[2] = ".";
643 char *found_name = NULL;
644 int ret;
645 NTSTATUS status;
648 * Check if the name exists up to this point.
651 DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname));
653 ret = vfs_stat(state->conn, state->smb_fname);
654 if (ret == 0) {
656 * It exists. it must either be a directory or this must
657 * be the last part of the path for it to be OK.
659 if (state->end && !S_ISDIR(state->smb_fname->st.st_ex_mode)) {
661 * An intermediate part of the name isn't
662 * a directory.
664 DBG_DEBUG("Not a dir [%s]\n", state->name);
665 *state->end = '/';
667 * We need to return the fact that the
668 * intermediate name resolution failed. This
669 * is used to return an error of ERRbadpath
670 * rather than ERRbadfile. Some Windows
671 * applications depend on the difference between
672 * these two errors.
674 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
676 return NT_STATUS_OK;
679 /* Stat failed - ensure we don't use it. */
680 SET_STAT_INVALID(state->smb_fname->st);
682 if (state->posix_pathnames) {
684 * For posix_pathnames, we're done.
685 * Don't blunder into the
686 * get_real_filename() codepath as they may
687 * be doing case insensitive lookups. So when
688 * creating a new POSIX directory Foo they might
689 * match on name foo.
691 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13803
693 if (state->end != NULL) {
694 const char *morepath = NULL;
696 * If this is intermediate we must
697 * restore the full path.
699 *state->end = '/';
701 * If there are any more components
702 * after the failed LSTAT we cannot
703 * continue.
705 morepath = strchr(state->end + 1, '/');
706 if (morepath != NULL) {
707 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
710 if (errno == ENOENT) {
711 /* New file or directory. */
712 state->done = true;
713 return NT_STATUS_OK;
715 if ((errno == EACCES) &&
716 (state->ucf_flags & UCF_PREP_CREATEFILE)) {
717 /* POSIX Dropbox case. */
718 errno = 0;
719 state->done = true;
720 return NT_STATUS_OK;
722 return map_nt_error_from_unix(errno);
726 * Reset errno so we can detect
727 * directory open errors.
729 errno = 0;
732 * Try to find this part of the path in the directory.
735 dname = (struct smb_filename) {
736 .base_name = state->dirpath,
737 .twrp = state->smb_fname->twrp,
740 /* handle null paths */
741 if ((dname.base_name == NULL) || (dname.base_name[0] == '\0')) {
742 dname.base_name = dot;
745 status = get_real_filename(state->conn,
746 &dname,
747 state->name,
748 talloc_tos(),
749 &found_name);
750 if (!NT_STATUS_IS_OK(status)) {
751 return unix_convert_step_search_fail(state, status);
755 * Restore the rest of the string. If the string was
756 * mangled the size may have changed.
758 if (state->end) {
759 char *tmp;
760 size_t name_ofs =
761 state->name - state->smb_fname->base_name;
763 if (!ISDOT(state->dirpath)) {
764 tmp = talloc_asprintf(state->smb_fname,
765 "%s/%s/%s", state->dirpath,
766 found_name, state->end+1);
768 else {
769 tmp = talloc_asprintf(state->smb_fname,
770 "%s/%s", found_name,
771 state->end+1);
773 if (tmp == NULL) {
774 DBG_ERR("talloc_asprintf failed\n");
775 return NT_STATUS_NO_MEMORY;
777 TALLOC_FREE(state->smb_fname->base_name);
778 state->smb_fname->base_name = tmp;
779 state->name = state->smb_fname->base_name + name_ofs;
780 state->end = state->name + strlen(found_name);
781 *state->end = '\0';
782 } else {
783 char *tmp;
784 size_t name_ofs =
785 state->name - state->smb_fname->base_name;
787 if (!ISDOT(state->dirpath)) {
788 tmp = talloc_asprintf(state->smb_fname,
789 "%s/%s", state->dirpath,
790 found_name);
791 } else {
792 tmp = talloc_strdup(state->smb_fname,
793 found_name);
795 if (tmp == NULL) {
796 DBG_ERR("talloc failed\n");
797 return NT_STATUS_NO_MEMORY;
799 TALLOC_FREE(state->smb_fname->base_name);
800 state->smb_fname->base_name = tmp;
801 state->name = state->smb_fname->base_name + name_ofs;
804 * We just scanned for, and found the end of
805 * the path. We must return a valid stat struct
806 * if it exists. JRA.
809 ret = vfs_stat(state->conn, state->smb_fname);
810 if (ret != 0) {
811 SET_STAT_INVALID(state->smb_fname->st);
815 TALLOC_FREE(found_name);
816 return NT_STATUS_OK;
819 static NTSTATUS unix_convert_step(struct uc_state *state)
821 NTSTATUS status;
824 * Pinpoint the end of this section of the filename.
826 /* mb safe. '/' can't be in any encoded char. */
827 state->end = strchr(state->name, '/');
830 * Chop the name at this point.
832 if (state->end != NULL) {
833 *state->end = 0;
836 DBG_DEBUG("dirpath [%s] name [%s]\n", state->dirpath, state->name);
838 /* The name cannot have a component of "." */
840 if (ISDOT(state->name)) {
841 if (state->end == NULL) {
842 /* Error code at the end of a pathname. */
843 return NT_STATUS_OBJECT_NAME_INVALID;
845 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
848 status = unix_convert_step_stat(state);
849 if (!NT_STATUS_IS_OK(status)) {
850 return status;
852 if (state->done) {
853 return NT_STATUS_OK;
857 * Add to the dirpath that we have resolved so far.
860 if (!ISDOT(state->dirpath)) {
861 char *tmp = talloc_asprintf(state->mem_ctx,
862 "%s/%s", state->dirpath, state->name);
863 if (!tmp) {
864 DBG_ERR("talloc_asprintf failed\n");
865 return NT_STATUS_NO_MEMORY;
867 TALLOC_FREE(state->dirpath);
868 state->dirpath = tmp;
870 else {
871 TALLOC_FREE(state->dirpath);
872 if (!(state->dirpath = talloc_strdup(state->mem_ctx,state->name))) {
873 DBG_ERR("talloc_strdup failed\n");
874 return NT_STATUS_NO_MEMORY;
879 * Cache the dirpath thus far. Don't cache a name with mangled
880 * components as this can change the size.
882 if(!state->component_was_mangled) {
883 stat_cache_add(state->orig_path,
884 state->dirpath,
885 state->smb_fname->twrp,
886 state->case_sensitive);
890 * Restore the / that we wiped out earlier.
892 if (state->end != NULL) {
893 *state->end = '/';
896 return NT_STATUS_OK;
899 NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
900 connection_struct *conn,
901 const char *orig_path,
902 NTTIME twrp,
903 struct smb_filename **smb_fname_out,
904 uint32_t ucf_flags)
906 struct uc_state uc_state;
907 struct uc_state *state = &uc_state;
908 NTSTATUS status;
909 int ret = -1;
910 int parent_stat_errno = 0;
912 *state = (struct uc_state) {
913 .mem_ctx = mem_ctx,
914 .conn = conn,
915 .orig_path = orig_path,
916 .ucf_flags = ucf_flags,
917 .posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES),
918 .case_sensitive = conn->case_sensitive,
919 .case_preserve = conn->case_preserve,
920 .short_case_preserve = conn->short_case_preserve,
923 *smb_fname_out = NULL;
925 if (state->posix_pathnames) {
926 /* POSIX means ignore case settings on share. */
927 state->case_sensitive = true;
928 state->case_preserve = true;
929 state->short_case_preserve = true;
932 state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename);
933 if (state->smb_fname == NULL) {
934 return NT_STATUS_NO_MEMORY;
937 if (state->conn->printer) {
938 /* we don't ever use the filenames on a printer share as a
939 filename - so don't convert them */
940 state->smb_fname->base_name = talloc_strdup(
941 state->smb_fname, state->orig_path);
942 if (state->smb_fname->base_name == NULL) {
943 status = NT_STATUS_NO_MEMORY;
944 goto err;
946 goto done;
949 state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
951 DBG_DEBUG("Called on file [%s]\n", state->orig_path);
953 if (state->orig_path[0] == '/') {
954 DBG_ERR("Path [%s] starts with '/'\n", state->orig_path);
955 return NT_STATUS_OBJECT_NAME_INVALID;
958 /* Start with the full orig_path as given by the caller. */
959 state->smb_fname->base_name = talloc_strdup(
960 state->smb_fname, state->orig_path);
961 if (state->smb_fname->base_name == NULL) {
962 DBG_ERR("talloc_strdup failed\n");
963 status = NT_STATUS_NO_MEMORY;
964 goto err;
967 /* Canonicalize any @GMT- paths. */
968 status = canonicalize_snapshot_path(state->smb_fname, ucf_flags, twrp);
969 if (!NT_STATUS_IS_OK(status)) {
970 goto err;
974 * If we trimmed down to a single '\0' character
975 * then we should use the "." directory to avoid
976 * searching the cache, but not if we are in a
977 * printing share.
978 * As we know this is valid we can return true here.
981 if (state->smb_fname->base_name[0] == '\0') {
982 state->smb_fname->base_name = talloc_strdup(state->smb_fname, ".");
983 if (state->smb_fname->base_name == NULL) {
984 status = NT_STATUS_NO_MEMORY;
985 goto err;
987 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
988 status = map_nt_error_from_unix(errno);
989 goto err;
991 DBG_DEBUG("conversion finished [] -> [%s]\n",
992 state->smb_fname->base_name);
993 goto done;
996 if (state->orig_path[0] == '.' && (state->orig_path[1] == '/' ||
997 state->orig_path[1] == '\0')) {
998 /* Start of pathname can't be "." only. */
999 if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') {
1000 status = NT_STATUS_OBJECT_NAME_INVALID;
1001 } else {
1002 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1004 goto err;
1008 * Large directory fix normalization. If we're case sensitive, and
1009 * the case preserving parameters are set to "no", normalize the case of
1010 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
1011 * This is in conflict with the current (3.0.20) man page, but is
1012 * what people expect from the "large directory howto". I'll update
1013 * the man page. Thanks to jht@samba.org for finding this. JRA.
1016 status = normalize_filename_case(state->conn,
1017 state->smb_fname->base_name,
1018 ucf_flags);
1019 if (!NT_STATUS_IS_OK(status)) {
1020 DBG_ERR("normalize_filename_case %s failed\n",
1021 state->smb_fname->base_name);
1022 goto err;
1026 * Strip off the stream, and add it back when we're done with the
1027 * base_name.
1029 if (!state->posix_pathnames) {
1030 state->stream = strchr_m(state->smb_fname->base_name, ':');
1032 if (state->stream != NULL) {
1033 char *tmp = talloc_strdup(state->smb_fname, state->stream);
1034 if (tmp == NULL) {
1035 status = NT_STATUS_NO_MEMORY;
1036 goto err;
1039 * Since this is actually pointing into
1040 * smb_fname->base_name this truncates base_name.
1042 *state->stream = '\0';
1043 state->stream = tmp;
1045 if (state->smb_fname->base_name[0] == '\0') {
1047 * orig_name was just a stream name.
1048 * This is a stream on the root of
1049 * the share. Replace base_name with
1050 * a "."
1052 state->smb_fname->base_name =
1053 talloc_strdup(state->smb_fname, ".");
1054 if (state->smb_fname->base_name == NULL) {
1055 status = NT_STATUS_NO_MEMORY;
1056 goto err;
1058 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1059 status = map_nt_error_from_unix(errno);
1060 goto err;
1062 /* dirpath must exist. */
1063 state->dirpath = talloc_strdup(state->mem_ctx,".");
1064 if (state->dirpath == NULL) {
1065 status = NT_STATUS_NO_MEMORY;
1066 goto err;
1068 DBG_INFO("conversion finished [%s] -> [%s]\n",
1069 state->orig_path,
1070 state->smb_fname->base_name);
1071 goto done;
1076 state->name = state->smb_fname->base_name;
1079 * If we're providing case insensitive semantics or
1080 * the underlying filesystem is case insensitive,
1081 * then a case-normalized hit in the stat-cache is
1082 * authoritative. JRA.
1084 * Note: We're only checking base_name. The stream_name will be
1085 * added and verified in build_stream_path().
1088 if (!state->case_sensitive ||
1089 !(state->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
1091 bool found;
1093 found = stat_cache_lookup(state->conn,
1094 &state->smb_fname->base_name,
1095 &state->dirpath,
1096 &state->name,
1097 state->smb_fname->twrp,
1098 &state->smb_fname->st);
1100 * stat_cache_lookup() allocates on talloc_tos() even
1101 * when !found, reparent correctly
1103 talloc_steal(state->smb_fname, state->smb_fname->base_name);
1104 talloc_steal(state->mem_ctx, state->dirpath);
1106 if (found) {
1107 goto done;
1112 * Make sure "dirpath" is an allocated string, we use this for
1113 * building the directories with talloc_asprintf and free it.
1116 if (state->dirpath == NULL) {
1117 state->dirpath = talloc_strdup(state->mem_ctx,".");
1118 if (state->dirpath == NULL) {
1119 DBG_ERR("talloc_strdup failed\n");
1120 status = NT_STATUS_NO_MEMORY;
1121 goto err;
1126 * If we have a wildcard we must walk the path to
1127 * find where the error is, even if case sensitive
1128 * is true.
1131 if (!state->posix_pathnames) {
1132 /* POSIX pathnames have no wildcards. */
1133 bool name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
1134 if (name_has_wildcard) {
1135 /* Wildcard not valid anywhere. */
1136 status = NT_STATUS_OBJECT_NAME_INVALID;
1137 goto fail;
1141 DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
1142 state->smb_fname->base_name, state->dirpath, state->name);
1145 * stat the name - if it exists then we can add the stream back (if
1146 * there was one) and be done!
1149 ret = vfs_stat(state->conn, state->smb_fname);
1150 if (ret == 0) {
1151 status = check_for_dot_component(state->smb_fname);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 goto fail;
1155 /* Add the path (not including the stream) to the cache. */
1156 stat_cache_add(state->orig_path,
1157 state->smb_fname->base_name,
1158 state->smb_fname->twrp,
1159 state->case_sensitive);
1160 DBG_DEBUG("Conversion of base_name finished "
1161 "[%s] -> [%s]\n",
1162 state->orig_path, state->smb_fname->base_name);
1163 goto done;
1166 /* Stat failed - ensure we don't use it. */
1167 SET_STAT_INVALID(state->smb_fname->st);
1170 * Note: we must continue processing a path if we get EACCES
1171 * from stat. With NFS4 permissions the file might be lacking
1172 * READ_ATTR, but if the parent has LIST permissions we can
1173 * resolve the path in the path traversal loop down below.
1176 if (errno == ENOENT) {
1177 /* Optimization when creating a new file - only
1178 the last component doesn't exist.
1179 NOTE : check_parent_exists() doesn't preserve errno.
1181 int saved_errno = errno;
1182 status = check_parent_exists(state->mem_ctx,
1183 state->conn,
1184 state->posix_pathnames,
1185 state->smb_fname,
1186 &state->dirpath,
1187 &state->name,
1188 &parent_stat_errno);
1189 errno = saved_errno;
1190 if (!NT_STATUS_IS_OK(status)) {
1191 goto fail;
1196 * A special case - if we don't have any wildcards or mangling chars and are case
1197 * sensitive or the underlying filesystem is case insensitive then searching
1198 * won't help.
1200 * NB. As POSIX sets state->case_sensitive as
1201 * true we will never call into mangle_is_mangled() here.
1204 if ((state->case_sensitive || !(state->conn->fs_capabilities &
1205 FILE_CASE_SENSITIVE_SEARCH)) &&
1206 !mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
1208 status = check_for_dot_component(state->smb_fname);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 goto fail;
1214 * The stat failed. Could be ok as it could be
1215 * a new file.
1218 if (errno == ENOTDIR || errno == ELOOP) {
1219 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1220 goto fail;
1221 } else if (errno == ENOENT) {
1223 * Was it a missing last component ?
1224 * or a missing intermediate component ?
1226 * Optimization.
1228 * For this code path we can guarantee that
1229 * we have gone through check_parent_exists()
1230 * and it returned NT_STATUS_OK.
1232 * Either there was no parent component (".")
1233 * parent_stat_errno == 0 and we have a missing
1234 * last component here.
1236 * OR check_parent_exists() called STAT/LSTAT
1237 * and if it failed parent_stat_errno has been
1238 * set telling us if the parent existed or not.
1240 * Either way we can avoid another STAT/LSTAT
1241 * system call on the parent here.
1243 if (parent_stat_errno == ENOTDIR ||
1244 parent_stat_errno == ENOENT ||
1245 parent_stat_errno == ELOOP) {
1246 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1247 goto fail;
1251 * Missing last component is ok - new file.
1252 * Also deal with permission denied elsewhere.
1253 * Just drop out to done.
1255 goto done;
1260 * is_mangled() was changed to look at an entire pathname, not
1261 * just a component. JRA.
1264 if (state->posix_pathnames) {
1266 * POSIX names are never mangled and we must not
1267 * call into mangling functions.
1269 state->component_was_mangled = false;
1270 } else if (mangle_is_mangled(state->name, state->conn->params)) {
1271 state->component_was_mangled = true;
1275 * Now we need to recursively match the name against the real
1276 * directory structure.
1280 * Match each part of the path name separately, trying the names
1281 * as is first, then trying to scan the directory for matching names.
1284 for (; state->name ; state->name = (state->end ? state->end + 1:(char *)NULL)) {
1285 status = unix_convert_step(state);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
1288 goto err;
1290 goto fail;
1292 if (state->done) {
1293 goto done;
1298 * Cache the full path. Don't cache a name with mangled or wildcard
1299 * components as this can change the size.
1302 if(!state->component_was_mangled) {
1303 stat_cache_add(state->orig_path,
1304 state->smb_fname->base_name,
1305 state->smb_fname->twrp,
1306 state->case_sensitive);
1310 * The name has been resolved.
1313 done:
1314 /* Add back the stream if one was stripped off originally. */
1315 if (state->stream != NULL) {
1316 state->smb_fname->stream_name = state->stream;
1318 /* Check path now that the base_name has been converted. */
1319 status = build_stream_path(state->mem_ctx, state->conn, state->smb_fname);
1320 if (!NT_STATUS_IS_OK(status)) {
1321 goto fail;
1325 DBG_DEBUG("Conversion finished [%s] -> [%s]\n",
1326 state->orig_path, smb_fname_str_dbg(state->smb_fname));
1328 TALLOC_FREE(state->dirpath);
1329 *smb_fname_out = state->smb_fname;
1330 return NT_STATUS_OK;
1331 fail:
1332 DBG_DEBUG("Conversion failed: dirpath [%s] name [%s]\n",
1333 state->dirpath, state->name);
1334 if ((state->dirpath != NULL) && !ISDOT(state->dirpath)) {
1335 state->smb_fname->base_name = talloc_asprintf(
1336 state->smb_fname,
1337 "%s/%s",
1338 state->dirpath,
1339 state->name);
1340 } else {
1341 state->smb_fname->base_name = talloc_strdup(
1342 state->smb_fname, state->name);
1344 if (state->smb_fname->base_name == NULL) {
1345 DBG_ERR("talloc_asprintf failed\n");
1346 status = NT_STATUS_NO_MEMORY;
1347 goto err;
1350 *smb_fname_out = state->smb_fname;
1351 TALLOC_FREE(state->dirpath);
1352 return status;
1353 err:
1354 TALLOC_FREE(state->smb_fname);
1355 return status;
1358 /****************************************************************************
1359 Ensure a path is not vetoed.
1360 ****************************************************************************/
1362 static NTSTATUS check_veto_path(connection_struct *conn,
1363 const struct smb_filename *smb_fname)
1365 const char *name = smb_fname->base_name;
1367 if (IS_VETO_PATH(conn, name)) {
1368 /* Is it not dot or dot dot. */
1369 if (!(ISDOT(name) || ISDOTDOT(name))) {
1370 DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1371 name));
1372 return map_nt_error_from_unix(ENOENT);
1375 return NT_STATUS_OK;
1378 /****************************************************************************
1379 Check a filename - possibly calling check_reduced_name.
1380 This is called by every routine before it allows an operation on a filename.
1381 It does any final confirmation necessary to ensure that the filename is
1382 a valid one for the user to access.
1383 ****************************************************************************/
1385 static NTSTATUS check_name(connection_struct *conn,
1386 const struct smb_filename *smb_fname)
1388 NTSTATUS status = check_veto_path(conn, smb_fname);
1390 if (!NT_STATUS_IS_OK(status)) {
1391 return status;
1394 if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1395 status = check_reduced_name(conn, NULL, smb_fname);
1396 if (!NT_STATUS_IS_OK(status)) {
1397 DEBUG(5,("check_name: name %s failed with %s\n",
1398 smb_fname->base_name,
1399 nt_errstr(status)));
1400 return status;
1404 return NT_STATUS_OK;
1407 /****************************************************************************
1408 Check if two filenames are equal.
1409 This needs to be careful about whether we are case sensitive.
1410 ****************************************************************************/
1412 static bool fname_equal(const char *name1, const char *name2,
1413 bool case_sensitive)
1415 /* Normal filename handling */
1416 if (case_sensitive) {
1417 return(strcmp(name1,name2) == 0);
1420 return(strequal(name1,name2));
1423 static bool sname_equal(const char *name1, const char *name2,
1424 bool case_sensitive)
1426 bool match;
1427 const char *s1 = NULL;
1428 const char *s2 = NULL;
1429 size_t n1;
1430 size_t n2;
1431 const char *e1 = NULL;
1432 const char *e2 = NULL;
1433 char *c1 = NULL;
1434 char *c2 = NULL;
1436 match = fname_equal(name1, name2, case_sensitive);
1437 if (match) {
1438 return true;
1441 if (name1[0] != ':') {
1442 return false;
1444 if (name2[0] != ':') {
1445 return false;
1447 s1 = &name1[1];
1448 e1 = strchr(s1, ':');
1449 if (e1 == NULL) {
1450 n1 = strlen(s1);
1451 } else {
1452 n1 = PTR_DIFF(e1, s1);
1454 s2 = &name2[1];
1455 e2 = strchr(s2, ':');
1456 if (e2 == NULL) {
1457 n2 = strlen(s2);
1458 } else {
1459 n2 = PTR_DIFF(e2, s2);
1462 /* Normal filename handling */
1463 if (case_sensitive) {
1464 return (strncmp(s1, s2, n1) == 0);
1468 * We can't use strnequal() here
1469 * as it takes the number of codepoints
1470 * and not the number of bytes.
1472 * So we make a copy before calling
1473 * strequal().
1475 * Note that we TALLOC_FREE() in reverse order
1476 * in order to avoid memory fragmentation.
1479 c1 = talloc_strndup(talloc_tos(), s1, n1);
1480 c2 = talloc_strndup(talloc_tos(), s2, n2);
1481 if (c1 == NULL || c2 == NULL) {
1482 TALLOC_FREE(c2);
1483 TALLOC_FREE(c1);
1484 return (strncmp(s1, s2, n1) == 0);
1487 match = strequal(c1, c2);
1488 TALLOC_FREE(c2);
1489 TALLOC_FREE(c1);
1490 return match;
1493 /****************************************************************************
1494 Scan a directory to find a filename, matching without case sensitivity.
1495 If the name looks like a mangled name then try via the mangling functions
1496 ****************************************************************************/
1498 NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
1499 const char *name,
1500 bool mangled,
1501 TALLOC_CTX *mem_ctx,
1502 char **found_name)
1504 struct connection_struct *conn = dirfsp->conn;
1505 struct smb_Dir *cur_dir = NULL;
1506 const char *dname = NULL;
1507 char *talloced = NULL;
1508 char *unmangled_name = NULL;
1509 long curpos;
1510 NTSTATUS status;
1512 /* If we have a case-sensitive filesystem, it doesn't do us any
1513 * good to search for a name. If a case variation of the name was
1514 * there, then the original stat(2) would have found it.
1516 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1517 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1521 * The incoming name can be mangled, and if we de-mangle it
1522 * here it will not compare correctly against the filename (name2)
1523 * read from the directory and then mangled by the name_to_8_3()
1524 * call. We need to mangle both names or neither.
1525 * (JRA).
1527 * Fix for bug found by Dina Fine. If in case sensitive mode then
1528 * the mangle cache is no good (3 letter extension could be wrong
1529 * case - so don't demangle in this case - leave as mangled and
1530 * allow the mangling of the directory entry read (which is done
1531 * case insensitively) to match instead. This will lead to more
1532 * false positive matches but we fail completely without it. JRA.
1535 if (mangled && !conn->case_sensitive) {
1536 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1537 &unmangled_name,
1538 conn->params);
1539 if (!mangled) {
1540 /* Name is now unmangled. */
1541 name = unmangled_name;
1545 /* open the directory */
1546 status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
1547 if (!NT_STATUS_IS_OK(status)) {
1548 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
1549 fsp_str_dbg(dirfsp),
1550 nt_errstr(status));
1551 TALLOC_FREE(unmangled_name);
1552 return status;
1555 /* now scan for matching names */
1556 curpos = 0;
1557 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1559 /* Is it dot or dot dot. */
1560 if (ISDOT(dname) || ISDOTDOT(dname)) {
1561 TALLOC_FREE(talloced);
1562 continue;
1566 * At this point dname is the unmangled name.
1567 * name is either mangled or not, depending on the state
1568 * of the "mangled" variable. JRA.
1572 * Check mangled name against mangled name, or unmangled name
1573 * against unmangled name.
1576 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1577 fname_equal(name, dname, conn->case_sensitive)) {
1578 /* we've found the file, change it's name and return */
1579 *found_name = talloc_strdup(mem_ctx, dname);
1580 TALLOC_FREE(unmangled_name);
1581 TALLOC_FREE(cur_dir);
1582 if (!*found_name) {
1583 TALLOC_FREE(talloced);
1584 return NT_STATUS_NO_MEMORY;
1586 TALLOC_FREE(talloced);
1587 return NT_STATUS_OK;
1589 TALLOC_FREE(talloced);
1592 TALLOC_FREE(unmangled_name);
1593 TALLOC_FREE(cur_dir);
1594 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1597 NTSTATUS get_real_filename_full_scan(connection_struct *conn,
1598 const char *path,
1599 const char *name,
1600 bool mangled,
1601 TALLOC_CTX *mem_ctx,
1602 char **found_name)
1604 struct smb_filename *smb_dname = NULL;
1605 NTSTATUS status;
1607 /* handle null paths */
1608 if ((path == NULL) || (*path == 0)) {
1609 path = ".";
1612 status = synthetic_pathref(
1613 talloc_tos(),
1614 conn->cwd_fsp,
1615 path,
1616 NULL,
1617 NULL,
1620 &smb_dname);
1621 if (!NT_STATUS_IS_OK(status)) {
1622 return status;
1625 status = get_real_filename_full_scan_at(
1626 smb_dname->fsp, name, mangled, mem_ctx, found_name);
1628 TALLOC_FREE(smb_dname);
1629 return status;
1632 /****************************************************************************
1633 Wrapper around the vfs get_real_filename and the full directory scan
1634 fallback.
1635 ****************************************************************************/
1637 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
1638 const char *name,
1639 TALLOC_CTX *mem_ctx,
1640 char **found_name)
1642 struct connection_struct *conn = dirfsp->conn;
1643 NTSTATUS status;
1644 bool mangled;
1646 mangled = mangle_is_mangled(name, conn->params);
1648 if (mangled) {
1649 status = get_real_filename_full_scan_at(
1650 dirfsp, name, mangled, mem_ctx, found_name);
1651 return status;
1654 /* Try the vfs first to take advantage of case-insensitive stat. */
1655 status = SMB_VFS_GET_REAL_FILENAME_AT(
1656 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
1659 * If the case-insensitive stat was successful, or returned an error
1660 * other than EOPNOTSUPP then there is no need to fall back on the
1661 * full directory scan.
1663 if (NT_STATUS_IS_OK(status) ||
1664 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1665 return status;
1668 status = get_real_filename_full_scan_at(
1669 dirfsp, name, mangled, mem_ctx, found_name);
1670 return status;
1674 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
1675 * the stat cache for the last component to be looked up. Cache
1676 * contents is the correctly capitalized translation of the parameter
1677 * "name" as it exists on disk. This is indexed by inode of the dirfsp
1678 * and name, and contrary to stat_cahce_lookup() it does not
1679 * vfs_stat() the last component. This will be taken care of by an
1680 * attempt to do a openat_pathref_fsp().
1682 static bool get_real_filename_cache_key(
1683 TALLOC_CTX *mem_ctx,
1684 struct files_struct *dirfsp,
1685 const char *name,
1686 DATA_BLOB *_key)
1688 struct file_id fid = vfs_file_id_from_sbuf(
1689 dirfsp->conn, &dirfsp->fsp_name->st);
1690 char *upper = NULL;
1691 uint8_t *key = NULL;
1692 size_t namelen, keylen;
1694 upper = talloc_strdup_upper(mem_ctx, name);
1695 if (upper == NULL) {
1696 return false;
1698 namelen = talloc_get_size(upper);
1700 keylen = namelen + sizeof(fid);
1701 if (keylen < sizeof(fid)) {
1702 TALLOC_FREE(upper);
1703 return false;
1706 key = talloc_size(mem_ctx, keylen);
1707 if (key == NULL) {
1708 TALLOC_FREE(upper);
1709 return false;
1712 memcpy(key, &fid, sizeof(fid));
1713 memcpy(key + sizeof(fid), upper, namelen);
1714 TALLOC_FREE(upper);
1716 *_key = (DATA_BLOB) { .data = key, .length = keylen, };
1717 return true;
1720 static NTSTATUS get_real_filename(connection_struct *conn,
1721 struct smb_filename *path,
1722 const char *name,
1723 TALLOC_CTX *mem_ctx,
1724 char **found_name)
1726 struct smb_filename *smb_dname = NULL;
1727 NTSTATUS status;
1729 smb_dname = cp_smb_filename_nostream(talloc_tos(), path);
1730 if (smb_dname == NULL) {
1731 return NT_STATUS_NO_MEMORY;
1734 again:
1735 status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
1737 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1738 S_ISLNK(smb_dname->st.st_ex_mode)) {
1739 status = NT_STATUS_STOPPED_ON_SYMLINK;
1742 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1743 (smb_dname->twrp != 0)) {
1745 * Retry looking at the non-snapshot path, copying the
1746 * fallback mechanism from vfs_shadow_copy2.c when
1747 * shadow_copy2_convert() fails. This path-based
1748 * routine get_real_filename() should go away and be
1749 * replaced with a fd-based one, so spoiling it with a
1750 * shadow_copy2 specific mechanism should not be too
1751 * bad.
1753 smb_dname->twrp = 0;
1754 goto again;
1757 if (!NT_STATUS_IS_OK(status)) {
1758 DBG_DEBUG("openat_pathref_fsp(%s) failed: %s\n",
1759 smb_fname_str_dbg(smb_dname),
1760 nt_errstr(status));
1763 * ENOTDIR and ELOOP both map to
1764 * NT_STATUS_OBJECT_PATH_NOT_FOUND in the filename
1765 * walk.
1767 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY) ||
1768 NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1769 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1772 return status;
1775 status = get_real_filename_at(
1776 smb_dname->fsp, name, mem_ctx, found_name);
1777 TALLOC_FREE(smb_dname);
1778 return status;
1781 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1782 connection_struct *conn,
1783 struct smb_filename *smb_fname)
1785 NTSTATUS status;
1786 unsigned int i, num_streams = 0;
1787 struct stream_struct *streams = NULL;
1788 struct smb_filename *pathref = NULL;
1790 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1791 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1792 return NT_STATUS_OK;
1795 if (errno != ENOENT) {
1796 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1797 status = map_nt_error_from_unix(errno);
1798 goto fail;
1801 if (smb_fname->fsp == NULL) {
1802 status = synthetic_pathref(mem_ctx,
1803 conn->cwd_fsp,
1804 smb_fname->base_name,
1805 NULL,
1806 NULL,
1807 smb_fname->twrp,
1808 smb_fname->flags,
1809 &pathref);
1810 if (!NT_STATUS_IS_OK(status)) {
1811 if (NT_STATUS_EQUAL(status,
1812 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1813 TALLOC_FREE(pathref);
1814 SET_STAT_INVALID(smb_fname->st);
1815 return NT_STATUS_OK;
1817 DBG_DEBUG("synthetic_pathref failed: %s\n",
1818 nt_errstr(status));
1819 goto fail;
1821 } else {
1822 pathref = smb_fname;
1825 /* Fall back to a case-insensitive scan of all streams on the file. */
1826 status = vfs_fstreaminfo(pathref->fsp, mem_ctx,
1827 &num_streams, &streams);
1828 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1829 SET_STAT_INVALID(smb_fname->st);
1830 TALLOC_FREE(pathref);
1831 return NT_STATUS_OK;
1834 if (!NT_STATUS_IS_OK(status)) {
1835 DEBUG(10, ("vfs_fstreaminfo failed: %s\n", nt_errstr(status)));
1836 goto fail;
1839 for (i=0; i<num_streams; i++) {
1840 bool equal = sname_equal(
1841 smb_fname->stream_name,
1842 streams[i].name,
1843 conn->case_sensitive);
1845 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
1846 smb_fname->stream_name,
1847 streams[i].name,
1848 equal ? "" : "not ");
1850 if (equal) {
1851 break;
1855 /* Couldn't find the stream. */
1856 if (i == num_streams) {
1857 SET_STAT_INVALID(smb_fname->st);
1858 TALLOC_FREE(pathref);
1859 TALLOC_FREE(streams);
1860 return NT_STATUS_OK;
1863 DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1864 smb_fname->stream_name, streams[i].name));
1867 TALLOC_FREE(smb_fname->stream_name);
1868 smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1869 if (smb_fname->stream_name == NULL) {
1870 status = NT_STATUS_NO_MEMORY;
1871 goto fail;
1874 SET_STAT_INVALID(smb_fname->st);
1876 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1877 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1879 status = NT_STATUS_OK;
1880 fail:
1881 TALLOC_FREE(pathref);
1882 TALLOC_FREE(streams);
1883 return status;
1887 * Lightweight function to just get last component
1888 * for rename / enumerate directory calls.
1891 char *get_original_lcomp(TALLOC_CTX *ctx,
1892 connection_struct *conn,
1893 const char *filename_in,
1894 uint32_t ucf_flags)
1896 struct smb_filename *smb_fname = NULL;
1897 char *last_slash = NULL;
1898 char *orig_lcomp;
1899 char *fname = NULL;
1900 NTTIME twrp = 0;
1901 NTSTATUS status;
1903 if (ucf_flags & UCF_DFS_PATHNAME) {
1904 status = dfs_redirect(ctx,
1905 conn,
1906 filename_in,
1907 ucf_flags,
1908 !conn->sconn->using_smb2,
1909 &twrp,
1910 &fname);
1911 if (!NT_STATUS_IS_OK(status)) {
1912 DBG_DEBUG("dfs_redirect "
1913 "failed for name %s with %s\n",
1914 filename_in,
1915 nt_errstr(status));
1916 return NULL;
1918 filename_in = fname;
1919 ucf_flags &= ~UCF_DFS_PATHNAME;
1923 * NB. We don't need to care about
1924 * is_fake_file_path(filename_in) here as these
1925 * code paths don't ever return original_lcomp
1926 * or use it anyway.
1929 if (ucf_flags & UCF_GMT_PATHNAME) {
1931 * Ensure we don't return a @GMT
1932 * value as the last component.
1934 smb_fname = synthetic_smb_fname(ctx,
1935 filename_in,
1936 NULL,
1937 NULL,
1938 twrp,
1940 if (smb_fname == NULL) {
1941 TALLOC_FREE(fname);
1942 return NULL;
1944 status = canonicalize_snapshot_path(smb_fname,
1945 ucf_flags,
1946 twrp);
1947 if (!NT_STATUS_IS_OK(status)) {
1948 TALLOC_FREE(fname);
1949 TALLOC_FREE(smb_fname);
1950 return NULL;
1952 filename_in = smb_fname->base_name;
1954 last_slash = strrchr(filename_in, '/');
1955 if (last_slash != NULL) {
1956 orig_lcomp = talloc_strdup(ctx, last_slash+1);
1957 } else {
1958 orig_lcomp = talloc_strdup(ctx, filename_in);
1960 /* We're done with any temp names here. */
1961 TALLOC_FREE(smb_fname);
1962 TALLOC_FREE(fname);
1963 if (orig_lcomp == NULL) {
1964 return NULL;
1966 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
1967 if (!NT_STATUS_IS_OK(status)) {
1968 TALLOC_FREE(orig_lcomp);
1969 return NULL;
1971 return orig_lcomp;
1975 * Go through all the steps to validate a filename.
1977 * @param ctx talloc_ctx to allocate memory with.
1978 * @param conn connection struct for vfs calls.
1979 * @param smbreq SMB request if we're using privileges.
1980 * @param name_in The unconverted name.
1981 * @param ucf_flags flags to pass through to unix_convert().
1982 * @param twrp Optional VSS time
1983 * @param p_cont_wcard If not NULL, will be set to true if the dfs path
1984 * resolution detects a wildcard.
1985 * @param _smb_fname The final converted name will be allocated if the
1986 * return is NT_STATUS_OK.
1988 * @return NT_STATUS_OK if all operations completed successfully, appropriate
1989 * error otherwise.
1991 NTSTATUS filename_convert(TALLOC_CTX *ctx,
1992 connection_struct *conn,
1993 const char *name_in,
1994 uint32_t ucf_flags,
1995 NTTIME twrp,
1996 struct smb_filename **_smb_fname)
1998 struct smb_filename *smb_fname = NULL;
1999 NTSTATUS status;
2001 *_smb_fname = NULL;
2003 if (ucf_flags & UCF_DFS_PATHNAME) {
2004 char *fname = NULL;
2005 NTTIME dfs_twrp = 0;
2006 status = dfs_redirect(ctx, conn,
2007 name_in,
2008 ucf_flags,
2009 !conn->sconn->using_smb2,
2010 &dfs_twrp,
2011 &fname);
2012 if (!NT_STATUS_IS_OK(status)) {
2013 DBG_DEBUG("dfs_redirect "
2014 "failed for name %s with %s\n",
2015 name_in,
2016 nt_errstr(status));
2017 return status;
2019 name_in = fname;
2020 ucf_flags &= ~UCF_DFS_PATHNAME;
2021 if (twrp == 0 && dfs_twrp != 0) {
2022 twrp = dfs_twrp;
2026 if (is_fake_file_path(name_in)) {
2027 smb_fname = synthetic_smb_fname_split(ctx,
2028 name_in,
2029 (ucf_flags & UCF_POSIX_PATHNAMES));
2030 if (smb_fname == NULL) {
2031 return NT_STATUS_NO_MEMORY;
2033 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
2034 smb_fname->st.st_ex_btime = (struct timespec){0, SAMBA_UTIME_OMIT};
2035 smb_fname->st.st_ex_atime = (struct timespec){0, SAMBA_UTIME_OMIT};
2036 smb_fname->st.st_ex_mtime = (struct timespec){0, SAMBA_UTIME_OMIT};
2037 smb_fname->st.st_ex_ctime = (struct timespec){0, SAMBA_UTIME_OMIT};
2039 *_smb_fname = smb_fname;
2040 return NT_STATUS_OK;
2043 status = unix_convert(ctx, conn, name_in, twrp, &smb_fname, ucf_flags);
2044 if (!NT_STATUS_IS_OK(status)) {
2045 DBG_DEBUG("unix_convert failed "
2046 "for name %s with %s\n",
2047 name_in,
2048 nt_errstr(status));
2049 return status;
2052 if ((ucf_flags & UCF_POSIX_PATHNAMES) &&
2053 VALID_STAT(smb_fname->st) &&
2054 S_ISLNK(smb_fname->st.st_ex_mode))
2056 status = check_veto_path(conn, smb_fname);
2057 if (!NT_STATUS_IS_OK(status)) {
2058 TALLOC_FREE(smb_fname);
2059 return status;
2061 } else {
2062 status = check_name(conn, smb_fname);
2064 if (!NT_STATUS_IS_OK(status)) {
2065 DBG_NOTICE("check_name failed "
2066 "for name %s with %s\n",
2067 smb_fname_str_dbg(smb_fname),
2068 nt_errstr(status));
2069 TALLOC_FREE(smb_fname);
2070 return status;
2073 if (!VALID_STAT(smb_fname->st)) {
2074 DBG_DEBUG("[%s] does not exist, skipping pathref fsp\n",
2075 smb_fname_str_dbg(smb_fname));
2076 *_smb_fname = smb_fname;
2077 return NT_STATUS_OK;
2080 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
2081 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2083 * We deal with symlinks here as we do in
2084 * SMB_VFS_CREATE_FILE(): return success for POSIX clients with
2085 * the notable difference that there will be no fsp in
2086 * smb_fname->fsp.
2088 * For Windows (non POSIX) clients fail with
2089 * NT_STATUS_OBJECT_NAME_NOT_FOUND.
2091 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH &&
2092 S_ISLNK(smb_fname->st.st_ex_mode))
2094 status = NT_STATUS_OK;
2097 if (!NT_STATUS_IS_OK(status)) {
2098 DBG_DEBUG("openat_pathref_fsp [%s] failed: %s\n",
2099 smb_fname_str_dbg(smb_fname),
2100 nt_errstr(status));
2101 return status;
2104 *_smb_fname = smb_fname;
2105 return status;
2108 #if 0
2110 * Strip a @GMT component from an SMB1-DFS path. Could be anywhere
2111 * in the path.
2114 static char *strip_gmt_from_raw_dfs(TALLOC_CTX *ctx,
2115 const char *name_in,
2116 bool posix_pathnames,
2117 NTTIME *_twrp)
2119 NTSTATUS status;
2120 struct smb_filename *smb_fname = NULL;
2121 char *name_out = NULL;
2123 smb_fname = synthetic_smb_fname(ctx,
2124 name_in,
2125 NULL,
2126 NULL,
2129 if (smb_fname == NULL) {
2130 return NULL;
2132 if (!posix_pathnames) {
2134 * Raw DFS names are still '\\' separated.
2135 * canonicalize_snapshot_path() only works
2136 * on '/' separated paths. Convert.
2138 string_replace(smb_fname->base_name, '\\', '/');
2140 status = canonicalize_snapshot_path(smb_fname,
2141 UCF_GMT_PATHNAME,
2143 if (!NT_STATUS_IS_OK(status)) {
2144 TALLOC_FREE(smb_fname);
2145 return NULL;
2147 if (!posix_pathnames) {
2148 /* Replace as raw DFS names. */
2149 string_replace(smb_fname->base_name, '/', '\\');
2151 name_out = talloc_strdup(ctx, smb_fname->base_name);
2152 *_twrp = smb_fname->twrp;
2153 TALLOC_FREE(smb_fname);
2154 return name_out;
2156 #endif
2159 * Deal with the SMB1 semantics of sending a pathname with a
2160 * wildcard as the terminal component for a SMB1search or
2161 * trans2 findfirst.
2164 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
2165 connection_struct *conn,
2166 char *name_in,
2167 uint32_t ucf_flags,
2168 struct smb_filename **_smb_fname_out,
2169 char **_mask_out)
2171 NTSTATUS status;
2172 char *p = NULL;
2173 char *mask = NULL;
2174 struct smb_filename *smb_fname = NULL;
2175 bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
2176 NTTIME twrp = 0;
2178 *_smb_fname_out = NULL;
2179 *_mask_out = NULL;
2181 DBG_DEBUG("name_in: %s\n", name_in);
2183 if (ucf_flags & UCF_GMT_PATHNAME) {
2184 extract_snapshot_token(name_in, ucf_flags, &twrp);
2185 ucf_flags &= ~UCF_GMT_PATHNAME;
2188 if (ucf_flags & UCF_DFS_PATHNAME) {
2190 * We've been given a raw DFS pathname.
2191 * In Windows mode this is separated by '\'
2192 * characters, in POSIX by '/' characters.
2194 char path_sep = posix_pathnames ? '/' : '\\';
2195 char *fname = NULL;
2196 char *name_in_copy = NULL;
2197 char *last_component = NULL;
2199 /* Work on a copy of name_in. */
2200 name_in_copy = talloc_strdup(ctx, name_in);
2201 if (name_in_copy == NULL) {
2202 return NT_STATUS_NO_MEMORY;
2206 * Now we know that the last component is the
2207 * wildcard. Copy it and truncate to remove it.
2209 p = strrchr_m(name_in_copy, path_sep);
2210 if (p == NULL) {
2211 last_component = talloc_strdup(ctx, name_in_copy);
2212 name_in_copy[0] = '\0';
2213 } else {
2214 last_component = talloc_strdup(ctx, p+1);
2215 *p = '\0';
2217 if (last_component == NULL) {
2218 return NT_STATUS_NO_MEMORY;
2221 DBG_DEBUG("name_in_copy: %s\n", name_in_copy);
2224 * Now we can call dfs_redirect()
2225 * on the name without wildcard.
2227 status = dfs_redirect(ctx,
2228 conn,
2229 name_in_copy,
2230 ucf_flags,
2231 !conn->sconn->using_smb2,
2232 NULL,
2233 &fname);
2234 if (!NT_STATUS_IS_OK(status)) {
2235 DBG_DEBUG("dfs_redirect "
2236 "failed for name %s with %s\n",
2237 name_in_copy,
2238 nt_errstr(status));
2239 return status;
2241 /* Add the last component back. */
2242 if (fname[0] == '\0') {
2243 name_in = talloc_strdup(ctx, last_component);
2244 } else {
2245 name_in = talloc_asprintf(ctx,
2246 "%s%c%s",
2247 fname,
2248 path_sep,
2249 last_component);
2251 if (name_in == NULL) {
2252 return NT_STATUS_NO_MEMORY;
2254 ucf_flags &= ~UCF_DFS_PATHNAME;
2256 DBG_DEBUG("After DFS redirect name_in: %s\n", name_in);
2259 smb_fname = synthetic_smb_fname(ctx,
2260 name_in,
2261 NULL,
2262 NULL,
2263 twrp,
2264 posix_pathnames ?
2265 SMB_FILENAME_POSIX_PATH : 0);
2266 if (smb_fname == NULL) {
2267 return NT_STATUS_NO_MEMORY;
2270 /* Get the original lcomp. */
2271 mask = get_original_lcomp(ctx,
2272 conn,
2273 name_in,
2274 ucf_flags);
2275 if (mask == NULL) {
2276 return NT_STATUS_NO_MEMORY;
2279 if (mask[0] == '\0') {
2280 /* Windows and OS/2 systems treat search on the root as * */
2281 TALLOC_FREE(mask);
2282 mask = talloc_strdup(ctx, "*");
2283 if (mask == NULL) {
2284 return NT_STATUS_NO_MEMORY;
2288 DBG_DEBUG("mask = %s\n", mask);
2291 * Remove the terminal component so
2292 * filename_convert never sees the mask.
2294 p = strrchr_m(smb_fname->base_name,'/');
2295 if (p == NULL) {
2296 /* filename_convert handles a '\0' base_name. */
2297 smb_fname->base_name[0] = '\0';
2298 } else {
2299 *p = '\0';
2302 DBG_DEBUG("For filename_convert: smb_fname = %s\n",
2303 smb_fname_str_dbg(smb_fname));
2305 /* Convert the parent directory path. */
2306 status = filename_convert(ctx,
2307 conn,
2308 smb_fname->base_name,
2309 ucf_flags,
2310 smb_fname->twrp,
2311 &smb_fname);
2313 if (!NT_STATUS_IS_OK(status)) {
2314 DBG_DEBUG("filename_convert error for %s: %s\n",
2315 smb_fname_str_dbg(smb_fname),
2316 nt_errstr(status));
2319 *_smb_fname_out = talloc_move(ctx, &smb_fname);
2320 *_mask_out = talloc_move(ctx, &mask);
2322 return status;
2326 * Get the correct capitalized stream name hanging off
2327 * base_fsp. Equivalent of get_real_filename(), but for streams.
2329 static NTSTATUS get_real_stream_name(
2330 TALLOC_CTX *mem_ctx,
2331 struct files_struct *base_fsp,
2332 const char *stream_name,
2333 char **_found)
2335 unsigned int i, num_streams = 0;
2336 struct stream_struct *streams = NULL;
2337 NTSTATUS status;
2339 status = vfs_fstreaminfo(
2340 base_fsp, talloc_tos(), &num_streams, &streams);
2341 if (!NT_STATUS_IS_OK(status)) {
2342 return status;
2345 for (i=0; i<num_streams; i++) {
2346 bool equal = sname_equal(stream_name, streams[i].name, false);
2348 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
2349 stream_name,
2350 streams[i].name,
2351 equal ? "" : "not ");
2353 if (equal) {
2354 *_found = talloc_move(mem_ctx, &streams[i].name);
2355 TALLOC_FREE(streams);
2356 return NT_STATUS_OK;
2360 TALLOC_FREE(streams);
2361 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2364 static bool filename_split_lcomp(
2365 TALLOC_CTX *mem_ctx,
2366 const char *name_in,
2367 bool posix,
2368 char **_dirname,
2369 const char **_fname_rel,
2370 const char **_streamname)
2372 const char *lcomp = NULL;
2373 const char *fname_rel = NULL;
2374 const char *streamname = NULL;
2375 char *dirname = NULL;
2377 if (name_in[0] == '\0') {
2378 fname_rel = ".";
2379 dirname = talloc_strdup(mem_ctx, "");
2380 if (dirname == NULL) {
2381 return false;
2383 goto done;
2386 lcomp = strrchr_m(name_in, '/');
2387 if (lcomp != NULL) {
2388 fname_rel = lcomp+1;
2389 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
2390 if (dirname == NULL) {
2391 return false;
2393 goto find_stream;
2397 * No slash, dir is emtpy
2399 dirname = talloc_strdup(mem_ctx, "");
2400 if (dirname == NULL) {
2401 return false;
2404 if (!posix && (name_in[0] == ':')) {
2406 * Special case for stream on root directory
2408 fname_rel = ".";
2409 streamname = name_in;
2410 goto done;
2413 fname_rel = name_in;
2415 find_stream:
2416 if (!posix) {
2417 streamname = strchr_m(fname_rel, ':');
2419 if (streamname != NULL) {
2420 fname_rel = talloc_strndup(
2421 mem_ctx,
2422 fname_rel,
2423 streamname - fname_rel);
2424 if (fname_rel == NULL) {
2425 TALLOC_FREE(dirname);
2426 return false;
2431 done:
2432 *_dirname = dirname;
2433 *_fname_rel = fname_rel;
2434 *_streamname = streamname;
2435 return true;
2439 * Create the correct capitalization of a file name to be created.
2441 static NTSTATUS filename_convert_normalize_new(
2442 TALLOC_CTX *mem_ctx,
2443 struct connection_struct *conn,
2444 char *name_in,
2445 char **_normalized)
2447 char *name = name_in;
2449 *_normalized = NULL;
2451 if (!conn->case_preserve ||
2452 (mangle_is_8_3(name, false,
2453 conn->params) &&
2454 !conn->short_case_preserve)) {
2456 char *normalized = talloc_strdup(mem_ctx, name);
2457 if (normalized == NULL) {
2458 return NT_STATUS_NO_MEMORY;
2461 strnorm(normalized, lp_default_case(SNUM(conn)));
2462 name = normalized;
2465 if (mangle_is_mangled(name, conn->params)) {
2466 bool found;
2467 char *unmangled = NULL;
2469 found = mangle_lookup_name_from_8_3(
2470 mem_ctx, name, &unmangled, conn->params);
2471 if (found) {
2472 name = unmangled;
2476 if (name != name_in) {
2477 *_normalized = name;
2480 return NT_STATUS_OK;
2484 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
2485 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
2486 * the first attempt based on the filename sent by the client gives
2487 * ENOENT.
2489 static NTSTATUS openat_pathref_fsp_case_insensitive(
2490 struct files_struct *dirfsp,
2491 struct smb_filename *smb_fname_rel,
2492 uint32_t ucf_flags)
2494 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
2495 DATA_BLOB cache_key = { .data = NULL, };
2496 char *found_name = NULL;
2497 NTSTATUS status;
2498 bool ok;
2500 SET_STAT_INVALID(smb_fname_rel->st);
2502 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
2504 if (NT_STATUS_IS_OK(status)) {
2505 return NT_STATUS_OK;
2508 if (VALID_STAT(smb_fname_rel->st)) {
2510 * We got an error although the object existed. Might
2511 * be a symlink we don't want.
2513 return status;
2516 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2518 * Only retry on ENOENT
2520 return status;
2523 if (posix || dirfsp->conn->case_sensitive) {
2525 * Only return case insensitive if required
2527 return status;
2530 if (lp_stat_cache()) {
2531 char *base_name = smb_fname_rel->base_name;
2532 DATA_BLOB value = { .data = NULL };
2534 ok = get_real_filename_cache_key(
2535 talloc_tos(), dirfsp, base_name, &cache_key);
2536 if (!ok) {
2538 * probably ENOMEM, just bail
2540 return status;
2543 DO_PROFILE_INC(statcache_lookups);
2545 ok = memcache_lookup(
2546 NULL, GETREALFILENAME_CACHE, cache_key, &value);
2547 if (!ok) {
2548 DO_PROFILE_INC(statcache_misses);
2549 goto lookup;
2551 DO_PROFILE_INC(statcache_hits);
2553 TALLOC_FREE(smb_fname_rel->base_name);
2554 smb_fname_rel->base_name = talloc_memdup(
2555 smb_fname_rel, value.data, value.length);
2556 if (smb_fname_rel->base_name == NULL) {
2557 TALLOC_FREE(cache_key.data);
2558 return NT_STATUS_NO_MEMORY;
2561 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
2562 if (NT_STATUS_IS_OK(status)) {
2563 TALLOC_FREE(cache_key.data);
2564 return NT_STATUS_OK;
2567 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
2570 lookup:
2571 status = get_real_filename_at(
2572 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
2573 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2574 (ucf_flags & UCF_PREP_CREATEFILE)) {
2576 * dropbox
2578 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
2581 if (NT_STATUS_IS_OK(status)) {
2582 TALLOC_FREE(smb_fname_rel->base_name);
2583 smb_fname_rel->base_name = found_name;
2585 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
2588 if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
2589 DATA_BLOB value = {
2590 .data = (uint8_t *)smb_fname_rel->base_name,
2591 .length = strlen(smb_fname_rel->base_name) + 1,
2594 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
2597 TALLOC_FREE(cache_key.data);
2599 return status;
2603 * Split up name_in as sent by the client into a directory pathref fsp
2604 * and a relative smb_filename.
2606 static const char *previous_slash(const char *name_in, const char *slash)
2608 const char *prev = name_in;
2610 while (true) {
2611 const char *next = strchr_m(prev, '/');
2613 SMB_ASSERT(next != NULL); /* we have at least one slash */
2615 if (next == slash) {
2616 break;
2619 prev = next+1;
2622 if (prev == name_in) {
2623 /* no previous slash */
2624 return NULL;
2627 return prev;
2630 static char *symlink_target_path(
2631 TALLOC_CTX *mem_ctx,
2632 const char *name_in,
2633 const char *substitute,
2634 size_t unparsed)
2636 size_t name_in_len = strlen(name_in);
2637 const char *p_unparsed = NULL;
2638 const char *parent = NULL;
2639 char *ret;
2641 SMB_ASSERT(unparsed <= name_in_len);
2643 p_unparsed = name_in + (name_in_len - unparsed);
2645 if (substitute[0] == '/') {
2646 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
2647 return ret;
2650 if (unparsed == 0) {
2651 parent = strrchr_m(name_in, '/');
2652 } else {
2653 parent = previous_slash(name_in, p_unparsed);
2656 if (parent == NULL) {
2657 /* no previous slash */
2658 parent = name_in;
2661 ret = talloc_asprintf(
2662 mem_ctx,
2663 "%.*s%s%s",
2664 (int)(parent - name_in),
2665 name_in,
2666 substitute,
2667 p_unparsed);
2668 return ret;
2672 * Split up name_in as sent by the client into a directory pathref fsp
2673 * and a relative smb_filename.
2675 static NTSTATUS filename_convert_dirfsp_nosymlink(
2676 TALLOC_CTX *mem_ctx,
2677 connection_struct *conn,
2678 const char *name_in,
2679 uint32_t ucf_flags,
2680 NTTIME twrp,
2681 struct files_struct **_dirfsp,
2682 struct smb_filename **_smb_fname,
2683 char **_substitute,
2684 size_t *_unparsed)
2686 struct smb_filename *smb_dirname = NULL;
2687 struct smb_filename *smb_fname_rel = NULL;
2688 struct smb_filename *smb_fname = NULL;
2689 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
2690 char *dirname = NULL;
2691 const char *fname_rel = NULL;
2692 const char *streamname = NULL;
2693 char *saved_streamname = NULL;
2694 struct files_struct *base_fsp = NULL;
2695 bool ok;
2696 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2698 if (ucf_flags & UCF_DFS_PATHNAME) {
2699 char *fname = NULL;
2700 NTTIME dfs_twrp = 0;
2701 status = dfs_redirect(
2702 mem_ctx,
2703 conn,
2704 name_in,
2705 ucf_flags,
2706 !conn->sconn->using_smb2,
2707 &dfs_twrp,
2708 &fname);
2709 if (!NT_STATUS_IS_OK(status)) {
2710 DBG_DEBUG("dfs_redirect "
2711 "failed for name %s with %s\n",
2712 name_in,
2713 nt_errstr(status));
2714 return status;
2716 name_in = fname;
2717 ucf_flags &= ~UCF_DFS_PATHNAME;
2718 if (twrp == 0 && dfs_twrp != 0) {
2719 twrp = dfs_twrp;
2723 if (is_fake_file_path(name_in) || conn->printer) {
2724 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
2725 if (smb_fname == NULL) {
2726 return NT_STATUS_NO_MEMORY;
2728 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
2729 smb_fname->st.st_ex_btime =
2730 (struct timespec){0, SAMBA_UTIME_OMIT};
2731 smb_fname->st.st_ex_atime =
2732 (struct timespec){0, SAMBA_UTIME_OMIT};
2733 smb_fname->st.st_ex_mtime =
2734 (struct timespec){0, SAMBA_UTIME_OMIT};
2735 smb_fname->st.st_ex_ctime =
2736 (struct timespec){0, SAMBA_UTIME_OMIT};
2738 *_dirfsp = conn->cwd_fsp;
2739 *_smb_fname = smb_fname;
2740 return NT_STATUS_OK;
2744 * Catch an invalid path of "." before we
2745 * call filename_split_lcomp(). We need to
2746 * do this as filename_split_lcomp() will
2747 * use "." for the missing relative component
2748 * when an empty name_in path is sent by
2749 * the client.
2751 if (ISDOT(name_in)) {
2752 status = NT_STATUS_OBJECT_NAME_INVALID;
2753 goto fail;
2756 ok = filename_split_lcomp(
2757 talloc_tos(),
2758 name_in,
2759 posix,
2760 &dirname,
2761 &fname_rel,
2762 &streamname);
2763 if (!ok) {
2764 status = NT_STATUS_NO_MEMORY;
2765 goto fail;
2768 if (!posix) {
2769 bool name_has_wild = ms_has_wild(dirname);
2770 name_has_wild |= ms_has_wild(fname_rel);
2771 if (name_has_wild) {
2772 status = NT_STATUS_OBJECT_NAME_INVALID;
2773 goto fail;
2777 if (dirname[0] == '\0') {
2778 status = synthetic_pathref(
2779 mem_ctx,
2780 conn->cwd_fsp,
2781 ".",
2782 NULL,
2783 NULL,
2785 posix ? SMB_FILENAME_POSIX_PATH : 0,
2786 &smb_dirname);
2787 } else {
2788 char *substitute = NULL;
2789 size_t unparsed = 0;
2791 status = openat_pathref_dirfsp_nosymlink(
2792 mem_ctx,
2793 conn,
2794 dirname,
2796 &smb_dirname,
2797 &unparsed,
2798 &substitute);
2800 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
2802 size_t name_in_len = strlen(name_in);
2803 size_t dirname_len = strlen(dirname);
2805 SMB_ASSERT(name_in_len >= dirname_len);
2807 *_substitute = substitute;
2808 *_unparsed = unparsed + (name_in_len - dirname_len);
2810 goto fail;
2814 if (!NT_STATUS_IS_OK(status)) {
2815 DBG_DEBUG("opening directory %s failed: %s\n",
2816 dirname,
2817 nt_errstr(status));
2818 TALLOC_FREE(dirname);
2820 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
2822 * Except ACCESS_DENIED, everything else leads
2823 * to PATH_NOT_FOUND.
2825 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
2828 goto fail;
2831 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
2832 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
2833 goto fail;
2837 * Only look at bad last component values
2838 * once we know we have a valid directory. That
2839 * way we won't confuse error messages from
2840 * opening the directory path with error
2841 * messages from a bad last component.
2844 /* Relative filename can't be empty */
2845 if (fname_rel[0] == '\0') {
2846 status = NT_STATUS_OBJECT_NAME_INVALID;
2847 goto fail;
2850 /* Relative filename can't be ".." */
2851 if (ISDOTDOT(fname_rel)) {
2852 status = NT_STATUS_OBJECT_NAME_INVALID;
2853 goto fail;
2855 /* Relative name can only be dot if directory is empty. */
2856 if (ISDOT(fname_rel) && dirname[0] != '\0') {
2857 status = NT_STATUS_OBJECT_NAME_INVALID;
2858 goto fail;
2861 TALLOC_FREE(dirname);
2863 smb_fname_rel = synthetic_smb_fname(
2864 mem_ctx,
2865 fname_rel,
2866 streamname,
2867 NULL,
2868 twrp,
2869 posix ? SMB_FILENAME_POSIX_PATH : 0);
2870 if (smb_fname_rel == NULL) {
2871 status = NT_STATUS_NO_MEMORY;
2872 goto fail;
2875 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
2876 is_named_stream(smb_fname_rel)) {
2878 * Find the base_fsp first without the stream.
2880 saved_streamname = smb_fname_rel->stream_name;
2881 smb_fname_rel->stream_name = NULL;
2884 status = normalize_filename_case(
2885 conn, smb_fname_rel->base_name, ucf_flags);
2886 if (!NT_STATUS_IS_OK(status)) {
2887 DBG_ERR("normalize_filename_case %s failed: %s\n",
2888 smb_fname_rel->base_name,
2889 nt_errstr(status));
2890 goto fail;
2893 status = openat_pathref_fsp_case_insensitive(
2894 smb_dirname->fsp, smb_fname_rel, ucf_flags);
2896 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2898 char *normalized = NULL;
2900 if (VALID_STAT(smb_fname_rel->st)) {
2901 #if defined(WITH_SMB1SERVER)
2903 * In SMB1 posix mode, if this is a symlink,
2904 * allow access to the name with a NULL smb_fname->fsp.
2906 if (!conn->sconn->using_smb2 &&
2907 posix &&
2908 S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
2909 SMB_ASSERT(smb_fname_rel->fsp == NULL);
2910 SMB_ASSERT(streamname == NULL);
2912 smb_fname = full_path_from_dirfsp_atname(
2913 mem_ctx,
2914 smb_dirname->fsp,
2915 smb_fname_rel);
2916 if (smb_fname == NULL) {
2917 status = NT_STATUS_NO_MEMORY;
2918 goto fail;
2920 goto done;
2922 #endif
2924 * NT_STATUS_OBJECT_NAME_NOT_FOUND is
2925 * misleading: The object exists but might be
2926 * a symlink pointing outside the share.
2928 goto fail;
2932 * Creating a new file
2935 status = filename_convert_normalize_new(
2936 smb_fname_rel,
2937 conn,
2938 smb_fname_rel->base_name,
2939 &normalized);
2940 if (!NT_STATUS_IS_OK(status)) {
2941 DBG_DEBUG("filename_convert_normalize_new failed: "
2942 "%s\n",
2943 nt_errstr(status));
2944 goto fail;
2946 if (normalized != NULL) {
2947 smb_fname_rel->base_name = normalized;
2950 smb_fname_rel->stream_name = saved_streamname;
2952 smb_fname = full_path_from_dirfsp_atname(
2953 mem_ctx, smb_dirname->fsp, smb_fname_rel);
2954 if (smb_fname == NULL) {
2955 status = NT_STATUS_NO_MEMORY;
2956 goto fail;
2958 goto done;
2961 if (!NT_STATUS_IS_OK(status)) {
2962 goto fail;
2965 if (saved_streamname == NULL) {
2966 /* smb_fname must be allocated off mem_ctx. */
2967 smb_fname = cp_smb_filename(mem_ctx,
2968 smb_fname_rel->fsp->fsp_name);
2969 if (smb_fname == NULL) {
2970 goto fail;
2972 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
2973 if (!NT_STATUS_IS_OK(status)) {
2974 goto fail;
2976 goto done;
2979 base_fsp = smb_fname_rel->fsp;
2980 smb_fname_fsp_unlink(smb_fname_rel);
2981 SET_STAT_INVALID(smb_fname_rel->st);
2983 smb_fname_rel->stream_name = saved_streamname;
2985 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
2987 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
2988 !conn->case_sensitive) {
2989 char *found = NULL;
2991 status = get_real_stream_name(
2992 smb_fname_rel,
2993 base_fsp,
2994 smb_fname_rel->stream_name,
2995 &found);
2997 if (NT_STATUS_IS_OK(status)) {
2998 smb_fname_rel->stream_name = found;
2999 found = NULL;
3000 status = open_stream_pathref_fsp(
3001 &base_fsp, smb_fname_rel);
3005 if (NT_STATUS_IS_OK(status)) {
3006 /* smb_fname must be allocated off mem_ctx. */
3007 smb_fname = cp_smb_filename(mem_ctx,
3008 smb_fname_rel->fsp->fsp_name);
3009 if (smb_fname == NULL) {
3010 goto fail;
3012 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
3013 if (!NT_STATUS_IS_OK(status)) {
3014 goto fail;
3016 goto done;
3019 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
3021 * Creating a new stream
3023 * We should save the already-open base fsp for
3024 * create_file_unixpath() somehow.
3026 smb_fname = full_path_from_dirfsp_atname(
3027 mem_ctx, smb_dirname->fsp, smb_fname_rel);
3028 if (smb_fname == NULL) {
3029 status = NT_STATUS_NO_MEMORY;
3030 goto fail;
3032 goto done;
3035 if (!NT_STATUS_IS_OK(status)) {
3036 goto fail;
3039 done:
3040 *_dirfsp = smb_dirname->fsp;
3041 *_smb_fname = smb_fname;
3043 smb_fname_fsp_unlink(smb_fname_rel);
3044 TALLOC_FREE(smb_fname_rel);
3045 return NT_STATUS_OK;
3047 fail:
3048 TALLOC_FREE(dirname);
3049 TALLOC_FREE(smb_dirname);
3050 TALLOC_FREE(smb_fname_rel);
3051 return status;
3054 NTSTATUS filename_convert_dirfsp(
3055 TALLOC_CTX *mem_ctx,
3056 connection_struct *conn,
3057 const char *name_in,
3058 uint32_t ucf_flags,
3059 NTTIME twrp,
3060 struct files_struct **_dirfsp,
3061 struct smb_filename **_smb_fname)
3063 char *substitute = NULL;
3064 size_t unparsed = 0;
3065 NTSTATUS status;
3066 char *target = NULL;
3067 char *abs_target = NULL;
3068 char *abs_target_canon = NULL;
3069 size_t symlink_redirects = 0;
3070 bool in_share;
3072 next:
3073 if (symlink_redirects > 40) {
3074 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3077 status = filename_convert_dirfsp_nosymlink(
3078 mem_ctx,
3079 conn,
3080 name_in,
3081 ucf_flags,
3082 twrp,
3083 _dirfsp,
3084 _smb_fname,
3085 &substitute,
3086 &unparsed);
3088 #if defined(WITH_SMB1SERVER)
3090 * This isn't 100% correct, but it gets us close enough
3091 * to the old behavior for SMB1+POSIX libsmbclient. If we went through a
3092 * symlink, and we got NT_STATUS_ACCESS_DENIED on the directory
3093 * containing the target, just don't allow the client to see the
3094 * intermediate path.
3096 if (!conn->sconn->using_smb2 &&
3097 (ucf_flags & UCF_POSIX_PATHNAMES) &&
3098 symlink_redirects > 0 &&
3099 NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
3100 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3102 #endif
3104 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
3105 return status;
3108 if (!lp_follow_symlinks(SNUM(conn))) {
3109 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3113 * Right now, SMB2 and SMB1 always traverse symlinks
3114 * within the share. SMB1+POSIX traverses non-terminal
3115 * symlinks within the share.
3117 * When we add SMB2+POSIX we need to return
3118 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
3119 * symlink target data read below if SMB2+POSIX has
3120 * UCF_POSIX_PATHNAMES set to cause the client to
3121 * resolve all symlinks locally.
3124 target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
3125 if (target == NULL) {
3126 return NT_STATUS_NO_MEMORY;
3129 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
3130 name_in,
3131 substitute,
3132 unparsed,
3133 target);
3135 if (target[0] == '/') {
3136 abs_target = target;
3137 } else {
3138 abs_target = talloc_asprintf(
3139 mem_ctx, "%s/%s", conn->connectpath, target);
3140 if (abs_target == NULL) {
3141 return NT_STATUS_NO_MEMORY;
3145 abs_target_canon = canonicalize_absolute_path(mem_ctx, abs_target);
3146 if (abs_target_canon == NULL) {
3147 return NT_STATUS_NO_MEMORY;
3150 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
3152 in_share = strncmp(
3153 abs_target_canon,
3154 conn->connectpath,
3155 strlen(conn->connectpath)) == 0;
3156 if (!in_share) {
3157 DBG_DEBUG("wide link to %s\n", abs_target_canon);
3158 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3161 name_in = talloc_strdup(
3162 mem_ctx, abs_target_canon + strlen(conn->connectpath) + 1);
3164 symlink_redirects += 1;
3166 goto next;
3170 * Build the full path from a dirfsp and dirfsp relative name
3172 struct smb_filename *full_path_from_dirfsp_atname(
3173 TALLOC_CTX *mem_ctx,
3174 const struct files_struct *dirfsp,
3175 const struct smb_filename *atname)
3177 struct smb_filename *fname = NULL;
3178 char *path = NULL;
3180 if (dirfsp == dirfsp->conn->cwd_fsp ||
3181 ISDOT(dirfsp->fsp_name->base_name) ||
3182 atname->base_name[0] == '/')
3184 path = talloc_strdup(mem_ctx, atname->base_name);
3185 } else {
3186 path = talloc_asprintf(mem_ctx, "%s/%s",
3187 dirfsp->fsp_name->base_name,
3188 atname->base_name);
3190 if (path == NULL) {
3191 return NULL;
3194 fname = synthetic_smb_fname(mem_ctx,
3195 path,
3196 atname->stream_name,
3197 &atname->st,
3198 atname->twrp,
3199 atname->flags);
3200 TALLOC_FREE(path);
3201 if (fname == NULL) {
3202 return NULL;
3205 return fname;