vfs_gpfs: Move call to load GPFS library
[Samba.git] / source3 / smbd / filename.c
blob3cffef1cfeeb8f98bab01c9ed7101398ff2361a4
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 return 0;
42 if (req->posix_pathnames) {
43 ucf_flags |= UCF_POSIX_PATHNAMES;
45 if (!req->sconn->using_smb2) {
46 ucf_flags |= UCF_LCOMP_LNK_OK;
49 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
50 ucf_flags |= UCF_DFS_PATHNAME;
52 if (req->flags2 & FLAGS2_REPARSE_PATH) {
53 ucf_flags |= UCF_GMT_PATHNAME;
56 return ucf_flags;
59 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
61 uint32_t ucf_flags = 0;
63 ucf_flags |= ucf_flags_from_smb_request(req);
65 switch (create_disposition) {
66 case FILE_OPEN:
67 case FILE_OVERWRITE:
68 break;
69 case FILE_SUPERSEDE:
70 case FILE_CREATE:
71 case FILE_OPEN_IF:
72 case FILE_OVERWRITE_IF:
73 ucf_flags |= UCF_PREP_CREATEFILE;
74 break;
77 return ucf_flags;
80 /****************************************************************************
81 Mangle the 2nd name and check if it is then equal to the first name.
82 ****************************************************************************/
84 static bool mangled_equal(const char *name1,
85 const char *name2,
86 const struct share_params *p)
88 char mname[13];
90 if (!name_to_8_3(name2, mname, False, p)) {
91 return False;
93 return strequal(name1, mname);
97 * Strip a valid @GMT-token from any incoming filename path,
98 * adding any NTTIME encoded in the pathname into the
99 * twrp field of the passed in smb_fname.
101 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
102 * at the *start* of a pathname component.
104 * If twrp is passed in then smb_fname->twrp is set to that
105 * value, and the @GMT-token part of the filename is removed
106 * and does not change the stored smb_fname->twrp.
110 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
111 uint32_t ucf_flags,
112 NTTIME twrp)
114 bool found;
116 if (twrp != 0) {
117 smb_fname->twrp = twrp;
120 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
121 return NT_STATUS_OK;
124 found = extract_snapshot_token(smb_fname->base_name, &twrp);
125 if (!found) {
126 return NT_STATUS_OK;
129 if (smb_fname->twrp == 0) {
130 smb_fname->twrp = twrp;
133 return NT_STATUS_OK;
136 static bool strnorm(char *s, int case_default)
138 if (case_default == CASE_UPPER)
139 return strupper_m(s);
140 else
141 return strlower_m(s);
145 * Utility function to normalize case on an incoming client filename
146 * if required on this connection struct.
147 * Performs an in-place case conversion guaranteed to stay the same size.
150 static NTSTATUS normalize_filename_case(connection_struct *conn,
151 char *filename,
152 uint32_t ucf_flags)
154 bool ok;
156 if (ucf_flags & UCF_POSIX_PATHNAMES) {
158 * POSIX never normalizes filename case.
160 return NT_STATUS_OK;
162 if (!conn->case_sensitive) {
163 return NT_STATUS_OK;
165 if (conn->case_preserve) {
166 return NT_STATUS_OK;
168 if (conn->short_case_preserve) {
169 return NT_STATUS_OK;
171 ok = strnorm(filename, lp_default_case(SNUM(conn)));
172 if (!ok) {
173 return NT_STATUS_INVALID_PARAMETER;
175 return NT_STATUS_OK;
178 /****************************************************************************
179 Check if two filenames are equal.
180 This needs to be careful about whether we are case sensitive.
181 ****************************************************************************/
183 static bool fname_equal(const char *name1, const char *name2,
184 bool case_sensitive)
186 /* Normal filename handling */
187 if (case_sensitive) {
188 return(strcmp(name1,name2) == 0);
191 return(strequal(name1,name2));
194 static bool sname_equal(const char *name1, const char *name2,
195 bool case_sensitive)
197 bool match;
198 const char *s1 = NULL;
199 const char *s2 = NULL;
200 size_t n1;
201 size_t n2;
202 const char *e1 = NULL;
203 const char *e2 = NULL;
204 char *c1 = NULL;
205 char *c2 = NULL;
207 match = fname_equal(name1, name2, case_sensitive);
208 if (match) {
209 return true;
212 if (name1[0] != ':') {
213 return false;
215 if (name2[0] != ':') {
216 return false;
218 s1 = &name1[1];
219 e1 = strchr(s1, ':');
220 if (e1 == NULL) {
221 n1 = strlen(s1);
222 } else {
223 n1 = PTR_DIFF(e1, s1);
225 s2 = &name2[1];
226 e2 = strchr(s2, ':');
227 if (e2 == NULL) {
228 n2 = strlen(s2);
229 } else {
230 n2 = PTR_DIFF(e2, s2);
233 /* Normal filename handling */
234 if (case_sensitive) {
235 return (strncmp(s1, s2, n1) == 0);
239 * We can't use strnequal() here
240 * as it takes the number of codepoints
241 * and not the number of bytes.
243 * So we make a copy before calling
244 * strequal().
246 * Note that we TALLOC_FREE() in reverse order
247 * in order to avoid memory fragmentation.
250 c1 = talloc_strndup(talloc_tos(), s1, n1);
251 c2 = talloc_strndup(talloc_tos(), s2, n2);
252 if (c1 == NULL || c2 == NULL) {
253 TALLOC_FREE(c2);
254 TALLOC_FREE(c1);
255 return (strncmp(s1, s2, n1) == 0);
258 match = strequal(c1, c2);
259 TALLOC_FREE(c2);
260 TALLOC_FREE(c1);
261 return match;
264 /****************************************************************************
265 Scan a directory to find a filename, matching without case sensitivity.
266 If the name looks like a mangled name then try via the mangling functions
267 ****************************************************************************/
269 NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
270 const char *name,
271 bool mangled,
272 TALLOC_CTX *mem_ctx,
273 char **found_name)
275 struct connection_struct *conn = dirfsp->conn;
276 struct smb_Dir *cur_dir = NULL;
277 const char *dname = NULL;
278 char *talloced = NULL;
279 char *unmangled_name = NULL;
280 NTSTATUS status;
282 /* If we have a case-sensitive filesystem, it doesn't do us any
283 * good to search for a name. If a case variation of the name was
284 * there, then the original stat(2) would have found it.
286 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
287 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
291 * The incoming name can be mangled, and if we de-mangle it
292 * here it will not compare correctly against the filename (name2)
293 * read from the directory and then mangled by the name_to_8_3()
294 * call. We need to mangle both names or neither.
295 * (JRA).
297 * Fix for bug found by Dina Fine. If in case sensitive mode then
298 * the mangle cache is no good (3 letter extension could be wrong
299 * case - so don't demangle in this case - leave as mangled and
300 * allow the mangling of the directory entry read (which is done
301 * case insensitively) to match instead. This will lead to more
302 * false positive matches but we fail completely without it. JRA.
305 if (mangled && !conn->case_sensitive) {
306 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
307 &unmangled_name,
308 conn->params);
309 if (!mangled) {
310 /* Name is now unmangled. */
311 name = unmangled_name;
315 /* open the directory */
316 status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
317 if (!NT_STATUS_IS_OK(status)) {
318 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
319 fsp_str_dbg(dirfsp),
320 nt_errstr(status));
321 TALLOC_FREE(unmangled_name);
322 return status;
325 /* now scan for matching names */
326 while ((dname = ReadDirName(cur_dir, &talloced))) {
328 /* Is it dot or dot dot. */
329 if (ISDOT(dname) || ISDOTDOT(dname)) {
330 TALLOC_FREE(talloced);
331 continue;
335 * At this point dname is the unmangled name.
336 * name is either mangled or not, depending on the state
337 * of the "mangled" variable. JRA.
341 * Check mangled name against mangled name, or unmangled name
342 * against unmangled name.
345 if ((mangled && mangled_equal(name,dname,conn->params)) ||
346 fname_equal(name, dname, conn->case_sensitive)) {
347 /* we've found the file, change it's name and return */
348 *found_name = talloc_strdup(mem_ctx, dname);
349 TALLOC_FREE(unmangled_name);
350 TALLOC_FREE(cur_dir);
351 if (!*found_name) {
352 TALLOC_FREE(talloced);
353 return NT_STATUS_NO_MEMORY;
355 TALLOC_FREE(talloced);
356 return NT_STATUS_OK;
358 TALLOC_FREE(talloced);
361 TALLOC_FREE(unmangled_name);
362 TALLOC_FREE(cur_dir);
363 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
366 /****************************************************************************
367 Wrapper around the vfs get_real_filename and the full directory scan
368 fallback.
369 ****************************************************************************/
371 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
372 const char *name,
373 TALLOC_CTX *mem_ctx,
374 char **found_name)
376 struct connection_struct *conn = dirfsp->conn;
377 NTSTATUS status;
378 bool mangled;
380 mangled = mangle_is_mangled(name, conn->params);
382 if (mangled) {
383 status = get_real_filename_full_scan_at(
384 dirfsp, name, mangled, mem_ctx, found_name);
385 return status;
388 /* Try the vfs first to take advantage of case-insensitive stat. */
389 status = SMB_VFS_GET_REAL_FILENAME_AT(
390 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
393 * If the case-insensitive stat was successful, or returned an error
394 * other than EOPNOTSUPP then there is no need to fall back on the
395 * full directory scan.
397 if (NT_STATUS_IS_OK(status) ||
398 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
399 return status;
402 status = get_real_filename_full_scan_at(
403 dirfsp, name, mangled, mem_ctx, found_name);
404 return status;
408 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
409 * the stat cache for the last component to be looked up. Cache
410 * contents is the correctly capitalized translation of the parameter
411 * "name" as it exists on disk. This is indexed by inode of the dirfsp
412 * and name, and contrary to stat_cahce_lookup() it does not
413 * vfs_stat() the last component. This will be taken care of by an
414 * attempt to do a openat_pathref_fsp().
416 static bool get_real_filename_cache_key(
417 TALLOC_CTX *mem_ctx,
418 struct files_struct *dirfsp,
419 const char *name,
420 DATA_BLOB *_key)
422 struct file_id fid = vfs_file_id_from_sbuf(
423 dirfsp->conn, &dirfsp->fsp_name->st);
424 char *upper = NULL;
425 uint8_t *key = NULL;
426 size_t namelen, keylen;
428 upper = talloc_strdup_upper(mem_ctx, name);
429 if (upper == NULL) {
430 return false;
432 namelen = talloc_get_size(upper);
434 keylen = namelen + sizeof(fid);
435 if (keylen < sizeof(fid)) {
436 TALLOC_FREE(upper);
437 return false;
440 key = talloc_size(mem_ctx, keylen);
441 if (key == NULL) {
442 TALLOC_FREE(upper);
443 return false;
446 memcpy(key, &fid, sizeof(fid));
447 memcpy(key + sizeof(fid), upper, namelen);
448 TALLOC_FREE(upper);
450 *_key = (DATA_BLOB) { .data = key, .length = keylen, };
451 return true;
455 * Lightweight function to just get last component
456 * for rename / enumerate directory calls.
459 char *get_original_lcomp(TALLOC_CTX *ctx,
460 connection_struct *conn,
461 const char *filename_in,
462 uint32_t ucf_flags)
464 char *last_slash = NULL;
465 char *orig_lcomp;
466 NTSTATUS status;
468 last_slash = strrchr(filename_in, '/');
469 if (last_slash != NULL) {
470 orig_lcomp = talloc_strdup(ctx, last_slash+1);
471 } else {
472 orig_lcomp = talloc_strdup(ctx, filename_in);
474 if (orig_lcomp == NULL) {
475 return NULL;
477 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
478 if (!NT_STATUS_IS_OK(status)) {
479 TALLOC_FREE(orig_lcomp);
480 return NULL;
482 return orig_lcomp;
486 * Deal with the SMB1 semantics of sending a pathname with a
487 * wildcard as the terminal component for a SMB1search or
488 * trans2 findfirst.
491 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
492 connection_struct *conn,
493 char *name_in,
494 uint32_t ucf_flags,
495 struct files_struct **_dirfsp,
496 struct smb_filename **_smb_fname_out,
497 char **_mask_out)
499 NTSTATUS status;
500 char *p = NULL;
501 char *mask = NULL;
502 struct smb_filename *smb_fname = NULL;
503 NTTIME twrp = 0;
505 *_smb_fname_out = NULL;
506 *_dirfsp = NULL;
507 *_mask_out = NULL;
509 DBG_DEBUG("name_in: %s\n", name_in);
511 if (ucf_flags & UCF_GMT_PATHNAME) {
512 extract_snapshot_token(name_in, &twrp);
513 ucf_flags &= ~UCF_GMT_PATHNAME;
516 /* Get the original lcomp. */
517 mask = get_original_lcomp(ctx,
518 conn,
519 name_in,
520 ucf_flags);
521 if (mask == NULL) {
522 return NT_STATUS_NO_MEMORY;
525 if (mask[0] == '\0') {
526 /* Windows and OS/2 systems treat search on the root as * */
527 TALLOC_FREE(mask);
528 mask = talloc_strdup(ctx, "*");
529 if (mask == NULL) {
530 return NT_STATUS_NO_MEMORY;
534 DBG_DEBUG("mask = %s\n", mask);
537 * Remove the terminal component so
538 * filename_convert_dirfsp never sees the mask.
540 p = strrchr_m(name_in,'/');
541 if (p == NULL) {
542 /* filename_convert_dirfsp handles a '\0' name. */
543 name_in[0] = '\0';
544 } else {
545 *p = '\0';
548 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
549 name_in);
551 /* Convert the parent directory path. */
552 status = filename_convert_dirfsp(ctx,
553 conn,
554 name_in,
555 ucf_flags,
556 twrp,
557 _dirfsp,
558 &smb_fname);
560 if (!NT_STATUS_IS_OK(status)) {
561 DBG_DEBUG("filename_convert error for %s: %s\n",
562 name_in,
563 nt_errstr(status));
566 *_smb_fname_out = talloc_move(ctx, &smb_fname);
567 *_mask_out = talloc_move(ctx, &mask);
569 return status;
573 * Get the correct capitalized stream name hanging off
574 * base_fsp. Equivalent of get_real_filename(), but for streams.
576 static NTSTATUS get_real_stream_name(
577 TALLOC_CTX *mem_ctx,
578 struct files_struct *base_fsp,
579 const char *stream_name,
580 char **_found)
582 unsigned int i, num_streams = 0;
583 struct stream_struct *streams = NULL;
584 NTSTATUS status;
586 status = vfs_fstreaminfo(
587 base_fsp, talloc_tos(), &num_streams, &streams);
588 if (!NT_STATUS_IS_OK(status)) {
589 return status;
592 for (i=0; i<num_streams; i++) {
593 bool equal = sname_equal(stream_name, streams[i].name, false);
595 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
596 stream_name,
597 streams[i].name,
598 equal ? "" : "not ");
600 if (equal) {
601 *_found = talloc_move(mem_ctx, &streams[i].name);
602 TALLOC_FREE(streams);
603 return NT_STATUS_OK;
607 TALLOC_FREE(streams);
608 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
611 static bool filename_split_lcomp(
612 TALLOC_CTX *mem_ctx,
613 const char *name_in,
614 bool posix,
615 char **_dirname,
616 const char **_fname_rel,
617 const char **_streamname)
619 const char *lcomp = NULL;
620 const char *fname_rel = NULL;
621 const char *streamname = NULL;
622 char *dirname = NULL;
624 if (name_in[0] == '\0') {
625 fname_rel = ".";
626 dirname = talloc_strdup(mem_ctx, "");
627 if (dirname == NULL) {
628 return false;
630 goto done;
633 lcomp = strrchr_m(name_in, '/');
634 if (lcomp != NULL) {
635 fname_rel = lcomp+1;
636 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
637 if (dirname == NULL) {
638 return false;
640 goto find_stream;
644 * No slash, dir is emtpy
646 dirname = talloc_strdup(mem_ctx, "");
647 if (dirname == NULL) {
648 return false;
651 if (!posix && (name_in[0] == ':')) {
653 * Special case for stream on root directory
655 fname_rel = ".";
656 streamname = name_in;
657 goto done;
660 fname_rel = name_in;
662 find_stream:
663 if (!posix) {
664 streamname = strchr_m(fname_rel, ':');
666 if (streamname != NULL) {
667 fname_rel = talloc_strndup(
668 mem_ctx,
669 fname_rel,
670 streamname - fname_rel);
671 if (fname_rel == NULL) {
672 TALLOC_FREE(dirname);
673 return false;
678 done:
679 *_dirname = dirname;
680 *_fname_rel = fname_rel;
681 *_streamname = streamname;
682 return true;
686 * Create the correct capitalization of a file name to be created.
688 static NTSTATUS filename_convert_normalize_new(
689 TALLOC_CTX *mem_ctx,
690 struct connection_struct *conn,
691 char *name_in,
692 char **_normalized)
694 char *name = name_in;
696 *_normalized = NULL;
698 if (!conn->case_preserve ||
699 (mangle_is_8_3(name, false,
700 conn->params) &&
701 !conn->short_case_preserve)) {
703 char *normalized = talloc_strdup(mem_ctx, name);
704 if (normalized == NULL) {
705 return NT_STATUS_NO_MEMORY;
708 strnorm(normalized, lp_default_case(SNUM(conn)));
709 name = normalized;
712 if (mangle_is_mangled(name, conn->params)) {
713 bool found;
714 char *unmangled = NULL;
716 found = mangle_lookup_name_from_8_3(
717 mem_ctx, name, &unmangled, conn->params);
718 if (found) {
719 name = unmangled;
723 if (name != name_in) {
724 *_normalized = name;
727 return NT_STATUS_OK;
731 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
732 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
733 * the first attempt based on the filename sent by the client gives
734 * ENOENT.
736 static NTSTATUS openat_pathref_fsp_case_insensitive(
737 struct files_struct *dirfsp,
738 struct smb_filename *smb_fname_rel,
739 uint32_t ucf_flags)
741 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
742 DATA_BLOB cache_key = { .data = NULL, };
743 char *found_name = NULL;
744 NTSTATUS status;
745 bool ok;
747 SET_STAT_INVALID(smb_fname_rel->st);
749 /* Check veto files - only looks at last component. */
750 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
751 DBG_DEBUG("veto files rejecting last component %s\n",
752 smb_fname_str_dbg(smb_fname_rel));
753 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
756 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
758 if (NT_STATUS_IS_OK(status)) {
759 return NT_STATUS_OK;
762 if (VALID_STAT(smb_fname_rel->st)) {
764 * We got an error although the object existed. Might
765 * be a symlink we don't want.
767 return status;
770 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
772 * Only retry on ENOENT
774 return status;
777 if (posix || dirfsp->conn->case_sensitive) {
779 * Only return case insensitive if required
781 return status;
784 if (lp_stat_cache()) {
785 char *base_name = smb_fname_rel->base_name;
786 DATA_BLOB value = { .data = NULL };
788 ok = get_real_filename_cache_key(
789 talloc_tos(), dirfsp, base_name, &cache_key);
790 if (!ok) {
792 * probably ENOMEM, just bail
794 return status;
797 DO_PROFILE_INC(statcache_lookups);
799 ok = memcache_lookup(
800 NULL, GETREALFILENAME_CACHE, cache_key, &value);
801 if (!ok) {
802 DO_PROFILE_INC(statcache_misses);
803 goto lookup;
805 DO_PROFILE_INC(statcache_hits);
807 TALLOC_FREE(smb_fname_rel->base_name);
808 smb_fname_rel->base_name = talloc_memdup(
809 smb_fname_rel, value.data, value.length);
810 if (smb_fname_rel->base_name == NULL) {
811 TALLOC_FREE(cache_key.data);
812 return NT_STATUS_NO_MEMORY;
815 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
816 DBG_DEBUG("veto files rejecting last component %s\n",
817 smb_fname_str_dbg(smb_fname_rel));
818 TALLOC_FREE(cache_key.data);
819 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
822 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
823 if (NT_STATUS_IS_OK(status)) {
824 TALLOC_FREE(cache_key.data);
825 return NT_STATUS_OK;
828 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
831 lookup:
832 status = get_real_filename_at(
833 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
834 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
835 (ucf_flags & UCF_PREP_CREATEFILE)) {
837 * dropbox
839 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
842 if (NT_STATUS_IS_OK(status)) {
843 TALLOC_FREE(smb_fname_rel->base_name);
844 smb_fname_rel->base_name = found_name;
846 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
847 DBG_DEBUG("veto files rejecting last component %s\n",
848 smb_fname_str_dbg(smb_fname_rel));
849 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
852 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
855 if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
856 DATA_BLOB value = {
857 .data = (uint8_t *)smb_fname_rel->base_name,
858 .length = strlen(smb_fname_rel->base_name) + 1,
861 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
864 TALLOC_FREE(cache_key.data);
866 return status;
869 static const char *previous_slash(const char *name_in, const char *slash)
871 const char *prev = name_in;
873 while (true) {
874 const char *next = strchr_m(prev, '/');
876 SMB_ASSERT(next != NULL); /* we have at least one slash */
878 if (next == slash) {
879 break;
882 prev = next+1;
885 if (prev == name_in) {
886 /* no previous slash */
887 return NULL;
890 return prev;
893 static char *symlink_target_path(
894 TALLOC_CTX *mem_ctx,
895 const char *name_in,
896 const char *substitute,
897 size_t unparsed)
899 size_t name_in_len = strlen(name_in);
900 const char *p_unparsed = NULL;
901 const char *parent = NULL;
902 char *ret;
904 SMB_ASSERT(unparsed <= name_in_len);
906 p_unparsed = name_in + (name_in_len - unparsed);
908 if (substitute[0] == '/') {
909 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
910 return ret;
913 if (unparsed == 0) {
914 parent = strrchr_m(name_in, '/');
915 } else {
916 parent = previous_slash(name_in, p_unparsed);
919 if (parent == NULL) {
920 /* no previous slash */
921 parent = name_in;
924 ret = talloc_asprintf(
925 mem_ctx,
926 "%.*s%s%s",
927 (int)(parent - name_in),
928 name_in,
929 substitute,
930 p_unparsed);
931 return ret;
934 static NTSTATUS safe_symlink_target_path(
935 TALLOC_CTX *mem_ctx,
936 const char *connectpath,
937 const char *name_in,
938 const char *substitute,
939 size_t unparsed,
940 char **_name_out)
942 char *target = NULL;
943 char *abs_target = NULL;
944 char *abs_target_canon = NULL;
945 const char *relative = NULL;
946 char *name_out = NULL;
947 NTSTATUS status = NT_STATUS_NO_MEMORY;
948 bool in_share;
950 target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
951 if (target == NULL) {
952 goto fail;
955 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
956 name_in,
957 substitute,
958 unparsed,
959 target);
961 if (target[0] == '/') {
962 abs_target = target;
963 } else {
964 abs_target = talloc_asprintf(
965 target, "%s/%s", connectpath, target);
966 if (abs_target == NULL) {
967 goto fail;
971 abs_target_canon = canonicalize_absolute_path(target, abs_target);
972 if (abs_target_canon == NULL) {
973 goto fail;
976 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
978 in_share = subdir_of(
979 connectpath, strlen(connectpath), abs_target_canon, &relative);
980 if (!in_share) {
981 DBG_DEBUG("wide link to %s\n", abs_target_canon);
982 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
983 goto fail;
986 name_out = talloc_strdup(mem_ctx, relative);
987 if (name_out == NULL) {
988 goto fail;
991 status = NT_STATUS_OK;
992 *_name_out = name_out;
993 fail:
994 TALLOC_FREE(target);
995 return status;
999 * Split up name_in as sent by the client into a directory pathref fsp
1000 * and a relative smb_filename.
1002 static NTSTATUS filename_convert_dirfsp_nosymlink(
1003 TALLOC_CTX *mem_ctx,
1004 connection_struct *conn,
1005 const char *name_in,
1006 uint32_t ucf_flags,
1007 NTTIME twrp,
1008 struct files_struct **_dirfsp,
1009 struct smb_filename **_smb_fname,
1010 char **_substitute,
1011 size_t *_unparsed)
1013 struct smb_filename *smb_dirname = NULL;
1014 struct smb_filename *smb_fname_rel = NULL;
1015 struct smb_filename *smb_fname = NULL;
1016 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
1017 char *dirname = NULL;
1018 const char *fname_rel = NULL;
1019 const char *streamname = NULL;
1020 char *saved_streamname = NULL;
1021 struct files_struct *base_fsp = NULL;
1022 bool ok;
1023 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1025 SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
1027 if (is_fake_file_path(name_in)) {
1028 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
1029 if (smb_fname == NULL) {
1030 return NT_STATUS_NO_MEMORY;
1032 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1033 smb_fname->st.st_ex_btime =
1034 (struct timespec){0, SAMBA_UTIME_OMIT};
1035 smb_fname->st.st_ex_atime =
1036 (struct timespec){0, SAMBA_UTIME_OMIT};
1037 smb_fname->st.st_ex_mtime =
1038 (struct timespec){0, SAMBA_UTIME_OMIT};
1039 smb_fname->st.st_ex_ctime =
1040 (struct timespec){0, SAMBA_UTIME_OMIT};
1042 *_dirfsp = conn->cwd_fsp;
1043 *_smb_fname = smb_fname;
1044 return NT_STATUS_OK;
1048 * Catch an invalid path of "." before we
1049 * call filename_split_lcomp(). We need to
1050 * do this as filename_split_lcomp() will
1051 * use "." for the missing relative component
1052 * when an empty name_in path is sent by
1053 * the client.
1055 if (ISDOT(name_in)) {
1056 status = NT_STATUS_OBJECT_NAME_INVALID;
1057 goto fail;
1060 ok = filename_split_lcomp(
1061 talloc_tos(),
1062 name_in,
1063 posix,
1064 &dirname,
1065 &fname_rel,
1066 &streamname);
1067 if (!ok) {
1068 status = NT_STATUS_NO_MEMORY;
1069 goto fail;
1072 if ((streamname != NULL) &&
1073 ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
1074 status = NT_STATUS_OBJECT_NAME_INVALID;
1075 goto fail;
1078 if (!posix) {
1079 bool name_has_wild = ms_has_wild(dirname);
1080 name_has_wild |= ms_has_wild(fname_rel);
1081 if (name_has_wild) {
1082 status = NT_STATUS_OBJECT_NAME_INVALID;
1083 goto fail;
1087 if (dirname[0] == '\0') {
1088 status = synthetic_pathref(
1089 mem_ctx,
1090 conn->cwd_fsp,
1091 ".",
1092 NULL,
1093 NULL,
1095 posix ? SMB_FILENAME_POSIX_PATH : 0,
1096 &smb_dirname);
1097 } else {
1098 char *substitute = NULL;
1099 size_t unparsed = 0;
1101 status = normalize_filename_case(conn, dirname, ucf_flags);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 DBG_ERR("normalize_filename_case %s failed: %s\n",
1104 dirname,
1105 nt_errstr(status));
1106 goto fail;
1109 status = openat_pathref_dirfsp_nosymlink(
1110 mem_ctx,
1111 conn,
1112 dirname,
1114 posix,
1115 &smb_dirname,
1116 &unparsed,
1117 &substitute);
1119 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1121 size_t name_in_len = strlen(name_in);
1122 size_t dirname_len = strlen(dirname);
1124 SMB_ASSERT(name_in_len >= dirname_len);
1126 *_substitute = substitute;
1127 *_unparsed = unparsed + (name_in_len - dirname_len);
1129 goto fail;
1133 if (!NT_STATUS_IS_OK(status)) {
1134 DBG_DEBUG("opening directory %s failed: %s\n",
1135 dirname,
1136 nt_errstr(status));
1137 TALLOC_FREE(dirname);
1139 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
1140 /* MS-DFS error must propagate back out. */
1141 goto fail;
1144 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1146 * Except ACCESS_DENIED, everything else leads
1147 * to PATH_NOT_FOUND.
1149 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1152 goto fail;
1155 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
1156 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1157 goto fail;
1161 * Only look at bad last component values
1162 * once we know we have a valid directory. That
1163 * way we won't confuse error messages from
1164 * opening the directory path with error
1165 * messages from a bad last component.
1168 /* Relative filename can't be empty */
1169 if (fname_rel[0] == '\0') {
1170 status = NT_STATUS_OBJECT_NAME_INVALID;
1171 goto fail;
1174 /* Relative filename can't be ".." */
1175 if (ISDOTDOT(fname_rel)) {
1176 status = NT_STATUS_OBJECT_NAME_INVALID;
1177 goto fail;
1179 /* Relative name can only be dot if directory is empty. */
1180 if (ISDOT(fname_rel) && dirname[0] != '\0') {
1181 status = NT_STATUS_OBJECT_NAME_INVALID;
1182 goto fail;
1185 TALLOC_FREE(dirname);
1187 smb_fname_rel = synthetic_smb_fname(
1188 mem_ctx,
1189 fname_rel,
1190 streamname,
1191 NULL,
1192 twrp,
1193 posix ? SMB_FILENAME_POSIX_PATH : 0);
1194 if (smb_fname_rel == NULL) {
1195 status = NT_STATUS_NO_MEMORY;
1196 goto fail;
1199 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
1200 is_named_stream(smb_fname_rel)) {
1202 * Find the base_fsp first without the stream.
1204 saved_streamname = smb_fname_rel->stream_name;
1205 smb_fname_rel->stream_name = NULL;
1208 status = normalize_filename_case(
1209 conn, smb_fname_rel->base_name, ucf_flags);
1210 if (!NT_STATUS_IS_OK(status)) {
1211 DBG_ERR("normalize_filename_case %s failed: %s\n",
1212 smb_fname_rel->base_name,
1213 nt_errstr(status));
1214 goto fail;
1217 status = openat_pathref_fsp_case_insensitive(
1218 smb_dirname->fsp, smb_fname_rel, ucf_flags);
1220 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1221 VALID_STAT(smb_fname_rel->st) &&
1222 S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
1225 * If we're on an MSDFS share, see if this is
1226 * an MSDFS link.
1228 if (lp_host_msdfs() &&
1229 lp_msdfs_root(SNUM(conn)) &&
1230 is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
1232 status = NT_STATUS_PATH_NOT_COVERED;
1233 goto fail;
1236 #if defined(WITH_SMB1SERVER)
1238 * In SMB1 posix mode, if this is a symlink,
1239 * allow access to the name with a NULL smb_fname->fsp.
1241 if (ucf_flags & UCF_LCOMP_LNK_OK) {
1242 SMB_ASSERT(smb_fname_rel->fsp == NULL);
1243 SMB_ASSERT(streamname == NULL);
1245 smb_fname = full_path_from_dirfsp_atname(
1246 mem_ctx,
1247 smb_dirname->fsp,
1248 smb_fname_rel);
1249 if (smb_fname == NULL) {
1250 status = NT_STATUS_NO_MEMORY;
1251 goto fail;
1253 goto done;
1255 #endif
1258 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1259 !VALID_STAT(smb_fname_rel->st)) {
1261 char *normalized = NULL;
1264 * Creating a new file
1267 status = filename_convert_normalize_new(
1268 smb_fname_rel,
1269 conn,
1270 smb_fname_rel->base_name,
1271 &normalized);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 DBG_DEBUG("filename_convert_normalize_new failed: "
1274 "%s\n",
1275 nt_errstr(status));
1276 goto fail;
1278 if (normalized != NULL) {
1279 smb_fname_rel->base_name = normalized;
1282 smb_fname_rel->stream_name = saved_streamname;
1284 smb_fname = full_path_from_dirfsp_atname(
1285 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1286 if (smb_fname == NULL) {
1287 status = NT_STATUS_NO_MEMORY;
1288 goto fail;
1290 goto done;
1293 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
1294 /* A vetoed file, pretend it's not there */
1295 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1297 if (!NT_STATUS_IS_OK(status)) {
1298 goto fail;
1301 if (saved_streamname == NULL) {
1302 /* smb_fname must be allocated off mem_ctx. */
1303 smb_fname = cp_smb_filename(mem_ctx,
1304 smb_fname_rel->fsp->fsp_name);
1305 if (smb_fname == NULL) {
1306 goto fail;
1308 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1309 if (!NT_STATUS_IS_OK(status)) {
1310 goto fail;
1312 goto done;
1315 base_fsp = smb_fname_rel->fsp;
1316 smb_fname_fsp_unlink(smb_fname_rel);
1317 SET_STAT_INVALID(smb_fname_rel->st);
1319 smb_fname_rel->stream_name = saved_streamname;
1321 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1323 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1324 !conn->case_sensitive) {
1325 char *found = NULL;
1327 status = get_real_stream_name(
1328 smb_fname_rel,
1329 base_fsp,
1330 smb_fname_rel->stream_name,
1331 &found);
1333 if (NT_STATUS_IS_OK(status)) {
1334 smb_fname_rel->stream_name = found;
1335 found = NULL;
1336 status = open_stream_pathref_fsp(
1337 &base_fsp, smb_fname_rel);
1341 if (NT_STATUS_IS_OK(status)) {
1342 /* smb_fname must be allocated off mem_ctx. */
1343 smb_fname = cp_smb_filename(mem_ctx,
1344 smb_fname_rel->fsp->fsp_name);
1345 if (smb_fname == NULL) {
1346 goto fail;
1348 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 goto fail;
1352 goto done;
1355 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1357 * Creating a new stream
1359 * We should save the already-open base fsp for
1360 * create_file_unixpath() somehow.
1362 smb_fname = full_path_from_dirfsp_atname(
1363 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1364 if (smb_fname == NULL) {
1365 status = NT_STATUS_NO_MEMORY;
1366 goto fail;
1369 * When open_stream_pathref_fsp() returns
1370 * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1371 * has been set to NULL, so we must free base_fsp separately
1372 * to prevent fd-leaks when opening a stream that doesn't
1373 * exist.
1375 fd_close(base_fsp);
1376 file_free(NULL, base_fsp);
1377 base_fsp = NULL;
1378 goto done;
1381 if (!NT_STATUS_IS_OK(status)) {
1382 goto fail;
1385 done:
1386 *_dirfsp = smb_dirname->fsp;
1387 *_smb_fname = smb_fname;
1389 smb_fname_fsp_unlink(smb_fname_rel);
1390 TALLOC_FREE(smb_fname_rel);
1391 return NT_STATUS_OK;
1393 fail:
1395 * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1396 * has been set to NULL, so we must free base_fsp separately
1397 * to prevent fd-leaks when opening a stream that doesn't
1398 * exist.
1400 if (base_fsp != NULL) {
1401 fd_close(base_fsp);
1402 file_free(NULL, base_fsp);
1403 base_fsp = NULL;
1405 TALLOC_FREE(dirname);
1406 TALLOC_FREE(smb_dirname);
1407 TALLOC_FREE(smb_fname_rel);
1408 return status;
1411 NTSTATUS filename_convert_dirfsp(
1412 TALLOC_CTX *mem_ctx,
1413 connection_struct *conn,
1414 const char *name_in,
1415 uint32_t ucf_flags,
1416 NTTIME twrp,
1417 struct files_struct **_dirfsp,
1418 struct smb_filename **_smb_fname)
1420 char *substitute = NULL;
1421 size_t unparsed = 0;
1422 NTSTATUS status;
1423 char *target = NULL;
1424 size_t symlink_redirects = 0;
1426 next:
1427 if (symlink_redirects > 40) {
1428 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1431 status = filename_convert_dirfsp_nosymlink(
1432 mem_ctx,
1433 conn,
1434 name_in,
1435 ucf_flags,
1436 twrp,
1437 _dirfsp,
1438 _smb_fname,
1439 &substitute,
1440 &unparsed);
1442 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1443 return status;
1446 if (!lp_follow_symlinks(SNUM(conn))) {
1447 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1451 * Right now, SMB2 and SMB1 always traverse symlinks
1452 * within the share. SMB1+POSIX traverses non-terminal
1453 * symlinks within the share.
1455 * When we add SMB2+POSIX we need to return
1456 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1457 * symlink target data read below if SMB2+POSIX has
1458 * UCF_POSIX_PATHNAMES set to cause the client to
1459 * resolve all symlinks locally.
1462 status = safe_symlink_target_path(
1463 mem_ctx,
1464 conn->connectpath,
1465 name_in,
1466 substitute,
1467 unparsed,
1468 &target);
1469 if (!NT_STATUS_IS_OK(status)) {
1470 return status;
1472 name_in = target;
1474 symlink_redirects += 1;
1476 goto next;
1480 * Build the full path from a dirfsp and dirfsp relative name
1482 struct smb_filename *full_path_from_dirfsp_atname(
1483 TALLOC_CTX *mem_ctx,
1484 const struct files_struct *dirfsp,
1485 const struct smb_filename *atname)
1487 struct smb_filename *fname = NULL;
1488 char *path = NULL;
1490 if (dirfsp == dirfsp->conn->cwd_fsp ||
1491 ISDOT(dirfsp->fsp_name->base_name) ||
1492 atname->base_name[0] == '/')
1494 path = talloc_strdup(mem_ctx, atname->base_name);
1495 } else {
1496 path = talloc_asprintf(mem_ctx, "%s/%s",
1497 dirfsp->fsp_name->base_name,
1498 atname->base_name);
1500 if (path == NULL) {
1501 return NULL;
1504 fname = synthetic_smb_fname(mem_ctx,
1505 path,
1506 atname->stream_name,
1507 &atname->st,
1508 atname->twrp,
1509 atname->flags);
1510 TALLOC_FREE(path);
1511 if (fname == NULL) {
1512 return NULL;
1515 return fname;