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