s3: smbd: Remove unused check_name_with_privilege().
[Samba.git] / source3 / smbd / filename.c
blob8aa0a6d48c8e7ced371540ea6631991e63ca0f46
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"
33 static int get_real_filename(connection_struct *conn,
34 struct smb_filename *path,
35 const char *name,
36 TALLOC_CTX *mem_ctx,
37 char **found_name);
39 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
41 uint32_t ucf_flags = 0;
43 if (req != NULL) {
44 if (req->posix_pathnames) {
45 ucf_flags |= UCF_POSIX_PATHNAMES;
47 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
48 ucf_flags |= UCF_DFS_PATHNAME;
50 if (req->flags2 & FLAGS2_REPARSE_PATH) {
51 ucf_flags |= UCF_GMT_PATHNAME;
55 return ucf_flags;
58 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
60 uint32_t ucf_flags = 0;
62 ucf_flags |= ucf_flags_from_smb_request(req);
64 switch (create_disposition) {
65 case FILE_OPEN:
66 case FILE_OVERWRITE:
67 break;
68 case FILE_SUPERSEDE:
69 case FILE_CREATE:
70 case FILE_OPEN_IF:
71 case FILE_OVERWRITE_IF:
72 ucf_flags |= UCF_PREP_CREATEFILE;
73 break;
76 return ucf_flags;
79 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
80 connection_struct *conn,
81 struct smb_filename *smb_fname);
83 /****************************************************************************
84 Mangle the 2nd name and check if it is then equal to the first name.
85 ****************************************************************************/
87 static bool mangled_equal(const char *name1,
88 const char *name2,
89 const struct share_params *p)
91 char mname[13];
93 if (!name_to_8_3(name2, mname, False, p)) {
94 return False;
96 return strequal(name1, mname);
99 /****************************************************************************
100 Cope with the differing wildcard and non-wildcard error cases.
101 ****************************************************************************/
103 static NTSTATUS determine_path_error(const char *name,
104 bool allow_wcard_last_component,
105 bool posix_pathnames)
107 const char *p;
108 bool name_has_wild = false;
110 if (!allow_wcard_last_component) {
111 /* Error code within a pathname. */
112 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
115 /* We're terminating here so we
116 * can be a little slower and get
117 * the error code right. Windows
118 * treats the last part of the pathname
119 * separately I think, so if the last
120 * component is a wildcard then we treat
121 * this ./ as "end of component" */
123 p = strchr(name, '/');
125 if (!posix_pathnames) {
126 name_has_wild = ms_has_wild(name);
129 if (!p && (name_has_wild || ISDOT(name))) {
130 /* Error code at the end of a pathname. */
131 return NT_STATUS_OBJECT_NAME_INVALID;
132 } else {
133 /* Error code within a pathname. */
134 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
138 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
140 /* Ensure we catch all names with in "/."
141 this is disallowed under Windows and
142 in POSIX they've already been removed. */
143 const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
144 if (p) {
145 if (p[2] == '/') {
146 /* Error code within a pathname. */
147 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
148 } else if (p[2] == '\0') {
149 /* Error code at the end of a pathname. */
150 return NT_STATUS_OBJECT_NAME_INVALID;
153 return NT_STATUS_OK;
156 /****************************************************************************
157 Optimization for common case where the missing part
158 is in the last component and the client already
159 sent the correct case.
160 Returns NT_STATUS_OK to mean continue the tree walk
161 (possibly with modified start pointer).
162 Any other NT_STATUS_XXX error means terminate the path
163 lookup here.
164 ****************************************************************************/
166 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
167 connection_struct *conn,
168 bool posix_pathnames,
169 const struct smb_filename *smb_fname,
170 char **pp_dirpath,
171 char **pp_start,
172 int *p_parent_stat_errno)
174 char *parent_name = NULL;
175 struct smb_filename *parent_fname = NULL;
176 const char *last_component = NULL;
177 NTSTATUS status;
178 int ret;
180 if (!parent_dirname(ctx, smb_fname->base_name,
181 &parent_name,
182 &last_component)) {
183 return NT_STATUS_NO_MEMORY;
186 if (!posix_pathnames) {
187 if (ms_has_wild(parent_name)) {
188 goto no_optimization_out;
193 * If there was no parent component in
194 * smb_fname->base_name then don't do this
195 * optimization.
197 if (smb_fname->base_name == last_component) {
198 goto no_optimization_out;
201 parent_fname = synthetic_smb_fname(ctx,
202 parent_name,
203 NULL,
204 NULL,
205 smb_fname->twrp,
206 smb_fname->flags);
207 if (parent_fname == NULL) {
208 return NT_STATUS_NO_MEMORY;
211 if (posix_pathnames) {
212 ret = SMB_VFS_LSTAT(conn, parent_fname);
213 } else {
214 ret = SMB_VFS_STAT(conn, parent_fname);
217 /* If the parent stat failed, just continue
218 with the normal tree walk. */
220 if (ret == -1) {
222 * Optimization. Preserving the
223 * errno from the STAT/LSTAT here
224 * will allow us to save a duplicate
225 * STAT/LSTAT system call of the parent
226 * pathname in a hot code path in the caller.
228 if (p_parent_stat_errno != NULL) {
229 *p_parent_stat_errno = errno;
231 goto no_optimization_out;
234 status = check_for_dot_component(parent_fname);
235 if (!NT_STATUS_IS_OK(status)) {
236 return status;
239 /* Parent exists - set "start" to be the
240 * last component to shorten the tree walk. */
243 * Safe to use discard_const_p
244 * here as last_component points
245 * into our smb_fname->base_name.
247 *pp_start = discard_const_p(char, last_component);
249 /* Update dirpath. */
250 TALLOC_FREE(*pp_dirpath);
251 *pp_dirpath = talloc_strdup(ctx, parent_fname->base_name);
252 if (!*pp_dirpath) {
253 return NT_STATUS_NO_MEMORY;
256 DEBUG(5,("check_parent_exists: name "
257 "= %s, dirpath = %s, "
258 "start = %s\n",
259 smb_fname->base_name,
260 *pp_dirpath,
261 *pp_start));
263 return NT_STATUS_OK;
265 no_optimization_out:
268 * We must still return an *pp_dirpath
269 * initialized to ".", and a *pp_start
270 * pointing at smb_fname->base_name.
273 TALLOC_FREE(parent_name);
274 TALLOC_FREE(parent_fname);
276 *pp_dirpath = talloc_strdup(ctx, ".");
277 if (*pp_dirpath == NULL) {
278 return NT_STATUS_NO_MEMORY;
281 * Safe to use discard_const_p
282 * here as by convention smb_fname->base_name
283 * is allocated off ctx.
285 *pp_start = discard_const_p(char, smb_fname->base_name);
286 return NT_STATUS_OK;
290 * Re-order a known good @GMT-token path.
293 static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
294 char *startp,
295 char *endp)
297 size_t endlen = 0;
298 size_t gmt_len = endp - startp;
299 char gmt_store[gmt_len + 1];
300 char *parent = NULL;
301 const char *last_component = NULL;
302 char *newstr;
303 bool ret;
305 DBG_DEBUG("|%s| -> ", smb_fname->base_name);
307 /* Save off the @GMT-token. */
308 memcpy(gmt_store, startp, gmt_len);
309 gmt_store[gmt_len] = '\0';
311 if (*endp == '/') {
312 /* Remove any trailing '/' */
313 endp++;
316 if (*endp == '\0') {
318 * @GMT-token was at end of path.
319 * Remove any preceding '/'
321 if (startp > smb_fname->base_name && startp[-1] == '/') {
322 startp--;
326 /* Remove @GMT-token from the path. */
327 endlen = strlen(endp);
328 memmove(startp, endp, endlen + 1);
330 /* Split the remaining path into components. */
331 ret = parent_dirname(smb_fname,
332 smb_fname->base_name,
333 &parent,
334 &last_component);
335 if (!ret) {
336 /* Must terminate debug with \n */
337 DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
338 return NT_STATUS_NO_MEMORY;
341 if (ISDOT(parent)) {
342 if (last_component[0] == '\0') {
343 newstr = talloc_strdup(smb_fname,
344 gmt_store);
345 } else {
346 newstr = talloc_asprintf(smb_fname,
347 "%s/%s",
348 gmt_store,
349 last_component);
351 } else {
352 newstr = talloc_asprintf(smb_fname,
353 "%s/%s/%s",
354 gmt_store,
355 parent,
356 last_component);
359 TALLOC_FREE(parent);
360 TALLOC_FREE(smb_fname->base_name);
361 smb_fname->base_name = newstr;
363 DBG_DEBUG("|%s|\n", newstr);
365 return NT_STATUS_OK;
369 * Strip a valid @GMT-token from any incoming filename path,
370 * adding any NTTIME encoded in the pathname into the
371 * twrp field of the passed in smb_fname.
373 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
374 * at the *start* of a pathname component.
376 * If twrp is passed in then smb_fname->twrp is set to that
377 * value, and the @GMT-token part of the filename is removed
378 * and does not change the stored smb_fname->twrp.
382 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
383 uint32_t ucf_flags,
384 NTTIME twrp)
386 char *startp = NULL;
387 char *endp = NULL;
388 char *tmp = NULL;
389 struct tm tm;
390 time_t t;
391 NTTIME nt;
392 NTSTATUS status;
394 if (twrp != 0) {
395 smb_fname->twrp = twrp;
398 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
399 return NT_STATUS_OK;
402 startp = strchr_m(smb_fname->base_name, '@');
403 if (startp == NULL) {
404 /* No @ */
405 return NT_STATUS_OK;
408 startp = strstr_m(startp, "@GMT-");
409 if (startp == NULL) {
410 /* No @ */
411 return NT_STATUS_OK;
414 if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
415 /* the GMT-token does not start a path-component */
416 return NT_STATUS_OK;
419 endp = strptime(startp, GMT_FORMAT, &tm);
420 if (endp == NULL) {
421 /* Not a valid timestring. */
422 return NT_STATUS_OK;
425 if (endp[0] != '\0' && endp[0] != '/') {
427 * It is not a complete path component, i.e. the path
428 * component continues after the gmt-token.
430 return NT_STATUS_OK;
433 status = rearrange_snapshot_path(smb_fname, startp, endp);
434 if (!NT_STATUS_IS_OK(status)) {
435 return status;
438 startp = smb_fname->base_name + GMT_NAME_LEN;
439 if (startp[0] == '/') {
440 startp++;
443 tmp = talloc_strdup(smb_fname, startp);
444 if (tmp == NULL) {
445 return NT_STATUS_NO_MEMORY;
448 TALLOC_FREE(smb_fname->base_name);
449 smb_fname->base_name = tmp;
451 if (smb_fname->twrp == 0) {
452 tm.tm_isdst = -1;
453 t = timegm(&tm);
454 unix_to_nt_time(&nt, t);
455 smb_fname->twrp = nt;
458 return NT_STATUS_OK;
462 * Utility function to normalize case on an incoming client filename
463 * if required on this connection struct.
464 * Performs an in-place case conversion guaranteed to stay the same size.
467 static NTSTATUS normalize_filename_case(connection_struct *conn,
468 char *filename,
469 uint32_t ucf_flags)
471 bool ok;
473 if (ucf_flags & UCF_POSIX_PATHNAMES) {
475 * POSIX never normalizes filename case.
477 return NT_STATUS_OK;
479 if (!conn->case_sensitive) {
480 return NT_STATUS_OK;
482 if (conn->case_preserve) {
483 return NT_STATUS_OK;
485 if (conn->short_case_preserve) {
486 return NT_STATUS_OK;
488 ok = strnorm(filename, lp_default_case(SNUM(conn)));
489 if (!ok) {
490 return NT_STATUS_INVALID_PARAMETER;
492 return NT_STATUS_OK;
495 /****************************************************************************
496 This routine is called to convert names from the dos namespace to unix
497 namespace. It needs to handle any case conversions, mangling, format changes,
498 streams etc.
500 We assume that we have already done a chdir() to the right "root" directory
501 for this service.
503 Conversion to basic unix format is already done in check_path_syntax().
505 Names must be relative to the root of the service - any leading /. and
506 trailing /'s should have been trimmed by check_path_syntax().
508 The function will return an NTSTATUS error if some part of the name except for
509 the last part cannot be resolved, else NT_STATUS_OK.
511 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
512 didn't get any fatal errors that should immediately terminate the calling SMB
513 processing whilst resolving.
515 If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard
516 should be allowed in the last component of the path only.
518 If the orig_path was a stream, smb_filename->base_name will point to the base
519 filename, and smb_filename->stream_name will point to the stream name. If
520 orig_path was not a stream, then smb_filename->stream_name will be NULL.
522 On exit from unix_convert, the smb_filename->st stat struct will be populated
523 if the file exists and was found, if not this stat struct will be filled with
524 zeros (and this can be detected by checking for nlinks = 0, which can never be
525 true for any file).
526 ****************************************************************************/
528 struct uc_state {
529 TALLOC_CTX *mem_ctx;
530 struct connection_struct *conn;
531 struct smb_filename *smb_fname;
532 const char *orig_path;
533 uint32_t ucf_flags;
534 char *name;
535 char *end;
536 char *dirpath;
537 char *stream;
538 bool component_was_mangled;
539 bool name_has_wildcard;
540 bool posix_pathnames;
541 bool allow_wcard_last_component;
542 bool done;
543 bool case_sensitive;
544 bool case_preserve;
545 bool short_case_preserve;
548 static NTSTATUS unix_convert_step_search_fail(struct uc_state *state)
550 char *unmangled;
552 if (state->end) {
554 * An intermediate part of the name
555 * can't be found.
557 DBG_DEBUG("Intermediate [%s] missing\n",
558 state->name);
559 *state->end = '/';
562 * We need to return the fact that the
563 * intermediate name resolution failed.
564 * This is used to return an error of
565 * ERRbadpath rather than ERRbadfile.
566 * Some Windows applications depend on
567 * the difference between these two
568 * errors.
572 * ENOENT, ENOTDIR and ELOOP all map
573 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
574 * in the filename walk.
577 if (errno == ENOENT ||
578 errno == ENOTDIR ||
579 errno == ELOOP)
581 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
583 return map_nt_error_from_unix(errno);
587 * ENOENT/EACCESS are the only valid errors
588 * here.
591 if (errno == EACCES) {
592 if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
593 return NT_STATUS_ACCESS_DENIED;
594 } else {
596 * This is the dropbox
597 * behaviour. A dropbox is a
598 * directory with only -wx
599 * permissions, so
600 * get_real_filename fails
601 * with EACCESS, it needs to
602 * list the directory. We
603 * nevertheless want to allow
604 * users creating a file.
606 errno = 0;
610 if ((errno != 0) && (errno != ENOENT)) {
612 * ENOTDIR and ELOOP both map to
613 * NT_STATUS_OBJECT_PATH_NOT_FOUND
614 * in the filename walk.
616 if (errno == ENOTDIR || errno == ELOOP) {
617 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
619 return map_nt_error_from_unix(errno);
623 * POSIX pathnames must never call into mangling.
625 if (state->posix_pathnames) {
626 goto done;
630 * Just the last part of the name doesn't exist.
631 * We need to strupper() or strlower() it as
632 * this conversion may be used for file creation
633 * purposes. Fix inspired by
634 * Thomas Neumann <t.neumann@iku-ag.de>.
636 if (!state->case_preserve ||
637 (mangle_is_8_3(state->name, false,
638 state->conn->params) &&
639 !state->short_case_preserve)) {
640 if (!strnorm(state->name,
641 lp_default_case(SNUM(state->conn)))) {
642 DBG_DEBUG("strnorm %s failed\n",
643 state->name);
644 return NT_STATUS_INVALID_PARAMETER;
649 * check on the mangled stack to see if we can
650 * recover the base of the filename.
653 if (mangle_is_mangled(state->name, state->conn->params)
654 && mangle_lookup_name_from_8_3(state->mem_ctx,
655 state->name,
656 &unmangled,
657 state->conn->params)) {
658 char *tmp;
659 size_t name_ofs =
660 state->name - state->smb_fname->base_name;
662 if (!ISDOT(state->dirpath)) {
663 tmp = talloc_asprintf(
664 state->smb_fname, "%s/%s",
665 state->dirpath, unmangled);
666 TALLOC_FREE(unmangled);
668 else {
669 tmp = unmangled;
671 if (tmp == NULL) {
672 DBG_ERR("talloc failed\n");
673 return NT_STATUS_NO_MEMORY;
675 TALLOC_FREE(state->smb_fname->base_name);
676 state->smb_fname->base_name = tmp;
677 state->name =
678 state->smb_fname->base_name + name_ofs;
679 state->end = state->name + strlen(state->name);
682 done:
684 DBG_DEBUG("New file [%s]\n", state->name);
685 state->done = true;
686 return NT_STATUS_OK;
689 static NTSTATUS unix_convert_step_stat(struct uc_state *state)
691 struct smb_filename dname;
692 char dot[2] = ".";
693 char *found_name = NULL;
694 int ret;
697 * Check if the name exists up to this point.
700 DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname));
702 ret = vfs_stat(state->conn, state->smb_fname);
703 if (ret == 0) {
705 * It exists. it must either be a directory or this must
706 * be the last part of the path for it to be OK.
708 if (state->end && !S_ISDIR(state->smb_fname->st.st_ex_mode)) {
710 * An intermediate part of the name isn't
711 * a directory.
713 DBG_DEBUG("Not a dir [%s]\n", state->name);
714 *state->end = '/';
716 * We need to return the fact that the
717 * intermediate name resolution failed. This
718 * is used to return an error of ERRbadpath
719 * rather than ERRbadfile. Some Windows
720 * applications depend on the difference between
721 * these two errors.
723 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
725 return NT_STATUS_OK;
728 /* Stat failed - ensure we don't use it. */
729 SET_STAT_INVALID(state->smb_fname->st);
731 if (state->posix_pathnames) {
733 * For posix_pathnames, we're done.
734 * Don't blunder into the name_has_wildcard OR
735 * get_real_filename() codepaths as they may
736 * be doing case insensitive lookups. So when
737 * creating a new POSIX directory Foo they might
738 * match on name foo.
740 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13803
742 if (state->end != NULL) {
743 const char *morepath = NULL;
745 * If this is intermediate we must
746 * restore the full path.
748 *state->end = '/';
750 * If there are any more components
751 * after the failed LSTAT we cannot
752 * continue.
754 morepath = strchr(state->end + 1, '/');
755 if (morepath != NULL) {
756 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
759 if (errno == ENOENT) {
760 /* New file or directory. */
761 state->done = true;
762 return NT_STATUS_OK;
764 if ((errno == EACCES) &&
765 (state->ucf_flags & UCF_PREP_CREATEFILE)) {
766 /* POSIX Dropbox case. */
767 errno = 0;
768 state->done = true;
769 return NT_STATUS_OK;
771 return map_nt_error_from_unix(errno);
775 * Reset errno so we can detect
776 * directory open errors.
778 errno = 0;
781 * Try to find this part of the path in the directory.
784 if (state->name_has_wildcard) {
785 return unix_convert_step_search_fail(state);
788 dname = (struct smb_filename) {
789 .base_name = state->dirpath,
790 .twrp = state->smb_fname->twrp,
793 /* handle null paths */
794 if ((dname.base_name == NULL) || (dname.base_name[0] == '\0')) {
795 dname.base_name = dot;
798 ret = get_real_filename(state->conn,
799 &dname,
800 state->name,
801 talloc_tos(),
802 &found_name);
803 if (ret != 0) {
804 return unix_convert_step_search_fail(state);
808 * Restore the rest of the string. If the string was
809 * mangled the size may have changed.
811 if (state->end) {
812 char *tmp;
813 size_t name_ofs =
814 state->name - state->smb_fname->base_name;
816 if (!ISDOT(state->dirpath)) {
817 tmp = talloc_asprintf(state->smb_fname,
818 "%s/%s/%s", state->dirpath,
819 found_name, state->end+1);
821 else {
822 tmp = talloc_asprintf(state->smb_fname,
823 "%s/%s", found_name,
824 state->end+1);
826 if (tmp == NULL) {
827 DBG_ERR("talloc_asprintf failed\n");
828 return NT_STATUS_NO_MEMORY;
830 TALLOC_FREE(state->smb_fname->base_name);
831 state->smb_fname->base_name = tmp;
832 state->name = state->smb_fname->base_name + name_ofs;
833 state->end = state->name + strlen(found_name);
834 *state->end = '\0';
835 } else {
836 char *tmp;
837 size_t name_ofs =
838 state->name - state->smb_fname->base_name;
840 if (!ISDOT(state->dirpath)) {
841 tmp = talloc_asprintf(state->smb_fname,
842 "%s/%s", state->dirpath,
843 found_name);
844 } else {
845 tmp = talloc_strdup(state->smb_fname,
846 found_name);
848 if (tmp == NULL) {
849 DBG_ERR("talloc failed\n");
850 return NT_STATUS_NO_MEMORY;
852 TALLOC_FREE(state->smb_fname->base_name);
853 state->smb_fname->base_name = tmp;
854 state->name = state->smb_fname->base_name + name_ofs;
857 * We just scanned for, and found the end of
858 * the path. We must return a valid stat struct
859 * if it exists. JRA.
862 ret = vfs_stat(state->conn, state->smb_fname);
863 if (ret != 0) {
864 SET_STAT_INVALID(state->smb_fname->st);
868 TALLOC_FREE(found_name);
869 return NT_STATUS_OK;
872 static NTSTATUS unix_convert_step(struct uc_state *state)
874 NTSTATUS status;
877 * Pinpoint the end of this section of the filename.
879 /* mb safe. '/' can't be in any encoded char. */
880 state->end = strchr(state->name, '/');
883 * Chop the name at this point.
885 if (state->end != NULL) {
886 *state->end = 0;
889 DBG_DEBUG("dirpath [%s] name [%s]\n", state->dirpath, state->name);
891 /* The name cannot have a component of "." */
893 if (ISDOT(state->name)) {
894 if (state->end == NULL) {
895 /* Error code at the end of a pathname. */
896 return NT_STATUS_OBJECT_NAME_INVALID;
898 return determine_path_error(state->end+1,
899 state->allow_wcard_last_component,
900 state->posix_pathnames);
903 /* The name cannot have a wildcard if it's not
904 the last component. */
906 if (!state->posix_pathnames) {
907 state->name_has_wildcard = ms_has_wild(state->name);
910 /* Wildcards never valid within a pathname. */
911 if (state->name_has_wildcard && state->end != NULL) {
912 return NT_STATUS_OBJECT_NAME_INVALID;
915 /* Skip the stat call if it's a wildcard end. */
916 if (state->name_has_wildcard) {
917 DBG_DEBUG("Wildcard [%s]\n", state->name);
918 state->done = true;
919 return NT_STATUS_OK;
922 status = unix_convert_step_stat(state);
923 if (!NT_STATUS_IS_OK(status)) {
924 return status;
926 if (state->done) {
927 return NT_STATUS_OK;
931 * Add to the dirpath that we have resolved so far.
934 if (!ISDOT(state->dirpath)) {
935 char *tmp = talloc_asprintf(state->mem_ctx,
936 "%s/%s", state->dirpath, state->name);
937 if (!tmp) {
938 DBG_ERR("talloc_asprintf failed\n");
939 return NT_STATUS_NO_MEMORY;
941 TALLOC_FREE(state->dirpath);
942 state->dirpath = tmp;
944 else {
945 TALLOC_FREE(state->dirpath);
946 if (!(state->dirpath = talloc_strdup(state->mem_ctx,state->name))) {
947 DBG_ERR("talloc_strdup failed\n");
948 return NT_STATUS_NO_MEMORY;
953 * Cache the dirpath thus far. Don't cache a name with mangled
954 * or wildcard components as this can change the size.
956 if(!state->component_was_mangled && !state->name_has_wildcard) {
957 stat_cache_add(state->orig_path,
958 state->dirpath,
959 state->smb_fname->twrp,
960 state->case_sensitive);
964 * Restore the / that we wiped out earlier.
966 if (state->end != NULL) {
967 *state->end = '/';
970 return NT_STATUS_OK;
973 NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
974 connection_struct *conn,
975 const char *orig_path,
976 NTTIME twrp,
977 struct smb_filename **smb_fname_out,
978 uint32_t ucf_flags)
980 struct uc_state uc_state;
981 struct uc_state *state = &uc_state;
982 NTSTATUS status;
983 int ret = -1;
985 *state = (struct uc_state) {
986 .mem_ctx = mem_ctx,
987 .conn = conn,
988 .orig_path = orig_path,
989 .ucf_flags = ucf_flags,
990 .posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES),
991 .allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP),
992 .case_sensitive = conn->case_sensitive,
993 .case_preserve = conn->case_preserve,
994 .short_case_preserve = conn->short_case_preserve,
997 *smb_fname_out = NULL;
999 if (state->posix_pathnames) {
1000 /* POSIX means ignore case settings on share. */
1001 state->case_sensitive = true;
1002 state->case_preserve = true;
1003 state->short_case_preserve = true;
1006 state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename);
1007 if (state->smb_fname == NULL) {
1008 return NT_STATUS_NO_MEMORY;
1011 if (state->conn->printer) {
1012 /* we don't ever use the filenames on a printer share as a
1013 filename - so don't convert them */
1014 state->smb_fname->base_name = talloc_strdup(
1015 state->smb_fname, state->orig_path);
1016 if (state->smb_fname->base_name == NULL) {
1017 status = NT_STATUS_NO_MEMORY;
1018 goto err;
1020 goto done;
1023 state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
1025 DBG_DEBUG("Called on file [%s]\n", state->orig_path);
1027 if (state->orig_path[0] == '/') {
1028 DBG_ERR("Path [%s] starts with '/'\n", state->orig_path);
1029 return NT_STATUS_OBJECT_NAME_INVALID;
1032 /* Start with the full orig_path as given by the caller. */
1033 state->smb_fname->base_name = talloc_strdup(
1034 state->smb_fname, state->orig_path);
1035 if (state->smb_fname->base_name == NULL) {
1036 DBG_ERR("talloc_strdup failed\n");
1037 status = NT_STATUS_NO_MEMORY;
1038 goto err;
1041 /* Canonicalize any @GMT- paths. */
1042 status = canonicalize_snapshot_path(state->smb_fname, ucf_flags, twrp);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 goto err;
1048 * If we trimmed down to a single '\0' character
1049 * then we should use the "." directory to avoid
1050 * searching the cache, but not if we are in a
1051 * printing share.
1052 * As we know this is valid we can return true here.
1055 if (state->smb_fname->base_name[0] == '\0') {
1056 state->smb_fname->base_name = talloc_strdup(state->smb_fname, ".");
1057 if (state->smb_fname->base_name == NULL) {
1058 status = NT_STATUS_NO_MEMORY;
1059 goto err;
1061 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1062 status = map_nt_error_from_unix(errno);
1063 goto err;
1065 DBG_DEBUG("conversion finished [] -> [%s]\n",
1066 state->smb_fname->base_name);
1067 goto done;
1070 if (state->orig_path[0] == '.' && (state->orig_path[1] == '/' ||
1071 state->orig_path[1] == '\0')) {
1072 /* Start of pathname can't be "." only. */
1073 if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') {
1074 status = NT_STATUS_OBJECT_NAME_INVALID;
1075 } else {
1076 status =determine_path_error(&state->orig_path[2],
1077 state->allow_wcard_last_component,
1078 state->posix_pathnames);
1080 goto err;
1084 * Large directory fix normalization. If we're case sensitive, and
1085 * the case preserving parameters are set to "no", normalize the case of
1086 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
1087 * This is in conflict with the current (3.0.20) man page, but is
1088 * what people expect from the "large directory howto". I'll update
1089 * the man page. Thanks to jht@samba.org for finding this. JRA.
1092 status = normalize_filename_case(state->conn,
1093 state->smb_fname->base_name,
1094 ucf_flags);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 DBG_ERR("normalize_filename_case %s failed\n",
1097 state->smb_fname->base_name);
1098 goto err;
1102 * Strip off the stream, and add it back when we're done with the
1103 * base_name.
1105 if (!state->posix_pathnames) {
1106 state->stream = strchr_m(state->smb_fname->base_name, ':');
1108 if (state->stream != NULL) {
1109 char *tmp = talloc_strdup(state->smb_fname, state->stream);
1110 if (tmp == NULL) {
1111 status = NT_STATUS_NO_MEMORY;
1112 goto err;
1115 * Since this is actually pointing into
1116 * smb_fname->base_name this truncates base_name.
1118 *state->stream = '\0';
1119 state->stream = tmp;
1121 if (state->smb_fname->base_name[0] == '\0') {
1123 * orig_name was just a stream name.
1124 * This is a stream on the root of
1125 * the share. Replace base_name with
1126 * a "."
1128 state->smb_fname->base_name =
1129 talloc_strdup(state->smb_fname, ".");
1130 if (state->smb_fname->base_name == NULL) {
1131 status = NT_STATUS_NO_MEMORY;
1132 goto err;
1134 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1135 status = map_nt_error_from_unix(errno);
1136 goto err;
1138 /* dirpath must exist. */
1139 state->dirpath = talloc_strdup(state->mem_ctx,".");
1140 if (state->dirpath == NULL) {
1141 status = NT_STATUS_NO_MEMORY;
1142 goto err;
1144 DBG_INFO("conversion finished [%s] -> [%s]\n",
1145 state->orig_path,
1146 state->smb_fname->base_name);
1147 goto done;
1152 state->name = state->smb_fname->base_name;
1155 * If we're providing case insensitive semantics or
1156 * the underlying filesystem is case insensitive,
1157 * then a case-normalized hit in the stat-cache is
1158 * authoritative. JRA.
1160 * Note: We're only checking base_name. The stream_name will be
1161 * added and verified in build_stream_path().
1164 if (!state->case_sensitive ||
1165 !(state->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
1167 bool found;
1169 found = stat_cache_lookup(state->conn,
1170 state->posix_pathnames,
1171 &state->smb_fname->base_name,
1172 &state->dirpath,
1173 &state->name,
1174 state->smb_fname->twrp,
1175 &state->smb_fname->st);
1176 if (found) {
1177 goto done;
1182 * Make sure "dirpath" is an allocated string, we use this for
1183 * building the directories with talloc_asprintf and free it.
1186 if (state->dirpath == NULL) {
1187 state->dirpath = talloc_strdup(state->mem_ctx,".");
1188 if (state->dirpath == NULL) {
1189 DBG_ERR("talloc_strdup failed\n");
1190 status = NT_STATUS_NO_MEMORY;
1191 goto err;
1196 * If we have a wildcard we must walk the path to
1197 * find where the error is, even if case sensitive
1198 * is true.
1201 if (!state->posix_pathnames) {
1202 /* POSIX pathnames have no wildcards. */
1203 state->name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
1204 if (state->name_has_wildcard && !state->allow_wcard_last_component) {
1205 /* Wildcard not valid anywhere. */
1206 status = NT_STATUS_OBJECT_NAME_INVALID;
1207 goto fail;
1211 DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
1212 state->smb_fname->base_name, state->dirpath, state->name);
1214 if (!state->name_has_wildcard) {
1215 int parent_stat_errno = 0;
1218 * stat the name - if it exists then we can add the stream back (if
1219 * there was one) and be done!
1222 ret = vfs_stat(state->conn, state->smb_fname);
1223 if (ret == 0) {
1224 status = check_for_dot_component(state->smb_fname);
1225 if (!NT_STATUS_IS_OK(status)) {
1226 goto fail;
1228 /* Add the path (not including the stream) to the cache. */
1229 stat_cache_add(state->orig_path,
1230 state->smb_fname->base_name,
1231 state->smb_fname->twrp,
1232 state->case_sensitive);
1233 DBG_DEBUG("Conversion of base_name finished "
1234 "[%s] -> [%s]\n",
1235 state->orig_path, state->smb_fname->base_name);
1236 goto done;
1239 /* Stat failed - ensure we don't use it. */
1240 SET_STAT_INVALID(state->smb_fname->st);
1243 * Note: we must continue processing a path if we get EACCES
1244 * from stat. With NFS4 permissions the file might be lacking
1245 * READ_ATTR, but if the parent has LIST permissions we can
1246 * resolve the path in the path traversal loop down below.
1249 if (errno == ENOENT) {
1250 /* Optimization when creating a new file - only
1251 the last component doesn't exist.
1252 NOTE : check_parent_exists() doesn't preserve errno.
1254 int saved_errno = errno;
1255 status = check_parent_exists(state->mem_ctx,
1256 state->conn,
1257 state->posix_pathnames,
1258 state->smb_fname,
1259 &state->dirpath,
1260 &state->name,
1261 &parent_stat_errno);
1262 errno = saved_errno;
1263 if (!NT_STATUS_IS_OK(status)) {
1264 goto fail;
1269 * A special case - if we don't have any wildcards or mangling chars and are case
1270 * sensitive or the underlying filesystem is case insensitive then searching
1271 * won't help.
1273 * NB. As POSIX sets state->case_sensitive as
1274 * true we will never call into mangle_is_mangled() here.
1277 if ((state->case_sensitive || !(state->conn->fs_capabilities &
1278 FILE_CASE_SENSITIVE_SEARCH)) &&
1279 !mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
1281 status = check_for_dot_component(state->smb_fname);
1282 if (!NT_STATUS_IS_OK(status)) {
1283 goto fail;
1287 * The stat failed. Could be ok as it could be
1288 * a new file.
1291 if (errno == ENOTDIR || errno == ELOOP) {
1292 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1293 goto fail;
1294 } else if (errno == ENOENT) {
1296 * Was it a missing last component ?
1297 * or a missing intermediate component ?
1299 * Optimization.
1301 * For this code path we can guarantee that
1302 * we have gone through check_parent_exists()
1303 * and it returned NT_STATUS_OK.
1305 * Either there was no parent component (".")
1306 * parent_stat_errno == 0 and we have a missing
1307 * last component here.
1309 * OR check_parent_exists() called STAT/LSTAT
1310 * and if it failed parent_stat_errno has been
1311 * set telling us if the parent existed or not.
1313 * Either way we can avoid another STAT/LSTAT
1314 * system call on the parent here.
1316 if (parent_stat_errno == ENOTDIR ||
1317 parent_stat_errno == ENOENT ||
1318 parent_stat_errno == ELOOP) {
1319 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1320 goto fail;
1324 * Missing last component is ok - new file.
1325 * Also deal with permission denied elsewhere.
1326 * Just drop out to done.
1328 goto done;
1331 } else {
1333 * We have a wildcard in the pathname.
1335 * Optimization for common case where the wildcard
1336 * is in the last component and the client already
1337 * sent the correct case.
1338 * NOTE : check_parent_exists() doesn't preserve errno.
1340 int saved_errno = errno;
1341 status = check_parent_exists(state->mem_ctx,
1342 state->conn,
1343 state->posix_pathnames,
1344 state->smb_fname,
1345 &state->dirpath,
1346 &state->name,
1347 NULL);
1348 errno = saved_errno;
1349 if (!NT_STATUS_IS_OK(status)) {
1350 goto fail;
1355 * is_mangled() was changed to look at an entire pathname, not
1356 * just a component. JRA.
1359 if (state->posix_pathnames) {
1361 * POSIX names are never mangled and we must not
1362 * call into mangling functions.
1364 state->component_was_mangled = false;
1365 } else if (mangle_is_mangled(state->name, state->conn->params)) {
1366 state->component_was_mangled = true;
1370 * Now we need to recursively match the name against the real
1371 * directory structure.
1375 * Match each part of the path name separately, trying the names
1376 * as is first, then trying to scan the directory for matching names.
1379 for (; state->name ; state->name = (state->end ? state->end + 1:(char *)NULL)) {
1380 status = unix_convert_step(state);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
1383 goto err;
1385 goto fail;
1387 if (state->done) {
1388 goto done;
1393 * Cache the full path. Don't cache a name with mangled or wildcard
1394 * components as this can change the size.
1397 if(!state->component_was_mangled && !state->name_has_wildcard) {
1398 stat_cache_add(state->orig_path,
1399 state->smb_fname->base_name,
1400 state->smb_fname->twrp,
1401 state->case_sensitive);
1405 * The name has been resolved.
1408 done:
1409 /* Add back the stream if one was stripped off originally. */
1410 if (state->stream != NULL) {
1411 state->smb_fname->stream_name = state->stream;
1413 /* Check path now that the base_name has been converted. */
1414 status = build_stream_path(state->mem_ctx, state->conn, state->smb_fname);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 goto fail;
1420 DBG_DEBUG("Conversion finished [%s] -> [%s]\n",
1421 state->orig_path, smb_fname_str_dbg(state->smb_fname));
1423 TALLOC_FREE(state->dirpath);
1424 *smb_fname_out = state->smb_fname;
1425 return NT_STATUS_OK;
1426 fail:
1427 DBG_DEBUG("Conversion failed: dirpath [%s] name [%s]\n",
1428 state->dirpath, state->name);
1429 if ((state->dirpath != NULL) && !ISDOT(state->dirpath)) {
1430 state->smb_fname->base_name = talloc_asprintf(
1431 state->smb_fname,
1432 "%s/%s",
1433 state->dirpath,
1434 state->name);
1435 } else {
1436 state->smb_fname->base_name = talloc_strdup(
1437 state->smb_fname, state->name);
1439 if (state->smb_fname->base_name == NULL) {
1440 DBG_ERR("talloc_asprintf failed\n");
1441 status = NT_STATUS_NO_MEMORY;
1442 goto err;
1445 *smb_fname_out = state->smb_fname;
1446 TALLOC_FREE(state->dirpath);
1447 return status;
1448 err:
1449 TALLOC_FREE(state->smb_fname);
1450 return status;
1453 /****************************************************************************
1454 Ensure a path is not vetoed.
1455 ****************************************************************************/
1457 static NTSTATUS check_veto_path(connection_struct *conn,
1458 const struct smb_filename *smb_fname)
1460 const char *name = smb_fname->base_name;
1462 if (IS_VETO_PATH(conn, name)) {
1463 /* Is it not dot or dot dot. */
1464 if (!(ISDOT(name) || ISDOTDOT(name))) {
1465 DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1466 name));
1467 return map_nt_error_from_unix(ENOENT);
1470 return NT_STATUS_OK;
1473 /****************************************************************************
1474 Check a filename - possibly calling check_reduced_name.
1475 This is called by every routine before it allows an operation on a filename.
1476 It does any final confirmation necessary to ensure that the filename is
1477 a valid one for the user to access.
1478 ****************************************************************************/
1480 static NTSTATUS check_name(connection_struct *conn,
1481 const struct smb_filename *smb_fname)
1483 NTSTATUS status = check_veto_path(conn, smb_fname);
1485 if (!NT_STATUS_IS_OK(status)) {
1486 return status;
1489 if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1490 status = check_reduced_name(conn, NULL, smb_fname);
1491 if (!NT_STATUS_IS_OK(status)) {
1492 DEBUG(5,("check_name: name %s failed with %s\n",
1493 smb_fname->base_name,
1494 nt_errstr(status)));
1495 return status;
1499 return NT_STATUS_OK;
1502 /****************************************************************************
1503 Check if two filenames are equal.
1504 This needs to be careful about whether we are case sensitive.
1505 ****************************************************************************/
1507 static bool fname_equal(const char *name1, const char *name2,
1508 bool case_sensitive)
1510 /* Normal filename handling */
1511 if (case_sensitive) {
1512 return(strcmp(name1,name2) == 0);
1515 return(strequal(name1,name2));
1518 static bool sname_equal(const char *name1, const char *name2,
1519 bool case_sensitive)
1521 bool match;
1522 const char *s1 = NULL;
1523 const char *s2 = NULL;
1524 size_t n1;
1525 size_t n2;
1526 const char *e1 = NULL;
1527 const char *e2 = NULL;
1528 char *c1 = NULL;
1529 char *c2 = NULL;
1531 match = fname_equal(name1, name2, case_sensitive);
1532 if (match) {
1533 return true;
1536 if (name1[0] != ':') {
1537 return false;
1539 if (name2[0] != ':') {
1540 return false;
1542 s1 = &name1[1];
1543 e1 = strchr(s1, ':');
1544 if (e1 == NULL) {
1545 n1 = strlen(s1);
1546 } else {
1547 n1 = PTR_DIFF(e1, s1);
1549 s2 = &name2[1];
1550 e2 = strchr(s2, ':');
1551 if (e2 == NULL) {
1552 n2 = strlen(s2);
1553 } else {
1554 n2 = PTR_DIFF(e2, s2);
1557 /* Normal filename handling */
1558 if (case_sensitive) {
1559 return (strncmp(s1, s2, n1) == 0);
1563 * We can't use strnequal() here
1564 * as it takes the number of codepoints
1565 * and not the number of bytes.
1567 * So we make a copy before calling
1568 * strequal().
1570 * Note that we TALLOC_FREE() in reverse order
1571 * in order to avoid memory fragmentation.
1574 c1 = talloc_strndup(talloc_tos(), s1, n1);
1575 c2 = talloc_strndup(talloc_tos(), s2, n2);
1576 if (c1 == NULL || c2 == NULL) {
1577 TALLOC_FREE(c2);
1578 TALLOC_FREE(c1);
1579 return (strncmp(s1, s2, n1) == 0);
1582 match = strequal(c1, c2);
1583 TALLOC_FREE(c2);
1584 TALLOC_FREE(c1);
1585 return match;
1588 /****************************************************************************
1589 Scan a directory to find a filename, matching without case sensitivity.
1590 If the name looks like a mangled name then try via the mangling functions
1591 ****************************************************************************/
1593 int get_real_filename_full_scan(connection_struct *conn,
1594 const char *path,
1595 const char *name,
1596 bool mangled,
1597 TALLOC_CTX *mem_ctx,
1598 char **found_name)
1600 struct smb_Dir *cur_dir;
1601 const char *dname = NULL;
1602 char *talloced = NULL;
1603 char *unmangled_name = NULL;
1604 long curpos;
1605 struct smb_filename *smb_fname = NULL;
1607 /* handle null paths */
1608 if ((path == NULL) || (*path == 0)) {
1609 path = ".";
1612 /* If we have a case-sensitive filesystem, it doesn't do us any
1613 * good to search for a name. If a case variation of the name was
1614 * there, then the original stat(2) would have found it.
1616 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1617 errno = ENOENT;
1618 return -1;
1622 * The incoming name can be mangled, and if we de-mangle it
1623 * here it will not compare correctly against the filename (name2)
1624 * read from the directory and then mangled by the name_to_8_3()
1625 * call. We need to mangle both names or neither.
1626 * (JRA).
1628 * Fix for bug found by Dina Fine. If in case sensitive mode then
1629 * the mangle cache is no good (3 letter extension could be wrong
1630 * case - so don't demangle in this case - leave as mangled and
1631 * allow the mangling of the directory entry read (which is done
1632 * case insensitively) to match instead. This will lead to more
1633 * false positive matches but we fail completely without it. JRA.
1636 if (mangled && !conn->case_sensitive) {
1637 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1638 &unmangled_name,
1639 conn->params);
1640 if (!mangled) {
1641 /* Name is now unmangled. */
1642 name = unmangled_name;
1646 smb_fname = synthetic_smb_fname(talloc_tos(),
1647 path,
1648 NULL,
1649 NULL,
1652 if (smb_fname == NULL) {
1653 TALLOC_FREE(unmangled_name);
1654 return -1;
1657 /* open the directory */
1658 if (!(cur_dir = OpenDir(talloc_tos(), conn, smb_fname, NULL, 0))) {
1659 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1660 TALLOC_FREE(unmangled_name);
1661 TALLOC_FREE(smb_fname);
1662 return -1;
1665 TALLOC_FREE(smb_fname);
1667 /* now scan for matching names */
1668 curpos = 0;
1669 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1671 /* Is it dot or dot dot. */
1672 if (ISDOT(dname) || ISDOTDOT(dname)) {
1673 TALLOC_FREE(talloced);
1674 continue;
1678 * At this point dname is the unmangled name.
1679 * name is either mangled or not, depending on the state
1680 * of the "mangled" variable. JRA.
1684 * Check mangled name against mangled name, or unmangled name
1685 * against unmangled name.
1688 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1689 fname_equal(name, dname, conn->case_sensitive)) {
1690 /* we've found the file, change it's name and return */
1691 *found_name = talloc_strdup(mem_ctx, dname);
1692 TALLOC_FREE(unmangled_name);
1693 TALLOC_FREE(cur_dir);
1694 if (!*found_name) {
1695 errno = ENOMEM;
1696 TALLOC_FREE(talloced);
1697 return -1;
1699 TALLOC_FREE(talloced);
1700 return 0;
1702 TALLOC_FREE(talloced);
1705 TALLOC_FREE(unmangled_name);
1706 TALLOC_FREE(cur_dir);
1707 errno = ENOENT;
1708 return -1;
1711 /****************************************************************************
1712 Wrapper around the vfs get_real_filename and the full directory scan
1713 fallback.
1714 ****************************************************************************/
1716 static int get_real_filename(connection_struct *conn,
1717 struct smb_filename *path,
1718 const char *name,
1719 TALLOC_CTX *mem_ctx,
1720 char **found_name)
1722 int ret;
1723 bool mangled;
1725 mangled = mangle_is_mangled(name, conn->params);
1727 if (mangled) {
1728 return get_real_filename_full_scan(conn,
1729 path->base_name,
1730 name,
1731 mangled,
1732 mem_ctx,
1733 found_name);
1736 /* Try the vfs first to take advantage of case-insensitive stat. */
1737 ret = SMB_VFS_GET_REAL_FILENAME(conn,
1738 path,
1739 name,
1740 mem_ctx,
1741 found_name);
1744 * If the case-insensitive stat was successful, or returned an error
1745 * other than EOPNOTSUPP then there is no need to fall back on the
1746 * full directory scan.
1748 if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1749 return ret;
1752 return get_real_filename_full_scan(conn,
1753 path->base_name,
1754 name,
1755 mangled,
1756 mem_ctx,
1757 found_name);
1760 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1761 connection_struct *conn,
1762 struct smb_filename *smb_fname)
1764 NTSTATUS status;
1765 unsigned int i, num_streams = 0;
1766 struct stream_struct *streams = NULL;
1767 struct smb_filename *pathref = NULL;
1769 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1770 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1771 return NT_STATUS_OK;
1774 if (errno != ENOENT) {
1775 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1776 status = map_nt_error_from_unix(errno);
1777 goto fail;
1780 if (smb_fname->fsp == NULL) {
1781 status = synthetic_pathref(mem_ctx,
1782 conn->cwd_fsp,
1783 smb_fname->base_name,
1784 NULL,
1785 NULL,
1786 smb_fname->twrp,
1787 smb_fname->flags,
1788 &pathref);
1789 if (!NT_STATUS_IS_OK(status)) {
1790 if (NT_STATUS_EQUAL(status,
1791 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1792 TALLOC_FREE(pathref);
1793 SET_STAT_INVALID(smb_fname->st);
1794 return NT_STATUS_OK;
1796 DBG_DEBUG("synthetic_pathref failed: %s\n",
1797 nt_errstr(status));
1798 goto fail;
1800 } else {
1801 pathref = smb_fname;
1804 /* Fall back to a case-insensitive scan of all streams on the file. */
1805 status = vfs_fstreaminfo(pathref->fsp, mem_ctx,
1806 &num_streams, &streams);
1807 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1808 SET_STAT_INVALID(smb_fname->st);
1809 TALLOC_FREE(pathref);
1810 return NT_STATUS_OK;
1813 if (!NT_STATUS_IS_OK(status)) {
1814 DEBUG(10, ("vfs_fstreaminfo failed: %s\n", nt_errstr(status)));
1815 goto fail;
1818 for (i=0; i<num_streams; i++) {
1819 DEBUG(10, ("comparing [%s] and [%s]: ",
1820 smb_fname->stream_name, streams[i].name));
1821 if (sname_equal(smb_fname->stream_name, streams[i].name,
1822 conn->case_sensitive)) {
1823 DEBUGADD(10, ("equal\n"));
1824 break;
1826 DEBUGADD(10, ("not equal\n"));
1829 /* Couldn't find the stream. */
1830 if (i == num_streams) {
1831 SET_STAT_INVALID(smb_fname->st);
1832 TALLOC_FREE(pathref);
1833 TALLOC_FREE(streams);
1834 return NT_STATUS_OK;
1837 DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1838 smb_fname->stream_name, streams[i].name));
1841 TALLOC_FREE(smb_fname->stream_name);
1842 smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1843 if (smb_fname->stream_name == NULL) {
1844 status = NT_STATUS_NO_MEMORY;
1845 goto fail;
1848 SET_STAT_INVALID(smb_fname->st);
1850 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1851 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1853 status = NT_STATUS_OK;
1854 fail:
1855 TALLOC_FREE(pathref);
1856 TALLOC_FREE(streams);
1857 return status;
1861 * Lightweight function to just get last component
1862 * for rename / enumerate directory calls.
1865 char *get_original_lcomp(TALLOC_CTX *ctx,
1866 connection_struct *conn,
1867 const char *filename_in,
1868 uint32_t ucf_flags)
1870 struct smb_filename *smb_fname = NULL;
1871 char *last_slash = NULL;
1872 char *orig_lcomp;
1873 char *fname = NULL;
1874 NTSTATUS status;
1876 if (ucf_flags & UCF_DFS_PATHNAME) {
1877 status = dfs_redirect(ctx,
1878 conn,
1879 filename_in,
1880 ucf_flags,
1881 !conn->sconn->using_smb2,
1882 &fname);
1883 if (!NT_STATUS_IS_OK(status)) {
1884 DBG_DEBUG("dfs_redirect "
1885 "failed for name %s with %s\n",
1886 filename_in,
1887 nt_errstr(status));
1888 return NULL;
1890 filename_in = fname;
1891 ucf_flags &= ~UCF_DFS_PATHNAME;
1895 * NB. We don't need to care about
1896 * is_fake_file_path(filename_in) here as these
1897 * code paths don't ever return original_lcomp
1898 * or use it anyway.
1901 if (ucf_flags & UCF_GMT_PATHNAME) {
1903 * Ensure we don't return a @GMT
1904 * value as the last component.
1906 smb_fname = synthetic_smb_fname(ctx,
1907 filename_in,
1908 NULL,
1909 NULL,
1912 if (smb_fname == NULL) {
1913 TALLOC_FREE(fname);
1914 return NULL;
1916 status = canonicalize_snapshot_path(smb_fname,
1917 ucf_flags,
1919 if (!NT_STATUS_IS_OK(status)) {
1920 TALLOC_FREE(fname);
1921 TALLOC_FREE(smb_fname);
1922 return NULL;
1924 filename_in = smb_fname->base_name;
1926 last_slash = strrchr(filename_in, '/');
1927 if (last_slash != NULL) {
1928 orig_lcomp = talloc_strdup(ctx, last_slash+1);
1929 } else {
1930 orig_lcomp = talloc_strdup(ctx, filename_in);
1932 /* We're done with any temp names here. */
1933 TALLOC_FREE(smb_fname);
1934 TALLOC_FREE(fname);
1935 if (orig_lcomp == NULL) {
1936 return NULL;
1938 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 TALLOC_FREE(orig_lcomp);
1941 return NULL;
1943 return orig_lcomp;
1947 * Go through all the steps to validate a filename.
1949 * @param ctx talloc_ctx to allocate memory with.
1950 * @param conn connection struct for vfs calls.
1951 * @param smbreq SMB request if we're using privileges.
1952 * @param name_in The unconverted name.
1953 * @param ucf_flags flags to pass through to unix_convert().
1954 * @param twrp Optional VSS time
1955 * @param p_cont_wcard If not NULL, will be set to true if the dfs path
1956 * resolution detects a wildcard.
1957 * @param _smb_fname The final converted name will be allocated if the
1958 * return is NT_STATUS_OK.
1960 * @return NT_STATUS_OK if all operations completed successfully, appropriate
1961 * error otherwise.
1963 static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
1964 connection_struct *conn,
1965 struct smb_request *smbreq,
1966 const char *name_in,
1967 uint32_t ucf_flags,
1968 NTTIME twrp,
1969 struct smb_filename **_smb_fname)
1971 struct smb_filename *smb_fname = NULL;
1972 bool has_wild;
1973 NTSTATUS status;
1975 *_smb_fname = NULL;
1977 if (ucf_flags & UCF_DFS_PATHNAME) {
1978 char *fname = NULL;
1979 status = dfs_redirect(ctx, conn,
1980 name_in,
1981 ucf_flags,
1982 !conn->sconn->using_smb2,
1983 &fname);
1984 if (!NT_STATUS_IS_OK(status)) {
1985 DEBUG(10,("filename_convert_internal: dfs_redirect "
1986 "failed for name %s with %s\n",
1987 name_in,
1988 nt_errstr(status) ));
1989 return status;
1991 name_in = fname;
1992 ucf_flags &= ~UCF_DFS_PATHNAME;
1995 if (is_fake_file_path(name_in)) {
1996 smb_fname = synthetic_smb_fname_split(ctx,
1997 name_in,
1998 (ucf_flags & UCF_POSIX_PATHNAMES));
1999 if (smb_fname == NULL) {
2000 return NT_STATUS_NO_MEMORY;
2002 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
2003 smb_fname->st.st_ex_btime = (struct timespec){0, SAMBA_UTIME_OMIT};
2004 smb_fname->st.st_ex_atime = (struct timespec){0, SAMBA_UTIME_OMIT};
2005 smb_fname->st.st_ex_mtime = (struct timespec){0, SAMBA_UTIME_OMIT};
2006 smb_fname->st.st_ex_ctime = (struct timespec){0, SAMBA_UTIME_OMIT};
2008 *_smb_fname = smb_fname;
2009 return NT_STATUS_OK;
2012 status = unix_convert(ctx, conn, name_in, twrp, &smb_fname, ucf_flags);
2013 if (!NT_STATUS_IS_OK(status)) {
2014 DEBUG(10,("filename_convert_internal: unix_convert failed "
2015 "for name %s with %s\n",
2016 name_in,
2017 nt_errstr(status) ));
2018 return status;
2021 if ((ucf_flags & UCF_POSIX_PATHNAMES) &&
2022 VALID_STAT(smb_fname->st) &&
2023 S_ISLNK(smb_fname->st.st_ex_mode))
2025 status = check_veto_path(conn, smb_fname);
2026 if (!NT_STATUS_IS_OK(status)) {
2027 TALLOC_FREE(smb_fname);
2028 return status;
2030 } else {
2031 status = check_name(conn, smb_fname);
2033 if (!NT_STATUS_IS_OK(status)) {
2034 DEBUG(3,("filename_convert_internal: check_name failed "
2035 "for name %s with %s\n",
2036 smb_fname_str_dbg(smb_fname),
2037 nt_errstr(status) ));
2038 TALLOC_FREE(smb_fname);
2039 return status;
2042 has_wild = ms_has_wild(name_in);
2043 if (has_wild) {
2044 DBG_DEBUG("[%s] contains wildcard, skipping pathref fsp\n",
2045 name_in);
2046 *_smb_fname = smb_fname;
2047 return NT_STATUS_OK;
2050 if (!VALID_STAT(smb_fname->st)) {
2051 DBG_DEBUG("[%s] does not exist, skipping pathref fsp\n",
2052 smb_fname_str_dbg(smb_fname));
2053 *_smb_fname = smb_fname;
2054 return NT_STATUS_OK;
2057 status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
2058 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2060 * We deal with symlinks here as we do in
2061 * SMB_VFS_CREATE_FILE(): return success for POSIX clients with
2062 * the notable difference that there will be no fsp in
2063 * smb_fname->fsp.
2065 * For Windows (non POSIX) clients fail with
2066 * NT_STATUS_OBJECT_NAME_NOT_FOUND.
2068 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH &&
2069 S_ISLNK(smb_fname->st.st_ex_mode))
2071 status = NT_STATUS_OK;
2074 if (!NT_STATUS_IS_OK(status)) {
2075 DBG_DEBUG("open_pathref_fsp [%s] failed: %s\n",
2076 smb_fname_str_dbg(smb_fname),
2077 nt_errstr(status));
2078 return status;
2081 *_smb_fname = smb_fname;
2082 return status;
2086 * Go through all the steps to validate a filename.
2087 * Non-root version.
2090 NTSTATUS filename_convert(TALLOC_CTX *ctx,
2091 connection_struct *conn,
2092 const char *name_in,
2093 uint32_t ucf_flags,
2094 NTTIME twrp,
2095 struct smb_filename **pp_smb_fname)
2097 return filename_convert_internal(ctx,
2098 conn,
2099 NULL,
2100 name_in,
2101 ucf_flags,
2102 twrp,
2103 pp_smb_fname);
2107 * Build the full path from a dirfsp and dirfsp relative name
2109 struct smb_filename *full_path_from_dirfsp_atname(
2110 TALLOC_CTX *mem_ctx,
2111 const struct files_struct *dirfsp,
2112 const struct smb_filename *atname)
2114 struct smb_filename *fname = NULL;
2115 char *path = NULL;
2117 if (dirfsp == dirfsp->conn->cwd_fsp ||
2118 ISDOT(dirfsp->fsp_name->base_name) ||
2119 atname->base_name[0] == '/')
2121 path = talloc_strdup(mem_ctx, atname->base_name);
2122 } else {
2123 path = talloc_asprintf(mem_ctx, "%s/%s",
2124 dirfsp->fsp_name->base_name,
2125 atname->base_name);
2127 if (path == NULL) {
2128 return NULL;
2131 fname = synthetic_smb_fname(mem_ctx,
2132 path,
2133 atname->stream_name,
2134 &atname->st,
2135 atname->twrp,
2136 atname->flags);
2137 TALLOC_FREE(path);
2138 if (fname == NULL) {
2139 return NULL;
2142 return fname;