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