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