s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / smbd / filename.c
blob0be8e320ffa02d765a1c8f47e3aa7135039cedc5
1 /*
2 Unix SMB/CIFS implementation.
3 filename handling routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 1999-2007
6 Copyright (C) Ying Chen 2000
7 Copyright (C) Volker Lendecke 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * New hash table stat cache code added by Ying Chen.
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "fake_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
32 #include "lib/util/memcache.h"
34 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
36 uint32_t ucf_flags = 0;
38 if (req != NULL) {
39 if (req->posix_pathnames) {
40 ucf_flags |= UCF_POSIX_PATHNAMES;
42 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
43 ucf_flags |= UCF_DFS_PATHNAME;
45 if (req->flags2 & FLAGS2_REPARSE_PATH) {
46 ucf_flags |= UCF_GMT_PATHNAME;
50 return ucf_flags;
53 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
55 uint32_t ucf_flags = 0;
57 ucf_flags |= ucf_flags_from_smb_request(req);
59 switch (create_disposition) {
60 case FILE_OPEN:
61 case FILE_OVERWRITE:
62 break;
63 case FILE_SUPERSEDE:
64 case FILE_CREATE:
65 case FILE_OPEN_IF:
66 case FILE_OVERWRITE_IF:
67 ucf_flags |= UCF_PREP_CREATEFILE;
68 break;
71 return ucf_flags;
74 /****************************************************************************
75 Mangle the 2nd name and check if it is then equal to the first name.
76 ****************************************************************************/
78 static bool mangled_equal(const char *name1,
79 const char *name2,
80 const struct share_params *p)
82 char mname[13];
84 if (!name_to_8_3(name2, mname, False, p)) {
85 return False;
87 return strequal(name1, mname);
90 static bool find_snapshot_token(
91 const char *filename,
92 const char **_start,
93 const char **_next_component,
94 NTTIME *twrp)
96 const char *start = NULL;
97 const char *end = NULL;
98 struct tm tm;
99 time_t t;
101 start = strstr_m(filename, "@GMT-");
103 if (start == NULL) {
104 return false;
107 if ((start > filename) && (start[-1] != '/')) {
108 /* the GMT-token does not start a path-component */
109 return false;
112 end = strptime(start, GMT_FORMAT, &tm);
113 if (end == NULL) {
114 /* Not a valid timestring. */
115 return false;
118 if ((end[0] != '\0') && (end[0] != '/')) {
120 * It is not a complete path component, i.e. the path
121 * component continues after the gmt-token.
123 return false;
126 tm.tm_isdst = -1;
127 t = timegm(&tm);
128 unix_to_nt_time(twrp, t);
130 DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
131 nt_time_string(talloc_tos(), *twrp));
133 *_start = start;
135 if (end[0] == '/') {
136 end += 1;
138 *_next_component = end;
140 return true;
143 bool extract_snapshot_token(char *fname, NTTIME *twrp)
145 const char *start = NULL;
146 const char *next = NULL;
147 size_t remaining;
148 bool found;
150 found = find_snapshot_token(fname, &start, &next, twrp);
151 if (!found) {
152 return false;
155 remaining = strlen(next);
156 memmove(discard_const_p(char, start), next, remaining+1);
158 return true;
162 * Strip a valid @GMT-token from any incoming filename path,
163 * adding any NTTIME encoded in the pathname into the
164 * twrp field of the passed in smb_fname.
166 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
167 * at the *start* of a pathname component.
169 * If twrp is passed in then smb_fname->twrp is set to that
170 * value, and the @GMT-token part of the filename is removed
171 * and does not change the stored smb_fname->twrp.
175 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
176 uint32_t ucf_flags,
177 NTTIME twrp)
179 bool found;
181 if (twrp != 0) {
182 smb_fname->twrp = twrp;
185 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
186 return NT_STATUS_OK;
189 found = extract_snapshot_token(smb_fname->base_name, &twrp);
190 if (!found) {
191 return NT_STATUS_OK;
194 if (smb_fname->twrp == 0) {
195 smb_fname->twrp = twrp;
198 return NT_STATUS_OK;
201 static bool strnorm(char *s, int case_default)
203 if (case_default == CASE_UPPER)
204 return strupper_m(s);
205 else
206 return strlower_m(s);
210 * Utility function to normalize case on an incoming client filename
211 * if required on this connection struct.
212 * Performs an in-place case conversion guaranteed to stay the same size.
215 static NTSTATUS normalize_filename_case(connection_struct *conn,
216 char *filename,
217 uint32_t ucf_flags)
219 bool ok;
221 if (ucf_flags & UCF_POSIX_PATHNAMES) {
223 * POSIX never normalizes filename case.
225 return NT_STATUS_OK;
227 if (!conn->case_sensitive) {
228 return NT_STATUS_OK;
230 if (conn->case_preserve) {
231 return NT_STATUS_OK;
233 if (conn->short_case_preserve) {
234 return NT_STATUS_OK;
236 ok = strnorm(filename, lp_default_case(SNUM(conn)));
237 if (!ok) {
238 return NT_STATUS_INVALID_PARAMETER;
240 return NT_STATUS_OK;
243 /****************************************************************************
244 Check if two filenames are equal.
245 This needs to be careful about whether we are case sensitive.
246 ****************************************************************************/
248 static bool fname_equal(const char *name1, const char *name2,
249 bool case_sensitive)
251 /* Normal filename handling */
252 if (case_sensitive) {
253 return(strcmp(name1,name2) == 0);
256 return(strequal(name1,name2));
259 static bool sname_equal(const char *name1, const char *name2,
260 bool case_sensitive)
262 bool match;
263 const char *s1 = NULL;
264 const char *s2 = NULL;
265 size_t n1;
266 size_t n2;
267 const char *e1 = NULL;
268 const char *e2 = NULL;
269 char *c1 = NULL;
270 char *c2 = NULL;
272 match = fname_equal(name1, name2, case_sensitive);
273 if (match) {
274 return true;
277 if (name1[0] != ':') {
278 return false;
280 if (name2[0] != ':') {
281 return false;
283 s1 = &name1[1];
284 e1 = strchr(s1, ':');
285 if (e1 == NULL) {
286 n1 = strlen(s1);
287 } else {
288 n1 = PTR_DIFF(e1, s1);
290 s2 = &name2[1];
291 e2 = strchr(s2, ':');
292 if (e2 == NULL) {
293 n2 = strlen(s2);
294 } else {
295 n2 = PTR_DIFF(e2, s2);
298 /* Normal filename handling */
299 if (case_sensitive) {
300 return (strncmp(s1, s2, n1) == 0);
304 * We can't use strnequal() here
305 * as it takes the number of codepoints
306 * and not the number of bytes.
308 * So we make a copy before calling
309 * strequal().
311 * Note that we TALLOC_FREE() in reverse order
312 * in order to avoid memory fragmentation.
315 c1 = talloc_strndup(talloc_tos(), s1, n1);
316 c2 = talloc_strndup(talloc_tos(), s2, n2);
317 if (c1 == NULL || c2 == NULL) {
318 TALLOC_FREE(c2);
319 TALLOC_FREE(c1);
320 return (strncmp(s1, s2, n1) == 0);
323 match = strequal(c1, c2);
324 TALLOC_FREE(c2);
325 TALLOC_FREE(c1);
326 return match;
329 /****************************************************************************
330 Scan a directory to find a filename, matching without case sensitivity.
331 If the name looks like a mangled name then try via the mangling functions
332 ****************************************************************************/
334 NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
335 const char *name,
336 bool mangled,
337 TALLOC_CTX *mem_ctx,
338 char **found_name)
340 struct connection_struct *conn = dirfsp->conn;
341 struct smb_Dir *cur_dir = NULL;
342 const char *dname = NULL;
343 char *talloced = NULL;
344 char *unmangled_name = NULL;
345 long curpos;
346 NTSTATUS status;
348 /* If we have a case-sensitive filesystem, it doesn't do us any
349 * good to search for a name. If a case variation of the name was
350 * there, then the original stat(2) would have found it.
352 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
353 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
357 * The incoming name can be mangled, and if we de-mangle it
358 * here it will not compare correctly against the filename (name2)
359 * read from the directory and then mangled by the name_to_8_3()
360 * call. We need to mangle both names or neither.
361 * (JRA).
363 * Fix for bug found by Dina Fine. If in case sensitive mode then
364 * the mangle cache is no good (3 letter extension could be wrong
365 * case - so don't demangle in this case - leave as mangled and
366 * allow the mangling of the directory entry read (which is done
367 * case insensitively) to match instead. This will lead to more
368 * false positive matches but we fail completely without it. JRA.
371 if (mangled && !conn->case_sensitive) {
372 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
373 &unmangled_name,
374 conn->params);
375 if (!mangled) {
376 /* Name is now unmangled. */
377 name = unmangled_name;
381 /* open the directory */
382 status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
383 if (!NT_STATUS_IS_OK(status)) {
384 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
385 fsp_str_dbg(dirfsp),
386 nt_errstr(status));
387 TALLOC_FREE(unmangled_name);
388 return status;
391 /* now scan for matching names */
392 curpos = 0;
393 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
395 /* Is it dot or dot dot. */
396 if (ISDOT(dname) || ISDOTDOT(dname)) {
397 TALLOC_FREE(talloced);
398 continue;
402 * At this point dname is the unmangled name.
403 * name is either mangled or not, depending on the state
404 * of the "mangled" variable. JRA.
408 * Check mangled name against mangled name, or unmangled name
409 * against unmangled name.
412 if ((mangled && mangled_equal(name,dname,conn->params)) ||
413 fname_equal(name, dname, conn->case_sensitive)) {
414 /* we've found the file, change it's name and return */
415 *found_name = talloc_strdup(mem_ctx, dname);
416 TALLOC_FREE(unmangled_name);
417 TALLOC_FREE(cur_dir);
418 if (!*found_name) {
419 TALLOC_FREE(talloced);
420 return NT_STATUS_NO_MEMORY;
422 TALLOC_FREE(talloced);
423 return NT_STATUS_OK;
425 TALLOC_FREE(talloced);
428 TALLOC_FREE(unmangled_name);
429 TALLOC_FREE(cur_dir);
430 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
433 /****************************************************************************
434 Wrapper around the vfs get_real_filename and the full directory scan
435 fallback.
436 ****************************************************************************/
438 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
439 const char *name,
440 TALLOC_CTX *mem_ctx,
441 char **found_name)
443 struct connection_struct *conn = dirfsp->conn;
444 NTSTATUS status;
445 bool mangled;
447 mangled = mangle_is_mangled(name, conn->params);
449 if (mangled) {
450 status = get_real_filename_full_scan_at(
451 dirfsp, name, mangled, mem_ctx, found_name);
452 return status;
455 /* Try the vfs first to take advantage of case-insensitive stat. */
456 status = SMB_VFS_GET_REAL_FILENAME_AT(
457 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
460 * If the case-insensitive stat was successful, or returned an error
461 * other than EOPNOTSUPP then there is no need to fall back on the
462 * full directory scan.
464 if (NT_STATUS_IS_OK(status) ||
465 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
466 return status;
469 status = get_real_filename_full_scan_at(
470 dirfsp, name, mangled, mem_ctx, found_name);
471 return status;
475 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
476 * the stat cache for the last component to be looked up. Cache
477 * contents is the correctly capitalized translation of the parameter
478 * "name" as it exists on disk. This is indexed by inode of the dirfsp
479 * and name, and contrary to stat_cahce_lookup() it does not
480 * vfs_stat() the last component. This will be taken care of by an
481 * attempt to do a openat_pathref_fsp().
483 static bool get_real_filename_cache_key(
484 TALLOC_CTX *mem_ctx,
485 struct files_struct *dirfsp,
486 const char *name,
487 DATA_BLOB *_key)
489 struct file_id fid = vfs_file_id_from_sbuf(
490 dirfsp->conn, &dirfsp->fsp_name->st);
491 char *upper = NULL;
492 uint8_t *key = NULL;
493 size_t namelen, keylen;
495 upper = talloc_strdup_upper(mem_ctx, name);
496 if (upper == NULL) {
497 return false;
499 namelen = talloc_get_size(upper);
501 keylen = namelen + sizeof(fid);
502 if (keylen < sizeof(fid)) {
503 TALLOC_FREE(upper);
504 return false;
507 key = talloc_size(mem_ctx, keylen);
508 if (key == NULL) {
509 TALLOC_FREE(upper);
510 return false;
513 memcpy(key, &fid, sizeof(fid));
514 memcpy(key + sizeof(fid), upper, namelen);
515 TALLOC_FREE(upper);
517 *_key = (DATA_BLOB) { .data = key, .length = keylen, };
518 return true;
522 * Lightweight function to just get last component
523 * for rename / enumerate directory calls.
526 char *get_original_lcomp(TALLOC_CTX *ctx,
527 connection_struct *conn,
528 const char *filename_in,
529 uint32_t ucf_flags)
531 char *last_slash = NULL;
532 char *orig_lcomp;
533 NTSTATUS status;
535 last_slash = strrchr(filename_in, '/');
536 if (last_slash != NULL) {
537 orig_lcomp = talloc_strdup(ctx, last_slash+1);
538 } else {
539 orig_lcomp = talloc_strdup(ctx, filename_in);
541 if (orig_lcomp == NULL) {
542 return NULL;
544 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
545 if (!NT_STATUS_IS_OK(status)) {
546 TALLOC_FREE(orig_lcomp);
547 return NULL;
549 return orig_lcomp;
553 * Deal with the SMB1 semantics of sending a pathname with a
554 * wildcard as the terminal component for a SMB1search or
555 * trans2 findfirst.
558 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
559 connection_struct *conn,
560 char *name_in,
561 uint32_t ucf_flags,
562 struct files_struct **_dirfsp,
563 struct smb_filename **_smb_fname_out,
564 char **_mask_out)
566 NTSTATUS status;
567 char *p = NULL;
568 char *mask = NULL;
569 struct smb_filename *smb_fname = NULL;
570 NTTIME twrp = 0;
572 *_smb_fname_out = NULL;
573 *_dirfsp = NULL;
574 *_mask_out = NULL;
576 DBG_DEBUG("name_in: %s\n", name_in);
578 if (ucf_flags & UCF_GMT_PATHNAME) {
579 extract_snapshot_token(name_in, &twrp);
580 ucf_flags &= ~UCF_GMT_PATHNAME;
583 if (ucf_flags & UCF_DFS_PATHNAME) {
585 * We've been given a raw DFS pathname.
587 char *pathname = NULL;
588 DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in);
589 status = dfs_filename_convert(ctx,
590 conn,
591 ucf_flags,
592 name_in,
593 &pathname);
594 if (!NT_STATUS_IS_OK(status)) {
595 DBG_DEBUG("dfs_filename_convert "
596 "failed for name %s with %s\n",
597 name_in,
598 nt_errstr(status));
599 return status;
601 ucf_flags &= ~UCF_DFS_PATHNAME;
602 name_in = pathname;
603 DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in);
606 /* Get the original lcomp. */
607 mask = get_original_lcomp(ctx,
608 conn,
609 name_in,
610 ucf_flags);
611 if (mask == NULL) {
612 return NT_STATUS_NO_MEMORY;
615 if (mask[0] == '\0') {
616 /* Windows and OS/2 systems treat search on the root as * */
617 TALLOC_FREE(mask);
618 mask = talloc_strdup(ctx, "*");
619 if (mask == NULL) {
620 return NT_STATUS_NO_MEMORY;
624 DBG_DEBUG("mask = %s\n", mask);
627 * Remove the terminal component so
628 * filename_convert_dirfsp never sees the mask.
630 p = strrchr_m(name_in,'/');
631 if (p == NULL) {
632 /* filename_convert_dirfsp handles a '\0' name. */
633 name_in[0] = '\0';
634 } else {
635 *p = '\0';
638 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
639 name_in);
641 /* Convert the parent directory path. */
642 status = filename_convert_dirfsp(ctx,
643 conn,
644 name_in,
645 ucf_flags,
646 twrp,
647 _dirfsp,
648 &smb_fname);
650 if (!NT_STATUS_IS_OK(status)) {
651 DBG_DEBUG("filename_convert error for %s: %s\n",
652 name_in,
653 nt_errstr(status));
656 *_smb_fname_out = talloc_move(ctx, &smb_fname);
657 *_mask_out = talloc_move(ctx, &mask);
659 return status;
663 * Get the correct capitalized stream name hanging off
664 * base_fsp. Equivalent of get_real_filename(), but for streams.
666 static NTSTATUS get_real_stream_name(
667 TALLOC_CTX *mem_ctx,
668 struct files_struct *base_fsp,
669 const char *stream_name,
670 char **_found)
672 unsigned int i, num_streams = 0;
673 struct stream_struct *streams = NULL;
674 NTSTATUS status;
676 status = vfs_fstreaminfo(
677 base_fsp, talloc_tos(), &num_streams, &streams);
678 if (!NT_STATUS_IS_OK(status)) {
679 return status;
682 for (i=0; i<num_streams; i++) {
683 bool equal = sname_equal(stream_name, streams[i].name, false);
685 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
686 stream_name,
687 streams[i].name,
688 equal ? "" : "not ");
690 if (equal) {
691 *_found = talloc_move(mem_ctx, &streams[i].name);
692 TALLOC_FREE(streams);
693 return NT_STATUS_OK;
697 TALLOC_FREE(streams);
698 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
701 static bool filename_split_lcomp(
702 TALLOC_CTX *mem_ctx,
703 const char *name_in,
704 bool posix,
705 char **_dirname,
706 const char **_fname_rel,
707 const char **_streamname)
709 const char *lcomp = NULL;
710 const char *fname_rel = NULL;
711 const char *streamname = NULL;
712 char *dirname = NULL;
714 if (name_in[0] == '\0') {
715 fname_rel = ".";
716 dirname = talloc_strdup(mem_ctx, "");
717 if (dirname == NULL) {
718 return false;
720 goto done;
723 lcomp = strrchr_m(name_in, '/');
724 if (lcomp != NULL) {
725 fname_rel = lcomp+1;
726 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
727 if (dirname == NULL) {
728 return false;
730 goto find_stream;
734 * No slash, dir is emtpy
736 dirname = talloc_strdup(mem_ctx, "");
737 if (dirname == NULL) {
738 return false;
741 if (!posix && (name_in[0] == ':')) {
743 * Special case for stream on root directory
745 fname_rel = ".";
746 streamname = name_in;
747 goto done;
750 fname_rel = name_in;
752 find_stream:
753 if (!posix) {
754 streamname = strchr_m(fname_rel, ':');
756 if (streamname != NULL) {
757 fname_rel = talloc_strndup(
758 mem_ctx,
759 fname_rel,
760 streamname - fname_rel);
761 if (fname_rel == NULL) {
762 TALLOC_FREE(dirname);
763 return false;
768 done:
769 *_dirname = dirname;
770 *_fname_rel = fname_rel;
771 *_streamname = streamname;
772 return true;
776 * Create the correct capitalization of a file name to be created.
778 static NTSTATUS filename_convert_normalize_new(
779 TALLOC_CTX *mem_ctx,
780 struct connection_struct *conn,
781 char *name_in,
782 char **_normalized)
784 char *name = name_in;
786 *_normalized = NULL;
788 if (!conn->case_preserve ||
789 (mangle_is_8_3(name, false,
790 conn->params) &&
791 !conn->short_case_preserve)) {
793 char *normalized = talloc_strdup(mem_ctx, name);
794 if (normalized == NULL) {
795 return NT_STATUS_NO_MEMORY;
798 strnorm(normalized, lp_default_case(SNUM(conn)));
799 name = normalized;
802 if (mangle_is_mangled(name, conn->params)) {
803 bool found;
804 char *unmangled = NULL;
806 found = mangle_lookup_name_from_8_3(
807 mem_ctx, name, &unmangled, conn->params);
808 if (found) {
809 name = unmangled;
813 if (name != name_in) {
814 *_normalized = name;
817 return NT_STATUS_OK;
821 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
822 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
823 * the first attempt based on the filename sent by the client gives
824 * ENOENT.
826 static NTSTATUS openat_pathref_fsp_case_insensitive(
827 struct files_struct *dirfsp,
828 struct smb_filename *smb_fname_rel,
829 uint32_t ucf_flags)
831 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
832 DATA_BLOB cache_key = { .data = NULL, };
833 char *found_name = NULL;
834 NTSTATUS status;
835 bool ok;
837 SET_STAT_INVALID(smb_fname_rel->st);
839 /* Check veto files - only looks at last component. */
840 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
841 DBG_DEBUG("veto files rejecting last component %s\n",
842 smb_fname_str_dbg(smb_fname_rel));
843 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
846 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
848 if (NT_STATUS_IS_OK(status)) {
849 return NT_STATUS_OK;
852 if (VALID_STAT(smb_fname_rel->st)) {
854 * We got an error although the object existed. Might
855 * be a symlink we don't want.
857 return status;
860 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
862 * Only retry on ENOENT
864 return status;
867 if (posix || dirfsp->conn->case_sensitive) {
869 * Only return case insensitive if required
871 return status;
874 if (lp_stat_cache()) {
875 char *base_name = smb_fname_rel->base_name;
876 DATA_BLOB value = { .data = NULL };
878 ok = get_real_filename_cache_key(
879 talloc_tos(), dirfsp, base_name, &cache_key);
880 if (!ok) {
882 * probably ENOMEM, just bail
884 return status;
887 DO_PROFILE_INC(statcache_lookups);
889 ok = memcache_lookup(
890 NULL, GETREALFILENAME_CACHE, cache_key, &value);
891 if (!ok) {
892 DO_PROFILE_INC(statcache_misses);
893 goto lookup;
895 DO_PROFILE_INC(statcache_hits);
897 TALLOC_FREE(smb_fname_rel->base_name);
898 smb_fname_rel->base_name = talloc_memdup(
899 smb_fname_rel, value.data, value.length);
900 if (smb_fname_rel->base_name == NULL) {
901 TALLOC_FREE(cache_key.data);
902 return NT_STATUS_NO_MEMORY;
905 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
906 DBG_DEBUG("veto files rejecting last component %s\n",
907 smb_fname_str_dbg(smb_fname_rel));
908 TALLOC_FREE(cache_key.data);
909 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
912 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
913 if (NT_STATUS_IS_OK(status)) {
914 TALLOC_FREE(cache_key.data);
915 return NT_STATUS_OK;
918 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
921 lookup:
922 status = get_real_filename_at(
923 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
924 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
925 (ucf_flags & UCF_PREP_CREATEFILE)) {
927 * dropbox
929 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
932 if (NT_STATUS_IS_OK(status)) {
933 TALLOC_FREE(smb_fname_rel->base_name);
934 smb_fname_rel->base_name = found_name;
936 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
937 DBG_DEBUG("veto files rejecting last component %s\n",
938 smb_fname_str_dbg(smb_fname_rel));
939 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
942 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
945 if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
946 DATA_BLOB value = {
947 .data = (uint8_t *)smb_fname_rel->base_name,
948 .length = strlen(smb_fname_rel->base_name) + 1,
951 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
954 TALLOC_FREE(cache_key.data);
956 return status;
960 * Split up name_in as sent by the client into a directory pathref fsp
961 * and a relative smb_filename.
963 static const char *previous_slash(const char *name_in, const char *slash)
965 const char *prev = name_in;
967 while (true) {
968 const char *next = strchr_m(prev, '/');
970 SMB_ASSERT(next != NULL); /* we have at least one slash */
972 if (next == slash) {
973 break;
976 prev = next+1;
979 if (prev == name_in) {
980 /* no previous slash */
981 return NULL;
984 return prev;
987 static char *symlink_target_path(
988 TALLOC_CTX *mem_ctx,
989 const char *name_in,
990 const char *substitute,
991 size_t unparsed)
993 size_t name_in_len = strlen(name_in);
994 const char *p_unparsed = NULL;
995 const char *parent = NULL;
996 char *ret;
998 SMB_ASSERT(unparsed <= name_in_len);
1000 p_unparsed = name_in + (name_in_len - unparsed);
1002 if (substitute[0] == '/') {
1003 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
1004 return ret;
1007 if (unparsed == 0) {
1008 parent = strrchr_m(name_in, '/');
1009 } else {
1010 parent = previous_slash(name_in, p_unparsed);
1013 if (parent == NULL) {
1014 /* no previous slash */
1015 parent = name_in;
1018 ret = talloc_asprintf(
1019 mem_ctx,
1020 "%.*s%s%s",
1021 (int)(parent - name_in),
1022 name_in,
1023 substitute,
1024 p_unparsed);
1025 return ret;
1029 * Split up name_in as sent by the client into a directory pathref fsp
1030 * and a relative smb_filename.
1032 static NTSTATUS filename_convert_dirfsp_nosymlink(
1033 TALLOC_CTX *mem_ctx,
1034 connection_struct *conn,
1035 const char *name_in,
1036 uint32_t ucf_flags,
1037 NTTIME twrp,
1038 struct files_struct **_dirfsp,
1039 struct smb_filename **_smb_fname,
1040 char **_substitute,
1041 size_t *_unparsed)
1043 struct smb_filename *smb_dirname = NULL;
1044 struct smb_filename *smb_fname_rel = NULL;
1045 struct smb_filename *smb_fname = NULL;
1046 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
1047 char *dirname = NULL;
1048 const char *fname_rel = NULL;
1049 const char *streamname = NULL;
1050 char *saved_streamname = NULL;
1051 struct files_struct *base_fsp = NULL;
1052 bool ok;
1053 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1055 if (ucf_flags & UCF_DFS_PATHNAME) {
1057 * We've been given a raw DFS pathname.
1059 char *pathname = NULL;
1060 DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in);
1061 status = dfs_filename_convert(mem_ctx,
1062 conn,
1063 ucf_flags,
1064 name_in,
1065 &pathname);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 DBG_DEBUG("dfs_filename_convert "
1068 "failed for name %s with %s\n",
1069 name_in,
1070 nt_errstr(status));
1071 return status;
1073 ucf_flags &= ~UCF_DFS_PATHNAME;
1074 name_in = pathname;
1075 DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in);
1078 if (is_fake_file_path(name_in)) {
1079 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
1080 if (smb_fname == NULL) {
1081 return NT_STATUS_NO_MEMORY;
1083 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1084 smb_fname->st.st_ex_btime =
1085 (struct timespec){0, SAMBA_UTIME_OMIT};
1086 smb_fname->st.st_ex_atime =
1087 (struct timespec){0, SAMBA_UTIME_OMIT};
1088 smb_fname->st.st_ex_mtime =
1089 (struct timespec){0, SAMBA_UTIME_OMIT};
1090 smb_fname->st.st_ex_ctime =
1091 (struct timespec){0, SAMBA_UTIME_OMIT};
1093 *_dirfsp = conn->cwd_fsp;
1094 *_smb_fname = smb_fname;
1095 return NT_STATUS_OK;
1099 * Catch an invalid path of "." before we
1100 * call filename_split_lcomp(). We need to
1101 * do this as filename_split_lcomp() will
1102 * use "." for the missing relative component
1103 * when an empty name_in path is sent by
1104 * the client.
1106 if (ISDOT(name_in)) {
1107 status = NT_STATUS_OBJECT_NAME_INVALID;
1108 goto fail;
1111 ok = filename_split_lcomp(
1112 talloc_tos(),
1113 name_in,
1114 posix,
1115 &dirname,
1116 &fname_rel,
1117 &streamname);
1118 if (!ok) {
1119 status = NT_STATUS_NO_MEMORY;
1120 goto fail;
1123 if ((streamname != NULL) &&
1124 ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
1125 status = NT_STATUS_OBJECT_NAME_INVALID;
1126 goto fail;
1129 if (!posix) {
1130 bool name_has_wild = ms_has_wild(dirname);
1131 name_has_wild |= ms_has_wild(fname_rel);
1132 if (name_has_wild) {
1133 status = NT_STATUS_OBJECT_NAME_INVALID;
1134 goto fail;
1138 if (dirname[0] == '\0') {
1139 status = synthetic_pathref(
1140 mem_ctx,
1141 conn->cwd_fsp,
1142 ".",
1143 NULL,
1144 NULL,
1146 posix ? SMB_FILENAME_POSIX_PATH : 0,
1147 &smb_dirname);
1148 } else {
1149 char *substitute = NULL;
1150 size_t unparsed = 0;
1152 status = openat_pathref_dirfsp_nosymlink(
1153 mem_ctx,
1154 conn,
1155 dirname,
1157 &smb_dirname,
1158 &unparsed,
1159 &substitute);
1161 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1163 size_t name_in_len = strlen(name_in);
1164 size_t dirname_len = strlen(dirname);
1166 SMB_ASSERT(name_in_len >= dirname_len);
1168 *_substitute = substitute;
1169 *_unparsed = unparsed + (name_in_len - dirname_len);
1171 goto fail;
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DBG_DEBUG("opening directory %s failed: %s\n",
1177 dirname,
1178 nt_errstr(status));
1179 TALLOC_FREE(dirname);
1181 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1182 /* MS-DFS error must propagate back out. */
1183 goto fail;
1186 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1188 * Except ACCESS_DENIED, everything else leads
1189 * to PATH_NOT_FOUND.
1191 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1194 goto fail;
1197 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
1198 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1199 goto fail;
1203 * Only look at bad last component values
1204 * once we know we have a valid directory. That
1205 * way we won't confuse error messages from
1206 * opening the directory path with error
1207 * messages from a bad last component.
1210 /* Relative filename can't be empty */
1211 if (fname_rel[0] == '\0') {
1212 status = NT_STATUS_OBJECT_NAME_INVALID;
1213 goto fail;
1216 /* Relative filename can't be ".." */
1217 if (ISDOTDOT(fname_rel)) {
1218 status = NT_STATUS_OBJECT_NAME_INVALID;
1219 goto fail;
1221 /* Relative name can only be dot if directory is empty. */
1222 if (ISDOT(fname_rel) && dirname[0] != '\0') {
1223 status = NT_STATUS_OBJECT_NAME_INVALID;
1224 goto fail;
1227 TALLOC_FREE(dirname);
1229 smb_fname_rel = synthetic_smb_fname(
1230 mem_ctx,
1231 fname_rel,
1232 streamname,
1233 NULL,
1234 twrp,
1235 posix ? SMB_FILENAME_POSIX_PATH : 0);
1236 if (smb_fname_rel == NULL) {
1237 status = NT_STATUS_NO_MEMORY;
1238 goto fail;
1241 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
1242 is_named_stream(smb_fname_rel)) {
1244 * Find the base_fsp first without the stream.
1246 saved_streamname = smb_fname_rel->stream_name;
1247 smb_fname_rel->stream_name = NULL;
1250 status = normalize_filename_case(
1251 conn, smb_fname_rel->base_name, ucf_flags);
1252 if (!NT_STATUS_IS_OK(status)) {
1253 DBG_ERR("normalize_filename_case %s failed: %s\n",
1254 smb_fname_rel->base_name,
1255 nt_errstr(status));
1256 goto fail;
1259 status = openat_pathref_fsp_case_insensitive(
1260 smb_dirname->fsp, smb_fname_rel, ucf_flags);
1262 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1264 char *normalized = NULL;
1266 if (VALID_STAT(smb_fname_rel->st)) {
1268 * If we're on an MSDFS share, see if this is
1269 * an MSDFS link.
1271 if (lp_host_msdfs() &&
1272 lp_msdfs_root(SNUM(conn)) &&
1273 S_ISLNK(smb_fname_rel->st.st_ex_mode) &&
1274 is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
1276 status = NT_STATUS_PATH_NOT_COVERED;
1277 goto fail;
1280 #if defined(WITH_SMB1SERVER)
1282 * In SMB1 posix mode, if this is a symlink,
1283 * allow access to the name with a NULL smb_fname->fsp.
1285 if (!conn->sconn->using_smb2 &&
1286 posix &&
1287 S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
1288 SMB_ASSERT(smb_fname_rel->fsp == NULL);
1289 SMB_ASSERT(streamname == NULL);
1291 smb_fname = full_path_from_dirfsp_atname(
1292 mem_ctx,
1293 smb_dirname->fsp,
1294 smb_fname_rel);
1295 if (smb_fname == NULL) {
1296 status = NT_STATUS_NO_MEMORY;
1297 goto fail;
1299 goto done;
1301 #endif
1303 * NT_STATUS_OBJECT_NAME_NOT_FOUND is
1304 * misleading: The object exists but might be
1305 * a symlink pointing outside the share.
1307 goto fail;
1311 * Creating a new file
1314 status = filename_convert_normalize_new(
1315 smb_fname_rel,
1316 conn,
1317 smb_fname_rel->base_name,
1318 &normalized);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 DBG_DEBUG("filename_convert_normalize_new failed: "
1321 "%s\n",
1322 nt_errstr(status));
1323 goto fail;
1325 if (normalized != NULL) {
1326 smb_fname_rel->base_name = normalized;
1329 smb_fname_rel->stream_name = saved_streamname;
1331 smb_fname = full_path_from_dirfsp_atname(
1332 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1333 if (smb_fname == NULL) {
1334 status = NT_STATUS_NO_MEMORY;
1335 goto fail;
1337 goto done;
1340 if (!NT_STATUS_IS_OK(status)) {
1341 goto fail;
1344 if (saved_streamname == NULL) {
1345 /* smb_fname must be allocated off mem_ctx. */
1346 smb_fname = cp_smb_filename(mem_ctx,
1347 smb_fname_rel->fsp->fsp_name);
1348 if (smb_fname == NULL) {
1349 goto fail;
1351 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1352 if (!NT_STATUS_IS_OK(status)) {
1353 goto fail;
1355 goto done;
1358 base_fsp = smb_fname_rel->fsp;
1359 smb_fname_fsp_unlink(smb_fname_rel);
1360 SET_STAT_INVALID(smb_fname_rel->st);
1362 smb_fname_rel->stream_name = saved_streamname;
1364 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1366 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1367 !conn->case_sensitive) {
1368 char *found = NULL;
1370 status = get_real_stream_name(
1371 smb_fname_rel,
1372 base_fsp,
1373 smb_fname_rel->stream_name,
1374 &found);
1376 if (NT_STATUS_IS_OK(status)) {
1377 smb_fname_rel->stream_name = found;
1378 found = NULL;
1379 status = open_stream_pathref_fsp(
1380 &base_fsp, smb_fname_rel);
1384 if (NT_STATUS_IS_OK(status)) {
1385 /* smb_fname must be allocated off mem_ctx. */
1386 smb_fname = cp_smb_filename(mem_ctx,
1387 smb_fname_rel->fsp->fsp_name);
1388 if (smb_fname == NULL) {
1389 goto fail;
1391 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1392 if (!NT_STATUS_IS_OK(status)) {
1393 goto fail;
1395 goto done;
1398 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1400 * Creating a new stream
1402 * We should save the already-open base fsp for
1403 * create_file_unixpath() somehow.
1405 smb_fname = full_path_from_dirfsp_atname(
1406 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1407 if (smb_fname == NULL) {
1408 status = NT_STATUS_NO_MEMORY;
1409 goto fail;
1411 goto done;
1414 if (!NT_STATUS_IS_OK(status)) {
1415 goto fail;
1418 done:
1419 *_dirfsp = smb_dirname->fsp;
1420 *_smb_fname = smb_fname;
1422 smb_fname_fsp_unlink(smb_fname_rel);
1423 TALLOC_FREE(smb_fname_rel);
1424 return NT_STATUS_OK;
1426 fail:
1427 TALLOC_FREE(dirname);
1428 TALLOC_FREE(smb_dirname);
1429 TALLOC_FREE(smb_fname_rel);
1430 return status;
1433 NTSTATUS filename_convert_dirfsp(
1434 TALLOC_CTX *mem_ctx,
1435 connection_struct *conn,
1436 const char *name_in,
1437 uint32_t ucf_flags,
1438 NTTIME twrp,
1439 struct files_struct **_dirfsp,
1440 struct smb_filename **_smb_fname)
1442 char *substitute = NULL;
1443 size_t unparsed = 0;
1444 NTSTATUS status;
1445 char *target = NULL;
1446 char *abs_target = NULL;
1447 char *abs_target_canon = NULL;
1448 size_t symlink_redirects = 0;
1449 bool in_share;
1451 next:
1452 if (symlink_redirects > 40) {
1453 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1456 status = filename_convert_dirfsp_nosymlink(
1457 mem_ctx,
1458 conn,
1459 name_in,
1460 ucf_flags,
1461 twrp,
1462 _dirfsp,
1463 _smb_fname,
1464 &substitute,
1465 &unparsed);
1467 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1468 return status;
1471 if (!lp_follow_symlinks(SNUM(conn))) {
1472 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1476 * Right now, SMB2 and SMB1 always traverse symlinks
1477 * within the share. SMB1+POSIX traverses non-terminal
1478 * symlinks within the share.
1480 * When we add SMB2+POSIX we need to return
1481 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1482 * symlink target data read below if SMB2+POSIX has
1483 * UCF_POSIX_PATHNAMES set to cause the client to
1484 * resolve all symlinks locally.
1487 target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
1488 if (target == NULL) {
1489 return NT_STATUS_NO_MEMORY;
1492 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
1493 name_in,
1494 substitute,
1495 unparsed,
1496 target);
1498 if (target[0] == '/') {
1499 abs_target = target;
1500 } else {
1501 abs_target = talloc_asprintf(
1502 mem_ctx, "%s/%s", conn->connectpath, target);
1503 if (abs_target == NULL) {
1504 return NT_STATUS_NO_MEMORY;
1508 abs_target_canon = canonicalize_absolute_path(mem_ctx, abs_target);
1509 if (abs_target_canon == NULL) {
1510 return NT_STATUS_NO_MEMORY;
1513 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
1515 in_share = strncmp(
1516 abs_target_canon,
1517 conn->connectpath,
1518 strlen(conn->connectpath)) == 0;
1519 if (!in_share) {
1520 DBG_DEBUG("wide link to %s\n", abs_target_canon);
1521 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1524 name_in = talloc_strdup(
1525 mem_ctx, abs_target_canon + strlen(conn->connectpath) + 1);
1527 symlink_redirects += 1;
1529 goto next;
1533 * Build the full path from a dirfsp and dirfsp relative name
1535 struct smb_filename *full_path_from_dirfsp_atname(
1536 TALLOC_CTX *mem_ctx,
1537 const struct files_struct *dirfsp,
1538 const struct smb_filename *atname)
1540 struct smb_filename *fname = NULL;
1541 char *path = NULL;
1543 if (dirfsp == dirfsp->conn->cwd_fsp ||
1544 ISDOT(dirfsp->fsp_name->base_name) ||
1545 atname->base_name[0] == '/')
1547 path = talloc_strdup(mem_ctx, atname->base_name);
1548 } else {
1549 path = talloc_asprintf(mem_ctx, "%s/%s",
1550 dirfsp->fsp_name->base_name,
1551 atname->base_name);
1553 if (path == NULL) {
1554 return NULL;
1557 fname = synthetic_smb_fname(mem_ctx,
1558 path,
1559 atname->stream_name,
1560 &atname->st,
1561 atname->twrp,
1562 atname->flags);
1563 TALLOC_FREE(path);
1564 if (fname == NULL) {
1565 return NULL;
1568 return fname;