auth4: avoid map_user_info() in auth_check_password_send()
[Samba.git] / source3 / smbd / filename.c
blob2d85e8de0b550df4483bee384eabd20d0aa49aad
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
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.
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.
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/>.
24 * New hash table stat cache code added by Ying Chen.
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "fake_file.h"
30 #include "smbd/smbd.h"
31 #include "smbd/globals.h"
33 uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
35 uint32_t ucf_flags = 0;
37 if (req != NULL && req->posix_pathnames) {
38 ucf_flags |= UCF_POSIX_PATHNAMES;
41 switch (create_disposition) {
42 case FILE_OPEN:
43 case FILE_OVERWRITE:
44 break;
45 case FILE_SUPERSEDE:
46 case FILE_CREATE:
47 case FILE_OPEN_IF:
48 case FILE_OVERWRITE_IF:
49 ucf_flags |= UCF_PREP_CREATEFILE;
50 break;
53 return ucf_flags;
56 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
57 connection_struct *conn,
58 struct smb_filename *smb_fname);
60 /****************************************************************************
61 Mangle the 2nd name and check if it is then equal to the first name.
62 ****************************************************************************/
64 static bool mangled_equal(const char *name1,
65 const char *name2,
66 const struct share_params *p)
68 char mname[13];
70 if (!name_to_8_3(name2, mname, False, p)) {
71 return False;
73 return strequal(name1, mname);
76 /****************************************************************************
77 Cope with the differing wildcard and non-wildcard error cases.
78 ****************************************************************************/
80 static NTSTATUS determine_path_error(const char *name,
81 bool allow_wcard_last_component,
82 bool posix_pathnames)
84 const char *p;
85 bool name_has_wild = false;
87 if (!allow_wcard_last_component) {
88 /* Error code within a pathname. */
89 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
92 /* We're terminating here so we
93 * can be a little slower and get
94 * the error code right. Windows
95 * treats the last part of the pathname
96 * separately I think, so if the last
97 * component is a wildcard then we treat
98 * this ./ as "end of component" */
100 p = strchr(name, '/');
102 if (!posix_pathnames) {
103 name_has_wild = ms_has_wild(name);
106 if (!p && (name_has_wild || ISDOT(name))) {
107 /* Error code at the end of a pathname. */
108 return NT_STATUS_OBJECT_NAME_INVALID;
109 } else {
110 /* Error code within a pathname. */
111 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
115 static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
117 /* Ensure we catch all names with in "/."
118 this is disallowed under Windows and
119 in POSIX they've already been removed. */
120 const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
121 if (p) {
122 if (p[2] == '/') {
123 /* Error code within a pathname. */
124 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
125 } else if (p[2] == '\0') {
126 /* Error code at the end of a pathname. */
127 return NT_STATUS_OBJECT_NAME_INVALID;
130 return NT_STATUS_OK;
133 /****************************************************************************
134 Optimization for common case where the missing part
135 is in the last component and the client already
136 sent the correct case.
137 Returns NT_STATUS_OK to mean continue the tree walk
138 (possibly with modified start pointer).
139 Any other NT_STATUS_XXX error means terminate the path
140 lookup here.
141 ****************************************************************************/
143 static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
144 connection_struct *conn,
145 bool posix_pathnames,
146 const struct smb_filename *smb_fname,
147 char **pp_dirpath,
148 char **pp_start)
150 struct smb_filename parent_fname;
151 const char *last_component = NULL;
152 NTSTATUS status;
153 int ret;
154 bool parent_fname_has_wild = false;
156 ZERO_STRUCT(parent_fname);
157 if (!parent_dirname(ctx, smb_fname->base_name,
158 &parent_fname.base_name,
159 &last_component)) {
160 return NT_STATUS_NO_MEMORY;
163 if (!posix_pathnames) {
164 parent_fname_has_wild = ms_has_wild(parent_fname.base_name);
168 * If there was no parent component in
169 * smb_fname->base_name of the parent name
170 * contained a wildcard then don't do this
171 * optimization.
173 if ((smb_fname->base_name == last_component) ||
174 parent_fname_has_wild) {
175 return NT_STATUS_OK;
178 if (posix_pathnames) {
179 ret = SMB_VFS_LSTAT(conn, &parent_fname);
180 } else {
181 ret = SMB_VFS_STAT(conn, &parent_fname);
184 /* If the parent stat failed, just continue
185 with the normal tree walk. */
187 if (ret == -1) {
188 return NT_STATUS_OK;
191 status = check_for_dot_component(&parent_fname);
192 if (!NT_STATUS_IS_OK(status)) {
193 return status;
196 /* Parent exists - set "start" to be the
197 * last component to shorten the tree walk. */
200 * Safe to use discard_const_p
201 * here as last_component points
202 * into our smb_fname->base_name.
204 *pp_start = discard_const_p(char, last_component);
206 /* Update dirpath. */
207 TALLOC_FREE(*pp_dirpath);
208 *pp_dirpath = talloc_strdup(ctx, parent_fname.base_name);
209 if (!*pp_dirpath) {
210 return NT_STATUS_NO_MEMORY;
213 DEBUG(5,("check_parent_exists: name "
214 "= %s, dirpath = %s, "
215 "start = %s\n",
216 smb_fname->base_name,
217 *pp_dirpath,
218 *pp_start));
220 return NT_STATUS_OK;
224 * Re-order a known good @GMT-token path.
227 static NTSTATUS rearrange_snapshot_path(struct smb_filename *smb_fname,
228 char *startp,
229 char *endp)
231 size_t endlen = 0;
232 size_t gmt_len = endp - startp;
233 char gmt_store[gmt_len + 1];
234 char *parent = NULL;
235 const char *last_component = NULL;
236 char *newstr;
237 bool ret;
239 DBG_DEBUG("|%s| -> ", smb_fname->base_name);
241 /* Save off the @GMT-token. */
242 memcpy(gmt_store, startp, gmt_len);
243 gmt_store[gmt_len] = '\0';
245 if (*endp == '/') {
246 /* Remove any trailing '/' */
247 endp++;
250 if (*endp == '\0') {
252 * @GMT-token was at end of path.
253 * Remove any preceeding '/'
255 if (startp > smb_fname->base_name && startp[-1] == '/') {
256 startp--;
260 /* Remove @GMT-token from the path. */
261 endlen = strlen(endp);
262 memmove(startp, endp, endlen + 1);
264 /* Split the remaining path into components. */
265 ret = parent_dirname(smb_fname,
266 smb_fname->base_name,
267 &parent,
268 &last_component);
269 if (ret == false) {
270 /* Must terminate debug with \n */
271 DBG_DEBUG("NT_STATUS_NO_MEMORY\n");
272 return NT_STATUS_NO_MEMORY;
275 if (ISDOT(parent)) {
276 if (last_component[0] == '\0') {
277 newstr = talloc_strdup(smb_fname,
278 gmt_store);
279 } else {
280 newstr = talloc_asprintf(smb_fname,
281 "%s/%s",
282 gmt_store,
283 last_component);
285 } else {
286 newstr = talloc_asprintf(smb_fname,
287 "%s/%s/%s",
288 gmt_store,
289 parent,
290 last_component);
293 TALLOC_FREE(parent);
294 TALLOC_FREE(smb_fname->base_name);
295 smb_fname->base_name = newstr;
297 DBG_DEBUG("|%s|\n", newstr);
299 return NT_STATUS_OK;
303 * Canonicalize any incoming pathname potentially containining
304 * a @GMT-token into a path that looks like:
306 * @GMT-YYYY-MM-DD-HH-MM-SS/path/name/components/last_component
308 * Leaves single path @GMT-token -component alone:
310 * @GMT-YYYY-MM-DD-HH-MM-SS -> @GMT-YYYY-MM-DD-HH-MM-SS
312 * Eventually when struct smb_filename is updated and the VFS
313 * ABI is changed this will remove the @GMT-YYYY-MM-DD-HH-MM-SS
314 * and store in the struct smb_filename as a struct timeval field
315 * instead.
318 static NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname)
320 char *startp = strchr_m(smb_fname->base_name, '@');
321 char *endp = NULL;
322 struct tm tm;
324 if (startp == NULL) {
325 /* No @ */
326 return NT_STATUS_OK;
329 startp = strstr_m(startp, "@GMT-");
330 if (startp == NULL) {
331 /* No @ */
332 return NT_STATUS_OK;
335 if ((startp > smb_fname->base_name) && (startp[-1] != '/')) {
336 /* the GMT-token does not start a path-component */
337 return NT_STATUS_OK;
340 endp = strptime(startp, GMT_FORMAT, &tm);
341 if (endp == NULL) {
342 /* Not a valid timestring. */
343 return NT_STATUS_OK;
346 if ( endp[0] == '\0') {
347 return rearrange_snapshot_path(smb_fname,
348 startp,
349 endp);
352 if (endp[0] != '/') {
354 * It is not a complete path component, i.e. the path
355 * component continues after the gmt-token.
357 return NT_STATUS_OK;
360 return rearrange_snapshot_path(smb_fname,
361 startp,
362 endp);
365 /****************************************************************************
366 This routine is called to convert names from the dos namespace to unix
367 namespace. It needs to handle any case conversions, mangling, format changes,
368 streams etc.
370 We assume that we have already done a chdir() to the right "root" directory
371 for this service.
373 The function will return an NTSTATUS error if some part of the name except for
374 the last part cannot be resolved, else NT_STATUS_OK.
376 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
377 didn't get any fatal errors that should immediately terminate the calling SMB
378 processing whilst resolving.
380 If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
381 of the pathname is set in smb_filename->original_lcomp.
383 If UCF_ALWAYS_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected
384 and should be allowed in the last component of the path only.
386 If the orig_path was a stream, smb_filename->base_name will point to the base
387 filename, and smb_filename->stream_name will point to the stream name. If
388 orig_path was not a stream, then smb_filename->stream_name will be NULL.
390 On exit from unix_convert, the smb_filename->st stat struct will be populated
391 if the file exists and was found, if not this stat struct will be filled with
392 zeros (and this can be detected by checking for nlinks = 0, which can never be
393 true for any file).
394 ****************************************************************************/
396 NTSTATUS unix_convert(TALLOC_CTX *ctx,
397 connection_struct *conn,
398 const char *orig_path,
399 struct smb_filename **smb_fname_out,
400 uint32_t ucf_flags)
402 struct smb_filename *smb_fname = NULL;
405 * This looks strange. But we need "start" initialized to "" here but
406 * it can't be a const char *, so 'char *start = "";' does not work.
408 char cnull = '\0';
409 char *start = &cnull;
411 char *end;
412 char *dirpath = NULL;
413 char *stream = NULL;
414 bool component_was_mangled = False;
415 bool name_has_wildcard = False;
416 bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
417 bool allow_wcard_last_component =
418 (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
419 bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
420 NTSTATUS status;
421 int ret = -1;
423 *smb_fname_out = NULL;
425 smb_fname = talloc_zero(ctx, struct smb_filename);
426 if (smb_fname == NULL) {
427 return NT_STATUS_NO_MEMORY;
430 if (conn->printer) {
431 /* we don't ever use the filenames on a printer share as a
432 filename - so don't convert them */
433 if (!(smb_fname->base_name = talloc_strdup(smb_fname,
434 orig_path))) {
435 status = NT_STATUS_NO_MEMORY;
436 goto err;
438 goto done;
441 smb_fname->flags = posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
443 DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
446 * Conversion to basic unix format is already done in
447 * check_path_syntax().
451 * Names must be relative to the root of the service - any leading /.
452 * and trailing /'s should have been trimmed by check_path_syntax().
455 #ifdef DEVELOPER
456 SMB_ASSERT(*orig_path != '/');
457 #endif
460 * If we trimmed down to a single '\0' character
461 * then we should use the "." directory to avoid
462 * searching the cache, but not if we are in a
463 * printing share.
464 * As we know this is valid we can return true here.
467 if (!*orig_path) {
468 if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) {
469 status = NT_STATUS_NO_MEMORY;
470 goto err;
472 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
473 status = map_nt_error_from_unix(errno);
474 goto err;
476 DEBUG(5, ("conversion finished \"\" -> %s\n",
477 smb_fname->base_name));
478 goto done;
481 if (orig_path[0] == '.' && (orig_path[1] == '/' ||
482 orig_path[1] == '\0')) {
483 /* Start of pathname can't be "." only. */
484 if (orig_path[1] == '\0' || orig_path[2] == '\0') {
485 status = NT_STATUS_OBJECT_NAME_INVALID;
486 } else {
487 status =determine_path_error(&orig_path[2],
488 allow_wcard_last_component,
489 posix_pathnames);
491 goto err;
494 /* Start with the full orig_path as given by the caller. */
495 if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) {
496 DEBUG(0, ("talloc_strdup failed\n"));
497 status = NT_STATUS_NO_MEMORY;
498 goto err;
501 /* Canonicalize any @GMT- paths. */
502 if (posix_pathnames == false) {
503 status = canonicalize_snapshot_path(smb_fname);
504 if (!NT_STATUS_IS_OK(status)) {
505 goto err;
510 * Large directory fix normalization. If we're case sensitive, and
511 * the case preserving parameters are set to "no", normalize the case of
512 * the incoming filename from the client WHETHER IT EXISTS OR NOT !
513 * This is in conflict with the current (3.0.20) man page, but is
514 * what people expect from the "large directory howto". I'll update
515 * the man page. Thanks to jht@samba.org for finding this. JRA.
518 if (conn->case_sensitive && !conn->case_preserve &&
519 !conn->short_case_preserve) {
520 if (!strnorm(smb_fname->base_name, lp_default_case(SNUM(conn)))) {
521 DEBUG(0, ("strnorm %s failed\n", smb_fname->base_name));
522 status = NT_STATUS_INVALID_PARAMETER;
523 goto err;
528 * Ensure saved_last_component is valid even if file exists.
531 if(save_last_component) {
532 end = strrchr_m(smb_fname->base_name, '/');
533 if (end) {
534 smb_fname->original_lcomp = talloc_strdup(smb_fname,
535 end + 1);
536 } else {
537 smb_fname->original_lcomp =
538 talloc_strdup(smb_fname, smb_fname->base_name);
540 if (smb_fname->original_lcomp == NULL) {
541 status = NT_STATUS_NO_MEMORY;
542 goto err;
547 * Strip off the stream, and add it back when we're done with the
548 * base_name.
550 if (!posix_pathnames) {
551 stream = strchr_m(smb_fname->base_name, ':');
553 if (stream != NULL) {
554 char *tmp = talloc_strdup(smb_fname, stream);
555 if (tmp == NULL) {
556 status = NT_STATUS_NO_MEMORY;
557 goto err;
560 * Since this is actually pointing into
561 * smb_fname->base_name this truncates base_name.
563 *stream = '\0';
564 stream = tmp;
566 if (smb_fname->base_name[0] == '\0') {
568 * orig_name was just a stream name.
569 * This is a stream on the root of
570 * the share. Replace base_name with
571 * a "."
573 smb_fname->base_name =
574 talloc_strdup(smb_fname, ".");
575 if (smb_fname->base_name == NULL) {
576 status = NT_STATUS_NO_MEMORY;
577 goto err;
579 if (SMB_VFS_STAT(conn, smb_fname) != 0) {
580 status = map_nt_error_from_unix(errno);
581 goto err;
583 /* dirpath must exist. */
584 dirpath = talloc_strdup(ctx,"");
585 if (dirpath == NULL) {
586 status = NT_STATUS_NO_MEMORY;
587 goto err;
589 DEBUG(5, ("conversion finished %s -> %s\n",
590 orig_path,
591 smb_fname->base_name));
592 goto done;
597 start = smb_fname->base_name;
600 * If we're providing case insensitive semantics or
601 * the underlying filesystem is case insensitive,
602 * then a case-normalized hit in the stat-cache is
603 * authoratitive. JRA.
605 * Note: We're only checking base_name. The stream_name will be
606 * added and verified in build_stream_path().
609 if((!conn->case_sensitive || !(conn->fs_capabilities &
610 FILE_CASE_SENSITIVE_SEARCH)) &&
611 stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start,
612 &smb_fname->st)) {
613 goto done;
617 * Make sure "dirpath" is an allocated string, we use this for
618 * building the directories with talloc_asprintf and free it.
621 if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
622 DEBUG(0, ("talloc_strdup failed\n"));
623 status = NT_STATUS_NO_MEMORY;
624 goto err;
628 * If we have a wildcard we must walk the path to
629 * find where the error is, even if case sensitive
630 * is true.
633 if (!posix_pathnames) {
634 /* POSIX pathnames have no wildcards. */
635 name_has_wildcard = ms_has_wild(smb_fname->base_name);
636 if (name_has_wildcard && !allow_wcard_last_component) {
637 /* Wildcard not valid anywhere. */
638 status = NT_STATUS_OBJECT_NAME_INVALID;
639 goto fail;
643 DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
644 smb_fname->base_name, dirpath, start));
646 if (!name_has_wildcard) {
648 * stat the name - if it exists then we can add the stream back (if
649 * there was one) and be done!
652 if (posix_pathnames) {
653 ret = SMB_VFS_LSTAT(conn, smb_fname);
654 } else {
655 ret = SMB_VFS_STAT(conn, smb_fname);
658 if (ret == 0) {
659 status = check_for_dot_component(smb_fname);
660 if (!NT_STATUS_IS_OK(status)) {
661 goto fail;
663 /* Add the path (not including the stream) to the cache. */
664 stat_cache_add(orig_path, smb_fname->base_name,
665 conn->case_sensitive);
666 DEBUG(5,("conversion of base_name finished %s -> %s\n",
667 orig_path, smb_fname->base_name));
668 goto done;
671 /* Stat failed - ensure we don't use it. */
672 SET_STAT_INVALID(smb_fname->st);
674 if (errno == ENOENT) {
675 /* Optimization when creating a new file - only
676 the last component doesn't exist.
677 NOTE : check_parent_exists() doesn't preserve errno.
679 int saved_errno = errno;
680 status = check_parent_exists(ctx,
681 conn,
682 posix_pathnames,
683 smb_fname,
684 &dirpath,
685 &start);
686 errno = saved_errno;
687 if (!NT_STATUS_IS_OK(status)) {
688 goto fail;
693 * A special case - if we don't have any wildcards or mangling chars and are case
694 * sensitive or the underlying filesystem is case insensitive then searching
695 * won't help.
698 if ((conn->case_sensitive || !(conn->fs_capabilities &
699 FILE_CASE_SENSITIVE_SEARCH)) &&
700 !mangle_is_mangled(smb_fname->base_name, conn->params)) {
702 status = check_for_dot_component(smb_fname);
703 if (!NT_STATUS_IS_OK(status)) {
704 goto fail;
708 * The stat failed. Could be ok as it could be
709 * a new file.
712 if (errno == ENOTDIR || errno == ELOOP) {
713 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
714 goto fail;
715 } else if (errno == ENOENT) {
717 * Was it a missing last component ?
718 * or a missing intermediate component ?
720 struct smb_filename parent_fname;
721 const char *last_component = NULL;
723 ZERO_STRUCT(parent_fname);
724 if (!parent_dirname(ctx, smb_fname->base_name,
725 &parent_fname.base_name,
726 &last_component)) {
727 status = NT_STATUS_NO_MEMORY;
728 goto fail;
730 if (posix_pathnames) {
731 ret = SMB_VFS_LSTAT(conn, &parent_fname);
732 } else {
733 ret = SMB_VFS_STAT(conn, &parent_fname);
735 if (ret == -1) {
736 if (errno == ENOTDIR ||
737 errno == ENOENT ||
738 errno == ELOOP) {
739 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
740 goto fail;
745 * Missing last component is ok - new file.
746 * Also deal with permission denied elsewhere.
747 * Just drop out to done.
749 goto done;
752 } else {
754 * We have a wildcard in the pathname.
756 * Optimization for common case where the wildcard
757 * is in the last component and the client already
758 * sent the correct case.
759 * NOTE : check_parent_exists() doesn't preserve errno.
761 int saved_errno = errno;
762 status = check_parent_exists(ctx,
763 conn,
764 posix_pathnames,
765 smb_fname,
766 &dirpath,
767 &start);
768 errno = saved_errno;
769 if (!NT_STATUS_IS_OK(status)) {
770 goto fail;
775 * is_mangled() was changed to look at an entire pathname, not
776 * just a component. JRA.
779 if (mangle_is_mangled(start, conn->params)) {
780 component_was_mangled = True;
784 * Now we need to recursively match the name against the real
785 * directory structure.
789 * Match each part of the path name separately, trying the names
790 * as is first, then trying to scan the directory for matching names.
793 for (; start ; start = (end?end+1:(char *)NULL)) {
795 * Pinpoint the end of this section of the filename.
797 /* mb safe. '/' can't be in any encoded char. */
798 end = strchr(start, '/');
801 * Chop the name at this point.
803 if (end) {
804 *end = 0;
807 if (save_last_component) {
808 TALLOC_FREE(smb_fname->original_lcomp);
809 smb_fname->original_lcomp = talloc_strdup(smb_fname,
810 end ? end + 1 : start);
811 if (!smb_fname->original_lcomp) {
812 DEBUG(0, ("talloc failed\n"));
813 status = NT_STATUS_NO_MEMORY;
814 goto err;
818 /* The name cannot have a component of "." */
820 if (ISDOT(start)) {
821 if (!end) {
822 /* Error code at the end of a pathname. */
823 status = NT_STATUS_OBJECT_NAME_INVALID;
824 } else {
825 status = determine_path_error(end+1,
826 allow_wcard_last_component,
827 posix_pathnames);
829 goto fail;
832 /* The name cannot have a wildcard if it's not
833 the last component. */
835 if (!posix_pathnames) {
836 name_has_wildcard = ms_has_wild(start);
839 /* Wildcards never valid within a pathname. */
840 if (name_has_wildcard && end) {
841 status = NT_STATUS_OBJECT_NAME_INVALID;
842 goto fail;
845 /* Skip the stat call if it's a wildcard end. */
846 if (name_has_wildcard) {
847 DEBUG(5,("Wildcard %s\n",start));
848 goto done;
852 * Check if the name exists up to this point.
855 if (posix_pathnames) {
856 ret = SMB_VFS_LSTAT(conn, smb_fname);
857 } else {
858 ret = SMB_VFS_STAT(conn, smb_fname);
861 if (ret == 0) {
863 * It exists. it must either be a directory or this must
864 * be the last part of the path for it to be OK.
866 if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) {
868 * An intermediate part of the name isn't
869 * a directory.
871 DEBUG(5,("Not a dir %s\n",start));
872 *end = '/';
874 * We need to return the fact that the
875 * intermediate name resolution failed. This
876 * is used to return an error of ERRbadpath
877 * rather than ERRbadfile. Some Windows
878 * applications depend on the difference between
879 * these two errors.
881 status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
882 goto fail;
885 } else {
886 char *found_name = NULL;
888 /* Stat failed - ensure we don't use it. */
889 SET_STAT_INVALID(smb_fname->st);
892 * Reset errno so we can detect
893 * directory open errors.
895 errno = 0;
898 * Try to find this part of the path in the directory.
901 if (name_has_wildcard ||
902 (get_real_filename(conn, dirpath, start,
903 talloc_tos(),
904 &found_name) == -1)) {
905 char *unmangled;
907 if (end) {
909 * An intermediate part of the name
910 * can't be found.
912 DEBUG(5,("Intermediate not found %s\n",
913 start));
914 *end = '/';
917 * We need to return the fact that the
918 * intermediate name resolution failed.
919 * This is used to return an error of
920 * ERRbadpath rather than ERRbadfile.
921 * Some Windows applications depend on
922 * the difference between these two
923 * errors.
927 * ENOENT, ENOTDIR and ELOOP all map
928 * to NT_STATUS_OBJECT_PATH_NOT_FOUND
929 * in the filename walk.
932 if (errno == ENOENT ||
933 errno == ENOTDIR ||
934 errno == ELOOP) {
935 status =
936 NT_STATUS_OBJECT_PATH_NOT_FOUND;
938 else {
939 status =
940 map_nt_error_from_unix(errno);
942 goto fail;
946 * ENOENT/EACCESS are the only valid errors
947 * here.
950 if (errno == EACCES) {
951 if ((ucf_flags & UCF_PREP_CREATEFILE) == 0) {
952 status = NT_STATUS_ACCESS_DENIED;
953 goto fail;
954 } else {
956 * This is the dropbox
957 * behaviour. A dropbox is a
958 * directory with only -wx
959 * permissions, so
960 * get_real_filename fails
961 * with EACCESS, it needs to
962 * list the directory. We
963 * nevertheless want to allow
964 * users creating a file.
966 errno = 0;
970 if ((errno != 0) && (errno != ENOENT)) {
972 * ENOTDIR and ELOOP both map to
973 * NT_STATUS_OBJECT_PATH_NOT_FOUND
974 * in the filename walk.
976 if (errno == ENOTDIR ||
977 errno == ELOOP) {
978 status =
979 NT_STATUS_OBJECT_PATH_NOT_FOUND;
980 } else {
981 status =
982 map_nt_error_from_unix(errno);
984 goto fail;
988 * Just the last part of the name doesn't exist.
989 * We need to strupper() or strlower() it as
990 * this conversion may be used for file creation
991 * purposes. Fix inspired by
992 * Thomas Neumann <t.neumann@iku-ag.de>.
994 if (!conn->case_preserve ||
995 (mangle_is_8_3(start, False,
996 conn->params) &&
997 !conn->short_case_preserve)) {
998 if (!strnorm(start,
999 lp_default_case(SNUM(conn)))) {
1000 DEBUG(0, ("strnorm %s failed\n",
1001 start));
1002 status = NT_STATUS_INVALID_PARAMETER;
1003 goto err;
1008 * check on the mangled stack to see if we can
1009 * recover the base of the filename.
1012 if (mangle_is_mangled(start, conn->params)
1013 && mangle_lookup_name_from_8_3(ctx,
1014 start,
1015 &unmangled,
1016 conn->params)) {
1017 char *tmp;
1018 size_t start_ofs =
1019 start - smb_fname->base_name;
1021 if (*dirpath != '\0') {
1022 tmp = talloc_asprintf(
1023 smb_fname, "%s/%s",
1024 dirpath, unmangled);
1025 TALLOC_FREE(unmangled);
1027 else {
1028 tmp = unmangled;
1030 if (tmp == NULL) {
1031 DEBUG(0, ("talloc failed\n"));
1032 status = NT_STATUS_NO_MEMORY;
1033 goto err;
1035 TALLOC_FREE(smb_fname->base_name);
1036 smb_fname->base_name = tmp;
1037 start =
1038 smb_fname->base_name + start_ofs;
1039 end = start + strlen(start);
1042 DEBUG(5,("New file %s\n",start));
1043 goto done;
1048 * Restore the rest of the string. If the string was
1049 * mangled the size may have changed.
1051 if (end) {
1052 char *tmp;
1053 size_t start_ofs =
1054 start - smb_fname->base_name;
1056 if (*dirpath != '\0') {
1057 tmp = talloc_asprintf(smb_fname,
1058 "%s/%s/%s", dirpath,
1059 found_name, end+1);
1061 else {
1062 tmp = talloc_asprintf(smb_fname,
1063 "%s/%s", found_name,
1064 end+1);
1066 if (tmp == NULL) {
1067 DEBUG(0, ("talloc_asprintf failed\n"));
1068 status = NT_STATUS_NO_MEMORY;
1069 goto err;
1071 TALLOC_FREE(smb_fname->base_name);
1072 smb_fname->base_name = tmp;
1073 start = smb_fname->base_name + start_ofs;
1074 end = start + strlen(found_name);
1075 *end = '\0';
1076 } else {
1077 char *tmp;
1078 size_t start_ofs =
1079 start - smb_fname->base_name;
1081 if (*dirpath != '\0') {
1082 tmp = talloc_asprintf(smb_fname,
1083 "%s/%s", dirpath,
1084 found_name);
1085 } else {
1086 tmp = talloc_strdup(smb_fname,
1087 found_name);
1089 if (tmp == NULL) {
1090 DEBUG(0, ("talloc failed\n"));
1091 status = NT_STATUS_NO_MEMORY;
1092 goto err;
1094 TALLOC_FREE(smb_fname->base_name);
1095 smb_fname->base_name = tmp;
1096 start = smb_fname->base_name + start_ofs;
1099 * We just scanned for, and found the end of
1100 * the path. We must return a valid stat struct
1101 * if it exists. JRA.
1104 if (posix_pathnames) {
1105 ret = SMB_VFS_LSTAT(conn, smb_fname);
1106 } else {
1107 ret = SMB_VFS_STAT(conn, smb_fname);
1110 if (ret != 0) {
1111 SET_STAT_INVALID(smb_fname->st);
1115 TALLOC_FREE(found_name);
1116 } /* end else */
1119 * Add to the dirpath that we have resolved so far.
1122 if (*dirpath != '\0') {
1123 char *tmp = talloc_asprintf(ctx,
1124 "%s/%s", dirpath, start);
1125 if (!tmp) {
1126 DEBUG(0, ("talloc_asprintf failed\n"));
1127 status = NT_STATUS_NO_MEMORY;
1128 goto err;
1130 TALLOC_FREE(dirpath);
1131 dirpath = tmp;
1133 else {
1134 TALLOC_FREE(dirpath);
1135 if (!(dirpath = talloc_strdup(ctx,start))) {
1136 DEBUG(0, ("talloc_strdup failed\n"));
1137 status = NT_STATUS_NO_MEMORY;
1138 goto err;
1143 * Cache the dirpath thus far. Don't cache a name with mangled
1144 * or wildcard components as this can change the size.
1146 if(!component_was_mangled && !name_has_wildcard) {
1147 stat_cache_add(orig_path, dirpath,
1148 conn->case_sensitive);
1152 * Restore the / that we wiped out earlier.
1154 if (end) {
1155 *end = '/';
1160 * Cache the full path. Don't cache a name with mangled or wildcard
1161 * components as this can change the size.
1164 if(!component_was_mangled && !name_has_wildcard) {
1165 stat_cache_add(orig_path, smb_fname->base_name,
1166 conn->case_sensitive);
1170 * The name has been resolved.
1173 DEBUG(5,("conversion finished %s -> %s\n", orig_path,
1174 smb_fname->base_name));
1176 done:
1177 /* Add back the stream if one was stripped off originally. */
1178 if (stream != NULL) {
1179 smb_fname->stream_name = stream;
1181 /* Check path now that the base_name has been converted. */
1182 status = build_stream_path(ctx, conn, smb_fname);
1183 if (!NT_STATUS_IS_OK(status)) {
1184 goto fail;
1187 TALLOC_FREE(dirpath);
1188 *smb_fname_out = smb_fname;
1189 return NT_STATUS_OK;
1190 fail:
1191 DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
1192 if (dirpath && *dirpath != '\0') {
1193 smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s",
1194 dirpath, start);
1195 } else {
1196 smb_fname->base_name = talloc_strdup(smb_fname, start);
1198 if (!smb_fname->base_name) {
1199 DEBUG(0, ("talloc_asprintf failed\n"));
1200 status = NT_STATUS_NO_MEMORY;
1201 goto err;
1204 *smb_fname_out = smb_fname;
1205 TALLOC_FREE(dirpath);
1206 return status;
1207 err:
1208 TALLOC_FREE(smb_fname);
1209 return status;
1212 /****************************************************************************
1213 Ensure a path is not vetoed.
1214 ****************************************************************************/
1216 static NTSTATUS check_veto_path(connection_struct *conn, const char *name)
1218 if (IS_VETO_PATH(conn, name)) {
1219 /* Is it not dot or dot dot. */
1220 if (!(ISDOT(name) || ISDOTDOT(name))) {
1221 DEBUG(5,("check_veto_path: file path name %s vetoed\n",
1222 name));
1223 return map_nt_error_from_unix(ENOENT);
1226 return NT_STATUS_OK;
1229 /****************************************************************************
1230 Check a filename - possibly calling check_reduced_name.
1231 This is called by every routine before it allows an operation on a filename.
1232 It does any final confirmation necessary to ensure that the filename is
1233 a valid one for the user to access.
1234 ****************************************************************************/
1236 NTSTATUS check_name(connection_struct *conn, const char *name)
1238 NTSTATUS status = check_veto_path(conn, name);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 return status;
1244 if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) {
1245 status = check_reduced_name(conn, NULL, name);
1246 if (!NT_STATUS_IS_OK(status)) {
1247 DEBUG(5,("check_name: name %s failed with %s\n",name,
1248 nt_errstr(status)));
1249 return status;
1253 return NT_STATUS_OK;
1256 /****************************************************************************
1257 Must be called as root. Creates the struct privilege_paths
1258 attached to the struct smb_request if this call is successful.
1259 ****************************************************************************/
1261 static NTSTATUS check_name_with_privilege(connection_struct *conn,
1262 struct smb_request *smbreq,
1263 const char *name)
1265 NTSTATUS status = check_veto_path(conn, name);
1267 if (!NT_STATUS_IS_OK(status)) {
1268 return status;
1270 return check_reduced_name_with_privilege(conn,
1271 name,
1272 smbreq);
1275 /****************************************************************************
1276 Check if two filenames are equal.
1277 This needs to be careful about whether we are case sensitive.
1278 ****************************************************************************/
1280 static bool fname_equal(const char *name1, const char *name2,
1281 bool case_sensitive)
1283 /* Normal filename handling */
1284 if (case_sensitive) {
1285 return(strcmp(name1,name2) == 0);
1288 return(strequal(name1,name2));
1291 /****************************************************************************
1292 Scan a directory to find a filename, matching without case sensitivity.
1293 If the name looks like a mangled name then try via the mangling functions
1294 ****************************************************************************/
1296 static int get_real_filename_full_scan(connection_struct *conn,
1297 const char *path, const char *name,
1298 bool mangled,
1299 TALLOC_CTX *mem_ctx, char **found_name)
1301 struct smb_Dir *cur_dir;
1302 const char *dname = NULL;
1303 char *talloced = NULL;
1304 char *unmangled_name = NULL;
1305 long curpos;
1306 struct smb_filename *smb_fname = NULL;
1308 /* handle null paths */
1309 if ((path == NULL) || (*path == 0)) {
1310 path = ".";
1313 /* If we have a case-sensitive filesystem, it doesn't do us any
1314 * good to search for a name. If a case variation of the name was
1315 * there, then the original stat(2) would have found it.
1317 if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) {
1318 errno = ENOENT;
1319 return -1;
1323 * The incoming name can be mangled, and if we de-mangle it
1324 * here it will not compare correctly against the filename (name2)
1325 * read from the directory and then mangled by the name_to_8_3()
1326 * call. We need to mangle both names or neither.
1327 * (JRA).
1329 * Fix for bug found by Dina Fine. If in case sensitive mode then
1330 * the mangle cache is no good (3 letter extension could be wrong
1331 * case - so don't demangle in this case - leave as mangled and
1332 * allow the mangling of the directory entry read (which is done
1333 * case insensitively) to match instead. This will lead to more
1334 * false positive matches but we fail completely without it. JRA.
1337 if (mangled && !conn->case_sensitive) {
1338 mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name,
1339 &unmangled_name,
1340 conn->params);
1341 if (!mangled) {
1342 /* Name is now unmangled. */
1343 name = unmangled_name;
1347 smb_fname = synthetic_smb_fname(talloc_tos(),
1348 path,
1349 NULL,
1350 NULL,
1352 if (smb_fname == NULL) {
1353 TALLOC_FREE(unmangled_name);
1354 return -1;
1357 /* open the directory */
1358 if (!(cur_dir = OpenDir(talloc_tos(), conn, smb_fname, NULL, 0))) {
1359 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
1360 TALLOC_FREE(unmangled_name);
1361 TALLOC_FREE(smb_fname);
1362 return -1;
1365 TALLOC_FREE(smb_fname);
1367 /* now scan for matching names */
1368 curpos = 0;
1369 while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) {
1371 /* Is it dot or dot dot. */
1372 if (ISDOT(dname) || ISDOTDOT(dname)) {
1373 TALLOC_FREE(talloced);
1374 continue;
1378 * At this point dname is the unmangled name.
1379 * name is either mangled or not, depending on the state
1380 * of the "mangled" variable. JRA.
1384 * Check mangled name against mangled name, or unmangled name
1385 * against unmangled name.
1388 if ((mangled && mangled_equal(name,dname,conn->params)) ||
1389 fname_equal(name, dname, conn->case_sensitive)) {
1390 /* we've found the file, change it's name and return */
1391 *found_name = talloc_strdup(mem_ctx, dname);
1392 TALLOC_FREE(unmangled_name);
1393 TALLOC_FREE(cur_dir);
1394 if (!*found_name) {
1395 errno = ENOMEM;
1396 TALLOC_FREE(talloced);
1397 return -1;
1399 TALLOC_FREE(talloced);
1400 return 0;
1402 TALLOC_FREE(talloced);
1405 TALLOC_FREE(unmangled_name);
1406 TALLOC_FREE(cur_dir);
1407 errno = ENOENT;
1408 return -1;
1411 /****************************************************************************
1412 Wrapper around the vfs get_real_filename and the full directory scan
1413 fallback.
1414 ****************************************************************************/
1416 int get_real_filename(connection_struct *conn, const char *path,
1417 const char *name, TALLOC_CTX *mem_ctx,
1418 char **found_name)
1420 int ret;
1421 bool mangled;
1423 mangled = mangle_is_mangled(name, conn->params);
1425 if (mangled) {
1426 return get_real_filename_full_scan(conn, path, name, mangled,
1427 mem_ctx, found_name);
1430 /* Try the vfs first to take advantage of case-insensitive stat. */
1431 ret = SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name);
1434 * If the case-insensitive stat was successful, or returned an error
1435 * other than EOPNOTSUPP then there is no need to fall back on the
1436 * full directory scan.
1438 if (ret == 0 || (ret == -1 && errno != EOPNOTSUPP)) {
1439 return ret;
1442 return get_real_filename_full_scan(conn, path, name, mangled, mem_ctx,
1443 found_name);
1446 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
1447 connection_struct *conn,
1448 struct smb_filename *smb_fname)
1450 NTSTATUS status;
1451 unsigned int i, num_streams = 0;
1452 struct stream_struct *streams = NULL;
1454 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1455 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1456 return NT_STATUS_OK;
1459 if (errno != ENOENT) {
1460 DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno)));
1461 status = map_nt_error_from_unix(errno);
1462 goto fail;
1465 /* Fall back to a case-insensitive scan of all streams on the file. */
1466 status = vfs_streaminfo(conn, NULL, smb_fname, mem_ctx,
1467 &num_streams, &streams);
1469 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1470 SET_STAT_INVALID(smb_fname->st);
1471 return NT_STATUS_OK;
1474 if (!NT_STATUS_IS_OK(status)) {
1475 DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
1476 goto fail;
1479 for (i=0; i<num_streams; i++) {
1480 DEBUG(10, ("comparing [%s] and [%s]: ",
1481 smb_fname->stream_name, streams[i].name));
1482 if (fname_equal(smb_fname->stream_name, streams[i].name,
1483 conn->case_sensitive)) {
1484 DEBUGADD(10, ("equal\n"));
1485 break;
1487 DEBUGADD(10, ("not equal\n"));
1490 /* Couldn't find the stream. */
1491 if (i == num_streams) {
1492 SET_STAT_INVALID(smb_fname->st);
1493 TALLOC_FREE(streams);
1494 return NT_STATUS_OK;
1497 DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
1498 smb_fname->stream_name, streams[i].name));
1501 TALLOC_FREE(smb_fname->stream_name);
1502 smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name);
1503 if (smb_fname->stream_name == NULL) {
1504 status = NT_STATUS_NO_MEMORY;
1505 goto fail;
1508 SET_STAT_INVALID(smb_fname->st);
1510 if (SMB_VFS_STAT(conn, smb_fname) == 0) {
1511 DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname)));
1513 status = NT_STATUS_OK;
1514 fail:
1515 TALLOC_FREE(streams);
1516 return status;
1520 * Go through all the steps to validate a filename.
1522 * @param ctx talloc_ctx to allocate memory with.
1523 * @param conn connection struct for vfs calls.
1524 * @param dfs_path Whether this path requires dfs resolution.
1525 * @param smbreq SMB request if we're using privileges.
1526 * @param name_in The unconverted name.
1527 * @param ucf_flags flags to pass through to unix_convert().
1528 * UCF_ALWAYS_ALLOW_WCARD_LCOMP will be OR'd in if
1529 * p_cont_wcard != NULL and is true and
1530 * UCF_COND_ALLOW_WCARD_LCOMP.
1531 * @param p_cont_wcard If not NULL, will be set to true if the dfs path
1532 * resolution detects a wildcard.
1533 * @param pp_smb_fname The final converted name will be allocated if the
1534 * return is NT_STATUS_OK.
1536 * @return NT_STATUS_OK if all operations completed succesfully, appropriate
1537 * error otherwise.
1539 static NTSTATUS filename_convert_internal(TALLOC_CTX *ctx,
1540 connection_struct *conn,
1541 bool dfs_path,
1542 struct smb_request *smbreq,
1543 const char *name_in,
1544 uint32_t ucf_flags,
1545 bool *ppath_contains_wcard,
1546 struct smb_filename **pp_smb_fname)
1548 NTSTATUS status;
1549 char *fname = NULL;
1551 *pp_smb_fname = NULL;
1553 status = resolve_dfspath_wcard(ctx, conn,
1554 dfs_path,
1555 name_in,
1556 ucf_flags,
1557 !conn->sconn->using_smb2,
1558 &fname,
1559 ppath_contains_wcard);
1560 if (!NT_STATUS_IS_OK(status)) {
1561 DEBUG(10,("filename_convert_internal: resolve_dfspath failed "
1562 "for name %s with %s\n",
1563 name_in,
1564 nt_errstr(status) ));
1565 return status;
1568 if (is_fake_file_path(name_in)) {
1569 SMB_STRUCT_STAT st;
1570 ZERO_STRUCT(st);
1571 st.st_ex_nlink = 1;
1572 *pp_smb_fname = synthetic_smb_fname_split(ctx,
1573 name_in,
1574 (ucf_flags & UCF_POSIX_PATHNAMES));
1575 if (*pp_smb_fname == NULL) {
1576 return NT_STATUS_NO_MEMORY;
1578 (*pp_smb_fname)->st = st;
1579 return NT_STATUS_OK;
1583 * If the caller conditionally allows wildcard lookups, only add the
1584 * always allow if the path actually does contain a wildcard.
1586 if (ucf_flags & UCF_COND_ALLOW_WCARD_LCOMP &&
1587 ppath_contains_wcard != NULL && *ppath_contains_wcard) {
1588 ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
1591 status = unix_convert(ctx, conn, fname, pp_smb_fname, ucf_flags);
1592 if (!NT_STATUS_IS_OK(status)) {
1593 DEBUG(10,("filename_convert_internal: unix_convert failed "
1594 "for name %s with %s\n",
1595 fname,
1596 nt_errstr(status) ));
1597 return status;
1600 if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) &&
1601 VALID_STAT((*pp_smb_fname)->st) &&
1602 S_ISLNK((*pp_smb_fname)->st.st_ex_mode)) {
1603 return check_veto_path(conn, (*pp_smb_fname)->base_name);
1606 if (!smbreq) {
1607 status = check_name(conn, (*pp_smb_fname)->base_name);
1608 } else {
1609 status = check_name_with_privilege(conn, smbreq, (*pp_smb_fname)->base_name);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 DEBUG(3,("filename_convert_internal: check_name failed "
1613 "for name %s with %s\n",
1614 smb_fname_str_dbg(*pp_smb_fname),
1615 nt_errstr(status) ));
1616 TALLOC_FREE(*pp_smb_fname);
1617 return status;
1620 return status;
1624 * Go through all the steps to validate a filename.
1625 * Non-root version.
1628 NTSTATUS filename_convert(TALLOC_CTX *ctx,
1629 connection_struct *conn,
1630 bool dfs_path,
1631 const char *name_in,
1632 uint32_t ucf_flags,
1633 bool *ppath_contains_wcard,
1634 struct smb_filename **pp_smb_fname)
1636 return filename_convert_internal(ctx,
1637 conn,
1638 dfs_path,
1639 NULL,
1640 name_in,
1641 ucf_flags,
1642 ppath_contains_wcard,
1643 pp_smb_fname);
1647 * Go through all the steps to validate a filename.
1648 * root (privileged) version.
1651 NTSTATUS filename_convert_with_privilege(TALLOC_CTX *ctx,
1652 connection_struct *conn,
1653 struct smb_request *smbreq,
1654 const char *name_in,
1655 uint32_t ucf_flags,
1656 bool *ppath_contains_wcard,
1657 struct smb_filename **pp_smb_fname)
1659 return filename_convert_internal(ctx,
1660 conn,
1661 smbreq->flags2 & FLAGS2_DFS_PATHNAMES,
1662 smbreq,
1663 name_in,
1664 ucf_flags,
1665 ppath_contains_wcard,
1666 pp_smb_fname);