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