smbd: Make strnorm() static to filename.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
33 static int get_real_filename(connection_struct *conn,
34                              struct smb_filename *path,
35                              const char *name,
36                              TALLOC_CTX *mem_ctx,
37                              char **found_name);
38
39 static NTSTATUS check_name(connection_struct *conn,
40                            const struct smb_filename *smb_fname);
41
42 uint32_t ucf_flags_from_smb_request(struct smb_request *req)
43 {
44         uint32_t ucf_flags = 0;
45
46         if (req != NULL) {
47                 if (req->posix_pathnames) {
48                         ucf_flags |= UCF_POSIX_PATHNAMES;
49                 }
50                 if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
51                         ucf_flags |= UCF_DFS_PATHNAME;
52                 }
53                 if (req->flags2 & FLAGS2_REPARSE_PATH) {
54                         ucf_flags |= UCF_GMT_PATHNAME;
55                 }
56         }
57
58         return ucf_flags;
59 }
60
61 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
62 {
63         uint32_t ucf_flags = 0;
64
65         ucf_flags |= ucf_flags_from_smb_request(req);
66
67         switch (create_disposition) {
68         case FILE_OPEN:
69         case FILE_OVERWRITE:
70                 break;
71         case FILE_SUPERSEDE:
72         case FILE_CREATE:
73         case FILE_OPEN_IF:
74         case FILE_OVERWRITE_IF:
75                 ucf_flags |= UCF_PREP_CREATEFILE;
76                 break;
77         }
78
79         return ucf_flags;
80 }
81
82 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
83                                   connection_struct *conn,
84                                   struct smb_filename *smb_fname);
85
86 /****************************************************************************
87  Mangle the 2nd name and check if it is then equal to the first name.
88 ****************************************************************************/
89
90 static bool mangled_equal(const char *name1,
91                         const char *name2,
92                         const struct share_params *p)
93 {
94         char mname[13];
95
96         if (!name_to_8_3(name2, mname, False, p)) {
97                 return False;
98         }
99         return strequal(name1, mname);
100 }
101
102 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
103 {
104         /* Ensure we catch all names with in "/."
105            this is disallowed under Windows and
106            in POSIX they've already been removed. */
107         const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
108         if (p) {
109                 if (p[2] == '/') {
110                         /* Error code within a pathname. */
111                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
112                 } else if (p[2] == '\0') {
113                         /* Error code at the end of a pathname. */
114                         return NT_STATUS_OBJECT_NAME_INVALID;
115                 }
116         }
117         return NT_STATUS_OK;
118 }
119
120 /****************************************************************************
121  Optimization for common case where the missing part
122  is in the last component and the client already
123  sent the correct case.
124  Returns NT_STATUS_OK to mean continue the tree walk
125  (possibly with modified start pointer).
126  Any other NT_STATUS_XXX error means terminate the path
127  lookup here.
128 ****************************************************************************/
129
130 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
131                                 connection_struct *conn,
132                                 bool posix_pathnames,
133                                 const struct smb_filename *smb_fname,
134                                 char **pp_dirpath,
135                                 char **pp_start,
136                                 int *p_parent_stat_errno)
137 {
138         char *parent_name = NULL;
139         struct smb_filename *parent_fname = NULL;
140         const char *last_component = NULL;
141         NTSTATUS status;
142         int ret;
143
144         if (!parent_dirname(ctx, smb_fname->base_name,
145                                 &parent_name,
146                                 &last_component)) {
147                 return NT_STATUS_NO_MEMORY;
148         }
149
150         if (!posix_pathnames) {
151                 if (ms_has_wild(parent_name)) {
152                         goto no_optimization_out;
153                 }
154         }
155
156         /*
157          * If there was no parent component in
158          * smb_fname->base_name then don't do this
159          * optimization.
160          */
161         if (smb_fname->base_name == last_component) {
162                 goto no_optimization_out;
163         }
164
165         parent_fname = synthetic_smb_fname(ctx,
166                                            parent_name,
167                                            NULL,
168                                            NULL,
169                                            smb_fname->twrp,
170                                            smb_fname->flags);
171         if (parent_fname == NULL) {
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         ret = vfs_stat(conn, parent_fname);
176
177         /* If the parent stat failed, just continue
178            with the normal tree walk. */
179
180         if (ret == -1) {
181                 /*
182                  * Optimization. Preserving the
183                  * errno from the STAT/LSTAT here
184                  * will allow us to save a duplicate
185                  * STAT/LSTAT system call of the parent
186                  * pathname in a hot code path in the caller.
187                  */
188                 if (p_parent_stat_errno != NULL) {
189                         *p_parent_stat_errno = errno;
190                 }
191                 goto no_optimization_out;
192         }
193
194         status = check_for_dot_component(parent_fname);
195         if (!NT_STATUS_IS_OK(status)) {
196                 return status;
197         }
198
199         /* Parent exists - set "start" to be the
200          * last component to shorten the tree walk. */
201
202         /*
203          * Safe to use discard_const_p
204          * here as last_component points
205          * into our smb_fname->base_name.
206          */
207         *pp_start = discard_const_p(char, last_component);
208
209         /* Update dirpath. */
210         TALLOC_FREE(*pp_dirpath);
211         *pp_dirpath = talloc_strdup(ctx, parent_fname->base_name);
212         if (!*pp_dirpath) {
213                 return NT_STATUS_NO_MEMORY;
214         }
215
216         DEBUG(5,("check_parent_exists: name "
217                 "= %s, dirpath = %s, "
218                 "start = %s\n",
219                 smb_fname->base_name,
220                 *pp_dirpath,
221                 *pp_start));
222
223         return NT_STATUS_OK;
224
225   no_optimization_out:
226
227         /*
228          * We must still return an *pp_dirpath
229          * initialized to ".", and a *pp_start
230          * pointing at smb_fname->base_name.
231          */
232
233         TALLOC_FREE(parent_name);
234         TALLOC_FREE(parent_fname);
235
236         *pp_dirpath = talloc_strdup(ctx, ".");
237         if (*pp_dirpath == NULL) {
238                 return NT_STATUS_NO_MEMORY;
239         }
240         /*
241          * Safe to use discard_const_p
242          * here as by convention smb_fname->base_name
243          * is allocated off ctx.
244          */
245         *pp_start = discard_const_p(char, smb_fname->base_name);
246         return NT_STATUS_OK;
247 }
248
249 /*
250  * Re-order a known good @GMT-token path.
251  */
252
253 static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
254                                 char *startp,
255                                 char *endp)
256 {
257         size_t endlen = 0;
258         size_t gmt_len = endp - startp;
259         char gmt_store[gmt_len + 1];
260         char *parent = NULL;
261         const char *last_component = NULL;
262         char *newstr;
263         bool ret;
264
265         DBG_DEBUG("|%s| -> ", smb_fname->base_name);
266
267         /* Save off the @GMT-token. */
268         memcpy(gmt_store, startp, gmt_len);
269         gmt_store[gmt_len] = '\0';
270
271         if (*endp == '/') {
272                 /* Remove any trailing '/' */
273                 endp++;
274         }
275
276         if (*endp == '\0') {
277                 /*
278                  * @GMT-token was at end of path.
279                  * Remove any preceding '/'
280                  */
281                 if (startp > smb_fname->base_name && startp[-1] == '/') {
282                         startp--;
283                 }
284         }
285
286         /* Remove @GMT-token from the path. */
287         endlen = strlen(endp);
288         memmove(startp, endp, endlen + 1);
289
290         /* Split the remaining path into components. */
291         ret = parent_dirname(smb_fname,
292                                 smb_fname->base_name,
293                                 &parent,
294                                 &last_component);
295         if (!ret) {
296                 /* Must terminate debug with \n */
297                 DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
298                 return NT_STATUS_NO_MEMORY;
299         }
300
301         if (ISDOT(parent)) {
302                 if (last_component[0] == '\0') {
303                         newstr = talloc_strdup(smb_fname,
304                                         gmt_store);
305                 } else {
306                         newstr = talloc_asprintf(smb_fname,
307                                         "%s/%s",
308                                         gmt_store,
309                                         last_component);
310                 }
311         } else {
312                 newstr = talloc_asprintf(smb_fname,
313                                         "%s/%s/%s",
314                                         gmt_store,
315                                         parent,
316                                         last_component);
317         }
318
319         TALLOC_FREE(parent);
320         TALLOC_FREE(smb_fname->base_name);
321         smb_fname->base_name = newstr;
322
323         DBG_DEBUG("|%s|\n", newstr);
324
325         return NT_STATUS_OK;
326 }
327
328 /*
329  * Strip a valid @GMT-token from any incoming filename path,
330  * adding any NTTIME encoded in the pathname into the
331  * twrp field of the passed in smb_fname.
332  *
333  * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS
334  * at the *start* of a pathname component.
335  *
336  * If twrp is passed in then smb_fname->twrp is set to that
337  * value, and the @GMT-token part of the filename is removed
338  * and does not change the stored smb_fname->twrp.
339  *
340  */
341
342 NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname,
343                                     uint32_t ucf_flags,
344                                     NTTIME twrp)
345 {
346         char *startp = NULL;
347         char *endp = NULL;
348         char *tmp = NULL;
349         struct tm tm;
350         time_t t;
351         NTTIME nt;
352         NTSTATUS status;
353
354         if (twrp != 0) {
355                 smb_fname->twrp = twrp;
356         }
357
358         if (!(ucf_flags & UCF_GMT_PATHNAME)) {
359                 return NT_STATUS_OK;
360         }
361
362         startp = strchr_m(smb_fname->base_name, '@');
363         if (startp == NULL) {
364                 /* No @ */
365                 return NT_STATUS_OK;
366         }
367
368         startp = strstr_m(startp, "@GMT-");
369         if (startp == NULL) {
370                 /* No @ */
371                 return NT_STATUS_OK;
372         }
373
374         if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
375                 /* the GMT-token does not start a path-component */
376                 return NT_STATUS_OK;
377         }
378
379         endp = strptime(startp, GMT_FORMAT, &tm);
380         if (endp == NULL) {
381                 /* Not a valid timestring. */
382                 return NT_STATUS_OK;
383         }
384
385         if (endp[0] != '\0' && endp[0] != '/') {
386                 /*
387                  * It is not a complete path component, i.e. the path
388                  * component continues after the gmt-token.
389                  */
390                 return NT_STATUS_OK;
391         }
392
393         status = rearrange_snapshot_path(smb_fname, startp, endp);
394         if (!NT_STATUS_IS_OK(status)) {
395                 return status;
396         }
397
398         startp = smb_fname->base_name + GMT_NAME_LEN;
399         if (startp[0] == '/') {
400                 startp++;
401         }
402
403         tmp = talloc_strdup(smb_fname, startp);
404         if (tmp == NULL) {
405                 return NT_STATUS_NO_MEMORY;
406         }
407
408         TALLOC_FREE(smb_fname->base_name);
409         smb_fname->base_name = tmp;
410
411         if (smb_fname->twrp == 0) {
412                 tm.tm_isdst = -1;
413                 t = timegm(&tm);
414                 unix_to_nt_time(&nt, t);
415                 smb_fname->twrp = nt;
416         }
417
418         return NT_STATUS_OK;
419 }
420
421 static bool strnorm(char *s, int case_default)
422 {
423         if (case_default == CASE_UPPER)
424                 return strupper_m(s);
425         else
426                 return strlower_m(s);
427 }
428
429 /*
430  * Utility function to normalize case on an incoming client filename
431  * if required on this connection struct.
432  * Performs an in-place case conversion guaranteed to stay the same size.
433  */
434
435 static NTSTATUS normalize_filename_case(connection_struct *conn,
436                                         char *filename,
437                                         uint32_t ucf_flags)
438 {
439         bool ok;
440
441         if (ucf_flags & UCF_POSIX_PATHNAMES) {
442                 /*
443                  * POSIX never normalizes filename case.
444                  */
445                 return NT_STATUS_OK;
446         }
447         if (!conn->case_sensitive) {
448                 return NT_STATUS_OK;
449         }
450         if (conn->case_preserve) {
451                 return NT_STATUS_OK;
452         }
453         if (conn->short_case_preserve) {
454                 return NT_STATUS_OK;
455         }
456         ok = strnorm(filename, lp_default_case(SNUM(conn)));
457         if (!ok) {
458                 return NT_STATUS_INVALID_PARAMETER;
459         }
460         return NT_STATUS_OK;
461 }
462
463 /****************************************************************************
464 This routine is called to convert names from the dos namespace to unix
465 namespace. It needs to handle any case conversions, mangling, format changes,
466 streams etc.
467
468 We assume that we have already done a chdir() to the right "root" directory
469 for this service.
470
471 Conversion to basic unix format is already done in check_path_syntax().
472
473 Names must be relative to the root of the service - any leading /.  and
474 trailing /'s should have been trimmed by check_path_syntax().
475
476 The function will return an NTSTATUS error if some part of the name except for
477 the last part cannot be resolved, else NT_STATUS_OK.
478
479 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
480 didn't get any fatal errors that should immediately terminate the calling SMB
481 processing whilst resolving.
482
483 If the orig_path was a stream, smb_filename->base_name will point to the base
484 filename, and smb_filename->stream_name will point to the stream name.  If
485 orig_path was not a stream, then smb_filename->stream_name will be NULL.
486
487 On exit from unix_convert, the smb_filename->st stat struct will be populated
488 if the file exists and was found, if not this stat struct will be filled with
489 zeros (and this can be detected by checking for nlinks = 0, which can never be
490 true for any file).
491 ****************************************************************************/
492
493 struct uc_state {
494         TALLOC_CTX *mem_ctx;
495         struct connection_struct *conn;
496         struct smb_filename *smb_fname;
497         const char *orig_path;
498         uint32_t ucf_flags;
499         char *name;
500         char *end;
501         char *dirpath;
502         char *stream;
503         bool component_was_mangled;
504         bool posix_pathnames;
505         bool done;
506         bool case_sensitive;
507         bool case_preserve;
508         bool short_case_preserve;
509 };
510
511 static NTSTATUS unix_convert_step_search_fail(struct uc_state *state)
512 {
513         char *unmangled;
514
515         if (state->end) {
516                 /*
517                  * An intermediate part of the name
518                  * can't be found.
519                  */
520                 DBG_DEBUG("Intermediate [%s] missing\n",
521                           state->name);
522                 *state->end = '/';
523
524                 /*
525                  * We need to return the fact that the
526                  * intermediate name resolution failed.
527                  * This is used to return an error of
528                  * ERRbadpath rather than ERRbadfile.
529                  * Some Windows applications depend on
530                  * the difference between these two
531                  * errors.
532                  */
533
534                 /*
535                  * ENOENT, ENOTDIR and ELOOP all map
536                  * to NT_STATUS_OBJECT_PATH_NOT_FOUND
537                  * in the filename walk.
538                  */
539
540                 if (errno == ENOENT ||
541                     errno == ENOTDIR ||
542                     errno == ELOOP)
543                 {
544                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
545                 }
546                 return map_nt_error_from_unix(errno);
547         }
548
549         /*
550          * ENOENT/EACCESS are the only valid errors
551          * here.
552          */
553
554         if (errno == EACCES) {
555                 if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
556                         /*
557                          * Could be a symlink pointing to
558                          * a directory outside the share
559                          * to which we don't have access.
560                          * If so, we need to know that here
561                          * so we can return the correct error code.
562                          * check_name() is never called if we
563                          * error out of filename_convert().
564                          */
565                         int ret;
566                         NTSTATUS status;
567                         struct smb_filename dname = (struct smb_filename) {
568                                         .base_name = state->dirpath,
569                                         .twrp = state->smb_fname->twrp,
570                         };
571
572                         /* handle null paths */
573                         if ((dname.base_name == NULL) ||
574                                         (dname.base_name[0] == '\0')) {
575                                 return NT_STATUS_ACCESS_DENIED;
576                         }
577                         ret = SMB_VFS_LSTAT(state->conn, &dname);
578                         if (ret != 0) {
579                                 return NT_STATUS_ACCESS_DENIED;
580                         }
581                         if (!S_ISLNK(dname.st.st_ex_mode)) {
582                                 return NT_STATUS_ACCESS_DENIED;
583                         }
584                         status = check_name(state->conn, &dname);
585                         if (!NT_STATUS_IS_OK(status)) {
586                                 /* We know this is an intermediate path. */
587                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
588                         }
589                         return NT_STATUS_ACCESS_DENIED;
590                 } else {
591                         /*
592                          * This is the dropbox
593                          * behaviour. A dropbox is a
594                          * directory with only -wx
595                          * permissions, so
596                          * get_real_filename fails
597                          * with EACCESS, it needs to
598                          * list the directory. We
599                          * nevertheless want to allow
600                          * users creating a file.
601                          */
602                         errno = 0;
603                 }
604         }
605
606         if ((errno != 0) && (errno != ENOENT)) {
607                 /*
608                  * ENOTDIR and ELOOP both map to
609                  * NT_STATUS_OBJECT_PATH_NOT_FOUND
610                  * in the filename walk.
611                  */
612                 if (errno == ENOTDIR || errno == ELOOP) {
613                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
614                 }
615                 return map_nt_error_from_unix(errno);
616         }
617
618         /*
619          * POSIX pathnames must never call into mangling.
620          */
621         if (state->posix_pathnames) {
622                 goto done;
623         }
624
625         /*
626          * Just the last part of the name doesn't exist.
627          * We need to strupper() or strlower() it as
628          * this conversion may be used for file creation
629          * purposes. Fix inspired by
630          * Thomas Neumann <t.neumann@iku-ag.de>.
631          */
632         if (!state->case_preserve ||
633             (mangle_is_8_3(state->name, false,
634                            state->conn->params) &&
635              !state->short_case_preserve)) {
636                 if (!strnorm(state->name,
637                              lp_default_case(SNUM(state->conn)))) {
638                         DBG_DEBUG("strnorm %s failed\n",
639                                   state->name);
640                         return NT_STATUS_INVALID_PARAMETER;
641                 }
642         }
643
644         /*
645          * check on the mangled stack to see if we can
646          * recover the base of the filename.
647          */
648
649         if (mangle_is_mangled(state->name, state->conn->params)
650             && mangle_lookup_name_from_8_3(state->mem_ctx,
651                                            state->name,
652                                            &unmangled,
653                                            state->conn->params)) {
654                 char *tmp;
655                 size_t name_ofs =
656                         state->name - state->smb_fname->base_name;
657
658                 if (!ISDOT(state->dirpath)) {
659                         tmp = talloc_asprintf(
660                                 state->smb_fname, "%s/%s",
661                                 state->dirpath, unmangled);
662                         TALLOC_FREE(unmangled);
663                 }
664                 else {
665                         tmp = unmangled;
666                 }
667                 if (tmp == NULL) {
668                         DBG_ERR("talloc failed\n");
669                         return NT_STATUS_NO_MEMORY;
670                 }
671                 TALLOC_FREE(state->smb_fname->base_name);
672                 state->smb_fname->base_name = tmp;
673                 state->name =
674                         state->smb_fname->base_name + name_ofs;
675                 state->end = state->name + strlen(state->name);
676         }
677
678   done:
679
680         DBG_DEBUG("New file [%s]\n", state->name);
681         state->done = true;
682         return NT_STATUS_OK;
683 }
684
685 static NTSTATUS unix_convert_step_stat(struct uc_state *state)
686 {
687         struct smb_filename dname;
688         char dot[2] = ".";
689         char *found_name = NULL;
690         int ret;
691
692         /*
693          * Check if the name exists up to this point.
694          */
695
696         DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname));
697
698         ret = vfs_stat(state->conn, state->smb_fname);
699         if (ret == 0) {
700                 /*
701                  * It exists. it must either be a directory or this must
702                  * be the last part of the path for it to be OK.
703                  */
704                 if (state->end && !S_ISDIR(state->smb_fname->st.st_ex_mode)) {
705                         /*
706                          * An intermediate part of the name isn't
707                          * a directory.
708                          */
709                         DBG_DEBUG("Not a dir [%s]\n", state->name);
710                         *state->end = '/';
711                         /*
712                          * We need to return the fact that the
713                          * intermediate name resolution failed. This
714                          * is used to return an error of ERRbadpath
715                          * rather than ERRbadfile. Some Windows
716                          * applications depend on the difference between
717                          * these two errors.
718                          */
719                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
720                 }
721                 return NT_STATUS_OK;
722         }
723
724         /* Stat failed - ensure we don't use it. */
725         SET_STAT_INVALID(state->smb_fname->st);
726
727         if (state->posix_pathnames) {
728                 /*
729                  * For posix_pathnames, we're done.
730                  * Don't blunder into the
731                  * get_real_filename() codepath as they may
732                  * be doing case insensitive lookups. So when
733                  * creating a new POSIX directory Foo they might
734                  * match on name foo.
735                  *
736                  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13803
737                  */
738                 if (state->end != NULL) {
739                         const char *morepath = NULL;
740                         /*
741                          * If this is intermediate we must
742                          * restore the full path.
743                          */
744                         *state->end = '/';
745                         /*
746                          * If there are any more components
747                          * after the failed LSTAT we cannot
748                          * continue.
749                          */
750                         morepath = strchr(state->end + 1, '/');
751                         if (morepath != NULL) {
752                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
753                         }
754                 }
755                 if (errno == ENOENT) {
756                         /* New file or directory. */
757                         state->done = true;
758                         return NT_STATUS_OK;
759                 }
760                 if ((errno == EACCES) &&
761                     (state->ucf_flags & UCF_PREP_CREATEFILE)) {
762                         /* POSIX Dropbox case. */
763                         errno = 0;
764                         state->done = true;
765                         return NT_STATUS_OK;
766                 }
767                 return map_nt_error_from_unix(errno);
768         }
769
770         /*
771          * Reset errno so we can detect
772          * directory open errors.
773          */
774         errno = 0;
775
776         /*
777          * Try to find this part of the path in the directory.
778          */
779
780         dname = (struct smb_filename) {
781                 .base_name = state->dirpath,
782                 .twrp = state->smb_fname->twrp,
783         };
784
785         /* handle null paths */
786         if ((dname.base_name == NULL) || (dname.base_name[0] == '\0')) {
787                 dname.base_name = dot;
788         }
789
790         ret = get_real_filename(state->conn,
791                                 &dname,
792                                 state->name,
793                                 talloc_tos(),
794                                 &found_name);
795         if (ret != 0) {
796                 return unix_convert_step_search_fail(state);
797         }
798
799         /*
800          * Restore the rest of the string. If the string was
801          * mangled the size may have changed.
802          */
803         if (state->end) {
804                 char *tmp;
805                 size_t name_ofs =
806                         state->name - state->smb_fname->base_name;
807
808                 if (!ISDOT(state->dirpath)) {
809                         tmp = talloc_asprintf(state->smb_fname,
810                                               "%s/%s/%s", state->dirpath,
811                                               found_name, state->end+1);
812                 }
813                 else {
814                         tmp = talloc_asprintf(state->smb_fname,
815                                               "%s/%s", found_name,
816                                               state->end+1);
817                 }
818                 if (tmp == NULL) {
819                         DBG_ERR("talloc_asprintf failed\n");
820                         return NT_STATUS_NO_MEMORY;
821                 }
822                 TALLOC_FREE(state->smb_fname->base_name);
823                 state->smb_fname->base_name = tmp;
824                 state->name = state->smb_fname->base_name + name_ofs;
825                 state->end = state->name + strlen(found_name);
826                 *state->end = '\0';
827         } else {
828                 char *tmp;
829                 size_t name_ofs =
830                         state->name - state->smb_fname->base_name;
831
832                 if (!ISDOT(state->dirpath)) {
833                         tmp = talloc_asprintf(state->smb_fname,
834                                               "%s/%s", state->dirpath,
835                                               found_name);
836                 } else {
837                         tmp = talloc_strdup(state->smb_fname,
838                                             found_name);
839                 }
840                 if (tmp == NULL) {
841                         DBG_ERR("talloc failed\n");
842                         return NT_STATUS_NO_MEMORY;
843                 }
844                 TALLOC_FREE(state->smb_fname->base_name);
845                 state->smb_fname->base_name = tmp;
846                 state->name = state->smb_fname->base_name + name_ofs;
847
848                 /*
849                  * We just scanned for, and found the end of
850                  * the path. We must return a valid stat struct
851                  * if it exists. JRA.
852                  */
853
854                 ret = vfs_stat(state->conn, state->smb_fname);
855                 if (ret != 0) {
856                         SET_STAT_INVALID(state->smb_fname->st);
857                 }
858         }
859
860         TALLOC_FREE(found_name);
861         return NT_STATUS_OK;
862 }
863
864 static NTSTATUS unix_convert_step(struct uc_state *state)
865 {
866         NTSTATUS status;
867
868         /*
869          * Pinpoint the end of this section of the filename.
870          */
871         /* mb safe. '/' can't be in any encoded char. */
872         state->end = strchr(state->name, '/');
873
874         /*
875          * Chop the name at this point.
876          */
877         if (state->end != NULL) {
878                 *state->end = 0;
879         }
880
881         DBG_DEBUG("dirpath [%s] name [%s]\n", state->dirpath, state->name);
882
883         /* The name cannot have a component of "." */
884
885         if (ISDOT(state->name)) {
886                 if (state->end == NULL)  {
887                         /* Error code at the end of a pathname. */
888                         return NT_STATUS_OBJECT_NAME_INVALID;
889                 }
890                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
891         }
892
893         status = unix_convert_step_stat(state);
894         if (!NT_STATUS_IS_OK(status)) {
895                 return status;
896         }
897         if (state->done) {
898                 return NT_STATUS_OK;
899         }
900
901         /*
902          * Add to the dirpath that we have resolved so far.
903          */
904
905         if (!ISDOT(state->dirpath)) {
906                 char *tmp = talloc_asprintf(state->mem_ctx,
907                                             "%s/%s", state->dirpath, state->name);
908                 if (!tmp) {
909                         DBG_ERR("talloc_asprintf failed\n");
910                         return NT_STATUS_NO_MEMORY;
911                 }
912                 TALLOC_FREE(state->dirpath);
913                 state->dirpath = tmp;
914         }
915         else {
916                 TALLOC_FREE(state->dirpath);
917                 if (!(state->dirpath = talloc_strdup(state->mem_ctx,state->name))) {
918                         DBG_ERR("talloc_strdup failed\n");
919                         return NT_STATUS_NO_MEMORY;
920                 }
921         }
922
923         /*
924          * Cache the dirpath thus far. Don't cache a name with mangled
925          * components as this can change the size.
926          */
927         if(!state->component_was_mangled) {
928                 stat_cache_add(state->orig_path,
929                                state->dirpath,
930                                state->smb_fname->twrp,
931                                state->case_sensitive);
932         }
933
934         /*
935          * Restore the / that we wiped out earlier.
936          */
937         if (state->end != NULL) {
938                 *state->end = '/';
939         }
940
941         return NT_STATUS_OK;
942 }
943
944 NTSTATUS unix_convert(TALLOC_CTX *mem_ctx,
945                       connection_struct *conn,
946                       const char *orig_path,
947                       NTTIME twrp,
948                       struct smb_filename **smb_fname_out,
949                       uint32_t ucf_flags)
950 {
951         struct uc_state uc_state;
952         struct uc_state *state = &uc_state;
953         NTSTATUS status;
954         int ret = -1;
955         int parent_stat_errno = 0;
956
957         *state = (struct uc_state) {
958                 .mem_ctx = mem_ctx,
959                 .conn = conn,
960                 .orig_path = orig_path,
961                 .ucf_flags = ucf_flags,
962                 .posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES),
963                 .case_sensitive = conn->case_sensitive,
964                 .case_preserve = conn->case_preserve,
965                 .short_case_preserve = conn->short_case_preserve,
966         };
967
968         *smb_fname_out = NULL;
969
970         if (state->posix_pathnames) {
971                 /* POSIX means ignore case settings on share. */
972                 state->case_sensitive = true;
973                 state->case_preserve = true;
974                 state->short_case_preserve = true;
975         }
976
977         state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename);
978         if (state->smb_fname == NULL) {
979                 return NT_STATUS_NO_MEMORY;
980         }
981
982         if (state->conn->printer) {
983                 /* we don't ever use the filenames on a printer share as a
984                         filename - so don't convert them */
985                 state->smb_fname->base_name = talloc_strdup(
986                         state->smb_fname, state->orig_path);
987                 if (state->smb_fname->base_name == NULL) {
988                         status = NT_STATUS_NO_MEMORY;
989                         goto err;
990                 }
991                 goto done;
992         }
993
994         state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
995
996         DBG_DEBUG("Called on file [%s]\n", state->orig_path);
997
998         if (state->orig_path[0] == '/') {
999                 DBG_ERR("Path [%s] starts with '/'\n", state->orig_path);
1000                 return NT_STATUS_OBJECT_NAME_INVALID;
1001         }
1002
1003         /* Start with the full orig_path as given by the caller. */
1004         state->smb_fname->base_name = talloc_strdup(
1005                 state->smb_fname, state->orig_path);
1006         if (state->smb_fname->base_name == NULL) {
1007                 DBG_ERR("talloc_strdup failed\n");
1008                 status = NT_STATUS_NO_MEMORY;
1009                 goto err;
1010         }
1011
1012         /* Canonicalize any @GMT- paths. */
1013         status = canonicalize_snapshot_path(state->smb_fname, ucf_flags, twrp);
1014         if (!NT_STATUS_IS_OK(status)) {
1015                 goto err;
1016         }
1017
1018         /*
1019          * If we trimmed down to a single '\0' character
1020          * then we should use the "." directory to avoid
1021          * searching the cache, but not if we are in a
1022          * printing share.
1023          * As we know this is valid we can return true here.
1024          */
1025
1026         if (state->smb_fname->base_name[0] == '\0') {
1027                 state->smb_fname->base_name = talloc_strdup(state->smb_fname, ".");
1028                 if (state->smb_fname->base_name == NULL) {
1029                         status = NT_STATUS_NO_MEMORY;
1030                         goto err;
1031                 }
1032                 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1033                         status = map_nt_error_from_unix(errno);
1034                         goto err;
1035                 }
1036                 DBG_DEBUG("conversion finished [] -> [%s]\n",
1037                           state->smb_fname->base_name);
1038                 goto done;
1039         }
1040
1041         if (state->orig_path[0] == '.' && (state->orig_path[1] == '/' ||
1042                                 state->orig_path[1] == '\0')) {
1043                 /* Start of pathname can't be "." only. */
1044                 if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') {
1045                         status = NT_STATUS_OBJECT_NAME_INVALID;
1046                 } else {
1047                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1048                 }
1049                 goto err;
1050         }
1051
1052         /*
1053          * Large directory fix normalization. If we're case sensitive, and
1054          * the case preserving parameters are set to "no", normalize the case of
1055          * the incoming filename from the client WHETHER IT EXISTS OR NOT !
1056          * This is in conflict with the current (3.0.20) man page, but is
1057          * what people expect from the "large directory howto". I'll update
1058          * the man page. Thanks to jht@samba.org for finding this. JRA.
1059          */
1060
1061         status = normalize_filename_case(state->conn,
1062                                          state->smb_fname->base_name,
1063                                          ucf_flags);
1064         if (!NT_STATUS_IS_OK(status)) {
1065                 DBG_ERR("normalize_filename_case %s failed\n",
1066                                 state->smb_fname->base_name);
1067                 goto err;
1068         }
1069
1070         /*
1071          * Strip off the stream, and add it back when we're done with the
1072          * base_name.
1073          */
1074         if (!state->posix_pathnames) {
1075                 state->stream = strchr_m(state->smb_fname->base_name, ':');
1076
1077                 if (state->stream != NULL) {
1078                         char *tmp = talloc_strdup(state->smb_fname, state->stream);
1079                         if (tmp == NULL) {
1080                                 status = NT_STATUS_NO_MEMORY;
1081                                 goto err;
1082                         }
1083                         /*
1084                          * Since this is actually pointing into
1085                          * smb_fname->base_name this truncates base_name.
1086                          */
1087                         *state->stream = '\0';
1088                         state->stream = tmp;
1089
1090                         if (state->smb_fname->base_name[0] == '\0') {
1091                                 /*
1092                                  * orig_name was just a stream name.
1093                                  * This is a stream on the root of
1094                                  * the share. Replace base_name with
1095                                  * a "."
1096                                  */
1097                                 state->smb_fname->base_name =
1098                                         talloc_strdup(state->smb_fname, ".");
1099                                 if (state->smb_fname->base_name == NULL) {
1100                                         status = NT_STATUS_NO_MEMORY;
1101                                         goto err;
1102                                 }
1103                                 if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) {
1104                                         status = map_nt_error_from_unix(errno);
1105                                         goto err;
1106                                 }
1107                                 /* dirpath must exist. */
1108                                 state->dirpath = talloc_strdup(state->mem_ctx,".");
1109                                 if (state->dirpath == NULL) {
1110                                         status = NT_STATUS_NO_MEMORY;
1111                                         goto err;
1112                                 }
1113                                 DBG_INFO("conversion finished [%s] -> [%s]\n",
1114                                          state->orig_path,
1115                                          state->smb_fname->base_name);
1116                                 goto done;
1117                         }
1118                 }
1119         }
1120
1121         state->name = state->smb_fname->base_name;
1122
1123         /*
1124          * If we're providing case insensitive semantics or
1125          * the underlying filesystem is case insensitive,
1126          * then a case-normalized hit in the stat-cache is
1127          * authoritative. JRA.
1128          *
1129          * Note: We're only checking base_name.  The stream_name will be
1130          * added and verified in build_stream_path().
1131          */
1132
1133         if (!state->case_sensitive ||
1134             !(state->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH))
1135         {
1136                 bool found;
1137
1138                 found = stat_cache_lookup(state->conn,
1139                                           &state->smb_fname->base_name,
1140                                           &state->dirpath,
1141                                           &state->name,
1142                                           state->smb_fname->twrp,
1143                                           &state->smb_fname->st);
1144                 if (found) {
1145                         goto done;
1146                 }
1147         }
1148
1149         /*
1150          * Make sure "dirpath" is an allocated string, we use this for
1151          * building the directories with talloc_asprintf and free it.
1152          */
1153
1154         if (state->dirpath == NULL) {
1155                 state->dirpath = talloc_strdup(state->mem_ctx,".");
1156                 if (state->dirpath == NULL) {
1157                         DBG_ERR("talloc_strdup failed\n");
1158                         status = NT_STATUS_NO_MEMORY;
1159                         goto err;
1160                 }
1161         }
1162
1163         /*
1164          * If we have a wildcard we must walk the path to
1165          * find where the error is, even if case sensitive
1166          * is true.
1167          */
1168
1169         if (!state->posix_pathnames) {
1170                 /* POSIX pathnames have no wildcards. */
1171                 bool name_has_wildcard = ms_has_wild(state->smb_fname->base_name);
1172                 if (name_has_wildcard) {
1173                         /* Wildcard not valid anywhere. */
1174                         status = NT_STATUS_OBJECT_NAME_INVALID;
1175                         goto fail;
1176                 }
1177         }
1178
1179         DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n",
1180                   state->smb_fname->base_name, state->dirpath, state->name);
1181
1182         /*
1183          * stat the name - if it exists then we can add the stream back (if
1184          * there was one) and be done!
1185          */
1186
1187         ret = vfs_stat(state->conn, state->smb_fname);
1188         if (ret == 0) {
1189                 status = check_for_dot_component(state->smb_fname);
1190                 if (!NT_STATUS_IS_OK(status)) {
1191                         goto fail;
1192                 }
1193                 /* Add the path (not including the stream) to the cache. */
1194                 stat_cache_add(state->orig_path,
1195                                state->smb_fname->base_name,
1196                                state->smb_fname->twrp,
1197                                state->case_sensitive);
1198                 DBG_DEBUG("Conversion of base_name finished "
1199                           "[%s] -> [%s]\n",
1200                           state->orig_path, state->smb_fname->base_name);
1201                 goto done;
1202         }
1203
1204         /* Stat failed - ensure we don't use it. */
1205         SET_STAT_INVALID(state->smb_fname->st);
1206
1207         /*
1208          * Note: we must continue processing a path if we get EACCES
1209          * from stat. With NFS4 permissions the file might be lacking
1210          * READ_ATTR, but if the parent has LIST permissions we can
1211          * resolve the path in the path traversal loop down below.
1212          */
1213
1214         if (errno == ENOENT) {
1215                 /* Optimization when creating a new file - only
1216                    the last component doesn't exist.
1217                    NOTE : check_parent_exists() doesn't preserve errno.
1218                 */
1219                 int saved_errno = errno;
1220                 status = check_parent_exists(state->mem_ctx,
1221                                         state->conn,
1222                                         state->posix_pathnames,
1223                                         state->smb_fname,
1224                                         &state->dirpath,
1225                                         &state->name,
1226                                         &parent_stat_errno);
1227                 errno = saved_errno;
1228                 if (!NT_STATUS_IS_OK(status)) {
1229                         goto fail;
1230                 }
1231         }
1232
1233         /*
1234          * A special case - if we don't have any wildcards or mangling chars and are case
1235          * sensitive or the underlying filesystem is case insensitive then searching
1236          * won't help.
1237          *
1238          * NB. As POSIX sets state->case_sensitive as
1239          * true we will never call into mangle_is_mangled() here.
1240          */
1241
1242         if ((state->case_sensitive || !(state->conn->fs_capabilities &
1243                                 FILE_CASE_SENSITIVE_SEARCH)) &&
1244                         !mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) {
1245
1246                 status = check_for_dot_component(state->smb_fname);
1247                 if (!NT_STATUS_IS_OK(status)) {
1248                         goto fail;
1249                 }
1250
1251                 /*
1252                  * The stat failed. Could be ok as it could be
1253                  * a new file.
1254                  */
1255
1256                 if (errno == ENOTDIR || errno == ELOOP) {
1257                         status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1258                         goto fail;
1259                 } else if (errno == ENOENT) {
1260                         /*
1261                          * Was it a missing last component ?
1262                          * or a missing intermediate component ?
1263                          *
1264                          * Optimization.
1265                          *
1266                          * For this code path we can guarantee that
1267                          * we have gone through check_parent_exists()
1268                          * and it returned NT_STATUS_OK.
1269                          *
1270                          * Either there was no parent component (".")
1271                          * parent_stat_errno == 0 and we have a missing
1272                          * last component here.
1273                          *
1274                          * OR check_parent_exists() called STAT/LSTAT
1275                          * and if it failed parent_stat_errno has been
1276                          * set telling us if the parent existed or not.
1277                          *
1278                          * Either way we can avoid another STAT/LSTAT
1279                          * system call on the parent here.
1280                          */
1281                         if (parent_stat_errno == ENOTDIR ||
1282                                         parent_stat_errno == ENOENT ||
1283                                         parent_stat_errno == ELOOP) {
1284                                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1285                                 goto fail;
1286                         }
1287
1288                         /*
1289                          * Missing last component is ok - new file.
1290                          * Also deal with permission denied elsewhere.
1291                          * Just drop out to done.
1292                          */
1293                         goto done;
1294                 }
1295         }
1296
1297         /*
1298          * is_mangled() was changed to look at an entire pathname, not
1299          * just a component. JRA.
1300          */
1301
1302         if (state->posix_pathnames) {
1303                 /*
1304                  * POSIX names are never mangled and we must not
1305                  * call into mangling functions.
1306                  */
1307                 state->component_was_mangled = false;
1308         } else if (mangle_is_mangled(state->name, state->conn->params)) {
1309                 state->component_was_mangled = true;
1310         }
1311
1312         /*
1313          * Now we need to recursively match the name against the real
1314          * directory structure.
1315          */
1316
1317         /*
1318          * Match each part of the path name separately, trying the names
1319          * as is first, then trying to scan the directory for matching names.
1320          */
1321
1322         for (; state->name ; state->name = (state->end ? state->end + 1:(char *)NULL)) {
1323                 status = unix_convert_step(state);
1324                 if (!NT_STATUS_IS_OK(status)) {
1325                         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
1326                                 goto err;
1327                         }
1328                         goto fail;
1329                 }
1330                 if (state->done) {
1331                         goto done;
1332                 }
1333         }
1334
1335         /*
1336          * Cache the full path. Don't cache a name with mangled or wildcard
1337          * components as this can change the size.
1338          */
1339
1340         if(!state->component_was_mangled) {
1341                 stat_cache_add(state->orig_path,
1342                                state->smb_fname->base_name,
1343                                state->smb_fname->twrp,
1344                                state->case_sensitive);
1345         }
1346
1347         /*
1348          * The name has been resolved.
1349          */
1350
1351  done:
1352         /* Add back the stream if one was stripped off originally. */
1353         if (state->stream != NULL) {
1354                 state->smb_fname->stream_name = state->stream;
1355
1356                 /* Check path now that the base_name has been converted. */
1357                 status = build_stream_path(state->mem_ctx, state->conn, state->smb_fname);
1358                 if (!NT_STATUS_IS_OK(status)) {
1359                         goto fail;
1360                 }
1361         }
1362
1363         DBG_DEBUG("Conversion finished [%s] -> [%s]\n",
1364                    state->orig_path, smb_fname_str_dbg(state->smb_fname));
1365
1366         TALLOC_FREE(state->dirpath);
1367         *smb_fname_out = state->smb_fname;
1368         return NT_STATUS_OK;
1369  fail:
1370         DBG_DEBUG("Conversion failed: dirpath [%s] name [%s]\n",
1371                   state->dirpath, state->name);
1372         if ((state->dirpath != NULL) && !ISDOT(state->dirpath)) {
1373                 state->smb_fname->base_name = talloc_asprintf(
1374                         state->smb_fname,
1375                         "%s/%s",
1376                         state->dirpath,
1377                         state->name);
1378         } else {
1379                 state->smb_fname->base_name = talloc_strdup(
1380                         state->smb_fname, state->name);
1381         }
1382         if (state->smb_fname->base_name == NULL) {
1383                 DBG_ERR("talloc_asprintf failed\n");
1384                 status = NT_STATUS_NO_MEMORY;
1385                 goto err;
1386         }
1387
1388         *smb_fname_out = state->smb_fname;
1389         TALLOC_FREE(state->dirpath);
1390         return status;
1391  err:
1392         TALLOC_FREE(state->smb_fname);
1393         return status;
1394 }
1395
1396 /****************************************************************************
1397  Ensure a path is not vetoed.
1398 ****************************************************************************/
1399
1400 static NTSTATUS check_veto_path(connection_struct *conn,
1401                         const struct smb_filename *smb_fname)
1402 {
1403         const char *name = smb_fname->base_name;
1404
1405         if (IS_VETO_PATH(conn, name))  {
1406                 /* Is it not dot or dot dot. */
1407                 if (!(ISDOT(name) || ISDOTDOT(name))) {
1408                         DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1409                                                 name));
1410                         return map_nt_error_from_unix(ENOENT);
1411                 }
1412         }
1413         return NT_STATUS_OK;
1414 }
1415
1416 /****************************************************************************
1417  Check a filename - possibly calling check_reduced_name.
1418  This is called by every routine before it allows an operation on a filename.
1419  It does any final confirmation necessary to ensure that the filename is
1420  a valid one for the user to access.
1421 ****************************************************************************/
1422
1423 static NTSTATUS check_name(connection_struct *conn,
1424                         const struct smb_filename *smb_fname)
1425 {
1426         NTSTATUS status = check_veto_path(conn, smb_fname);
1427
1428         if (!NT_STATUS_IS_OK(status)) {
1429                 return status;
1430         }
1431
1432         if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1433                 status = check_reduced_name(conn, NULL, smb_fname);
1434                 if (!NT_STATUS_IS_OK(status)) {
1435                         DEBUG(5,("check_name: name %s failed with %s\n",
1436                                         smb_fname->base_name,
1437                                         nt_errstr(status)));
1438                         return status;
1439                 }
1440         }
1441
1442         return NT_STATUS_OK;
1443 }
1444
1445 /****************************************************************************
1446  Check if two filenames are equal.
1447  This needs to be careful about whether we are case sensitive.
1448 ****************************************************************************/
1449
1450 static bool fname_equal(const char *name1, const char *name2,
1451                 bool case_sensitive)
1452 {
1453         /* Normal filename handling */
1454         if (case_sensitive) {
1455                 return(strcmp(name1,name2) == 0);
1456         }
1457
1458         return(strequal(name1,name2));
1459 }
1460
1461 static bool sname_equal(const char *name1, const char *name2,
1462                 bool case_sensitive)
1463 {
1464         bool match;
1465         const char *s1 = NULL;
1466         const char *s2 = NULL;
1467         size_t n1;
1468         size_t n2;
1469         const char *e1 = NULL;
1470         const char *e2 = NULL;
1471         char *c1 = NULL;
1472         char *c2 = NULL;
1473
1474         match = fname_equal(name1, name2, case_sensitive);
1475         if (match) {
1476                 return true;
1477         }
1478
1479         if (name1[0] != ':') {
1480                 return false;
1481         }
1482         if (name2[0] != ':') {
1483                 return false;
1484         }
1485         s1 = &name1[1];
1486         e1 = strchr(s1, ':');
1487         if (e1 == NULL) {
1488                 n1 = strlen(s1);
1489         } else {
1490                 n1 = PTR_DIFF(e1, s1);
1491         }
1492         s2 = &name2[1];
1493         e2 = strchr(s2, ':');
1494         if (e2 == NULL) {
1495                 n2 = strlen(s2);
1496         } else {
1497                 n2 = PTR_DIFF(e2, s2);
1498         }
1499
1500         /* Normal filename handling */
1501         if (case_sensitive) {
1502                 return (strncmp(s1, s2, n1) == 0);
1503         }
1504
1505         /*
1506          * We can't use strnequal() here
1507          * as it takes the number of codepoints
1508          * and not the number of bytes.
1509          *
1510          * So we make a copy before calling
1511          * strequal().
1512          *
1513          * Note that we TALLOC_FREE() in reverse order
1514          * in order to avoid memory fragmentation.
1515          */
1516
1517         c1 = talloc_strndup(talloc_tos(), s1, n1);
1518         c2 = talloc_strndup(talloc_tos(), s2, n2);
1519         if (c1 == NULL || c2 == NULL) {
1520                 TALLOC_FREE(c2);
1521                 TALLOC_FREE(c1);
1522                 return (strncmp(s1, s2, n1) == 0);
1523         }
1524
1525         match = strequal(c1, c2);
1526         TALLOC_FREE(c2);
1527         TALLOC_FREE(c1);
1528         return match;
1529 }
1530
1531 /****************************************************************************
1532  Scan a directory to find a filename, matching without case sensitivity.
1533  If the name looks like a mangled name then try via the mangling functions
1534 ****************************************************************************/
1535
1536 int get_real_filename_full_scan(connection_struct *conn,
1537                                 const char *path,
1538                                 const char *name,
1539                                 bool mangled,
1540                                 TALLOC_CTX *mem_ctx,
1541                                 char **found_name)
1542 {
1543         struct smb_Dir *cur_dir;
1544         const char *dname = NULL;
1545         char *talloced = NULL;
1546         char *unmangled_name = NULL;
1547         long curpos;
1548         struct smb_filename *smb_fname = NULL;
1549
1550         /* handle null paths */
1551         if ((path == NULL) || (*path == 0)) {
1552                 path = ".";
1553         }
1554
1555         /* If we have a case-sensitive filesystem, it doesn't do us any
1556          * good to search for a name. If a case variation of the name was
1557          * there, then the original stat(2) would have found it.
1558          */
1559         if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1560                 errno = ENOENT;
1561                 return -1;
1562         }
1563
1564         /*
1565          * The incoming name can be mangled, and if we de-mangle it
1566          * here it will not compare correctly against the filename (name2)
1567          * read from the directory and then mangled by the name_to_8_3()
1568          * call. We need to mangle both names or neither.
1569          * (JRA).
1570          *
1571          * Fix for bug found by Dina Fine. If in case sensitive mode then
1572          * the mangle cache is no good (3 letter extension could be wrong
1573          * case - so don't demangle in this case - leave as mangled and
1574          * allow the mangling of the directory entry read (which is done
1575          * case insensitively) to match instead. This will lead to more
1576          * false positive matches but we fail completely without it. JRA.
1577          */
1578
1579         if (mangled && !conn->case_sensitive) {
1580                 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1581                                                        &unmangled_name,
1582                                                        conn->params);
1583                 if (!mangled) {
1584                         /* Name is now unmangled. */
1585                         name = unmangled_name;
1586                 }
1587         }
1588
1589         smb_fname = synthetic_smb_fname(talloc_tos(),
1590                                         path,
1591                                         NULL,
1592                                         NULL,
1593                                         0,
1594                                         0);
1595         if (smb_fname == NULL) {
1596                 TALLOC_FREE(unmangled_name);
1597                 return -1;
1598         }
1599
1600         /* open the directory */
1601         if (!(cur_dir = OpenDir(talloc_tos(), conn, smb_fname, NULL, 0))) {
1602                 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1603                 TALLOC_FREE(unmangled_name);
1604                 TALLOC_FREE(smb_fname);
1605                 return -1;
1606         }
1607
1608         TALLOC_FREE(smb_fname);
1609
1610         /* now scan for matching names */
1611         curpos = 0;
1612         while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1613
1614                 /* Is it dot or dot dot. */
1615                 if (ISDOT(dname) || ISDOTDOT(dname)) {
1616                         TALLOC_FREE(talloced);
1617                         continue;
1618                 }
1619
1620                 /*
1621                  * At this point dname is the unmangled name.
1622                  * name is either mangled or not, depending on the state
1623                  * of the "mangled" variable. JRA.
1624                  */
1625
1626                 /*
1627                  * Check mangled name against mangled name, or unmangled name
1628                  * against unmangled name.
1629                  */
1630
1631                 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1632                         fname_equal(name, dname, conn->case_sensitive)) {
1633                         /* we've found the file, change it's name and return */
1634                         *found_name = talloc_strdup(mem_ctx, dname);
1635                         TALLOC_FREE(unmangled_name);
1636                         TALLOC_FREE(cur_dir);
1637                         if (!*found_name) {
1638                                 errno = ENOMEM;
1639                                 TALLOC_FREE(talloced);
1640                                 return -1;
1641                         }
1642                         TALLOC_FREE(talloced);
1643                         return 0;
1644                 }
1645                 TALLOC_FREE(talloced);
1646         }
1647
1648         TALLOC_FREE(unmangled_name);
1649         TALLOC_FREE(cur_dir);
1650         errno = ENOENT;
1651         return -1;
1652 }
1653
1654 /****************************************************************************
1655  Wrapper around the vfs get_real_filename and the full directory scan
1656  fallback.
1657 ****************************************************************************/
1658
1659 static int get_real_filename(connection_struct *conn,
1660                              struct smb_filename *path,
1661                              const char *name,
1662                              TALLOC_CTX *mem_ctx,
1663                              char **found_name)
1664 {
1665         int ret;
1666         bool mangled;
1667
1668         mangled = mangle_is_mangled(name, conn->params);
1669
1670         if (mangled) {
1671                 return get_real_filename_full_scan(conn,
1672                                                    path->base_name,
1673                                                    name,
1674                                                    mangled,
1675                                                    mem_ctx,
1676                                                    found_name);
1677         }
1678
1679         /* Try the vfs first to take advantage of case-insensitive stat. */
1680         ret = SMB_VFS_GET_REAL_FILENAME(conn,
1681                                         path,
1682                                         name,
1683                                         mem_ctx,
1684                                         found_name);
1685
1686         /*
1687          * If the case-insensitive stat was successful, or returned an error
1688          * other than EOPNOTSUPP then there is no need to fall back on the
1689          * full directory scan.
1690          */
1691         if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1692                 return ret;
1693         }
1694
1695         return get_real_filename_full_scan(conn,
1696                                            path->base_name,
1697                                            name,
1698                                            mangled,
1699                                            mem_ctx,
1700                                            found_name);
1701 }
1702
1703 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1704                                   connection_struct *conn,
1705                                   struct smb_filename *smb_fname)
1706 {
1707         NTSTATUS status;
1708         unsigned int i, num_streams = 0;
1709         struct stream_struct *streams = NULL;
1710         struct smb_filename *pathref = NULL;
1711
1712         if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1713                 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1714                 return NT_STATUS_OK;
1715         }
1716
1717         if (errno != ENOENT) {
1718                 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1719                 status = map_nt_error_from_unix(errno);
1720                 goto fail;
1721         }
1722
1723         if (smb_fname->fsp == NULL) {
1724                 status = synthetic_pathref(mem_ctx,
1725                                         conn->cwd_fsp,
1726                                         smb_fname->base_name,
1727                                         NULL,
1728                                         NULL,
1729                                         smb_fname->twrp,
1730                                         smb_fname->flags,
1731                                         &pathref);
1732                 if (!NT_STATUS_IS_OK(status)) {
1733                         if (NT_STATUS_EQUAL(status,
1734                                 NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1735                                 TALLOC_FREE(pathref);
1736                                 SET_STAT_INVALID(smb_fname->st);
1737                                 return NT_STATUS_OK;
1738                         }
1739                         DBG_DEBUG("synthetic_pathref failed: %s\n",
1740                                   nt_errstr(status));
1741                         goto fail;
1742                 }
1743         } else {
1744                 pathref = smb_fname;
1745         }
1746
1747         /* Fall back to a case-insensitive scan of all streams on the file. */
1748         status = vfs_fstreaminfo(pathref->fsp, mem_ctx,
1749                                 &num_streams, &streams);
1750         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1751                 SET_STAT_INVALID(smb_fname->st);
1752                 TALLOC_FREE(pathref);
1753                 return NT_STATUS_OK;
1754         }
1755
1756         if (!NT_STATUS_IS_OK(status)) {
1757                 DEBUG(10, ("vfs_fstreaminfo failed: %s\n", nt_errstr(status)));
1758                 goto fail;
1759         }
1760
1761         for (i=0; i<num_streams; i++) {
1762                 bool equal = sname_equal(
1763                         smb_fname->stream_name,
1764                         streams[i].name,
1765                         conn->case_sensitive);
1766
1767                 DBG_DEBUG("comparing [%s] and [%s]: %sequal\n",
1768                           smb_fname->stream_name,
1769                           streams[i].name,
1770                           equal ? "" : "not ");
1771
1772                 if (equal) {
1773                         break;
1774                 }
1775         }
1776
1777         /* Couldn't find the stream. */
1778         if (i == num_streams) {
1779                 SET_STAT_INVALID(smb_fname->st);
1780                 TALLOC_FREE(pathref);
1781                 TALLOC_FREE(streams);
1782                 return NT_STATUS_OK;
1783         }
1784
1785         DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1786                 smb_fname->stream_name, streams[i].name));
1787
1788
1789         TALLOC_FREE(smb_fname->stream_name);
1790         smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1791         if (smb_fname->stream_name == NULL) {
1792                 status = NT_STATUS_NO_MEMORY;
1793                 goto fail;
1794         }
1795
1796         SET_STAT_INVALID(smb_fname->st);
1797
1798         if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1799                 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1800         }
1801         status = NT_STATUS_OK;
1802  fail:
1803         TALLOC_FREE(pathref);
1804         TALLOC_FREE(streams);
1805         return status;
1806 }
1807
1808 /*
1809  * Lightweight function to just get last component
1810  * for rename / enumerate directory calls.
1811  */
1812
1813 char *get_original_lcomp(TALLOC_CTX *ctx,
1814                         connection_struct *conn,
1815                         const char *filename_in,
1816                         uint32_t ucf_flags)
1817 {
1818         struct smb_filename *smb_fname = NULL;
1819         char *last_slash = NULL;
1820         char *orig_lcomp;
1821         char *fname = NULL;
1822         NTTIME twrp = 0;
1823         NTSTATUS status;
1824
1825         if (ucf_flags & UCF_DFS_PATHNAME) {
1826                 status = dfs_redirect(ctx,
1827                                 conn,
1828                                 filename_in,
1829                                 ucf_flags,
1830                                 !conn->sconn->using_smb2,
1831                                 &twrp,
1832                                 &fname);
1833                 if (!NT_STATUS_IS_OK(status)) {
1834                         DBG_DEBUG("dfs_redirect "
1835                                 "failed for name %s with %s\n",
1836                                 filename_in,
1837                                 nt_errstr(status));
1838                         return NULL;
1839                 }
1840                 filename_in = fname;
1841                 ucf_flags &= ~UCF_DFS_PATHNAME;
1842         }
1843
1844         /*
1845          * NB. We don't need to care about
1846          * is_fake_file_path(filename_in) here as these
1847          * code paths don't ever return original_lcomp
1848          * or use it anyway.
1849          */
1850
1851         if (ucf_flags & UCF_GMT_PATHNAME) {
1852                 /*
1853                  * Ensure we don't return a @GMT
1854                  * value as the last component.
1855                  */
1856                 smb_fname = synthetic_smb_fname(ctx,
1857                                         filename_in,
1858                                         NULL,
1859                                         NULL,
1860                                         twrp,
1861                                         0);
1862                 if (smb_fname == NULL) {
1863                         TALLOC_FREE(fname);
1864                         return NULL;
1865                 }
1866                 status = canonicalize_snapshot_path(smb_fname,
1867                                                     ucf_flags,
1868                                                     twrp);
1869                 if (!NT_STATUS_IS_OK(status)) {
1870                         TALLOC_FREE(fname);
1871                         TALLOC_FREE(smb_fname);
1872                         return NULL;
1873                 }
1874                 filename_in = smb_fname->base_name;
1875         }
1876         last_slash = strrchr(filename_in, '/');
1877         if (last_slash != NULL) {
1878                 orig_lcomp = talloc_strdup(ctx, last_slash+1);
1879         } else {
1880                 orig_lcomp = talloc_strdup(ctx, filename_in);
1881         }
1882         /* We're done with any temp names here. */
1883         TALLOC_FREE(smb_fname);
1884         TALLOC_FREE(fname);
1885         if (orig_lcomp == NULL) {
1886                 return NULL;
1887         }
1888         status = normalize_filename_case(conn, orig_lcomp, ucf_flags);
1889         if (!NT_STATUS_IS_OK(status)) {
1890                 TALLOC_FREE(orig_lcomp);
1891                 return NULL;
1892         }
1893         return orig_lcomp;
1894 }
1895
1896 /**
1897  * Go through all the steps to validate a filename.
1898  *
1899  * @param ctx           talloc_ctx to allocate memory with.
1900  * @param conn          connection struct for vfs calls.
1901  * @param smbreq        SMB request if we're using privileges.
1902  * @param name_in       The unconverted name.
1903  * @param ucf_flags     flags to pass through to unix_convert().
1904  * @param twrp          Optional VSS time
1905  * @param p_cont_wcard  If not NULL, will be set to true if the dfs path
1906  *                      resolution detects a wildcard.
1907  * @param _smb_fname    The final converted name will be allocated if the
1908  *                      return is NT_STATUS_OK.
1909  *
1910  * @return NT_STATUS_OK if all operations completed successfully, appropriate
1911  *         error otherwise.
1912  */
1913 NTSTATUS filename_convert(TALLOC_CTX *ctx,
1914                           connection_struct *conn,
1915                           const char *name_in,
1916                           uint32_t ucf_flags,
1917                           NTTIME twrp,
1918                           struct smb_filename **_smb_fname)
1919 {
1920         struct smb_filename *smb_fname = NULL;
1921         NTSTATUS status;
1922
1923         *_smb_fname = NULL;
1924
1925         if (ucf_flags & UCF_DFS_PATHNAME) {
1926                 char *fname = NULL;
1927                 NTTIME dfs_twrp = 0;
1928                 status = dfs_redirect(ctx, conn,
1929                                 name_in,
1930                                 ucf_flags,
1931                                 !conn->sconn->using_smb2,
1932                                 &dfs_twrp,
1933                                 &fname);
1934                 if (!NT_STATUS_IS_OK(status)) {
1935                         DBG_DEBUG("dfs_redirect "
1936                                 "failed for name %s with %s\n",
1937                                 name_in,
1938                                 nt_errstr(status));
1939                         return status;
1940                 }
1941                 name_in = fname;
1942                 ucf_flags &= ~UCF_DFS_PATHNAME;
1943                 if (twrp == 0 && dfs_twrp != 0) {
1944                         twrp = dfs_twrp;
1945                 }
1946         }
1947
1948         if (is_fake_file_path(name_in)) {
1949                 smb_fname = synthetic_smb_fname_split(ctx,
1950                                         name_in,
1951                                         (ucf_flags & UCF_POSIX_PATHNAMES));
1952                 if (smb_fname == NULL) {
1953                         return NT_STATUS_NO_MEMORY;
1954                 }
1955                 smb_fname->st = (SMB_STRUCT_STAT) { .st_ex_nlink = 1 };
1956                 smb_fname->st.st_ex_btime = (struct timespec){0, SAMBA_UTIME_OMIT};
1957                 smb_fname->st.st_ex_atime = (struct timespec){0, SAMBA_UTIME_OMIT};
1958                 smb_fname->st.st_ex_mtime = (struct timespec){0, SAMBA_UTIME_OMIT};
1959                 smb_fname->st.st_ex_ctime = (struct timespec){0, SAMBA_UTIME_OMIT};
1960
1961                 *_smb_fname = smb_fname;
1962                 return NT_STATUS_OK;
1963         }
1964
1965         status = unix_convert(ctx, conn, name_in, twrp, &smb_fname, ucf_flags);
1966         if (!NT_STATUS_IS_OK(status)) {
1967                 DBG_DEBUG("unix_convert failed "
1968                         "for name %s with %s\n",
1969                         name_in,
1970                         nt_errstr(status));
1971                 return status;
1972         }
1973
1974         if ((ucf_flags & UCF_POSIX_PATHNAMES) &&
1975             VALID_STAT(smb_fname->st) &&
1976             S_ISLNK(smb_fname->st.st_ex_mode))
1977         {
1978                 status = check_veto_path(conn, smb_fname);
1979                 if (!NT_STATUS_IS_OK(status)) {
1980                         TALLOC_FREE(smb_fname);
1981                         return status;
1982                 }
1983         } else {
1984                 status = check_name(conn, smb_fname);
1985         }
1986         if (!NT_STATUS_IS_OK(status)) {
1987                 DBG_NOTICE("check_name failed "
1988                         "for name %s with %s\n",
1989                         smb_fname_str_dbg(smb_fname),
1990                         nt_errstr(status));
1991                 TALLOC_FREE(smb_fname);
1992                 return status;
1993         }
1994
1995         if (!VALID_STAT(smb_fname->st)) {
1996                 DBG_DEBUG("[%s] does not exist, skipping pathref fsp\n",
1997                           smb_fname_str_dbg(smb_fname));
1998                 *_smb_fname = smb_fname;
1999                 return NT_STATUS_OK;
2000         }
2001
2002         status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
2003         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2004                 /*
2005                  * We deal with symlinks here as we do in
2006                  * SMB_VFS_CREATE_FILE(): return success for POSIX clients with
2007                  * the notable difference that there will be no fsp in
2008                  * smb_fname->fsp.
2009                  *
2010                  * For Windows (non POSIX) clients fail with
2011                  * NT_STATUS_OBJECT_NAME_NOT_FOUND.
2012                  */
2013                 if (smb_fname->flags & SMB_FILENAME_POSIX_PATH &&
2014                     S_ISLNK(smb_fname->st.st_ex_mode))
2015                 {
2016                         status = NT_STATUS_OK;
2017                 }
2018         }
2019         if (!NT_STATUS_IS_OK(status)) {
2020                 DBG_DEBUG("openat_pathref_fsp [%s] failed: %s\n",
2021                           smb_fname_str_dbg(smb_fname),
2022                           nt_errstr(status));
2023                 return status;
2024         }
2025
2026         *_smb_fname = smb_fname;
2027         return status;
2028 }
2029
2030 /*
2031  * Strip a @GMT component from an SMB1-DFS path. Could be anywhere
2032  * in the path.
2033  */
2034
2035 static char *strip_gmt_from_raw_dfs(TALLOC_CTX *ctx,
2036                                     const char *name_in,
2037                                     bool posix_pathnames,
2038                                     NTTIME *_twrp)
2039 {
2040         NTSTATUS status;
2041         struct smb_filename *smb_fname = NULL;
2042         char *name_out = NULL;
2043
2044         smb_fname = synthetic_smb_fname(ctx,
2045                                         name_in,
2046                                         NULL,
2047                                         NULL,
2048                                         0,
2049                                         0);
2050         if (smb_fname == NULL) {
2051                 return NULL;
2052         }
2053         if (!posix_pathnames) {
2054                 /*
2055                  * Raw DFS names are still '\\' separated.
2056                  * canonicalize_snapshot_path() only works
2057                  * on '/' separated paths. Convert.
2058                  */
2059                 string_replace(smb_fname->base_name, '\\', '/');
2060         }
2061         status = canonicalize_snapshot_path(smb_fname,
2062                                             UCF_GMT_PATHNAME,
2063                                             0);
2064         if (!NT_STATUS_IS_OK(status)) {
2065                 TALLOC_FREE(smb_fname);
2066                 return NULL;
2067         }
2068         if (!posix_pathnames) {
2069                 /* Replace as raw DFS names. */
2070                 string_replace(smb_fname->base_name, '/', '\\');
2071         }
2072         name_out = talloc_strdup(ctx, smb_fname->base_name);
2073         *_twrp = smb_fname->twrp;
2074         TALLOC_FREE(smb_fname);
2075         return name_out;
2076 }
2077
2078 /*
2079  * Deal with the SMB1 semantics of sending a pathname with a
2080  * wildcard as the terminal component for a SMB1search or
2081  * trans2 findfirst.
2082  */
2083
2084 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
2085                                            connection_struct *conn,
2086                                            const char *name_in,
2087                                            uint32_t ucf_flags,
2088                                            struct smb_filename **_smb_fname_out,
2089                                            char **_mask_out)
2090 {
2091         NTSTATUS status;
2092         char *p = NULL;
2093         char *mask = NULL;
2094         struct smb_filename *smb_fname = NULL;
2095         bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
2096         NTTIME twrp = 0;
2097         TALLOC_CTX *frame = talloc_stackframe();
2098
2099         *_smb_fname_out = NULL;
2100         *_mask_out = NULL;
2101
2102         DBG_DEBUG("name_in: %s\n", name_in);
2103
2104         if (ucf_flags & UCF_DFS_PATHNAME) {
2105                 /*
2106                  * We've been given a raw DFS pathname.
2107                  * In Windows mode this is separated by '\\'
2108                  * characters.
2109                  *
2110                  * We need to remove the last component
2111                  * which must be a wildcard before passing
2112                  * to dfs_redirect(). But the last component
2113                  * may also be a @GMT- token so we have to
2114                  * remove that first.
2115                  */
2116                 char path_sep = posix_pathnames ? '/' : '\\';
2117                 char *fname = NULL;
2118                 char *name_in_copy = NULL;
2119                 char *last_component = NULL;
2120
2121                 /* Work on a copy of name_in. */
2122                 if (ucf_flags & UCF_GMT_PATHNAME) {
2123                         name_in_copy = strip_gmt_from_raw_dfs(frame,
2124                                                               name_in,
2125                                                               posix_pathnames,
2126                                                               &twrp);
2127                         ucf_flags &= ~UCF_GMT_PATHNAME;
2128                 } else {
2129                         name_in_copy = talloc_strdup(frame, name_in);
2130                 }
2131                 if (name_in_copy == NULL) {
2132                         TALLOC_FREE(frame);
2133                         return NT_STATUS_NO_MEMORY;
2134                 }
2135
2136                 /*
2137                  * Now we know that the last component is the
2138                  * wildcard. Copy it and truncate to remove it.
2139                  */
2140                 p = strrchr_m(name_in_copy, path_sep);
2141                 if (p == NULL) {
2142                         last_component = talloc_strdup(frame, name_in_copy);
2143                         name_in_copy[0] = '\0';
2144                 } else {
2145                         last_component = talloc_strdup(frame, p+1);
2146                         *p = '\0';
2147                 }
2148                 if (last_component == NULL) {
2149                         TALLOC_FREE(frame);
2150                         return NT_STATUS_NO_MEMORY;
2151                 }
2152
2153                 DBG_DEBUG("name_in_copy: %s\n", name_in);
2154
2155                 /*
2156                  * Now we can call dfs_redirect()
2157                  * on the name without wildcard.
2158                  */
2159                 status = dfs_redirect(frame,
2160                                       conn,
2161                                       name_in_copy,
2162                                       ucf_flags,
2163                                       !conn->sconn->using_smb2,
2164                                       NULL,
2165                                       &fname);
2166                 if (!NT_STATUS_IS_OK(status)) {
2167                         DBG_DEBUG("dfs_redirect "
2168                                 "failed for name %s with %s\n",
2169                                 name_in_copy,
2170                                 nt_errstr(status));
2171                         TALLOC_FREE(frame);
2172                         return status;
2173                 }
2174                 /* Add the last component back. */
2175                 if (fname[0] == '\0') {
2176                         name_in = talloc_strdup(frame, last_component);
2177                 } else {
2178                         name_in = talloc_asprintf(frame,
2179                                                   "%s%c%s",
2180                                                   fname,
2181                                                   path_sep,
2182                                                   last_component);
2183                 }
2184                 if (name_in == NULL) {
2185                         TALLOC_FREE(frame);
2186                         return NT_STATUS_NO_MEMORY;
2187                 }
2188                 ucf_flags &= ~UCF_DFS_PATHNAME;
2189
2190                 DBG_DEBUG("After DFS redirect name_in: %s\n", name_in);
2191         }
2192
2193         smb_fname = synthetic_smb_fname(frame,
2194                                         name_in,
2195                                         NULL,
2196                                         NULL,
2197                                         twrp,
2198                                         posix_pathnames ?
2199                                                 SMB_FILENAME_POSIX_PATH : 0);
2200         if (smb_fname == NULL) {
2201                 TALLOC_FREE(frame);
2202                 return NT_STATUS_NO_MEMORY;
2203         }
2204
2205         /* Canonicalize any @GMT- paths. */
2206         status = canonicalize_snapshot_path(smb_fname, ucf_flags, twrp);
2207         if (!NT_STATUS_IS_OK(status)) {
2208                 TALLOC_FREE(frame);
2209                 return status;
2210         }
2211
2212         /* Get the original lcomp. */
2213         mask = get_original_lcomp(frame,
2214                                   conn,
2215                                   name_in,
2216                                   ucf_flags);
2217         if (mask == NULL) {
2218                 TALLOC_FREE(frame);
2219                 return NT_STATUS_NO_MEMORY;
2220         }
2221
2222         if (mask[0] == '\0') {
2223                 /* Windows and OS/2 systems treat search on the root as * */
2224                 TALLOC_FREE(mask);
2225                 mask = talloc_strdup(frame, "*");
2226                 if (mask == NULL) {
2227                         TALLOC_FREE(frame);
2228                         return NT_STATUS_NO_MEMORY;
2229                 }
2230         }
2231
2232         DBG_DEBUG("mask = %s\n", mask);
2233
2234         /*
2235          * Remove the terminal component so
2236          * filename_convert never sees the mask.
2237          */
2238         p = strrchr_m(smb_fname->base_name,'/');
2239         if (p == NULL) {
2240                 /* filename_convert handles a '\0' base_name. */
2241                 smb_fname->base_name[0] = '\0';
2242         } else {
2243                 *p = '\0';
2244         }
2245
2246         DBG_DEBUG("For filename_convert: smb_fname = %s\n",
2247                 smb_fname_str_dbg(smb_fname));
2248
2249         /* Convert the parent directory path. */
2250         status = filename_convert(frame,
2251                                   conn,
2252                                   smb_fname->base_name,
2253                                   ucf_flags,
2254                                   smb_fname->twrp,
2255                                   &smb_fname);
2256
2257         if (NT_STATUS_IS_OK(status)) {
2258                 *_smb_fname_out = talloc_move(ctx, &smb_fname);
2259                 *_mask_out = talloc_move(ctx, &mask);
2260         } else {
2261                 DBG_DEBUG("filename_convert error for %s: %s\n",
2262                         smb_fname_str_dbg(smb_fname),
2263                         nt_errstr(status));
2264         }
2265
2266         TALLOC_FREE(frame);
2267         return status;
2268 }
2269
2270 /*
2271  * Build the full path from a dirfsp and dirfsp relative name
2272  */
2273 struct smb_filename *full_path_from_dirfsp_atname(
2274         TALLOC_CTX *mem_ctx,
2275         const struct files_struct *dirfsp,
2276         const struct smb_filename *atname)
2277 {
2278         struct smb_filename *fname = NULL;
2279         char *path = NULL;
2280
2281         if (dirfsp == dirfsp->conn->cwd_fsp ||
2282             ISDOT(dirfsp->fsp_name->base_name) ||
2283             atname->base_name[0] == '/')
2284         {
2285                 path = talloc_strdup(mem_ctx, atname->base_name);
2286         } else {
2287                 path = talloc_asprintf(mem_ctx, "%s/%s",
2288                                        dirfsp->fsp_name->base_name,
2289                                        atname->base_name);
2290         }
2291         if (path == NULL) {
2292                 return NULL;
2293         }
2294
2295         fname = synthetic_smb_fname(mem_ctx,
2296                                     path,
2297                                     atname->stream_name,
2298                                     &atname->st,
2299                                     atname->twrp,
2300                                     atname->flags);
2301         TALLOC_FREE(path);
2302         if (fname == NULL) {
2303                 return NULL;
2304         }
2305
2306         return fname;
2307 }