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