s3:smbd: Fix code spelling
[samba.git] / source3 / smbd / filename.c
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
8
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.
13
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.
18
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/>.
21 */
22
23 /*
24  * New hash table stat cache code added by Ying Chen.
25  */
26
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_symlink.h"
34
35 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
36 {
37         uint32_t ucf_flags = 0;
38
39         if (req == NULL) {
40                 return 0;
41         }
42
43         if (req->posix_pathnames) {
44                 ucf_flags |= UCF_POSIX_PATHNAMES;
45
46                 if (!req->sconn->using_smb2) {
47                         ucf_flags |= UCF_LCOMP_LNK_OK;
48                 }
49         }
50         if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
51                 ucf_flags |= UCF_DFS_PATHNAME;
52         }
53         if (req->flags2 & FLAGS2_REPARSE_PATH) {
54                 ucf_flags |= UCF_GMT_PATHNAME;
55         }
56
57         return ucf_flags;
58 }
59
60 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
61 {
62         uint32_t ucf_flags = 0;
63
64         ucf_flags |= ucf_flags_from_smb_request(req);
65
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;
76         }
77
78         return ucf_flags;
79 }
80
81 /****************************************************************************
82  Mangle the 2nd name and check if it is then equal to the first name.
83 ****************************************************************************/
84
85 static bool mangled_equal(const char *name1,
86                         const char *name2,
87                         const struct share_params *p)
88 {
89         char mname[13];
90
91         if (!name_to_8_3(name2, mname, False, p)) {
92                 return False;
93         }
94         return strequal(name1, mname);
95 }
96
97 /*
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.
101  *
102  * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
103  * at the *start* of a pathname component.
104  *
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.
108  *
109  */
110
111 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
112                                     uint32_t ucf_flags,
113                                     NTTIME twrp)
114 {
115         bool found;
116
117         if (twrp != 0) {
118                 smb_fname->twrp = twrp;
119         }
120
121         if (!(ucf_flags & UCF_GMT_PATHNAME)) {
122                 return NT_STATUS_OK;
123         }
124
125         found = extract_snapshot_token(smb_fname->base_name, &twrp);
126         if (!found) {
127                 return NT_STATUS_OK;
128         }
129
130         if (smb_fname->twrp == 0) {
131                 smb_fname->twrp = twrp;
132         }
133
134         return NT_STATUS_OK;
135 }
136
137 static bool strnorm(char *s, int case_default)
138 {
139         if (case_default == CASE_UPPER)
140                 return strupper_m(s);
141         else
142                 return strlower_m(s);
143 }
144
145 /*
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.
149  */
150
151 static NTSTATUS normalize_filename_case(connection_struct *conn,
152                                         char *filename,
153                                         uint32_t ucf_flags)
154 {
155         bool ok;
156
157         if (ucf_flags & UCF_POSIX_PATHNAMES) {
158                 /*
159                  * POSIX never normalizes filename case.
160                  */
161                 return NT_STATUS_OK;
162         }
163         if (!conn->case_sensitive) {
164                 return NT_STATUS_OK;
165         }
166         if (conn->case_preserve) {
167                 return NT_STATUS_OK;
168         }
169         if (conn->short_case_preserve) {
170                 return NT_STATUS_OK;
171         }
172         ok = strnorm(filename, lp_default_case(SNUM(conn)));
173         if (!ok) {
174                 return NT_STATUS_INVALID_PARAMETER;
175         }
176         return NT_STATUS_OK;
177 }
178
179 /****************************************************************************
180  Check if two filenames are equal.
181  This needs to be careful about whether we are case sensitive.
182 ****************************************************************************/
183
184 static bool fname_equal(const char *name1, const char *name2,
185                 bool case_sensitive)
186 {
187         /* Normal filename handling */
188         if (case_sensitive) {
189                 return(strcmp(name1,name2) == 0);
190         }
191
192         return(strequal(name1,name2));
193 }
194
195 static bool sname_equal(const char *name1, const char *name2,
196                 bool case_sensitive)
197 {
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;
207
208         match = fname_equal(name1, name2, case_sensitive);
209         if (match) {
210                 return true;
211         }
212
213         if (name1[0] != ':') {
214                 return false;
215         }
216         if (name2[0] != ':') {
217                 return false;
218         }
219         s1 = &name1[1];
220         e1 = strchr(s1, ':');
221         if (e1 == NULL) {
222                 n1 = strlen(s1);
223         } else {
224                 n1 = PTR_DIFF(e1, s1);
225         }
226         s2 = &name2[1];
227         e2 = strchr(s2, ':');
228         if (e2 == NULL) {
229                 n2 = strlen(s2);
230         } else {
231                 n2 = PTR_DIFF(e2, s2);
232         }
233
234         /* Normal filename handling */
235         if (case_sensitive) {
236                 return (strncmp(s1, s2, n1) == 0);
237         }
238
239         /*
240          * We can't use strnequal() here
241          * as it takes the number of codepoints
242          * and not the number of bytes.
243          *
244          * So we make a copy before calling
245          * strequal().
246          *
247          * Note that we TALLOC_FREE() in reverse order
248          * in order to avoid memory fragmentation.
249          */
250
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);
257         }
258
259         match = strequal(c1, c2);
260         TALLOC_FREE(c2);
261         TALLOC_FREE(c1);
262         return match;
263 }
264
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 ****************************************************************************/
269
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)
275 {
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;
282
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.
286          */
287         if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
288                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
289         }
290
291         /*
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).
297          *
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.
304          */
305
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;
313                 }
314         }
315
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;
324         }
325
326         /* now scan for matching names */
327         while ((dname = ReadDirName(cur_dir, &talloced))) {
328
329                 /* Is it dot or dot dot. */
330                 if (ISDOT(dname) || ISDOTDOT(dname)) {
331                         TALLOC_FREE(talloced);
332                         continue;
333                 }
334
335                 /*
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.
339                  */
340
341                 /*
342                  * Check mangled name against mangled name, or unmangled name
343                  * against unmangled name.
344                  */
345
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;
355                         }
356                         TALLOC_FREE(talloced);
357                         return NT_STATUS_OK;
358                 }
359                 TALLOC_FREE(talloced);
360         }
361
362         TALLOC_FREE(unmangled_name);
363         TALLOC_FREE(cur_dir);
364         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
365 }
366
367 /****************************************************************************
368  Wrapper around the vfs get_real_filename and the full directory scan
369  fallback.
370 ****************************************************************************/
371
372 NTSTATUS get_real_filename_at(struct files_struct *dirfsp,
373                               const char *name,
374                               TALLOC_CTX *mem_ctx,
375                               char **found_name)
376 {
377         struct connection_struct *conn = dirfsp->conn;
378         NTSTATUS status;
379         bool mangled;
380
381         mangled = mangle_is_mangled(name, conn->params);
382
383         if (mangled) {
384                 status = get_real_filename_full_scan_at(
385                         dirfsp, name, mangled, mem_ctx, found_name);
386                 return status;
387         }
388
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);
392
393         /*
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.
397          */
398         if (NT_STATUS_IS_OK(status) ||
399             !NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
400                 return status;
401         }
402
403         status = get_real_filename_full_scan_at(
404                 dirfsp, name, mangled, mem_ctx, found_name);
405         return status;
406 }
407
408 /*
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().
416  */
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)
422 {
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;
428
429         upper = talloc_strdup_upper(mem_ctx, name);
430         if (upper == NULL) {
431                 return false;
432         }
433         namelen = talloc_get_size(upper);
434
435         keylen = namelen + sizeof(fid);
436         if (keylen < sizeof(fid)) {
437                 TALLOC_FREE(upper);
438                 return false;
439         }
440
441         key = talloc_size(mem_ctx, keylen);
442         if (key == NULL) {
443                 TALLOC_FREE(upper);
444                 return false;
445         }
446
447         memcpy(key, &fid, sizeof(fid));
448         memcpy(key + sizeof(fid), upper, namelen);
449         TALLOC_FREE(upper);
450
451         *_key = (DATA_BLOB) { .data = key, .length = keylen, };
452         return true;
453 }
454
455 /*
456  * Lightweight function to just get last component
457  * for rename / enumerate directory calls.
458  */
459
460 char *get_original_lcomp(TALLOC_CTX *ctx,
461                         connection_struct *conn,
462                         const char *filename_in,
463                         uint32_t ucf_flags)
464 {
465         char *last_slash = NULL;
466         char *orig_lcomp;
467         NTSTATUS status;
468
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);
474         }
475         if (orig_lcomp == NULL) {
476                 return NULL;
477         }
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;
482         }
483         return orig_lcomp;
484 }
485
486 /*
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.
490  */
491
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)
499 {
500         NTSTATUS status;
501         char *p = NULL;
502         char *mask = NULL;
503         struct smb_filename *smb_fname = NULL;
504         NTTIME twrp = 0;
505
506         *_smb_fname_out = NULL;
507         *_dirfsp = NULL;
508         *_mask_out = NULL;
509
510         DBG_DEBUG("name_in: %s\n", name_in);
511
512         if (ucf_flags & UCF_GMT_PATHNAME) {
513                 extract_snapshot_token(name_in, &twrp);
514                 ucf_flags &= ~UCF_GMT_PATHNAME;
515         }
516
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;
524         }
525
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;
532                 }
533         }
534
535         DBG_DEBUG("mask = %s\n", mask);
536
537         /*
538          * Remove the terminal component so
539          * filename_convert_dirfsp never sees the mask.
540          */
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';
547         }
548
549         DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n",
550                 name_in);
551
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);
560
561         if (!NT_STATUS_IS_OK(status)) {
562                 DBG_DEBUG("filename_convert error for %s: %s\n",
563                         name_in,
564                         nt_errstr(status));
565         }
566
567         *_smb_fname_out = talloc_move(ctx, &smb_fname);
568         *_mask_out = talloc_move(ctx, &mask);
569
570         return status;
571 }
572
573 /*
574  * Get the correct capitalized stream name hanging off
575  * base_fsp. Equivalent of get_real_filename(), but for streams.
576  */
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)
582 {
583         unsigned int i, num_streams = 0;
584         struct stream_struct *streams = NULL;
585         NTSTATUS status;
586
587         status = vfs_fstreaminfo(
588                 base_fsp, talloc_tos(), &num_streams, &streams);
589         if (!NT_STATUS_IS_OK(status)) {
590                 return status;
591         }
592
593         for (i=0; i<num_streams; i++) {
594                 bool equal = sname_equal(stream_name, streams[i].name, false);
595
596                 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
597                           stream_name,
598                           streams[i].name,
599                           equal ? "" : "not ");
600
601                 if (equal) {
602                         *_found = talloc_move(mem_ctx, &streams[i].name);
603                         TALLOC_FREE(streams);
604                         return NT_STATUS_OK;
605                 }
606         }
607
608         TALLOC_FREE(streams);
609         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
610 }
611
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)
619 {
620         const char *lcomp = NULL;
621         const char *fname_rel = NULL;
622         const char *streamname = NULL;
623         char *dirname = NULL;
624
625         if (name_in[0] == '\0') {
626                 fname_rel = ".";
627                 dirname = talloc_strdup(mem_ctx, "");
628                 if (dirname == NULL) {
629                         return false;
630                 }
631                 goto done;
632         }
633
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;
640                 }
641                 goto find_stream;
642         }
643
644         /*
645          * No slash, dir is empty
646          */
647         dirname = talloc_strdup(mem_ctx, "");
648         if (dirname == NULL) {
649                 return false;
650         }
651
652         if (!posix && (name_in[0] == ':')) {
653                 /*
654                  * Special case for stream on root directory
655                  */
656                 fname_rel = ".";
657                 streamname = name_in;
658                 goto done;
659         }
660
661         fname_rel = name_in;
662
663 find_stream:
664         if (!posix) {
665                 streamname = strchr_m(fname_rel, ':');
666
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;
675                         }
676                 }
677         }
678
679 done:
680         *_dirname = dirname;
681         *_fname_rel = fname_rel;
682         *_streamname = streamname;
683         return true;
684 }
685
686 /*
687  * Create the correct capitalization of a file name to be created.
688  */
689 static NTSTATUS filename_convert_normalize_new(
690         TALLOC_CTX *mem_ctx,
691         struct connection_struct *conn,
692         char *name_in,
693         char **_normalized)
694 {
695         char *name = name_in;
696
697         *_normalized = NULL;
698
699         if (!conn->case_preserve ||
700             (mangle_is_8_3(name, false,
701                            conn->params) &&
702              !conn->short_case_preserve)) {
703
704                 char *normalized = talloc_strdup(mem_ctx, name);
705                 if (normalized == NULL) {
706                         return NT_STATUS_NO_MEMORY;
707                 }
708
709                 strnorm(normalized, lp_default_case(SNUM(conn)));
710                 name = normalized;
711         }
712
713         if (mangle_is_mangled(name, conn->params)) {
714                 bool found;
715                 char *unmangled = NULL;
716
717                 found = mangle_lookup_name_from_8_3(
718                         mem_ctx, name, &unmangled, conn->params);
719                 if (found) {
720                         name = unmangled;
721                 }
722         }
723
724         if (name != name_in) {
725                 *_normalized = name;
726         }
727
728         return NT_STATUS_OK;
729 }
730
731 /*
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.
736  */
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)
741 {
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;
747
748         SET_STAT_INVALID(smb_fname_rel->st);
749
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;
755         }
756
757         status = openat_pathref_fsp(dirfsp, smb_fname_rel);
758
759         if (NT_STATUS_IS_OK(status)) {
760                 return NT_STATUS_OK;
761         }
762
763         if (VALID_STAT(smb_fname_rel->st)) {
764                 /*
765                  * We got an error although the object existed. Might
766                  * be a symlink we don't want.
767                  */
768                 return status;
769         }
770
771         if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
772                 /*
773                  * Only retry on ENOENT
774                  */
775                 return status;
776         }
777
778         if (posix || dirfsp->conn->case_sensitive) {
779                 /*
780                  * Only return case insensitive if required
781                  */
782                 return status;
783         }
784
785         if (lp_stat_cache()) {
786                 char *base_name = smb_fname_rel->base_name;
787                 DATA_BLOB value = { .data = NULL };
788
789                 ok = get_real_filename_cache_key(
790                         talloc_tos(), dirfsp, base_name, &cache_key);
791                 if (!ok) {
792                         /*
793                          * probably ENOMEM, just bail
794                          */
795                         return status;
796                 }
797
798                 DO_PROFILE_INC(statcache_lookups);
799
800                 ok = memcache_lookup(
801                         NULL, GETREALFILENAME_CACHE, cache_key, &value);
802                 if (!ok) {
803                         DO_PROFILE_INC(statcache_misses);
804                         goto lookup;
805                 }
806                 DO_PROFILE_INC(statcache_hits);
807
808                 TALLOC_FREE(smb_fname_rel->base_name);
809                 smb_fname_rel->base_name = talloc_memdup(
810                         smb_fname_rel, value.data, value.length);
811                 if (smb_fname_rel->base_name == NULL) {
812                         TALLOC_FREE(cache_key.data);
813                         return NT_STATUS_NO_MEMORY;
814                 }
815
816                 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
817                         DBG_DEBUG("veto files rejecting last component %s\n",
818                                   smb_fname_str_dbg(smb_fname_rel));
819                         TALLOC_FREE(cache_key.data);
820                         return NT_STATUS_NETWORK_OPEN_RESTRICTION;
821                 }
822
823                 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
824                 if (NT_STATUS_IS_OK(status)) {
825                         TALLOC_FREE(cache_key.data);
826                         return NT_STATUS_OK;
827                 }
828
829                 memcache_delete(NULL, GETREALFILENAME_CACHE, cache_key);
830         }
831
832 lookup:
833         status = get_real_filename_at(
834                 dirfsp, smb_fname_rel->base_name, smb_fname_rel, &found_name);
835         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
836             (ucf_flags & UCF_PREP_CREATEFILE)) {
837                 /*
838                  * dropbox
839                  */
840                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
841         }
842
843         if (NT_STATUS_IS_OK(status)) {
844                 TALLOC_FREE(smb_fname_rel->base_name);
845                 smb_fname_rel->base_name = found_name;
846
847                 if (IS_VETO_PATH(dirfsp->conn, smb_fname_rel->base_name)) {
848                         DBG_DEBUG("veto files rejecting last component %s\n",
849                                 smb_fname_str_dbg(smb_fname_rel));
850                         return NT_STATUS_NETWORK_OPEN_RESTRICTION;
851                 }
852
853                 status = openat_pathref_fsp(dirfsp, smb_fname_rel);
854         }
855
856         if (NT_STATUS_IS_OK(status) && (cache_key.data != NULL)) {
857                 DATA_BLOB value = {
858                         .data = (uint8_t *)smb_fname_rel->base_name,
859                         .length = strlen(smb_fname_rel->base_name) + 1,
860                 };
861
862                 memcache_add(NULL, GETREALFILENAME_CACHE, cache_key, value);
863         }
864
865         TALLOC_FREE(cache_key.data);
866
867         return status;
868 }
869
870 static const char *previous_slash(const char *name_in, const char *slash)
871 {
872         const char *prev = name_in;
873
874         while (true) {
875                 const char *next = strchr_m(prev, '/');
876
877                 SMB_ASSERT(next != NULL); /* we have at least one slash */
878
879                 if (next == slash) {
880                         break;
881                 }
882
883                 prev = next+1;
884         };
885
886         if (prev == name_in) {
887                 /* no previous slash */
888                 return NULL;
889         }
890
891         return prev;
892 }
893
894 static char *symlink_target_path(
895         TALLOC_CTX *mem_ctx,
896         const char *name_in,
897         const char *substitute,
898         size_t unparsed)
899 {
900         size_t name_in_len = strlen(name_in);
901         const char *p_unparsed = NULL;
902         const char *parent = NULL;
903         char *ret;
904
905         SMB_ASSERT(unparsed <= name_in_len);
906
907         p_unparsed = name_in + (name_in_len - unparsed);
908
909         if (substitute[0] == '/') {
910                 ret = talloc_asprintf(mem_ctx, "%s%s", substitute, p_unparsed);
911                 return ret;
912         }
913
914         if (unparsed == 0) {
915                 parent = strrchr_m(name_in, '/');
916         } else {
917                 parent = previous_slash(name_in, p_unparsed);
918         }
919
920         if (parent == NULL) {
921                 /* no previous slash */
922                 parent = name_in;
923         }
924
925         ret = talloc_asprintf(
926                 mem_ctx,
927                 "%.*s%s%s",
928                 (int)(parent - name_in),
929                 name_in,
930                 substitute,
931                 p_unparsed);
932         return ret;
933 }
934
935 static NTSTATUS safe_symlink_target_path(
936         TALLOC_CTX *mem_ctx,
937         const char *connectpath,
938         const char *name_in,
939         const char *substitute,
940         size_t unparsed,
941         char **_name_out)
942 {
943         char *target = NULL;
944         char *abs_target = NULL;
945         char *abs_target_canon = NULL;
946         const char *relative = NULL;
947         char *name_out = NULL;
948         NTSTATUS status = NT_STATUS_NO_MEMORY;
949         bool in_share;
950
951         target = symlink_target_path(mem_ctx, name_in, substitute, unparsed);
952         if (target == NULL) {
953                 goto fail;
954         }
955
956         DBG_DEBUG("name_in: %s, substitute: %s, unparsed: %zu, target=%s\n",
957                   name_in,
958                   substitute,
959                   unparsed,
960                   target);
961
962         if (target[0] == '/') {
963                 abs_target = target;
964         } else {
965                 abs_target = talloc_asprintf(
966                         target, "%s/%s", connectpath, target);
967                 if (abs_target == NULL) {
968                         goto fail;
969                 }
970         }
971
972         abs_target_canon = canonicalize_absolute_path(target, abs_target);
973         if (abs_target_canon == NULL) {
974                 goto fail;
975         }
976
977         DBG_DEBUG("abs_target_canon=%s\n", abs_target_canon);
978
979         in_share = subdir_of(
980                 connectpath, strlen(connectpath), abs_target_canon, &relative);
981         if (!in_share) {
982                 DBG_DEBUG("wide link to %s\n", abs_target_canon);
983                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
984                 goto fail;
985         }
986
987         name_out = talloc_strdup(mem_ctx, relative);
988         if (name_out == NULL) {
989                 goto fail;
990         }
991
992         status = NT_STATUS_OK;
993         *_name_out = name_out;
994 fail:
995         TALLOC_FREE(target);
996         return status;
997 }
998
999 /*
1000  * Split up name_in as sent by the client into a directory pathref fsp
1001  * and a relative smb_filename.
1002  */
1003 static NTSTATUS filename_convert_dirfsp_nosymlink(
1004         TALLOC_CTX *mem_ctx,
1005         connection_struct *conn,
1006         const char *name_in,
1007         uint32_t ucf_flags,
1008         NTTIME twrp,
1009         struct files_struct **_dirfsp,
1010         struct smb_filename **_smb_fname,
1011         char **_substitute,
1012         size_t *_unparsed)
1013 {
1014         struct smb_filename *smb_dirname = NULL;
1015         struct smb_filename *smb_fname_rel = NULL;
1016         struct smb_filename *smb_fname = NULL;
1017         const bool posix = (ucf_flags & UCF_POSIX_PATHNAMES);
1018         char *dirname = NULL;
1019         const char *fname_rel = NULL;
1020         const char *streamname = NULL;
1021         char *saved_streamname = NULL;
1022         struct files_struct *base_fsp = NULL;
1023         bool ok;
1024         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1025
1026         SMB_ASSERT(!(ucf_flags & UCF_DFS_PATHNAME));
1027
1028         if (is_fake_file_path(name_in)) {
1029                 smb_fname = synthetic_smb_fname_split(mem_ctx, name_in, posix);
1030                 if (smb_fname == NULL) {
1031                         return NT_STATUS_NO_MEMORY;
1032                 }
1033                 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1034                 smb_fname->st.st_ex_btime =
1035                         (struct timespec){0, SAMBA_UTIME_OMIT};
1036                 smb_fname->st.st_ex_atime =
1037                         (struct timespec){0, SAMBA_UTIME_OMIT};
1038                 smb_fname->st.st_ex_mtime =
1039                         (struct timespec){0, SAMBA_UTIME_OMIT};
1040                 smb_fname->st.st_ex_ctime =
1041                         (struct timespec){0, SAMBA_UTIME_OMIT};
1042
1043                 *_dirfsp = conn->cwd_fsp;
1044                 *_smb_fname = smb_fname;
1045                 return NT_STATUS_OK;
1046         }
1047
1048         /*
1049          * Catch an invalid path of "." before we
1050          * call filename_split_lcomp(). We need to
1051          * do this as filename_split_lcomp() will
1052          * use "." for the missing relative component
1053          * when an empty name_in path is sent by
1054          * the client.
1055          */
1056         if (ISDOT(name_in)) {
1057                 status = NT_STATUS_OBJECT_NAME_INVALID;
1058                 goto fail;
1059         }
1060
1061         ok = filename_split_lcomp(
1062                 talloc_tos(),
1063                 name_in,
1064                 posix,
1065                 &dirname,
1066                 &fname_rel,
1067                 &streamname);
1068         if (!ok) {
1069                 status = NT_STATUS_NO_MEMORY;
1070                 goto fail;
1071         }
1072
1073         if ((streamname != NULL) &&
1074             ((conn->fs_capabilities & FILE_NAMED_STREAMS) == 0)) {
1075                 status = NT_STATUS_OBJECT_NAME_INVALID;
1076                 goto fail;
1077         }
1078
1079         if (!posix) {
1080                 bool name_has_wild = ms_has_wild(dirname);
1081                 name_has_wild |= ms_has_wild(fname_rel);
1082                 if (name_has_wild) {
1083                         status = NT_STATUS_OBJECT_NAME_INVALID;
1084                         goto fail;
1085                 }
1086         }
1087
1088         if (dirname[0] == '\0') {
1089                 status = synthetic_pathref(
1090                         mem_ctx,
1091                         conn->cwd_fsp,
1092                         ".",
1093                         NULL,
1094                         NULL,
1095                         0,
1096                         posix ? SMB_FILENAME_POSIX_PATH : 0,
1097                         &smb_dirname);
1098         } else {
1099                 struct open_symlink_err *symlink_err = NULL;
1100
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;
1107                 }
1108
1109                 status = openat_pathref_fsp_nosymlink(mem_ctx,
1110                                                       conn,
1111                                                       conn->cwd_fsp,
1112                                                       dirname,
1113                                                       0,
1114                                                       posix,
1115                                                       &smb_dirname,
1116                                                       &symlink_err);
1117
1118                 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1119                         size_t name_in_len, dirname_len;
1120
1121                         if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1122                             strnequal(symlink_err->reparse->substitute_name,
1123                                       "msdfs:",
1124                                       6)) {
1125                                 status = NT_STATUS_PATH_NOT_COVERED;
1126                                 goto fail;
1127                         }
1128
1129                         name_in_len = strlen(name_in);
1130                         dirname_len = strlen(dirname);
1131
1132                         SMB_ASSERT(name_in_len >= dirname_len);
1133
1134                         *_substitute = talloc_move(
1135                                 mem_ctx,
1136                                 &symlink_err->reparse->substitute_name);
1137                         *_unparsed = symlink_err->unparsed +
1138                                      (name_in_len - dirname_len);
1139
1140                         goto fail;
1141                 }
1142         }
1143
1144         if (!NT_STATUS_IS_OK(status)) {
1145                 DBG_DEBUG("opening directory %s failed: %s\n",
1146                           dirname,
1147                           nt_errstr(status));
1148                 TALLOC_FREE(dirname);
1149
1150                 if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1151                         /*
1152                          * Except ACCESS_DENIED, everything else leads
1153                          * to PATH_NOT_FOUND.
1154                          */
1155                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1156                 }
1157
1158                 goto fail;
1159         }
1160
1161         if (!VALID_STAT_OF_DIR(smb_dirname->st)) {
1162                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1163                 goto fail;
1164         }
1165         smb_dirname->fsp->fsp_flags.is_directory = true;
1166
1167         /*
1168          * Only look at bad last component values
1169          * once we know we have a valid directory. That
1170          * way we won't confuse error messages from
1171          * opening the directory path with error
1172          * messages from a bad last component.
1173          */
1174
1175         /* Relative filename can't be empty */
1176         if (fname_rel[0] == '\0') {
1177                 status = NT_STATUS_OBJECT_NAME_INVALID;
1178                 goto fail;
1179         }
1180
1181         /* Relative filename can't be ".." */
1182         if (ISDOTDOT(fname_rel)) {
1183                 status = NT_STATUS_OBJECT_NAME_INVALID;
1184                 goto fail;
1185         }
1186         /* Relative name can only be dot if directory is empty. */
1187         if (ISDOT(fname_rel) && dirname[0] != '\0') {
1188                 status = NT_STATUS_OBJECT_NAME_INVALID;
1189                 goto fail;
1190         }
1191
1192         TALLOC_FREE(dirname);
1193
1194         smb_fname_rel = synthetic_smb_fname(
1195                 mem_ctx,
1196                 fname_rel,
1197                 streamname,
1198                 NULL,
1199                 twrp,
1200                 posix ? SMB_FILENAME_POSIX_PATH : 0);
1201         if (smb_fname_rel == NULL) {
1202                 status = NT_STATUS_NO_MEMORY;
1203                 goto fail;
1204         }
1205
1206         if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
1207             is_named_stream(smb_fname_rel)) {
1208                 /*
1209                  * Find the base_fsp first without the stream.
1210                  */
1211                 saved_streamname = smb_fname_rel->stream_name;
1212                 smb_fname_rel->stream_name = NULL;
1213         }
1214
1215         status = normalize_filename_case(
1216                 conn, smb_fname_rel->base_name, ucf_flags);
1217         if (!NT_STATUS_IS_OK(status)) {
1218                 DBG_ERR("normalize_filename_case %s failed: %s\n",
1219                         smb_fname_rel->base_name,
1220                         nt_errstr(status));
1221                 goto fail;
1222         }
1223
1224         status = openat_pathref_fsp_case_insensitive(
1225                 smb_dirname->fsp, smb_fname_rel, ucf_flags);
1226
1227         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1228             VALID_STAT(smb_fname_rel->st) &&
1229             S_ISLNK(smb_fname_rel->st.st_ex_mode)) {
1230
1231                 /*
1232                  * If we're on an MSDFS share, see if this is
1233                  * an MSDFS link.
1234                  */
1235                 if (lp_host_msdfs() &&
1236                     lp_msdfs_root(SNUM(conn)) &&
1237                     is_msdfs_link(smb_dirname->fsp, smb_fname_rel))
1238                 {
1239                         status = NT_STATUS_PATH_NOT_COVERED;
1240                         goto fail;
1241                 }
1242
1243 #if defined(WITH_SMB1SERVER)
1244                 /*
1245                  * In SMB1 posix mode, if this is a symlink,
1246                  * allow access to the name with a NULL smb_fname->fsp.
1247                  */
1248                 if (ucf_flags & UCF_LCOMP_LNK_OK) {
1249                         SMB_ASSERT(smb_fname_rel->fsp == NULL);
1250                         SMB_ASSERT(streamname == NULL);
1251
1252                         smb_fname = full_path_from_dirfsp_atname(
1253                                 mem_ctx,
1254                                 smb_dirname->fsp,
1255                                 smb_fname_rel);
1256                         if (smb_fname == NULL) {
1257                                 status = NT_STATUS_NO_MEMORY;
1258                                 goto fail;
1259                         }
1260                         goto done;
1261                 }
1262 #endif
1263         }
1264
1265         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1266             !VALID_STAT(smb_fname_rel->st)) {
1267
1268                 char *normalized = NULL;
1269
1270                 /*
1271                  * Creating a new file
1272                  */
1273
1274                 status = filename_convert_normalize_new(
1275                         smb_fname_rel,
1276                         conn,
1277                         smb_fname_rel->base_name,
1278                         &normalized);
1279                 if (!NT_STATUS_IS_OK(status)) {
1280                         DBG_DEBUG("filename_convert_normalize_new failed: "
1281                                   "%s\n",
1282                                   nt_errstr(status));
1283                         goto fail;
1284                 }
1285                 if (normalized != NULL) {
1286                         smb_fname_rel->base_name = normalized;
1287                 }
1288
1289                 smb_fname_rel->stream_name = saved_streamname;
1290
1291                 smb_fname = full_path_from_dirfsp_atname(
1292                         mem_ctx, smb_dirname->fsp, smb_fname_rel);
1293                 if (smb_fname == NULL) {
1294                         status = NT_STATUS_NO_MEMORY;
1295                         goto fail;
1296                 }
1297                 goto done;
1298         }
1299
1300         if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_OPEN_RESTRICTION)) {
1301                 /* A vetoed file, pretend it's not there  */
1302                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1303         }
1304         if (!NT_STATUS_IS_OK(status)) {
1305                 goto fail;
1306         }
1307
1308         if (saved_streamname == NULL) {
1309                 /* smb_fname must be allocated off mem_ctx. */
1310                 smb_fname = cp_smb_filename(mem_ctx,
1311                                             smb_fname_rel->fsp->fsp_name);
1312                 if (smb_fname == NULL) {
1313                         goto fail;
1314                 }
1315                 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1316                 if (!NT_STATUS_IS_OK(status)) {
1317                         goto fail;
1318                 }
1319                 goto done;
1320         }
1321
1322         base_fsp = smb_fname_rel->fsp;
1323         smb_fname_fsp_unlink(smb_fname_rel);
1324         SET_STAT_INVALID(smb_fname_rel->st);
1325
1326         smb_fname_rel->stream_name = saved_streamname;
1327
1328         status = open_stream_pathref_fsp(&base_fsp, smb_fname_rel);
1329
1330         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
1331             !conn->case_sensitive) {
1332                 char *found = NULL;
1333
1334                 status = get_real_stream_name(
1335                         smb_fname_rel,
1336                         base_fsp,
1337                         smb_fname_rel->stream_name,
1338                         &found);
1339
1340                 if (NT_STATUS_IS_OK(status)) {
1341                         smb_fname_rel->stream_name = found;
1342                         found = NULL;
1343                         status = open_stream_pathref_fsp(
1344                                 &base_fsp, smb_fname_rel);
1345                 }
1346         }
1347
1348         if (NT_STATUS_IS_OK(status)) {
1349                 /* smb_fname must be allocated off mem_ctx. */
1350                 smb_fname = cp_smb_filename(mem_ctx,
1351                                             smb_fname_rel->fsp->fsp_name);
1352                 if (smb_fname == NULL) {
1353                         goto fail;
1354                 }
1355                 status = move_smb_fname_fsp_link(smb_fname, smb_fname_rel);
1356                 if (!NT_STATUS_IS_OK(status)) {
1357                         goto fail;
1358                 }
1359                 goto done;
1360         }
1361
1362         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1363                 /*
1364                  * Creating a new stream
1365                  *
1366                  * We should save the already-open base fsp for
1367                  * create_file_unixpath() somehow.
1368                  */
1369                 smb_fname = full_path_from_dirfsp_atname(
1370                         mem_ctx, smb_dirname->fsp, smb_fname_rel);
1371                 if (smb_fname == NULL) {
1372                         status = NT_STATUS_NO_MEMORY;
1373                         goto fail;
1374                 }
1375                 /*
1376                  * When open_stream_pathref_fsp() returns
1377                  * NT_STATUS_OBJECT_NAME_NOT_FOUND, smb_fname_rel->fsp
1378                  * has been set to NULL, so we must free base_fsp separately
1379                  * to prevent fd-leaks when opening a stream that doesn't
1380                  * exist.
1381                  */
1382                 fd_close(base_fsp);
1383                 file_free(NULL, base_fsp);
1384                 base_fsp = NULL;
1385                 goto done;
1386         }
1387
1388         if (!NT_STATUS_IS_OK(status)) {
1389                 goto fail;
1390         }
1391
1392 done:
1393         *_dirfsp = smb_dirname->fsp;
1394         *_smb_fname = smb_fname;
1395
1396         smb_fname_fsp_unlink(smb_fname_rel);
1397         TALLOC_FREE(smb_fname_rel);
1398         return NT_STATUS_OK;
1399
1400 fail:
1401         /*
1402          * If open_stream_pathref_fsp() returns an error, smb_fname_rel->fsp
1403          * has been set to NULL, so we must free base_fsp separately
1404          * to prevent fd-leaks when opening a stream that doesn't
1405          * exist.
1406          */
1407         if (base_fsp != NULL) {
1408                 fd_close(base_fsp);
1409                 file_free(NULL, base_fsp);
1410                 base_fsp = NULL;
1411         }
1412         TALLOC_FREE(dirname);
1413         TALLOC_FREE(smb_dirname);
1414         TALLOC_FREE(smb_fname_rel);
1415         return status;
1416 }
1417
1418 NTSTATUS filename_convert_dirfsp(
1419         TALLOC_CTX *mem_ctx,
1420         connection_struct *conn,
1421         const char *name_in,
1422         uint32_t ucf_flags,
1423         NTTIME twrp,
1424         struct files_struct **_dirfsp,
1425         struct smb_filename **_smb_fname)
1426 {
1427         char *substitute = NULL;
1428         size_t unparsed = 0;
1429         NTSTATUS status;
1430         char *target = NULL;
1431         size_t symlink_redirects = 0;
1432
1433 next:
1434         if (symlink_redirects > 40) {
1435                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1436         }
1437
1438         status = filename_convert_dirfsp_nosymlink(
1439                 mem_ctx,
1440                 conn,
1441                 name_in,
1442                 ucf_flags,
1443                 twrp,
1444                 _dirfsp,
1445                 _smb_fname,
1446                 &substitute,
1447                 &unparsed);
1448
1449         if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
1450                 return status;
1451         }
1452
1453         if (!lp_follow_symlinks(SNUM(conn))) {
1454                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1455         }
1456
1457         /*
1458          * Right now, SMB2 and SMB1 always traverse symlinks
1459          * within the share. SMB1+POSIX traverses non-terminal
1460          * symlinks within the share.
1461          *
1462          * When we add SMB2+POSIX we need to return
1463          * a NT_STATUS_STOPPED_ON_SYMLINK error here, using the
1464          * symlink target data read below if SMB2+POSIX has
1465          * UCF_POSIX_PATHNAMES set to cause the client to
1466          * resolve all symlinks locally.
1467          */
1468
1469         status = safe_symlink_target_path(
1470                 mem_ctx,
1471                 conn->connectpath,
1472                 name_in,
1473                 substitute,
1474                 unparsed,
1475                 &target);
1476         if (!NT_STATUS_IS_OK(status)) {
1477                 return status;
1478         }
1479         name_in = target;
1480
1481         symlink_redirects += 1;
1482
1483         goto next;
1484 }
1485
1486 char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
1487                                         const struct files_struct *dirfsp,
1488                                         const char *at_base_name)
1489 {
1490         char *path = NULL;
1491
1492         if (dirfsp == dirfsp->conn->cwd_fsp ||
1493             ISDOT(dirfsp->fsp_name->base_name) || at_base_name[0] == '/') {
1494                 path = talloc_strdup(mem_ctx, at_base_name);
1495         } else {
1496                 path = talloc_asprintf(mem_ctx,
1497                                        "%s/%s",
1498                                        dirfsp->fsp_name->base_name,
1499                                        at_base_name);
1500         }
1501
1502         return path;
1503 }
1504
1505 /*
1506  * Build the full path from a dirfsp and dirfsp relative name
1507  */
1508 struct smb_filename *
1509 full_path_from_dirfsp_atname(TALLOC_CTX *mem_ctx,
1510                              const struct files_struct *dirfsp,
1511                              const struct smb_filename *atname)
1512 {
1513         struct smb_filename *fname = NULL;
1514         char *path = NULL;
1515
1516         path = full_path_from_dirfsp_at_basename(mem_ctx,
1517                                                  dirfsp,
1518                                                  atname->base_name);
1519         if (path == NULL) {
1520                 return NULL;
1521         }
1522
1523         fname = synthetic_smb_fname(mem_ctx,
1524                                     path,
1525                                     atname->stream_name,
1526                                     &atname->st,
1527                                     atname->twrp,
1528                                     atname->flags);
1529         TALLOC_FREE(path);
1530         if (fname == NULL) {
1531                 return NULL;
1532         }
1533
1534         return fname;
1535 }