tests/krb5: Clarify checksum type assertion message
[Samba.git] / source3 / smbd / filename.c
blobdb23fe405879526247d4fb03395d516754ef6176
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 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
35 uint32_t ucf_flags = 0;
37 if (req != NULL) {
38 if (req->posix_pathnames) {
39 ucf_flags |= UCF_POSIX_PATHNAMES;
41 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
42 ucf_flags |= UCF_DFS_PATHNAME;
44 if (req->flags2 & FLAGS2_REPARSE_PATH) {
45 ucf_flags |= UCF_GMT_PATHNAME;
49 return ucf_flags;
52 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
54 uint32_t ucf_flags = 0;
56 ucf_flags |= ucf_flags_from_smb_request(req);
58 switch (create_disposition) {
59 case FILE_OPEN:
60 case FILE_OVERWRITE:
61 break;
62 case FILE_SUPERSEDE:
63 case FILE_CREATE:
64 case FILE_OPEN_IF:
65 case FILE_OVERWRITE_IF:
66 ucf_flags |= UCF_PREP_CREATEFILE;
67 break;
70 return ucf_flags;
73 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
74 connection_struct *conn,
75 struct smb_filename *smb_fname);
77 /****************************************************************************
78 Mangle the 2nd name and check if it is then equal to the first name.
79 ****************************************************************************/
81 static bool mangled_equal(const char *name1,
82 const char *name2,
83 const struct share_params *p)
85 char mname[13];
87 if (!name_to_8_3(name2, mname, False, p)) {
88 return False;
90 return strequal(name1, mname);
93 /****************************************************************************
94 Cope with the differing wildcard and non-wildcard error cases.
95 ****************************************************************************/
97 static NTSTATUS determine_path_error(const char *name,
98 bool allow_wcard_last_component,
99 bool posix_pathnames)
101 const char *p;
102 bool name_has_wild = false;
104 if (!allow_wcard_last_component) {
105 /* Error code within a pathname. */
106 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
109 /* We're terminating here so we
110 * can be a little slower and get
111 * the error code right. Windows
112 * treats the last part of the pathname
113 * separately I think, so if the last
114 * component is a wildcard then we treat
115 * this ./ as "end of component" */
117 p = strchr(name, '/');
119 if (!posix_pathnames) {
120 name_has_wild = ms_has_wild(name);
123 if (!p && (name_has_wild || ISDOT(name))) {
124 /* Error code at the end of a pathname. */
125 return NT_STATUS_OBJECT_NAME_INVALID;
126 } else {
127 /* Error code within a pathname. */
128 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
132 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
134 /* Ensure we catch all names with in "/."
135 this is disallowed under Windows and
136 in POSIX they've already been removed. */
137 const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
138 if (p) {
139 if (p[2] == '/') {
140 /* Error code within a pathname. */
141 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
142 } else if (p[2] == '\0') {
143 /* Error code at the end of a pathname. */
144 return NT_STATUS_OBJECT_NAME_INVALID;
147 return NT_STATUS_OK;
150 /****************************************************************************
151 Optimization for common case where the missing part
152 is in the last component and the client already
153 sent the correct case.
154 Returns NT_STATUS_OK to mean continue the tree walk
155 (possibly with modified start pointer).
156 Any other NT_STATUS_XXX error means terminate the path
157 lookup here.
158 ****************************************************************************/
160 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
161 connection_struct *conn,
162 bool posix_pathnames,
163 const struct smb_filename *smb_fname,
164 char **pp_dirpath,
165 char **pp_start)
167 char *parent_name = NULL;
168 struct smb_filename *parent_fname = NULL;
169 const char *last_component = NULL;
170 NTSTATUS status;
171 int ret;
173 if (!parent_dirname(ctx, smb_fname->base_name,
174 &parent_name,
175 &last_component)) {
176 return NT_STATUS_NO_MEMORY;
179 if (!posix_pathnames) {
180 if (ms_has_wild(parent_name)) {
181 goto no_optimization_out;
186 * If there was no parent component in
187 * smb_fname->base_name then don't do this
188 * optimization.
190 if (smb_fname->base_name == last_component) {
191 goto no_optimization_out;
194 parent_fname = synthetic_smb_fname(ctx,
195 parent_name,
196 NULL,
197 NULL,
198 smb_fname->twrp,
199 smb_fname->flags);
200 if (parent_fname == NULL) {
201 return NT_STATUS_NO_MEMORY;
204 if (posix_pathnames) {
205 ret = SMB_VFS_LSTAT(conn, parent_fname);
206 } else {
207 ret = SMB_VFS_STAT(conn, parent_fname);
210 /* If the parent stat failed, just continue
211 with the normal tree walk. */
213 if (ret == -1) {
214 goto no_optimization_out;
217 status = check_for_dot_component(parent_fname);
218 if (!NT_STATUS_IS_OK(status)) {
219 return status;
222 /* Parent exists - set "start" to be the
223 * last component to shorten the tree walk. */
226 * Safe to use discard_const_p
227 * here as last_component points
228 * into our smb_fname->base_name.
230 *pp_start = discard_const_p(char, last_component);
232 /* Update dirpath. */
233 TALLOC_FREE(*pp_dirpath);
234 *pp_dirpath = talloc_strdup(ctx, parent_fname->base_name);
235 if (!*pp_dirpath) {
236 return NT_STATUS_NO_MEMORY;
239 DEBUG(5,("check_parent_exists: name "
240 "= %s, dirpath = %s, "
241 "start = %s\n",
242 smb_fname->base_name,
243 *pp_dirpath,
244 *pp_start));
246 return NT_STATUS_OK;
248 no_optimization_out:
251 * We must still return an *pp_dirpath
252 * initialized to ".", and a *pp_start
253 * pointing at smb_fname->base_name.
256 TALLOC_FREE(parent_name);
257 TALLOC_FREE(parent_fname);
259 *pp_dirpath = talloc_strdup(ctx, ".");
260 if (*pp_dirpath == NULL) {
261 return NT_STATUS_NO_MEMORY;
264 * Safe to use discard_const_p
265 * here as by convention smb_fname->base_name
266 * is allocated off ctx.
268 *pp_start = discard_const_p(char, smb_fname->base_name);
269 return NT_STATUS_OK;
273 * Re-order a known good @GMT-token path.
276 static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
277 char *startp,
278 char *endp)
280 size_t endlen = 0;
281 size_t gmt_len = endp - startp;
282 char gmt_store[gmt_len + 1];
283 char *parent = NULL;
284 const char *last_component = NULL;
285 char *newstr;
286 bool ret;
288 DBG_DEBUG("|%s| -> ", smb_fname->base_name);
290 /* Save off the @GMT-token. */
291 memcpy(gmt_store, startp, gmt_len);
292 gmt_store[gmt_len] = '\0';
294 if (*endp == '/') {
295 /* Remove any trailing '/' */
296 endp++;
299 if (*endp == '\0') {
301 * @GMT-token was at end of path.
302 * Remove any preceding '/'
304 if (startp > smb_fname->base_name && startp[-1] == '/') {
305 startp--;
309 /* Remove @GMT-token from the path. */
310 endlen = strlen(endp);
311 memmove(startp, endp, endlen + 1);
313 /* Split the remaining path into components. */
314 ret = parent_dirname(smb_fname,
315 smb_fname->base_name,
316 &parent,
317 &last_component);
318 if (ret == false) {
319 /* Must terminate debug with \n */
320 DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
321 return NT_STATUS_NO_MEMORY;
324 if (ISDOT(parent)) {
325 if (last_component[0] == '\0') {
326 newstr = talloc_strdup(smb_fname,
327 gmt_store);
328 } else {
329 newstr = talloc_asprintf(smb_fname,
330 "%s/%s",
331 gmt_store,
332 last_component);
334 } else {
335 newstr = talloc_asprintf(smb_fname,
336 "%s/%s/%s",
337 gmt_store,
338 parent,
339 last_component);
342 TALLOC_FREE(parent);
343 TALLOC_FREE(smb_fname->base_name);
344 smb_fname->base_name = newstr;
346 DBG_DEBUG("|%s|\n", newstr);
348 return NT_STATUS_OK;
352 * Strip a valid @GMT-token from any incoming filename path,
353 * adding any NTTIME encoded in the pathname into the
354 * twrp field of the passed in smb_fname.
356 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
357 * at the *start* of a pathname component.
359 * If twrp is passed in then smb_fname->twrp is set to that
360 * value, and the @GMT-token part of the filename is removed
361 * and does not change the stored smb_fname->twrp.
365 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
366 uint32_t ucf_flags,
367 NTTIME twrp)
369 char *startp = NULL;
370 char *endp = NULL;
371 char *tmp = NULL;
372 struct tm tm;
373 time_t t;
374 NTTIME nt;
375 NTSTATUS status;
377 if (twrp != 0) {
378 smb_fname->twrp = twrp;
381 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
382 return NT_STATUS_OK;
385 startp = strchr_m(smb_fname->base_name, '@');
386 if (startp == NULL) {
387 /* No @ */
388 return NT_STATUS_OK;
391 startp = strstr_m(startp, "@GMT-");
392 if (startp == NULL) {
393 /* No @ */
394 return NT_STATUS_OK;
397 if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
398 /* the GMT-token does not start a path-component */
399 return NT_STATUS_OK;
402 endp = strptime(startp, GMT_FORMAT, &tm);
403 if (endp == NULL) {
404 /* Not a valid timestring. */
405 return NT_STATUS_OK;
408 if (endp[0] != '\0' && endp[0] != '/') {
410 * It is not a complete path component, i.e. the path
411 * component continues after the gmt-token.
413 return NT_STATUS_OK;
416 status = rearrange_snapshot_path(smb_fname, startp, endp);
417 if (!NT_STATUS_IS_OK(status)) {
418 return status;
421 startp = smb_fname->base_name + GMT_NAME_LEN;
422 if (startp[0] == '/') {
423 startp++;
426 tmp = talloc_strdup(smb_fname, startp);
427 if (tmp == NULL) {
428 return NT_STATUS_NO_MEMORY;
431 TALLOC_FREE(smb_fname->base_name);
432 smb_fname->base_name = tmp;
434 if (smb_fname->twrp == 0) {
435 tm.tm_isdst = -1;
436 t = timegm(&tm);
437 unix_to_nt_time(&nt, t);
438 smb_fname->twrp = nt;
441 return NT_STATUS_OK;
445 * Utility function to normalize case on an incoming client filename
446 * if required on this connection struct.
447 * Performs an in-place case conversion guaranteed to stay the same size.
450 static NTSTATUS normalize_filename_case(connection_struct *conn, char *filename)
452 bool ok;
454 if (!conn->case_sensitive) {
455 return NT_STATUS_OK;
457 if (conn->case_preserve) {
458 return NT_STATUS_OK;
460 if (conn->short_case_preserve) {
461 return NT_STATUS_OK;
463 ok = strnorm(filename, lp_default_case(SNUM(conn)));
464 if (!ok) {
465 return NT_STATUS_INVALID_PARAMETER;
467 return NT_STATUS_OK;
470 /****************************************************************************
471 This routine is called to convert names from the dos namespace to unix
472 namespace. It needs to handle any case conversions, mangling, format changes,
473 streams etc.
475 We assume that we have already done a chdir() to the right "root" directory
476 for this service.
478 Conversion to basic unix format is already done in check_path_syntax().
480 Names must be relative to the root of the service - any leading /. and
481 trailing /'s should have been trimmed by check_path_syntax().
483 The function will return an NTSTATUS error if some part of the name except for
484 the last part cannot be resolved, else NT_STATUS_OK.
486 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
487 didn't get any fatal errors that should immediately terminate the calling SMB
488 processing whilst resolving.
490 If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected
491 and should be allowed in the last component of the path only.
493 If the orig_path was a stream, smb_filename->base_name will point to the base
494 filename, and smb_filename->stream_name will point to the stream name. If
495 orig_path was not a stream, then smb_filename->stream_name will be NULL.
497 On exit from unix_convert, the smb_filename->st stat struct will be populated
498 if the file exists and was found, if not this stat struct will be filled with
499 zeros (and this can be detected by checking for nlinks = 0, which can never be
500 true for any file).
501 ****************************************************************************/
503 struct uc_state {
504 TALLOC_CTX *mem_ctx;
505 struct connection_struct *conn;
506 struct smb_filename *smb_fname;
507 const char *orig_path;
508 uint32_t ucf_flags;
509 char *name;
510 char *end;
511 char *dirpath;
512 char *stream;
513 bool component_was_mangled;
514 bool name_has_wildcard;
515 bool posix_pathnames;
516 bool allow_wcard_last_component;
517 bool done;
520 static NTSTATUS unix_convert_step_search_fail(struct uc_state *state)
522 char *unmangled;
524 if (state->end) {
526 * An intermediate part of the name
527 * can't be found.
529 DBG_DEBUG("Intermediate [%s] missing\n",
530 state->name);
531 *state->end = '/';
534 * We need to return the fact that the
535 * intermediate name resolution failed.
536 * This is used to return an error of
537 * ERRbadpath rather than ERRbadfile.
538 * Some Windows applications depend on
539 * the difference between these two
540 * errors.
544 * ENOENT, ENOTDIR and ELOOP all map
545 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
546 * in the filename walk.
549 if (errno == ENOENT ||
550 errno == ENOTDIR ||
551 errno == ELOOP)
553 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
555 return map_nt_error_from_unix(errno);
559 * ENOENT/EACCESS are the only valid errors
560 * here.
563 if (errno == EACCES) {
564 if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
565 return NT_STATUS_ACCESS_DENIED;
566 } else {
568 * This is the dropbox
569 * behaviour. A dropbox is a
570 * directory with only -wx
571 * permissions, so
572 * get_real_filename fails
573 * with EACCESS, it needs to
574 * list the directory. We
575 * nevertheless want to allow
576 * users creating a file.
578 errno = 0;
582 if ((errno != 0) && (errno != ENOENT)) {
584 * ENOTDIR and ELOOP both map to
585 * NT_STATUS_OBJECT_PATH_NOT_FOUND
586 * in the filename walk.
588 if (errno == ENOTDIR || errno == ELOOP) {
589 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
591 return map_nt_error_from_unix(errno);
595 * Just the last part of the name doesn't exist.
596 * We need to strupper() or strlower() it as
597 * this conversion may be used for file creation
598 * purposes. Fix inspired by
599 * Thomas Neumann <t.neumann@iku-ag.de>.
601 if (!state->conn->case_preserve ||
602 (mangle_is_8_3(state->name, false,
603 state->conn->params) &&
604 !state->conn->short_case_preserve)) {
605 if (!strnorm(state->name,
606 lp_default_case(SNUM(state->conn)))) {
607 DBG_DEBUG("strnorm %s failed\n",
608 state->name);
609 return NT_STATUS_INVALID_PARAMETER;
614 * check on the mangled stack to see if we can
615 * recover the base of the filename.
618 if (mangle_is_mangled(state->name, state->conn->params)
619 && mangle_lookup_name_from_8_3(state->mem_ctx,
620 state->name,
621 &unmangled,
622 state->conn->params)) {
623 char *tmp;
624 size_t name_ofs =
625 state->name - state->smb_fname->base_name;
627 if (!ISDOT(state->dirpath)) {
628 tmp = talloc_asprintf(
629 state->smb_fname, "%s/%s",
630 state->dirpath, unmangled);
631 TALLOC_FREE(unmangled);
633 else {
634 tmp = unmangled;
636 if (tmp == NULL) {
637 DBG_ERR("talloc failed\n");
638 return NT_STATUS_NO_MEMORY;
640 TALLOC_FREE(state->smb_fname->base_name);
641 state->smb_fname->base_name = tmp;
642 state->name =
643 state->smb_fname->base_name + name_ofs;
644 state->end = state->name + strlen(state->name);
647 DBG_DEBUG("New file [%s]\n", state->name);
648 state->done = true;
649 return NT_STATUS_OK;
652 static NTSTATUS unix_convert_step_stat(struct uc_state *state)
654 struct smb_filename dname;
655 char dot[2] = ".";
656 char *found_name = NULL;
657 int ret;
660 * Check if the name exists up to this point.
663 DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname));
665 if (state->posix_pathnames) {
666 ret = SMB_VFS_LSTAT(state->conn, state->smb_fname);
667 } else {
668 ret = SMB_VFS_STAT(state->conn, state->smb_fname);
670 if (ret == 0) {
672 * It exists. it must either be a directory or this must
673 * be the last part of the path for it to be OK.
675 if (state->end && !S_ISDIR(state->smb_fname->st.st_ex_mode)) {
677 * An intermediate part of the name isn't
678 * a directory.
680 DBG_DEBUG("Not a dir [%s]\n", state->name);
681 *state->end = '/';
683 * We need to return the fact that the
684 * intermediate name resolution failed. This
685 * is used to return an error of ERRbadpath
686 * rather than ERRbadfile. Some Windows
687 * applications depend on the difference between
688 * these two errors.
690 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
692 return NT_STATUS_OK;
695 /* Stat failed - ensure we don't use it. */
696 SET_STAT_INVALID(state->smb_fname->st);
698 if (state->posix_pathnames) {
700 * For posix_pathnames, we're done.
701 * Don't blunder into the name_has_wildcard OR
702 * get_real_filename() codepaths as they may
703 * be doing case insensitive lookups. So when
704 * creating a new POSIX directory Foo they might
705 * match on name foo.
707 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13803
709 if (state->end != NULL) {
710 const char *morepath = NULL;
712 * If this is intermediate we must
713 * restore the full path.
715 *state->end = '/';
717 * If there are any more components
718 * after the failed LSTAT we cannot
719 * continue.
721 morepath = strchr(state->end + 1, '/');
722 if (morepath != NULL) {
723 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
726 if (errno == ENOENT) {
727 /* New file or directory. */
728 state->done = true;
729 return NT_STATUS_OK;
731 if ((errno == EACCES) &&
732 (state->ucf_flags & UCF_PREP_CREATEFILE)) {
733 /* POSIX Dropbox case. */
734 errno = 0;
735 state->done = true;
736 return NT_STATUS_OK;
738 return map_nt_error_from_unix(errno);
742 * Reset errno so we can detect
743 * directory open errors.
745 errno = 0;
748 * Try to find this part of the path in the directory.
751 if (state->name_has_wildcard) {
752 return unix_convert_step_search_fail(state);
755 dname = (struct smb_filename) {
756 .base_name = state->dirpath,
757 .twrp = state->smb_fname->twrp,
760 /* handle null paths */
761 if ((dname.base_name == NULL) || (dname.base_name[0] == '\0')) {
762 dname.base_name = dot;
765 ret = get_real_filename(state->conn,
766 &dname,
767 state->name,
768 talloc_tos(),
769 &found_name);
770 if (ret != 0) {
771 return unix_convert_step_search_fail(state);
775 * Restore the rest of the string. If the string was
776 * mangled the size may have changed.
778 if (state->end) {
779 char *tmp;
780 size_t name_ofs =
781 state->name - state->smb_fname->base_name;
783 if (!ISDOT(state->dirpath)) {
784 tmp = talloc_asprintf(state->smb_fname,
785 "%s/%s/%s", state->dirpath,
786 found_name, state->end+1);
788 else {
789 tmp = talloc_asprintf(state->smb_fname,
790 "%s/%s", found_name,
791 state->end+1);
793 if (tmp == NULL) {
794 DBG_ERR("talloc_asprintf failed\n");
795 return NT_STATUS_NO_MEMORY;
797 TALLOC_FREE(state->smb_fname->base_name);
798 state->smb_fname->base_name = tmp;
799 state->name = state->smb_fname->base_name + name_ofs;
800 state->end = state->name + strlen(found_name);
801 *state->end = '\0';
802 } else {
803 char *tmp;
804 size_t name_ofs =
805 state->name - state->smb_fname->base_name;
807 if (!ISDOT(state->dirpath)) {
808 tmp = talloc_asprintf(state->smb_fname,
809 "%s/%s", state->dirpath,
810 found_name);
811 } else {
812 tmp = talloc_strdup(state->smb_fname,
813 found_name);
815 if (tmp == NULL) {
816 DBG_ERR("talloc failed\n");
817 return NT_STATUS_NO_MEMORY;
819 TALLOC_FREE(state->smb_fname->base_name);
820 state->smb_fname->base_name = tmp;
821 state->name = state->smb_fname->base_name + name_ofs;
824 * We just scanned for, and found the end of
825 * the path. We must return a valid stat struct
826 * if it exists. JRA.
829 if (state->posix_pathnames) {
830 ret = SMB_VFS_LSTAT(state->conn, state->smb_fname);
831 } else {
832 ret = SMB_VFS_STAT(state->conn, state->smb_fname);
835 if (ret != 0) {
836 SET_STAT_INVALID(state->smb_fname->st);
840 TALLOC_FREE(found_name);
841 return NT_STATUS_OK;
844 static NTSTATUS unix_convert_step(struct uc_state *state)
846 NTSTATUS status;
849 * Pinpoint the end of this section of the filename.
851 /* mb safe. '/' can't be in any encoded char. */
852 state->end = strchr(state->name, '/');
855 * Chop the name at this point.
857 if (state->end != NULL) {
858 *state->end = 0;
861 DBG_DEBUG("dirpath [%s] name [%s]\n", state->dirpath, state->name);
863 /* The name cannot have a component of "." */
865 if (ISDOT(state->name)) {
866 if (state->end == NULL) {
867 /* Error code at the end of a pathname. */
868 return NT_STATUS_OBJECT_NAME_INVALID;
870 return determine_path_error(state->end+1,
871 state->allow_wcard_last_component,
872 state->posix_pathnames);
875 /* The name cannot have a wildcard if it's not
876 the last component. */
878 if (!state->posix_pathnames) {
879 state->name_has_wildcard = ms_has_wild(state->name);
882 /* Wildcards never valid within a pathname. */
883 if (state->name_has_wildcard && state->end != NULL) {
884 return NT_STATUS_OBJECT_NAME_INVALID;
887 /* Skip the stat call if it's a wildcard end. */
888 if (state->name_has_wildcard) {
889 DBG_DEBUG("Wildcard [%s]\n", state->name);
890 state->done = true;
891 return NT_STATUS_OK;
894 status = unix_convert_step_stat(state);
895 if (!NT_STATUS_IS_OK(status)) {
896 return status;
898 if (state->done) {
899 return NT_STATUS_OK;
903 * Add to the dirpath that we have resolved so far.
906 if (!ISDOT(state->dirpath)) {
907 char *tmp = talloc_asprintf(state->mem_ctx,
908 "%s/%s", state->dirpath, state->name);
909 if (!tmp) {
910 DBG_ERR("talloc_asprintf failed\n");
911 return NT_STATUS_NO_MEMORY;
913 TALLOC_FREE(state->dirpath);
914 state->dirpath = tmp;
916 else {
917 TALLOC_FREE(state->dirpath);
918 if (!(state->dirpath = talloc_strdup(state->mem_ctx,state->name))) {
919 DBG_ERR("talloc_strdup failed\n");
920 return NT_STATUS_NO_MEMORY;
925 * Cache the dirpath thus far. Don't cache a name with mangled
926 * or wildcard components as this can change the size.
928 if(!state->component_was_mangled && !state->name_has_wildcard) {
929 stat_cache_add(state->orig_path,
930 state->dirpath,
931 state->smb_fname->twrp,
932 state->conn->case_sensitive);
936 * Restore the / that we wiped out earlier.
938 if (state->end != NULL) {
939 *state->end = '/';
942 return NT_STATUS_OK;
945 NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
946 connection_struct *conn,
947 const char *orig_path,
948 NTTIME twrp,
949 struct smb_filename **smb_fname_out,
950 uint32_t ucf_flags)
952 struct uc_state uc_state;
953 struct uc_state *state = &uc_state;
954 NTSTATUS status;
955 int ret = -1;
957 *state = (struct uc_state) {
958 .mem_ctx = mem_ctx,
959 .conn = conn,
960 .orig_path = orig_path,
961 .ucf_flags = ucf_flags,
962 .posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES),
963 .allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP),
966 *smb_fname_out = NULL;
968 state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename);
969 if (state->smb_fname == NULL) {
970 return NT_STATUS_NO_MEMORY;
973 if (state->conn->printer) {
974 /* we don't ever use the filenames on a printer share as a
975 filename - so don't convert them */
976 state->smb_fname->base_name = talloc_strdup(
977 state->smb_fname, state->orig_path);
978 if (state->smb_fname->base_name == NULL) {
979 status = NT_STATUS_NO_MEMORY;
980 goto err;
982 goto done;
985 state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
987 DBG_DEBUG("Called on file [%s]\n", state->orig_path);
989 if (state->orig_path[0] == '/') {
990 DBG_ERR("Path [%s] starts with '/'\n", state->orig_path);
991 return NT_STATUS_OBJECT_NAME_INVALID;
994 /* Start with the full orig_path as given by the caller. */
995 state->smb_fname->base_name = talloc_strdup(
996 state->smb_fname, state->orig_path);
997 if (state->smb_fname->base_name == NULL) {
998 DBG_ERR("talloc_strdup failed\n");
999 status = NT_STATUS_NO_MEMORY;
1000 goto err;
1003 /* Canonicalize any @GMT- paths. */
1004 status = canonicalize_snapshot_path(state->smb_fname, ucf_flags, twrp);
1005 if (!NT_STATUS_IS_OK(status)) {
1006 goto err;
1010 * If we trimmed down to a single '\0' character
1011 * then we should use the "." directory to avoid
1012 * searching the cache, but not if we are in a
1013 * printing share.
1014 * As we know this is valid we can return true here.
1017 if (state->smb_fname->base_name[0] == '\0') {
1018 state->smb_fname->base_name = talloc_strdup(state->smb_fname, ".");
1019 if (state->smb_fname->base_name == NULL) {
1020 status = NT_STATUS_NO_MEMORY;
1021 goto err;
1023 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1024 status = map_nt_error_from_unix(errno);
1025 goto err;
1027 DBG_DEBUG("conversion finished [] -> [%s]\n",
1028 state->smb_fname->base_name);
1029 goto done;
1032 if (state->orig_path[0] == '.' && (state->orig_path[1] == '/' ||
1033 state->orig_path[1] == '\0')) {
1034 /* Start of pathname can't be "." only. */
1035 if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') {
1036 status = NT_STATUS_OBJECT_NAME_INVALID;
1037 } else {
1038 status =determine_path_error(&state->orig_path[2],
1039 state->allow_wcard_last_component,
1040 state->posix_pathnames);
1042 goto err;
1046 * Large directory fix normalization. If we're case sensitive, and
1047 * the case preserving parameters are set to "no", normalize the case of
1048 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
1049 * This is in conflict with the current (3.0.20) man page, but is
1050 * what people expect from the "large directory howto". I'll update
1051 * the man page. Thanks to jht@samba.org for finding this. JRA.
1054 status = normalize_filename_case(state->conn, state->smb_fname->base_name);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 DBG_ERR("normalize_filename_case %s failed\n",
1057 state->smb_fname->base_name);
1058 goto err;
1062 * Strip off the stream, and add it back when we're done with the
1063 * base_name.
1065 if (!state->posix_pathnames) {
1066 state->stream = strchr_m(state->smb_fname->base_name, ':');
1068 if (state->stream != NULL) {
1069 char *tmp = talloc_strdup(state->smb_fname, state->stream);
1070 if (tmp == NULL) {
1071 status = NT_STATUS_NO_MEMORY;
1072 goto err;
1075 * Since this is actually pointing into
1076 * smb_fname->base_name this truncates base_name.
1078 *state->stream = '\0';
1079 state->stream = tmp;
1081 if (state->smb_fname->base_name[0] == '\0') {
1083 * orig_name was just a stream name.
1084 * This is a stream on the root of
1085 * the share. Replace base_name with
1086 * a "."
1088 state->smb_fname->base_name =
1089 talloc_strdup(state->smb_fname, ".");
1090 if (state->smb_fname->base_name == NULL) {
1091 status = NT_STATUS_NO_MEMORY;
1092 goto err;
1094 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1095 status = map_nt_error_from_unix(errno);
1096 goto err;
1098 /* dirpath must exist. */
1099 state->dirpath = talloc_strdup(state->mem_ctx,".");
1100 if (state->dirpath == NULL) {
1101 status = NT_STATUS_NO_MEMORY;
1102 goto err;
1104 DBG_INFO("conversion finished [%s] -> [%s]\n",
1105 state->orig_path,
1106 state->smb_fname->base_name);
1107 goto done;
1112 state->name = state->smb_fname->base_name;
1115 * If we're providing case insensitive semantics or
1116 * the underlying filesystem is case insensitive,
1117 * then a case-normalized hit in the stat-cache is
1118 * authoritative. JRA.
1120 * Note: We're only checking base_name. The stream_name will be
1121 * added and verified in build_stream_path().
1124 if (!state->conn->case_sensitive ||
1125 !(state->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
1127 bool found;
1129 found = stat_cache_lookup(state->conn,
1130 state->posix_pathnames,
1131 &state->smb_fname->base_name,
1132 &state->dirpath,
1133 &state->name,
1134 state->smb_fname->twrp,
1135 &state->smb_fname->st);
1136 if (found) {
1137 goto done;
1142 * Make sure "dirpath" is an allocated string, we use this for
1143 * building the directories with talloc_asprintf and free it.
1146 if (state->dirpath == NULL) {
1147 state->dirpath = talloc_strdup(state->mem_ctx,".");
1148 if (state->dirpath == NULL) {
1149 DBG_ERR("talloc_strdup failed\n");
1150 status = NT_STATUS_NO_MEMORY;
1151 goto err;
1156 * If we have a wildcard we must walk the path to
1157 * find where the error is, even if case sensitive
1158 * is true.
1161 if (!state->posix_pathnames) {
1162 /* POSIX pathnames have no wildcards. */
1163 state->name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
1164 if (state->name_has_wildcard && !state->allow_wcard_last_component) {
1165 /* Wildcard not valid anywhere. */
1166 status = NT_STATUS_OBJECT_NAME_INVALID;
1167 goto fail;
1171 DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
1172 state->smb_fname->base_name, state->dirpath, state->name);
1174 if (!state->name_has_wildcard) {
1176 * stat the name - if it exists then we can add the stream back (if
1177 * there was one) and be done!
1180 if (state->posix_pathnames) {
1181 ret = SMB_VFS_LSTAT(state->conn, state->smb_fname);
1182 } else {
1183 ret = SMB_VFS_STAT(state->conn, state->smb_fname);
1186 if (ret == 0) {
1187 status = check_for_dot_component(state->smb_fname);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 goto fail;
1191 /* Add the path (not including the stream) to the cache. */
1192 stat_cache_add(state->orig_path,
1193 state->smb_fname->base_name,
1194 state->smb_fname->twrp,
1195 state->conn->case_sensitive);
1196 DBG_DEBUG("Conversion of base_name finished "
1197 "[%s] -> [%s]\n",
1198 state->orig_path, state->smb_fname->base_name);
1199 goto done;
1202 /* Stat failed - ensure we don't use it. */
1203 SET_STAT_INVALID(state->smb_fname->st);
1206 * Note: we must continue processing a path if we get EACCES
1207 * from stat. With NFS4 permissions the file might be lacking
1208 * READ_ATTR, but if the parent has LIST permissions we can
1209 * resolve the path in the path traversal loop down below.
1212 if (errno == ENOENT) {
1213 /* Optimization when creating a new file - only
1214 the last component doesn't exist.
1215 NOTE : check_parent_exists() doesn't preserve errno.
1217 int saved_errno = errno;
1218 status = check_parent_exists(state->mem_ctx,
1219 state->conn,
1220 state->posix_pathnames,
1221 state->smb_fname,
1222 &state->dirpath,
1223 &state->name);
1224 errno = saved_errno;
1225 if (!NT_STATUS_IS_OK(status)) {
1226 goto fail;
1231 * A special case - if we don't have any wildcards or mangling chars and are case
1232 * sensitive or the underlying filesystem is case insensitive then searching
1233 * won't help.
1236 if ((state->conn->case_sensitive || !(state->conn->fs_capabilities &
1237 FILE_CASE_SENSITIVE_SEARCH)) &&
1238 !mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
1240 status = check_for_dot_component(state->smb_fname);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 goto fail;
1246 * The stat failed. Could be ok as it could be
1247 * a new file.
1250 if (errno == ENOTDIR || errno == ELOOP) {
1251 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1252 goto fail;
1253 } else if (errno == ENOENT) {
1255 * Was it a missing last component ?
1256 * or a missing intermediate component ?
1258 struct smb_filename *parent_fname = NULL;
1259 struct smb_filename *base_fname = NULL;
1260 bool ok;
1262 ok = parent_smb_fname(state->mem_ctx,
1263 state->smb_fname,
1264 &parent_fname,
1265 &base_fname);
1266 if (!ok) {
1267 status = NT_STATUS_NO_MEMORY;
1268 goto fail;
1270 if (state->posix_pathnames) {
1271 ret = SMB_VFS_LSTAT(state->conn,
1272 parent_fname);
1273 } else {
1274 ret = SMB_VFS_STAT(state->conn,
1275 parent_fname);
1277 TALLOC_FREE(parent_fname);
1278 if (ret == -1) {
1279 if (errno == ENOTDIR ||
1280 errno == ENOENT ||
1281 errno == ELOOP) {
1282 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1283 goto fail;
1288 * Missing last component is ok - new file.
1289 * Also deal with permission denied elsewhere.
1290 * Just drop out to done.
1292 goto done;
1295 } else {
1297 * We have a wildcard in the pathname.
1299 * Optimization for common case where the wildcard
1300 * is in the last component and the client already
1301 * sent the correct case.
1302 * NOTE : check_parent_exists() doesn't preserve errno.
1304 int saved_errno = errno;
1305 status = check_parent_exists(state->mem_ctx,
1306 state->conn,
1307 state->posix_pathnames,
1308 state->smb_fname,
1309 &state->dirpath,
1310 &state->name);
1311 errno = saved_errno;
1312 if (!NT_STATUS_IS_OK(status)) {
1313 goto fail;
1318 * is_mangled() was changed to look at an entire pathname, not
1319 * just a component. JRA.
1322 if (mangle_is_mangled(state->name, state->conn->params)) {
1323 state->component_was_mangled = true;
1327 * Now we need to recursively match the name against the real
1328 * directory structure.
1332 * Match each part of the path name separately, trying the names
1333 * as is first, then trying to scan the directory for matching names.
1336 for (; state->name ; state->name = (state->end ? state->end + 1:(char *)NULL)) {
1337 status = unix_convert_step(state);
1338 if (!NT_STATUS_IS_OK(status)) {
1339 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
1340 goto err;
1342 goto fail;
1344 if (state->done) {
1345 goto done;
1350 * Cache the full path. Don't cache a name with mangled or wildcard
1351 * components as this can change the size.
1354 if(!state->component_was_mangled && !state->name_has_wildcard) {
1355 stat_cache_add(state->orig_path,
1356 state->smb_fname->base_name,
1357 state->smb_fname->twrp,
1358 state->conn->case_sensitive);
1362 * The name has been resolved.
1365 done:
1366 /* Add back the stream if one was stripped off originally. */
1367 if (state->stream != NULL) {
1368 state->smb_fname->stream_name = state->stream;
1370 /* Check path now that the base_name has been converted. */
1371 status = build_stream_path(state->mem_ctx, state->conn, state->smb_fname);
1372 if (!NT_STATUS_IS_OK(status)) {
1373 goto fail;
1377 DBG_DEBUG("Conversion finished [%s] -> [%s]\n",
1378 state->orig_path, smb_fname_str_dbg(state->smb_fname));
1380 TALLOC_FREE(state->dirpath);
1381 *smb_fname_out = state->smb_fname;
1382 return NT_STATUS_OK;
1383 fail:
1384 DBG_DEBUG("Conversion failed: dirpath [%s] name [%s]\n",
1385 state->dirpath, state->name);
1386 if ((state->dirpath != NULL) && !ISDOT(state->dirpath)) {
1387 state->smb_fname->base_name = talloc_asprintf(
1388 state->smb_fname,
1389 "%s/%s",
1390 state->dirpath,
1391 state->name);
1392 } else {
1393 state->smb_fname->base_name = talloc_strdup(
1394 state->smb_fname, state->name);
1396 if (state->smb_fname->base_name == NULL) {
1397 DBG_ERR("talloc_asprintf failed\n");
1398 status = NT_STATUS_NO_MEMORY;
1399 goto err;
1402 *smb_fname_out = state->smb_fname;
1403 TALLOC_FREE(state->dirpath);
1404 return status;
1405 err:
1406 TALLOC_FREE(state->smb_fname);
1407 return status;
1410 /****************************************************************************
1411 Ensure a path is not vetoed.
1412 ****************************************************************************/
1414 static NTSTATUS check_veto_path(connection_struct *conn,
1415 const struct smb_filename *smb_fname)
1417 const char *name = smb_fname->base_name;
1419 if (IS_VETO_PATH(conn, name)) {
1420 /* Is it not dot or dot dot. */
1421 if (!(ISDOT(name) || ISDOTDOT(name))) {
1422 DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1423 name));
1424 return map_nt_error_from_unix(ENOENT);
1427 return NT_STATUS_OK;
1430 /****************************************************************************
1431 Check a filename - possibly calling check_reduced_name.
1432 This is called by every routine before it allows an operation on a filename.
1433 It does any final confirmation necessary to ensure that the filename is
1434 a valid one for the user to access.
1435 ****************************************************************************/
1437 NTSTATUS check_name(connection_struct *conn,
1438 const struct smb_filename *smb_fname)
1440 NTSTATUS status = check_veto_path(conn, smb_fname);
1442 if (!NT_STATUS_IS_OK(status)) {
1443 return status;
1446 if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1447 status = check_reduced_name(conn, NULL, smb_fname);
1448 if (!NT_STATUS_IS_OK(status)) {
1449 DEBUG(5,("check_name: name %s failed with %s\n",
1450 smb_fname->base_name,
1451 nt_errstr(status)));
1452 return status;
1456 return NT_STATUS_OK;
1459 /****************************************************************************
1460 Must be called as root. Creates the struct privilege_paths
1461 attached to the struct smb_request if this call is successful.
1462 ****************************************************************************/
1464 static NTSTATUS check_name_with_privilege(connection_struct *conn,
1465 struct smb_request *smbreq,
1466 const struct smb_filename *smb_fname)
1468 NTSTATUS status = check_veto_path(conn, smb_fname);
1470 if (!NT_STATUS_IS_OK(status)) {
1471 return status;
1473 return check_reduced_name_with_privilege(conn,
1474 smb_fname,
1475 smbreq);
1478 /****************************************************************************
1479 Check if two filenames are equal.
1480 This needs to be careful about whether we are case sensitive.
1481 ****************************************************************************/
1483 static bool fname_equal(const char *name1, const char *name2,
1484 bool case_sensitive)
1486 /* Normal filename handling */
1487 if (case_sensitive) {
1488 return(strcmp(name1,name2) == 0);
1491 return(strequal(name1,name2));
1494 static bool sname_equal(const char *name1, const char *name2,
1495 bool case_sensitive)
1497 bool match;
1498 const char *s1 = NULL;
1499 const char *s2 = NULL;
1500 size_t n1;
1501 size_t n2;
1502 const char *e1 = NULL;
1503 const char *e2 = NULL;
1504 char *c1 = NULL;
1505 char *c2 = NULL;
1507 match = fname_equal(name1, name2, case_sensitive);
1508 if (match) {
1509 return true;
1512 if (name1[0] != ':') {
1513 return false;
1515 if (name2[0] != ':') {
1516 return false;
1518 s1 = &name1[1];
1519 e1 = strchr(s1, ':');
1520 if (e1 == NULL) {
1521 n1 = strlen(s1);
1522 } else {
1523 n1 = PTR_DIFF(e1, s1);
1525 s2 = &name2[1];
1526 e2 = strchr(s2, ':');
1527 if (e2 == NULL) {
1528 n2 = strlen(s2);
1529 } else {
1530 n2 = PTR_DIFF(e2, s2);
1533 /* Normal filename handling */
1534 if (case_sensitive) {
1535 return (strncmp(s1, s2, n1) == 0);
1539 * We can't use strnequal() here
1540 * as it takes the number of codepoints
1541 * and not the number of bytes.
1543 * So we make a copy before calling
1544 * strequal().
1546 * Note that we TALLOC_FREE() in reverse order
1547 * in order to avoid memory fragmentation.
1550 c1 = talloc_strndup(talloc_tos(), s1, n1);
1551 c2 = talloc_strndup(talloc_tos(), s2, n2);
1552 if (c1 == NULL || c2 == NULL) {
1553 TALLOC_FREE(c2);
1554 TALLOC_FREE(c1);
1555 return (strncmp(s1, s2, n1) == 0);
1558 match = strequal(c1, c2);
1559 TALLOC_FREE(c2);
1560 TALLOC_FREE(c1);
1561 return match;
1564 /****************************************************************************
1565 Scan a directory to find a filename, matching without case sensitivity.
1566 If the name looks like a mangled name then try via the mangling functions
1567 ****************************************************************************/
1569 int get_real_filename_full_scan(connection_struct *conn,
1570 const char *path,
1571 const char *name,
1572 bool mangled,
1573 TALLOC_CTX *mem_ctx,
1574 char **found_name)
1576 struct smb_Dir *cur_dir;
1577 const char *dname = NULL;
1578 char *talloced = NULL;
1579 char *unmangled_name = NULL;
1580 long curpos;
1581 struct smb_filename *smb_fname = NULL;
1583 /* handle null paths */
1584 if ((path == NULL) || (*path == 0)) {
1585 path = ".";
1588 /* If we have a case-sensitive filesystem, it doesn't do us any
1589 * good to search for a name. If a case variation of the name was
1590 * there, then the original stat(2) would have found it.
1592 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1593 errno = ENOENT;
1594 return -1;
1598 * The incoming name can be mangled, and if we de-mangle it
1599 * here it will not compare correctly against the filename (name2)
1600 * read from the directory and then mangled by the name_to_8_3()
1601 * call. We need to mangle both names or neither.
1602 * (JRA).
1604 * Fix for bug found by Dina Fine. If in case sensitive mode then
1605 * the mangle cache is no good (3 letter extension could be wrong
1606 * case - so don't demangle in this case - leave as mangled and
1607 * allow the mangling of the directory entry read (which is done
1608 * case insensitively) to match instead. This will lead to more
1609 * false positive matches but we fail completely without it. JRA.
1612 if (mangled && !conn->case_sensitive) {
1613 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1614 &unmangled_name,
1615 conn->params);
1616 if (!mangled) {
1617 /* Name is now unmangled. */
1618 name = unmangled_name;
1622 smb_fname = synthetic_smb_fname(talloc_tos(),
1623 path,
1624 NULL,
1625 NULL,
1628 if (smb_fname == NULL) {
1629 TALLOC_FREE(unmangled_name);
1630 return -1;
1633 /* open the directory */
1634 if (!(cur_dir = OpenDir(talloc_tos(), conn, smb_fname, NULL, 0))) {
1635 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1636 TALLOC_FREE(unmangled_name);
1637 TALLOC_FREE(smb_fname);
1638 return -1;
1641 TALLOC_FREE(smb_fname);
1643 /* now scan for matching names */
1644 curpos = 0;
1645 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1647 /* Is it dot or dot dot. */
1648 if (ISDOT(dname) || ISDOTDOT(dname)) {
1649 TALLOC_FREE(talloced);
1650 continue;
1654 * At this point dname is the unmangled name.
1655 * name is either mangled or not, depending on the state
1656 * of the "mangled" variable. JRA.
1660 * Check mangled name against mangled name, or unmangled name
1661 * against unmangled name.
1664 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1665 fname_equal(name, dname, conn->case_sensitive)) {
1666 /* we've found the file, change it's name and return */
1667 *found_name = talloc_strdup(mem_ctx, dname);
1668 TALLOC_FREE(unmangled_name);
1669 TALLOC_FREE(cur_dir);
1670 if (!*found_name) {
1671 errno = ENOMEM;
1672 TALLOC_FREE(talloced);
1673 return -1;
1675 TALLOC_FREE(talloced);
1676 return 0;
1678 TALLOC_FREE(talloced);
1681 TALLOC_FREE(unmangled_name);
1682 TALLOC_FREE(cur_dir);
1683 errno = ENOENT;
1684 return -1;
1687 /****************************************************************************
1688 Wrapper around the vfs get_real_filename and the full directory scan
1689 fallback.
1690 ****************************************************************************/
1692 int get_real_filename(connection_struct *conn,
1693 struct smb_filename *path,
1694 const char *name,
1695 TALLOC_CTX *mem_ctx,
1696 char **found_name)
1698 int ret;
1699 bool mangled;
1701 mangled = mangle_is_mangled(name, conn->params);
1703 if (mangled) {
1704 return get_real_filename_full_scan(conn,
1705 path->base_name,
1706 name,
1707 mangled,
1708 mem_ctx,
1709 found_name);
1712 /* Try the vfs first to take advantage of case-insensitive stat. */
1713 ret = SMB_VFS_GET_REAL_FILENAME(conn,
1714 path,
1715 name,
1716 mem_ctx,
1717 found_name);
1720 * If the case-insensitive stat was successful, or returned an error
1721 * other than EOPNOTSUPP then there is no need to fall back on the
1722 * full directory scan.
1724 if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1725 return ret;
1728 return get_real_filename_full_scan(conn,
1729 path->base_name,
1730 name,
1731 mangled,
1732 mem_ctx,
1733 found_name);
1736 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1737 connection_struct *conn,
1738 struct smb_filename *smb_fname)
1740 NTSTATUS status;
1741 unsigned int i, num_streams = 0;
1742 struct stream_struct *streams = NULL;
1744 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1745 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1746 return NT_STATUS_OK;
1749 if (errno != ENOENT) {
1750 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1751 status = map_nt_error_from_unix(errno);
1752 goto fail;
1755 /* Fall back to a case-insensitive scan of all streams on the file. */
1756 status = vfs_streaminfo(conn, NULL, smb_fname, mem_ctx,
1757 &num_streams, &streams);
1759 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1760 SET_STAT_INVALID(smb_fname->st);
1761 return NT_STATUS_OK;
1764 if (!NT_STATUS_IS_OK(status)) {
1765 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
1766 goto fail;
1769 for (i=0; i<num_streams; i++) {
1770 DEBUG(10, ("comparing [%s] and [%s]: ",
1771 smb_fname->stream_name, streams[i].name));
1772 if (sname_equal(smb_fname->stream_name, streams[i].name,
1773 conn->case_sensitive)) {
1774 DEBUGADD(10, ("equal\n"));
1775 break;
1777 DEBUGADD(10, ("not equal\n"));
1780 /* Couldn't find the stream. */
1781 if (i == num_streams) {
1782 SET_STAT_INVALID(smb_fname->st);
1783 TALLOC_FREE(streams);
1784 return NT_STATUS_OK;
1787 DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1788 smb_fname->stream_name, streams[i].name));
1791 TALLOC_FREE(smb_fname->stream_name);
1792 smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1793 if (smb_fname->stream_name == NULL) {
1794 status = NT_STATUS_NO_MEMORY;
1795 goto fail;
1798 SET_STAT_INVALID(smb_fname->st);
1800 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1801 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1803 status = NT_STATUS_OK;
1804 fail:
1805 TALLOC_FREE(streams);
1806 return status;
1810 * Lightweight function to just get last component
1811 * for rename / enumerate directory calls.
1814 char *get_original_lcomp(TALLOC_CTX *ctx,
1815 connection_struct *conn,
1816 const char *filename_in,
1817 uint32_t ucf_flags)
1819 struct smb_filename *smb_fname = NULL;
1820 char *last_slash = NULL;
1821 char *orig_lcomp;
1822 char *fname = NULL;
1823 NTSTATUS status;
1825 if (ucf_flags & UCF_DFS_PATHNAME) {
1826 status = resolve_dfspath_wcard(ctx,
1827 conn,
1828 filename_in,
1829 ucf_flags,
1830 !conn->sconn->using_smb2,
1831 &fname,
1832 NULL);
1833 if (!NT_STATUS_IS_OK(status)) {
1834 DBG_DEBUG("resolve_dfspath "
1835 "failed for name %s with %s\n",
1836 filename_in,
1837 nt_errstr(status));
1838 return NULL;
1840 filename_in = fname;
1841 ucf_flags &= ~UCF_DFS_PATHNAME;
1845 * NB. We don't need to care about
1846 * is_fake_file_path(filename_in) here as these
1847 * code paths don't ever return original_lcomp
1848 * or use it anyway.
1851 if (ucf_flags & UCF_GMT_PATHNAME) {
1853 * Ensure we don't return a @GMT
1854 * value as the last component.
1856 smb_fname = synthetic_smb_fname(ctx,
1857 filename_in,
1858 NULL,
1859 NULL,
1862 if (smb_fname == NULL) {
1863 TALLOC_FREE(fname);
1864 return NULL;
1866 status = canonicalize_snapshot_path(smb_fname,
1867 ucf_flags,
1869 if (!NT_STATUS_IS_OK(status)) {
1870 TALLOC_FREE(fname);
1871 TALLOC_FREE(smb_fname);
1872 return NULL;
1874 filename_in = smb_fname->base_name;
1876 last_slash = strrchr(filename_in, '/');
1877 if (last_slash != NULL) {
1878 orig_lcomp = talloc_strdup(ctx, last_slash+1);
1879 } else {
1880 orig_lcomp = talloc_strdup(ctx, filename_in);
1882 /* We're done with any temp names here. */
1883 TALLOC_FREE(smb_fname);
1884 TALLOC_FREE(fname);
1885 if (orig_lcomp == NULL) {
1886 return NULL;
1888 status = normalize_filename_case(conn, orig_lcomp);
1889 if (!NT_STATUS_IS_OK(status)) {
1890 TALLOC_FREE(orig_lcomp);
1891 return NULL;
1893 return orig_lcomp;
1897 * Go through all the steps to validate a filename.
1899 * @param ctx talloc_ctx to allocate memory with.
1900 * @param conn connection struct for vfs calls.
1901 * @param smbreq SMB request if we're using privileges.
1902 * @param name_in The unconverted name.
1903 * @param ucf_flags flags to pass through to unix_convert().
1904 * UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
1905 * p_cont_wcard != NULL and is true and
1906 * UCF_COND_ALLOW_WCARD_LCOMP.
1907 * @param twrp Optional VSS time
1908 * @param p_cont_wcard If not NULL, will be set to true if the dfs path
1909 * resolution detects a wildcard.
1910 * @param _smb_fname The final converted name will be allocated if the
1911 * return is NT_STATUS_OK.
1913 * @return NT_STATUS_OK if all operations completed successfully, appropriate
1914 * error otherwise.
1916 static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
1917 connection_struct *conn,
1918 struct smb_request *smbreq,
1919 const char *name_in,
1920 uint32_t ucf_flags,
1921 NTTIME twrp,
1922 bool *ppath_contains_wcard,
1923 struct smb_filename **_smb_fname)
1925 struct smb_filename *smb_fname = NULL;
1926 NTSTATUS status;
1928 *_smb_fname = NULL;
1930 if (ucf_flags & UCF_DFS_PATHNAME) {
1931 bool path_contains_wcard = false;
1932 char *fname = NULL;
1933 status = resolve_dfspath_wcard(ctx, conn,
1934 name_in,
1935 ucf_flags,
1936 !conn->sconn->using_smb2,
1937 &fname,
1938 &path_contains_wcard);
1939 if (!NT_STATUS_IS_OK(status)) {
1940 DEBUG(10,("filename_convert_internal: resolve_dfspath "
1941 "failed for name %s with %s\n",
1942 name_in,
1943 nt_errstr(status) ));
1944 return status;
1946 name_in = fname;
1947 if (ppath_contains_wcard != NULL && path_contains_wcard) {
1948 *ppath_contains_wcard = path_contains_wcard;
1950 ucf_flags &= ~UCF_DFS_PATHNAME;
1953 if (is_fake_file_path(name_in)) {
1954 smb_fname = synthetic_smb_fname_split(ctx,
1955 name_in,
1956 (ucf_flags & UCF_POSIX_PATHNAMES));
1957 if (smb_fname == NULL) {
1958 return NT_STATUS_NO_MEMORY;
1960 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1961 smb_fname->st.st_ex_btime = (struct timespec){0, SAMBA_UTIME_OMIT};
1962 smb_fname->st.st_ex_atime = (struct timespec){0, SAMBA_UTIME_OMIT};
1963 smb_fname->st.st_ex_mtime = (struct timespec){0, SAMBA_UTIME_OMIT};
1964 smb_fname->st.st_ex_ctime = (struct timespec){0, SAMBA_UTIME_OMIT};
1966 *_smb_fname = smb_fname;
1967 return NT_STATUS_OK;
1971 * If the caller conditionally allows wildcard lookups, only add the
1972 * always allow if the path actually does contain a wildcard.
1974 if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP &&
1975 ppath_contains_wcard != NULL && *ppath_contains_wcard) {
1976 ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
1979 status = unix_convert(ctx, conn, name_in, twrp, &smb_fname, ucf_flags);
1980 if (!NT_STATUS_IS_OK(status)) {
1981 DEBUG(10,("filename_convert_internal: unix_convert failed "
1982 "for name %s with %s\n",
1983 name_in,
1984 nt_errstr(status) ));
1985 return status;
1988 if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) &&
1989 VALID_STAT(smb_fname->st) &&
1990 S_ISLNK(smb_fname->st.st_ex_mode)) {
1991 status = check_veto_path(conn, smb_fname);
1992 if (!NT_STATUS_IS_OK(status)) {
1993 TALLOC_FREE(smb_fname);
1994 return status;
1996 *_smb_fname = smb_fname;
1997 return NT_STATUS_OK;
2000 if (!smbreq) {
2001 status = check_name(conn, smb_fname);
2002 } else {
2003 status = check_name_with_privilege(conn, smbreq,
2004 smb_fname);
2006 if (!NT_STATUS_IS_OK(status)) {
2007 DEBUG(3,("filename_convert_internal: check_name failed "
2008 "for name %s with %s\n",
2009 smb_fname_str_dbg(smb_fname),
2010 nt_errstr(status) ));
2011 TALLOC_FREE(smb_fname);
2012 return status;
2015 *_smb_fname = smb_fname;
2016 return status;
2020 * Go through all the steps to validate a filename.
2021 * Non-root version.
2024 NTSTATUS filename_convert(TALLOC_CTX *ctx,
2025 connection_struct *conn,
2026 const char *name_in,
2027 uint32_t ucf_flags,
2028 NTTIME twrp,
2029 bool *ppath_contains_wcard,
2030 struct smb_filename **pp_smb_fname)
2032 return filename_convert_internal(ctx,
2033 conn,
2034 NULL,
2035 name_in,
2036 ucf_flags,
2037 twrp,
2038 ppath_contains_wcard,
2039 pp_smb_fname);
2043 * Go through all the steps to validate a filename.
2044 * root (privileged) version.
2047 NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
2048 connection_struct *conn,
2049 struct smb_request *smbreq,
2050 const char *name_in,
2051 uint32_t ucf_flags,
2052 bool *ppath_contains_wcard,
2053 struct smb_filename **pp_smb_fname)
2055 return filename_convert_internal(ctx,
2056 conn,
2057 smbreq,
2058 name_in,
2059 ucf_flags,
2061 ppath_contains_wcard,
2062 pp_smb_fname);