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