param: rename lp function and variable from 'defaultcase' to 'default_case'
[vlendec/samba-autobuild/.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 NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
34                                   connection_struct *conn,
35                                   const char *orig_path,
36                                   struct smb_filename *smb_fname);
37
38 /****************************************************************************
39  Mangle the 2nd name and check if it is then equal to the first name.
40 ****************************************************************************/
41
42 static bool mangled_equal(const char *name1,
43                         const char *name2,
44                         const struct share_params *p)
45 {
46         char mname[13];
47
48         if (!name_to_8_3(name2, mname, False, p)) {
49                 return False;
50         }
51         return strequal(name1, mname);
52 }
53
54 /****************************************************************************
55  Cope with the differing wildcard and non-wildcard error cases.
56 ****************************************************************************/
57
58 static NTSTATUS determine_path_error(const char *name,
59                         bool allow_wcard_last_component)
60 {
61         const char *p;
62
63         if (!allow_wcard_last_component) {
64                 /* Error code within a pathname. */
65                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
66         }
67
68         /* We're terminating here so we
69          * can be a little slower and get
70          * the error code right. Windows
71          * treats the last part of the pathname
72          * separately I think, so if the last
73          * component is a wildcard then we treat
74          * this ./ as "end of component" */
75
76         p = strchr(name, '/');
77
78         if (!p && (ms_has_wild(name) || ISDOT(name))) {
79                 /* Error code at the end of a pathname. */
80                 return NT_STATUS_OBJECT_NAME_INVALID;
81         } else {
82                 /* Error code within a pathname. */
83                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
84         }
85 }
86
87 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
88 {
89         /* Ensure we catch all names with in "/."
90            this is disallowed under Windows and
91            in POSIX they've already been removed. */
92         const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
93         if (p) {
94                 if (p[2] == '/') {
95                         /* Error code within a pathname. */
96                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
97                 } else if (p[2] == '\0') {
98                         /* Error code at the end of a pathname. */
99                         return NT_STATUS_OBJECT_NAME_INVALID;
100                 }
101         }
102         return NT_STATUS_OK;
103 }
104
105 /****************************************************************************
106  Optimization for common case where the missing part
107  is in the last component and the client already
108  sent the correct case.
109  Returns NT_STATUS_OK to mean continue the tree walk
110  (possibly with modified start pointer).
111  Any other NT_STATUS_XXX error means terminate the path
112  lookup here.
113 ****************************************************************************/
114
115 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
116                                 connection_struct *conn,
117                                 bool posix_pathnames,
118                                 const struct smb_filename *smb_fname,
119                                 char **pp_dirpath,
120                                 char **pp_start)
121 {
122         struct smb_filename parent_fname;
123         const char *last_component = NULL;
124         NTSTATUS status;
125         int ret;
126
127         ZERO_STRUCT(parent_fname);
128         if (!parent_dirname(ctx, smb_fname->base_name,
129                                 &parent_fname.base_name,
130                                 &last_component)) {
131                 return NT_STATUS_NO_MEMORY;
132         }
133
134         /*
135          * If there was no parent component in
136          * smb_fname->base_name of the parent name
137          * contained a wildcard then don't do this
138          * optimization.
139          */
140         if ((smb_fname->base_name == last_component) ||
141                         ms_has_wild(parent_fname.base_name)) {
142                 return NT_STATUS_OK;
143         }
144
145         if (posix_pathnames) {
146                 ret = SMB_VFS_LSTAT(conn, &parent_fname);
147         } else {
148                 ret = SMB_VFS_STAT(conn, &parent_fname);
149         }
150
151         /* If the parent stat failed, just continue
152            with the normal tree walk. */
153
154         if (ret == -1) {
155                 return NT_STATUS_OK;
156         }
157
158         status = check_for_dot_component(&parent_fname);
159         if (!NT_STATUS_IS_OK(status)) {
160                 return status;
161         }
162
163         /* Parent exists - set "start" to be the
164          * last compnent to shorten the tree walk. */
165
166         /*
167          * Safe to use discard_const_p
168          * here as last_component points
169          * into our smb_fname->base_name.
170          */
171         *pp_start = discard_const_p(char, last_component);
172
173         /* Update dirpath. */
174         TALLOC_FREE(*pp_dirpath);
175         *pp_dirpath = talloc_strdup(ctx, parent_fname.base_name);
176         if (!*pp_dirpath) {
177                 return NT_STATUS_NO_MEMORY;
178         }
179
180         DEBUG(5,("check_parent_exists: name "
181                 "= %s, dirpath = %s, "
182                 "start = %s\n",
183                 smb_fname->base_name,
184                 *pp_dirpath,
185                 *pp_start));
186
187         return NT_STATUS_OK;
188 }
189
190 /****************************************************************************
191 This routine is called to convert names from the dos namespace to unix
192 namespace. It needs to handle any case conversions, mangling, format changes,
193 streams etc.
194
195 We assume that we have already done a chdir() to the right "root" directory
196 for this service.
197
198 The function will return an NTSTATUS error if some part of the name except for
199 the last part cannot be resolved, else NT_STATUS_OK.
200
201 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
202 didn't get any fatal errors that should immediately terminate the calling SMB
203 processing whilst resolving.
204
205 If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
206 of the pathname is set in smb_filename->original_lcomp.
207
208 If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected
209 and should be allowed in the last component of the path only.
210
211 If the orig_path was a stream, smb_filename->base_name will point to the base
212 filename, and smb_filename->stream_name will point to the stream name.  If
213 orig_path was not a stream, then smb_filename->stream_name will be NULL.
214
215 On exit from unix_convert, the smb_filename->st stat struct will be populated
216 if the file exists and was found, if not this stat struct will be filled with
217 zeros (and this can be detected by checking for nlinks = 0, which can never be
218 true for any file).
219 ****************************************************************************/
220
221 NTSTATUS unix_convert(TALLOC_CTX *ctx,
222                       connection_struct *conn,
223                       const char *orig_path,
224                       struct smb_filename **smb_fname_out,
225                       uint32_t ucf_flags)
226 {
227         struct smb_filename *smb_fname = NULL;
228         char *start, *end;
229         char *dirpath = NULL;
230         char *stream = NULL;
231         bool component_was_mangled = False;
232         bool name_has_wildcard = False;
233         bool posix_pathnames = false;
234         bool allow_wcard_last_component =
235             (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
236         bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
237         NTSTATUS status;
238         int ret = -1;
239
240         *smb_fname_out = NULL;
241
242         smb_fname = talloc_zero(ctx, struct smb_filename);
243         if (smb_fname == NULL) {
244                 return NT_STATUS_NO_MEMORY;
245         }
246
247         if (conn->printer) {
248                 /* we don't ever use the filenames on a printer share as a
249                         filename - so don't convert them */
250                 if (!(smb_fname->base_name = talloc_strdup(smb_fname,
251                                                            orig_path))) {
252                         status = NT_STATUS_NO_MEMORY;
253                         goto err;
254                 }
255                 goto done;
256         }
257
258         DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
259
260         /*
261          * Conversion to basic unix format is already done in
262          * check_path_syntax().
263          */
264
265         /*
266          * Names must be relative to the root of the service - any leading /.
267          * and trailing /'s should have been trimmed by check_path_syntax().
268          */
269
270 #ifdef DEVELOPER
271         SMB_ASSERT(*orig_path != '/');
272 #endif
273
274         /*
275          * If we trimmed down to a single '\0' character
276          * then we should use the "." directory to avoid
277          * searching the cache, but not if we are in a
278          * printing share.
279          * As we know this is valid we can return true here.
280          */
281
282         if (!*orig_path) {
283                 if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) {
284                         status = NT_STATUS_NO_MEMORY;
285                         goto err;
286                 }
287                 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
288                         status = map_nt_error_from_unix(errno);
289                         goto err;
290                 }
291                 DEBUG(5, ("conversion finished \"\" -> %s\n",
292                           smb_fname->base_name));
293                 goto done;
294         }
295
296         if (orig_path[0] == '.' && (orig_path[1] == '/' ||
297                                 orig_path[1] == '\0')) {
298                 /* Start of pathname can't be "." only. */
299                 if (orig_path[1] == '\0' || orig_path[2] == '\0') {
300                         status = NT_STATUS_OBJECT_NAME_INVALID;
301                 } else {
302                         status =determine_path_error(&orig_path[2],
303                             allow_wcard_last_component);
304                 }
305                 goto err;
306         }
307
308         /* Start with the full orig_path as given by the caller. */
309         if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) {
310                 DEBUG(0, ("talloc_strdup failed\n"));
311                 status = NT_STATUS_NO_MEMORY;
312                 goto err;
313         }
314
315         /*
316          * Large directory fix normalization. If we're case sensitive, and
317          * the case preserving parameters are set to "no", normalize the case of
318          * the incoming filename from the client WHETHER IT EXISTS OR NOT !
319          * This is in conflict with the current (3.0.20) man page, but is
320          * what people expect from the "large directory howto". I'll update
321          * the man page. Thanks to jht@samba.org for finding this. JRA.
322          */
323
324         if (conn->case_sensitive && !conn->case_preserve &&
325                         !conn->short_case_preserve) {
326                 if (!strnorm(smb_fname->base_name, lp_default_case(SNUM(conn)))) {
327                         DEBUG(0, ("strnorm %s failed\n", smb_fname->base_name));
328                         status = NT_STATUS_INVALID_PARAMETER;
329                         goto err;
330                 }
331         }
332
333         /*
334          * Ensure saved_last_component is valid even if file exists.
335          */
336
337         if(save_last_component) {
338                 end = strrchr_m(smb_fname->base_name, '/');
339                 if (end) {
340                         smb_fname->original_lcomp = talloc_strdup(smb_fname,
341                                                                   end + 1);
342                 } else {
343                         smb_fname->original_lcomp =
344                             talloc_strdup(smb_fname, smb_fname->base_name);
345                 }
346                 if (smb_fname->original_lcomp == NULL) {
347                         status = NT_STATUS_NO_MEMORY;
348                         goto err;
349                 }
350         }
351
352         posix_pathnames = (lp_posix_pathnames() ||
353                                 (ucf_flags & UCF_POSIX_PATHNAMES));
354
355         /*
356          * Strip off the stream, and add it back when we're done with the
357          * base_name.
358          */
359         if (!posix_pathnames) {
360                 stream = strchr_m(smb_fname->base_name, ':');
361
362                 if (stream != NULL) {
363                         char *tmp = talloc_strdup(smb_fname, stream);
364                         if (tmp == NULL) {
365                                 status = NT_STATUS_NO_MEMORY;
366                                 goto err;
367                         }
368                         /*
369                          * Since this is actually pointing into
370                          * smb_fname->base_name this truncates base_name.
371                          */
372                         *stream = '\0';
373                         stream = tmp;
374                 }
375         }
376
377         start = smb_fname->base_name;
378
379         /*
380          * If we're providing case insensitive semantics or
381          * the underlying filesystem is case insensitive,
382          * then a case-normalized hit in the stat-cache is
383          * authoratitive. JRA.
384          *
385          * Note: We're only checking base_name.  The stream_name will be
386          * added and verified in build_stream_path().
387          */
388
389         if((!conn->case_sensitive || !(conn->fs_capabilities &
390                                        FILE_CASE_SENSITIVE_SEARCH)) &&
391             stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start,
392                               &smb_fname->st)) {
393                 goto done;
394         }
395
396         /*
397          * Make sure "dirpath" is an allocated string, we use this for
398          * building the directories with talloc_asprintf and free it.
399          */
400
401         if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
402                 DEBUG(0, ("talloc_strdup failed\n"));
403                 status = NT_STATUS_NO_MEMORY;
404                 goto err;
405         }
406
407         /*
408          * If we have a wildcard we must walk the path to
409          * find where the error is, even if case sensitive
410          * is true.
411          */
412
413         name_has_wildcard = ms_has_wild(smb_fname->base_name);
414         if (name_has_wildcard && !allow_wcard_last_component) {
415                 /* Wildcard not valid anywhere. */
416                 status = NT_STATUS_OBJECT_NAME_INVALID;
417                 goto fail;
418         }
419
420         DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
421                  smb_fname->base_name, dirpath, start));
422
423         if (!name_has_wildcard) {
424                 /*
425                  * stat the name - if it exists then we can add the stream back (if
426                  * there was one) and be done!
427                  */
428
429                 if (posix_pathnames) {
430                         ret = SMB_VFS_LSTAT(conn, smb_fname);
431                 } else {
432                         ret = SMB_VFS_STAT(conn, smb_fname);
433                 }
434
435                 if (ret == 0) {
436                         status = check_for_dot_component(smb_fname);
437                         if (!NT_STATUS_IS_OK(status)) {
438                                 goto fail;
439                         }
440                         /* Add the path (not including the stream) to the cache. */
441                         stat_cache_add(orig_path, smb_fname->base_name,
442                                        conn->case_sensitive);
443                         DEBUG(5,("conversion of base_name finished %s -> %s\n",
444                                  orig_path, smb_fname->base_name));
445                         goto done;
446                 }
447
448                 /* Stat failed - ensure we don't use it. */
449                 SET_STAT_INVALID(smb_fname->st);
450
451                 if (errno == ENOENT) {
452                         /* Optimization when creating a new file - only
453                            the last component doesn't exist.
454                            NOTE : check_parent_exists() doesn't preserve errno.
455                         */
456                         int saved_errno = errno;
457                         status = check_parent_exists(ctx,
458                                                 conn,
459                                                 posix_pathnames,
460                                                 smb_fname,
461                                                 &dirpath,
462                                                 &start);
463                         errno = saved_errno;
464                         if (!NT_STATUS_IS_OK(status)) {
465                                 goto fail;
466                         }
467                 }
468
469                 /*
470                  * A special case - if we don't have any wildcards or mangling chars and are case
471                  * sensitive or the underlying filesystem is case insensitive then searching
472                  * won't help.
473                  */
474
475                 if ((conn->case_sensitive || !(conn->fs_capabilities &
476                                         FILE_CASE_SENSITIVE_SEARCH)) &&
477                                 !mangle_is_mangled(smb_fname->base_name, conn->params)) {
478
479                         status = check_for_dot_component(smb_fname);
480                         if (!NT_STATUS_IS_OK(status)) {
481                                 goto fail;
482                         }
483
484                         /*
485                          * The stat failed. Could be ok as it could be
486                          * a new file.
487                          */
488
489                         if (errno == ENOTDIR || errno == ELOOP) {
490                                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
491                                 goto fail;
492                         } else if (errno == ENOENT) {
493                                 /*
494                                  * Was it a missing last component ?
495                                  * or a missing intermediate component ?
496                                  */
497                                 struct smb_filename parent_fname;
498                                 const char *last_component = NULL;
499
500                                 ZERO_STRUCT(parent_fname);
501                                 if (!parent_dirname(ctx, smb_fname->base_name,
502                                                         &parent_fname.base_name,
503                                                         &last_component)) {
504                                         status = NT_STATUS_NO_MEMORY;
505                                         goto fail;
506                                 }
507                                 if (posix_pathnames) {
508                                         ret = SMB_VFS_LSTAT(conn, &parent_fname);
509                                 } else {
510                                         ret = SMB_VFS_STAT(conn, &parent_fname);
511                                 }
512                                 if (ret == -1) {
513                                         if (errno == ENOTDIR ||
514                                                         errno == ENOENT ||
515                                                         errno == ELOOP) {
516                                                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
517                                                 goto fail;
518                                         }
519                                 }
520
521                                 /*
522                                  * Missing last component is ok - new file.
523                                  * Also deal with permission denied elsewhere.
524                                  * Just drop out to done.
525                                  */
526                                 goto done;
527                         }
528                 }
529         } else {
530                 /*
531                  * We have a wildcard in the pathname.
532                  *
533                  * Optimization for common case where the wildcard
534                  * is in the last component and the client already
535                  * sent the correct case.
536                  * NOTE : check_parent_exists() doesn't preserve errno.
537                  */
538                 int saved_errno = errno;
539                 status = check_parent_exists(ctx,
540                                         conn,
541                                         posix_pathnames,
542                                         smb_fname,
543                                         &dirpath,
544                                         &start);
545                 errno = saved_errno;
546                 if (!NT_STATUS_IS_OK(status)) {
547                         goto fail;
548                 }
549         }
550
551         /*
552          * is_mangled() was changed to look at an entire pathname, not
553          * just a component. JRA.
554          */
555
556         if (mangle_is_mangled(start, conn->params)) {
557                 component_was_mangled = True;
558         }
559
560         /*
561          * Now we need to recursively match the name against the real
562          * directory structure.
563          */
564
565         /*
566          * Match each part of the path name separately, trying the names
567          * as is first, then trying to scan the directory for matching names.
568          */
569
570         for (; start ; start = (end?end+1:(char *)NULL)) {
571                 /*
572                  * Pinpoint the end of this section of the filename.
573                  */
574                 /* mb safe. '/' can't be in any encoded char. */
575                 end = strchr(start, '/');
576
577                 /*
578                  * Chop the name at this point.
579                  */
580                 if (end) {
581                         *end = 0;
582                 }
583
584                 if (save_last_component) {
585                         TALLOC_FREE(smb_fname->original_lcomp);
586                         smb_fname->original_lcomp = talloc_strdup(smb_fname,
587                                                         end ? end + 1 : start);
588                         if (!smb_fname->original_lcomp) {
589                                 DEBUG(0, ("talloc failed\n"));
590                                 status = NT_STATUS_NO_MEMORY;
591                                 goto err;
592                         }
593                 }
594
595                 /* The name cannot have a component of "." */
596
597                 if (ISDOT(start)) {
598                         if (!end)  {
599                                 /* Error code at the end of a pathname. */
600                                 status = NT_STATUS_OBJECT_NAME_INVALID;
601                         } else {
602                                 status = determine_path_error(end+1,
603                                                 allow_wcard_last_component);
604                         }
605                         goto fail;
606                 }
607
608                 /* The name cannot have a wildcard if it's not
609                    the last component. */
610
611                 name_has_wildcard = ms_has_wild(start);
612
613                 /* Wildcards never valid within a pathname. */
614                 if (name_has_wildcard && end) {
615                         status = NT_STATUS_OBJECT_NAME_INVALID;
616                         goto fail;
617                 }
618
619                 /* Skip the stat call if it's a wildcard end. */
620                 if (name_has_wildcard) {
621                         DEBUG(5,("Wildcard %s\n",start));
622                         goto done;
623                 }
624
625                 /*
626                  * Check if the name exists up to this point.
627                  */
628
629                 if (posix_pathnames) {
630                         ret = SMB_VFS_LSTAT(conn, smb_fname);
631                 } else {
632                         ret = SMB_VFS_STAT(conn, smb_fname);
633                 }
634
635                 if (ret == 0) {
636                         /*
637                          * It exists. it must either be a directory or this must
638                          * be the last part of the path for it to be OK.
639                          */
640                         if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) {
641                                 /*
642                                  * An intermediate part of the name isn't
643                                  * a directory.
644                                  */
645                                 DEBUG(5,("Not a dir %s\n",start));
646                                 *end = '/';
647                                 /*
648                                  * We need to return the fact that the
649                                  * intermediate name resolution failed. This
650                                  * is used to return an error of ERRbadpath
651                                  * rather than ERRbadfile. Some Windows
652                                  * applications depend on the difference between
653                                  * these two errors.
654                                  */
655                                 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
656                                 goto fail;
657                         }
658
659                 } else {
660                         char *found_name = NULL;
661
662                         /* Stat failed - ensure we don't use it. */
663                         SET_STAT_INVALID(smb_fname->st);
664
665                         /*
666                          * Reset errno so we can detect
667                          * directory open errors.
668                          */
669                         errno = 0;
670
671                         /*
672                          * Try to find this part of the path in the directory.
673                          */
674
675                         if (name_has_wildcard ||
676                             (get_real_filename(conn, dirpath, start,
677                                                talloc_tos(),
678                                                &found_name) == -1)) {
679                                 char *unmangled;
680
681                                 if (end) {
682                                         /*
683                                          * An intermediate part of the name
684                                          * can't be found.
685                                          */
686                                         DEBUG(5,("Intermediate not found %s\n",
687                                                         start));
688                                         *end = '/';
689
690                                         /*
691                                          * We need to return the fact that the
692                                          * intermediate name resolution failed.
693                                          * This is used to return an error of
694                                          * ERRbadpath rather than ERRbadfile.
695                                          * Some Windows applications depend on
696                                          * the difference between these two
697                                          * errors.
698                                          */
699
700                                         /*
701                                          * ENOENT, ENOTDIR and ELOOP all map
702                                          * to NT_STATUS_OBJECT_PATH_NOT_FOUND
703                                          * in the filename walk.
704                                          */
705
706                                         if (errno == ENOENT ||
707                                                         errno == ENOTDIR ||
708                                                         errno == ELOOP) {
709                                                 status =
710                                                 NT_STATUS_OBJECT_PATH_NOT_FOUND;
711                                         }
712                                         else {
713                                                 status =
714                                                 map_nt_error_from_unix(errno);
715                                         }
716                                         goto fail;
717                                 }
718
719                                 /*
720                                  * ENOENT/EACCESS are the only valid errors
721                                  * here.
722                                  */
723
724                                 if (errno == EACCES) {
725                                         if ((ucf_flags & UCF_PREP_CREATEFILE) == 0) {
726                                                 status = NT_STATUS_ACCESS_DENIED;
727                                                 goto fail;
728                                         } else {
729                                                 /*
730                                                  * This is the dropbox
731                                                  * behaviour. A dropbox is a
732                                                  * directory with only -wx
733                                                  * permissions, so
734                                                  * get_real_filename fails
735                                                  * with EACCESS, it needs to
736                                                  * list the directory. We
737                                                  * nevertheless want to allow
738                                                  * users creating a file.
739                                                  */
740                                                 errno = 0;
741                                         }
742                                 }
743
744                                 if ((errno != 0) && (errno != ENOENT)) {
745                                         /*
746                                          * ENOTDIR and ELOOP both map to
747                                          * NT_STATUS_OBJECT_PATH_NOT_FOUND
748                                          * in the filename walk.
749                                          */
750                                         if (errno == ENOTDIR ||
751                                                         errno == ELOOP) {
752                                                 status =
753                                                 NT_STATUS_OBJECT_PATH_NOT_FOUND;
754                                         } else {
755                                                 status =
756                                                 map_nt_error_from_unix(errno);
757                                         }
758                                         goto fail;
759                                 }
760
761                                 /*
762                                  * Just the last part of the name doesn't exist.
763                                  * We need to strupper() or strlower() it as
764                                  * this conversion may be used for file creation
765                                  * purposes. Fix inspired by
766                                  * Thomas Neumann <t.neumann@iku-ag.de>.
767                                  */
768                                 if (!conn->case_preserve ||
769                                     (mangle_is_8_3(start, False,
770                                                    conn->params) &&
771                                                  !conn->short_case_preserve)) {
772                                         if (!strnorm(start,
773                                                         lp_default_case(SNUM(conn)))) {
774                                                 DEBUG(0, ("strnorm %s failed\n",
775                                                         start));
776                                                 status = NT_STATUS_INVALID_PARAMETER;
777                                                 goto err;
778                                         }
779                                 }
780
781                                 /*
782                                  * check on the mangled stack to see if we can
783                                  * recover the base of the filename.
784                                  */
785
786                                 if (mangle_is_mangled(start, conn->params)
787                                     && mangle_lookup_name_from_8_3(ctx,
788                                                         start,
789                                                         &unmangled,
790                                                         conn->params)) {
791                                         char *tmp;
792                                         size_t start_ofs =
793                                             start - smb_fname->base_name;
794
795                                         if (*dirpath != '\0') {
796                                                 tmp = talloc_asprintf(
797                                                         smb_fname, "%s/%s",
798                                                         dirpath, unmangled);
799                                                 TALLOC_FREE(unmangled);
800                                         }
801                                         else {
802                                                 tmp = unmangled;
803                                         }
804                                         if (tmp == NULL) {
805                                                 DEBUG(0, ("talloc failed\n"));
806                                                 status = NT_STATUS_NO_MEMORY;
807                                                 goto err;
808                                         }
809                                         TALLOC_FREE(smb_fname->base_name);
810                                         smb_fname->base_name = tmp;
811                                         start =
812                                             smb_fname->base_name + start_ofs;
813                                         end = start + strlen(start);
814                                 }
815
816                                 DEBUG(5,("New file %s\n",start));
817                                 goto done;
818                         }
819
820
821                         /*
822                          * Restore the rest of the string. If the string was
823                          * mangled the size may have changed.
824                          */
825                         if (end) {
826                                 char *tmp;
827                                 size_t start_ofs =
828                                     start - smb_fname->base_name;
829
830                                 if (*dirpath != '\0') {
831                                         tmp = talloc_asprintf(smb_fname,
832                                                 "%s/%s/%s", dirpath,
833                                                 found_name, end+1);
834                                 }
835                                 else {
836                                         tmp = talloc_asprintf(smb_fname,
837                                                 "%s/%s", found_name,
838                                                 end+1);
839                                 }
840                                 if (tmp == NULL) {
841                                         DEBUG(0, ("talloc_asprintf failed\n"));
842                                         status = NT_STATUS_NO_MEMORY;
843                                         goto err;
844                                 }
845                                 TALLOC_FREE(smb_fname->base_name);
846                                 smb_fname->base_name = tmp;
847                                 start = smb_fname->base_name + start_ofs;
848                                 end = start + strlen(found_name);
849                                 *end = '\0';
850                         } else {
851                                 char *tmp;
852                                 size_t start_ofs =
853                                     start - smb_fname->base_name;
854
855                                 if (*dirpath != '\0') {
856                                         tmp = talloc_asprintf(smb_fname,
857                                                 "%s/%s", dirpath,
858                                                 found_name);
859                                 } else {
860                                         tmp = talloc_strdup(smb_fname,
861                                                 found_name);
862                                 }
863                                 if (tmp == NULL) {
864                                         DEBUG(0, ("talloc failed\n"));
865                                         status = NT_STATUS_NO_MEMORY;
866                                         goto err;
867                                 }
868                                 TALLOC_FREE(smb_fname->base_name);
869                                 smb_fname->base_name = tmp;
870                                 start = smb_fname->base_name + start_ofs;
871
872                                 /*
873                                  * We just scanned for, and found the end of
874                                  * the path. We must return a valid stat struct
875                                  * if it exists. JRA.
876                                  */
877
878                                 if (posix_pathnames) {
879                                         ret = SMB_VFS_LSTAT(conn, smb_fname);
880                                 } else {
881                                         ret = SMB_VFS_STAT(conn, smb_fname);
882                                 }
883
884                                 if (ret != 0) {
885                                         SET_STAT_INVALID(smb_fname->st);
886                                 }
887                         }
888
889                         TALLOC_FREE(found_name);
890                 } /* end else */
891
892 #ifdef DEVELOPER
893                 /*
894                  * This sucks!
895                  * We should never provide different behaviors
896                  * depending on DEVELOPER!!!
897                  */
898                 if (VALID_STAT(smb_fname->st)) {
899                         bool delete_pending;
900                         uint32_t name_hash;
901
902                         status = file_name_hash(conn,
903                                         smb_fname_str_dbg(smb_fname),
904                                         &name_hash);
905                         if (!NT_STATUS_IS_OK(status)) {
906                                 goto fail;
907                         }
908
909                         get_file_infos(vfs_file_id_from_sbuf(conn,
910                                                              &smb_fname->st),
911                                        name_hash,
912                                        &delete_pending, NULL);
913                         if (delete_pending) {
914                                 status = NT_STATUS_DELETE_PENDING;
915                                 goto fail;
916                         }
917                 }
918 #endif
919
920                 /*
921                  * Add to the dirpath that we have resolved so far.
922                  */
923
924                 if (*dirpath != '\0') {
925                         char *tmp = talloc_asprintf(ctx,
926                                         "%s/%s", dirpath, start);
927                         if (!tmp) {
928                                 DEBUG(0, ("talloc_asprintf failed\n"));
929                                 status = NT_STATUS_NO_MEMORY;
930                                 goto err;
931                         }
932                         TALLOC_FREE(dirpath);
933                         dirpath = tmp;
934                 }
935                 else {
936                         TALLOC_FREE(dirpath);
937                         if (!(dirpath = talloc_strdup(ctx,start))) {
938                                 DEBUG(0, ("talloc_strdup failed\n"));
939                                 status = NT_STATUS_NO_MEMORY;
940                                 goto err;
941                         }
942                 }
943
944                 /*
945                  * Cache the dirpath thus far. Don't cache a name with mangled
946                  * or wildcard components as this can change the size.
947                  */
948                 if(!component_was_mangled && !name_has_wildcard) {
949                         stat_cache_add(orig_path, dirpath,
950                                         conn->case_sensitive);
951                 }
952
953                 /*
954                  * Restore the / that we wiped out earlier.
955                  */
956                 if (end) {
957                         *end = '/';
958                 }
959         }
960
961         /*
962          * Cache the full path. Don't cache a name with mangled or wildcard
963          * components as this can change the size.
964          */
965
966         if(!component_was_mangled && !name_has_wildcard) {
967                 stat_cache_add(orig_path, smb_fname->base_name,
968                                conn->case_sensitive);
969         }
970
971         /*
972          * The name has been resolved.
973          */
974
975         DEBUG(5,("conversion finished %s -> %s\n", orig_path,
976                  smb_fname->base_name));
977
978  done:
979         /* Add back the stream if one was stripped off originally. */
980         if (stream != NULL) {
981                 smb_fname->stream_name = stream;
982
983                 /* Check path now that the base_name has been converted. */
984                 status = build_stream_path(ctx, conn, orig_path, smb_fname);
985                 if (!NT_STATUS_IS_OK(status)) {
986                         goto fail;
987                 }
988         }
989         TALLOC_FREE(dirpath);
990         *smb_fname_out = smb_fname;
991         return NT_STATUS_OK;
992  fail:
993         DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
994         if (*dirpath != '\0') {
995                 smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s",
996                                                        dirpath, start);
997         } else {
998                 smb_fname->base_name = talloc_strdup(smb_fname, start);
999         }
1000         if (!smb_fname->base_name) {
1001                 DEBUG(0, ("talloc_asprintf failed\n"));
1002                 status = NT_STATUS_NO_MEMORY;
1003                 goto err;
1004         }
1005
1006         *smb_fname_out = smb_fname;
1007         TALLOC_FREE(dirpath);
1008         return status;
1009  err:
1010         TALLOC_FREE(smb_fname);
1011         return status;
1012 }
1013
1014 /****************************************************************************
1015  Ensure a path is not vetod.
1016 ****************************************************************************/
1017
1018 NTSTATUS check_veto_path(connection_struct *conn, const char *name)
1019 {
1020         if (IS_VETO_PATH(conn, name))  {
1021                 /* Is it not dot or dot dot. */
1022                 if (!(ISDOT(name) || ISDOTDOT(name))) {
1023                         DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1024                                                 name));
1025                         return map_nt_error_from_unix(ENOENT);
1026                 }
1027         }
1028         return NT_STATUS_OK;
1029 }
1030
1031 /****************************************************************************
1032  Check a filename - possibly calling check_reduced_name.
1033  This is called by every routine before it allows an operation on a filename.
1034  It does any final confirmation necessary to ensure that the filename is
1035  a valid one for the user to access.
1036 ****************************************************************************/
1037
1038 NTSTATUS check_name(connection_struct *conn, const char *name)
1039 {
1040         NTSTATUS status = check_veto_path(conn, name);
1041
1042         if (!NT_STATUS_IS_OK(status)) {
1043                 return status;
1044         }
1045
1046         if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) {
1047                 status = check_reduced_name(conn,name);
1048                 if (!NT_STATUS_IS_OK(status)) {
1049                         DEBUG(5,("check_name: name %s failed with %s\n",name,
1050                                                 nt_errstr(status)));
1051                         return status;
1052                 }
1053         }
1054
1055         return NT_STATUS_OK;
1056 }
1057
1058 /****************************************************************************
1059  Must be called as root. Creates the struct privilege_paths
1060  attached to the struct smb_request if this call is successful.
1061 ****************************************************************************/
1062
1063 static NTSTATUS check_name_with_privilege(connection_struct *conn,
1064                 struct smb_request *smbreq,
1065                 const char *name)
1066 {
1067         NTSTATUS status = check_veto_path(conn, name);
1068
1069         if (!NT_STATUS_IS_OK(status)) {
1070                 return status;
1071         }
1072         return check_reduced_name_with_privilege(conn,
1073                         name,
1074                         smbreq);
1075 }
1076
1077 /****************************************************************************
1078  Check if two filenames are equal.
1079  This needs to be careful about whether we are case sensitive.
1080 ****************************************************************************/
1081
1082 static bool fname_equal(const char *name1, const char *name2,
1083                 bool case_sensitive)
1084 {
1085         /* Normal filename handling */
1086         if (case_sensitive) {
1087                 return(strcmp(name1,name2) == 0);
1088         }
1089
1090         return(strequal(name1,name2));
1091 }
1092
1093 /****************************************************************************
1094  Scan a directory to find a filename, matching without case sensitivity.
1095  If the name looks like a mangled name then try via the mangling functions
1096 ****************************************************************************/
1097
1098 static int get_real_filename_full_scan(connection_struct *conn,
1099                                        const char *path, const char *name,
1100                                        bool mangled,
1101                                        TALLOC_CTX *mem_ctx, char **found_name)
1102 {
1103         struct smb_Dir *cur_dir;
1104         const char *dname = NULL;
1105         char *talloced = NULL;
1106         char *unmangled_name = NULL;
1107         long curpos;
1108
1109         /* handle null paths */
1110         if ((path == NULL) || (*path == 0)) {
1111                 path = ".";
1112         }
1113
1114         /* If we have a case-sensitive filesystem, it doesn't do us any
1115          * good to search for a name. If a case variation of the name was
1116          * there, then the original stat(2) would have found it.
1117          */
1118         if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1119                 errno = ENOENT;
1120                 return -1;
1121         }
1122
1123         /*
1124          * The incoming name can be mangled, and if we de-mangle it
1125          * here it will not compare correctly against the filename (name2)
1126          * read from the directory and then mangled by the name_to_8_3()
1127          * call. We need to mangle both names or neither.
1128          * (JRA).
1129          *
1130          * Fix for bug found by Dina Fine. If in case sensitive mode then
1131          * the mangle cache is no good (3 letter extension could be wrong
1132          * case - so don't demangle in this case - leave as mangled and
1133          * allow the mangling of the directory entry read (which is done
1134          * case insensitively) to match instead. This will lead to more
1135          * false positive matches but we fail completely without it. JRA.
1136          */
1137
1138         if (mangled && !conn->case_sensitive) {
1139                 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1140                                                        &unmangled_name,
1141                                                        conn->params);
1142                 if (!mangled) {
1143                         /* Name is now unmangled. */
1144                         name = unmangled_name;
1145                 }
1146         }
1147
1148         /* open the directory */
1149         if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) {
1150                 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1151                 TALLOC_FREE(unmangled_name);
1152                 return -1;
1153         }
1154
1155         /* now scan for matching names */
1156         curpos = 0;
1157         while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1158
1159                 /* Is it dot or dot dot. */
1160                 if (ISDOT(dname) || ISDOTDOT(dname)) {
1161                         TALLOC_FREE(talloced);
1162                         continue;
1163                 }
1164
1165                 /*
1166                  * At this point dname is the unmangled name.
1167                  * name is either mangled or not, depending on the state
1168                  * of the "mangled" variable. JRA.
1169                  */
1170
1171                 /*
1172                  * Check mangled name against mangled name, or unmangled name
1173                  * against unmangled name.
1174                  */
1175
1176                 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1177                         fname_equal(name, dname, conn->case_sensitive)) {
1178                         /* we've found the file, change it's name and return */
1179                         *found_name = talloc_strdup(mem_ctx, dname);
1180                         TALLOC_FREE(unmangled_name);
1181                         TALLOC_FREE(cur_dir);
1182                         if (!*found_name) {
1183                                 errno = ENOMEM;
1184                                 TALLOC_FREE(talloced);
1185                                 return -1;
1186                         }
1187                         TALLOC_FREE(talloced);
1188                         return 0;
1189                 }
1190                 TALLOC_FREE(talloced);
1191         }
1192
1193         TALLOC_FREE(unmangled_name);
1194         TALLOC_FREE(cur_dir);
1195         errno = ENOENT;
1196         return -1;
1197 }
1198
1199 /****************************************************************************
1200  Wrapper around the vfs get_real_filename and the full directory scan
1201  fallback.
1202 ****************************************************************************/
1203
1204 int get_real_filename(connection_struct *conn, const char *path,
1205                       const char *name, TALLOC_CTX *mem_ctx,
1206                       char **found_name)
1207 {
1208         int ret;
1209         bool mangled;
1210
1211         mangled = mangle_is_mangled(name, conn->params);
1212
1213         if (mangled) {
1214                 return get_real_filename_full_scan(conn, path, name, mangled,
1215                                                    mem_ctx, found_name);
1216         }
1217
1218         /* Try the vfs first to take advantage of case-insensitive stat. */
1219         ret = SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name);
1220
1221         /*
1222          * If the case-insensitive stat was successful, or returned an error
1223          * other than EOPNOTSUPP then there is no need to fall back on the
1224          * full directory scan.
1225          */
1226         if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1227                 return ret;
1228         }
1229
1230         return get_real_filename_full_scan(conn, path, name, mangled, mem_ctx,
1231                                            found_name);
1232 }
1233
1234 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1235                                   connection_struct *conn,
1236                                   const char *orig_path,
1237                                   struct smb_filename *smb_fname)
1238 {
1239         NTSTATUS status;
1240         unsigned int i, num_streams = 0;
1241         struct stream_struct *streams = NULL;
1242
1243         if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1244                 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1245                 return NT_STATUS_OK;
1246         }
1247
1248         if (errno != ENOENT) {
1249                 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1250                 status = map_nt_error_from_unix(errno);
1251                 goto fail;
1252         }
1253
1254         /* Fall back to a case-insensitive scan of all streams on the file. */
1255         status = vfs_streaminfo(conn, NULL, smb_fname->base_name, mem_ctx,
1256                                 &num_streams, &streams);
1257
1258         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1259                 SET_STAT_INVALID(smb_fname->st);
1260                 return NT_STATUS_OK;
1261         }
1262
1263         if (!NT_STATUS_IS_OK(status)) {
1264                 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
1265                 goto fail;
1266         }
1267
1268         for (i=0; i<num_streams; i++) {
1269                 DEBUG(10, ("comparing [%s] and [%s]: ",
1270                            smb_fname->stream_name, streams[i].name));
1271                 if (fname_equal(smb_fname->stream_name, streams[i].name,
1272                                 conn->case_sensitive)) {
1273                         DEBUGADD(10, ("equal\n"));
1274                         break;
1275                 }
1276                 DEBUGADD(10, ("not equal\n"));
1277         }
1278
1279         /* Couldn't find the stream. */
1280         if (i == num_streams) {
1281                 SET_STAT_INVALID(smb_fname->st);
1282                 TALLOC_FREE(streams);
1283                 return NT_STATUS_OK;
1284         }
1285
1286         DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1287                 smb_fname->stream_name, streams[i].name));
1288
1289
1290         TALLOC_FREE(smb_fname->stream_name);
1291         smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1292         if (smb_fname->stream_name == NULL) {
1293                 status = NT_STATUS_NO_MEMORY;
1294                 goto fail;
1295         }
1296
1297         SET_STAT_INVALID(smb_fname->st);
1298
1299         if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1300                 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1301         }
1302         status = NT_STATUS_OK;
1303  fail:
1304         TALLOC_FREE(streams);
1305         return status;
1306 }
1307
1308 /**
1309  * Go through all the steps to validate a filename.
1310  *
1311  * @param ctx           talloc_ctx to allocate memory with.
1312  * @param conn          connection struct for vfs calls.
1313  * @param dfs_path      Whether this path requires dfs resolution.
1314  * @param smbreq        SMB request if we're using privileges.
1315  * @param name_in       The unconverted name.
1316  * @param ucf_flags     flags to pass through to unix_convert().
1317  *                      UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
1318  *                      p_cont_wcard != NULL and is true and
1319  *                      UCF_COND_ALLOW_WCARD_LCOMP.
1320  * @param p_cont_wcard  If not NULL, will be set to true if the dfs path
1321  *                      resolution detects a wildcard.
1322  * @param pp_smb_fname  The final converted name will be allocated if the
1323  *                      return is NT_STATUS_OK.
1324  *
1325  * @return NT_STATUS_OK if all operations completed succesfully, appropriate
1326  *         error otherwise.
1327  */
1328 static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
1329                                 connection_struct *conn,
1330                                 bool dfs_path,
1331                                 struct smb_request *smbreq,
1332                                 const char *name_in,
1333                                 uint32_t ucf_flags,
1334                                 bool *ppath_contains_wcard,
1335                                 struct smb_filename **pp_smb_fname)
1336 {
1337         NTSTATUS status;
1338         bool allow_wcards = (ucf_flags & (UCF_COND_ALLOW_WCARD_LCOMP|UCF_ALWAYS_ALLOW_WCARD_LCOMP));
1339         char *fname = NULL;
1340
1341         *pp_smb_fname = NULL;
1342
1343         status = resolve_dfspath_wcard(ctx, conn,
1344                                 dfs_path,
1345                                 name_in,
1346                                 allow_wcards,
1347                                 !conn->sconn->using_smb2,
1348                                 &fname,
1349                                 ppath_contains_wcard);
1350         if (!NT_STATUS_IS_OK(status)) {
1351                 DEBUG(10,("filename_convert_internal: resolve_dfspath failed "
1352                         "for name %s with %s\n",
1353                         name_in,
1354                         nt_errstr(status) ));
1355                 return status;
1356         }
1357
1358         if (is_fake_file_path(name_in)) {
1359                 SMB_STRUCT_STAT st;
1360                 ZERO_STRUCT(st);
1361                 st.st_ex_nlink = 1;
1362                 *pp_smb_fname = synthetic_smb_fname_split(ctx,
1363                                                           name_in,
1364                                                           &st);
1365                 if (*pp_smb_fname == NULL) {
1366                         return NT_STATUS_NO_MEMORY;
1367                 }
1368                 return NT_STATUS_OK;
1369         }
1370
1371         /*
1372          * If the caller conditionally allows wildcard lookups, only add the
1373          * always allow if the path actually does contain a wildcard.
1374          */
1375         if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP &&
1376             ppath_contains_wcard != NULL && *ppath_contains_wcard) {
1377                 ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
1378         }
1379
1380         status = unix_convert(ctx, conn, fname, pp_smb_fname, ucf_flags);
1381         if (!NT_STATUS_IS_OK(status)) {
1382                 DEBUG(10,("filename_convert_internal: unix_convert failed "
1383                         "for name %s with %s\n",
1384                         fname,
1385                         nt_errstr(status) ));
1386                 return status;
1387         }
1388
1389         if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) &&
1390                         VALID_STAT((*pp_smb_fname)->st) &&
1391                         S_ISLNK((*pp_smb_fname)->st.st_ex_mode)) {
1392                 return check_veto_path(conn, (*pp_smb_fname)->base_name);
1393         }
1394
1395         if (!smbreq) {
1396                 status = check_name(conn, (*pp_smb_fname)->base_name);
1397         } else {
1398                 status = check_name_with_privilege(conn, smbreq, (*pp_smb_fname)->base_name);
1399         }
1400         if (!NT_STATUS_IS_OK(status)) {
1401                 DEBUG(3,("filename_convert_internal: check_name failed "
1402                         "for name %s with %s\n",
1403                         smb_fname_str_dbg(*pp_smb_fname),
1404                         nt_errstr(status) ));
1405                 TALLOC_FREE(*pp_smb_fname);
1406                 return status;
1407         }
1408
1409         return status;
1410 }
1411
1412 /*
1413  * Go through all the steps to validate a filename.
1414  * Non-root version.
1415  */
1416
1417 NTSTATUS filename_convert(TALLOC_CTX *ctx,
1418                                 connection_struct *conn,
1419                                 bool dfs_path,
1420                                 const char *name_in,
1421                                 uint32_t ucf_flags,
1422                                 bool *ppath_contains_wcard,
1423                                 struct smb_filename **pp_smb_fname)
1424 {
1425         return filename_convert_internal(ctx,
1426                                         conn,
1427                                         dfs_path,
1428                                         NULL,
1429                                         name_in,
1430                                         ucf_flags,
1431                                         ppath_contains_wcard,
1432                                         pp_smb_fname);
1433 }
1434
1435 /*
1436  * Go through all the steps to validate a filename.
1437  * root (privileged) version.
1438  */
1439
1440 NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
1441                                 connection_struct *conn,
1442                                 struct smb_request *smbreq,
1443                                 const char *name_in,
1444                                 uint32_t ucf_flags,
1445                                 bool *ppath_contains_wcard,
1446                                 struct smb_filename **pp_smb_fname)
1447 {
1448         return filename_convert_internal(ctx,
1449                                         conn,
1450                                         smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
1451                                         smbreq,
1452                                         name_in,
1453                                         ucf_flags,
1454                                         ppath_contains_wcard,
1455                                         pp_smb_fname);
1456 }