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