libsmb: Add reparse_data_buffer_marshall()
[Samba.git] / source3 / smbd / filename.c
blob3c54ab1776297b41f09387c8f4375c9c4e49d9b2
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"
33 #include "libcli/smb/reparse.h"
35 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
37 uint32_t ucf_flags = 0;
39 if (req == NULL) {
40 return 0;
43 if (req->posix_pathnames) {
44 ucf_flags |= UCF_POSIX_PATHNAMES;
46 if (!req->sconn->using_smb2) {
47 ucf_flags |= UCF_LCOMP_LNK_OK;
50 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
51 ucf_flags |= UCF_DFS_PATHNAME;
53 if (req->flags2 & FLAGS2_REPARSE_PATH) {
54 ucf_flags |= UCF_GMT_PATHNAME;
57 return ucf_flags;
60 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
62 uint32_t ucf_flags = 0;
64 ucf_flags |= ucf_flags_from_smb_request(req);
66 switch (create_disposition) {
67 case FILE_OPEN:
68 case FILE_OVERWRITE:
69 break;
70 case FILE_SUPERSEDE:
71 case FILE_CREATE:
72 case FILE_OPEN_IF:
73 case FILE_OVERWRITE_IF:
74 ucf_flags |= UCF_PREP_CREATEFILE;
75 break;
78 return ucf_flags;
81 /****************************************************************************
82 Mangle the 2nd name and check if it is then equal to the first name.
83 ****************************************************************************/
85 static bool mangled_equal(const char *name1,
86 const char *name2,
87 const struct share_params *p)
89 char mname[13];
91 if (!name_to_8_3(name2, mname, False, p)) {
92 return False;
94 return strequal(name1, mname);
98 * Strip a valid @GMT-token from any incoming filename path,
99 * adding any NTTIME encoded in the pathname into the
100 * twrp field of the passed in smb_fname.
102 * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
103 * at the *start* of a pathname component.
105 * If twrp is passed in then smb_fname->twrp is set to that
106 * value, and the @GMT-token part of the filename is removed
107 * and does not change the stored smb_fname->twrp.
111 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
112 uint32_t ucf_flags,
113 NTTIME twrp)
115 bool found;
117 if (twrp != 0) {
118 smb_fname->twrp = twrp;
121 if (!(ucf_flags & UCF_GMT_PATHNAME)) {
122 return NT_STATUS_OK;
125 found = extract_snapshot_token(smb_fname->base_name, &twrp);
126 if (!found) {
127 return NT_STATUS_OK;
130 if (smb_fname->twrp == 0) {
131 smb_fname->twrp = twrp;
134 return NT_STATUS_OK;
137 static bool strnorm(char *s, int case_default)
139 if (case_default == CASE_UPPER)
140 return strupper_m(s);
141 else
142 return strlower_m(s);
146 * Utility function to normalize case on an incoming client filename
147 * if required on this connection struct.
148 * Performs an in-place case conversion guaranteed to stay the same size.
151 static NTSTATUS normalize_filename_case(connection_struct *conn,
152 char *filename,
153 uint32_t ucf_flags)
155 bool ok;
157 if (ucf_flags & UCF_POSIX_PATHNAMES) {
159 * POSIX never normalizes filename case.
161 return NT_STATUS_OK;
163 if (!conn->case_sensitive) {
164 return NT_STATUS_OK;
166 if (conn->case_preserve) {
167 return NT_STATUS_OK;
169 if (conn->short_case_preserve) {
170 return NT_STATUS_OK;
172 ok = strnorm(filename, lp_default_case(SNUM(conn)));
173 if (!ok) {
174 return NT_STATUS_INVALID_PARAMETER;
176 return NT_STATUS_OK;
179 /****************************************************************************
180 Check if two filenames are equal.
181 This needs to be careful about whether we are case sensitive.
182 ****************************************************************************/
184 static bool fname_equal(const char *name1, const char *name2,
185 bool case_sensitive)
187 /* Normal filename handling */
188 if (case_sensitive) {
189 return(strcmp(name1,name2) == 0);
192 return(strequal(name1,name2));
195 static bool sname_equal(const char *name1, const char *name2,
196 bool case_sensitive)
198 bool match;
199 const char *s1 = NULL;
200 const char *s2 = NULL;
201 size_t n1;
202 size_t n2;
203 const char *e1 = NULL;
204 const char *e2 = NULL;
205 char *c1 = NULL;
206 char *c2 = NULL;
208 match = fname_equal(name1, name2, case_sensitive);
209 if (match) {
210 return true;
213 if (name1[0] != ':') {
214 return false;
216 if (name2[0] != ':') {
217 return false;
219 s1 = &name1[1];
220 e1 = strchr(s1, ':');
221 if (e1 == NULL) {
222 n1 = strlen(s1);
223 } else {
224 n1 = PTR_DIFF(e1, s1);
226 s2 = &name2[1];
227 e2 = strchr(s2, ':');
228 if (e2 == NULL) {
229 n2 = strlen(s2);
230 } else {
231 n2 = PTR_DIFF(e2, s2);
234 /* Normal filename handling */
235 if (case_sensitive) {
236 return (strncmp(s1, s2, n1) == 0);
240 * We can't use strnequal() here
241 * as it takes the number of codepoints
242 * and not the number of bytes.
244 * So we make a copy before calling
245 * strequal().
247 * Note that we TALLOC_FREE() in reverse order
248 * in order to avoid memory fragmentation.
251 c1 = talloc_strndup(talloc_tos(), s1, n1);
252 c2 = talloc_strndup(talloc_tos(), s2, n2);
253 if (c1 == NULL || c2 == NULL) {
254 TALLOC_FREE(c2);
255 TALLOC_FREE(c1);
256 return (strncmp(s1, s2, n1) == 0);
259 match = strequal(c1, c2);
260 TALLOC_FREE(c2);
261 TALLOC_FREE(c1);
262 return match;
265 /****************************************************************************
266 Scan a directory to find a filename, matching without case sensitivity.
267 If the name looks like a mangled name then try via the mangling functions
268 ****************************************************************************/
270 NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp,
271 const char *name,
272 bool mangled,
273 TALLOC_CTX *mem_ctx,
274 char **found_name)
276 struct connection_struct *conn = dirfsp->conn;
277 struct smb_Dir *cur_dir = NULL;
278 const char *dname = NULL;
279 char *talloced = NULL;
280 char *unmangled_name = NULL;
281 NTSTATUS status;
283 /* If we have a case-sensitive filesystem, it doesn't do us any
284 * good to search for a name. If a case variation of the name was
285 * there, then the original stat(2) would have found it.
287 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
288 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
292 * The incoming name can be mangled, and if we de-mangle it
293 * here it will not compare correctly against the filename (name2)
294 * read from the directory and then mangled by the name_to_8_3()
295 * call. We need to mangle both names or neither.
296 * (JRA).
298 * Fix for bug found by Dina Fine. If in case sensitive mode then
299 * the mangle cache is no good (3 letter extension could be wrong
300 * case - so don't demangle in this case - leave as mangled and
301 * allow the mangling of the directory entry read (which is done
302 * case insensitively) to match instead. This will lead to more
303 * false positive matches but we fail completely without it. JRA.
306 if (mangled && !conn->case_sensitive) {
307 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
308 &unmangled_name,
309 conn->params);
310 if (!mangled) {
311 /* Name is now unmangled. */
312 name = unmangled_name;
316 /* open the directory */
317 status = OpenDir_from_pathref(talloc_tos(), dirfsp, NULL, 0, &cur_dir);
318 if (!NT_STATUS_IS_OK(status)) {
319 DBG_NOTICE("scan dir didn't open dir [%s]: %s\n",
320 fsp_str_dbg(dirfsp),
321 nt_errstr(status));
322 TALLOC_FREE(unmangled_name);
323 return status;
326 /* now scan for matching names */
327 while ((dname = ReadDirName(cur_dir, &talloced))) {
329 /* Is it dot or dot dot. */
330 if (ISDOT(dname) || ISDOTDOT(dname)) {
331 TALLOC_FREE(talloced);
332 continue;
336 * At this point dname is the unmangled name.
337 * name is either mangled or not, depending on the state
338 * of the "mangled" variable. JRA.
342 * Check mangled name against mangled name, or unmangled name
343 * against unmangled name.
346 if ((mangled && mangled_equal(name,dname,conn->params)) ||
347 fname_equal(name, dname, conn->case_sensitive)) {
348 /* we've found the file, change it's name and return */
349 *found_name = talloc_strdup(mem_ctx, dname);
350 TALLOC_FREE(unmangled_name);
351 TALLOC_FREE(cur_dir);
352 if (!*found_name) {
353 TALLOC_FREE(talloced);
354 return NT_STATUS_NO_MEMORY;
356 TALLOC_FREE(talloced);
357 return NT_STATUS_OK;
359 TALLOC_FREE(talloced);
362 TALLOC_FREE(unmangled_name);
363 TALLOC_FREE(cur_dir);
364 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
367 /****************************************************************************
368 Wrapper around the vfs get_real_filename and the full directory scan
369 fallback.
370 ****************************************************************************/
372 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
373 const char *name,
374 TALLOC_CTX *mem_ctx,
375 char **found_name)
377 struct connection_struct *conn = dirfsp->conn;
378 NTSTATUS status;
379 bool mangled;
381 mangled = mangle_is_mangled(name, conn->params);
383 if (mangled) {
384 status = get_real_filename_full_scan_at(
385 dirfsp, name, mangled, mem_ctx, found_name);
386 return status;
389 /* Try the vfs first to take advantage of case-insensitive stat. */
390 status = SMB_VFS_GET_REAL_FILENAME_AT(
391 dirfsp->conn, dirfsp, name, mem_ctx, found_name);
394 * If the case-insensitive stat was successful, or returned an error
395 * other than EOPNOTSUPP then there is no need to fall back on the
396 * full directory scan.
398 if (NT_STATUS_IS_OK(status) ||
399 !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
400 return status;
403 status = get_real_filename_full_scan_at(
404 dirfsp, name, mangled, mem_ctx, found_name);
405 return status;
409 * Create the memcache-key for GETREALFILENAME_CACHE: This supplements
410 * the stat cache for the last component to be looked up. Cache
411 * contents is the correctly capitalized translation of the parameter
412 * "name" as it exists on disk. This is indexed by inode of the dirfsp
413 * and name, and contrary to stat_cahce_lookup() it does not
414 * vfs_stat() the last component. This will be taken care of by an
415 * attempt to do a openat_pathref_fsp().
417 static bool get_real_filename_cache_key(
418 TALLOC_CTX *mem_ctx,
419 struct files_struct *dirfsp,
420 const char *name,
421 DATA_BLOB *_key)
423 struct file_id fid = vfs_file_id_from_sbuf(
424 dirfsp->conn, &dirfsp->fsp_name->st);
425 char *upper = NULL;
426 uint8_t *key = NULL;
427 size_t namelen, keylen;
429 upper = talloc_strdup_upper(mem_ctx, name);
430 if (upper == NULL) {
431 return false;
433 namelen = talloc_get_size(upper);
435 keylen = namelen + sizeof(fid);
436 if (keylen < sizeof(fid)) {
437 TALLOC_FREE(upper);
438 return false;
441 key = talloc_size(mem_ctx, keylen);
442 if (key == NULL) {
443 TALLOC_FREE(upper);
444 return false;
447 memcpy(key, &fid, sizeof(fid));
448 memcpy(key + sizeof(fid), upper, namelen);
449 TALLOC_FREE(upper);
451 *_key = (DATA_BLOB) { .data = key, .length = keylen, };
452 return true;
456 * Lightweight function to just get last component
457 * for rename / enumerate directory calls.
460 char *get_original_lcomp(TALLOC_CTX *ctx,
461 connection_struct *conn,
462 const char *filename_in,
463 uint32_t ucf_flags)
465 char *last_slash = NULL;
466 char *orig_lcomp;
467 NTSTATUS status;
469 last_slash = strrchr(filename_in, '/');
470 if (last_slash != NULL) {
471 orig_lcomp = talloc_strdup(ctx, last_slash+1);
472 } else {
473 orig_lcomp = talloc_strdup(ctx, filename_in);
475 if (orig_lcomp == NULL) {
476 return NULL;
478 status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
479 if (!NT_STATUS_IS_OK(status)) {
480 TALLOC_FREE(orig_lcomp);
481 return NULL;
483 return orig_lcomp;
487 * Deal with the SMB1 semantics of sending a pathname with a
488 * wildcard as the terminal component for a SMB1search or
489 * trans2 findfirst.
492 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
493 connection_struct *conn,
494 char *name_in,
495 uint32_t ucf_flags,
496 struct files_struct **_dirfsp,
497 struct smb_filename **_smb_fname_out,
498 char **_mask_out)
500 NTSTATUS status;
501 char *p = NULL;
502 char *mask = NULL;
503 struct smb_filename *smb_fname = NULL;
504 NTTIME twrp = 0;
506 *_smb_fname_out = NULL;
507 *_dirfsp = NULL;
508 *_mask_out = NULL;
510 DBG_DEBUG("name_in: %s\n", name_in);
512 if (ucf_flags & UCF_GMT_PATHNAME) {
513 extract_snapshot_token(name_in, &twrp);
514 ucf_flags &= ~UCF_GMT_PATHNAME;
517 /* Get the original lcomp. */
518 mask = get_original_lcomp(ctx,
519 conn,
520 name_in,
521 ucf_flags);
522 if (mask == NULL) {
523 return NT_STATUS_NO_MEMORY;
526 if (mask[0] == '\0') {
527 /* Windows and OS/2 systems treat search on the root as * */
528 TALLOC_FREE(mask);
529 mask = talloc_strdup(ctx, "*");
530 if (mask == NULL) {
531 return NT_STATUS_NO_MEMORY;
535 DBG_DEBUG("mask = %s\n", mask);
538 * Remove the terminal component so
539 * filename_convert_dirfsp never sees the mask.
541 p = strrchr_m(name_in,'/');
542 if (p == NULL) {
543 /* filename_convert_dirfsp handles a '\0' name. */
544 name_in[0] = '\0';
545 } else {
546 *p = '\0';
549 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
550 name_in);
552 /* Convert the parent directory path. */
553 status = filename_convert_dirfsp(ctx,
554 conn,
555 name_in,
556 ucf_flags,
557 twrp,
558 _dirfsp,
559 &smb_fname);
561 if (!NT_STATUS_IS_OK(status)) {
562 DBG_DEBUG("filename_convert error for %s: %s\n",
563 name_in,
564 nt_errstr(status));
567 *_smb_fname_out = talloc_move(ctx, &smb_fname);
568 *_mask_out = talloc_move(ctx, &mask);
570 return status;
574 * Get the correct capitalized stream name hanging off
575 * base_fsp. Equivalent of get_real_filename(), but for streams.
577 static NTSTATUS get_real_stream_name(
578 TALLOC_CTX *mem_ctx,
579 struct files_struct *base_fsp,
580 const char *stream_name,
581 char **_found)
583 unsigned int i, num_streams = 0;
584 struct stream_struct *streams = NULL;
585 NTSTATUS status;
587 status = vfs_fstreaminfo(
588 base_fsp, talloc_tos(), &num_streams, &streams);
589 if (!NT_STATUS_IS_OK(status)) {
590 return status;
593 for (i=0; i<num_streams; i++) {
594 bool equal = sname_equal(stream_name, streams[i].name, false);
596 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
597 stream_name,
598 streams[i].name,
599 equal ? "" : "not ");
601 if (equal) {
602 *_found = talloc_move(mem_ctx, &streams[i].name);
603 TALLOC_FREE(streams);
604 return NT_STATUS_OK;
608 TALLOC_FREE(streams);
609 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
612 static bool filename_split_lcomp(
613 TALLOC_CTX *mem_ctx,
614 const char *name_in,
615 bool posix,
616 char **_dirname,
617 const char **_fname_rel,
618 const char **_streamname)
620 const char *lcomp = NULL;
621 const char *fname_rel = NULL;
622 const char *streamname = NULL;
623 char *dirname = NULL;
625 if (name_in[0] == '\0') {
626 fname_rel = ".";
627 dirname = talloc_strdup(mem_ctx, "");
628 if (dirname == NULL) {
629 return false;
631 goto done;
634 lcomp = strrchr_m(name_in, '/');
635 if (lcomp != NULL) {
636 fname_rel = lcomp+1;
637 dirname = talloc_strndup(mem_ctx, name_in, lcomp - name_in);
638 if (dirname == NULL) {
639 return false;
641 goto find_stream;
645 * No slash, dir is empty
647 dirname = talloc_strdup(mem_ctx, "");
648 if (dirname == NULL) {
649 return false;
652 if (!posix && (name_in[0] == ':')) {
654 * Special case for stream on root directory
656 fname_rel = ".";
657 streamname = name_in;
658 goto done;
661 fname_rel = name_in;
663 find_stream:
664 if (!posix) {
665 streamname = strchr_m(fname_rel, ':');
667 if (streamname != NULL) {
668 fname_rel = talloc_strndup(
669 mem_ctx,
670 fname_rel,
671 streamname - fname_rel);
672 if (fname_rel == NULL) {
673 TALLOC_FREE(dirname);
674 return false;
679 done:
680 *_dirname = dirname;
681 *_fname_rel = fname_rel;
682 *_streamname = streamname;
683 return true;
687 * Create the correct capitalization of a file name to be created.
689 static NTSTATUS filename_convert_normalize_new(
690 TALLOC_CTX *mem_ctx,
691 struct connection_struct *conn,
692 char *name_in,
693 char **_normalized)
695 char *name = name_in;
697 *_normalized = NULL;
699 if (!conn->case_preserve ||
700 (mangle_is_8_3(name, false,
701 conn->params) &&
702 !conn->short_case_preserve)) {
704 char *normalized = talloc_strdup(mem_ctx, name);
705 if (normalized == NULL) {
706 return NT_STATUS_NO_MEMORY;
709 strnorm(normalized, lp_default_case(SNUM(conn)));
710 name = normalized;
713 if (mangle_is_mangled(name, conn->params)) {
714 bool found;
715 char *unmangled = NULL;
717 found = mangle_lookup_name_from_8_3(
718 mem_ctx, name, &unmangled, conn->params);
719 if (found) {
720 name = unmangled;
724 if (name != name_in) {
725 *_normalized = name;
728 return NT_STATUS_OK;
732 * Open smb_fname_rel->fsp as a pathref fsp with a case insensitive
733 * fallback using GETREALFILENAME_CACHE and get_real_filename_at() if
734 * the first attempt based on the filename sent by the client gives
735 * ENOENT.
737 static NTSTATUS openat_pathref_fsp_case_insensitive(
738 struct files_struct *dirfsp,
739 struct smb_filename *smb_fname_rel,
740 uint32_t ucf_flags)
742 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
743 DATA_BLOB cache_key = { .data = NULL, };
744 char *found_name = NULL;
745 NTSTATUS status;
746 bool ok;
748 SET_STAT_INVALID(smb_fname_rel->st);
750 /* Check veto files - only looks at last component. */
751 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
752 DBG_DEBUG("veto files rejecting last component %s\n",
753 smb_fname_str_dbg(smb_fname_rel));
754 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
757 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
759 if (NT_STATUS_IS_OK(status)) {
760 return NT_STATUS_OK;
763 if (VALID_STAT(smb_fname_rel->st)) {
765 * We got an error although the object existed. Might
766 * be a symlink we don't want.
768 return status;
771 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
773 * Only retry on ENOENT
775 return status;
778 if (posix || dirfsp->conn->case_sensitive) {
780 * Only return case insensitive if required
782 return status;
785 if (lp_stat_cache()) {
786 char *base_name = smb_fname_rel->base_name;
787 char *original_relname = NULL;
788 DATA_BLOB value = { .data = NULL };
790 ok = get_real_filename_cache_key(
791 talloc_tos(), dirfsp, base_name, &cache_key);
792 if (!ok) {
794 * probably ENOMEM, just bail
796 return status;
799 DO_PROFILE_INC(statcache_lookups);
801 ok = memcache_lookup(
802 NULL, GETREALFILENAME_CACHE, cache_key, &value);
803 if (!ok) {
804 DO_PROFILE_INC(statcache_misses);
805 goto lookup;
807 DO_PROFILE_INC(statcache_hits);
810 * For the "new filename" case we need to preserve the
811 * capitalization the client sent us, see
812 * https://bugzilla.samba.org/show_bug.cgi?id=15481
814 original_relname = smb_fname_rel->base_name;
816 smb_fname_rel->base_name = talloc_memdup(
817 smb_fname_rel, value.data, value.length);
818 if (smb_fname_rel->base_name == NULL) {
819 TALLOC_FREE(cache_key.data);
820 return NT_STATUS_NO_MEMORY;
823 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
824 DBG_DEBUG("veto files rejecting last component %s\n",
825 smb_fname_str_dbg(smb_fname_rel));
826 TALLOC_FREE(cache_key.data);
827 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
830 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
831 if (NT_STATUS_IS_OK(status)) {
832 TALLOC_FREE(cache_key.data);
833 TALLOC_FREE(original_relname);
834 return NT_STATUS_OK;
837 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
838 TALLOC_FREE(smb_fname_rel->base_name);
839 smb_fname_rel->base_name = original_relname;
842 lookup:
843 status = get_real_filename_at(
844 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
845 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
846 (ucf_flags & UCF_PREP_CREATEFILE)) {
848 * dropbox
850 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
853 if (NT_STATUS_IS_OK(status)) {
854 TALLOC_FREE(smb_fname_rel->base_name);
855 smb_fname_rel->base_name = found_name;
857 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
858 DBG_DEBUG("veto files rejecting last component %s\n",
859 smb_fname_str_dbg(smb_fname_rel));
860 return NT_STATUS_NETWORK_OPEN_RESTRICTION;
863 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
866 if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
867 DATA_BLOB value = {
868 .data = (uint8_t *)smb_fname_rel->base_name,
869 .length = strlen(smb_fname_rel->base_name) + 1,
872 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
875 TALLOC_FREE(cache_key.data);
877 return status;
880 static const char *previous_slash(const char *name_in, const char *slash)
882 const char *prev = name_in;
884 while (true) {
885 const char *next = strchr_m(prev, '/');
887 SMB_ASSERT(next != NULL); /* we have at least one slash */
889 if (next == slash) {
890 break;
893 prev = next+1;
896 if (prev == name_in) {
897 /* no previous slash */
898 return NULL;
901 return prev;
904 static char *symlink_target_path(
905 TALLOC_CTX *mem_ctx,
906 const char *name_in,
907 const char *substitute,
908 size_t unparsed)
910 size_t name_in_len = strlen(name_in);
911 const char *p_unparsed = NULL;
912 const char *parent = NULL;
913 char *ret;
915 SMB_ASSERT(unparsed <= name_in_len);
917 p_unparsed = name_in + (name_in_len - unparsed);
919 if (substitute[0] == '/') {
920 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
921 return ret;
924 if (unparsed == 0) {
925 parent = strrchr_m(name_in, '/');
926 } else {
927 parent = previous_slash(name_in, p_unparsed);
930 if (parent == NULL) {
931 /* no previous slash */
932 parent = name_in;
935 ret = talloc_asprintf(
936 mem_ctx,
937 "%.*s%s%s",
938 (int)(parent - name_in),
939 name_in,
940 substitute,
941 p_unparsed);
942 return ret;
945 static NTSTATUS safe_symlink_target_path(
946 TALLOC_CTX *mem_ctx,
947 const char *connectpath,
948 const char *name_in,
949 const char *substitute,
950 size_t unparsed,
951 char **_name_out)
953 char *target = NULL;
954 char *abs_target = NULL;
955 char *abs_target_canon = NULL;
956 const char *relative = NULL;
957 char *name_out = NULL;
958 NTSTATUS status = NT_STATUS_NO_MEMORY;
959 bool in_share;
961 target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
962 if (target == NULL) {
963 goto fail;
966 DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
967 name_in,
968 substitute,
969 unparsed,
970 target);
972 if (target[0] == '/') {
973 abs_target = target;
974 } else {
975 abs_target = talloc_asprintf(
976 target, "%s/%s", connectpath, target);
977 if (abs_target == NULL) {
978 goto fail;
982 abs_target_canon = canonicalize_absolute_path(target, abs_target);
983 if (abs_target_canon == NULL) {
984 goto fail;
987 DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
989 in_share = subdir_of(
990 connectpath, strlen(connectpath), abs_target_canon, &relative);
991 if (!in_share) {
992 DBG_DEBUG("wide link to %s\n", abs_target_canon);
993 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
994 goto fail;
997 name_out = talloc_strdup(mem_ctx, relative);
998 if (name_out == NULL) {
999 goto fail;
1002 status = NT_STATUS_OK;
1003 *_name_out = name_out;
1004 fail:
1005 TALLOC_FREE(target);
1006 return status;
1010 * Split up name_in as sent by the client into a directory pathref fsp
1011 * and a relative smb_filename.
1013 static NTSTATUS filename_convert_dirfsp_nosymlink(
1014 TALLOC_CTX *mem_ctx,
1015 connection_struct *conn,
1016 const char *name_in,
1017 uint32_t ucf_flags,
1018 NTTIME twrp,
1019 struct files_struct **_dirfsp,
1020 struct smb_filename **_smb_fname,
1021 char **_substitute,
1022 size_t *_unparsed)
1024 struct smb_filename *smb_dirname = NULL;
1025 struct smb_filename *smb_fname_rel = NULL;
1026 struct smb_filename *smb_fname = NULL;
1027 const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
1028 char *dirname = NULL;
1029 const char *fname_rel = NULL;
1030 const char *streamname = NULL;
1031 char *saved_streamname = NULL;
1032 struct files_struct *base_fsp = NULL;
1033 bool ok;
1034 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1036 SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
1038 if (is_fake_file_path(name_in)) {
1039 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
1040 if (smb_fname == NULL) {
1041 return NT_STATUS_NO_MEMORY;
1043 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1044 smb_fname->st.st_ex_btime =
1045 (struct timespec){0, SAMBA_UTIME_OMIT};
1046 smb_fname->st.st_ex_atime =
1047 (struct timespec){0, SAMBA_UTIME_OMIT};
1048 smb_fname->st.st_ex_mtime =
1049 (struct timespec){0, SAMBA_UTIME_OMIT};
1050 smb_fname->st.st_ex_ctime =
1051 (struct timespec){0, SAMBA_UTIME_OMIT};
1053 *_dirfsp = conn->cwd_fsp;
1054 *_smb_fname = smb_fname;
1055 return NT_STATUS_OK;
1059 * Catch an invalid path of "." before we
1060 * call filename_split_lcomp(). We need to
1061 * do this as filename_split_lcomp() will
1062 * use "." for the missing relative component
1063 * when an empty name_in path is sent by
1064 * the client.
1066 if (ISDOT(name_in)) {
1067 status = NT_STATUS_OBJECT_NAME_INVALID;
1068 goto fail;
1071 ok = filename_split_lcomp(
1072 talloc_tos(),
1073 name_in,
1074 posix,
1075 &dirname,
1076 &fname_rel,
1077 &streamname);
1078 if (!ok) {
1079 status = NT_STATUS_NO_MEMORY;
1080 goto fail;
1083 if ((streamname != NULL) &&
1084 ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
1085 status = NT_STATUS_OBJECT_NAME_INVALID;
1086 goto fail;
1089 if (!posix) {
1090 bool name_has_wild = ms_has_wild(dirname);
1091 name_has_wild |= ms_has_wild(fname_rel);
1092 if (name_has_wild) {
1093 status = NT_STATUS_OBJECT_NAME_INVALID;
1094 goto fail;
1098 if (dirname[0] == '\0') {
1099 status = synthetic_pathref(
1100 mem_ctx,
1101 conn->cwd_fsp,
1102 ".",
1103 NULL,
1104 NULL,
1106 posix ? SMB_FILENAME_POSIX_PATH : 0,
1107 &smb_dirname);
1108 } else {
1109 struct open_symlink_err *symlink_err = NULL;
1111 status = normalize_filename_case(conn, dirname, ucf_flags);
1112 if (!NT_STATUS_IS_OK(status)) {
1113 DBG_ERR("normalize_filename_case %s failed: %s\n",
1114 dirname,
1115 nt_errstr(status));
1116 goto fail;
1119 status = openat_pathref_fsp_nosymlink(mem_ctx,
1120 conn,
1121 conn->cwd_fsp,
1122 dirname,
1124 posix,
1125 &smb_dirname,
1126 &symlink_err);
1128 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1129 size_t name_in_len, dirname_len;
1131 if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1132 strnequal(symlink_err->reparse->substitute_name,
1133 "msdfs:",
1134 6)) {
1135 status = NT_STATUS_PATH_NOT_COVERED;
1136 goto fail;
1139 name_in_len = strlen(name_in);
1140 dirname_len = strlen(dirname);
1142 SMB_ASSERT(name_in_len >= dirname_len);
1144 *_substitute = talloc_move(
1145 mem_ctx,
1146 &symlink_err->reparse->substitute_name);
1147 *_unparsed = symlink_err->unparsed +
1148 (name_in_len - dirname_len);
1150 goto fail;
1154 if (!NT_STATUS_IS_OK(status)) {
1155 DBG_DEBUG("opening directory %s failed: %s\n",
1156 dirname,
1157 nt_errstr(status));
1158 TALLOC_FREE(dirname);
1160 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1162 * Except ACCESS_DENIED, everything else leads
1163 * to PATH_NOT_FOUND.
1165 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1168 goto fail;
1171 if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
1172 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1173 goto fail;
1175 smb_dirname->fsp->fsp_flags.is_directory = true;
1178 * Only look at bad last component values
1179 * once we know we have a valid directory. That
1180 * way we won't confuse error messages from
1181 * opening the directory path with error
1182 * messages from a bad last component.
1185 /* Relative filename can't be empty */
1186 if (fname_rel[0] == '\0') {
1187 status = NT_STATUS_OBJECT_NAME_INVALID;
1188 goto fail;
1191 /* Relative filename can't be ".." */
1192 if (ISDOTDOT(fname_rel)) {
1193 status = NT_STATUS_OBJECT_NAME_INVALID;
1194 goto fail;
1196 /* Relative name can only be dot if directory is empty. */
1197 if (ISDOT(fname_rel) && dirname[0] != '\0') {
1198 status = NT_STATUS_OBJECT_NAME_INVALID;
1199 goto fail;
1202 TALLOC_FREE(dirname);
1204 smb_fname_rel = synthetic_smb_fname(
1205 mem_ctx,
1206 fname_rel,
1207 streamname,
1208 NULL,
1209 twrp,
1210 posix ? SMB_FILENAME_POSIX_PATH : 0);
1211 if (smb_fname_rel == NULL) {
1212 status = NT_STATUS_NO_MEMORY;
1213 goto fail;
1216 if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
1217 is_named_stream(smb_fname_rel)) {
1219 * Find the base_fsp first without the stream.
1221 saved_streamname = smb_fname_rel->stream_name;
1222 smb_fname_rel->stream_name = NULL;
1225 status = normalize_filename_case(
1226 conn, smb_fname_rel->base_name, ucf_flags);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 DBG_ERR("normalize_filename_case %s failed: %s\n",
1229 smb_fname_rel->base_name,
1230 nt_errstr(status));
1231 goto fail;
1234 status = openat_pathref_fsp_case_insensitive(
1235 smb_dirname->fsp, smb_fname_rel, ucf_flags);
1237 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1238 VALID_STAT(smb_fname_rel->st) &&
1239 S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
1242 * If we're on an MSDFS share, see if this is
1243 * an MSDFS link.
1245 if (lp_host_msdfs() &&
1246 lp_msdfs_root(SNUM(conn)) &&
1247 is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
1249 status = NT_STATUS_PATH_NOT_COVERED;
1250 goto fail;
1253 #if defined(WITH_SMB1SERVER)
1255 * In SMB1 posix mode, if this is a symlink,
1256 * allow access to the name with a NULL smb_fname->fsp.
1258 if (ucf_flags & UCF_LCOMP_LNK_OK) {
1259 SMB_ASSERT(smb_fname_rel->fsp == NULL);
1260 SMB_ASSERT(streamname == NULL);
1262 smb_fname = full_path_from_dirfsp_atname(
1263 mem_ctx,
1264 smb_dirname->fsp,
1265 smb_fname_rel);
1266 if (smb_fname == NULL) {
1267 status = NT_STATUS_NO_MEMORY;
1268 goto fail;
1270 goto done;
1272 #endif
1275 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1276 !VALID_STAT(smb_fname_rel->st)) {
1278 char *normalized = NULL;
1281 * Creating a new file
1284 status = filename_convert_normalize_new(
1285 smb_fname_rel,
1286 conn,
1287 smb_fname_rel->base_name,
1288 &normalized);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 DBG_DEBUG("filename_convert_normalize_new failed: "
1291 "%s\n",
1292 nt_errstr(status));
1293 goto fail;
1295 if (normalized != NULL) {
1296 smb_fname_rel->base_name = normalized;
1299 smb_fname_rel->stream_name = saved_streamname;
1301 smb_fname = full_path_from_dirfsp_atname(
1302 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1303 if (smb_fname == NULL) {
1304 status = NT_STATUS_NO_MEMORY;
1305 goto fail;
1307 goto done;
1310 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
1311 /* A vetoed file, pretend it's not there */
1312 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1314 if (!NT_STATUS_IS_OK(status)) {
1315 goto fail;
1318 if (saved_streamname == NULL) {
1319 /* smb_fname must be allocated off mem_ctx. */
1320 smb_fname = cp_smb_filename(mem_ctx,
1321 smb_fname_rel->fsp->fsp_name);
1322 if (smb_fname == NULL) {
1323 goto fail;
1325 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1326 if (!NT_STATUS_IS_OK(status)) {
1327 goto fail;
1329 goto done;
1332 base_fsp = smb_fname_rel->fsp;
1333 smb_fname_fsp_unlink(smb_fname_rel);
1334 SET_STAT_INVALID(smb_fname_rel->st);
1336 smb_fname_rel->stream_name = saved_streamname;
1338 status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1340 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1341 !conn->case_sensitive) {
1342 char *found = NULL;
1344 status = get_real_stream_name(
1345 smb_fname_rel,
1346 base_fsp,
1347 smb_fname_rel->stream_name,
1348 &found);
1350 if (NT_STATUS_IS_OK(status)) {
1351 smb_fname_rel->stream_name = found;
1352 found = NULL;
1353 status = open_stream_pathref_fsp(
1354 &base_fsp, smb_fname_rel);
1358 if (NT_STATUS_IS_OK(status)) {
1359 /* smb_fname must be allocated off mem_ctx. */
1360 smb_fname = cp_smb_filename(mem_ctx,
1361 smb_fname_rel->fsp->fsp_name);
1362 if (smb_fname == NULL) {
1363 goto fail;
1365 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1366 if (!NT_STATUS_IS_OK(status)) {
1367 goto fail;
1369 goto done;
1372 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1374 * Creating a new stream
1376 * We should save the already-open base fsp for
1377 * create_file_unixpath() somehow.
1379 smb_fname = full_path_from_dirfsp_atname(
1380 mem_ctx, smb_dirname->fsp, smb_fname_rel);
1381 if (smb_fname == NULL) {
1382 status = NT_STATUS_NO_MEMORY;
1383 goto fail;
1386 * When open_stream_pathref_fsp() returns
1387 * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1388 * has been set to NULL, so we must free base_fsp separately
1389 * to prevent fd-leaks when opening a stream that doesn't
1390 * exist.
1392 fd_close(base_fsp);
1393 file_free(NULL, base_fsp);
1394 base_fsp = NULL;
1395 goto done;
1398 if (!NT_STATUS_IS_OK(status)) {
1399 goto fail;
1402 done:
1403 *_dirfsp = smb_dirname->fsp;
1404 *_smb_fname = smb_fname;
1406 smb_fname_fsp_unlink(smb_fname_rel);
1407 TALLOC_FREE(smb_fname_rel);
1408 return NT_STATUS_OK;
1410 fail:
1412 * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1413 * has been set to NULL, so we must free base_fsp separately
1414 * to prevent fd-leaks when opening a stream that doesn't
1415 * exist.
1417 if (base_fsp != NULL) {
1418 fd_close(base_fsp);
1419 file_free(NULL, base_fsp);
1420 base_fsp = NULL;
1422 TALLOC_FREE(dirname);
1423 TALLOC_FREE(smb_dirname);
1424 TALLOC_FREE(smb_fname_rel);
1425 return status;
1428 NTSTATUS filename_convert_dirfsp(
1429 TALLOC_CTX *mem_ctx,
1430 connection_struct *conn,
1431 const char *name_in,
1432 uint32_t ucf_flags,
1433 NTTIME twrp,
1434 struct files_struct **_dirfsp,
1435 struct smb_filename **_smb_fname)
1437 char *substitute = NULL;
1438 size_t unparsed = 0;
1439 NTSTATUS status;
1440 char *target = NULL;
1441 size_t symlink_redirects = 0;
1443 next:
1444 if (symlink_redirects > 40) {
1445 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1448 status = filename_convert_dirfsp_nosymlink(
1449 mem_ctx,
1450 conn,
1451 name_in,
1452 ucf_flags,
1453 twrp,
1454 _dirfsp,
1455 _smb_fname,
1456 &substitute,
1457 &unparsed);
1459 if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1460 return status;
1463 if (!lp_follow_symlinks(SNUM(conn))) {
1464 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1468 * Right now, SMB2 and SMB1 always traverse symlinks
1469 * within the share. SMB1+POSIX traverses non-terminal
1470 * symlinks within the share.
1472 * When we add SMB2+POSIX we need to return
1473 * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1474 * symlink target data read below if SMB2+POSIX has
1475 * UCF_POSIX_PATHNAMES set to cause the client to
1476 * resolve all symlinks locally.
1479 status = safe_symlink_target_path(
1480 mem_ctx,
1481 conn->connectpath,
1482 name_in,
1483 substitute,
1484 unparsed,
1485 &target);
1486 if (!NT_STATUS_IS_OK(status)) {
1487 return status;
1489 name_in = target;
1491 symlink_redirects += 1;
1493 goto next;
1496 char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
1497 const struct files_struct *dirfsp,
1498 const char *at_base_name)
1500 char *path = NULL;
1502 if (dirfsp == dirfsp->conn->cwd_fsp ||
1503 ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
1504 path = talloc_strdup(mem_ctx, at_base_name);
1505 } else {
1506 path = talloc_asprintf(mem_ctx,
1507 "%s/%s",
1508 dirfsp->fsp_name->base_name,
1509 at_base_name);
1512 return path;
1516 * Build the full path from a dirfsp and dirfsp relative name
1518 struct smb_filename *
1519 full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
1520 const struct files_struct *dirfsp,
1521 const struct smb_filename *atname)
1523 struct smb_filename *fname = NULL;
1524 char *path = NULL;
1526 path = full_path_from_dirfsp_at_basename(mem_ctx,
1527 dirfsp,
1528 atname->base_name);
1529 if (path == NULL) {
1530 return NULL;
1533 fname = synthetic_smb_fname(mem_ctx,
1534 path,
1535 atname->stream_name,
1536 &atname->st,
1537 atname->twrp,
1538 atname->flags);
1539 TALLOC_FREE(path);
1540 if (fname == NULL) {
1541 return NULL;
1544 return fname;